File:  [ELWIX - Embedded LightWeight unIX -] / elwix / patches / freebsd.netblast.PR179085.patch
Revision 1.2: download - view: text, annotated - select for diffs - revision graph
Thu Mar 11 13:59:52 2021 UTC (3 years, 2 months ago) by misho
Branches: MAIN
CVS tags: elwix2_8, elwix2_7, HEAD, ELWIX2_7, ELWIX2_6
ver 2.6

    1: Index: tools/tools/netrate/netblast/Makefile
    2: ===================================================================
    3: --- tools/tools/netrate/netblast/Makefile	(revision 258293)
    4: +++ tools/tools/netrate/netblast/Makefile	(working copy)
    5: @@ -4,5 +4,8 @@
    6:  
    7:  PROG=	netblast
    8:  MAN=
    9: +LDFLAGS += -lpthread
   10:  
   11: +WARNS?= 3
   12: +
   13:  .include <bsd.prog.mk>
   14: Index: tools/tools/netrate/netblast/netblast.c
   15: ===================================================================
   16: --- tools/tools/netrate/netblast/netblast.c	(revision 258293)
   17: +++ tools/tools/netrate/netblast/netblast.c	(working copy)
   18: @@ -36,19 +36,29 @@
   19:  
   20:  #include <signal.h>
   21:  #include <stdio.h>
   22: +#include <inttypes.h>
   23:  #include <stdlib.h>
   24:  #include <string.h>
   25:  #include <unistd.h>			/* close */
   26:  
   27: +#include <pthread.h>
   28: +#include <fcntl.h>
   29: +#include <time.h>   /* clock_getres() */
   30: +
   31: +static int round_to(int n, int l)
   32: +{
   33: +    return ((n + l - 1)/l)*l;
   34: +}
   35: +
   36:  static void
   37:  usage(void)
   38:  {
   39:  
   40: -	fprintf(stderr, "netblast [ip] [port] [payloadsize] [duration]\n");
   41: +	fprintf(stderr, "netblast [ip] [port] [payloadsize] [duration] [nthreads]\n");
   42:  	exit(-1);
   43:  }
   44:  
   45: -static int	global_stop_flag;
   46: +static int	global_stop_flag=0;
   47:  
   48:  static void
   49:  signal_handler(int signum __unused)
   50: @@ -57,48 +67,28 @@
   51:  	global_stop_flag = 1;
   52:  }
   53:  
   54: +
   55:  /*
   56: - * Loop that blasts packets: begin by recording time information, resetting
   57: - * stats.  Set the interval timer for when we want to wake up.  Then go.
   58: - * SIGALRM will set a flag indicating it's time to stop.  Note that there's
   59: - * some overhead to the signal and timer setup, so the smaller the duration,
   60: - * the higher the relative overhead.
   61: + * Each socket uses multiple threads so the generator is
   62: + * more efficient. A collector thread runs the stats.
   63:   */
   64: -static int
   65: -blast_loop(int s, long duration, u_char *packet, u_int packet_len)
   66: +struct td_desc {
   67: +	pthread_t td_id;
   68: +	uint64_t counter; /* tx counter */
   69: +	uint64_t send_errors; /* tx send errors */
   70: +	uint64_t send_calls;    /* tx send calls */
   71: +	int s;
   72: +	u_char *packet;
   73: +	u_int packet_len;
   74: +};
   75: +
   76: +static void *
   77: +blast(void *data)
   78:  {
   79: -	struct timespec starttime, tmptime;
   80: -	struct itimerval it;
   81: -	u_int32_t counter;
   82: -	int send_errors, send_calls;
   83: -
   84: -	if (signal(SIGALRM, signal_handler) == SIG_ERR) {
   85: -		perror("signal");
   86: -		return (-1);
   87: -	}
   88: -
   89: -	if (clock_getres(CLOCK_REALTIME, &tmptime) == -1) {
   90: -		perror("clock_getres");
   91: -		return (-1);
   92: -	}
   93: -
   94: -	if (clock_gettime(CLOCK_REALTIME, &starttime) == -1) {
   95: -		perror("clock_gettime");
   96: -		return (-1);
   97: -	}
   98: -
   99: -	it.it_interval.tv_sec = 0;
  100: -	it.it_interval.tv_usec = 0;
  101: -	it.it_value.tv_sec = duration;
  102: -	it.it_value.tv_usec = 0;
  103: -
  104: -	if (setitimer(ITIMER_REAL, &it, NULL) < 0) {
  105: -		perror("setitimer");
  106: -		return (-1);
  107: -	}
  108: -
  109: -	send_errors = send_calls = 0;
  110: -	counter = 0;
  111: +    struct td_desc *t = data;
  112: +	t->counter=0;
  113: +	t->send_errors=0;
  114: +	t->send_calls=0;
  115:  	while (global_stop_flag == 0) {
  116:  		/*
  117:  		 * We maintain and, if there's room, send a counter.  Note
  118: @@ -110,32 +100,84 @@
  119:  		 * operation, causing the current sequence number also to be
  120:  		 * skipped.
  121:  		 */
  122: -		if (packet_len >= 4) {
  123: -			be32enc(packet, counter);
  124: -			counter++;
  125: +		if (t->packet_len >= 4) {
  126: +			be32enc(t->packet, t->counter);
  127: +			t->counter++;
  128:  		}
  129: -		if (send(s, packet, packet_len, 0) < 0)
  130: -			send_errors++;
  131: -		send_calls++;
  132: +		if (send(t->s, t->packet, t->packet_len, 0) < 0)
  133: +			t->send_errors++;
  134: +		t->send_calls++;
  135:  	}
  136: +    return NULL;
  137: +}
  138:  
  139: +static struct td_desc **
  140: +make_threads(int s, u_char *packet, u_int packet_len, int nthreads)
  141: +{
  142: +    int i;
  143: +    int lb = round_to(nthreads * sizeof (struct td_desc *), 64);
  144: +    int td_len = round_to(sizeof(struct td_desc), 64); // cache align
  145: +    char *m = calloc(1, lb + td_len * nthreads);
  146: +    struct td_desc **tp;
  147: +
  148: +    /* pointers plus the structs */
  149: +    if (m == NULL) {
  150: +        perror("no room for pointers!");
  151: +        exit(1);
  152: +    }
  153: +    tp = (struct td_desc **)m;
  154: +    m += lb;    /* skip the pointers */
  155: +    for (i = 0; i < nthreads; i++, m += td_len) {
  156: +        tp[i] = (struct td_desc *)m;
  157: +        tp[i]->s = s;
  158: +        tp[i]->packet = packet;
  159: +        tp[i]->packet_len = packet_len;
  160: +        if (pthread_create(&tp[i]->td_id, NULL, blast, tp[i])) {
  161: +            perror("unable to create thread");
  162: +            exit(1);
  163: +        }
  164: +    }
  165: +    return tp;
  166: +}
  167: +
  168: +
  169: +static void
  170: +main_thread(struct td_desc **tp, long duration, struct timespec starttime, struct timespec tmptime, long payloadsize, int family, int nthreads)
  171: +{
  172: +	uint64_t send_errors=0, send_calls=0;
  173: +	int i;
  174:  	if (clock_gettime(CLOCK_REALTIME, &tmptime) == -1) {
  175:  		perror("clock_gettime");
  176: -		return (-1);
  177:  	}
  178:  
  179: +	for (i = 0; i < nthreads; i++) {
  180: +		/* Wait for thread end */
  181: +		pthread_join( tp[i]->td_id, NULL);
  182: +		send_calls+=tp[i]->send_calls;
  183: +		send_errors+=tp[i]->send_errors;
  184: +    }
  185: +
  186:  	printf("\n");
  187: -	printf("start:             %zd.%09lu\n", starttime.tv_sec,
  188: +	printf("start:                      %zd.%09lu\n", starttime.tv_sec,
  189:  	    starttime.tv_nsec);
  190: -	printf("finish:            %zd.%09lu\n", tmptime.tv_sec,
  191: +	printf("finish:                     %zd.%09lu\n", tmptime.tv_sec,
  192:  	    tmptime.tv_nsec);
  193: -	printf("send calls:        %d\n", send_calls);
  194: -	printf("send errors:       %d\n", send_errors);
  195: -	printf("approx send rate:  %ld\n", (send_calls - send_errors) /
  196: +	printf("send calls:                 %" PRIu64 "\n", send_calls);
  197: +	printf("send errors:                %" PRIu64 "\n", send_errors);
  198: +	printf("send success:               %" PRIu64 "\n", send_calls - send_errors);
  199: +	printf("approx send rate:           %" PRIu64 "\n", (send_calls - send_errors) /
  200:  	    duration);
  201: -	printf("approx error rate: %d\n", (send_errors / send_calls));
  202: -
  203: -	return (0);
  204: +	printf("approx error rate:          %" PRIu64 "\n", (send_errors / send_calls));
  205: +	printf("approx Ethernet throughput: ");
  206: +	if (family == AF_INET)
  207: +		printf("%" PRIu64 " Mib/s\n", ((send_calls - send_errors) / duration ) *
  208: +		(payloadsize + 8 + 20 + 14 ) * 8 / 1000 / 1000);
  209: +	else if (family == AF_INET6)
  210: +		printf("%" PRIu64 " Mib/s\n", ((send_calls - send_errors) / duration ) *
  211: +		(payloadsize + 8 + 40 + 14 ) * 8 / 1000 / 1000);
  212: +	else printf("CAN 'T DETERMINE family type %i\n",family);
  213: +	printf("approx payload throughput:  %" PRIu64 " Mib/s\n", ((send_calls - send_errors) / 
  214: +		duration ) * payloadsize * 8 / 1000 / 1000);
  215:  }
  216:  
  217:  int
  218: @@ -143,11 +185,15 @@
  219:  {
  220:  	long payloadsize, duration;
  221:  	struct addrinfo hints, *res, *res0;
  222: -	char *dummy, *packet;
  223: -	int port, s, error;
  224: +	char *dummy;
  225: +	u_char *packet;
  226: +	int family, port, s, error, nthreads = 1;
  227: +	struct td_desc **tp;	
  228:  	const char *cause = NULL;
  229: +	struct timespec starttime, tmptime;
  230: +	struct itimerval it;
  231:  
  232: -	if (argc != 5)
  233: +	if (argc < 5)
  234:  		usage();
  235:  
  236:  	memset(&hints, 0, sizeof(hints));
  237: @@ -177,6 +223,11 @@
  238:  		/*NOTREACHED*/
  239:  	}
  240:  
  241: +	if (argc > 5)
  242: +        nthreads = strtoul(argv[5], &dummy, 10);
  243: +    if (nthreads < 1 || nthreads > 64)
  244: +        usage();
  245: +
  246:  	packet = malloc(payloadsize);
  247:  	if (packet == NULL) {
  248:  		perror("malloc");
  249: @@ -213,9 +264,46 @@
  250:  		return (-1);
  251:  		/*NOTREACHED*/
  252:  	}
  253: -
  254: +	family=res->ai_family;
  255:  	freeaddrinfo(res0);
  256:  
  257: -	return (blast_loop(s, duration, packet, payloadsize));
  258: +	printf("netblast %d threads sending on UDP port %d\n",
  259: +    nthreads, (u_short)port);
  260:  
  261: +	/*
  262: +	 * Begin by recording time information stats.
  263: +	 * Set the interval timer for when we want to wake up.
  264: +	 * SIGALRM will set a flag indicating it's time to stop.  Note that there's
  265: +	 * some overhead to the signal and timer setup, so the smaller the duration,
  266: +	 * the higher the relative overhead.
  267: +	 */
  268: +
  269: +	if (signal(SIGALRM, signal_handler) == SIG_ERR) {
  270: +		perror("signal");
  271: +		return (-1);
  272: +	}
  273: +
  274: +	if (clock_getres(CLOCK_REALTIME, &tmptime) == -1) {
  275: +		perror("clock_getres");
  276: +		return (-1);
  277: +	}
  278: +
  279: +	if (clock_gettime(CLOCK_REALTIME, &starttime) == -1) {
  280: +		perror("clock_gettime");
  281: +		return (-1);
  282: +	}
  283: +
  284: +	it.it_interval.tv_sec = 0;
  285: +	it.it_interval.tv_usec = 0;
  286: +	it.it_value.tv_sec = duration;
  287: +	it.it_value.tv_usec = 0;
  288: +
  289: +	if (setitimer(ITIMER_REAL, &it, NULL) < 0) {
  290: +		perror("setitimer");
  291: +		return (-1);
  292: +	}
  293: +
  294: +    tp = make_threads(s, packet, payloadsize, nthreads);
  295: +    main_thread(tp, duration, starttime,  tmptime, payloadsize, family, nthreads);
  296: +
  297:  }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>