aboutsummaryrefslogtreecommitdiff
path: root/src/seti/gnunet-seti-profiler.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/seti/gnunet-seti-profiler.c')
-rw-r--r--src/seti/gnunet-seti-profiler.c480
1 files changed, 480 insertions, 0 deletions
diff --git a/src/seti/gnunet-seti-profiler.c b/src/seti/gnunet-seti-profiler.c
new file mode 100644
index 000000000..b8230bcfc
--- /dev/null
+++ b/src/seti/gnunet-seti-profiler.c
@@ -0,0 +1,480 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2013, 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 set/gnunet-seti-profiler.c
23 * @brief profiling tool for set intersection
24 * @author Florian Dold
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_statistics_service.h"
29#include "gnunet_seti_service.h"
30#include "gnunet_testbed_service.h"
31
32
33static int ret;
34
35static unsigned int num_a = 5;
36static unsigned int num_b = 5;
37static unsigned int num_c = 20;
38
39const static struct GNUNET_CONFIGURATION_Handle *config;
40
41struct SetInfo
42{
43 char *id;
44 struct GNUNET_SETI_Handle *set;
45 struct GNUNET_SETI_OperationHandle *oh;
46 struct GNUNET_CONTAINER_MultiHashMap *sent;
47 struct GNUNET_CONTAINER_MultiHashMap *received;
48 int done;
49} info1, info2;
50
51static struct GNUNET_CONTAINER_MultiHashMap *common_sent;
52
53static struct GNUNET_HashCode app_id;
54
55static struct GNUNET_PeerIdentity local_peer;
56
57static struct GNUNET_SETI_ListenHandle *set_listener;
58
59static unsigned int use_intersection;
60
61static unsigned int element_size = 32;
62
63/**
64 * Handle to the statistics service.
65 */
66static struct GNUNET_STATISTICS_Handle *statistics;
67
68/**
69 * The profiler will write statistics
70 * for all peers to the file with this name.
71 */
72static char *statistics_filename;
73
74/**
75 * The profiler will write statistics
76 * for all peers to this file.
77 */
78static FILE *statistics_file;
79
80
81static int
82map_remove_iterator (void *cls,
83 const struct GNUNET_HashCode *key,
84 void *value)
85{
86 struct GNUNET_CONTAINER_MultiHashMap *m = cls;
87 int ret;
88
89 GNUNET_assert (NULL != key);
90
91 ret = GNUNET_CONTAINER_multihashmap_remove_all (m, key);
92 if (GNUNET_OK != ret)
93 printf ("spurious element\n");
94 return GNUNET_YES;
95}
96
97
98/**
99 * Callback function to process statistic values.
100 *
101 * @param cls closure
102 * @param subsystem name of subsystem that created the statistic
103 * @param name the name of the datum
104 * @param value the current value
105 * @param is_persistent #GNUNET_YES if the value is persistent, #GNUNET_NO if not
106 * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration
107 */
108static int
109statistics_result (void *cls,
110 const char *subsystem,
111 const char *name,
112 uint64_t value,
113 int is_persistent)
114{
115 if (NULL != statistics_file)
116 {
117 fprintf (statistics_file, "%s\t%s\t%lu\n", subsystem, name, (unsigned
118 long) value);
119 }
120 return GNUNET_OK;
121}
122
123
124static void
125statistics_done (void *cls,
126 int success)
127{
128 GNUNET_assert (GNUNET_YES == success);
129 if (NULL != statistics_file)
130 fclose (statistics_file);
131 GNUNET_SCHEDULER_shutdown ();
132}
133
134
135static void
136check_all_done (void)
137{
138 if ((info1.done == GNUNET_NO) || (info2.done == GNUNET_NO))
139 return;
140
141 GNUNET_CONTAINER_multihashmap_iterate (info1.received, map_remove_iterator,
142 info2.sent);
143 GNUNET_CONTAINER_multihashmap_iterate (info2.received, map_remove_iterator,
144 info1.sent);
145
146 printf ("set a: %d missing elements\n", GNUNET_CONTAINER_multihashmap_size (
147 info1.sent));
148 printf ("set b: %d missing elements\n", GNUNET_CONTAINER_multihashmap_size (
149 info2.sent));
150
151 if (NULL == statistics_filename)
152 {
153 GNUNET_SCHEDULER_shutdown ();
154 return;
155 }
156
157 statistics_file = fopen (statistics_filename, "w");
158 GNUNET_STATISTICS_get (statistics, NULL, NULL,
159 &statistics_done,
160 &statistics_result, NULL);
161}
162
163
164static void
165set_result_cb (void *cls,
166 const struct GNUNET_SETI_Element *element,
167 uint64_t current_size,
168 enum GNUNET_SETI_Status status)
169{
170 struct SetInfo *info = cls;
171 struct GNUNET_HashCode hash;
172
173 GNUNET_assert (GNUNET_NO == info->done);
174 switch (status)
175 {
176 case GNUNET_SETI_STATUS_DONE:
177 info->done = GNUNET_YES;
178 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
179 "set intersection done\n");
180 check_all_done ();
181 info->oh = NULL;
182 return;
183 case GNUNET_SETI_STATUS_FAILURE:
184 info->oh = NULL;
185 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
186 "failure\n");
187 GNUNET_SCHEDULER_shutdown ();
188 return;
189 case GNUNET_SETI_STATUS_ADD_LOCAL:
190 GNUNET_CRYPTO_hash (element->data,
191 element->size,
192 &hash);
193 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
194 "set %s: keep element %s\n",
195 info->id,
196 GNUNET_h2s (&hash));
197 break;
198 case GNUNET_SETI_STATUS_DEL_LOCAL:
199 GNUNET_CRYPTO_hash (element->data,
200 element->size,
201 &hash);
202 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
203 "set %s: remove element %s\n",
204 info->id,
205 GNUNET_h2s (&hash));
206 return;
207 default:
208 GNUNET_assert (0);
209 }
210
211 if (element->size != element_size)
212 {
213 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
214 "wrong element size: %u, expected %u\n",
215 element->size,
216 (unsigned int) sizeof(struct GNUNET_HashCode));
217 GNUNET_assert (0);
218 }
219
220 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
221 "set %s: got element (%s)\n",
222 info->id, GNUNET_h2s (element->data));
223 GNUNET_assert (NULL != element->data);
224 {
225 struct GNUNET_HashCode data_hash;
226
227 GNUNET_CRYPTO_hash (element->data,
228 element_size,
229 &data_hash);
230 GNUNET_CONTAINER_multihashmap_put (info->received,
231 &data_hash,
232 NULL,
233 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
234 }
235}
236
237
238static void
239set_listen_cb (void *cls,
240 const struct GNUNET_PeerIdentity *other_peer,
241 const struct GNUNET_MessageHeader *context_msg,
242 struct GNUNET_SETI_Request *request)
243{
244 /* max. 1 option plus terminator */
245 struct GNUNET_SETI_Option opts[2] = { { 0 } };
246 unsigned int n_opts = 0;
247
248 if (NULL == request)
249 {
250 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
251 "listener failed\n");
252 return;
253 }
254 GNUNET_assert (NULL == info2.oh);
255 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
256 "set listen cb called\n");
257 if (use_intersection)
258 {
259 opts[n_opts++] = (struct GNUNET_SETI_Option) { .type =
260 GNUNET_SETI_OPTION_RETURN_INTERSECTION };
261 }
262 opts[n_opts].type = GNUNET_SETI_OPTION_END;
263 info2.oh = GNUNET_SETI_accept (request,
264 opts,
265 &set_result_cb,
266 &info2);
267 GNUNET_SETI_commit (info2.oh,
268 info2.set);
269}
270
271
272static int
273set_insert_iterator (void *cls,
274 const struct GNUNET_HashCode *key,
275 void *value)
276{
277 struct GNUNET_SETI_Handle *set = cls;
278 struct GNUNET_SETI_Element el;
279
280 el.element_type = 0;
281 el.data = value;
282 el.size = element_size;
283 GNUNET_SETI_add_element (set, &el, NULL, NULL);
284 return GNUNET_YES;
285}
286
287
288static void
289handle_shutdown (void *cls)
290{
291 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
292 "Shutting down set profiler\n");
293 if (NULL != set_listener)
294 {
295 GNUNET_SETI_listen_cancel (set_listener);
296 set_listener = NULL;
297 }
298 if (NULL != info1.oh)
299 {
300 GNUNET_SETI_operation_cancel (info1.oh);
301 info1.oh = NULL;
302 }
303 if (NULL != info2.oh)
304 {
305 GNUNET_SETI_operation_cancel (info2.oh);
306 info2.oh = NULL;
307 }
308 if (NULL != info1.set)
309 {
310 GNUNET_SETI_destroy (info1.set);
311 info1.set = NULL;
312 }
313 if (NULL != info2.set)
314 {
315 GNUNET_SETI_destroy (info2.set);
316 info2.set = NULL;
317 }
318 GNUNET_STATISTICS_destroy (statistics, GNUNET_NO);
319}
320
321
322static void
323run (void *cls,
324 const struct GNUNET_CONFIGURATION_Handle *cfg,
325 struct GNUNET_TESTING_Peer *peer)
326{
327 unsigned int i;
328 struct GNUNET_HashCode hash;
329 /* max. 1 option plus terminator */
330 struct GNUNET_SETI_Option opts[2] = { { 0 } };
331 unsigned int n_opts = 0;
332
333 config = cfg;
334
335 GNUNET_assert (element_size > 0);
336
337 if (GNUNET_OK != GNUNET_CRYPTO_get_peer_identity (cfg, &local_peer))
338 {
339 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
340 "could not retrieve host identity\n");
341 ret = 0;
342 return;
343 }
344 statistics = GNUNET_STATISTICS_create ("set-profiler", cfg);
345 GNUNET_SCHEDULER_add_shutdown (&handle_shutdown, NULL);
346 info1.id = "a";
347 info2.id = "b";
348 info1.sent = GNUNET_CONTAINER_multihashmap_create (num_a + 1, GNUNET_NO);
349 info2.sent = GNUNET_CONTAINER_multihashmap_create (num_b + 1, GNUNET_NO);
350 common_sent = GNUNET_CONTAINER_multihashmap_create (num_c + 1, GNUNET_NO);
351 info1.received = GNUNET_CONTAINER_multihashmap_create (num_a + 1, GNUNET_NO);
352 info2.received = GNUNET_CONTAINER_multihashmap_create (num_b + 1, GNUNET_NO);
353 for (i = 0; i < num_a; i++)
354 {
355 char *data = GNUNET_malloc (element_size);
356 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, data, element_size);
357 GNUNET_CRYPTO_hash (data, element_size, &hash);
358 GNUNET_CONTAINER_multihashmap_put (info1.sent, &hash, data,
359 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
360 }
361
362 for (i = 0; i < num_b; i++)
363 {
364 char *data = GNUNET_malloc (element_size);
365 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, data, element_size);
366 GNUNET_CRYPTO_hash (data, element_size, &hash);
367 GNUNET_CONTAINER_multihashmap_put (info2.sent, &hash, data,
368 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
369 }
370
371 for (i = 0; i < num_c; i++)
372 {
373 char *data = GNUNET_malloc (element_size);
374 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, data, element_size);
375 GNUNET_CRYPTO_hash (data, element_size, &hash);
376 GNUNET_CONTAINER_multihashmap_put (common_sent, &hash, data,
377 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
378 }
379
380 GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_STRONG, &app_id);
381
382 info1.set = GNUNET_SETI_create (config);
383 info2.set = GNUNET_SETI_create (config);
384 GNUNET_CONTAINER_multihashmap_iterate (info1.sent,
385 &set_insert_iterator,
386 info1.set);
387 GNUNET_CONTAINER_multihashmap_iterate (info2.sent,
388 &set_insert_iterator,
389 info2.set);
390 GNUNET_CONTAINER_multihashmap_iterate (common_sent,
391 &set_insert_iterator,
392 info1.set);
393 GNUNET_CONTAINER_multihashmap_iterate (common_sent,
394 &set_insert_iterator,
395 info2.set);
396
397 set_listener = GNUNET_SETI_listen (config,
398 &app_id,
399 &set_listen_cb,
400 NULL);
401 if (use_intersection)
402 {
403 opts[n_opts++] = (struct GNUNET_SETI_Option) { .type =
404 GNUNET_SETI_OPTION_RETURN_INTERSECTION };
405 }
406 opts[n_opts].type = GNUNET_SETI_OPTION_END;
407
408 info1.oh = GNUNET_SETI_prepare (&local_peer,
409 &app_id,
410 NULL,
411 opts,
412 set_result_cb,
413 &info1);
414 GNUNET_SETI_commit (info1.oh,
415 info1.set);
416 GNUNET_SETI_destroy (info1.set);
417 info1.set = NULL;
418}
419
420
421static void
422pre_run (void *cls,
423 char *const *args,
424 const char *cfgfile,
425 const struct GNUNET_CONFIGURATION_Handle *cfg)
426{
427 if (0 != GNUNET_TESTING_peer_run ("set-profiler",
428 cfgfile,
429 &run, NULL))
430 ret = 2;
431}
432
433
434int
435main (int argc, char **argv)
436{
437 struct GNUNET_GETOPT_CommandLineOption options[] = {
438 GNUNET_GETOPT_option_uint ('A',
439 "num-first",
440 NULL,
441 gettext_noop ("number of values"),
442 &num_a),
443 GNUNET_GETOPT_option_uint ('B',
444 "num-second",
445 NULL,
446 gettext_noop ("number of values"),
447 &num_b),
448 GNUNET_GETOPT_option_uint ('C',
449 "num-common",
450 NULL,
451 gettext_noop ("number of values"),
452 &num_c),
453 GNUNET_GETOPT_option_uint ('i',
454 "use-intersection",
455 NULL,
456 gettext_noop (
457 "return intersection instead of delta"),
458 &use_intersection),
459 GNUNET_GETOPT_option_uint ('w',
460 "element-size",
461 NULL,
462 gettext_noop ("element size"),
463 &element_size),
464 GNUNET_GETOPT_option_filename ('s',
465 "statistics",
466 "FILENAME",
467 gettext_noop ("write statistics to file"),
468 &statistics_filename),
469 GNUNET_GETOPT_OPTION_END
470 };
471
472 GNUNET_PROGRAM_run2 (argc, argv,
473 "gnunet-seti-profiler",
474 "help",
475 options,
476 &pre_run,
477 NULL,
478 GNUNET_YES);
479 return ret;
480}