View | Details | Raw Unified | Return to bug 179085 | Differences between
and this patch

Collapse All | Expand All

(-)tools/tools/netrate/netblast/Makefile (+3 lines)
Lines 4-8 Link Here
4
4
5
PROG=	netblast
5
PROG=	netblast
6
MAN=
6
MAN=
7
LDFLAGS += -lpthread
8
BINDIR=	/usr/local/bin
9
WARNS?= 3
7
10
8
.include <bsd.prog.mk>
11
.include <bsd.prog.mk>
(-)tools/tools/netrate/netblast/netblast.c (-83 / +228 lines)
Lines 28-35 Link Here
28
28
29
#include <sys/endian.h>
29
#include <sys/endian.h>
30
#include <sys/types.h>
30
#include <sys/types.h>
31
#include <stdbool.h>
31
#include <sys/socket.h>
32
#include <sys/socket.h>
32
#include <sys/time.h>
33
#include <sys/time.h>
34
#include <sys/sysctl.h> 	/* sysctl */
33
35
34
#include <netinet/in.h>
36
#include <netinet/in.h>
35
#include <netdb.h>			/* getaddrinfo */
37
#include <netdb.h>			/* getaddrinfo */
Lines 36-105 Link Here
36
38
37
#include <signal.h>
39
#include <signal.h>
38
#include <stdio.h>
40
#include <stdio.h>
41
#include <inttypes.h>
39
#include <stdlib.h>
42
#include <stdlib.h>
40
#include <string.h>
43
#include <string.h>
41
#include <unistd.h>			/* close */
44
#include <unistd.h>			/* close */
45
#include <sys/cpuset.h>
46
#include <pthread.h>
47
#include <pthread_np.h>
48
#include <fcntl.h>
49
#include <time.h>   /* clock_getres() */
42
50
51
/* sysctl wrapper to return the number of active CPUs
52
   function from netmap/pkt-gen.c */
53
static int
54
system_ncpus(void)
55
{
56
    int ncpus;
57
    int mib[2] = { CTL_HW, HW_NCPU };
58
    size_t len = sizeof(mib);
59
    sysctl(mib, 2, &ncpus, &len, NULL, 0);
60
    return (ncpus);
61
}
62
63
/* set the thread affinity
64
   function from netmap/pkt-gen.c */
65
static int
66
setaffinity(pthread_t me, int i)
67
{
68
    cpuset_t cpumask;
69
70
    if (i == -1)
71
        return 0;
72
73
    /* Set thread affinity affinity.*/
74
    CPU_ZERO(&cpumask);
75
    CPU_SET(i, &cpumask);
76
	if (pthread_setaffinity_np(me, sizeof(cpuset_t), &cpumask) != 0) {
77
        perror("Unable to set affinity");
78
        return 1;
79
    }
80
    return 0;
81
}
82
83
static int round_to(int n, int l)
84
{
85
    return ((n + l - 1)/l)*l;
86
}
87
43
static void
88
static void
44
usage(void)
89
usage(void)
45
{
90
{
46
91
47
	fprintf(stderr, "netblast [ip] [port] [payloadsize] [duration]\n");
92
	fprintf(stderr, "netblast [ip] [port] [payloadsize] [duration] [nthreads]\n");
48
	exit(-1);
93
	exit(-1);
49
}
94
}
50
95
51
static int	global_stop_flag;
96
static bool	global_stop_flag=true;
52
97
53
static void
98
static void
54
signal_handler(int signum __unused)
99
signal_handler(int signum __unused)
55
{
100
{
56
101
57
	global_stop_flag = 1;
102
	global_stop_flag = false;
58
}
103
}
59
104
60
/*
105
/*
61
 * Loop that blasts packets: begin by recording time information, resetting
106
 * Each socket uses multiple threads so the generator is
62
 * stats.  Set the interval timer for when we want to wake up.  Then go.
107
 * more efficient. A collector thread runs the stats.
63
 * SIGALRM will set a flag indicating it's time to stop.  Note that there's
64
 * some overhead to the signal and timer setup, so the smaller the duration,
65
 * the higher the relative overhead.
66
 */
108
 */
