use NULL value in load_path_suffix to NOT load any files
[oweals/gnunet.git] / src / util / perf_mq.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2012, 2018, 2020 GNUnet e.V.
4
5      GNUnet is free software: you can redistribute it and/or modify it
6      under the terms of the GNU Affero General Public License as published
7      by the Free Software Foundation, either version 3 of the License,
8      or (at your option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      Affero General Public License for more details.
14
15      You should have received a copy of the GNU Affero General Public License
16      along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18      SPDX-License-Identifier: AGPL3.0-or-later
19  */
20
21 /**
22  * @file util/perf_mq.c
23  * @brief benchmark for mq
24  * @author Florian Dold
25  * @author Christian Grothoff
26  */
27 #include "platform.h"
28 #include "gnunet_util_lib.h"
29 #include <gauger.h>
30
31 #define NUM_TRANSMISSIONS 1000000
32
33 /**
34  * How long does the receiver take per message?
35  */
36 #define RECEIVER_THROTTLE GNUNET_TIME_relative_multiply ( \
37     GNUNET_TIME_UNIT_MILLISECONDS, 1)
38
39 static unsigned int received_cnt;
40
41
42 GNUNET_NETWORK_STRUCT_BEGIN
43
44 struct MyMessage
45 {
46   struct GNUNET_MessageHeader header;
47   uint32_t x GNUNET_PACKED;
48 };
49
50 GNUNET_NETWORK_STRUCT_END
51
52 static int global_ret;
53
54 static struct GNUNET_SCHEDULER_Task *task;
55
56 static struct GNUNET_MQ_Handle *cmq;
57
58
59 static void
60 do_shutdown (void *cls)
61 {
62   (void) cls;
63   if (NULL != task)
64   {
65     GNUNET_SCHEDULER_cancel (task);
66     task = NULL;
67   }
68   if (NULL != cmq)
69   {
70     GNUNET_MQ_destroy (cmq);
71     cmq = NULL;
72   }
73 }
74
75
76 /**
77  * Generic error handler, called with the appropriate
78  * error code and the same closure specified at the creation of
79  * the message queue.
80  * Not every message queue implementation supports an error handler.
81  *
82  * @param cls closure
83  * @param error error code
84  */
85 static void
86 error_cb (void *cls,
87           enum GNUNET_MQ_Error error)
88 {
89   GNUNET_break (0);
90   global_ret = 3;
91   GNUNET_SCHEDULER_shutdown ();
92 }
93
94
95 static void
96 handle_dummy (void *cls,
97               const struct MyMessage *msg)
98 {
99   struct GNUNET_SERVICE_Client *c = cls;
100
101   GNUNET_SERVICE_client_continue (c);
102   if (received_cnt != ntohl (msg->x))
103   {
104     GNUNET_break (0);
105     global_ret = 4;
106     GNUNET_SCHEDULER_shutdown ();
107   }
108   received_cnt++;
109 }
110
111
112 static void
113 handle_dummy2 (void *cls,
114                const struct MyMessage *msg)
115 {
116   struct GNUNET_SERVICE_Client *c = cls;
117
118   GNUNET_SERVICE_client_continue (c);
119   if (NUM_TRANSMISSIONS != received_cnt)
120   {
121     GNUNET_break (0);
122     global_ret = 5;
123   }
124   GNUNET_SCHEDULER_shutdown ();
125 }
126
127
128 static void
129 do_send (void *cls);
130
131
132 /**
133  * Function called whenever MQ has sent a message.
134  */
135 static void
136 notify_sent_cb (void *cls)
137 {
138   static unsigned int seen;
139   unsigned int *cnt = cls;
140
141   if (seen != *cnt)
142   {
143     GNUNET_break (0);
144     global_ret = 6;
145     GNUNET_SCHEDULER_shutdown ();
146   }
147   seen++;
148   GNUNET_free (cnt);
149   task = GNUNET_SCHEDULER_add_now (&do_send,
150                                    NULL);
151 }
152
153
154 static void
155 do_send (void *cls)
156 {
157   static unsigned int i = 0;
158   unsigned int *cnt;
159   struct GNUNET_MQ_Envelope *env;
160   struct MyMessage *m;
161
162   task = NULL;
163   if (NUM_TRANSMISSIONS == i)
164   {
165     env = GNUNET_MQ_msg (m,
166                          GNUNET_MESSAGE_TYPE_DUMMY2);
167     GNUNET_MQ_send (cmq,
168                     env);
169     return;
170   }
171   cnt = GNUNET_new (unsigned int);
172   *cnt = i;
173   env = GNUNET_MQ_msg (m,
174                        GNUNET_MESSAGE_TYPE_DUMMY);
175   GNUNET_MQ_notify_sent (env,
176                          &notify_sent_cb,
177                          cnt);
178   m->x = htonl (i);
179   GNUNET_MQ_send (cmq,
180                   env);
181   i++;
182 }
183
184
185 /**
186  * Start running the actual test.
187  *
188  * @param cls closure passed to #GNUNET_SERVICE_MAIN
189  * @param cfg configuration to use for this service
190  * @param sh handle to the newly create service
191  */
192 static void
193 run (void *cls,
194      const struct GNUNET_CONFIGURATION_Handle *cfg,
195      struct GNUNET_SERVICE_Handle *sh)
196 {
197   struct GNUNET_MQ_MessageHandler ch[] = {
198     GNUNET_MQ_handler_end ()
199   };
200
201   (void) cls;
202   (void) sh;
203   cmq = GNUNET_CLIENT_connect (cfg,
204                                "test_client",
205                                ch,
206                                &error_cb,
207                                NULL);
208   GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
209                                  NULL);
210   task = GNUNET_SCHEDULER_add_now (&do_send,
211                                    NULL);
212 }
213
214
215 /**
216  * Callback to be called when a client connects to the service.
217  *
218  * @param cls closure for the service
219  * @param c the new client that connected to the service
220  * @param mq the message queue used to send messages to the client
221  * @return the client-specific (`internal') closure
222  */
223 static void *
224 connect_cb (void *cls,
225             struct GNUNET_SERVICE_Client *c,
226             struct GNUNET_MQ_Handle *mq)
227 {
228   (void) cls;
229   (void) mq;
230   return c;
231 }
232
233
234 /**
235  * Callback to be called when a client disconnected from the service
236  *
237  * @param cls closure for the service
238  * @param c the client that disconnected
239  * @param internal_cls the client-specific (`internal') closure
240  */
241 static void
242 disconnect_cb (void *cls,
243                struct GNUNET_SERVICE_Client *c,
244                void *internal_cls)
245 {
246   (void) cls;
247   (void) c;
248   (void) internal_cls;
249 }
250
251
252 int
253 main (int argc, char **argv)
254 {
255   struct GNUNET_TIME_Absolute start;
256   char *test_argv[] = {
257     (char *) "test_client",
258     "-c",
259     "test_client_data.conf",
260     NULL
261   };
262   struct GNUNET_MQ_MessageHandler mh[] = {
263     GNUNET_MQ_hd_fixed_size (dummy,
264                              GNUNET_MESSAGE_TYPE_DUMMY,
265                              struct MyMessage,
266                              NULL),
267     GNUNET_MQ_hd_fixed_size (dummy2,
268                              GNUNET_MESSAGE_TYPE_DUMMY2,
269                              struct MyMessage,
270                              NULL),
271     GNUNET_MQ_handler_end ()
272   };
273
274   (void) argc;
275   (void) argv;
276   GNUNET_log_setup ("perf-mq",
277                     "INFO",
278                     NULL);
279   start = GNUNET_TIME_absolute_get ();
280   if (0 !=
281       GNUNET_SERVICE_run_ (3,
282                            test_argv,
283                            "test_client",
284                            GNUNET_SERVICE_OPTION_NONE,
285                            &run,
286                            &connect_cb,
287                            &disconnect_cb,
288                            NULL,
289                            mh))
290     return 1;
291   printf ("Scheduler perf took %s\n",
292           GNUNET_STRINGS_relative_time_to_string (
293             GNUNET_TIME_absolute_get_duration (start),
294             GNUNET_YES));
295   GAUGER ("UTIL", "Scheduler",
296           received_cnt / 1024 / (1
297                                  + GNUNET_TIME_absolute_get_duration
298                                    (start).rel_value_us / 1000LL), "kmsg/ms");
299   return global_ret;
300 }