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

Index: tools/tools/netrate/netblast/Makefile
===================================================================
--- tools/tools/netrate/netblast/Makefile	(revision 258293)
+++ tools/tools/netrate/netblast/Makefile	(working copy)
@@ -4,5 +4,8 @@
 
 PROG=	netblast
 MAN=
+LDFLAGS += -lpthread
 
+WARNS?= 3
+
 .include <bsd.prog.mk>
Index: tools/tools/netrate/netblast/netblast.c
===================================================================
--- tools/tools/netrate/netblast/netblast.c	(revision 258293)
+++ tools/tools/netrate/netblast/netblast.c	(working copy)
@@ -36,19 +36,29 @@
 
 #include <signal.h>
 #include <stdio.h>
+#include <inttypes.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>			/* close */
 
+#include <pthread.h>
+#include <fcntl.h>
+#include <time.h>   /* clock_getres() */
+
+static int round_to(int n, int l)
+{
+    return ((n + l - 1)/l)*l;
+}
+
 static void
 usage(void)
 {
 
-	fprintf(stderr, "netblast [ip] [port] [payloadsize] [duration]\n");
+	fprintf(stderr, "netblast [ip] [port] [payloadsize] [duration] [nthreads]\n");
 	exit(-1);
 }
 
-static int	global_stop_flag;
+static int	global_stop_flag=0;
 
 static void
 signal_handler(int signum __unused)
@@ -57,48 +67,28 @@
 	global_stop_flag = 1;
 }
 
+
 /*
- * Loop that blasts packets: begin by recording time information, resetting
- * stats.  Set the interval timer for when we want to wake up.  Then go.
- * SIGALRM will set a flag indicating it's time to stop.  Note that there's
- * some overhead to the signal and timer setup, so the smaller the duration,
- * the higher the relative overhead.
+ * Each socket uses multiple threads so the generator is
+ * more efficient. A collector thread runs the stats.
  */
