From c77d08eb9229f738aa9d6433a1d3e1d711abfa3d Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sat, 25 Aug 2012 22:02:37 +0200 Subject: [PATCH] bench: add timed and non-timed udp pummel benchmarks --- test/benchmark-list.h | 66 +++++--- test/benchmark-udp-packet-storm.c | 247 ------------------------------ test/benchmark-udp-pummel.c | 229 +++++++++++++++++++++++++++ uv.gyp | 2 +- 4 files changed, 276 insertions(+), 268 deletions(-) delete mode 100644 test/benchmark-udp-packet-storm.c create mode 100644 test/benchmark-udp-pummel.c diff --git a/test/benchmark-list.h b/test/benchmark-list.h index 5d59d4cf..8b6efeef 100644 --- a/test/benchmark-list.h +++ b/test/benchmark-list.h @@ -32,16 +32,31 @@ BENCHMARK_DECLARE (tcp_pump100_client) BENCHMARK_DECLARE (tcp_pump1_client) BENCHMARK_DECLARE (pipe_pump100_client) BENCHMARK_DECLARE (pipe_pump1_client) -BENCHMARK_DECLARE (udp_packet_storm_1v1) -BENCHMARK_DECLARE (udp_packet_storm_1v10) -BENCHMARK_DECLARE (udp_packet_storm_1v100) -BENCHMARK_DECLARE (udp_packet_storm_1v1000) -BENCHMARK_DECLARE (udp_packet_storm_10v10) -BENCHMARK_DECLARE (udp_packet_storm_10v100) -BENCHMARK_DECLARE (udp_packet_storm_10v1000) -BENCHMARK_DECLARE (udp_packet_storm_100v100) -BENCHMARK_DECLARE (udp_packet_storm_100v1000) -BENCHMARK_DECLARE (udp_packet_storm_1000v1000) + +/* Run until X packets have been sent/received. */ +BENCHMARK_DECLARE (udp_pummel_1v1) +BENCHMARK_DECLARE (udp_pummel_1v10) +BENCHMARK_DECLARE (udp_pummel_1v100) +BENCHMARK_DECLARE (udp_pummel_1v1000) +BENCHMARK_DECLARE (udp_pummel_10v10) +BENCHMARK_DECLARE (udp_pummel_10v100) +BENCHMARK_DECLARE (udp_pummel_10v1000) +BENCHMARK_DECLARE (udp_pummel_100v100) +BENCHMARK_DECLARE (udp_pummel_100v1000) +BENCHMARK_DECLARE (udp_pummel_1000v1000) + +/* Run until X seconds have elapsed. */ +BENCHMARK_DECLARE (udp_timed_pummel_1v1) +BENCHMARK_DECLARE (udp_timed_pummel_1v10) +BENCHMARK_DECLARE (udp_timed_pummel_1v100) +BENCHMARK_DECLARE (udp_timed_pummel_1v1000) +BENCHMARK_DECLARE (udp_timed_pummel_10v10) +BENCHMARK_DECLARE (udp_timed_pummel_10v100) +BENCHMARK_DECLARE (udp_timed_pummel_10v1000) +BENCHMARK_DECLARE (udp_timed_pummel_100v100) +BENCHMARK_DECLARE (udp_timed_pummel_100v1000) +BENCHMARK_DECLARE (udp_timed_pummel_1000v1000) + BENCHMARK_DECLARE (getaddrinfo) BENCHMARK_DECLARE (fs_stat) BENCHMARK_DECLARE (async1) @@ -97,16 +112,27 @@ TASK_LIST_START BENCHMARK_ENTRY (pipe_pound_1000) BENCHMARK_HELPER (pipe_pound_1000, pipe_echo_server) - BENCHMARK_ENTRY (udp_packet_storm_1v1) - BENCHMARK_ENTRY (udp_packet_storm_1v10) - BENCHMARK_ENTRY (udp_packet_storm_1v100) - BENCHMARK_ENTRY (udp_packet_storm_1v1000) - BENCHMARK_ENTRY (udp_packet_storm_10v10) - BENCHMARK_ENTRY (udp_packet_storm_10v100) - BENCHMARK_ENTRY (udp_packet_storm_10v1000) - BENCHMARK_ENTRY (udp_packet_storm_100v100) - BENCHMARK_ENTRY (udp_packet_storm_100v1000) - BENCHMARK_ENTRY (udp_packet_storm_1000v1000) + BENCHMARK_ENTRY (udp_pummel_1v1) + BENCHMARK_ENTRY (udp_pummel_1v10) + BENCHMARK_ENTRY (udp_pummel_1v100) + BENCHMARK_ENTRY (udp_pummel_1v1000) + BENCHMARK_ENTRY (udp_pummel_10v10) + BENCHMARK_ENTRY (udp_pummel_10v100) + BENCHMARK_ENTRY (udp_pummel_10v1000) + BENCHMARK_ENTRY (udp_pummel_100v100) + BENCHMARK_ENTRY (udp_pummel_100v1000) + BENCHMARK_ENTRY (udp_pummel_1000v1000) + + BENCHMARK_ENTRY (udp_timed_pummel_1v1) + BENCHMARK_ENTRY (udp_timed_pummel_1v10) + BENCHMARK_ENTRY (udp_timed_pummel_1v100) + BENCHMARK_ENTRY (udp_timed_pummel_1v1000) + BENCHMARK_ENTRY (udp_timed_pummel_10v10) + BENCHMARK_ENTRY (udp_timed_pummel_10v100) + BENCHMARK_ENTRY (udp_timed_pummel_10v1000) + BENCHMARK_ENTRY (udp_timed_pummel_100v100) + BENCHMARK_ENTRY (udp_timed_pummel_100v1000) + BENCHMARK_ENTRY (udp_timed_pummel_1000v1000) BENCHMARK_ENTRY (getaddrinfo) diff --git a/test/benchmark-udp-packet-storm.c b/test/benchmark-udp-packet-storm.c deleted file mode 100644 index 9842e4ce..00000000 --- a/test/benchmark-udp-packet-storm.c +++ /dev/null @@ -1,247 +0,0 @@ -/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -#include "task.h" -#include "uv.h" - -#include -#include -#include - -#define EXPECTED "RANG TANG DING DONG I AM THE JAPANESE SANDMAN" /* "Take eight!" */ - -#define TEST_DURATION 5000 /* ms */ - -#define MAX_SENDERS 1000 -#define MAX_RECEIVERS 1000 - -#define BASE_PORT 12345 - -static uv_loop_t* loop; - -static int n_senders_; -static int n_receivers_; -static uv_udp_t senders[MAX_SENDERS]; -static uv_udp_t receivers[MAX_RECEIVERS]; -static uv_buf_t bufs[5]; - -static int send_cb_called; -static int recv_cb_called; -static int close_cb_called; -static int stopping = 0; - -typedef struct { - struct sockaddr_in addr; -} sender_state_t; - - -static uv_buf_t alloc_cb(uv_handle_t* handle, size_t suggested_size) { - static char slab[65536]; - ASSERT(suggested_size <= sizeof slab); - return uv_buf_init(slab, sizeof slab); -} - - -static void send_cb(uv_udp_send_t* req, int status) { - sender_state_t* ss; - int r; - - if (stopping) { - return; - } - - ASSERT(req != NULL); - ASSERT(status == 0); - - ss = req->data; - - r = uv_udp_send(req, req->handle, bufs, ARRAY_SIZE(bufs), ss->addr, send_cb); - ASSERT(r == 0); - - req->data = ss; - - send_cb_called++; -} - - -static void recv_cb(uv_udp_t* handle, - ssize_t nread, - uv_buf_t buf, - struct sockaddr* addr, - unsigned flags) { - if (nread == 0) - return; - - if (nread == -1) { - ASSERT(uv_last_error(loop).code == UV_ECANCELED); - return; - } - - ASSERT(addr->sa_family == AF_INET); - ASSERT(!memcmp(buf.base, EXPECTED, nread)); - - recv_cb_called++; -} - - -static void close_cb(uv_handle_t* handle) { - ASSERT(handle != NULL); - close_cb_called++; -} - - -static void timeout_cb(uv_timer_t* timer, int status) { - int i; - - stopping = 1; - - for (i = 0; i < n_senders_; i++) - uv_close((uv_handle_t*)&senders[i], close_cb); - - for (i = 0; i < n_receivers_; i++) - uv_close((uv_handle_t*)&receivers[i], close_cb); -} - - -static int do_packet_storm(int n_senders, int n_receivers) { - uv_timer_t timeout; - sender_state_t *ss; - uv_udp_send_t* req; - uv_udp_t* handle; - int i; - int r; - - ASSERT(n_senders <= MAX_SENDERS); - ASSERT(n_receivers <= MAX_RECEIVERS); - - loop = uv_default_loop(); - - n_senders_ = n_senders; - n_receivers_ = n_receivers; - - r = uv_timer_init(loop, &timeout); - ASSERT(r == 0); - - r = uv_timer_start(&timeout, timeout_cb, TEST_DURATION, 0); - ASSERT(r == 0); - - /* Timer should not keep loop alive. */ - uv_unref((uv_handle_t*)&timeout); - - for (i = 0; i < n_receivers; i++) { - struct sockaddr_in addr; - handle = &receivers[i]; - - r = uv_udp_init(loop, handle); - ASSERT(r == 0); - - addr = uv_ip4_addr("0.0.0.0", BASE_PORT + i); - - r = uv_udp_bind(handle, addr, 0); - ASSERT(r == 0); - - r = uv_udp_recv_start(handle, alloc_cb, recv_cb); - ASSERT(r == 0); - } - - bufs[0] = uv_buf_init(EXPECTED + 0, 10); - bufs[1] = uv_buf_init(EXPECTED + 10, 10); - bufs[2] = uv_buf_init(EXPECTED + 20, 10); - bufs[3] = uv_buf_init(EXPECTED + 30, 10); - bufs[4] = uv_buf_init(EXPECTED + 40, 5); - - for (i = 0; i < n_senders; i++) { - handle = &senders[i]; - - r = uv_udp_init(loop, handle); - ASSERT(r == 0); - - req = malloc(sizeof(*req) + sizeof(*ss)); - - ss = (void*)(req + 1); - ss->addr = uv_ip4_addr("127.0.0.1", BASE_PORT + (i % n_receivers)); - - r = uv_udp_send(req, handle, bufs, ARRAY_SIZE(bufs), ss->addr, send_cb); - ASSERT(r == 0); - - req->data = ss; - } - - uv_run(loop); - - printf("udp_packet_storm_%dv%d: %.0f/s received, %.0f/s sent\n", - n_receivers, - n_senders, - recv_cb_called / (TEST_DURATION / 1000.0), - send_cb_called / (TEST_DURATION / 1000.0)); - - return 0; -} - - -BENCHMARK_IMPL(udp_packet_storm_1v1) { - return do_packet_storm(1, 1); -} - - -BENCHMARK_IMPL(udp_packet_storm_1v10) { - return do_packet_storm(1, 10); -} - - -BENCHMARK_IMPL(udp_packet_storm_1v100) { - return do_packet_storm(1, 100); -} - - -BENCHMARK_IMPL(udp_packet_storm_1v1000) { - return do_packet_storm(1, 1000); -} - - -BENCHMARK_IMPL(udp_packet_storm_10v10) { - return do_packet_storm(10, 10); -} - - -BENCHMARK_IMPL(udp_packet_storm_10v100) { - return do_packet_storm(10, 100); -} - - -BENCHMARK_IMPL(udp_packet_storm_10v1000) { - return do_packet_storm(10, 1000); -} - - -BENCHMARK_IMPL(udp_packet_storm_100v100) { - return do_packet_storm(100, 100); -} - - -BENCHMARK_IMPL(udp_packet_storm_100v1000) { - return do_packet_storm(100, 1000); -} - - -BENCHMARK_IMPL(udp_packet_storm_1000v1000) { - return do_packet_storm(1000, 1000); -} diff --git a/test/benchmark-udp-pummel.c b/test/benchmark-udp-pummel.c new file mode 100644 index 00000000..1a186c27 --- /dev/null +++ b/test/benchmark-udp-pummel.c @@ -0,0 +1,229 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "task.h" +#include "uv.h" + +#include +#include +#include + +#define EXPECTED "RANG TANG DING DONG I AM THE JAPANESE SANDMAN" /* "Take eight!" */ + +#define TEST_DURATION 5000 /* ms */ + +#define BASE_PORT 12345 + +struct sender_state { + struct sockaddr_in addr; + uv_udp_send_t send_req; + uv_udp_t udp_handle; +}; + +struct receiver_state { + struct sockaddr_in addr; + uv_udp_t udp_handle; +}; + +static unsigned int packet_counter = 1e6; /* not used in timed mode */ + +static int n_senders_; +static int n_receivers_; +static uv_buf_t bufs[5]; +static struct sender_state senders[1024]; +static struct receiver_state receivers[1024]; + +static unsigned int send_cb_called; +static unsigned int recv_cb_called; +static unsigned int close_cb_called; +static int timed; + + +static uv_buf_t alloc_cb(uv_handle_t* handle, size_t suggested_size) { + static char slab[65536]; + ASSERT(suggested_size <= sizeof slab); + return uv_buf_init(slab, sizeof slab); +} + + +static void send_cb(uv_udp_send_t* req, int status) { + struct sender_state* s; + + ASSERT(req != NULL); + + if (status != 0) { + ASSERT(status == -1); + ASSERT(uv_last_error(req->handle->loop).code == UV_EINTR); + return; + } + + s = container_of(req, struct sender_state, send_req); + ASSERT(req->handle == &s->udp_handle); + + if (timed) + goto send; + + if (packet_counter == 0) { + uv_close((uv_handle_t*)&s->udp_handle, NULL); + return; + } + + packet_counter--; + +send: + ASSERT(0 == uv_udp_send(&s->send_req, + &s->udp_handle, + bufs, + ARRAY_SIZE(bufs), + s->addr, + send_cb)); + send_cb_called++; +} + + +static void recv_cb(uv_udp_t* handle, + ssize_t nread, + uv_buf_t buf, + struct sockaddr* addr, + unsigned flags) { + if (nread == 0) + return; + + if (nread == -1) { + ASSERT(uv_last_error(handle->loop).code == UV_ECANCELED); + return; + } + + ASSERT(addr->sa_family == AF_INET); + ASSERT(!memcmp(buf.base, EXPECTED, nread)); + + recv_cb_called++; +} + + +static void close_cb(uv_handle_t* handle) { + ASSERT(handle != NULL); + close_cb_called++; +} + + +static void timeout_cb(uv_timer_t* timer, int status) { + int i; + + for (i = 0; i < n_senders_; i++) + uv_close((uv_handle_t*)&senders[i].udp_handle, close_cb); + + for (i = 0; i < n_receivers_; i++) + uv_close((uv_handle_t*)&receivers[i].udp_handle, close_cb); +} + + +static int do_packet_storm(int n_senders, + int n_receivers, + unsigned long timeout) { + uv_timer_t timer_handle; + uint64_t duration; + uv_loop_t* loop; + int i; + + ASSERT(n_senders <= ARRAY_SIZE(senders)); + ASSERT(n_receivers <= ARRAY_SIZE(receivers)); + + loop = uv_default_loop(); + + n_senders_ = n_senders; + n_receivers_ = n_receivers; + + if (timeout) { + ASSERT(0 == uv_timer_init(loop, &timer_handle)); + ASSERT(0 == uv_timer_start(&timer_handle, timeout_cb, timeout, 0)); + /* Timer should not keep loop alive. */ + uv_unref((uv_handle_t*)&timer_handle); + timed = 1; + } + + for (i = 0; i < n_receivers; i++) { + struct receiver_state* s = receivers + i; + struct sockaddr_in addr = uv_ip4_addr("0.0.0.0", BASE_PORT + i); + ASSERT(0 == uv_udp_init(loop, &s->udp_handle)); + ASSERT(0 == uv_udp_bind(&s->udp_handle, addr, 0)); + ASSERT(0 == uv_udp_recv_start(&s->udp_handle, alloc_cb, recv_cb)); + uv_unref((uv_handle_t*)&s->udp_handle); + } + + bufs[0] = uv_buf_init(EXPECTED + 0, 10); + bufs[1] = uv_buf_init(EXPECTED + 10, 10); + bufs[2] = uv_buf_init(EXPECTED + 20, 10); + bufs[3] = uv_buf_init(EXPECTED + 30, 10); + bufs[4] = uv_buf_init(EXPECTED + 40, 5); + + for (i = 0; i < n_senders; i++) { + struct sender_state* s = senders + i; + s->addr = uv_ip4_addr("127.0.0.1", BASE_PORT + (i % n_receivers)); + ASSERT(0 == uv_udp_init(loop, &s->udp_handle)); + ASSERT(0 == uv_udp_send(&s->send_req, + &s->udp_handle, + bufs, + ARRAY_SIZE(bufs), + s->addr, + send_cb)); + } + + duration = uv_hrtime(); + ASSERT(0 == uv_run(loop)); + duration = uv_hrtime() - duration; + duration = duration / 1e6; /* convert from nanoseconds to milliseconds */ + + printf("udp_packet_storm_%dv%d: %.0f/s received, %.0f/s sent. " + "%u received, %u sent in %.1f seconds.\n", + n_receivers, + n_senders, + recv_cb_called / (duration / 1000.0), + send_cb_called / (duration / 1000.0), + recv_cb_called, + send_cb_called, + duration / 1000.0); + + return 0; +} + + +#define X(a, b) \ + BENCHMARK_IMPL(udp_pummel_##a##v##b) { \ + return do_packet_storm(a, b, 0); \ + } \ + BENCHMARK_IMPL(udp_timed_pummel_##a##v##b) { \ + return do_packet_storm(a, b, TEST_DURATION); \ + } + +X(1, 1) +X(1, 10) +X(1, 100) +X(1, 1000) +X(10, 10) +X(10, 100) +X(10, 1000) +X(100, 10) +X(100, 100) +X(100, 1000) +X(1000, 1000) + +#undef X diff --git a/uv.gyp b/uv.gyp index 7b0fe1a5..d076a9d7 100644 --- a/uv.gyp +++ b/uv.gyp @@ -343,7 +343,7 @@ 'test/benchmark-spawn.c', 'test/benchmark-thread.c', 'test/benchmark-tcp-write-batch.c', - 'test/benchmark-udp-packet-storm.c', + 'test/benchmark-udp-pummel.c', 'test/dns-server.c', 'test/echo-server.c', 'test/blackhole-server.c',