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>