tools/kq_connect_client: Add option to bind process to cpu.
[dragonfly.git] / tools / tools / netrate / accept_connect / kq_connect_client / kq_connect_client.c
blobec0593a99ac845d730f7ea20c509a6dcb8ef0a8c
1 #include <sys/types.h>
2 #include <sys/event.h>
3 #include <sys/ioctl.h>
4 #include <sys/mman.h>
5 #include <sys/socket.h>
6 #include <sys/sysctl.h>
7 #include <sys/time.h>
8 #include <sys/usched.h>
9 #include <sys/wait.h>
11 #include <arpa/inet.h>
12 #include <netinet/in.h>
14 #include <err.h>
15 #include <errno.h>
16 #include <signal.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <unistd.h>
22 #ifndef timespecsub
23 #define timespecsub(vvp, uvp) \
24 do { \
25 (vvp)->tv_sec -= (uvp)->tv_sec; \
26 (vvp)->tv_nsec -= (uvp)->tv_nsec; \
27 if ((vvp)->tv_nsec < 0) { \
28 (vvp)->tv_sec--; \
29 (vvp)->tv_nsec += 1000000000; \
30 } \
31 } while (0)
32 #endif
34 static void mainloop(const struct sockaddr_in *, int, int, long, u_long *,
35 int, int);
37 static int bindcpu;
38 static int cpucnt;
40 static void
41 usage(const char *cmd)
43 fprintf(stderr, "%s -4 inet4 [-4 inet4_1] -p port "
44 "[-i n_instance] [-c conn_max] [-l duration] [-u] [-B]\n", cmd);
45 exit(1);
48 int
49 main(int argc, char *argv[])
51 struct sockaddr_in *in, *tmp;
52 int opt, ninst, nconn, i, in_max, in_cnt, do_udp;
53 long dur;
54 u_long *result, sum;
55 u_short port;
56 size_t prm_len;
58 prm_len = sizeof(cpucnt);
59 if (sysctlbyname("hw.ncpu", &cpucnt, &prm_len, NULL, 0) != 0)
60 err(2, "sysctl hw.ncpu failed");
61 ninst = cpucnt;
63 nconn = 8;
64 dur = 10;
65 port = 0;
66 do_udp = 0;
68 in_max = 8;
69 in = calloc(in_max, sizeof(struct sockaddr_in));
70 if (in == NULL)
71 err(1, "calloc failed");
72 in_cnt = 0;
74 while ((opt = getopt(argc, argv, "4:Bc:i:l:p:u")) != -1) {
75 switch (opt) {
76 case '4':
77 if (in_cnt >= in_max) {
78 struct sockaddr_in *old_in = in;
79 int old_in_max = in_max;
81 in_max <<= 1;
82 in = calloc(in_max, sizeof(struct sockaddr_in));
83 if (in == NULL)
84 err(1, "calloc failed");
86 memcpy(in, old_in,
87 old_in_max * sizeof(struct sockaddr_in));
88 free(old_in);
91 tmp = &in[in_cnt];
92 if (inet_pton(AF_INET, optarg, &tmp->sin_addr) <= 0) {
93 fprintf(stderr, "invalid inet address %s\n",
94 optarg);
95 usage(argv[0]);
97 ++in_cnt;
98 break;
100 case 'B':
101 bindcpu = 1;
102 break;
104 case 'c':
105 nconn = atoi(optarg);
106 break;
108 case 'i':
109 ninst = atoi(optarg);
110 break;
112 case 'l':
113 dur = strtol(optarg, NULL, 10);
114 break;
116 case 'p':
117 port = htons(atoi(optarg));
118 break;
120 case 'u':
121 do_udp = 1;
122 break;
124 default:
125 usage(argv[0]);
129 if (ninst < 1 || dur < 1 || nconn < 1 || port == 0 || in_cnt == 0)
130 usage(argv[0]);
132 for (i = 0; i < in_cnt; ++i) {
133 tmp = &in[i];
134 tmp->sin_family = AF_INET;
135 tmp->sin_port = port;
138 result = mmap(NULL, ninst * sizeof(u_long), PROT_READ | PROT_WRITE,
139 MAP_ANON | MAP_SHARED, -1, 0);
140 if (result == MAP_FAILED)
141 err(1, "mmap failed");
142 memset(result, 0, ninst * sizeof(u_long));
144 for (i = 0; i < ninst; ++i) {
145 pid_t pid;
147 pid = fork();
148 if (pid == 0) {
149 mainloop(in, in_cnt, nconn, dur, &result[i], do_udp, i);
150 exit(0);
151 } else if (pid < 0) {
152 err(1, "fork failed");
156 for (i = 0; i < ninst; ++i) {
157 pid_t pid;
159 pid = waitpid(-1, NULL, 0);
160 if (pid < 0)
161 err(1, "waitpid failed");
164 sum = 0;
165 for (i = 0; i < ninst; ++i)
166 sum += result[i];
167 printf("%lu\n", sum);
169 exit(0);
172 static void
173 udp_send(const struct sockaddr_in *in)
175 uint8_t d[18];
176 int s;
178 s = socket(AF_INET, SOCK_DGRAM, 0);
179 if (s < 0) {
180 warn("socket DGRAM failed");
181 return;
184 if (connect(s, (const struct sockaddr *)in, sizeof(*in)) < 0) {
185 warn("connect DGRAM failed");
186 goto done;
189 write(s, d, sizeof(d));
190 done:
191 close(s);
194 static void
195 mainloop(const struct sockaddr_in *in, int in_cnt, int nconn_max,
196 long dur, u_long *res, int do_udp, int inst)
198 struct timespec start, end;
199 struct kevent *evt_change0, *evt;
200 int kq, nchange = 0, nconn = 0, nevt_max;
201 u_long count = 0;
202 double time_us;
203 u_int in_idx = 0;
204 int nblock = 1;
206 if (bindcpu) {
207 int cpu = inst % cpucnt;
209 usched_set(getpid(), USCHED_SET_CPU, &cpu, sizeof(cpu));
212 kq = kqueue();
213 if (kq < 0)
214 err(1, "kqueue failed");
216 nevt_max = nconn_max + 1; /* timer */
218 evt_change0 = malloc(nevt_max * sizeof(struct kevent));
219 if (evt_change0 == NULL)
220 err(1, "malloc evt_change failed");
222 evt = malloc(nevt_max * sizeof(struct kevent));
223 if (evt == NULL)
224 err(1, "malloc evt failed");
226 EV_SET(&evt_change0[0], 0, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 0,
227 dur * 1000L, NULL);
228 nchange = 1;
230 clock_gettime(CLOCK_MONOTONIC_PRECISE, &start);
231 for (;;) {
232 struct kevent *evt_change = NULL;
233 int n, i, done = 0;
235 while (nconn < nconn_max) {
236 const struct sockaddr_in *tmp;
237 int s;
239 tmp = &in[in_idx % in_cnt];
240 ++in_idx;
242 if (do_udp)
243 udp_send(tmp);
245 s = socket(AF_INET, SOCK_STREAM, 0);
246 if (s < 0)
247 err(1, "socket failed");
249 if (ioctl(s, FIONBIO, &nblock, sizeof(nblock)) < 0)
250 err(1, "ioctl failed");
252 n = connect(s, (const struct sockaddr *)tmp,
253 sizeof(*tmp));
254 if (n == 0) {
255 ++count;
256 close(s);
257 continue;
258 } else {
259 int error = errno;
261 if (error != EINPROGRESS)
262 errc(1, error, "connect failed");
264 ++nconn;
266 if (nchange >= nevt_max) {
267 fprintf(stderr, "invalid nchange %d, max %d\n",
268 nchange, nevt_max);
269 abort();
271 EV_SET(&evt_change0[nchange], s, EVFILT_WRITE, EV_ADD,
272 0, 0, NULL);
273 ++nchange;
276 if (nchange)
277 evt_change = evt_change0;
279 n = kevent(kq, evt_change, nchange, evt, nevt_max, NULL);
280 if (n < 0)
281 err(1, "kevent failed");
282 nchange = 0;
284 for (i = 0; i < n; ++i) {
285 struct kevent *e = &evt[i];
287 if (e->filter == EVFILT_TIMER) {
288 done = 1;
289 continue;
292 if ((e->flags & EV_EOF) && e->fflags) {
293 /* Error, don't count */
294 } else {
295 ++count;
297 close(e->ident);
298 --nconn;
300 if (done)
301 break;
303 clock_gettime(CLOCK_MONOTONIC_PRECISE, &end);
305 timespecsub(&end, &start);
306 time_us = ((double)end.tv_sec * 1000000.0) +
307 ((double)end.tv_nsec / 1000.0);
309 *res = ((double)count * 1000000.0) / time_us;