diff --git a/test/benchmark-list.h b/test/benchmark-list.h index 1e843071..29e44c30 100644 --- a/test/benchmark-list.h +++ b/test/benchmark-list.h @@ -23,6 +23,7 @@ BENCHMARK_DECLARE (sizes) BENCHMARK_DECLARE (loop_count) BENCHMARK_DECLARE (loop_count_timed) BENCHMARK_DECLARE (ping_pongs) +BENCHMARK_DECLARE (ping_udp) BENCHMARK_DECLARE (tcp_write_batch) BENCHMARK_DECLARE (tcp4_pound_100) BENCHMARK_DECLARE (tcp4_pound_1000) diff --git a/test/benchmark-ping-udp.c b/test/benchmark-ping-udp.c new file mode 100644 index 00000000..a29502a7 --- /dev/null +++ b/test/benchmark-ping-udp.c @@ -0,0 +1,163 @@ +/* Copyright libuv project 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 "uv.h" +#include "task.h" + +#include +#include + +/* Run the benchmark for this many ms */ +#define TIME 5000 + +typedef struct { + int pongs; + int state; + uv_udp_t udp; + struct sockaddr_in server_addr; +} pinger_t; + +typedef struct buf_s { + uv_buf_t uv_buf_t; + struct buf_s* next; +} buf_t; + +static char PING[] = "PING\n"; + +static uv_loop_t* loop; + +static int completed_pingers; +static unsigned long completed_pings; +static int64_t start_time; + + +static void buf_alloc(uv_handle_t* tcp, size_t size, uv_buf_t* buf) { + static char slab[64 * 1024]; + buf->base = slab; + buf->len = sizeof(slab); +} + + +static void buf_free(const uv_buf_t* buf) { +} + + +static void pinger_close_cb(uv_handle_t* handle) { + pinger_t* pinger; + + pinger = (pinger_t*)handle->data; +#if DEBUG + fprintf(stderr, "ping_pongs: %d roundtrips/s\n", + pinger->pongs / (TIME / 1000)); +#endif + + completed_pings += pinger->pongs; + completed_pingers++; + free(pinger); +} + +static void pinger_write_ping(pinger_t* pinger) { + uv_buf_t buf; + int r; + + buf = uv_buf_init(PING, sizeof(PING) - 1); + r = uv_udp_try_send(&pinger->udp, &buf, 1, + (const struct sockaddr*) &pinger->server_addr); + if (r < 0) + FATAL("uv_udp_send failed"); +} + +static void pinger_read_cb(uv_udp_t* udp, + ssize_t nread, + const uv_buf_t* buf, + const struct sockaddr* addr, + unsigned flags) { + ssize_t i; + pinger_t* pinger; + pinger = (pinger_t*)udp->data; + + /* Now we count the pings */ + for (i = 0; i < nread; i++) { + ASSERT(buf->base[i] == PING[pinger->state]); + pinger->state = (pinger->state + 1) % (sizeof(PING) - 1); + if (pinger->state == 0) { + pinger->pongs++; + if (uv_now(loop) - start_time > TIME) { + uv_close((uv_handle_t*)udp, pinger_close_cb); + break; + } + pinger_write_ping(pinger); + } + } + + buf_free(buf); +} + +static void udp_pinger_new(void) { + pinger_t* pinger = malloc(sizeof(*pinger)); + int r; + + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &pinger->server_addr)); + pinger->state = 0; + pinger->pongs = 0; + + /* Try to do NUM_PINGS ping-pongs (connection-less). */ + r = uv_udp_init(loop, &pinger->udp); + ASSERT(r == 0); + + pinger->udp.data = pinger; + + /* Start pinging */ + if (0 != uv_udp_recv_start(&pinger->udp, buf_alloc, pinger_read_cb)) { + FATAL("uv_udp_read_start failed"); + } + pinger_write_ping(pinger); +} + +static int ping_udp(unsigned pingers) { + unsigned i; + + loop = uv_default_loop(); + start_time = uv_now(loop); + + for (i = 0; i < pingers; ++i) { + udp_pinger_new(); + } + uv_run(loop, UV_RUN_DEFAULT); + ASSERT(completed_pingers >= 1); + + fprintf(stderr, "ping_pongs: %d pingers, ~ %lu roundtrips/s\n", + completed_pingers, completed_pings / (TIME/1000)); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +#define X(PINGERS) \ +BENCHMARK_IMPL(ping_udp##PINGERS) {\ + return ping_udp(PINGERS); \ +} + +X(1) +X(10) +X(100) + +#undef X diff --git a/test/test-list.h b/test/test-list.h index f18264f0..50aaed46 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -685,11 +685,9 @@ TASK_LIST_START TEST_ENTRY (udp_try_send) TEST_ENTRY (udp_open) - TEST_HELPER (udp_open, udp4_echo_server) TEST_ENTRY (udp_open_twice) TEST_ENTRY (udp_open_bound) TEST_ENTRY (udp_open_connect) - TEST_HELPER (udp_open_connect, udp4_echo_server) #ifndef _WIN32 TEST_ENTRY (udp_send_unix) #endif diff --git a/test/test.gyp b/test/test.gyp index 73ff42c5..54b1026d 100644 --- a/test/test.gyp +++ b/test/test.gyp @@ -240,6 +240,7 @@ 'benchmark-million-timers.c', 'benchmark-multi-accept.c', 'benchmark-ping-pongs.c', + 'benchmark-ping-udp.c', 'benchmark-pound.c', 'benchmark-pump.c', 'benchmark-sizes.c',