Home | History | Annotate | Line # | Download | only in test
benchmark-ping-pongs.c revision 1.1
      1  1.1  christos /* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
      2  1.1  christos  *
      3  1.1  christos  * Permission is hereby granted, free of charge, to any person obtaining a copy
      4  1.1  christos  * of this software and associated documentation files (the "Software"), to
      5  1.1  christos  * deal in the Software without restriction, including without limitation the
      6  1.1  christos  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
      7  1.1  christos  * sell copies of the Software, and to permit persons to whom the Software is
      8  1.1  christos  * furnished to do so, subject to the following conditions:
      9  1.1  christos  *
     10  1.1  christos  * The above copyright notice and this permission notice shall be included in
     11  1.1  christos  * all copies or substantial portions of the Software.
     12  1.1  christos  *
     13  1.1  christos  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     14  1.1  christos  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     15  1.1  christos  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     16  1.1  christos  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     17  1.1  christos  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     18  1.1  christos  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
     19  1.1  christos  * IN THE SOFTWARE.
     20  1.1  christos  */
     21  1.1  christos 
     22  1.1  christos #include "uv.h"
     23  1.1  christos #include "task.h"
     24  1.1  christos 
     25  1.1  christos #include <stdlib.h>
     26  1.1  christos #include <stdio.h>
     27  1.1  christos 
     28  1.1  christos /* Run the benchmark for this many ms */
     29  1.1  christos #define TIME 5000
     30  1.1  christos 
     31  1.1  christos 
     32  1.1  christos typedef struct {
     33  1.1  christos   int pongs;
     34  1.1  christos   int state;
     35  1.1  christos   uv_tcp_t tcp;
     36  1.1  christos   uv_connect_t connect_req;
     37  1.1  christos   uv_shutdown_t shutdown_req;
     38  1.1  christos } pinger_t;
     39  1.1  christos 
     40  1.1  christos typedef struct buf_s {
     41  1.1  christos   uv_buf_t uv_buf_t;
     42  1.1  christos   struct buf_s* next;
     43  1.1  christos } buf_t;
     44  1.1  christos 
     45  1.1  christos 
     46  1.1  christos static char PING[] = "PING\n";
     47  1.1  christos 
     48  1.1  christos static uv_loop_t* loop;
     49  1.1  christos 
     50  1.1  christos static buf_t* buf_freelist = NULL;
     51  1.1  christos static int pinger_shutdown_cb_called;
     52  1.1  christos static int completed_pingers = 0;
     53  1.1  christos static int64_t start_time;
     54  1.1  christos 
     55  1.1  christos 
     56  1.1  christos static void buf_alloc(uv_handle_t* tcp, size_t size, uv_buf_t* buf) {
     57  1.1  christos   buf_t* ab;
     58  1.1  christos 
     59  1.1  christos   ab = buf_freelist;
     60  1.1  christos   if (ab != NULL)
     61  1.1  christos     buf_freelist = ab->next;
     62  1.1  christos   else {
     63  1.1  christos     ab = malloc(size + sizeof(*ab));
     64  1.1  christos     ab->uv_buf_t.len = size;
     65  1.1  christos     ab->uv_buf_t.base = (char*) (ab + 1);
     66  1.1  christos   }
     67  1.1  christos 
     68  1.1  christos   *buf = ab->uv_buf_t;
     69  1.1  christos }
     70  1.1  christos 
     71  1.1  christos 
     72  1.1  christos static void buf_free(const uv_buf_t* buf) {
     73  1.1  christos   buf_t* ab = (buf_t*) buf->base - 1;
     74  1.1  christos   ab->next = buf_freelist;
     75  1.1  christos   buf_freelist = ab;
     76  1.1  christos }
     77  1.1  christos 
     78  1.1  christos 
     79  1.1  christos static void pinger_close_cb(uv_handle_t* handle) {
     80  1.1  christos   pinger_t* pinger;
     81  1.1  christos 
     82  1.1  christos   pinger = (pinger_t*)handle->data;
     83  1.1  christos   fprintf(stderr, "ping_pongs: %d roundtrips/s\n", (1000 * pinger->pongs) / TIME);
     84  1.1  christos   fflush(stderr);
     85  1.1  christos 
     86  1.1  christos   free(pinger);
     87  1.1  christos 
     88  1.1  christos   completed_pingers++;
     89  1.1  christos }
     90  1.1  christos 
     91  1.1  christos 
     92  1.1  christos static void pinger_write_cb(uv_write_t* req, int status) {
     93  1.1  christos   ASSERT(status == 0);
     94  1.1  christos 
     95  1.1  christos   free(req);
     96  1.1  christos }
     97  1.1  christos 
     98  1.1  christos 
     99  1.1  christos static void pinger_write_ping(pinger_t* pinger) {
    100  1.1  christos   uv_write_t* req;
    101  1.1  christos   uv_buf_t buf;
    102  1.1  christos 
    103  1.1  christos   buf = uv_buf_init(PING, sizeof(PING) - 1);
    104  1.1  christos 
    105  1.1  christos   req = malloc(sizeof *req);
    106  1.1  christos   if (uv_write(req, (uv_stream_t*) &pinger->tcp, &buf, 1, pinger_write_cb)) {
    107  1.1  christos     FATAL("uv_write failed");
    108  1.1  christos   }
    109  1.1  christos }
    110  1.1  christos 
    111  1.1  christos 
    112  1.1  christos static void pinger_shutdown_cb(uv_shutdown_t* req, int status) {
    113  1.1  christos   ASSERT(status == 0);
    114  1.1  christos   pinger_shutdown_cb_called++;
    115  1.1  christos 
    116  1.1  christos   /*
    117  1.1  christos    * The close callback has not been triggered yet. We must wait for EOF
    118  1.1  christos    * until we close the connection.
    119  1.1  christos    */
    120  1.1  christos   ASSERT(completed_pingers == 0);
    121  1.1  christos }
    122  1.1  christos 
    123  1.1  christos 
    124  1.1  christos static void pinger_read_cb(uv_stream_t* tcp,
    125  1.1  christos                            ssize_t nread,
    126  1.1  christos                            const uv_buf_t* buf) {
    127  1.1  christos   ssize_t i;
    128  1.1  christos   pinger_t* pinger;
    129  1.1  christos 
    130  1.1  christos   pinger = (pinger_t*)tcp->data;
    131  1.1  christos 
    132  1.1  christos   if (nread < 0) {
    133  1.1  christos     ASSERT(nread == UV_EOF);
    134  1.1  christos 
    135  1.1  christos     if (buf->base) {
    136  1.1  christos       buf_free(buf);
    137  1.1  christos     }
    138  1.1  christos 
    139  1.1  christos     ASSERT(pinger_shutdown_cb_called == 1);
    140  1.1  christos     uv_close((uv_handle_t*)tcp, pinger_close_cb);
    141  1.1  christos 
    142  1.1  christos     return;
    143  1.1  christos   }
    144  1.1  christos 
    145  1.1  christos   /* Now we count the pings */
    146  1.1  christos   for (i = 0; i < nread; i++) {
    147  1.1  christos     ASSERT(buf->base[i] == PING[pinger->state]);
    148  1.1  christos     pinger->state = (pinger->state + 1) % (sizeof(PING) - 1);
    149  1.1  christos     if (pinger->state == 0) {
    150  1.1  christos       pinger->pongs++;
    151  1.1  christos       if (uv_now(loop) - start_time > TIME) {
    152  1.1  christos         uv_shutdown(&pinger->shutdown_req,
    153  1.1  christos                     (uv_stream_t*) tcp,
    154  1.1  christos                     pinger_shutdown_cb);
    155  1.1  christos         break;
    156  1.1  christos       } else {
    157  1.1  christos         pinger_write_ping(pinger);
    158  1.1  christos       }
    159  1.1  christos     }
    160  1.1  christos   }
    161  1.1  christos 
    162  1.1  christos   buf_free(buf);
    163  1.1  christos }
    164  1.1  christos 
    165  1.1  christos 
    166  1.1  christos static void pinger_connect_cb(uv_connect_t* req, int status) {
    167  1.1  christos   pinger_t *pinger = (pinger_t*)req->handle->data;
    168  1.1  christos 
    169  1.1  christos   ASSERT(status == 0);
    170  1.1  christos 
    171  1.1  christos   pinger_write_ping(pinger);
    172  1.1  christos 
    173  1.1  christos   if (uv_read_start(req->handle, buf_alloc, pinger_read_cb)) {
    174  1.1  christos     FATAL("uv_read_start failed");
    175  1.1  christos   }
    176  1.1  christos }
    177  1.1  christos 
    178  1.1  christos 
    179  1.1  christos static void pinger_new(void) {
    180  1.1  christos   struct sockaddr_in client_addr;
    181  1.1  christos   struct sockaddr_in server_addr;
    182  1.1  christos   pinger_t *pinger;
    183  1.1  christos   int r;
    184  1.1  christos 
    185  1.1  christos   ASSERT(0 == uv_ip4_addr("0.0.0.0", 0, &client_addr));
    186  1.1  christos   ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &server_addr));
    187  1.1  christos   pinger = malloc(sizeof(*pinger));
    188  1.1  christos   pinger->state = 0;
    189  1.1  christos   pinger->pongs = 0;
    190  1.1  christos 
    191  1.1  christos   /* Try to connect to the server and do NUM_PINGS ping-pongs. */
    192  1.1  christos   r = uv_tcp_init(loop, &pinger->tcp);
    193  1.1  christos   ASSERT(!r);
    194  1.1  christos 
    195  1.1  christos   pinger->tcp.data = pinger;
    196  1.1  christos 
    197  1.1  christos   ASSERT(0 == uv_tcp_bind(&pinger->tcp,
    198  1.1  christos                           (const struct sockaddr*) &client_addr,
    199  1.1  christos                           0));
    200  1.1  christos 
    201  1.1  christos   r = uv_tcp_connect(&pinger->connect_req,
    202  1.1  christos                      &pinger->tcp,
    203  1.1  christos                      (const struct sockaddr*) &server_addr,
    204  1.1  christos                      pinger_connect_cb);
    205  1.1  christos   ASSERT(!r);
    206  1.1  christos }
    207  1.1  christos 
    208  1.1  christos 
    209  1.1  christos BENCHMARK_IMPL(ping_pongs) {
    210  1.1  christos   loop = uv_default_loop();
    211  1.1  christos 
    212  1.1  christos   start_time = uv_now(loop);
    213  1.1  christos 
    214  1.1  christos   pinger_new();
    215  1.1  christos   uv_run(loop, UV_RUN_DEFAULT);
    216  1.1  christos 
    217  1.1  christos   ASSERT(completed_pingers == 1);
    218  1.1  christos 
    219  1.1  christos   MAKE_VALGRIND_HAPPY();
    220  1.1  christos   return 0;
    221  1.1  christos }
    222