FreeBSD Bugzilla – Attachment 216402 Details for
Bug 179085
[tools] [patch] pthread patch for netblast
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
patch for FreeBSD head
freebsd.netblast.PR179085.patch (text/plain), 11.16 KB, created by
Olivier Cochard
on 2020-07-12 06:40:40 UTC
(
hide
)
Description:
patch for FreeBSD head
Filename:
MIME Type:
Creator:
Olivier Cochard
Created:
2020-07-12 06:40:40 UTC
Size:
11.16 KB
patch
obsolete
>Index: tools/tools/netrate/netblast/Makefile >=================================================================== >--- tools/tools/netrate/netblast/Makefile (revision 361538) >+++ tools/tools/netrate/netblast/Makefile (working copy) >@@ -4,5 +4,8 @@ > > PROG= netblast > MAN= >+LDFLAGS += -lpthread >+BINDIR= /usr/local/bin >+WARNS?= 3 > > .include <bsd.prog.mk> >Index: tools/tools/netrate/netblast/netblast.c >=================================================================== >--- tools/tools/netrate/netblast/netblast.c (revision 361538) >+++ tools/tools/netrate/netblast/netblast.c (working copy) >@@ -28,8 +28,10 @@ > > #include <sys/endian.h> > #include <sys/types.h> >+#include <stdbool.h> > #include <sys/socket.h> > #include <sys/time.h> >+#include <sys/sysctl.h> /* sysctl */ > > #include <netinet/in.h> > #include <netdb.h> /* getaddrinfo */ >@@ -36,70 +38,142 @@ > > #include <signal.h> > #include <stdio.h> >+#include <inttypes.h> > #include <stdlib.h> > #include <string.h> > #include <unistd.h> /* close */ >+#include <sys/cpuset.h> >+#include <pthread.h> >+#include <pthread_np.h> >+#include <fcntl.h> >+#include <time.h> /* clock_getres() */ > >+/* sysctl wrapper to return the number of active CPUs >+ function from netmap/pkt-gen.c */ >+static int >+system_ncpus(void) >+{ >+ int ncpus; >+ int mib[2] = { CTL_HW, HW_NCPU }; >+ size_t len = sizeof(mib); >+ sysctl(mib, 2, &ncpus, &len, NULL, 0); >+ return (ncpus); >+} >+ >+/* set the thread affinity >+ function from netmap/pkt-gen.c */ >+static int >+setaffinity(pthread_t me, int i) >+{ >+ cpuset_t cpumask; >+ >+ if (i == -1) >+ return 0; >+ >+ /* Set thread affinity affinity.*/ >+ CPU_ZERO(&cpumask); >+ CPU_SET(i, &cpumask); >+ if (pthread_setaffinity_np(me, sizeof(cpuset_t), &cpumask) != 0) { >+ perror("Unable to set affinity"); >+ return 1; >+ } >+ return 0; >+} >+ >+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 bool global_stop_flag=true; > > static void > signal_handler(int signum __unused) > { > >- global_stop_flag = 1; >+ global_stop_flag = false; > } > > /* >- * 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 */ >+ char *address, *port; >+ int family; >+ 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; >+ struct td_desc *t = data; >+ t->counter=0; >+ t->send_errors=0; >+ t->send_calls=0; > >- if (signal(SIGALRM, signal_handler) == SIG_ERR) { >- perror("signal"); >- return (-1); >- } >+ struct addrinfo hints = {0}, *res = NULL , *res0 = NULL; > >- if (clock_getres(CLOCK_REALTIME, &tmptime) == -1) { >- perror("clock_getres"); >- return (-1); >- } >+ hints.ai_family = PF_UNSPEC; >+ hints.ai_socktype = SOCK_DGRAM; > >- if (clock_gettime(CLOCK_REALTIME, &starttime) == -1) { >- perror("clock_gettime"); >- return (-1); >+ int error = getaddrinfo(t->address,t->port, &hints, &res0); >+ if (error) { >+ perror(gai_strerror(error)); >+ return NULL; >+ /*NOTREACHED*/ > } > >- it.it_interval.tv_sec = 0; >- it.it_interval.tv_usec = 0; >- it.it_value.tv_sec = duration; >- it.it_value.tv_usec = 0; >+ int s = -1; /* socket */ >+ int n = 1; /* dummy value for setsockopt */ >+ const char *cause = NULL; > >- if (setitimer(ITIMER_REAL, &it, NULL) < 0) { >- perror("setitimer"); >- return (-1); >+ for (res = res0; res; res = res->ai_next) { >+ s = socket(res->ai_family, res->ai_socktype, 0); >+ if (s < 0) { >+ cause = "socket"; >+ continue; >+ } >+ >+ if (setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &n, sizeof n) < 0) { >+ cause = "SO_REUSEPORT"; >+ close(s); >+ s = -1; >+ continue; >+ } >+ >+ if (connect(s, res->ai_addr, res->ai_addrlen) < 0) { >+ cause = "connect"; >+ close(s); >+ s = -1; >+ continue; >+ } >+ >+ break; /* okay we got one */ > } >+ if (s < 0) { >+ perror(cause); >+ return NULL; >+ /*NOTREACHED*/ >+ } > >- send_errors = send_calls = 0; >- counter = 0; >- while (global_stop_flag == 0) { >+ /* Store address family for Ethernet bandwitdh estimation */ >+ t->family=res->ai_family; >+ >+ while (global_stop_flag) { > /* > * We maintain and, if there's room, send a counter. Note > * that even if the error is purely local, we still increment >@@ -110,32 +184,87 @@ > * 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(s, t->packet, t->packet_len, 0) < 0) >+ t->send_errors++; >+ t->send_calls++; > } >+ return NULL; >+} > >+static struct td_desc ** >+make_threads(char *address, char *port, 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 */ >+ int ncpu = system_ncpus(); >+ for (i = 0; i < nthreads; i++, m += td_len) { >+ tp[i] = (struct td_desc *)m; >+ tp[i]->address = address; >+ tp[i]->port = port; >+ 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); >+ } >+ if (setaffinity(tp[i]->td_id, i % ncpu)) { >+ perror("unable to set thread affinity"); >+ } >+ } >+ return tp; >+} >+ >+static void >+main_thread(struct td_desc **tp, long duration, struct timespec starttime, struct timespec tmptime, long payloadsize, int nthreads) >+{ >+ uint64_t send_errors=0, send_calls=0; > if (clock_gettime(CLOCK_REALTIME, &tmptime) == -1) { > perror("clock_gettime"); >- return (-1); > } > >+ for (int 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 (tp[0]->family == AF_INET) >+ printf("%" PRIu64 " Mib/s\n", ((send_calls - send_errors) / duration ) * >+ (payloadsize + 8 + 20 + 14 ) * 8 / 1000 / 1000); >+ else if (tp[0]->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",tp[0]->family); >+ printf("approx payload throughput: %" PRIu64 " Mib/s\n", ((send_calls - send_errors) / >+ duration ) * payloadsize * 8 / 1000 / 1000); > } > > int >@@ -142,18 +271,18 @@ > main(int argc, char *argv[]) > { > long payloadsize, duration; >- struct addrinfo hints, *res, *res0; >- char *dummy, *packet; >- int port, s, error; >- const char *cause = NULL; >+ char *dummy; >+ u_char *packet; >+ int port, nthreads = 1; >+ struct td_desc **tp; >+ struct timespec starttime, tmptime; >+ struct itimerval it; > >- if (argc != 5) >+ >+ >+ if (argc < 5) > usage(); > >- memset(&hints, 0, sizeof(hints)); >- hints.ai_family = PF_UNSPEC; >- hints.ai_socktype = SOCK_DGRAM; >- > port = strtoul(argv[2], &dummy, 10); > if (port < 1 || port > 65535 || *dummy != '\0') { > fprintf(stderr, "Invalid port number: %s\n", argv[2]); >@@ -177,6 +306,15 @@ > /*NOTREACHED*/ > } > >+ if (argc > 5) >+ nthreads = strtoul(argv[5], &dummy, 10); >+ if (nthreads < 1) >+ usage(); >+ int ncpu = system_ncpus(); >+ if (nthreads > ncpu) { >+ printf("WARNING: %d threads but only %d core(s) available\n", nthreads, ncpu); >+ } >+ > packet = malloc(payloadsize); > if (packet == NULL) { > perror("malloc"); >@@ -185,37 +323,44 @@ > } > > bzero(packet, payloadsize); >- error = getaddrinfo(argv[1],argv[2], &hints, &res0); >- if (error) { >- perror(gai_strerror(error)); >+ >+ printf("netblast %d threads sending on UDP port %d during %lu seconds\n", >+ nthreads, (u_short)port, duration); >+ >+ /* >+ * 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); >- /*NOTREACHED*/ > } >- s = -1; >- for (res = res0; res; res = res->ai_next) { >- s = socket(res->ai_family, res->ai_socktype, 0); >- if (s < 0) { >- cause = "socket"; >- continue; >- } > >- if (connect(s, res->ai_addr, res->ai_addrlen) < 0) { >- cause = "connect"; >- close(s); >- s = -1; >- continue; >- } >+ if (clock_getres(CLOCK_REALTIME, &tmptime) == -1) { >+ perror("clock_getres"); >+ return (-1); >+ } > >- break; /* okay we got one */ >+ if (clock_gettime(CLOCK_REALTIME, &starttime) == -1) { >+ perror("clock_gettime"); >+ return (-1); > } >- if (s < 0) { >- perror(cause); >+ >+ 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); >- /*NOTREACHED*/ > } > >- freeaddrinfo(res0); >+ tp = make_threads(argv[1],argv[2], packet, payloadsize, nthreads); >+ main_thread(tp, duration, starttime, tmptime, payloadsize, nthreads); > >- return (blast_loop(s, duration, packet, payloadsize)); >- > }
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 179085
:
134413
|
134414
|
134415
| 216402