5 #include <sys/socket.h>
6 #include <sys/sysctl.h>
8 #include <sys/usched.h>
11 #include <arpa/inet.h>
12 #include <netinet/in.h>
23 #define timespecsub(vvp, uvp) \
25 (vvp)->tv_sec -= (uvp)->tv_sec; \
26 (vvp)->tv_nsec -= (uvp)->tv_nsec; \
27 if ((vvp)->tv_nsec < 0) { \
29 (vvp)->tv_nsec += 1000000000; \
34 static void mainloop(const struct sockaddr_in
*, int, int, long, u_long
*,
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
);
49 main(int argc
, char *argv
[])
51 struct sockaddr_in
*in
, *tmp
;
52 int opt
, ninst
, nconn
, i
, in_max
, in_cnt
, do_udp
;
58 prm_len
= sizeof(cpucnt
);
59 if (sysctlbyname("hw.ncpu", &cpucnt
, &prm_len
, NULL
, 0) != 0)
60 err(2, "sysctl hw.ncpu failed");
69 in
= calloc(in_max
, sizeof(struct sockaddr_in
));
71 err(1, "calloc failed");
74 while ((opt
= getopt(argc
, argv
, "4:Bc:i:l:p:u")) != -1) {
77 if (in_cnt
>= in_max
) {
78 struct sockaddr_in
*old_in
= in
;
79 int old_in_max
= in_max
;
82 in
= calloc(in_max
, sizeof(struct sockaddr_in
));
84 err(1, "calloc failed");
87 old_in_max
* sizeof(struct sockaddr_in
));
92 if (inet_pton(AF_INET
, optarg
, &tmp
->sin_addr
) <= 0) {
93 fprintf(stderr
, "invalid inet address %s\n",
105 nconn
= atoi(optarg
);
109 ninst
= atoi(optarg
);
113 dur
= strtol(optarg
, NULL
, 10);
117 port
= htons(atoi(optarg
));
129 if (ninst
< 1 || dur
< 1 || nconn
< 1 || port
== 0 || in_cnt
== 0)
132 for (i
= 0; i
< in_cnt
; ++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
) {
149 mainloop(in
, in_cnt
, nconn
, dur
, &result
[i
], do_udp
, i
);
151 } else if (pid
< 0) {
152 err(1, "fork failed");
156 for (i
= 0; i
< ninst
; ++i
) {
159 pid
= waitpid(-1, NULL
, 0);
161 err(1, "waitpid failed");
165 for (i
= 0; i
< ninst
; ++i
)
167 printf("%lu\n", sum
);
173 udp_send(const struct sockaddr_in
*in
)
178 s
= socket(AF_INET
, SOCK_DGRAM
, 0);
180 warn("socket DGRAM failed");
184 if (connect(s
, (const struct sockaddr
*)in
, sizeof(*in
)) < 0) {
185 warn("connect DGRAM failed");
189 write(s
, d
, sizeof(d
));
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
;
207 int cpu
= inst
% cpucnt
;
209 usched_set(getpid(), USCHED_SET_CPU
, &cpu
, sizeof(cpu
));
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
));
224 err(1, "malloc evt failed");
226 EV_SET(&evt_change0
[0], 0, EVFILT_TIMER
, EV_ADD
| EV_ONESHOT
, 0,
230 clock_gettime(CLOCK_MONOTONIC_PRECISE
, &start
);
232 struct kevent
*evt_change
= NULL
;
235 while (nconn
< nconn_max
) {
236 const struct sockaddr_in
*tmp
;
239 tmp
= &in
[in_idx
% in_cnt
];
245 s
= socket(AF_INET
, SOCK_STREAM
, 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
,
261 if (error
!= EINPROGRESS
)
262 errc(1, error
, "connect failed");
266 if (nchange
>= nevt_max
) {
267 fprintf(stderr
, "invalid nchange %d, max %d\n",
271 EV_SET(&evt_change0
[nchange
], s
, EVFILT_WRITE
, EV_ADD
,
277 evt_change
= evt_change0
;
279 n
= kevent(kq
, evt_change
, nchange
, evt
, nevt_max
, NULL
);
281 err(1, "kevent failed");
284 for (i
= 0; i
< n
; ++i
) {
285 struct kevent
*e
= &evt
[i
];
287 if (e
->filter
== EVFILT_TIMER
) {
292 if ((e
->flags
& EV_EOF
) && e
->fflags
) {
293 /* Error, don't count */
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
;