--- /dev/null
+/*
+ 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 <http://www.gnu.org/licenses/>.
+
+ 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 <gauger.h>
+
+#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;
+}