libuv-svace-build
351 строка · 7.8 Кб
1/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
2*
3* Permission is hereby granted, free of charge, to any person obtaining a copy
4* of this software and associated documentation files (the "Software"), to
5* deal in the Software without restriction, including without limitation the
6* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7* sell copies of the Software, and to permit persons to whom the Software is
8* furnished to do so, subject to the following conditions:
9*
10* The above copyright notice and this permission notice shall be included in
11* all copies or substantial portions of the Software.
12*
13* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19* IN THE SOFTWARE.
20*/
21
22#include "task.h"
23#include "uv.h"
24
25/* Update this is you're going to run > 1000 concurrent requests. */
26#define MAX_CONNS 1000
27
28#undef NANOSEC
29#define NANOSEC ((uint64_t) 1e9)
30
31#undef DEBUG
32#define DEBUG 0
33
34struct conn_rec_s;
35
36typedef void (*setup_fn)(int num, void* arg);
37typedef void (*make_connect_fn)(struct conn_rec_s* conn);
38typedef int (*connect_fn)(int num, make_connect_fn make_connect, void* arg);
39
40/* Base class for tcp_conn_rec and pipe_conn_rec.
41* The ordering of fields matters!
42*/
43typedef struct conn_rec_s {
44int i;
45uv_connect_t conn_req;
46uv_write_t write_req;
47make_connect_fn make_connect;
48uv_stream_t stream;
49} conn_rec;
50
51typedef struct {
52int i;
53uv_connect_t conn_req;
54uv_write_t write_req;
55make_connect_fn make_connect;
56uv_tcp_t stream;
57} tcp_conn_rec;
58
59typedef struct {
60int i;
61uv_connect_t conn_req;
62uv_write_t write_req;
63make_connect_fn make_connect;
64uv_pipe_t stream;
65} pipe_conn_rec;
66
67static char buffer[] = "QS";
68
69static uv_loop_t* loop;
70
71static tcp_conn_rec tcp_conns[MAX_CONNS];
72static pipe_conn_rec pipe_conns[MAX_CONNS];
73
74static uint64_t start; /* in ms */
75static int closed_streams;
76static int conns_failed;
77
78static void alloc_cb(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf);
79static void connect_cb(uv_connect_t* conn_req, int status);
80static void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf);
81static void close_cb(uv_handle_t* handle);
82
83
84static void alloc_cb(uv_handle_t* handle,
85size_t suggested_size,
86uv_buf_t* buf) {
87static char slab[65536];
88buf->base = slab;
89buf->len = sizeof(slab);
90}
91
92
93static void after_write(uv_write_t* req, int status) {
94if (status != 0) {
95fprintf(stderr, "write error %s\n", uv_err_name(status));
96uv_close((uv_handle_t*)req->handle, close_cb);
97conns_failed++;
98return;
99}
100}
101
102
103static void connect_cb(uv_connect_t* req, int status) {
104conn_rec* conn;
105uv_buf_t buf;
106int r;
107
108if (status != 0) {
109#if DEBUG
110fprintf(stderr, "connect error %s\n", uv_err_name(status));
111#endif
112uv_close((uv_handle_t*)req->handle, close_cb);
113conns_failed++;
114return;
115}
116
117ASSERT_NOT_NULL(req);
118ASSERT_OK(status);
119
120conn = (conn_rec*)req->data;
121ASSERT_NOT_NULL(conn);
122
123#if DEBUG
124printf("connect_cb %d\n", conn->i);
125#endif
126
127r = uv_read_start(&conn->stream, alloc_cb, read_cb);
128ASSERT_OK(r);
129
130buf.base = buffer;
131buf.len = sizeof(buffer) - 1;
132
133r = uv_write(&conn->write_req, &conn->stream, &buf, 1, after_write);
134ASSERT_OK(r);
135}
136
137
138static void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
139
140ASSERT_NOT_NULL(stream);
141
142#if DEBUG
143printf("read_cb %d\n", p->i);
144#endif
145
146uv_close((uv_handle_t*)stream, close_cb);
147
148if (nread < 0) {
149if (nread == UV_EOF) {
150;
151} else if (nread == UV_ECONNRESET) {
152conns_failed++;
153} else {
154fprintf(stderr, "read error %s\n", uv_err_name(nread));
155ASSERT(0);
156}
157}
158}
159
160
161static void close_cb(uv_handle_t* handle) {
162conn_rec* p = (conn_rec*)handle->data;
163
164ASSERT_NOT_NULL(handle);
165closed_streams++;
166
167#if DEBUG
168printf("close_cb %d\n", p->i);
169#endif
170
171if (uv_now(loop) - start < 10000) {
172p->make_connect(p);
173}
174}
175
176
177static void tcp_do_setup(int num, void* arg) {
178int i;
179
180for (i = 0; i < num; i++) {
181tcp_conns[i].i = i;
182}
183}
184
185
186static void pipe_do_setup(int num, void* arg) {
187int i;
188
189for (i = 0; i < num; i++) {
190pipe_conns[i].i = i;
191}
192}
193
194
195static void tcp_make_connect(conn_rec* p) {
196struct sockaddr_in addr;
197tcp_conn_rec* tp;
198int r;
199
200tp = (tcp_conn_rec*) p;
201
202r = uv_tcp_init(loop, (uv_tcp_t*)&p->stream);
203ASSERT_OK(r);
204
205ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
206
207r = uv_tcp_connect(&tp->conn_req,
208(uv_tcp_t*) &p->stream,
209(const struct sockaddr*) &addr,
210connect_cb);
211if (r) {
212fprintf(stderr, "uv_tcp_connect error %s\n", uv_err_name(r));
213ASSERT(0);
214}
215
216#if DEBUG
217printf("make connect %d\n", p->i);
218#endif
219
220p->conn_req.data = p;
221p->write_req.data = p;
222p->stream.data = p;
223}
224
225
226static void pipe_make_connect(conn_rec* p) {
227int r;
228
229r = uv_pipe_init(loop, (uv_pipe_t*)&p->stream, 0);
230ASSERT_OK(r);
231
232uv_pipe_connect(&((pipe_conn_rec*) p)->conn_req,
233(uv_pipe_t*) &p->stream,
234TEST_PIPENAME,
235connect_cb);
236
237#if DEBUG
238printf("make connect %d\n", p->i);
239#endif
240
241p->conn_req.data = p;
242p->write_req.data = p;
243p->stream.data = p;
244}
245
246
247static int tcp_do_connect(int num, make_connect_fn make_connect, void* arg) {
248int i;
249
250for (i = 0; i < num; i++) {
251tcp_make_connect((conn_rec*)&tcp_conns[i]);
252tcp_conns[i].make_connect = make_connect;
253}
254
255return 0;
256}
257
258
259static int pipe_do_connect(int num, make_connect_fn make_connect, void* arg) {
260int i;
261
262for (i = 0; i < num; i++) {
263pipe_make_connect((conn_rec*)&pipe_conns[i]);
264pipe_conns[i].make_connect = make_connect;
265}
266
267return 0;
268}
269
270
271static int pound_it(int concurrency,
272const char* type,
273setup_fn do_setup,
274connect_fn do_connect,
275make_connect_fn make_connect,
276void* arg) {
277double secs;
278int r;
279uint64_t start_time; /* in ns */
280uint64_t end_time;
281
282loop = uv_default_loop();
283
284uv_update_time(loop);
285start = uv_now(loop);
286
287/* Run benchmark for at least five seconds. */
288start_time = uv_hrtime();
289
290do_setup(concurrency, arg);
291
292r = do_connect(concurrency, make_connect, arg);
293ASSERT(!r);
294
295uv_run(loop, UV_RUN_DEFAULT);
296
297end_time = uv_hrtime();
298
299/* Number of fractional seconds it took to run the benchmark. */
300secs = (double)(end_time - start_time) / NANOSEC;
301
302fprintf(stderr, "%s-conn-pound-%d: %.0f accepts/s (%d failed)\n",
303type,
304concurrency,
305closed_streams / secs,
306conns_failed);
307fflush(stderr);
308
309MAKE_VALGRIND_HAPPY(loop);
310return 0;
311}
312
313
314BENCHMARK_IMPL(tcp4_pound_100) {
315return pound_it(100,
316"tcp",
317tcp_do_setup,
318tcp_do_connect,
319tcp_make_connect,
320NULL);
321}
322
323
324BENCHMARK_IMPL(tcp4_pound_1000) {
325return pound_it(1000,
326"tcp",
327tcp_do_setup,
328tcp_do_connect,
329tcp_make_connect,
330NULL);
331}
332
333
334BENCHMARK_IMPL(pipe_pound_100) {
335return pound_it(100,
336"pipe",
337pipe_do_setup,
338pipe_do_connect,
339pipe_make_connect,
340NULL);
341}
342
343
344BENCHMARK_IMPL(pipe_pound_1000) {
345return pound_it(1000,
346"pipe",
347pipe_do_setup,
348pipe_do_connect,
349pipe_make_connect,
350NULL);
351}
352