67
static int
109
struct td_desc {
68
blast_loop(int s, long duration, u_char *packet, u_int packet_len)
110
	pthread_t td_id;
111
	uint64_t counter; /* tx counter */
112
	uint64_t send_errors; /* tx send errors */
113
	uint64_t send_calls;    /* tx send calls */
114
	char *address, *port;
115
	int family;
116
	u_char *packet;
117
	u_int packet_len;
118
};
119
120
static void *
121
blast(void *data)
69
{
122
{
70
	struct timespec starttime, tmptime;
123
    struct td_desc *t = data;
71
	struct itimerval it;
124
	t->counter=0;
72
	u_int32_t counter;
125
	t->send_errors=0;
73
	int send_errors, send_calls;
126
	t->send_calls=0;
74
127
75
	if (signal(SIGALRM, signal_handler) == SIG_ERR) {
128
	struct addrinfo hints = {0}, *res = NULL , *res0 = NULL;
76
		perror("signal");
77
		return (-1);
78
	}
79
129
80
	if (clock_getres(CLOCK_REALTIME, &tmptime) == -1) {
130
	hints.ai_family = PF_UNSPEC;
81
		perror("clock_getres");
131
	hints.ai_socktype = SOCK_DGRAM;
82
		return (-1);
83
	}
84
132
85
	if (clock_gettime(CLOCK_REALTIME, &starttime) == -1) {
133
	int error = getaddrinfo(t->address,t->port, &hints, &res0);
86
		perror("clock_gettime");
134
	if (error) {
87
		return (-1);
135
		perror(gai_strerror(error));
136
		return NULL;
137
		/*NOTREACHED*/
88
	}
138
	}
89
139
90
	it.it_interval.tv_sec = 0;
140
	int s = -1; /* socket */
91
	it.it_interval.tv_usec = 0;
141
	int n = 1; /* dummy value for setsockopt */
92
	it.it_value.tv_sec = duration;
142
	const char *cause = NULL;
93
	it.it_value.tv_usec = 0;
94
143
95
	if (setitimer(ITIMER_REAL, &it, NULL) < 0) {
144
	for (res = res0; res; res = res->ai_next) {
96
		perror("setitimer");
145
		s = socket(res->ai_family, res->ai_socktype, 0);
97
		return (-1);
146
		if (s < 0) {
147
			cause = "socket";
148
			continue;
149
		}
150
151
		if (setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &n, sizeof n) < 0) {
152
            cause = "SO_REUSEPORT";
153
            close(s);
154
			s = -1;
155
            continue;
156
        }
157
158
		if (connect(s, res->ai_addr, res->ai_addrlen) < 0) {
159
			cause = "connect";
160
			close(s);
161
			s = -1;
162
			continue;
163
		}
164
165
		break;  /* okay we got one */
98
	}
166
	}
167
	if (s < 0) {
168
		perror(cause);
169
		return NULL;
170
		/*NOTREACHED*/
171
	}
99
172
100
	send_errors = send_calls = 0;
173
	/* Store address family for Ethernet bandwitdh estimation */
101
	counter = 0;
174
	t->family=res->ai_family;
102
	while (global_stop_flag == 0) {
175
176
	while (global_stop_flag) {
103
		/*
177
		/*
104
		 * We maintain and, if there's room, send a counter.  Note
178
		 * We maintain and, if there's room, send a counter.  Note
105
		 * that even if the error is purely local, we still increment
179
		 * that even if the error is purely local, we still increment
Lines 110-141 Link Here
110
		 * operation, causing the current sequence number also to be
184
		 * operation, causing the current sequence number also to be
111
		 * skipped.
185
		 * skipped.
112
		 */
186
		 */
113
		if (packet_len >= 4) {
187
		if (t->packet_len >= 4) {
114
			be32enc(packet, counter);
188
			be32enc(t->packet, t->counter);
115
			counter++;
189
			t->counter++;
116
		}
190
		}
117
		if (send(s, packet, packet_len, 0) < 0)
191
		if (send(s, t->packet, t->packet_len, 0) < 0)
118
			send_errors++;
192
			t->send_errors++;
119
		send_calls++;
193
		t->send_calls++;
120
	}
194
	}
195
    return NULL;
196
}
121
197
198
static struct td_desc **
199
make_threads(char *address, char *port, u_char *packet, u_int packet_len, int nthreads)
200
{
201
    int i;
202
    int lb = round_to(nthreads * sizeof (struct td_desc *), 64);
203
    int td_len = round_to(sizeof(struct td_desc), 64); // cache align
204
    char *m = calloc(1, lb + td_len * nthreads);
205
    struct td_desc **tp;
206
207
    /* pointers plus the structs */
208
    if (m == NULL) {
209
        perror("no room for pointers!");
210
        exit(1);
211
    }
212
    tp = (struct td_desc **)m;
213
    m += lb;    /* skip the pointers */
214
	int ncpu = system_ncpus();
215
    for (i = 0; i < nthreads; i++, m += td_len) {
216
        tp[i] = (struct td_desc *)m;
217
        tp[i]->address = address;
218
		tp[i]->port = port;
219
        tp[i]->packet = packet;
220
        tp[i]->packet_len = packet_len;
221
        if (pthread_create(&tp[i]->td_id, NULL, blast, tp[i])) {
222
            perror("unable to create thread");
223
            exit(1);
224
		}
225
		if (setaffinity(tp[i]->td_id, i % ncpu)) {
226
			perror("unable to set thread affinity");
227
        }
228
    }
229
    return tp;
230
}
231
232
static void
233
main_thread(struct td_desc **tp, long duration, struct timespec starttime, struct timespec tmptime, long payloadsize, int nthreads)
234
{
235
	uint64_t send_errors=0, send_calls=0;
122
	if (clock_gettime(CLOCK_REALTIME, &tmptime) == -1) {
236
	if (clock_gettime(CLOCK_REALTIME, &tmptime) == -1) {
123
		perror("clock_gettime");
237
		perror("clock_gettime");
124
		return (-1);
125
	}
238
	}
126
239
240
	for (int i = 0; i < nthreads; i++) {
241
		/* Wait for thread end */
242
		pthread_join( tp[i]->td_id, NULL);
243
		send_calls+=tp[i]->send_calls;
244
		send_errors+=tp[i]->send_errors;
245
    }
246
127
	printf("\n");
247
	printf("\n");
128
	printf("start:             %zd.%09lu\n", starttime.tv_sec,
248
	printf("start:                      %zd.%09lu\n", starttime.tv_sec,
129
	    starttime.tv_nsec);
249
	    starttime.tv_nsec);
130
	printf("finish:            %zd.%09lu\n", tmptime.tv_sec,
250
	printf("finish:                     %zd.%09lu\n", tmptime.tv_sec,
131
	    tmptime.tv_nsec);
251
	    tmptime.tv_nsec);
132
	printf("send calls:        %d\n", send_calls);
252
	printf("send calls:                 %" PRIu64 "\n", send_calls);
133
	printf("send errors:       %d\n", send_errors);
253
	printf("send errors:                %" PRIu64 "\n", send_errors);
134
	printf("approx send rate:  %ld\n", (send_calls - send_errors) /
254
	printf("send success:               %" PRIu64 "\n", send_calls - send_errors);
255
	printf("approx send rate:           %" PRIu64 "\n", (send_calls - send_errors) /
135
	    duration);
256
	    duration);
136
	printf("approx error rate: %d\n", (send_errors / send_calls));
257
	printf("approx error rate:          %" PRIu64 "\n", (send_errors / send_calls));
137
258
	printf("approx Ethernet throughput: ");
138
	return (0);
259
	if (tp[0]->family == AF_INET)
260
		printf("%" PRIu64 " Mib/s\n", ((send_calls - send_errors) / duration ) *
261
		(payloadsize + 8 + 20 + 14 ) * 8 / 1000 / 1000);
262
	else if (tp[0]->family == AF_INET6)
263
		printf("%" PRIu64 " Mib/s\n", ((send_calls - send_errors) / duration ) *
264
		(payloadsize + 8 + 40 + 14 ) * 8 / 1000 / 1000);
265
	else printf("CAN 'T DETERMINE family type %i\n",tp[0]->family);
266
	printf("approx payload throughput:  %" PRIu64 " Mib/s\n", ((send_calls - send_errors) /
267
		duration ) * payloadsize * 8 / 1000 / 1000);
139
}
268
}
140
269
141
int
270
int
Lines 142-159 Link Here
142
main(int argc, char *argv[])
271
main(int argc, char *argv[])
143
{
272
{
144
	long payloadsize, duration;
273
	long payloadsize, duration;
145
	struct addrinfo hints, *res, *res0;
274
	char *dummy;
146
	char *dummy, *packet;
275
	u_char *packet;
147
	int port, s, error;
276
	int port, nthreads = 1;
148
	const char *cause = NULL;
277
	struct td_desc **tp;
278
	struct timespec starttime, tmptime;
279
	struct itimerval it;
149
280
150
	if (argc != 5)
281
282
283
	if (argc < 5)
151
		usage();
284
		usage();
152
285
153
	memset(&hints, 0, sizeof(hints));
154
	hints.ai_family = PF_UNSPEC;
155
	hints.ai_socktype = SOCK_DGRAM;
156
157
	port = strtoul(argv[2], &dummy, 10);
286
	port = strtoul(argv[2], &dummy, 10);
158
	if (port < 1 || port > 65535 || *dummy != '\0') {
287
	if (port < 1 || port > 65535 || *dummy != '\0') {
159
		fprintf(stderr, "Invalid port number: %s\n", argv[2]);
288
		fprintf(stderr, "Invalid port number: %s\n", argv[2]);
Lines 177-182 Link Here
177
		/*NOTREACHED*/
306
		/*NOTREACHED*/
178
	}
307
	}
179
308
309
	if (argc > 5)
310
        	nthreads = strtoul(argv[5], &dummy, 10);
311
	if (nthreads < 1)
312
		usage();
313
	int ncpu = system_ncpus();
314
	if (nthreads > ncpu) {
315
		printf("WARNING: %d threads but only %d core(s) available\n", nthreads, ncpu);
316
	}
317
180
	packet = malloc(payloadsize);
318
	packet = malloc(payloadsize);
181
	if (packet == NULL) {
319
	if (packet == NULL) {
182
		perror("malloc");
320
		perror("malloc");
Lines 185-221 Link Here
185
	}
323
	}
186
324
187
	bzero(packet, payloadsize);
325
	bzero(packet, payloadsize);
188
	error = getaddrinfo(argv[1],argv[2], &hints, &res0);
326
189
	if (error) {
327
	printf("netblast %d threads sending on UDP port %d during %lu seconds\n",
190
		perror(gai_strerror(error));
328
    nthreads, (u_short)port, duration);
329
330
	/*
331
	 * Begin by recording time information stats.
332
	 * Set the interval timer for when we want to wake up.
333
	 * SIGALRM will set a flag indicating it's time to stop.  Note that there's
334
	 * some overhead to the signal and timer setup, so the smaller the duration,
335
	 * the higher the relative overhead.
336
	 */
337
338
	if (signal(SIGALRM, signal_handler) == SIG_ERR) {
339
		perror("signal");
191
		return (-1);
340
		return (-1);
192
		/*NOTREACHED*/
193
	}
341
	}
194
	s = -1;
195
	for (res = res0; res; res = res->ai_next) {
196
		s = socket(res->ai_family, res->ai_socktype, 0);
197
		if (s < 0) {
198
			cause = "socket";
199
			continue;
200
		}
201
342
202
		if (connect(s, res->ai_addr, res->ai_addrlen) < 0) {
343
	if (clock_getres(CLOCK_REALTIME, &tmptime) == -1) {
203
			cause = "connect";
344
		perror("clock_getres");
204
			close(s);
345
		return (-1);
205
			s = -1;
346
	}
206
			continue;
207
		}
208
347
209
		break;  /* okay we got one */
348
	if (clock_gettime(CLOCK_REALTIME, &starttime) == -1) {
349
		perror("clock_gettime");
350
		return (-1);
210
	}
351
	}
211
	if (s < 0) {
352
212
		perror(cause);
353
	it.it_interval.tv_sec = 0;
354
	it.it_interval.tv_usec = 0;
355
	it.it_value.tv_sec = duration;
356
	it.it_value.tv_usec = 0;
357
358
	if (setitimer(ITIMER_REAL, &it, NULL) < 0) {
359
		perror("setitimer");
213
		return (-1);
360
		return (-1);
214
		/*NOTREACHED*/
215
	}
361
	}
216
362
217
	freeaddrinfo(res0);
363
    tp = make_threads(argv[1],argv[2], packet, payloadsize, nthreads);
364
    main_thread(tp, duration, starttime,  tmptime, payloadsize, nthreads);
218
365
219
	return (blast_loop(s, duration, packet, payloadsize));
220
221
}
366
}

Return to bug 179085