6
6
*
7
7
*/
8
8
9
+ #include < vector>
10
+ #include < algorithm>
11
+
9
12
#include " hv.h"
10
13
#include " hmain.h" // import parse_opt
11
14
#include " hloop.h"
15
18
#include " HttpParser.h"
16
19
using namespace hv ;
17
20
18
- static const char options[] = " hvc:d:t:" ;
21
+ static const char options[] = " hvc:d:t:b:i: " ;
19
22
20
23
static const char detail_options[] = R"(
21
24
-h Print help infomation
22
25
-v Show verbose infomation
23
26
-c <connections> Number of connections, default: 1000
24
27
-d <duration> Duration of test, default: 10s
25
28
-t <threads> Number of threads, default: 4
29
+ -b <bytes> Content-Length, default: 0
30
+ -i <interval> Interval of timer, default: 0ms
26
31
)" ;
27
32
28
33
static int connections = 1000 ;
29
- static int duration = 10 ;
34
+ static int duration = 10 ; // s
30
35
static int threads = 4 ;
36
+ static int bytes = 0 ; // byte
37
+ static int interval = 0 ; // ms
31
38
32
39
static bool verbose = false ;
33
40
static const char * url = NULL ;
@@ -48,6 +55,8 @@ typedef struct connection_s {
48
55
uint64_t response_cnt;
49
56
uint64_t ok_cnt;
50
57
uint64_t readbytes;
58
+ uint64_t start_time;
59
+ std::vector<int > delays;
51
60
52
61
connection_s ()
53
62
: parser(HttpParser::New(HTTP_CLIENT, HTTP_V1))
@@ -63,6 +72,7 @@ typedef struct connection_s {
63
72
}
64
73
65
74
void SendRequest () {
75
+ start_time = hloop_now_ms (hevent_loop (io));
66
76
hio_write (io, request_msg.data (), request_msg.size ());
67
77
++request_cnt;
68
78
parser->InitResponse (response.get ());
@@ -77,6 +87,8 @@ typedef struct connection_s {
77
87
return false ;
78
88
}
79
89
if (parser->IsComplete ()) {
90
+ int delay = hloop_now_ms (hevent_loop (io)) - start_time;
91
+ delays.push_back (delay);
80
92
++response_cnt;
81
93
if (response->status_code == HTTP_STATUS_OK) {
82
94
++ok_cnt;
@@ -90,6 +102,7 @@ static connection_t** conns = NULL;
90
102
91
103
static std::atomic<int > connected_num (0 );
92
104
static std::atomic<int > disconnected_num (0 );
105
+ static unsigned int connect_start_time = 0 ;
93
106
94
107
static void print_help () {
95
108
printf (" Usage: wrk [%s] <url>\n " , options);
@@ -106,13 +119,20 @@ static void print_result() {
106
119
uint64_t total_response_cnt = 0 ;
107
120
uint64_t total_ok_cnt = 0 ;
108
121
uint64_t total_readbytes = 0 ;
122
+ uint64_t total_delay = 0 ;
123
+ std::vector<int > delays;
109
124
connection_t * conn = NULL ;
110
125
for (int i = 0 ; i < connections; ++i) {
111
126
conn = conns[i];
112
127
total_request_cnt += conn->request_cnt ;
113
128
total_response_cnt += conn->response_cnt ;
114
129
total_ok_cnt += conn->ok_cnt ;
115
130
total_readbytes += conn->readbytes ;
131
+ delays.insert (delays.end (), conn->delays .begin (), conn->delays .end ());
132
+ }
133
+ std::sort (delays.begin (), delays.end ());
134
+ for (int i = 0 ; i < delays.size (); ++i) {
135
+ total_delay += delays[i];
116
136
}
117
137
printf (" %llu requests, %llu OK, %lluMB read in %ds\n " ,
118
138
LLU (total_request_cnt),
@@ -121,6 +141,19 @@ static void print_result() {
121
141
duration);
122
142
printf (" Requests/sec: %8llu\n " , LLU (total_response_cnt / duration));
123
143
printf (" Transfer/sec: %8lluMB\n " , LLU ((total_readbytes / duration) >> 20 ));
144
+ printf (" Latency avg: %8llums\n " , LLU (total_delay / delays.size ()));
145
+ printf (" Percentage of the requests served within a certain time (ms)\n " );
146
+ printf (" 50%% %d\n " , delays[delays.size () * 0.5 ]);
147
+ printf (" 60%% %d\n " , delays[delays.size () * 0.6 ]);
148
+ printf (" 70%% %d\n " , delays[delays.size () * 0.7 ]);
149
+ printf (" 80%% %d\n " , delays[delays.size () * 0.8 ]);
150
+ printf (" 90%% %d\n " , delays[delays.size () * 0.9 ]);
151
+ printf (" 95%% %d\n " , delays[delays.size () * 0.95 ]);
152
+ printf (" 96%% %d\n " , delays[delays.size () * 0.96 ]);
153
+ printf (" 97%% %d\n " , delays[delays.size () * 0.97 ]);
154
+ printf (" 98%% %d\n " , delays[delays.size () * 0.98 ]);
155
+ printf (" 99%% %d\n " , delays[delays.size () * 0.99 ]);
156
+ printf (" 100%% %d (longest delay)\n " , delays.back ());
124
157
}
125
158
126
159
static void start_reconnect (hio_t * io);
@@ -140,19 +173,30 @@ static void on_close(hio_t* io) {
140
173
static void on_recv (hio_t * io, void * buf, int readbytes) {
141
174
connection_t * conn = (connection_t *)hevent_userdata (io);
142
175
if (conn->RecvResponse ((const char *)buf, readbytes)) {
143
- conn->SendRequest ();
176
+ if (interval == 0 ) {
177
+ conn->SendRequest ();
178
+ }
144
179
}
145
180
}
146
181
182
+ static void send_heartbeat (hio_t * io) {
183
+ connection_t * conn = (connection_t *)hevent_userdata (io);
184
+ conn->SendRequest ();
185
+ }
186
+
147
187
static void on_connect (hio_t * io) {
148
188
if (++connected_num == connections) {
149
189
if (verbose) {
150
- printf (" all connected\n " );
190
+ printf (" all connected in %ums \n " , gettick_ms () - connect_start_time );
151
191
}
152
192
}
153
193
154
194
connection_t * conn = (connection_t *)hevent_userdata (io);
155
- conn->SendRequest ();
195
+ if (interval == 0 ) {
196
+ conn->SendRequest ();
197
+ } else {
198
+ hio_set_heartbeat (io, interval, send_heartbeat);
199
+ }
156
200
157
201
hio_setcb_read (io, on_recv);
158
202
hio_read (io);
@@ -203,10 +247,14 @@ int main(int argc, char** argv) {
203
247
const char * strConnections = get_arg (" c" );
204
248
const char * strDuration = get_arg (" d" );
205
249
const char * strThreads = get_arg (" t" );
250
+ const char * strBytes = get_arg (" b" );
251
+ const char * strInterval = get_arg (" i" );
206
252
207
253
if (strConnections) connections = atoi (strConnections);
208
254
if (strDuration) duration = atoi (strDuration);
209
255
if (strThreads) threads = atoi (strThreads);
256
+ if (strBytes) bytes = atoi (strBytes);
257
+ if (strInterval) interval = atoi (strInterval);
210
258
211
259
print_cmd ();
212
260
@@ -243,14 +291,19 @@ int main(int argc, char** argv) {
243
291
// Dump request
244
292
request->headers [" User-Agent" ] = std::string (" libhv/" ) + hv_version ();
245
293
request->headers [" Connection" ] = " keep-alive" ;
294
+ if (bytes > 0 ) {
295
+ request->method = HTTP_POST;
296
+ request->body = std::string (bytes, ' a' );
297
+ }
246
298
request_msg = request->Dump (true , true );
247
- printf (" %s " , request_msg.c_str ());
299
+ printf (" %.*s " , int (request_msg. size () - request-> body . size ()) , request_msg.c_str ());
248
300
249
301
// EventLoopThreadPool
250
302
EventLoopThreadPool loop_threads (threads);
251
303
loop_threads.start (true );
252
304
253
305
// connections
306
+ connect_start_time = gettick_ms ();
254
307
conns = (connection_t **)malloc (sizeof (connection_t *) * connections);
255
308
for (int i = 0 ; i < connections; ++i) {
256
309
conns[i] = new connection_t ;
0 commit comments