2 This file is part of GNUnet
3 Copyright (C) 2013 GNUnet e.V.
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.
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.
17 * @file set/gnunet-set-profiler.c
18 * @brief profiling tool for set
19 * @author Florian Dold
22 #include "gnunet_util_lib.h"
23 #include "gnunet_statistics_service.h"
24 #include "gnunet_set_service.h"
25 #include "gnunet_testbed_service.h"
30 static unsigned int num_a = 5;
31 static unsigned int num_b = 5;
32 static unsigned int num_c = 20;
34 static char *op_str = "union";
36 const static struct GNUNET_CONFIGURATION_Handle *config;
41 struct GNUNET_SET_Handle *set;
42 struct GNUNET_SET_OperationHandle *oh;
43 struct GNUNET_CONTAINER_MultiHashMap *sent;
44 struct GNUNET_CONTAINER_MultiHashMap *received;
48 static struct GNUNET_CONTAINER_MultiHashMap *common_sent;
50 static struct GNUNET_HashCode app_id;
52 static struct GNUNET_PeerIdentity local_peer;
54 static struct GNUNET_SET_ListenHandle *set_listener;
57 static unsigned int force_delta;
58 static unsigned int force_full;
59 static unsigned int element_size = 32;
62 * Handle to the statistics service.
64 static struct GNUNET_STATISTICS_Handle *statistics;
67 * The profiler will write statistics
68 * for all peers to the file with this name.
70 static char *statistics_filename;
73 * The profiler will write statistics
74 * for all peers to this file.
76 static FILE *statistics_file;
80 map_remove_iterator (void *cls,
81 const struct GNUNET_HashCode *key,
84 struct GNUNET_CONTAINER_MultiHashMap *m = cls;
87 GNUNET_assert (NULL != key);
89 ret = GNUNET_CONTAINER_multihashmap_remove_all (m, key);
91 printf ("spurious element\n");
98 * Callback function to process statistic values.
101 * @param subsystem name of subsystem that created the statistic
102 * @param name the name of the datum
103 * @param value the current value
104 * @param is_persistent #GNUNET_YES if the value is persistent, #GNUNET_NO if not
105 * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration
108 statistics_result (void *cls,
109 const char *subsystem,
114 if (NULL != statistics_file)
116 fprintf (statistics_file, "%s\t%s\t%lu\n", subsystem, name, (unsigned long) value);
123 statistics_done (void *cls,
126 GNUNET_assert (GNUNET_YES == success);
127 if (NULL != statistics_file)
128 fclose (statistics_file);
129 GNUNET_SCHEDULER_shutdown ();
134 check_all_done (void)
136 if (info1.done == GNUNET_NO || info2.done == GNUNET_NO)
139 GNUNET_CONTAINER_multihashmap_iterate (info1.received, map_remove_iterator, info2.sent);
140 GNUNET_CONTAINER_multihashmap_iterate (info2.received, map_remove_iterator, info1.sent);
142 printf ("set a: %d missing elements\n", GNUNET_CONTAINER_multihashmap_size (info1.sent));
143 printf ("set b: %d missing elements\n", GNUNET_CONTAINER_multihashmap_size (info2.sent));
145 if (NULL == statistics_filename)
147 GNUNET_SCHEDULER_shutdown ();
151 statistics_file = fopen (statistics_filename, "w");
152 GNUNET_STATISTICS_get (statistics, NULL, NULL,
154 &statistics_result, NULL);
159 set_result_cb (void *cls,
160 const struct GNUNET_SET_Element *element,
161 uint64_t current_size,
162 enum GNUNET_SET_Status status)
164 struct SetInfo *info = cls;
165 struct GNUNET_HashCode hash;
167 GNUNET_assert (GNUNET_NO == info->done);
170 case GNUNET_SET_STATUS_DONE:
171 case GNUNET_SET_STATUS_HALF_DONE:
172 info->done = GNUNET_YES;
173 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "set %s done\n", info->id);
177 case GNUNET_SET_STATUS_FAILURE:
179 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "failure\n");
180 GNUNET_SCHEDULER_shutdown ();
182 case GNUNET_SET_STATUS_ADD_LOCAL:
183 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "set %s: local element\n", info->id);
185 case GNUNET_SET_STATUS_ADD_REMOTE:
186 GNUNET_CRYPTO_hash (element->data, element->size, &hash);
187 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "set %s: remote element %s\n", info->id,
189 // XXX: record and check
195 if (element->size != element_size)
197 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
198 "wrong element size: %u, expected %u\n",
200 (unsigned int) sizeof (struct GNUNET_HashCode));
204 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "set %s: got element (%s)\n",
205 info->id, GNUNET_h2s (element->data));
206 GNUNET_assert (NULL != element->data);
207 struct GNUNET_HashCode data_hash;
208 GNUNET_CRYPTO_hash (element->data, element_size, &data_hash);
209 GNUNET_CONTAINER_multihashmap_put (info->received,
211 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
216 set_listen_cb (void *cls,
217 const struct GNUNET_PeerIdentity *other_peer,
218 const struct GNUNET_MessageHeader *context_msg,
219 struct GNUNET_SET_Request *request)
221 /* max. 2 options plus terminator */
222 struct GNUNET_SET_Option opts[3] = {{0}};
223 unsigned int n_opts = 0;
227 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
228 "listener failed\n");
231 GNUNET_assert (NULL == info2.oh);
232 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
233 "set listen cb called\n");
236 opts[n_opts++] = (struct GNUNET_SET_Option) { .type = GNUNET_SET_OPTION_BYZANTINE };
238 GNUNET_assert (!(force_full && force_delta));
241 opts[n_opts++] = (struct GNUNET_SET_Option) { .type = GNUNET_SET_OPTION_FORCE_FULL };
245 opts[n_opts++] = (struct GNUNET_SET_Option) { .type = GNUNET_SET_OPTION_FORCE_DELTA };
248 opts[n_opts].type = 0;
249 info2.oh = GNUNET_SET_accept (request, GNUNET_SET_RESULT_SYMMETRIC,
251 set_result_cb, &info2);
252 GNUNET_SET_commit (info2.oh, info2.set);
257 set_insert_iterator (void *cls,
258 const struct GNUNET_HashCode *key,
261 struct GNUNET_SET_Handle *set = cls;
262 struct GNUNET_SET_Element el;
266 el.size = element_size;
267 GNUNET_SET_add_element (set, &el, NULL, NULL);
273 handle_shutdown (void *cls)
275 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
276 "Shutting down set profiler\n");
277 if (NULL != set_listener)
279 GNUNET_SET_listen_cancel (set_listener);
282 if (NULL != info1.oh)
284 GNUNET_SET_operation_cancel (info1.oh);
287 if (NULL != info2.oh)
289 GNUNET_SET_operation_cancel (info2.oh);
292 if (NULL != info1.set)
294 GNUNET_SET_destroy (info1.set);
297 if (NULL != info2.set)
299 GNUNET_SET_destroy (info2.set);
302 GNUNET_STATISTICS_destroy (statistics, GNUNET_NO);
308 const struct GNUNET_CONFIGURATION_Handle *cfg,
309 struct GNUNET_TESTING_Peer *peer)
312 struct GNUNET_HashCode hash;
313 /* max. 2 options plus terminator */
314 struct GNUNET_SET_Option opts[3] = {{0}};
315 unsigned int n_opts = 0;
319 GNUNET_assert (element_size > 0);
321 if (GNUNET_OK != GNUNET_CRYPTO_get_peer_identity (cfg, &local_peer))
323 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "could not retrieve host identity\n");
328 statistics = GNUNET_STATISTICS_create ("set-profiler", cfg);
330 GNUNET_SCHEDULER_add_shutdown (&handle_shutdown, NULL);
335 info1.sent = GNUNET_CONTAINER_multihashmap_create (num_a+1, GNUNET_NO);
336 info2.sent = GNUNET_CONTAINER_multihashmap_create (num_b+1, GNUNET_NO);
337 common_sent = GNUNET_CONTAINER_multihashmap_create (num_c+1, GNUNET_NO);
339 info1.received = GNUNET_CONTAINER_multihashmap_create (num_a+1, GNUNET_NO);
340 info2.received = GNUNET_CONTAINER_multihashmap_create (num_b+1, GNUNET_NO);
342 for (i = 0; i < num_a; i++)
344 char *data = GNUNET_malloc (element_size);
345 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, data, element_size);
346 GNUNET_CRYPTO_hash (data, element_size, &hash);
347 GNUNET_CONTAINER_multihashmap_put (info1.sent, &hash, data,
348 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
351 for (i = 0; i < num_b; i++)
353 char *data = GNUNET_malloc (element_size);
354 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, data, element_size);
355 GNUNET_CRYPTO_hash (data, element_size, &hash);
356 GNUNET_CONTAINER_multihashmap_put (info2.sent, &hash, data,
357 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
360 for (i = 0; i < num_c; i++)
362 char *data = GNUNET_malloc (element_size);
363 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, data, element_size);
364 GNUNET_CRYPTO_hash (data, element_size, &hash);
365 GNUNET_CONTAINER_multihashmap_put (common_sent, &hash, data,
366 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
369 GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_STRONG, &app_id);
371 /* FIXME: also implement intersection etc. */
372 info1.set = GNUNET_SET_create (config, GNUNET_SET_OPERATION_UNION);
373 info2.set = GNUNET_SET_create (config, GNUNET_SET_OPERATION_UNION);
375 GNUNET_CONTAINER_multihashmap_iterate (info1.sent, set_insert_iterator, info1.set);
376 GNUNET_CONTAINER_multihashmap_iterate (info2.sent, set_insert_iterator, info2.set);
377 GNUNET_CONTAINER_multihashmap_iterate (common_sent, set_insert_iterator, info1.set);
378 GNUNET_CONTAINER_multihashmap_iterate (common_sent, set_insert_iterator, info2.set);
380 set_listener = GNUNET_SET_listen (config, GNUNET_SET_OPERATION_UNION,
381 &app_id, set_listen_cb, NULL);
386 opts[n_opts++] = (struct GNUNET_SET_Option) { .type = GNUNET_SET_OPTION_BYZANTINE };
388 GNUNET_assert (!(force_full && force_delta));
391 opts[n_opts++] = (struct GNUNET_SET_Option) { .type = GNUNET_SET_OPTION_FORCE_FULL };
395 opts[n_opts++] = (struct GNUNET_SET_Option) { .type = GNUNET_SET_OPTION_FORCE_DELTA };
398 opts[n_opts].type = 0;
400 info1.oh = GNUNET_SET_prepare (&local_peer, &app_id, NULL,
401 GNUNET_SET_RESULT_SYMMETRIC,
403 set_result_cb, &info1);
404 GNUNET_SET_commit (info1.oh, info1.set);
405 GNUNET_SET_destroy (info1.set);
411 pre_run (void *cls, char *const *args, const char *cfgfile,
412 const struct GNUNET_CONFIGURATION_Handle *cfg)
414 if (0 != GNUNET_TESTING_peer_run ("set-profiler",
422 main (int argc, char **argv)
424 struct GNUNET_GETOPT_CommandLineOption options[] = {
425 GNUNET_GETOPT_option_uint ('A',
428 gettext_noop ("number of values"),
431 GNUNET_GETOPT_option_uint ('B',
434 gettext_noop ("number of values"),
437 GNUNET_GETOPT_option_flag ('b',
439 gettext_noop ("use byzantine mode"),
442 GNUNET_GETOPT_option_uint ('f',
445 gettext_noop ("force sending full set"),
448 GNUNET_GETOPT_option_uint ('d',
451 gettext_noop ("number delta operation"),
454 GNUNET_GETOPT_option_uint ('C',
457 gettext_noop ("number of values"),
460 GNUNET_GETOPT_option_string ('x',
463 gettext_noop ("operation to execute"),
466 GNUNET_GETOPT_option_uint ('w',
469 gettext_noop ("element size"),
472 GNUNET_GETOPT_option_filename ('s',
475 gettext_noop ("write statistics to file"),
476 &statistics_filename),
478 GNUNET_GETOPT_OPTION_END
480 GNUNET_PROGRAM_run2 (argc, argv, "gnunet-set-profiler",
482 options, &pre_run, NULL, GNUNET_YES);