|
160
|
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 "uv.h"
|
|
|
23 #include "task.h"
|
|
|
24
|
|
|
25 #include <stdlib.h>
|
|
|
26 #include <stdio.h>
|
|
|
27
|
|
|
28 /* Run the benchmark for this many ms */
|
|
|
29 #define TIME 5000
|
|
|
30
|
|
|
31
|
|
|
32 typedef struct {
|
|
|
33 int pongs;
|
|
|
34 int state;
|
|
|
35 uv_tcp_t tcp;
|
|
|
36 uv_connect_t connect_req;
|
|
|
37 uv_shutdown_t shutdown_req;
|
|
|
38 } pinger_t;
|
|
|
39
|
|
|
40 typedef struct buf_s {
|
|
|
41 uv_buf_t uv_buf_t;
|
|
|
42 struct buf_s* next;
|
|
|
43 } buf_t;
|
|
|
44
|
|
|
45
|
|
|
46 static char PING[] = "PING\n";
|
|
|
47
|
|
|
48 static uv_loop_t* loop;
|
|
|
49
|
|
|
50 static buf_t* buf_freelist = NULL;
|
|
|
51 static int pinger_shutdown_cb_called;
|
|
|
52 static int completed_pingers = 0;
|
|
|
53 static int64_t start_time;
|
|
|
54
|
|
|
55
|
|
|
56 static void buf_alloc(uv_handle_t* tcp, size_t size, uv_buf_t* buf) {
|
|
|
57 buf_t* ab;
|
|
|
58
|
|
|
59 ab = buf_freelist;
|
|
|
60 if (ab != NULL)
|
|
|
61 buf_freelist = ab->next;
|
|
|
62 else {
|
|
|
63 ab = malloc(size + sizeof(*ab));
|
|
|
64 ab->uv_buf_t.len = size;
|
|
|
65 ab->uv_buf_t.base = (char*) (ab + 1);
|
|
|
66 }
|
|
|
67
|
|
|
68 *buf = ab->uv_buf_t;
|
|
|
69 }
|
|
|
70
|
|
|
71
|
|
|
72 static void buf_free(const uv_buf_t* buf) {
|
|
|
73 buf_t* ab = (buf_t*) buf->base - 1;
|
|
|
74 ab->next = buf_freelist;
|
|
|
75 buf_freelist = ab;
|
|
|
76 }
|
|
|
77
|
|
|
78
|
|
|
79 static void pinger_close_cb(uv_handle_t* handle) {
|
|
|
80 pinger_t* pinger;
|
|
|
81
|
|
|
82 pinger = (pinger_t*)handle->data;
|
|
|
83 fprintf(stderr, "ping_pongs: %d roundtrips/s\n", (1000 * pinger->pongs) / TIME);
|
|
|
84 fflush(stderr);
|
|
|
85
|
|
|
86 free(pinger);
|
|
|
87
|
|
|
88 completed_pingers++;
|
|
|
89 }
|
|
|
90
|
|
|
91
|
|
|
92 static void pinger_write_cb(uv_write_t* req, int status) {
|
|
|
93 ASSERT_OK(status);
|
|
|
94
|
|
|
95 free(req);
|
|
|
96 }
|
|
|
97
|
|
|
98
|
|
|
99 static void pinger_write_ping(pinger_t* pinger) {
|
|
|
100 uv_write_t* req;
|
|
|
101 uv_buf_t buf;
|
|
|
102
|
|
|
103 buf = uv_buf_init(PING, sizeof(PING) - 1);
|
|
|
104
|
|
|
105 req = malloc(sizeof *req);
|
|
|
106 if (uv_write(req, (uv_stream_t*) &pinger->tcp, &buf, 1, pinger_write_cb)) {
|
|
|
107 FATAL("uv_write failed");
|
|
|
108 }
|
|
|
109 }
|
|
|
110
|
|
|
111
|
|
|
112 static void pinger_shutdown_cb(uv_shutdown_t* req, int status) {
|
|
|
113 ASSERT_OK(status);
|
|
|
114 pinger_shutdown_cb_called++;
|
|
|
115
|
|
|
116 /*
|
|
|
117 * The close callback has not been triggered yet. We must wait for EOF
|
|
|
118 * until we close the connection.
|
|
|
119 */
|
|
|
120 ASSERT_OK(completed_pingers);
|
|
|
121 }
|
|
|
122
|
|
|
123
|
|
|
124 static void pinger_read_cb(uv_stream_t* tcp,
|
|
|
125 ssize_t nread,
|
|
|
126 const uv_buf_t* buf) {
|
|
|
127 ssize_t i;
|
|
|
128 pinger_t* pinger;
|
|
|
129
|
|
|
130 pinger = (pinger_t*)tcp->data;
|
|
|
131
|
|
|
132 if (nread < 0) {
|
|
|
133 ASSERT_EQ(nread, UV_EOF);
|
|
|
134
|
|
|
135 if (buf->base) {
|
|
|
136 buf_free(buf);
|
|
|
137 }
|
|
|
138
|
|
|
139 ASSERT_EQ(1, pinger_shutdown_cb_called);
|
|
|
140 uv_close((uv_handle_t*)tcp, pinger_close_cb);
|
|
|
141
|
|
|
142 return;
|
|
|
143 }
|
|
|
144
|
|
|
145 /* Now we count the pings */
|
|
|
146 for (i = 0; i < nread; i++) {
|
|
|
147 ASSERT_EQ(buf->base[i], PING[pinger->state]);
|
|
|
148 pinger->state = (pinger->state + 1) % (sizeof(PING) - 1);
|
|
|
149 if (pinger->state == 0) {
|
|
|
150 pinger->pongs++;
|
|
|
151 if (uv_now(loop) - start_time > TIME) {
|
|
|
152 uv_shutdown(&pinger->shutdown_req,
|
|
|
153 (uv_stream_t*) tcp,
|
|
|
154 pinger_shutdown_cb);
|
|
|
155 break;
|
|
|
156 } else {
|
|
|
157 pinger_write_ping(pinger);
|
|
|
158 }
|
|
|
159 }
|
|
|
160 }
|
|
|
161
|
|
|
162 buf_free(buf);
|
|
|
163 }
|
|
|
164
|
|
|
165
|
|
|
166 static void pinger_connect_cb(uv_connect_t* req, int status) {
|
|
|
167 pinger_t *pinger = (pinger_t*)req->handle->data;
|
|
|
168
|
|
|
169 ASSERT_OK(status);
|
|
|
170
|
|
|
171 pinger_write_ping(pinger);
|
|
|
172
|
|
|
173 if (uv_read_start(req->handle, buf_alloc, pinger_read_cb)) {
|
|
|
174 FATAL("uv_read_start failed");
|
|
|
175 }
|
|
|
176 }
|
|
|
177
|
|
|
178
|
|
|
179 static void pinger_new(void) {
|
|
|
180 struct sockaddr_in client_addr;
|
|
|
181 struct sockaddr_in server_addr;
|
|
|
182 pinger_t *pinger;
|
|
|
183 int r;
|
|
|
184
|
|
|
185 ASSERT_OK(uv_ip4_addr("0.0.0.0", 0, &client_addr));
|
|
|
186 ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &server_addr));
|
|
|
187 pinger = malloc(sizeof(*pinger));
|
|
|
188 pinger->state = 0;
|
|
|
189 pinger->pongs = 0;
|
|
|
190
|
|
|
191 /* Try to connect to the server and do NUM_PINGS ping-pongs. */
|
|
|
192 r = uv_tcp_init(loop, &pinger->tcp);
|
|
|
193 ASSERT(!r);
|
|
|
194
|
|
|
195 pinger->tcp.data = pinger;
|
|
|
196
|
|
|
197 ASSERT_OK(uv_tcp_bind(&pinger->tcp,
|
|
|
198 (const struct sockaddr*) &client_addr,
|
|
|
199 0));
|
|
|
200
|
|
|
201 r = uv_tcp_connect(&pinger->connect_req,
|
|
|
202 &pinger->tcp,
|
|
|
203 (const struct sockaddr*) &server_addr,
|
|
|
204 pinger_connect_cb);
|
|
|
205 ASSERT(!r);
|
|
|
206 }
|
|
|
207
|
|
|
208
|
|
|
209 BENCHMARK_IMPL(ping_pongs) {
|
|
|
210 loop = uv_default_loop();
|
|
|
211
|
|
|
212 start_time = uv_now(loop);
|
|
|
213
|
|
|
214 pinger_new();
|
|
|
215 uv_run(loop, UV_RUN_DEFAULT);
|
|
|
216
|
|
|
217 ASSERT_EQ(1, completed_pingers);
|
|
|
218
|
|
|
219 MAKE_VALGRIND_HAPPY(loop);
|
|
|
220 return 0;
|
|
|
221 }
|