/test/benchmark-udp-packet-storm.c

http://github.com/joyent/libuv · C · 247 lines · 151 code · 75 blank · 21 comment · 22 complexity · b2402f9eb9d5e939a1c022a62f90932b MD5 · raw file

  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. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26. #define EXPECTED "RANG TANG DING DONG I AM THE JAPANESE SANDMAN" /* "Take eight!" */
  27. #define TEST_DURATION 5000 /* ms */
  28. #define MAX_SENDERS 1000
  29. #define MAX_RECEIVERS 1000
  30. #define BASE_PORT 12345
  31. static uv_loop_t* loop;
  32. static int n_senders_;
  33. static int n_receivers_;
  34. static uv_udp_t senders[MAX_SENDERS];
  35. static uv_udp_t receivers[MAX_RECEIVERS];
  36. static uv_buf_t bufs[5];
  37. static int send_cb_called;
  38. static int recv_cb_called;
  39. static int close_cb_called;
  40. static int stopping = 0;
  41. typedef struct {
  42. struct sockaddr_in addr;
  43. } sender_state_t;
  44. static uv_buf_t alloc_cb(uv_handle_t* handle, size_t suggested_size) {
  45. static char slab[65536];
  46. ASSERT(suggested_size <= sizeof slab);
  47. return uv_buf_init(slab, sizeof slab);
  48. }
  49. static void send_cb(uv_udp_send_t* req, int status) {
  50. sender_state_t* ss;
  51. int r;
  52. if (stopping) {
  53. return;
  54. }
  55. ASSERT(req != NULL);
  56. ASSERT(status == 0);
  57. ss = req->data;
  58. r = uv_udp_send(req, req->handle, bufs, ARRAY_SIZE(bufs), ss->addr, send_cb);
  59. ASSERT(r == 0);
  60. req->data = ss;
  61. send_cb_called++;
  62. }
  63. static void recv_cb(uv_udp_t* handle,
  64. ssize_t nread,
  65. uv_buf_t buf,
  66. struct sockaddr* addr,
  67. unsigned flags) {
  68. if (nread == 0)
  69. return;
  70. if (nread == -1) {
  71. ASSERT(uv_last_error(loop).code == UV_EINTR); /* FIXME change error code */
  72. return;
  73. }
  74. ASSERT(addr->sa_family == AF_INET);
  75. ASSERT(!memcmp(buf.base, EXPECTED, nread));
  76. recv_cb_called++;
  77. }
  78. static void close_cb(uv_handle_t* handle) {
  79. ASSERT(handle != NULL);
  80. close_cb_called++;
  81. }
  82. static void timeout_cb(uv_timer_t* timer, int status) {
  83. int i;
  84. stopping = 1;
  85. for (i = 0; i < n_senders_; i++)
  86. uv_close((uv_handle_t*)&senders[i], close_cb);
  87. for (i = 0; i < n_receivers_; i++)
  88. uv_close((uv_handle_t*)&receivers[i], close_cb);
  89. }
  90. static int do_packet_storm(int n_senders, int n_receivers) {
  91. uv_timer_t timeout;
  92. sender_state_t *ss;
  93. uv_udp_send_t* req;
  94. uv_udp_t* handle;
  95. int i;
  96. int r;
  97. ASSERT(n_senders <= MAX_SENDERS);
  98. ASSERT(n_receivers <= MAX_RECEIVERS);
  99. loop = uv_default_loop();
  100. n_senders_ = n_senders;
  101. n_receivers_ = n_receivers;
  102. r = uv_timer_init(loop, &timeout);
  103. ASSERT(r == 0);
  104. r = uv_timer_start(&timeout, timeout_cb, TEST_DURATION, 0);
  105. ASSERT(r == 0);
  106. /* Timer should not keep loop alive. */
  107. uv_unref(loop);
  108. for (i = 0; i < n_receivers; i++) {
  109. struct sockaddr_in addr;
  110. handle = &receivers[i];
  111. r = uv_udp_init(loop, handle);
  112. ASSERT(r == 0);
  113. addr = uv_ip4_addr("0.0.0.0", BASE_PORT + i);
  114. r = uv_udp_bind(handle, addr, 0);
  115. ASSERT(r == 0);
  116. r = uv_udp_recv_start(handle, alloc_cb, recv_cb);
  117. ASSERT(r == 0);
  118. }
  119. bufs[0] = uv_buf_init(EXPECTED + 0, 10);
  120. bufs[1] = uv_buf_init(EXPECTED + 10, 10);
  121. bufs[2] = uv_buf_init(EXPECTED + 20, 10);
  122. bufs[3] = uv_buf_init(EXPECTED + 30, 10);
  123. bufs[4] = uv_buf_init(EXPECTED + 40, 5);
  124. for (i = 0; i < n_senders; i++) {
  125. handle = &senders[i];
  126. r = uv_udp_init(loop, handle);
  127. ASSERT(r == 0);
  128. req = malloc(sizeof(*req) + sizeof(*ss));
  129. ss = (void*)(req + 1);
  130. ss->addr = uv_ip4_addr("127.0.0.1", BASE_PORT + (i % n_receivers));
  131. r = uv_udp_send(req, handle, bufs, ARRAY_SIZE(bufs), ss->addr, send_cb);
  132. ASSERT(r == 0);
  133. req->data = ss;
  134. }
  135. uv_run(loop);
  136. printf("udp_packet_storm_%dv%d: %.0f/s received, %.0f/s sent\n",
  137. n_receivers,
  138. n_senders,
  139. recv_cb_called / (TEST_DURATION / 1000.0),
  140. send_cb_called / (TEST_DURATION / 1000.0));
  141. return 0;
  142. }
  143. BENCHMARK_IMPL(udp_packet_storm_1v1) {
  144. return do_packet_storm(1, 1);
  145. }
  146. BENCHMARK_IMPL(udp_packet_storm_1v10) {
  147. return do_packet_storm(1, 10);
  148. }
  149. BENCHMARK_IMPL(udp_packet_storm_1v100) {
  150. return do_packet_storm(1, 100);
  151. }
  152. BENCHMARK_IMPL(udp_packet_storm_1v1000) {
  153. return do_packet_storm(1, 1000);
  154. }
  155. BENCHMARK_IMPL(udp_packet_storm_10v10) {
  156. return do_packet_storm(10, 10);
  157. }
  158. BENCHMARK_IMPL(udp_packet_storm_10v100) {
  159. return do_packet_storm(10, 100);
  160. }
  161. BENCHMARK_IMPL(udp_packet_storm_10v1000) {
  162. return do_packet_storm(10, 1000);
  163. }
  164. BENCHMARK_IMPL(udp_packet_storm_100v100) {
  165. return do_packet_storm(100, 100);
  166. }
  167. BENCHMARK_IMPL(udp_packet_storm_100v1000) {
  168. return do_packet_storm(100, 1000);
  169. }
  170. BENCHMARK_IMPL(udp_packet_storm_1000v1000) {
  171. return do_packet_storm(1000, 1000);
  172. }