public inbox for netdev@vger.kernel.org 
 help / color / mirror / Atom feed
From: John Heffner <jheffner@psc•edu>
To: lm@bitmover•com, Linus Torvalds <torvalds@linux-foundation•org>,
	davem@davemloft•net, wscott@bitmover•com, netdev@vger•kernel.org
Subject: Re: tcp bw in 2.6
Date: Tue, 02 Oct 2007 11:06:23 -0400	[thread overview]
Message-ID: <47025E6F.8080503@psc.edu> (raw)
In-Reply-To: <20071002022059.GE7037@bitmover.com>

[-- Attachment #1: Type: text/plain, Size: 417 bytes --]

Larry McVoy wrote:
> A short summary is "can someone please post a test program that sources
> and sinks data at the wire speed?"  because apparently I'm too old and
> clueless to write such a thing.

Here's a simple reference tcp source/sink that's I've used for years. 
For example, on a couple gigabit machines:

$ ./tcpsend -t10 dew
Sent 1240415312 bytes in 10.033101 seconds
Throughput: 123632294 B/s

   -John


[-- Attachment #2: discard.c --]
[-- Type: text/plain, Size: 2332 bytes --]

/*
 * discard.c
 * A simple discard server.
 *
 * Copyright 2003 John Heffner.
 */

#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/poll.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/param.h>
#include <netinet/in.h>

#if 0
#define RATELIMIT
#define RATE		100000	/* bytes/sec */
#define WAIT_TIME	(1000000/HZ-1)
#define READ_SIZE	(RATE/HZ)
#else
#define READ_SIZE	(1024*1024)
#endif

void child_handler(int sig)
{
	int status;
	
	wait(&status);
}

int main(int argc, char *argv[])
{
	int port = 9000;
	int lfd;
	struct sockaddr_in laddr;
	int newfd;
	struct sockaddr_in newaddr;
	int pid;
	socklen_t len;
	
	if (argc > 2) {
		fprintf(stderr, "usage: discard [port]\n");
		exit(1);
	}
	if (argc == 2) {
		if (sscanf(argv[1], "%d", &port) != 1 || port < 0 || port > 65535) {
			fprintf(stderr, "discard: error: not a port number\n");
			exit(1);
		}
	}
	
	if (signal(SIGCHLD, child_handler) == SIG_ERR) {
		perror("signal");
		exit(1);
	}
	
	memset(&laddr, 0, sizeof (laddr));
	laddr.sin_family = AF_INET;
	laddr.sin_port = htons(port);
	laddr.sin_addr.s_addr = INADDR_ANY;
	
	if ((lfd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
		perror("socket");
		exit(1);
	}
	if (bind(lfd, (struct sockaddr *)&laddr, sizeof (laddr)) != 0) {
		perror("bind");
		exit(1);
	}
	if (listen(lfd, 5) != 0) {
		perror("listen");
		exit(1);
	}
	
	for (;;) {
		if ((newfd = accept(lfd, (struct sockaddr *)&newaddr, &len)) < 0) {
			if (errno == EINTR)
				continue;
			perror("accept");
			exit(1);
		}
		
		if ((pid = fork()) < 0) {
			perror("fork");
			exit(1);
		} else if (pid == 0) {
			int n;
			char buf[READ_SIZE];
			int64_t data_rcvd = 0;
			struct timeval stime, etime;
			float time;
			
			gettimeofday(&stime, NULL);
			while ((n = read(newfd, buf, READ_SIZE)) > 0) {
				data_rcvd += n;
#ifdef RATELIMIT
				usleep(WAIT_TIME);
#endif
			}
 			gettimeofday(&etime, NULL);
			close(newfd);
			
			time = (float)(1000000*(etime.tv_sec - stime.tv_sec) + etime.tv_usec - stime.tv_usec) / 1000000.0;
			printf("Received %lld bytes in %f seconds\n", (long long)data_rcvd, time);
			printf("Throughput: %d B/s\n", (int)((float)data_rcvd / time));
			
			exit(0);
		}
		
		close(newfd);
	}
	
	return 1;
}

[-- Attachment #3: tcpsend.c --]
[-- Type: text/plain, Size: 6268 bytes --]

/*
 * tcpsend.c
 * Send pseudo-random data through a TCP connection.
 *
 * Copyright 2003 John Heffner.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <signal.h>
#include <errno.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/stat.h>
#ifdef __linux__
#include <sys/sendfile.h>
#endif

#define SNDSIZE	(1024 * 10)
#define BUFSIZE	(1024 * 1024)

#define max(a,b)	(a > b ? a : b)
#define min(a,b)	(a < b ? a : b)

int time_done = 0;
int interrupt_done = 0;

struct timeval starttime;

void int_handler(int sig)
{
	interrupt_done = 1;
}

void alarm_handler(int sig)
{
	time_done = 1;
}

static void usage_error(int err) {
	fprintf(stderr, "usage: tcpsend [-z] [-b max_bytes] [-t max_time] hostname [port]\n");
	exit(err);
}

static void cleanup_exit(int fd, char *filename, int status)
{
	if (fd > 0)
		close(fd);
	if (filename)
		unlink(filename);
	exit(status);
}

int main(int argc, char *argv[])
{
	char *hostname = "localhost";
	int port = 9000;
	int max_time = -1;
	int max_bytes = -1;
	int zerocopy = 0;
	
	int sockfd;
	struct sockaddr_in addr;
	struct hostent *hent;
	struct sigaction act;
	int i;
	int arg_state;
	char *tmp;
	int add;
	char *buf;
	int64_t data_sent;
	int n;
	off_t start;
	int amt;
	struct timeval etime;
	float time;
	int err;
	char *namebuf = NULL;
	int fd = -1;
	
	/* Read in args */
	if (argc == 2 && strcmp(argv[1], "-h") == 0)
		usage_error(0);
	
	for (arg_state = 0, i = 1; i < argc; i++) {
		if (argv[i][0] == '-') {
			if (arg_state != 0)
				usage_error(1);
			if (strlen(argv[i]) < 2)
				usage_error(1);
			
			add = 0;
			if (argv[i][1] == 'z') {
				zerocopy = 1;
			} else if (argv[i][1] == 'b' ||
			           argv[i][1] == 't') {
				if (strlen(argv[i]) > 2) {
					tmp = &(argv[i][2]);
				} else {
					add = 1;
					if (i + 1 >= argc)
						usage_error(1);
					tmp = argv[i + 1];
				}
				
				if (argv[i][1] == 'b') {
					if (sscanf(tmp, "%d", &max_bytes) != 1 ||
					    max_bytes < 0)
						usage_error(1);
				} else {
					if (sscanf(tmp, "%d", &max_time) != 1 ||
					    max_time < 0)
						usage_error(1);
				}
			} else {
				usage_error(1);
			}
			
			i += add;
		} else {
			switch (arg_state) {
			case 0:
				arg_state = 1;
				hostname = argv[i];
				break;
			case 1:
				arg_state = 2;
				if (sscanf(argv[i], "%d", &port) != 1 ||
				    port < 0 || port > 65535)
					usage_error(1);
				break;
			default:
				usage_error(1);
			}
		}
	}
	if (arg_state < 1)
		usage_error(1);
	
#ifndef __linux__
	if (zerocopy) {
		fprintf(stderr, "Zero-copy is only supported under Linux.\n");
		exit(1);
	}
#endif
	
	/* Set up addr struct from hostname and port */
	if ((hent = gethostbyname(hostname)) == NULL) {
		fprintf(stderr, "tcpsend: gethostbyname error\n");
		exit(1);
	}
	memset(&addr, 0, sizeof (addr));
	addr.sin_family = AF_INET;
	memcpy(&addr.sin_addr, hent->h_addr_list[0], 4);
	addr.sin_port = htons(port);
	
	
	/* Create buffer and fill with random data */
	if (gettimeofday(&starttime, NULL) < 0) {
		perror("gettimeofday");
		exit(1);
	}
	srand((unsigned int)(starttime.tv_usec + 1000000 * starttime.tv_sec));
	if ((buf = (char *)malloc(BUFSIZE)) == NULL) {
		fprintf(stderr, "malloc failed\n");
		exit(1);
	}
	for (i = 0; i < BUFSIZE; i += sizeof (int)) {
		*(int *)&buf[i] = rand();
	}
	if (zerocopy) {
		if ((namebuf = malloc(64)) == NULL) {
			fprintf(stderr, "malloc failed\n");
			exit(1);
		}
		sprintf(namebuf, "/tmp/tcpsend%d", getpid());
		if ((fd = open(namebuf, O_RDWR | O_CREAT, 0600)) < 0) {
			perror("open");
			exit(1);
		}
		for (amt = BUFSIZE; amt > 0; ) {
			if ((n = write(fd, buf, amt)) < 0) {
				perror("write");
				cleanup_exit(fd, namebuf, 1);
			}
			amt -= n;
		}
	}
	
	
	/* Open connection */
	if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
		perror("socket");
		cleanup_exit(fd, namebuf, 1);
	}
	if (connect(sockfd, (struct sockaddr *)&addr, sizeof (addr)) != 0) {
		perror("connect");
		cleanup_exit(fd, namebuf, 1);
	}
	
	
	/* Set up signal handlers */
	if (max_time >= 0) {
		if (sigaction(SIGALRM, NULL, &act) != 0) {
			perror("sigaction: SIGALRM");
			cleanup_exit(fd, namebuf, 1);
		}
		act.sa_handler = alarm_handler;
		act.sa_flags = 0;
		if (sigaction(SIGALRM, &act, NULL) != 0) {
			perror("sigaction: SIGALRM");
			cleanup_exit(fd, namebuf, 1);
		}
		alarm(max_time);
	}
	if (sigaction(SIGINT, NULL, &act) != 0) {
		perror("sigaction: SIGINT");
		cleanup_exit(fd, namebuf, 1);
	}
	act.sa_handler = int_handler;
	act.sa_flags = 0;
	if (sigaction(SIGINT, &act, NULL) != 0) {
		perror("sigaction: SIGINT");
		cleanup_exit(fd, namebuf, 1);
	}
	
	
	/* Send random data until we hit a max */
	data_sent = 0;
	while ((max_bytes < 0 ? 1 : data_sent < max_bytes) &&
	       !time_done && !interrupt_done) {
		start = rand() / (RAND_MAX / (BUFSIZE - SNDSIZE) + 1);
		if (max_bytes < 0)
			amt = SNDSIZE;
		else
			amt = min(SNDSIZE, max_bytes - data_sent);
		if (zerocopy) {
#ifdef __linux__			
			if ((n = sendfile(sockfd, fd, &start, amt)) < 0 && errno != EINTR) {
				perror("sendfile");
				cleanup_exit(fd, namebuf, 1);
			} else if (n == 0) {
				fprintf(stderr, "tcpsend: socket unexpectedly closed\n");
				cleanup_exit(fd, namebuf, 1);
			}
#endif
		} else {
			if ((n = write(sockfd, &buf[start], amt)) < 0 && errno != EINTR) {
				perror("write");
				cleanup_exit(fd, namebuf, 1);
			} else if (n == 0) {
				fprintf(stderr, "tcpsend: socket unexpectedly closed\n");
				cleanup_exit(fd, namebuf, 1);
			}
		}
		
		data_sent += n;
	}
	
	/* Close the socket and wait for the remote host to close */
	if (shutdown(sockfd, SHUT_WR) != 0) {
		perror("shutdown");
		cleanup_exit(fd, namebuf, 1);
	}
	err = read(sockfd, buf, 1);
	if (err < 0) {
		perror("read");
		cleanup_exit(fd, namebuf, 1);
	} else if (err > 0) {
		fprintf(stderr, "warning: data read on socket\n");
	}
	
	gettimeofday(&etime, NULL);
	time = (float)(1000000*(etime.tv_sec - starttime.tv_sec) +
	       etime.tv_usec - starttime.tv_usec) / 1000000.0;
	printf("Sent %lld bytes in %f seconds\n", (long long)data_sent, time);
	printf("Throughput: %d B/s\n", (int)((float)data_sent / time));
	
	cleanup_exit(fd, namebuf, 0);
	return 0;
}

[-- Attachment #4: Makefile --]
[-- Type: text/plain, Size: 75 bytes --]

CFLAGS = -g -O2 -Wall

all: tcpsend discard

clean:
	rm -f tcpsend discard

  parent reply	other threads:[~2007-10-02 15:07 UTC|newest]

Thread overview: 56+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <20070929142517.EC6AB5FB21@work.bitmover.com>
     [not found] ` <alpine.LFD.0.999.0709290914410.3579@woody.linux-foundation.org>
     [not found]   ` <20070929172639.GB7037@bitmover.com>
     [not found]     ` <alpine.LFD.0.999.0709291050200.3579@woody.linux-foundation.org>
2007-10-02  0:59       ` tcp bw in 2.6 Larry McVoy
2007-10-02  2:14         ` Linus Torvalds
2007-10-02  2:20           ` Larry McVoy
2007-10-02  3:50             ` David Miller
2007-10-02  4:23               ` Larry McVoy
2007-10-02 15:06             ` John Heffner [this message]
2007-10-02 17:14             ` Rick Jones
2007-10-02 17:20               ` Larry McVoy
2007-10-02 18:01                 ` Rick Jones
2007-10-02 18:40                   ` Larry McVoy
2007-10-02 19:47                     ` Rick Jones
2007-10-02 21:32                     ` David Miller
2007-10-03  7:19               ` Bill Fink
2007-10-02 10:52         ` Herbert Xu
2007-10-02 15:09           ` Larry McVoy
2007-10-02 15:41             ` Larry McVoy
2007-10-02 16:25               ` Larry McVoy
2007-10-02 16:47                 ` Stephen Hemminger
2007-10-02 16:49                   ` Larry McVoy
2007-10-02 17:10                     ` Stephen Hemminger
2007-10-15 12:40                   ` Daniel Schaffrath
2007-10-15 15:49                     ` Stephen Hemminger
2007-10-02 16:34               ` Linus Torvalds
2007-10-02 16:48                 ` Larry McVoy
2007-10-02 21:16                   ` David Miller
2007-10-02 21:26                     ` Larry McVoy
2007-10-02 21:47                       ` David Miller
2007-10-02 22:17                         ` Rick Jones
2007-10-02 22:32                           ` David Miller
2007-10-02 22:36                             ` Larry McVoy
2007-10-02 22:59                               ` Rick Jones
2007-10-03  8:02                               ` David Miller
2007-10-02 16:48               ` Ben Greear
2007-10-02 17:11                 ` Larry McVoy
2007-10-02 17:18                   ` Ben Greear
2007-10-02 17:21                     ` Larry McVoy
2007-10-02 17:54                       ` Stephen Hemminger
2007-10-02 18:35                         ` Larry McVoy
2007-10-02 18:29             ` John Heffner
2007-10-02 19:07               ` Larry McVoy
2007-10-02 19:29                 ` Linus Torvalds
2007-10-02 20:31                   ` David Miller
2007-10-02 19:33                 ` Larry McVoy
2007-10-02 19:53                   ` John Heffner
2007-10-02 20:14                     ` Larry McVoy
2007-10-02 20:40                       ` Rick Jones
2007-10-02 20:42                       ` Wayne Scott
2007-10-02 21:56                         ` Linus Torvalds
2007-10-02 19:27             ` Linus Torvalds
2007-10-02 19:53               ` Rick Jones
2007-10-02 20:33               ` David Miller
2007-10-02 20:44                 ` Roland Dreier
2007-10-02 21:21                 ` Larry McVoy
2007-10-03 21:13                   ` Pekka Pietikainen
2007-10-03 21:23                     ` Larry McVoy
2007-10-03 21:50                       ` Pekka Pietikainen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=47025E6F.8080503@psc.edu \
    --to=jheffner@psc$(echo .)edu \
    --cc=davem@davemloft$(echo .)net \
    --cc=lm@bitmover$(echo .)com \
    --cc=netdev@vger$(echo .)kernel.org \
    --cc=torvalds@linux-foundation$(echo .)org \
    --cc=wscott@bitmover$(echo .)com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox