Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 01 Sep 1999 18:49:11 -0700
From:      Dave Liebreich <davel@entera.com>
To:        freebsd-net@freebsd.org
Subject:   TCP socket performance?
Message-ID:  <199909020149.SAA02570@warhawk.entera.com>

next in thread | raw e-mail | index | archive | help
The following program was written to demonstrate a problem with Solaris 7
x86 networking.  I tried running it under FreeBSD 3.2-RELEASE (vanilla - no
tuning).

The program runs for a bit, then the system interactive response "freezes"
 - sending a HUP to the process restores the system to normal performace.

If anyone on this list has any ideas on why this program thrashes the system
so badly, or any suggestions on how to tune the system to not thrash, please
let me know.

Thanks

Dave Liebreich
QA
Entera, Inc.


--------->% cut here %<---------
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <sys/time.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <memory.h>
#include <signal.h>
#include <time.h>


#ifdef ONT_GET_ALARMED
static int useAlarm = 0;
#else
static int useAlarm = 1;
#endif

#ifdef ONT_USE_PIPES
static int usePipes;
#else
static int usePipes = 1;
#endif

static int numServProcs;
static int numCliProcs;
static int pipefds[2];


static sockaddr_in sin[1];
static pid_t startPid;

void pauseAnInstant(long num)
{
	timeval tv[1];
	tv->tv_sec = 0;
	tv->tv_usec = num * 1000;
	if (select(0, 0, 0, 0, tv) < 0)
		perror("select");
}

static void handler()
{
	if (getpid() == startPid)
		kill(0, SIGHUP);
}

static void sigHandler(int sig)
{
	exit(0);
}

int bite(int num)
{
	char first[10];
	char pre[2];
	char post[2];
	long pid=getpid();
	pre[0] = 'C';
	pre[1] = ' ' + num;
	post[0] = 'c';
	post[1] = ' ' + num;
	first[0] = 'F';
	first[1] = ' ' + num;
	memcpy(first + 2, (char *)&pid, sizeof pid);

	write(pipefds[1], first, sizeof pid + 2);
	for (;;)
	{
		char buf[2048];
		int fd(socket(AF_INET, SOCK_STREAM, 0));
		if (fd < 0)
		{
			perror("socket.2");
			return 1;
		}
		pauseAnInstant(10);
		write(pipefds[1], pre, 2);
		int r = connect(fd, (sockaddr*)sin, sizeof(sin));
		if (r < 0)
		{
			perror("connect");
			return 1;
		}
		write(pipefds[1], post, 2);

		if (write(fd, buf, sizeof(buf)) != sizeof buf)
			perror("read.write.bite");
		pauseAnInstant(150);
		if (read(fd, buf, sizeof(buf)) != sizeof(buf))
			perror("read.read.bite");
		close(fd);
	}
}

int attack()
{
	for (int i = 0; i < numCliProcs; ++i)
	{
		switch(fork())
		{
		case 0:
			sleep(1);
			return bite(i);
		case -1:
			perror("fork.2");
			return 1;
		}
	}
	while (wait((int *)0) < 0)
	{
		sleep(1);
	}
	return 0;
}

int block(int num, int bs)
{
	char first[10];
	char pre[2];
	char post[2];
	long pid=getpid();
	ssize_t frump;

	pre[0] = 'A';
	pre[1] = ' ' + num | 0x80;
	post[0] = 'a';
	post[1] = ' ' + num | 0x80;
	first[0] = 'F';
	first[1] = ' ' + num | 0x80;
	memcpy(first + 2, (char *)&pid, sizeof pid);
	write(pipefds[1], first, sizeof pid + 2);
	for (;;)
	{
		char buf[2048];
		int len = sizeof sin;
		pauseAnInstant(50);
		write(pipefds[1], pre, 2);
		if (useAlarm)
			alarm(100);
		int fd = accept(bs, (sockaddr *)sin, &len);
		if (useAlarm)
			alarm(0);
		if (fd < 0)
		{
			perror("accept");
			return 1;
		}
		write(pipefds[1], post, 2);
		if ((frump=read(fd, buf, sizeof(buf))) != sizeof(buf))
		  {
		    fprintf(stderr,"frump is %lu\n",frump);
		    perror("read.read.block");
		  }
		if (write(fd, buf, sizeof(buf)) != sizeof buf)
			perror("read.write.block");
		close(fd);
	}
}

int defend(int bs)
{
	for (int i = 0; i < numServProcs; ++i)
	{
		switch(fork())
		{
		case 0:
			sleep(1);
			return block(i, bs);
		case -1:
			perror("fork.3");
			return 1;
		}
	}
	while (wait((int *)0) < 0)
	{
		sleep(1);
	}
	return 0;
}

