Annotation of elwix/patches/freebsd.netblast.PR179085.patch, revision 1.2
1.2 ! misho 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>