-static int
-blast_loop(int s, long duration, u_char *packet, u_int packet_len)
+struct td_desc {
+	pthread_t td_id;
+	uint64_t counter; /* tx counter */
+	uint64_t send_errors; /* tx send errors */
+	uint64_t send_calls;    /* tx send calls */
+	int s;
+	u_char *packet;
+	u_int packet_len;
+};
+
+static void *
+blast(void *data)
 {
-	struct timespec starttime, tmptime;
-	struct itimerval it;
-	u_int32_t counter;
-	int send_errors, send_calls;
-
-	if (signal(SIGALRM, signal_handler) == SIG_ERR) {
-		perror("signal");
-		return (-1);
-	}
-
-	if (clock_getres(CLOCK_REALTIME, &tmptime) == -1) {
-		perror("clock_getres");
-		return (-1);
-	}
-
-	if (clock_gettime(CLOCK_REALTIME, &starttime) == -1) {
-		perror("clock_gettime");
-		return (-1);
-	}
-
-	it.it_interval.tv_sec = 0;
-	it.it_interval.tv_usec = 0;
-	it.it_value.tv_sec = duration;
-	it.it_value.tv_usec = 0;
-
-	if (setitimer(ITIMER_REAL, &it, NULL) < 0) {
-		perror("setitimer");
-		return (-1);
-	}
-
-	send_errors = send_calls = 0;
-	counter = 0;
+    struct td_desc *t = data;
+	t->counter=0;
+	t->send_errors=0;
+	t->send_calls=0;
 	while (global_stop_flag == 0) {
 		/*
 		 * We maintain and, if there's room, send a counter.  Note
@@ -110,32 +100,84 @@
 		 * operation, causing the current sequence number also to be
 		 * skipped.
 		 */
-		if (packet_len >= 4) {
-			be32enc(packet, counter);
-			counter++;
+		if (t->packet_len >= 4) {
+			be32enc(t->packet, t->counter);
+			t->counter++;
 		}
-		if (send(s, packet, packet_len, 0) < 0)
-			send_errors++;
-		send_calls++;
+		if (send(t->s, t->packet, t->packet_len, 0) < 0)
+			t->send_errors++;
+		t->send_calls++;
 	}
+    return NULL;
+}
 
+static struct td_desc **
+make_threads(int s, u_char *packet, u_int packet_len, int nthreads)
+{
+    int i;
+    int lb = round_to(nthreads * sizeof (struct td_desc *), 64);
+    int td_len = round_to(sizeof(struct td_desc), 64); // cache align
+    char *m = calloc(1, lb + td_len * nthreads);
+    struct td_desc **tp;
+
+    /* pointers plus the structs */
+    if (m == NULL) {
+        perror("no room for pointers!");
+        exit(1);
+    }
+    tp = (struct td_desc **)m;
+    m += lb;    /* skip the pointers */
+    for (i = 0; i < nthreads; i++, m += td_len) {
+        tp[i] = (struct td_desc *)m;
+        tp[i]->s = s;
+        tp[i]->packet = packet;
+        tp[i]->packet_len = packet_len;
+        if (pthread_create(&tp[i]->td_id, NULL, blast, tp[i])) {
+            perror("unable to create thread");
+            exit(1);
+        }
+    }
+    return tp;
+}
+
+
+static void
+main_thread(struct td_desc **tp, long duration, struct timespec starttime, struct timespec tmptime, long payloadsize, int family, int nthreads)
+{
+	uint64_t send_errors=0, send_calls=0;
+	int i;
 	if (clock_gettime(CLOCK_REALTIME, &tmptime) == -1) {
 		perror("clock_gettime");
-		return (-1);
 	}
 
+	for (i = 0; i < nthreads; i++) {
+		/* Wait for thread end */
+		pthread_join( tp[i]->td_id, NULL);
+		send_calls+=tp[i]->send_calls;
+		send_errors+=tp[i]->send_errors;
+    }
+
 	printf("\n");
-	printf("start:             %zd.%09lu\n", starttime.tv_sec,
+	printf("start:                      %zd.%09lu\n", starttime.tv_sec,
 	    starttime.tv_nsec);
-	printf("finish:            %zd.%09lu\n", tmptime.tv_sec,
+	printf("finish:                     %zd.%09lu\n", tmptime.tv_sec,
 	    tmptime.tv_nsec);
-	printf("send calls:        %d\n", send_calls);
-	printf("send errors:       %d\n", send_errors);
-	printf("approx send rate:  %ld\n", (send_calls - send_errors) /
+	printf("send calls:                 %" PRIu64 "\n", send_calls);
+	printf("send errors:                %" PRIu64 "\n", send_errors);
+	printf("send success:               %" PRIu64 "\n", send_calls - send_errors);
+	printf("approx send rate:           %" PRIu64 "\n", (send_calls - send_errors) /
 	    duration);
-	printf("approx error rate: %d\n", (send_errors / send_calls));
-
-	return (0);
+	printf("approx error rate:          %" PRIu64 "\n", (send_errors / send_calls));
+	printf("approx Ethernet throughput: ");
+	if (family == AF_INET)
+		printf("%" PRIu64 " Mib/s\n", ((send_calls - send_errors) / duration ) *
+		(payloadsize + 8 + 20 + 14 ) * 8 / 1000 / 1000);
+	else if (family == AF_INET6)
+		printf("%" PRIu64 " Mib/s\n", ((send_calls - send_errors) / duration ) *
+		(payloadsize + 8 + 40 + 14 ) * 8 / 1000 / 1000);
+	else printf("CAN 'T DETERMINE family type %i\n",family);
+	printf("approx payload throughput:  %" PRIu64 " Mib/s\n", ((send_calls - send_errors) / 
+		duration ) * payloadsize * 8 / 1000 / 1000);
 }
 
 int
@@ -143,11 +185,15 @@
 {
 	long payloadsize, duration;
 	struct addrinfo hints, *res, *res0;
-	char *dummy, *packet;
-	int port, s, error;
+	char *dummy;
+	u_char *packet;
+	int family, port, s, error, nthreads = 1;
+	struct td_desc **tp;	
 	const char *cause = NULL;
+	struct timespec starttime, tmptime;
+	struct itimerval it;
 
-	if (argc != 5)
+	if (argc < 5)
 		usage();
 
 	memset(&hints, 0, sizeof(hints));
@@ -177,6 +223,11 @@
 		/*NOTREACHED*/
 	}
 
+	if (argc > 5)
+        nthreads = strtoul(argv[5], &dummy, 10);
+    if (nthreads < 1 || nthreads > 64)
+        usage();
+
 	packet = malloc(payloadsize);
 	if (packet == NULL) {
 		perror("malloc");
@@ -213,9 +264,46 @@
 		return (-1);
 		/*NOTREACHED*/
 	}
-
+	family=res->ai_family;
 	freeaddrinfo(res0);
 
-	return (blast_loop(s, duration, packet, payloadsize));
+	printf("netblast %d threads sending on UDP port %d\n",
+    nthreads, (u_short)port);
 
+	/*
+	 * Begin by recording time information stats.
+	 * Set the interval timer for when we want to wake up.
+	 * SIGALRM will set a flag indicating it's time to stop.  Note that there's
+	 * some overhead to the signal and timer setup, so the smaller the duration,
+	 * the higher the relative overhead.
+	 */
+
+	if (signal(SIGALRM, signal_handler) == SIG_ERR) {
+		perror("signal");
+		return (-1);
+	}
+
+	if (clock_getres(CLOCK_REALTIME, &tmptime) == -1) {
+		perror("clock_getres");
+		return (-1);
+	}
+
+	if (clock_gettime(CLOCK_REALTIME, &starttime) == -1) {
+		perror("clock_gettime");
+		return (-1);
+	}
+
+	it.it_interval.tv_sec = 0;
+	it.it_interval.tv_usec = 0;
+	it.it_value.tv_sec = duration;
+	it.it_value.tv_usec = 0;
+
+	if (setitimer(ITIMER_REAL, &it, NULL) < 0) {
+		perror("setitimer");
+		return (-1);
+	}
+
+    tp = make_threads(s, packet, payloadsize, nthreads);
+    main_thread(tp, duration, starttime,  tmptime, payloadsize, family, nthreads);
+
 }

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