From 8a8da32a2b0c3f46fe5439651c4546d0760ea867 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Wed, 26 Oct 2011 11:41:50 +0000 Subject: [PATCH] expanding gnunet-transport towards a benchmarking tool --- src/transport/gnunet-transport.c | 204 +++++++++++++++++++++++++++++-- 1 file changed, 196 insertions(+), 8 deletions(-) diff --git a/src/transport/gnunet-transport.c b/src/transport/gnunet-transport.c index d3b8aabca..10994fbf8 100644 --- a/src/transport/gnunet-transport.c +++ b/src/transport/gnunet-transport.c @@ -20,7 +20,7 @@ /** * @file src/transport/gnunet-transport.c - * @brief Tool to help configure the transports. + * @brief Tool to help configure, measure and control the transport subsystem. * @author Christian Grothoff * * This utility can be used to test if a transport mechanism for @@ -36,11 +36,183 @@ static char *cpid; static struct GNUNET_TRANSPORT_Handle *handle; +static int benchmark_send; + +static int benchmark_receive; + +static int ret; + +static unsigned long long traffic_received; + +static unsigned long long traffic_sent; + +static struct GNUNET_TIME_Absolute start_time; + +static struct GNUNET_TRANSPORT_TransmitHandle *th; + +static struct GNUNET_PeerIdentity pid; + +static GNUNET_SCHEDULER_TaskIdentifier end; + + +/** + * Shutdown, print statistics. + */ static void do_disconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { - GNUNET_TRANSPORT_disconnect (handle); + struct GNUNET_TIME_Relative duration; + + if (NULL != th) + { + GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); + th = NULL; + } + GNUNET_TRANSPORT_disconnect (handle); + if (benchmark_receive) + { + duration = GNUNET_TIME_absolute_get_duration (start_time); + fprintf (stderr, + "Received %llu bytes/s\n", + traffic_received / (1+duration.rel_value)); + } + if (benchmark_send) + { + duration = GNUNET_TIME_absolute_get_duration (start_time); + fprintf (stderr, + "Transmitted %llu bytes/s\n", + traffic_sent / (1+duration.rel_value)); + } +} + + +/** + * Function called to notify a client about the socket + * begin ready to queue more data. "buf" will be + * NULL and "size" zero if the socket was closed for + * writing in the meantime. + * + * @param cls closure + * @param size number of bytes available in buf + * @param buf where the callee should write the message + * @return number of bytes written to buf + */ +static size_t +transmit_data (void *cls, size_t size, + void *buf) +{ + struct GNUNET_MessageHeader *m = buf; + + GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader)); + GNUNET_assert (size < GNUNET_SERVER_MAX_MESSAGE_SIZE); + m->size = ntohs (size); + m->type = ntohs (GNUNET_MESSAGE_TYPE_DUMMY); + memset (&m[1], 52, size - sizeof (struct GNUNET_MessageHeader)); + traffic_sent += size; + th = GNUNET_TRANSPORT_notify_transmit_ready (handle, + &pid, + 32 * 1024, + 0, + GNUNET_TIME_UNIT_FOREVER_REL, + &transmit_data, NULL); + return size; +} + + +/** + * Function called to notify transport users that another + * peer connected to us. + * + * @param cls closure + * @param peer the peer that connected + * @param ats performance data + * @param ats_count number of entries in ats (excluding 0-termination) + */ +static void +notify_connect (void *cls, + const struct GNUNET_PeerIdentity + * peer, + const struct + GNUNET_ATS_Information + * ats, uint32_t ats_count) +{ + if (0 != memcmp (&pid, + peer, + sizeof (struct GNUNET_PeerIdentity))) + return; + ret = 0; + if (benchmark_send) + { + start_time = GNUNET_TIME_absolute_get (); + th = GNUNET_TRANSPORT_notify_transmit_ready (handle, + peer, + 32 * 1024, + 0, + GNUNET_TIME_UNIT_FOREVER_REL, + &transmit_data, NULL); + } + else + { + /* all done, terminate instantly */ + GNUNET_SCHEDULER_cancel (end); + end = GNUNET_SCHEDULER_add_now (&do_disconnect, + NULL); + } +} + + +/** + * Function called to notify transport users that another + * peer disconnected from us. + * + * @param cls closure + * @param peer the peer that disconnected + */ +static void +notify_disconnect (void *cls, + const struct + GNUNET_PeerIdentity * peer) +{ + if ( (0 == memcmp (&pid, + peer, + sizeof (struct GNUNET_PeerIdentity))) && + (NULL != th) ) + { + GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); + th = NULL; + GNUNET_SCHEDULER_cancel (end); + end = GNUNET_SCHEDULER_add_now (&do_disconnect, + NULL); + } +} + + +/** + * Function called by the transport for each received message. + * + * @param cls closure + * @param peer (claimed) identity of the other peer + * @param message the message + * @param ats performance data + * @param ats_count number of entries in ats + */ +static void +notify_receive (void *cls, + const struct + GNUNET_PeerIdentity * peer, + const struct + GNUNET_MessageHeader * + message, + const struct + GNUNET_ATS_Information + * ats, uint32_t ats_count) +{ + if (! benchmark_receive) + return; + if (traffic_received == 0) + start_time = GNUNET_TIME_absolute_get (); + traffic_received += ntohs (message->size); } @@ -56,11 +228,19 @@ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { - struct GNUNET_PeerIdentity pid; + if (benchmark_send && (NULL == cpid)) + { + fprintf (stderr, _("Option `%s' makes no sense without option `%s'.\n"), + "-s", "-C"); + return; + } if (NULL != cpid) { + ret = 1; handle = GNUNET_TRANSPORT_connect (cfg, NULL, NULL, - NULL, NULL, NULL); + ¬ify_receive, + ¬ify_connect, + ¬ify_disconnect); if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string (cpid, &pid.hashPubKey)) { @@ -71,9 +251,11 @@ run (void *cls, char *const *args, const char *cfgfile, return; } GNUNET_TRANSPORT_try_connect (handle, &pid); - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, - &do_disconnect, - NULL); + end = GNUNET_SCHEDULER_add_delayed (benchmark_send + ? GNUNET_TIME_UNIT_FOREVER_REL + : GNUNET_TIME_UNIT_SECONDS, + &do_disconnect, + NULL); } } @@ -82,15 +264,21 @@ int main (int argc, char *const *argv) { static const struct GNUNET_GETOPT_CommandLineOption options[] = { + {'b', "benchmark", NULL, + gettext_noop ("measure how fast we are receiving data (until CTRL-C)"), + 0, &GNUNET_GETOPT_set_one, &benchmark_receive}, {'C', "connect", "PEER", gettext_noop ("try to connect to the given peer"), 1, &GNUNET_GETOPT_set_string, &cpid}, + {'s', "send", NULL, + gettext_noop ("send data for benchmarking to the other peer (until CTRL-C)"), + 0, &GNUNET_GETOPT_set_one, &benchmark_send}, GNUNET_GETOPT_OPTION_END }; return (GNUNET_OK == GNUNET_PROGRAM_run (argc, argv, "gnunet-transport", gettext_noop ("Direct access to transport service."), - options, &run, NULL)) ? 0 : 1; + options, &run, NULL)) ? ret : 1; } -- 2.25.1