Lines 40-54
Link Here
|
40 |
#include <string.h> |
40 |
#include <string.h> |
41 |
#include <unistd.h> /* close */ |
41 |
#include <unistd.h> /* close */ |
42 |
|
42 |
|
|
|
43 |
#include <pthread.h> |
44 |
#include <fcntl.h> |
45 |
#include <time.h> /* clock_getres() */ |
46 |
|
47 |
static int round_to(int n, int l) |
48 |
{ |
49 |
return ((n + l - 1)/l)*l; |
50 |
} |
51 |
|
43 |
static void |
52 |
static void |
44 |
usage(void) |
53 |
usage(void) |
45 |
{ |
54 |
{ |
46 |
|
55 |
|
47 |
fprintf(stderr, "netblast [ip] [port] [payloadsize] [duration]\n"); |
56 |
fprintf(stderr, "netblast [ip] [port] [payloadsize] [duration] [nthreads]\n"); |
48 |
exit(-1); |
57 |
exit(-1); |
49 |
} |
58 |
} |
50 |
|
59 |
|
51 |
static int global_stop_flag; |
60 |
static int global_stop_flag=0; |
52 |
|
61 |
|
53 |
static void |
62 |
static void |
54 |
signal_handler(int signum __unused) |
63 |
signal_handler(int signum __unused) |
Lines 57-104
Link Here
|
57 |
global_stop_flag = 1; |
66 |
global_stop_flag = 1; |
58 |
} |
67 |
} |
59 |
|
68 |
|
|
|
69 |
|
60 |
/* |
70 |
/* |
61 |
* Loop that blasts packets: begin by recording time information, resetting |
71 |
* Each socket uses multiple threads so the generator is |
62 |
* stats. Set the interval timer for when we want to wake up. Then go. |
72 |
* 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 |
*/ |
73 |
*/ |
67 |
static int |
74 |
struct td_desc { |
68 |
blast_loop(int s, long duration, u_char *packet, u_int packet_len) |
75 |
pthread_t td_id; |
69 |
{ |
76 |
uint64_t counter; /* tx counter */ |
70 |
struct timespec starttime, tmptime; |
77 |
uint64_t send_errors; /* tx send errors */ |
71 |
struct itimerval it; |
78 |
uint64_t send_calls; /* tx send calls */ |
72 |
u_int32_t counter; |
79 |
int s; |
73 |
int send_errors, send_calls; |
80 |
u_char *packet; |
74 |
|
81 |
u_int packet_len; |
75 |
if (signal(SIGALRM, signal_handler) == SIG_ERR) { |
82 |
}; |
76 |
perror("signal"); |
|
|
77 |
return (-1); |
78 |
} |
79 |
|
80 |
if (clock_getres(CLOCK_REALTIME, &tmptime) == -1) { |
81 |
perror("clock_getres"); |
82 |
return (-1); |
83 |
} |
84 |
|
85 |
if (clock_gettime(CLOCK_REALTIME, &starttime) == -1) { |
86 |
perror("clock_gettime"); |
87 |
return (-1); |
88 |
} |
89 |
|
90 |
it.it_interval.tv_sec = 0; |
91 |
it.it_interval.tv_usec = 0; |
92 |
it.it_value.tv_sec = duration; |
93 |
it.it_value.tv_usec = 0; |
94 |
|
83 |
|
95 |
if (setitimer(ITIMER_REAL, &it, NULL) < 0) { |
84 |
static void * |
96 |
perror("setitimer"); |
85 |
blast(void *data) |
97 |
return (-1); |
86 |
{ |
98 |
} |
87 |
struct td_desc *t = data; |
99 |
|
88 |
t->counter=0; |
100 |
send_errors = send_calls = 0; |
89 |
t->send_errors=0; |
101 |
counter = 0; |
90 |
t->send_calls=0; |
102 |
while (global_stop_flag == 0) { |
91 |
while (global_stop_flag == 0) { |
103 |
/* |
92 |
/* |
104 |
* We maintain and, if there's room, send a counter. Note |
93 |
* We maintain and, if there's room, send a counter. Note |
Lines 110-141
Link Here
|
110 |
* operation, causing the current sequence number also to be |
99 |
* operation, causing the current sequence number also to be |
111 |
* skipped. |
100 |
* skipped. |
112 |
*/ |
101 |
*/ |
113 |
if (packet_len >= 4) { |
102 |
if (t->packet_len >= 4) { |
114 |
be32enc(packet, counter); |
103 |
be32enc(t->packet, t->counter); |
115 |
counter++; |
104 |
t->counter++; |
116 |
} |
105 |
} |
117 |
if (send(s, packet, packet_len, 0) < 0) |
106 |
if (send(t->s, t->packet, t->packet_len, 0) < 0) |
118 |
send_errors++; |
107 |
t->send_errors++; |
119 |
send_calls++; |
108 |
t->send_calls++; |
120 |
} |
109 |
} |
|
|
110 |
return NULL; |
111 |
} |
112 |
|
113 |
static struct td_desc ** |
114 |
make_threads(int s, u_char *packet, u_int packet_len, int nthreads) |
115 |
{ |
116 |
int i; |
117 |
int lb = round_to(nthreads * sizeof (struct td_desc *), 64); |
118 |
int td_len = round_to(sizeof(struct td_desc), 64); // cache align |
119 |
char *m = calloc(1, lb + td_len * nthreads); |
120 |
struct td_desc **tp; |
121 |
|
122 |
/* pointers plus the structs */ |
123 |
if (m == NULL) { |
124 |
perror("no room for pointers!"); |
125 |
exit(1); |
126 |
} |
127 |
tp = (struct td_desc **)m; |
128 |
m += lb; /* skip the pointers */ |
129 |
for (i = 0; i < nthreads; i++, m += td_len) { |
130 |
tp[i] = (struct td_desc *)m; |
131 |
tp[i]->s = s; |
132 |
tp[i]->packet = packet; |
133 |
tp[i]->packet_len = packet_len; |
134 |
if (pthread_create(&tp[i]->td_id, NULL, blast, tp[i])) { |
135 |
perror("unable to create thread"); |
136 |
exit(1); |
137 |
} |
138 |
} |
139 |
return tp; |
140 |
} |
121 |
|
141 |
|
|
|
142 |
|
143 |
static void |
144 |
main_thread(struct td_desc **tp, long duration, struct timespec starttime, struct timespec tmptime, long payloadsize, int family, int nthreads) |
145 |
{ |
146 |
uint64_t send_errors=0, send_calls=0; |
147 |
int i; |
122 |
if (clock_gettime(CLOCK_REALTIME, &tmptime) == -1) { |
148 |
if (clock_gettime(CLOCK_REALTIME, &tmptime) == -1) { |
123 |
perror("clock_gettime"); |
149 |
perror("clock_gettime"); |
124 |
return (-1); |
|
|
125 |
} |
150 |
} |
126 |
|
151 |
|
|
|
152 |
for (i = 0; i < nthreads; i++) { |
153 |
/* Wait for thread end */ |
154 |
pthread_join( tp[i]->td_id, NULL); |
155 |
send_calls+=tp[i]->send_calls; |
156 |
send_errors+=tp[i]->send_errors; |
157 |
} |
158 |
|
127 |
printf("\n"); |
159 |
printf("\n"); |
128 |
printf("start: %zd.%09lu\n", starttime.tv_sec, |
160 |
printf("start: %zd.%09lu\n", starttime.tv_sec, |
129 |
starttime.tv_nsec); |
161 |
starttime.tv_nsec); |
130 |
printf("finish: %zd.%09lu\n", tmptime.tv_sec, |
162 |
printf("finish: %zd.%09lu\n", tmptime.tv_sec, |
131 |
tmptime.tv_nsec); |
163 |
tmptime.tv_nsec); |
132 |
printf("send calls: %d\n", send_calls); |
164 |
printf("send calls: %lu\n", send_calls); |
133 |
printf("send errors: %d\n", send_errors); |
165 |
printf("send errors: %lu\n", send_errors); |
134 |
printf("approx send rate: %ld\n", (send_calls - send_errors) / |
166 |
printf("send success: %lu\n", send_calls - send_errors); |
|
|
167 |
printf("approx send rate: %lu\n", (send_calls - send_errors) / |
135 |
duration); |
168 |
duration); |
136 |
printf("approx error rate: %d\n", (send_errors / send_calls)); |
169 |
printf("approx error rate: %lu\n", (send_errors / send_calls)); |
137 |
|
170 |
printf("approx Ethernet throughput: "); |
138 |
return (0); |
171 |
if (family == AF_INET) |
|
|
172 |
printf("%ld Mib/s\n", ((send_calls - send_errors) / duration ) * |
173 |
(payloadsize + 8 + 20 + 14 ) * 8 / 1000 / 1000); |
174 |
else if (family == AF_INET6) |
175 |
printf("%ld Mib/s\n", ((send_calls - send_errors) / duration ) * |
176 |
(payloadsize + 8 + 40 + 14 ) * 8 / 1000 / 1000); |
177 |
else printf("CAN 'T DETERMINE family type %i\n",family); |
178 |
printf("approx payload throughput: %ld Mib/s\n", ((send_calls - send_errors) / |
179 |
duration ) * payloadsize * 8 / 1000 / 1000); |
139 |
} |
180 |
} |
140 |
|
181 |
|
141 |
int |
182 |
int |
Lines 143-153
Link Here
|
143 |
{ |
184 |
{ |
144 |
long payloadsize, duration; |
185 |
long payloadsize, duration; |
145 |
struct addrinfo hints, *res, *res0; |
186 |
struct addrinfo hints, *res, *res0; |
146 |
char *dummy, *packet; |
187 |
char *dummy; |
147 |
int port, s, error; |
188 |
u_char *packet; |
|
|
189 |
int family, port, s, error, nthreads = 1; |
190 |
struct td_desc **tp; |
148 |
const char *cause = NULL; |
191 |
const char *cause = NULL; |
|
|
192 |
struct timespec starttime, tmptime; |
193 |
struct itimerval it; |
149 |
|
194 |
|
150 |
if (argc != 5) |
195 |
if (argc < 5) |
151 |
usage(); |
196 |
usage(); |
152 |
|
197 |
|
153 |
memset(&hints, 0, sizeof(hints)); |
198 |
memset(&hints, 0, sizeof(hints)); |
Lines 177-182
Link Here
|
177 |
/*NOTREACHED*/ |
222 |
/*NOTREACHED*/ |
178 |
} |
223 |
} |
179 |
|
224 |
|
|
|
225 |
if (argc > 5) |
226 |
nthreads = strtoul(argv[5], &dummy, 10); |
227 |
if (nthreads < 1 || nthreads > 64) |
228 |
usage(); |
229 |
|
180 |
packet = malloc(payloadsize); |
230 |
packet = malloc(payloadsize); |
181 |
if (packet == NULL) { |
231 |
if (packet == NULL) { |
182 |
perror("malloc"); |
232 |
perror("malloc"); |
Lines 213-221
Link Here
|
213 |
return (-1); |
263 |
return (-1); |
214 |
/*NOTREACHED*/ |
264 |
/*NOTREACHED*/ |
215 |
} |
265 |
} |
216 |
|
266 |
family=res->ai_family; |
217 |
freeaddrinfo(res0); |
267 |
freeaddrinfo(res0); |
218 |
|
268 |
|
219 |
return (blast_loop(s, duration, packet, payloadsize)); |
269 |
printf("netblast %d threads sending on UDP port %d\n", |
|
|
270 |
nthreads, (u_short)port); |
271 |
|
272 |
/* |
273 |
* Begin by recording time information stats. |
274 |
* Set the interval timer for when we want to wake up. |
275 |
* SIGALRM will set a flag indicating it's time to stop. Note that there's |
276 |
* some overhead to the signal and timer setup, so the smaller the duration, |
277 |
* the higher the relative overhead. |
278 |
*/ |
279 |
|
280 |
if (signal(SIGALRM, signal_handler) == SIG_ERR) { |
281 |
perror("signal"); |
282 |
return (-1); |
283 |
} |
284 |
|
285 |
if (clock_getres(CLOCK_REALTIME, &tmptime) == -1) { |
286 |
perror("clock_getres"); |
287 |
return (-1); |
288 |
} |
289 |
|
290 |
if (clock_gettime(CLOCK_REALTIME, &starttime) == -1) { |
291 |
perror("clock_gettime"); |
292 |
return (-1); |
293 |
} |
294 |
|
295 |
it.it_interval.tv_sec = 0; |
296 |
it.it_interval.tv_usec = 0; |
297 |
it.it_value.tv_sec = duration; |
298 |
it.it_value.tv_usec = 0; |
299 |
|
300 |
if (setitimer(ITIMER_REAL, &it, NULL) < 0) { |
301 |
perror("setitimer"); |
302 |
return (-1); |
303 |
} |
304 |
|
305 |
tp = make_threads(s, packet, payloadsize, nthreads); |
306 |
main_thread(tp, duration, starttime, tmptime, payloadsize, family, nthreads); |
220 |
|
307 |
|
221 |
} |
308 |
} |