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.
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/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
22 * @file set/gnunet-set-profiler.c
23 * @brief profiling tool for set
24 * @author Florian Dold
27 #include "gnunet_util_lib.h"
28 #include "gnunet_statistics_service.h"
29 #include "gnunet_set_service.h"
30 #include "gnunet_testbed_service.h"
35 static unsigned int num_a = 5;
36 static unsigned int num_b = 5;
37 static unsigned int num_c = 20;
39 static char *op_str = "union";
41 const static struct GNUNET_CONFIGURATION_Handle *config;
45 struct GNUNET_SET_Handle *set;
46 struct GNUNET_SET_OperationHandle *oh;
47 struct GNUNET_CONTAINER_MultiHashMap *sent;
48 struct GNUNET_CONTAINER_MultiHashMap *received;
52 static struct GNUNET_CONTAINER_MultiHashMap *common_sent;
54 static struct GNUNET_HashCode app_id;
56 static struct GNUNET_PeerIdentity local_peer;
58 static struct GNUNET_SET_ListenHandle *set_listener;
61 static unsigned int force_delta;
62 static unsigned int force_full;
63 static unsigned int element_size = 32;
66 * Handle to the statistics service.
68 static struct GNUNET_STATISTICS_Handle *statistics;
71 * The profiler will write statistics
72 * for all peers to the file with this name.
74 static char *statistics_filename;
77 * The profiler will write statistics
78 * for all peers to this file.
80 static FILE *statistics_file;
84 map_remove_iterator(void *cls,
85 const struct GNUNET_HashCode *key,
88 struct GNUNET_CONTAINER_MultiHashMap *m = cls;
91 GNUNET_assert(NULL != key);
93 ret = GNUNET_CONTAINER_multihashmap_remove_all(m, key);
95 printf("spurious element\n");
101 * Callback function to process statistic values.
104 * @param subsystem name of subsystem that created the statistic
105 * @param name the name of the datum
106 * @param value the current value
107 * @param is_persistent #GNUNET_YES if the value is persistent, #GNUNET_NO if not
108 * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration
111 statistics_result(void *cls,
112 const char *subsystem,
117 if (NULL != statistics_file)
119 fprintf(statistics_file, "%s\t%s\t%lu\n", subsystem, name, (unsigned long)value);
126 statistics_done(void *cls,
129 GNUNET_assert(GNUNET_YES == success);
130 if (NULL != statistics_file)
131 fclose(statistics_file);
132 GNUNET_SCHEDULER_shutdown();
139 if (info1.done == GNUNET_NO || info2.done == GNUNET_NO)
142 GNUNET_CONTAINER_multihashmap_iterate(info1.received, map_remove_iterator, info2.sent);
143 GNUNET_CONTAINER_multihashmap_iterate(info2.received, map_remove_iterator, info1.sent);
145 printf("set a: %d missing elements\n", GNUNET_CONTAINER_multihashmap_size(info1.sent));
146 printf("set b: %d missing elements\n", GNUNET_CONTAINER_multihashmap_size(info2.sent));
148 if (NULL == statistics_filename)
150 GNUNET_SCHEDULER_shutdown();
154 statistics_file = fopen(statistics_filename, "w");
155 GNUNET_STATISTICS_get(statistics, NULL, NULL,
157 &statistics_result, NULL);
162 set_result_cb(void *cls,
163 const struct GNUNET_SET_Element *element,
164 uint64_t current_size,
165 enum GNUNET_SET_Status status)
167 struct SetInfo *info = cls;
168 struct GNUNET_HashCode hash;
170 GNUNET_assert(GNUNET_NO == info->done);
173 case GNUNET_SET_STATUS_DONE:
174 case GNUNET_SET_STATUS_HALF_DONE:
175 info->done = GNUNET_YES;
176 GNUNET_log(GNUNET_ERROR_TYPE_INFO, "set %s done\n", info->id);
181 case GNUNET_SET_STATUS_FAILURE:
183 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "failure\n");
184 GNUNET_SCHEDULER_shutdown();
187 case GNUNET_SET_STATUS_ADD_LOCAL:
188 GNUNET_log(GNUNET_ERROR_TYPE_INFO, "set %s: local element\n", info->id);
191 case GNUNET_SET_STATUS_ADD_REMOTE:
192 GNUNET_CRYPTO_hash(element->data, element->size, &hash);
193 GNUNET_log(GNUNET_ERROR_TYPE_INFO, "set %s: remote element %s\n", info->id,
195 // XXX: record and check
202 if (element->size != element_size)
204 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
205 "wrong element size: %u, expected %u\n",
207 (unsigned int)sizeof(struct GNUNET_HashCode));
211 GNUNET_log(GNUNET_ERROR_TYPE_INFO, "set %s: got element (%s)\n",
212 info->id, GNUNET_h2s(element->data));
213 GNUNET_assert(NULL != element->data);
214 struct GNUNET_HashCode data_hash;
215 GNUNET_CRYPTO_hash(element->data, element_size, &data_hash);
216 GNUNET_CONTAINER_multihashmap_put(info->received,
218 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
223 set_listen_cb(void *cls,
224 const struct GNUNET_PeerIdentity *other_peer,
225 const struct GNUNET_MessageHeader *context_msg,
226 struct GNUNET_SET_Request *request)
228 /* max. 2 options plus terminator */
229 struct GNUNET_SET_Option opts[3] = { { 0 } };
230 unsigned int n_opts = 0;
234 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
235 "listener failed\n");
238 GNUNET_assert(NULL == info2.oh);
239 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
240 "set listen cb called\n");
243 opts[n_opts++] = (struct GNUNET_SET_Option) { .type = GNUNET_SET_OPTION_BYZANTINE };
245 GNUNET_assert(!(force_full && force_delta));
248 opts[n_opts++] = (struct GNUNET_SET_Option) { .type = GNUNET_SET_OPTION_FORCE_FULL };
252 opts[n_opts++] = (struct GNUNET_SET_Option) { .type = GNUNET_SET_OPTION_FORCE_DELTA };
255 opts[n_opts].type = 0;
256 info2.oh = GNUNET_SET_accept(request, GNUNET_SET_RESULT_SYMMETRIC,
258 set_result_cb, &info2);
259 GNUNET_SET_commit(info2.oh, info2.set);
264 set_insert_iterator(void *cls,
265 const struct GNUNET_HashCode *key,
268 struct GNUNET_SET_Handle *set = cls;
269 struct GNUNET_SET_Element el;
273 el.size = element_size;
274 GNUNET_SET_add_element(set, &el, NULL, NULL);
280 handle_shutdown(void *cls)
282 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
283 "Shutting down set profiler\n");
284 if (NULL != set_listener)
286 GNUNET_SET_listen_cancel(set_listener);
289 if (NULL != info1.oh)
291 GNUNET_SET_operation_cancel(info1.oh);
294 if (NULL != info2.oh)
296 GNUNET_SET_operation_cancel(info2.oh);
299 if (NULL != info1.set)
301 GNUNET_SET_destroy(info1.set);
304 if (NULL != info2.set)
306 GNUNET_SET_destroy(info2.set);
309 GNUNET_STATISTICS_destroy(statistics, GNUNET_NO);
315 const struct GNUNET_CONFIGURATION_Handle *cfg,
316 struct GNUNET_TESTING_Peer *peer)
319 struct GNUNET_HashCode hash;
320 /* max. 2 options plus terminator */
321 struct GNUNET_SET_Option opts[3] = { { 0 } };
322 unsigned int n_opts = 0;
326 GNUNET_assert(element_size > 0);
328 if (GNUNET_OK != GNUNET_CRYPTO_get_peer_identity(cfg, &local_peer))
330 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "could not retrieve host identity\n");
335 statistics = GNUNET_STATISTICS_create("set-profiler", cfg);
337 GNUNET_SCHEDULER_add_shutdown(&handle_shutdown, NULL);
342 info1.sent = GNUNET_CONTAINER_multihashmap_create(num_a + 1, GNUNET_NO);
343 info2.sent = GNUNET_CONTAINER_multihashmap_create(num_b + 1, GNUNET_NO);
344 common_sent = GNUNET_CONTAINER_multihashmap_create(num_c + 1, GNUNET_NO);
346 info1.received = GNUNET_CONTAINER_multihashmap_create(num_a + 1, GNUNET_NO);
347 info2.received = GNUNET_CONTAINER_multihashmap_create(num_b + 1, GNUNET_NO);
349 for (i = 0; i < num_a; i++)
351 char *data = GNUNET_malloc(element_size);
352 GNUNET_CRYPTO_random_block(GNUNET_CRYPTO_QUALITY_WEAK, data, element_size);
353 GNUNET_CRYPTO_hash(data, element_size, &hash);
354 GNUNET_CONTAINER_multihashmap_put(info1.sent, &hash, data,
355 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
358 for (i = 0; i < num_b; i++)
360 char *data = GNUNET_malloc(element_size);
361 GNUNET_CRYPTO_random_block(GNUNET_CRYPTO_QUALITY_WEAK, data, element_size);
362 GNUNET_CRYPTO_hash(data, element_size, &hash);
363 GNUNET_CONTAINER_multihashmap_put(info2.sent, &hash, data,
364 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
367 for (i = 0; i < num_c; i++)
369 char *data = GNUNET_malloc(element_size);
370 GNUNET_CRYPTO_random_block(GNUNET_CRYPTO_QUALITY_WEAK, data, element_size);
371 GNUNET_CRYPTO_hash(data, element_size, &hash);
372 GNUNET_CONTAINER_multihashmap_put(common_sent, &hash, data,
373 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
376 GNUNET_CRYPTO_hash_create_random(GNUNET_CRYPTO_QUALITY_STRONG, &app_id);
378 /* FIXME: also implement intersection etc. */
379 info1.set = GNUNET_SET_create(config, GNUNET_SET_OPERATION_UNION);
380 info2.set = GNUNET_SET_create(config, GNUNET_SET_OPERATION_UNION);
382 GNUNET_CONTAINER_multihashmap_iterate(info1.sent, set_insert_iterator, info1.set);
383 GNUNET_CONTAINER_multihashmap_iterate(info2.sent, set_insert_iterator, info2.set);
384 GNUNET_CONTAINER_multihashmap_iterate(common_sent, set_insert_iterator, info1.set);
385 GNUNET_CONTAINER_multihashmap_iterate(common_sent, set_insert_iterator, info2.set);
387 set_listener = GNUNET_SET_listen(config, GNUNET_SET_OPERATION_UNION,
388 &app_id, set_listen_cb, NULL);
393 opts[n_opts++] = (struct GNUNET_SET_Option) { .type = GNUNET_SET_OPTION_BYZANTINE };
395 GNUNET_assert(!(force_full && force_delta));
398 opts[n_opts++] = (struct GNUNET_SET_Option) { .type = GNUNET_SET_OPTION_FORCE_FULL };
402 opts[n_opts++] = (struct GNUNET_SET_Option) { .type = GNUNET_SET_OPTION_FORCE_DELTA };
405 opts[n_opts].type = 0;
407 info1.oh = GNUNET_SET_prepare(&local_peer, &app_id, NULL,
408 GNUNET_SET_RESULT_SYMMETRIC,
410 set_result_cb, &info1);
411 GNUNET_SET_commit(info1.oh, info1.set);
412 GNUNET_SET_destroy(info1.set);
418 pre_run(void *cls, char *const *args, const char *cfgfile,
419 const struct GNUNET_CONFIGURATION_Handle *cfg)
421 if (0 != GNUNET_TESTING_peer_run("set-profiler",
429 main(int argc, char **argv)
431 struct GNUNET_GETOPT_CommandLineOption options[] = {
432 GNUNET_GETOPT_option_uint('A',
435 gettext_noop("number of values"),
438 GNUNET_GETOPT_option_uint('B',
441 gettext_noop("number of values"),
444 GNUNET_GETOPT_option_flag('b',
446 gettext_noop("use byzantine mode"),
449 GNUNET_GETOPT_option_uint('f',
452 gettext_noop("force sending full set"),
455 GNUNET_GETOPT_option_uint('d',
458 gettext_noop("number delta operation"),
461 GNUNET_GETOPT_option_uint('C',
464 gettext_noop("number of values"),
467 GNUNET_GETOPT_option_string('x',
470 gettext_noop("operation to execute"),
473 GNUNET_GETOPT_option_uint('w',
476 gettext_noop("element size"),
479 GNUNET_GETOPT_option_filename('s',
482 gettext_noop("write statistics to file"),
483 &statistics_filename),
485 GNUNET_GETOPT_OPTION_END
488 GNUNET_PROGRAM_run2(argc, argv, "gnunet-set-profiler",
490 options, &pre_run, NULL, GNUNET_YES);