1 /* $NetBSD: bench_httpclient.c,v 1.1.1.1 2013/04/11 16:43:32 christos Exp $ */
3 * Copyright 2009-2012 Niels Provos and Nick Mathewson
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 4. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include <sys/types.h>
33 #include <sys/socket.h>
34 #include <netinet/in.h>
35 # ifdef _XOPEN_SOURCE_EXTENDED
36 # include <arpa/inet.h>
43 #include "event2/event.h"
44 #include "event2/bufferevent.h"
45 #include "event2/buffer.h"
46 #include "event2/util.h"
48 /* for EVUTIL_ERR_CONNECT_RETRIABLE macro */
49 #include "util-internal.h"
51 const char *resource
= NULL
;
52 struct event_base
*base
= NULL
;
54 int total_n_handled
= 0;
55 int total_n_errors
= 0;
56 int total_n_launched
= 0;
57 size_t total_n_bytes
= 0;
58 struct timeval total_time
= {0,0};
61 const int PARALLELISM
= 200;
62 const int N_REQUESTS
= 20000;
66 struct timeval started
;
69 static int launch_request(void);
70 static void readcb(struct bufferevent
*b
, void *arg
);
71 static void errorcb(struct bufferevent
*b
, short what
, void *arg
);
74 readcb(struct bufferevent
*b
, void *arg
)
76 struct request_info
*ri
= arg
;
77 struct evbuffer
*input
= bufferevent_get_input(b
);
78 size_t n
= evbuffer_get_length(input
);
81 evbuffer_drain(input
, n
);
85 errorcb(struct bufferevent
*b
, short what
, void *arg
)
87 struct request_info
*ri
= arg
;
88 struct timeval now
, diff
;
89 if (what
& BEV_EVENT_EOF
) {
91 total_n_bytes
+= ri
->n_read
;
92 evutil_gettimeofday(&now
, NULL
);
93 evutil_timersub(&now
, &ri
->started
, &diff
);
94 evutil_timeradd(&diff
, &total_time
, &total_time
);
96 if (total_n_handled
&& (total_n_handled
%1000)==0)
97 printf("%d requests done\n",total_n_handled
);
99 if (total_n_launched
< N_REQUESTS
) {
100 if (launch_request() < 0)
101 perror("Can't launch");
105 perror("Unexpected error");
108 bufferevent_setcb(b
, NULL
, NULL
, NULL
, NULL
);
110 bufferevent_disable(b
, EV_READ
|EV_WRITE
);
115 frob_socket(evutil_socket_t sock
)
119 if (setsockopt(sock
, SOL_SOCKET
, SO_REUSEADDR
, (void*)&one
, sizeof(one
))<0)
120 perror("setsockopt(SO_REUSEADDR)");
123 if (setsockopt(sock
, SOL_SOCKET
, SO_LINGER
, (void*)&l
, sizeof(l
))<0)
124 perror("setsockopt(SO_LINGER)");
130 evutil_socket_t sock
;
131 struct sockaddr_in sin
;
132 struct bufferevent
*b
;
134 struct request_info
*ri
;
136 memset(&sin
, 0, sizeof(sin
));
140 sin
.sin_family
= AF_INET
;
141 sin
.sin_addr
.s_addr
= htonl(0x7f000001);
142 sin
.sin_port
= htons(8080);
143 if ((sock
= socket(AF_INET
, SOCK_STREAM
, 0)) < 0)
145 if (evutil_make_socket_nonblocking(sock
) < 0)
148 if (connect(sock
, (struct sockaddr
*)&sin
, sizeof(sin
)) < 0) {
150 if (! EVUTIL_ERR_CONNECT_RETRIABLE(e
)) {
155 ri
= malloc(sizeof(*ri
));
157 evutil_gettimeofday(&ri
->started
, NULL
);
159 b
= bufferevent_socket_new(base
, sock
, BEV_OPT_CLOSE_ON_FREE
);
161 bufferevent_setcb(b
, readcb
, NULL
, errorcb
, ri
);
162 bufferevent_enable(b
, EV_READ
|EV_WRITE
);
164 evbuffer_add_printf(bufferevent_get_output(b
),
165 "GET %s HTTP/1.0\r\n\r\n", resource
);
172 main(int argc
, char **argv
)
175 struct timeval start
, end
, total
;
180 setvbuf(stdout
, NULL
, _IONBF
, 0);
182 base
= event_base_new();
184 for (i
=0; i
< PARALLELISM
; ++i
) {
185 if (launch_request() < 0)
189 evutil_gettimeofday(&start
, NULL
);
191 event_base_dispatch(base
);
193 evutil_gettimeofday(&end
, NULL
);
194 evutil_timersub(&end
, &start
, &total
);
195 usec
= total_time
.tv_sec
* 1000000 + total_time
.tv_usec
;
197 if (!total_n_handled
) {
198 puts("Nothing worked. You probably did something dumb.");
203 throughput
= total_n_handled
/
204 (total
.tv_sec
+ ((double)total
.tv_usec
)/1000000.0);
207 #define I64_FMT "%I64d"
208 #define I64_TYP __int64
210 #define I64_FMT "%lld"
211 #define I64_TYP long long int
214 printf("\n%d requests in %d.%06d sec. (%.2f throughput)\n"
215 "Each took about %.02f msec latency\n"
216 I64_FMT
"bytes read. %d errors.\n",
218 (int)total
.tv_sec
, (int)total
.tv_usec
,
220 (double)(usec
/1000) / total_n_handled
,
221 (I64_TYP
)total_n_bytes
, n_errors
);