tools/netrate: Use ncpus as # of instance by default
[dragonfly.git] / tools / tools / netrate / accept_connect / kq_connect_client / kq_connect_client.c
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/wait.h>
9
10 #include <arpa/inet.h>
11 #include <netinet/in.h>
12
13 #include <errno.h>
14 #include <signal.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <unistd.h>
19
20 static void     mainloop(const struct sockaddr_in *, int, int, long, u_long *,
21                     int);
22
23 static void
24 usage(const char *cmd)
25 {
26         fprintf(stderr, "%s -4 inet4 [-4 inet4_1] -p port "
27             "[-i n_instance] [-c conn_max] [-l duration] [-u]\n", cmd);
28         exit(1);
29 }
30
31 int
32 main(int argc, char *argv[])
33 {
34         struct sockaddr_in *in, *tmp;
35         int opt, ninst, nconn, i, in_max, in_cnt, do_udp;
36         long dur;
37         u_long *result, sum;
38         u_short port;
39         size_t prm_len;
40
41         prm_len = sizeof(ninst);
42         if (sysctlbyname("hw.ncpu", &ninst, &prm_len, NULL, 0) != 0) {
43                 fprintf(stderr, "sysctl hw.ncpu failed: %d\n", errno);
44                 exit(2);
45         }
46
47         nconn = 8;
48         dur = 10;
49         port = 0;
50         do_udp = 0;
51
52         in_max = 8;
53         in = calloc(in_max, sizeof(struct sockaddr_in));
54         if (in == NULL) {
55                 fprintf(stderr, "calloc failed\n");
56                 exit(1);
57         }
58         in_cnt = 0;
59
60         while ((opt = getopt(argc, argv, "4:p:i:l:c:u")) != -1) {
61                 switch (opt) {
62                 case '4':
63                         if (in_cnt >= in_max) {
64                                 struct sockaddr_in *old_in = in;
65                                 int old_in_max = in_max;
66
67                                 in_max <<= 1;
68                                 in = calloc(in_max, sizeof(struct sockaddr_in));
69                                 if (in == NULL) {
70                                         fprintf(stderr, "calloc failed\n");
71                                         exit(1);
72                                 }
73
74                                 memcpy(in, old_in,
75                                     old_in_max * sizeof(struct sockaddr_in));
76                                 free(old_in);
77                         }
78
79                         tmp = &in[in_cnt];
80                         if (inet_pton(AF_INET, optarg, &tmp->sin_addr) <= 0) {
81                                 fprintf(stderr, "invalid inet address %s\n",
82                                     optarg);
83                                 usage(argv[0]);
84                         }
85                         ++in_cnt;
86                         break;
87
88                 case 'p':
89                         port = htons(atoi(optarg));
90                         break;
91
92                 case 'i':
93                         ninst = atoi(optarg);
94                         break;
95
96                 case 'c':
97                         nconn = atoi(optarg);
98                         break;
99
100                 case 'l':
101                         dur = strtol(optarg, NULL, 10);
102                         break;
103
104                 case 'u':
105                         do_udp = 1;
106                         break;
107
108                 default:
109                         usage(argv[0]);
110                 }
111         }
112
113         if (ninst < 1 || dur < 1 || nconn < 1 || port == 0 || in_cnt == 0)
114                 usage(argv[0]);
115
116         for (i = 0; i < in_cnt; ++i) {
117                 tmp = &in[i];
118                 tmp->sin_family = AF_INET;
119                 tmp->sin_port = port;
120         }
121
122         result = mmap(NULL, ninst * sizeof(u_long), PROT_READ | PROT_WRITE,
123             MAP_ANON | MAP_SHARED, -1, 0);
124         if (result == MAP_FAILED) {
125                 fprintf(stderr, "mmap failed: %d\n", errno);
126                 exit(1);
127         }
128         memset(result, 0, ninst * sizeof(u_long));
129
130         for (i = 0; i < ninst; ++i) {
131                 pid_t pid;
132
133                 pid = fork();
134                 if (pid == 0) {
135                         mainloop(in, in_cnt, nconn, dur, &result[i], do_udp);
136                         exit(0);
137                 } else if (pid < 0) {
138                         fprintf(stderr, "fork failed: %d\n", errno);
139                 }
140         }
141
142         for (i = 0; i < ninst; ++i) {
143                 pid_t pid;
144
145                 pid = waitpid(-1, NULL, 0);
146                 if (pid < 0) {
147                         fprintf(stderr, "waitpid failed: %d\n", errno);
148                         exit(1);
149                 }
150         }
151
152         sum = 0;
153         for (i = 0; i < ninst; ++i)
154                 sum += result[i];
155         printf("%.2f\n", (double)sum / (double)dur);
156
157         exit(0);
158 }
159
160 static void
161 udp_send(const struct sockaddr_in *in)
162 {
163         uint8_t d[18];
164         int s;
165
166         s = socket(AF_INET, SOCK_DGRAM, 0);
167         if (s < 0) {
168                 fprintf(stderr, "socket DGRAM failed: %d\n", errno);
169                 return;
170         }
171
172         if (connect(s, (const struct sockaddr *)in, sizeof(*in)) < 0) {
173                 fprintf(stderr, "connect DGRAM failed: %d\n", errno);
174                 goto done;
175         }
176
177         write(s, d, sizeof(d));
178 done:
179         close(s);
180 }
181
182 static void
183 mainloop(const struct sockaddr_in *in, int in_cnt, int nconn_max,
184     long dur, u_long *res, int do_udp)
185 {
186         struct kevent *evt_change0, *evt;
187         int kq, nchange = 0, nconn = 0, nevt_max;
188         u_long count = 0;
189         u_int in_idx = 0;
190         int nblock = 1;
191
192         kq = kqueue();
193         if (kq < 0) {
194                 fprintf(stderr, "kqueue failed: %d\n", errno);
195                 return;
196         }
197
198         nevt_max = nconn_max + 1; /* timer */
199
200         evt_change0 = malloc(nevt_max * sizeof(struct kevent));
201         if (evt_change0 == NULL) {
202                 fprintf(stderr, "malloc evt_change failed\n");
203                 return;
204         }
205
206         evt = malloc(nevt_max * sizeof(struct kevent));
207         if (evt == NULL) {
208                 fprintf(stderr, "malloc evt failed\n");
209                 return;
210         }
211
212         EV_SET(&evt_change0[0], 0, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 0,
213             dur * 1000L, NULL);
214         nchange = 1;
215
216         for (;;) {
217                 struct kevent *evt_change = NULL;
218                 int n, i, done = 0;
219
220                 while (nconn < nconn_max) {
221                         const struct sockaddr_in *tmp;
222                         int s;
223
224                         tmp = &in[in_idx % in_cnt];
225                         ++in_idx;
226
227                         if (do_udp)
228                                 udp_send(tmp);
229
230                         s = socket(AF_INET, SOCK_STREAM, 0);
231                         if (s < 0) {
232                                 fprintf(stderr, "socket failed: %d\n", errno);
233                                 return;
234                         }
235
236                         if (ioctl(s, FIONBIO, &nblock, sizeof(nblock)) < 0) {
237                                 fprintf(stderr, "ioctl failed: %d\n", errno);
238                                 return;
239                         }
240
241                         n = connect(s, (const struct sockaddr *)tmp,
242                             sizeof(*tmp));
243                         if (n == 0) {
244                                 ++count;
245                                 close(s);
246                                 continue;
247                         } else {
248                                 int error = errno;
249
250                                 if (error != EINPROGRESS) {
251                                         fprintf(stderr, "connect failed: %d\n",
252                                             error);
253                                         return;
254                                 }
255                         }
256                         ++nconn;
257
258                         if (nchange >= nevt_max) {
259                                 fprintf(stderr, "invalid nchange %d, max %d\n",
260                                     nchange, nevt_max);
261                                 abort();
262                         }
263                         EV_SET(&evt_change0[nchange], s, EVFILT_WRITE, EV_ADD,
264                             0, 0, NULL);
265                         ++nchange;
266                 }
267
268                 if (nchange)
269                         evt_change = evt_change0;
270
271                 n = kevent(kq, evt_change, nchange, evt, nevt_max, NULL);
272                 if (n < 0) {
273                         fprintf(stderr, "kevent failed: %d\n", errno);
274                         return;
275                 }
276                 nchange = 0;
277
278                 for (i = 0; i < n; ++i) {
279                         struct kevent *e = &evt[i];
280
281                         if (e->filter == EVFILT_TIMER) {
282                                 done = 1;
283                                 continue;
284                         }
285
286                         if ((e->flags & EV_EOF) && e->fflags) {
287                                 /* Error, don't count */
288                         } else {
289                                 ++count;
290                         }
291                         close(e->ident);
292                         --nconn;
293                 }
294                 if (done)
295                         break;
296         }
297         *res = count;
298 }