From c656a8218c39da05d511b9c153368f63a2d92cf1 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Tue, 4 Feb 2020 19:11:40 +0100 Subject: [PATCH] adding MQ benchmark --- src/util/Makefile.am | 6 + src/util/perf_mq.c | 300 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 306 insertions(+) create mode 100644 src/util/perf_mq.c diff --git a/src/util/Makefile.am b/src/util/Makefile.am index 60b845414..ffe95a24f 100644 --- a/src/util/Makefile.am +++ b/src/util/Makefile.am @@ -246,6 +246,7 @@ if HAVE_BENCHMARKS perf_crypto_symmetric \ perf_crypto_asymmetric \ perf_malloc \ + perf_mq \ perf_scheduler endif @@ -609,6 +610,11 @@ perf_malloc_SOURCES = \ perf_malloc_LDADD = \ libgnunetutil.la +perf_mq_SOURCES = \ + perf_mq.c +perf_mq_LDADD = \ + libgnunetutil.la + perf_scheduler_SOURCES = \ perf_scheduler.c perf_scheduler_LDADD = \ diff --git a/src/util/perf_mq.c b/src/util/perf_mq.c new file mode 100644 index 000000000..f6e3d78e2 --- /dev/null +++ b/src/util/perf_mq.c @@ -0,0 +1,300 @@ +/* + This file is part of GNUnet. + Copyright (C) 2012, 2018, 2020 GNUnet e.V. + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + + SPDX-License-Identifier: AGPL3.0-or-later + */ + +/** + * @file util/perf_mq.c + * @brief benchmark for mq + * @author Florian Dold + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include + +#define NUM_TRANSMISSIONS 1000000 + +/** + * How long does the receiver take per message? + */ +#define RECEIVER_THROTTLE GNUNET_TIME_relative_multiply ( \ + GNUNET_TIME_UNIT_MILLISECONDS, 1) + +static unsigned int received_cnt; + + +GNUNET_NETWORK_STRUCT_BEGIN + +struct MyMessage +{ + struct GNUNET_MessageHeader header; + uint32_t x GNUNET_PACKED; +}; + +GNUNET_NETWORK_STRUCT_END + +static int global_ret; + +static struct GNUNET_SCHEDULER_Task *task; + +static struct GNUNET_MQ_Handle *cmq; + + +static void +do_shutdown (void *cls) +{ + (void) cls; + if (NULL != task) + { + GNUNET_SCHEDULER_cancel (task); + task = NULL; + } + if (NULL != cmq) + { + GNUNET_MQ_destroy (cmq); + cmq = NULL; + } +} + + +/** + * Generic error handler, called with the appropriate + * error code and the same closure specified at the creation of + * the message queue. + * Not every message queue implementation supports an error handler. + * + * @param cls closure + * @param error error code + */ +static void +error_cb (void *cls, + enum GNUNET_MQ_Error error) +{ + GNUNET_break (0); + global_ret = 3; + GNUNET_SCHEDULER_shutdown (); +} + + +static void +handle_dummy (void *cls, + const struct MyMessage *msg) +{ + struct GNUNET_SERVICE_Client *c = cls; + + GNUNET_SERVICE_client_continue (c); + if (received_cnt != ntohl (msg->x)) + { + GNUNET_break (0); + global_ret = 4; + GNUNET_SCHEDULER_shutdown (); + } + received_cnt++; +} + + +static void +handle_dummy2 (void *cls, + const struct MyMessage *msg) +{ + struct GNUNET_SERVICE_Client *c = cls; + + GNUNET_SERVICE_client_continue (c); + if (NUM_TRANSMISSIONS != received_cnt) + { + GNUNET_break (0); + global_ret = 5; + } + GNUNET_SCHEDULER_shutdown (); +} + + +static void +do_send (void *cls); + + +/** + * Function called whenever MQ has sent a message. + */ +static void +notify_sent_cb (void *cls) +{ + static unsigned int seen; + unsigned int *cnt = cls; + + if (seen != *cnt) + { + GNUNET_break (0); + global_ret = 6; + GNUNET_SCHEDULER_shutdown (); + } + seen++; + GNUNET_free (cnt); + task = GNUNET_SCHEDULER_add_now (&do_send, + NULL); +} + + +static void +do_send (void *cls) +{ + static unsigned int i = 0; + unsigned int *cnt; + struct GNUNET_MQ_Envelope *env; + struct MyMessage *m; + + task = NULL; + if (NUM_TRANSMISSIONS == i) + { + env = GNUNET_MQ_msg (m, + GNUNET_MESSAGE_TYPE_DUMMY2); + GNUNET_MQ_send (cmq, + env); + return; + } + cnt = GNUNET_new (unsigned int); + *cnt = i; + env = GNUNET_MQ_msg (m, + GNUNET_MESSAGE_TYPE_DUMMY); + GNUNET_MQ_notify_sent (env, + ¬ify_sent_cb, + cnt); + m->x = htonl (i); + GNUNET_MQ_send (cmq, + env); + i++; +} + + +/** + * Start running the actual test. + * + * @param cls closure passed to #GNUNET_SERVICE_MAIN + * @param cfg configuration to use for this service + * @param sh handle to the newly create service + */ +static void +run (void *cls, + const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_SERVICE_Handle *sh) +{ + struct GNUNET_MQ_MessageHandler ch[] = { + GNUNET_MQ_handler_end () + }; + + (void) cls; + (void) sh; + cmq = GNUNET_CLIENT_connect (cfg, + "test_client", + ch, + &error_cb, + NULL); + GNUNET_SCHEDULER_add_shutdown (&do_shutdown, + NULL); + task = GNUNET_SCHEDULER_add_now (&do_send, + NULL); +} + + +/** + * Callback to be called when a client connects to the service. + * + * @param cls closure for the service + * @param c the new client that connected to the service + * @param mq the message queue used to send messages to the client + * @return the client-specific (`internal') closure + */ +static void * +connect_cb (void *cls, + struct GNUNET_SERVICE_Client *c, + struct GNUNET_MQ_Handle *mq) +{ + (void) cls; + (void) mq; + return c; +} + + +/** + * Callback to be called when a client disconnected from the service + * + * @param cls closure for the service + * @param c the client that disconnected + * @param internal_cls the client-specific (`internal') closure + */ +static void +disconnect_cb (void *cls, + struct GNUNET_SERVICE_Client *c, + void *internal_cls) +{ + (void) cls; + (void) c; + (void) internal_cls; +} + + +int +main (int argc, char **argv) +{ + struct GNUNET_TIME_Absolute start; + char *test_argv[] = { + (char *) "test_client", + "-c", + "test_client_data.conf", + NULL + }; + struct GNUNET_MQ_MessageHandler mh[] = { + GNUNET_MQ_hd_fixed_size (dummy, + GNUNET_MESSAGE_TYPE_DUMMY, + struct MyMessage, + NULL), + GNUNET_MQ_hd_fixed_size (dummy2, + GNUNET_MESSAGE_TYPE_DUMMY2, + struct MyMessage, + NULL), + GNUNET_MQ_handler_end () + }; + + (void) argc; + (void) argv; + GNUNET_log_setup ("perf-mq", + "INFO", + NULL); + start = GNUNET_TIME_absolute_get (); + if (0 != + GNUNET_SERVICE_run_ (3, + test_argv, + "test_client", + GNUNET_SERVICE_OPTION_NONE, + &run, + &connect_cb, + &disconnect_cb, + NULL, + mh)) + return 1; + printf ("Scheduler perf took %s\n", + GNUNET_STRINGS_relative_time_to_string ( + GNUNET_TIME_absolute_get_duration (start), + GNUNET_YES)); + GAUGER ("UTIL", "Scheduler", + received_cnt / 1024 / (1 + + GNUNET_TIME_absolute_get_duration + (start).rel_value_us / 1000LL), "kmsg/ms"); + return global_ret; +} -- 2.25.1