1
0

benchmark-pound.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  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. #include "task.h"
  22. #include "uv.h"
  23. /* Update this is you're going to run > 1000 concurrent requests. */
  24. #define MAX_CONNS 1000
  25. #undef NANOSEC
  26. #define NANOSEC ((uint64_t) 1e9)
  27. #undef DEBUG
  28. #define DEBUG 0
  29. struct conn_rec_s;
  30. typedef void (*setup_fn)(int num, void* arg);
  31. typedef void (*make_connect_fn)(struct conn_rec_s* conn);
  32. typedef int (*connect_fn)(int num, make_connect_fn make_connect, void* arg);
  33. /* Base class for tcp_conn_rec and pipe_conn_rec.
  34. * The ordering of fields matters!
  35. */
  36. typedef struct conn_rec_s {
  37. int i;
  38. uv_connect_t conn_req;
  39. uv_write_t write_req;
  40. make_connect_fn make_connect;
  41. uv_stream_t stream;
  42. } conn_rec;
  43. typedef struct {
  44. int i;
  45. uv_connect_t conn_req;
  46. uv_write_t write_req;
  47. make_connect_fn make_connect;
  48. uv_tcp_t stream;
  49. } tcp_conn_rec;
  50. typedef struct {
  51. int i;
  52. uv_connect_t conn_req;
  53. uv_write_t write_req;
  54. make_connect_fn make_connect;
  55. uv_pipe_t stream;
  56. } pipe_conn_rec;
  57. static char buffer[] = "QS";
  58. static uv_loop_t* loop;
  59. static tcp_conn_rec tcp_conns[MAX_CONNS];
  60. static pipe_conn_rec pipe_conns[MAX_CONNS];
  61. static uint64_t start; /* in ms */
  62. static int closed_streams;
  63. static int conns_failed;
  64. static void alloc_cb(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf);
  65. static void connect_cb(uv_connect_t* conn_req, int status);
  66. static void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf);
  67. static void close_cb(uv_handle_t* handle);
  68. static void alloc_cb(uv_handle_t* handle,
  69. size_t suggested_size,
  70. uv_buf_t* buf) {
  71. static char slab[65536];
  72. buf->base = slab;
  73. buf->len = sizeof(slab);
  74. }
  75. static void after_write(uv_write_t* req, int status) {
  76. if (status != 0) {
  77. fprintf(stderr, "write error %s\n", uv_err_name(status));
  78. uv_close((uv_handle_t*)req->handle, close_cb);
  79. conns_failed++;
  80. return;
  81. }
  82. }
  83. static void connect_cb(uv_connect_t* req, int status) {
  84. conn_rec* conn;
  85. uv_buf_t buf;
  86. int r;
  87. if (status != 0) {
  88. #if DEBUG
  89. fprintf(stderr, "connect error %s\n", uv_err_name(status));
  90. #endif
  91. uv_close((uv_handle_t*)req->handle, close_cb);
  92. conns_failed++;
  93. return;
  94. }
  95. ASSERT(req != NULL);
  96. ASSERT(status == 0);
  97. conn = (conn_rec*)req->data;
  98. ASSERT(conn != NULL);
  99. #if DEBUG
  100. printf("connect_cb %d\n", conn->i);
  101. #endif
  102. r = uv_read_start(&conn->stream, alloc_cb, read_cb);
  103. ASSERT(r == 0);
  104. buf.base = buffer;
  105. buf.len = sizeof(buffer) - 1;
  106. r = uv_write(&conn->write_req, &conn->stream, &buf, 1, after_write);
  107. ASSERT(r == 0);
  108. }
  109. static void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
  110. ASSERT(stream != NULL);
  111. #if DEBUG
  112. printf("read_cb %d\n", p->i);
  113. #endif
  114. uv_close((uv_handle_t*)stream, close_cb);
  115. if (nread < 0) {
  116. if (nread == UV_EOF) {
  117. ;
  118. } else if (nread == UV_ECONNRESET) {
  119. conns_failed++;
  120. } else {
  121. fprintf(stderr, "read error %s\n", uv_err_name(nread));
  122. ASSERT(0);
  123. }
  124. }
  125. }
  126. static void close_cb(uv_handle_t* handle) {
  127. conn_rec* p = (conn_rec*)handle->data;
  128. ASSERT(handle != NULL);
  129. closed_streams++;
  130. #if DEBUG
  131. printf("close_cb %d\n", p->i);
  132. #endif
  133. if (uv_now(loop) - start < 10000) {
  134. p->make_connect(p);
  135. }
  136. }
  137. static void tcp_do_setup(int num, void* arg) {
  138. int i;
  139. for (i = 0; i < num; i++) {
  140. tcp_conns[i].i = i;
  141. }
  142. }
  143. static void pipe_do_setup(int num, void* arg) {
  144. int i;
  145. for (i = 0; i < num; i++) {
  146. pipe_conns[i].i = i;
  147. }
  148. }
  149. static void tcp_make_connect(conn_rec* p) {
  150. struct sockaddr_in addr;
  151. tcp_conn_rec* tp;
  152. int r;
  153. tp = (tcp_conn_rec*) p;
  154. r = uv_tcp_init(loop, (uv_tcp_t*)&p->stream);
  155. ASSERT(r == 0);
  156. ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
  157. r = uv_tcp_connect(&tp->conn_req,
  158. (uv_tcp_t*) &p->stream,
  159. (const struct sockaddr*) &addr,
  160. connect_cb);
  161. if (r) {
  162. fprintf(stderr, "uv_tcp_connect error %s\n", uv_err_name(r));
  163. ASSERT(0);
  164. }
  165. #if DEBUG
  166. printf("make connect %d\n", p->i);
  167. #endif
  168. p->conn_req.data = p;
  169. p->write_req.data = p;
  170. p->stream.data = p;
  171. }
  172. static void pipe_make_connect(conn_rec* p) {
  173. int r;
  174. r = uv_pipe_init(loop, (uv_pipe_t*)&p->stream, 0);
  175. ASSERT(r == 0);
  176. uv_pipe_connect(&((pipe_conn_rec*) p)->conn_req,
  177. (uv_pipe_t*) &p->stream,
  178. TEST_PIPENAME,
  179. connect_cb);
  180. #if DEBUG
  181. printf("make connect %d\n", p->i);
  182. #endif
  183. p->conn_req.data = p;
  184. p->write_req.data = p;
  185. p->stream.data = p;
  186. }
  187. static int tcp_do_connect(int num, make_connect_fn make_connect, void* arg) {
  188. int i;
  189. for (i = 0; i < num; i++) {
  190. tcp_make_connect((conn_rec*)&tcp_conns[i]);
  191. tcp_conns[i].make_connect = make_connect;
  192. }
  193. return 0;
  194. }
  195. static int pipe_do_connect(int num, make_connect_fn make_connect, void* arg) {
  196. int i;
  197. for (i = 0; i < num; i++) {
  198. pipe_make_connect((conn_rec*)&pipe_conns[i]);
  199. pipe_conns[i].make_connect = make_connect;
  200. }
  201. return 0;
  202. }
  203. static int pound_it(int concurrency,
  204. const char* type,
  205. setup_fn do_setup,
  206. connect_fn do_connect,
  207. make_connect_fn make_connect,
  208. void* arg) {
  209. double secs;
  210. int r;
  211. uint64_t start_time; /* in ns */
  212. uint64_t end_time;
  213. loop = uv_default_loop();
  214. uv_update_time(loop);
  215. start = uv_now(loop);
  216. /* Run benchmark for at least five seconds. */
  217. start_time = uv_hrtime();
  218. do_setup(concurrency, arg);
  219. r = do_connect(concurrency, make_connect, arg);
  220. ASSERT(!r);
  221. uv_run(loop, UV_RUN_DEFAULT);
  222. end_time = uv_hrtime();
  223. /* Number of fractional seconds it took to run the benchmark. */
  224. secs = (double)(end_time - start_time) / NANOSEC;
  225. LOGF("%s-conn-pound-%d: %.0f accepts/s (%d failed)\n",
  226. type,
  227. concurrency,
  228. closed_streams / secs,
  229. conns_failed);
  230. MAKE_VALGRIND_HAPPY();
  231. return 0;
  232. }
  233. BENCHMARK_IMPL(tcp4_pound_100) {
  234. return pound_it(100,
  235. "tcp",
  236. tcp_do_setup,
  237. tcp_do_connect,
  238. tcp_make_connect,
  239. NULL);
  240. }
  241. BENCHMARK_IMPL(tcp4_pound_1000) {
  242. return pound_it(1000,
  243. "tcp",
  244. tcp_do_setup,
  245. tcp_do_connect,
  246. tcp_make_connect,
  247. NULL);
  248. }
  249. BENCHMARK_IMPL(pipe_pound_100) {
  250. return pound_it(100,
  251. "pipe",
  252. pipe_do_setup,
  253. pipe_do_connect,
  254. pipe_make_connect,
  255. NULL);
  256. }
  257. BENCHMARK_IMPL(pipe_pound_1000) {
  258. return pound_it(1000,
  259. "pipe",
  260. pipe_do_setup,
  261. pipe_do_connect,
  262. pipe_make_connect,
  263. NULL);
  264. }