int readStuff()
{
	long counts[256];
	long ocounts[5][256];
	long marks[256];
	long pids[256];
	int phases[256];
	unsigned char buf[1 << 14];
	int ln(0); // int ln; BUG BUG BUG BWAHAHAHAHAA
	long strt = time((long *)0);
	long lasttim = 0;
	long nextReportTime = strt + 10;
	int leftover = 0;
	int i;

	memset((char *)counts, 0, sizeof counts);
	memset((char *)marks, 0, sizeof marks);
	memset((char *)phases, 0, sizeof phases);
	memset((char *)ocounts, 0, sizeof ocounts);
	memset((char *)pids, 0, sizeof pids);

	for(;;)
	{
		pauseAnInstant(450);
		if ((ln = read(pipefds[0], (char *)buf + leftover, sizeof(buf) - leftover)) < 0)
		{
			perror("read.readStuff");
			break;
		}
		if (ln == 0)
		{
			if (usePipes)
				break;
			continue;
		}
		ln += leftover;
		leftover = 0;
		if (ln & 1)
		{
			fprintf(stderr, "What the !?!?!?\n");
			ln &= ~1;
		}
		long tim = time((long *)0) - strt;
		for(i = 0; i < ln; i += 2)
		{
			int p = buf[i];
			int n = buf[i+1];
			if (p == 'F')
			{
				if (i + 2 + sizeof pids[0] > ln)
				{
					leftover = ln - i;
					memcpy(buf, buf + i, leftover);
					break;
				}
				memcpy((char *)&pids[n], buf + i + 2, sizeof *pids);
				i += sizeof *pids;
			}
			else
			{
				counts[p] += 1;
				ocounts[tim%5][p] += 1;
				phases[n] = p;
				marks[n] = tim;
			}
		}
		if (tim <= lasttim)
			continue;
		if (!(tim % 10) || tim >= nextReportTime)
		{
			nextReportTime = tim + 10;

			int any(0);
			int anyany(0);
			for(i = 0; i < 256; ++i)
			{
				if (marks[i] < tim - 4 && phases[i] == 'A')
				{
					if (!any)
					{
						printf("ACCEPT:");
						anyany = any = 1;
					}
					printf(" %lu:%d", pids[i], tim - marks[i]);
				}
			}
			if (any)
				printf("\n");

			any = 0;
			for(i = 0; i < 256; ++i)
			{
				if (marks[i] < tim - 4 && phases[i] == 'C')
				{
					if (!any)
					{
						printf("CONNECT:");
						anyany = any = 1;
					}
					printf(" %lu:%d", pids[i], tim - marks[i]);
				}
			}
			if (any)
				printf("\n");

			any = 0;
			for(i = 0; i < 256; ++i)
			{
				if (marks[i] < tim - 4 && phases[i] == 'a')
				{
					if (!any)
					{
						printf("ACCEPTTRANS:");
						anyany = any = 1;
					}
					printf(" %lu:%d", pids[i], tim - marks[i]);
				}
			}
			if (any)
				printf("\n");

			any = 0;
			for(i = 0; i < 256; ++i)
			{
				if (marks[i] < tim - 4 && phases[i] == 'c')
				{
					if (!any)
					{
						printf("CONNECTTRANS:");
						anyany = any = 1;
					}
					printf(" %lu:%d", pids[i], tim - marks[i]);
				}
			}
			if (any)
				printf("\n");

			if (!anyany)
			{
				printf("CLEAN\n");
			}
			printf("SEC: CNT:ACP  AVGTOTAL.TIM AVG-FIVE.SEC\n");
		}
		long n = (counts['a'] * 1000) / tim;
		long n2 = 0;
		for (int i = 0; i < 5; ++i)
		{
			n2 += (ocounts[i]['a'] * 1000) / (tim - lasttim);
		}
		n2 /= 5;
		printf("%03.3ld: %03ld:%03ld  %8ld.%03.3ld %8ld.%03.03ld\n",
			tim,
			counts['C'] - counts['c'], counts['A'] - counts['a'],
			n / 1000, n % 1000, n2 / 1000, n2 % 1000);
		fflush(stdout);
		lasttim = tim;
		memset((char *)ocounts[(tim+1)%5], 0, sizeof ocounts[0]);
	}
	fprintf(stderr, "Sneaking away....\n");
	return 0;
}

int main(int argc, char **argv)
{
	startPid = getpid();

	setpgrp(0, startPid);

	atexit(handler);
	signal(SIGINT, sigHandler);
	signal(SIGPIPE, SIG_IGN);

	if (usePipes)
	{
		if (pipe(pipefds))
		{
			perror("pipe");
			return 1;
		}
	}
	else
	{
		pipefds[1] = open("/tmp/incroyable", O_CREAT|O_TRUNC|O_WRONLY|O_APPEND, 0600);
		if (pipefds[1] < 0)
		{
			perror("open:O_CREAT|O_TRUNC|O_WRONLY|O_APPEND");
			return 1;
		}
		pipefds[0] = open("/tmp/incroyable", O_RDONLY, 0600);
		if (pipefds[0] < 0)
		{
			perror("open:O_RDONLY");
			return 1;
		}
		unlink("/tmp/incroyable");
	}

	close(0);

	switch(fork())
	{
	case -1:
		perror("fork.9");
		return 1;
	case 0:
		close(pipefds[1]);
		return readStuff();
	}

	nice(20);

	close(pipefds[0]);

	if (argc > 1)
		numServProcs = atoi(argv[1]);
	if (!numServProcs)
		numServProcs = 70;

	if (argc > 2)
		numCliProcs = atoi(argv[2]);
	if (!numCliProcs)
		numCliProcs = numServProcs;

	unsigned short portNo;
	int bs(socket(AF_INET, SOCK_STREAM, 0));
	if (bs < 0)
	{
		perror("socket.inet");
		return 1;
	}
	memset((char* )sin, 0, sizeof(sin));

	sin->sin_addr.s_addr = INADDR_ANY;
	sin->sin_port = htons(0);

	if (bind(bs, (struct sockaddr* )sin, sizeof(sin)) < 0)
	{
		perror("bind");
		return 1;
	}

	if (listen(bs, 100) < 0)
	{
		perror("listen");
		return 1;
	}

	int ln(sizeof(sin));
	if (getsockname(bs, (struct sockaddr* )sin, &ln) < 0)
	{
		perror("getsockname");
		return 1;
	}
	portNo = ntohs(sin->sin_port);

	printf("Listening on Port %u\n", portNo);
	fflush(stdout);
	close(1);

	switch(fork())
	{
	case 0:
		close(bs);
		sleep(3);
		return attack();
	case -1:
		perror("fork");
		return 1;
	}
	return defend(bs);
}


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-net" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199909020149.SAA02570>