133657a95SSepherosa Ziehau #include <sys/types.h>
233657a95SSepherosa Ziehau #include <sys/event.h>
3dbaf089dSSepherosa Ziehau #include <sys/ioctl.h>
433657a95SSepherosa Ziehau #include <sys/mman.h>
533657a95SSepherosa Ziehau #include <sys/socket.h>
6a74edad3SSepherosa Ziehau #include <sys/sysctl.h>
733657a95SSepherosa Ziehau #include <sys/time.h>
89a7343b2SSepherosa Ziehau #include <sys/usched.h>
933657a95SSepherosa Ziehau #include <sys/wait.h>
1033657a95SSepherosa Ziehau
1133657a95SSepherosa Ziehau #include <arpa/inet.h>
1233657a95SSepherosa Ziehau #include <netinet/in.h>
1333657a95SSepherosa Ziehau
149aebb1f1SSepherosa Ziehau #include <err.h>
1533657a95SSepherosa Ziehau #include <errno.h>
1633657a95SSepherosa Ziehau #include <signal.h>
1733657a95SSepherosa Ziehau #include <stdio.h>
1833657a95SSepherosa Ziehau #include <stdlib.h>
1933657a95SSepherosa Ziehau #include <string.h>
2033657a95SSepherosa Ziehau #include <unistd.h>
2133657a95SSepherosa Ziehau
22626b6155SSepherosa Ziehau static void mainloop(const struct sockaddr_in *, int, int, long, u_long *,
239a7343b2SSepherosa Ziehau int, int);
249a7343b2SSepherosa Ziehau
259a7343b2SSepherosa Ziehau static int bindcpu;
269a7343b2SSepherosa Ziehau static int cpucnt;
2733657a95SSepherosa Ziehau
2833657a95SSepherosa Ziehau static void
usage(const char * cmd)2933657a95SSepherosa Ziehau usage(const char *cmd)
3033657a95SSepherosa Ziehau {
3133657a95SSepherosa Ziehau fprintf(stderr, "%s -4 inet4 [-4 inet4_1] -p port "
329a7343b2SSepherosa Ziehau "[-i n_instance] [-c conn_max] [-l duration] [-u] [-B]\n", cmd);
3333657a95SSepherosa Ziehau exit(1);
3433657a95SSepherosa Ziehau }
3533657a95SSepherosa Ziehau
3633657a95SSepherosa Ziehau int
main(int argc,char * argv[])3733657a95SSepherosa Ziehau main(int argc, char *argv[])
3833657a95SSepherosa Ziehau {
3933657a95SSepherosa Ziehau struct sockaddr_in *in, *tmp;
40626b6155SSepherosa Ziehau int opt, ninst, nconn, i, in_max, in_cnt, do_udp;
4133657a95SSepherosa Ziehau long dur;
4233657a95SSepherosa Ziehau u_long *result, sum;
4333657a95SSepherosa Ziehau u_short port;
44a74edad3SSepherosa Ziehau size_t prm_len;
4533657a95SSepherosa Ziehau
469a7343b2SSepherosa Ziehau prm_len = sizeof(cpucnt);
479a7343b2SSepherosa Ziehau if (sysctlbyname("hw.ncpu", &cpucnt, &prm_len, NULL, 0) != 0)
489aebb1f1SSepherosa Ziehau err(2, "sysctl hw.ncpu failed");
499a7343b2SSepherosa Ziehau ninst = cpucnt;
50a74edad3SSepherosa Ziehau
5133657a95SSepherosa Ziehau nconn = 8;
5233657a95SSepherosa Ziehau dur = 10;
5333657a95SSepherosa Ziehau port = 0;
54626b6155SSepherosa Ziehau do_udp = 0;
5533657a95SSepherosa Ziehau
5633657a95SSepherosa Ziehau in_max = 8;
5733657a95SSepherosa Ziehau in = calloc(in_max, sizeof(struct sockaddr_in));
589aebb1f1SSepherosa Ziehau if (in == NULL)
599aebb1f1SSepherosa Ziehau err(1, "calloc failed");
6033657a95SSepherosa Ziehau in_cnt = 0;
6133657a95SSepherosa Ziehau
629a7343b2SSepherosa Ziehau while ((opt = getopt(argc, argv, "4:Bc:i:l:p:u")) != -1) {
6333657a95SSepherosa Ziehau switch (opt) {
6433657a95SSepherosa Ziehau case '4':
6533657a95SSepherosa Ziehau if (in_cnt >= in_max) {
6633657a95SSepherosa Ziehau struct sockaddr_in *old_in = in;
6733657a95SSepherosa Ziehau int old_in_max = in_max;
6833657a95SSepherosa Ziehau
6933657a95SSepherosa Ziehau in_max <<= 1;
7033657a95SSepherosa Ziehau in = calloc(in_max, sizeof(struct sockaddr_in));
719aebb1f1SSepherosa Ziehau if (in == NULL)
729aebb1f1SSepherosa Ziehau err(1, "calloc failed");
7333657a95SSepherosa Ziehau
7433657a95SSepherosa Ziehau memcpy(in, old_in,
7533657a95SSepherosa Ziehau old_in_max * sizeof(struct sockaddr_in));
7633657a95SSepherosa Ziehau free(old_in);
7733657a95SSepherosa Ziehau }
7833657a95SSepherosa Ziehau
7933657a95SSepherosa Ziehau tmp = &in[in_cnt];
8033657a95SSepherosa Ziehau if (inet_pton(AF_INET, optarg, &tmp->sin_addr) <= 0) {
8133657a95SSepherosa Ziehau fprintf(stderr, "invalid inet address %s\n",
8233657a95SSepherosa Ziehau optarg);
8333657a95SSepherosa Ziehau usage(argv[0]);
8433657a95SSepherosa Ziehau }
8533657a95SSepherosa Ziehau ++in_cnt;
8633657a95SSepherosa Ziehau break;
8733657a95SSepherosa Ziehau
889a7343b2SSepherosa Ziehau case 'B':
899a7343b2SSepherosa Ziehau bindcpu = 1;
9033657a95SSepherosa Ziehau break;
9133657a95SSepherosa Ziehau
9233657a95SSepherosa Ziehau case 'c':
9333657a95SSepherosa Ziehau nconn = atoi(optarg);
9433657a95SSepherosa Ziehau break;
9533657a95SSepherosa Ziehau
969a7343b2SSepherosa Ziehau case 'i':
979a7343b2SSepherosa Ziehau ninst = atoi(optarg);
989a7343b2SSepherosa Ziehau break;
999a7343b2SSepherosa Ziehau
10033657a95SSepherosa Ziehau case 'l':
10133657a95SSepherosa Ziehau dur = strtol(optarg, NULL, 10);
10233657a95SSepherosa Ziehau break;
10333657a95SSepherosa Ziehau
1049a7343b2SSepherosa Ziehau case 'p':
1059a7343b2SSepherosa Ziehau port = htons(atoi(optarg));
1069a7343b2SSepherosa Ziehau break;
1079a7343b2SSepherosa Ziehau
108626b6155SSepherosa Ziehau case 'u':
109626b6155SSepherosa Ziehau do_udp = 1;
110626b6155SSepherosa Ziehau break;
111626b6155SSepherosa Ziehau
11233657a95SSepherosa Ziehau default:
11333657a95SSepherosa Ziehau usage(argv[0]);
11433657a95SSepherosa Ziehau }
11533657a95SSepherosa Ziehau }
11633657a95SSepherosa Ziehau
11733657a95SSepherosa Ziehau if (ninst < 1 || dur < 1 || nconn < 1 || port == 0 || in_cnt == 0)
11833657a95SSepherosa Ziehau usage(argv[0]);
11933657a95SSepherosa Ziehau
12033657a95SSepherosa Ziehau for (i = 0; i < in_cnt; ++i) {
12133657a95SSepherosa Ziehau tmp = &in[i];
12233657a95SSepherosa Ziehau tmp->sin_family = AF_INET;
12333657a95SSepherosa Ziehau tmp->sin_port = port;
12433657a95SSepherosa Ziehau }
12533657a95SSepherosa Ziehau
12633657a95SSepherosa Ziehau result = mmap(NULL, ninst * sizeof(u_long), PROT_READ | PROT_WRITE,
12733657a95SSepherosa Ziehau MAP_ANON | MAP_SHARED, -1, 0);
1289aebb1f1SSepherosa Ziehau if (result == MAP_FAILED)
1299aebb1f1SSepherosa Ziehau err(1, "mmap failed");
13033657a95SSepherosa Ziehau memset(result, 0, ninst * sizeof(u_long));
13133657a95SSepherosa Ziehau
13233657a95SSepherosa Ziehau for (i = 0; i < ninst; ++i) {
13333657a95SSepherosa Ziehau pid_t pid;
13433657a95SSepherosa Ziehau
13533657a95SSepherosa Ziehau pid = fork();
13633657a95SSepherosa Ziehau if (pid == 0) {
1379a7343b2SSepherosa Ziehau mainloop(in, in_cnt, nconn, dur, &result[i], do_udp, i);
13833657a95SSepherosa Ziehau exit(0);
13933657a95SSepherosa Ziehau } else if (pid < 0) {
1409aebb1f1SSepherosa Ziehau err(1, "fork failed");
14133657a95SSepherosa Ziehau }
14233657a95SSepherosa Ziehau }
14333657a95SSepherosa Ziehau
14433657a95SSepherosa Ziehau for (i = 0; i < ninst; ++i) {
14533657a95SSepherosa Ziehau pid_t pid;
14633657a95SSepherosa Ziehau
14733657a95SSepherosa Ziehau pid = waitpid(-1, NULL, 0);
1489aebb1f1SSepherosa Ziehau if (pid < 0)
1499aebb1f1SSepherosa Ziehau err(1, "waitpid failed");
15033657a95SSepherosa Ziehau }
15133657a95SSepherosa Ziehau
15233657a95SSepherosa Ziehau sum = 0;
15333657a95SSepherosa Ziehau for (i = 0; i < ninst; ++i)
15433657a95SSepherosa Ziehau sum += result[i];
155141605edSSepherosa Ziehau printf("%lu\n", sum);
15633657a95SSepherosa Ziehau
15733657a95SSepherosa Ziehau exit(0);
15833657a95SSepherosa Ziehau }
15933657a95SSepherosa Ziehau
16033657a95SSepherosa Ziehau static void
udp_send(const struct sockaddr_in * in)161626b6155SSepherosa Ziehau udp_send(const struct sockaddr_in *in)
162626b6155SSepherosa Ziehau {
163626b6155SSepherosa Ziehau uint8_t d[18];
164626b6155SSepherosa Ziehau int s;
165626b6155SSepherosa Ziehau
166626b6155SSepherosa Ziehau s = socket(AF_INET, SOCK_DGRAM, 0);
167626b6155SSepherosa Ziehau if (s < 0) {
1689aebb1f1SSepherosa Ziehau warn("socket DGRAM failed");
169626b6155SSepherosa Ziehau return;
170626b6155SSepherosa Ziehau }
171626b6155SSepherosa Ziehau
172626b6155SSepherosa Ziehau if (connect(s, (const struct sockaddr *)in, sizeof(*in)) < 0) {
1739aebb1f1SSepherosa Ziehau warn("connect DGRAM failed");
174626b6155SSepherosa Ziehau goto done;
175626b6155SSepherosa Ziehau }
176626b6155SSepherosa Ziehau
177626b6155SSepherosa Ziehau write(s, d, sizeof(d));
178626b6155SSepherosa Ziehau done:
179626b6155SSepherosa Ziehau close(s);
180626b6155SSepherosa Ziehau }
181626b6155SSepherosa Ziehau
182626b6155SSepherosa Ziehau static void
mainloop(const struct sockaddr_in * in,int in_cnt,int nconn_max,long dur,u_long * res,int do_udp,int inst)18333657a95SSepherosa Ziehau mainloop(const struct sockaddr_in *in, int in_cnt, int nconn_max,
1849a7343b2SSepherosa Ziehau long dur, u_long *res, int do_udp, int inst)
18533657a95SSepherosa Ziehau {
186141605edSSepherosa Ziehau struct timespec start, end;
18733657a95SSepherosa Ziehau struct kevent *evt_change0, *evt;
18833657a95SSepherosa Ziehau int kq, nchange = 0, nconn = 0, nevt_max;
18933657a95SSepherosa Ziehau u_long count = 0;
190141605edSSepherosa Ziehau double time_us;
19133657a95SSepherosa Ziehau u_int in_idx = 0;
192bb610beaSSepherosa Ziehau #ifndef SOCK_NONBLOCK
193dbaf089dSSepherosa Ziehau int nblock = 1;
194bb610beaSSepherosa Ziehau #endif
19533657a95SSepherosa Ziehau
1969a7343b2SSepherosa Ziehau if (bindcpu) {
1979a7343b2SSepherosa Ziehau int cpu = inst % cpucnt;
1989a7343b2SSepherosa Ziehau
1999a7343b2SSepherosa Ziehau usched_set(getpid(), USCHED_SET_CPU, &cpu, sizeof(cpu));
2009a7343b2SSepherosa Ziehau }
2019a7343b2SSepherosa Ziehau
20233657a95SSepherosa Ziehau kq = kqueue();
2039aebb1f1SSepherosa Ziehau if (kq < 0)
2049aebb1f1SSepherosa Ziehau err(1, "kqueue failed");
20533657a95SSepherosa Ziehau
20633657a95SSepherosa Ziehau nevt_max = nconn_max + 1; /* timer */
20733657a95SSepherosa Ziehau
20833657a95SSepherosa Ziehau evt_change0 = malloc(nevt_max * sizeof(struct kevent));
2099aebb1f1SSepherosa Ziehau if (evt_change0 == NULL)
2109aebb1f1SSepherosa Ziehau err(1, "malloc evt_change failed");
21133657a95SSepherosa Ziehau
21233657a95SSepherosa Ziehau evt = malloc(nevt_max * sizeof(struct kevent));
2139aebb1f1SSepherosa Ziehau if (evt == NULL)
2149aebb1f1SSepherosa Ziehau err(1, "malloc evt failed");
21533657a95SSepherosa Ziehau
21633657a95SSepherosa Ziehau EV_SET(&evt_change0[0], 0, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 0,
21733657a95SSepherosa Ziehau dur * 1000L, NULL);
21833657a95SSepherosa Ziehau nchange = 1;
21933657a95SSepherosa Ziehau
220141605edSSepherosa Ziehau clock_gettime(CLOCK_MONOTONIC_PRECISE, &start);
22133657a95SSepherosa Ziehau for (;;) {
22233657a95SSepherosa Ziehau struct kevent *evt_change = NULL;
22333657a95SSepherosa Ziehau int n, i, done = 0;
22433657a95SSepherosa Ziehau
22533657a95SSepherosa Ziehau while (nconn < nconn_max) {
22633657a95SSepherosa Ziehau const struct sockaddr_in *tmp;
227dbaf089dSSepherosa Ziehau int s;
22833657a95SSepherosa Ziehau
229626b6155SSepherosa Ziehau tmp = &in[in_idx % in_cnt];
230626b6155SSepherosa Ziehau ++in_idx;
231626b6155SSepherosa Ziehau
232626b6155SSepherosa Ziehau if (do_udp)
233626b6155SSepherosa Ziehau udp_send(tmp);
234626b6155SSepherosa Ziehau
235bb610beaSSepherosa Ziehau #ifndef SOCK_NONBLOCK
23633657a95SSepherosa Ziehau s = socket(AF_INET, SOCK_STREAM, 0);
2379aebb1f1SSepherosa Ziehau if (s < 0)
2389aebb1f1SSepherosa Ziehau err(1, "socket failed");
23933657a95SSepherosa Ziehau
2409aebb1f1SSepherosa Ziehau if (ioctl(s, FIONBIO, &nblock, sizeof(nblock)) < 0)
2419aebb1f1SSepherosa Ziehau err(1, "ioctl failed");
242bb610beaSSepherosa Ziehau #else
243bb610beaSSepherosa Ziehau s = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
244bb610beaSSepherosa Ziehau if (s < 0)
245bb610beaSSepherosa Ziehau err(1, "socket failed");
246bb610beaSSepherosa Ziehau #endif
24733657a95SSepherosa Ziehau
24833657a95SSepherosa Ziehau n = connect(s, (const struct sockaddr *)tmp,
24933657a95SSepherosa Ziehau sizeof(*tmp));
25033657a95SSepherosa Ziehau if (n == 0) {
25133657a95SSepherosa Ziehau ++count;
25233657a95SSepherosa Ziehau close(s);
25333657a95SSepherosa Ziehau continue;
25433657a95SSepherosa Ziehau } else {
25533657a95SSepherosa Ziehau int error = errno;
25633657a95SSepherosa Ziehau
2579aebb1f1SSepherosa Ziehau if (error != EINPROGRESS)
2589aebb1f1SSepherosa Ziehau errc(1, error, "connect failed");
25933657a95SSepherosa Ziehau }
26033657a95SSepherosa Ziehau ++nconn;
26133657a95SSepherosa Ziehau
26233657a95SSepherosa Ziehau if (nchange >= nevt_max) {
26333657a95SSepherosa Ziehau fprintf(stderr, "invalid nchange %d, max %d\n",
26433657a95SSepherosa Ziehau nchange, nevt_max);
26533657a95SSepherosa Ziehau abort();
26633657a95SSepherosa Ziehau }
26733657a95SSepherosa Ziehau EV_SET(&evt_change0[nchange], s, EVFILT_WRITE, EV_ADD,
26833657a95SSepherosa Ziehau 0, 0, NULL);
26933657a95SSepherosa Ziehau ++nchange;
27033657a95SSepherosa Ziehau }
27133657a95SSepherosa Ziehau
27233657a95SSepherosa Ziehau if (nchange)
27333657a95SSepherosa Ziehau evt_change = evt_change0;
27433657a95SSepherosa Ziehau
27533657a95SSepherosa Ziehau n = kevent(kq, evt_change, nchange, evt, nevt_max, NULL);
2769aebb1f1SSepherosa Ziehau if (n < 0)
2779aebb1f1SSepherosa Ziehau err(1, "kevent failed");
27833657a95SSepherosa Ziehau nchange = 0;
27933657a95SSepherosa Ziehau
28033657a95SSepherosa Ziehau for (i = 0; i < n; ++i) {
28133657a95SSepherosa Ziehau struct kevent *e = &evt[i];
28233657a95SSepherosa Ziehau
28333657a95SSepherosa Ziehau if (e->filter == EVFILT_TIMER) {
28433657a95SSepherosa Ziehau done = 1;
28533657a95SSepherosa Ziehau continue;
28633657a95SSepherosa Ziehau }
28733657a95SSepherosa Ziehau
28833657a95SSepherosa Ziehau if ((e->flags & EV_EOF) && e->fflags) {
28933657a95SSepherosa Ziehau /* Error, don't count */
29033657a95SSepherosa Ziehau } else {
29133657a95SSepherosa Ziehau ++count;
29233657a95SSepherosa Ziehau }
29333657a95SSepherosa Ziehau close(e->ident);
29433657a95SSepherosa Ziehau --nconn;
29533657a95SSepherosa Ziehau }
29633657a95SSepherosa Ziehau if (done)
29733657a95SSepherosa Ziehau break;
29833657a95SSepherosa Ziehau }
299141605edSSepherosa Ziehau clock_gettime(CLOCK_MONOTONIC_PRECISE, &end);
300141605edSSepherosa Ziehau
301*944cd60cSSascha Wildner timespecsub(&end, &start, &end);
302141605edSSepherosa Ziehau time_us = ((double)end.tv_sec * 1000000.0) +
303141605edSSepherosa Ziehau ((double)end.tv_nsec / 1000.0);
304141605edSSepherosa Ziehau
305141605edSSepherosa Ziehau *res = ((double)count * 1000000.0) / time_us;
30633657a95SSepherosa Ziehau }
307