2 This file is part of GNUnet
3 Copyright (C) 2012 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 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 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
22 * @file consensus/gnunet-consensus-profiler.c
23 * @brief profiling tool for gnunet-consensus
24 * @author Florian Dold
27 #include "gnunet_util_lib.h"
28 #include "gnunet_time_lib.h"
29 #include "gnunet_consensus_service.h"
30 #include "gnunet_testbed_service.h"
32 static unsigned int num_peers = 2;
34 static unsigned int replication = 1;
36 static unsigned int num_values = 5;
38 static struct GNUNET_TIME_Relative conclude_timeout;
40 static struct GNUNET_TIME_Relative consensus_delay;
42 static struct GNUNET_CONSENSUS_Handle **consensus_handles;
44 static struct GNUNET_TESTBED_Operation **testbed_operations;
46 static unsigned int num_connected_handles;
48 static struct GNUNET_TESTBED_Peer **peers;
50 static struct GNUNET_PeerIdentity *peer_ids;
52 static unsigned int num_retrieved_peer_ids;
54 static struct GNUNET_HashCode session_id;
56 static unsigned int peers_done = 0;
58 static unsigned *results_for_peer;
60 static char *statistics_filename;
62 static FILE *statistics_file;
67 * Start time for all consensuses.
69 static struct GNUNET_TIME_Absolute start;
72 * Deadline for all consensuses.
74 static struct GNUNET_TIME_Absolute deadline;
78 * Signature of the event handler function called by the
79 * respective event controller.
82 * @param event information about the event
85 controller_cb (void *cls,
86 const struct GNUNET_TESTBED_EventInformation *event)
93 statistics_done_db (void *cls,
95 GNUNET_TESTBED_Operation
99 GNUNET_assert (NULL == emsg);
100 GNUNET_TESTBED_operation_done (op);
101 if (NULL != statistics_file)
102 fclose (statistics_file);
103 GNUNET_SCHEDULER_shutdown ();
108 * Callback function to process statistic values from all peers.
111 * @param peer the peer the statistic belong to
112 * @param subsystem name of subsystem that created the statistic
113 * @param name the name of the datum
114 * @param value the current value
115 * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not
116 * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration
119 statistics_cb (void *cls,
120 const struct GNUNET_TESTBED_Peer *peer,
121 const char *subsystem,
126 if (NULL != statistics_file)
128 fprintf (statistics_file, "P%u\t%s\t%s\t%lu\n", GNUNET_TESTBED_get_index (peer), subsystem, name, (unsigned long) value);
135 destroy (void *cls, const struct GNUNET_SCHEDULER_TaskContext *ctx)
137 struct GNUNET_CONSENSUS_Handle *consensus = cls;
139 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
140 "destroying consensus\n");
141 GNUNET_CONSENSUS_destroy (consensus);
143 if (peers_done == num_peers)
146 for (i = 0; i < num_peers; i++)
147 GNUNET_TESTBED_operation_done (testbed_operations[i]);
148 for (i = 0; i < num_peers; i++)
149 printf ("P%u got %u of %u elements\n",
153 if (NULL != statistics_filename)
154 statistics_file = fopen (statistics_filename, "w");
155 GNUNET_TESTBED_get_statistics (num_peers, peers, NULL, NULL,
164 * Called when a conclusion was successful.
166 * @param cls closure, the consensus handle
167 * @return #GNUNET_YES if more consensus groups should be offered,
171 conclude_cb (void *cls)
173 struct GNUNET_CONSENSUS_Handle **chp = cls;
175 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
176 "consensus %d done\n",
177 chp - consensus_handles);
178 GNUNET_SCHEDULER_add_now (destroy, *chp);
183 generate_indices (int *indices)
187 while (j < replication)
192 n = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, num_peers);
194 for (k = 0; k < j; k++)
200 if (GNUNET_NO == repeat)
209 int unique_indices[replication];
212 for (i = 0; i < num_values; i++)
215 struct GNUNET_HashCode val;
216 struct GNUNET_SET_Element element;
218 generate_indices (unique_indices);
219 GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, &val);
222 element.size = sizeof (val);
223 for (j = 0; j < replication; j++)
227 cid = unique_indices[j];
228 GNUNET_CONSENSUS_insert (consensus_handles[cid],
234 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
235 "all elements inserted, calling conclude\n");
237 for (i = 0; i < num_peers; i++)
238 GNUNET_CONSENSUS_conclude (consensus_handles[i],
239 conclude_cb, &consensus_handles[i]);
244 * Callback to be called when a service connect operation is completed
246 * @param cls the callback closure from functions generating an operation
247 * @param op the operation that has been finished
248 * @param ca_result the service handle returned from GNUNET_TESTBED_ConnectAdapter()
249 * @param emsg error message in case the operation has failed; will be NULL if
250 * operation has executed successfully.
253 connect_complete (void *cls,
254 struct GNUNET_TESTBED_Operation *op,
261 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
262 "testbed connect emsg: %s\n",
267 num_connected_handles++;
269 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
270 "connect complete\n");
272 if (num_connected_handles == num_peers)
280 new_element_cb (void *cls,
281 const struct GNUNET_SET_Element *element)
283 struct GNUNET_CONSENSUS_Handle **chp = cls;
284 int idx = chp - consensus_handles;
286 GNUNET_assert (NULL != cls);
288 results_for_peer[idx]++;
290 GNUNET_assert (sizeof (struct GNUNET_HashCode) == element->size);
292 if (GNUNET_YES == verbose)
294 printf ("P%d received %s\n",
296 GNUNET_h2s ((struct GNUNET_HashCode *) element->data));
302 * Adapter function called to establish a connection to
306 * @param cfg configuration of the peer to connect to; will be available until
307 * GNUNET_TESTBED_operation_done() is called on the operation returned
308 * from GNUNET_TESTBED_service_connect()
309 * @return service handle to return in 'op_result', NULL on error
312 connect_adapter (void *cls,
313 const struct GNUNET_CONFIGURATION_Handle *cfg)
315 struct GNUNET_CONSENSUS_Handle **chp = cls;
316 struct GNUNET_CONSENSUS_Handle *consensus;
317 chp = (struct GNUNET_CONSENSUS_Handle **) cls;
319 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
320 "connect adapter, %d peers\n",
322 consensus = GNUNET_CONSENSUS_create (cfg,
327 &new_element_cb, chp);
328 *chp = (struct GNUNET_CONSENSUS_Handle *) consensus;
334 * Adapter function called to destroy a connection to
338 * @param op_result service handle returned from the connect adapter
341 disconnect_adapter(void *cls, void *op_result)
343 /* FIXME: what to do here? */
348 * Callback to be called when the requested peer information is available
350 * @param cb_cls the closure from GNUNET_TETSBED_peer_get_information()
351 * @param op the operation this callback corresponds to
352 * @param pinfo the result; will be NULL if the operation has failed
353 * @param emsg error message if the operation has failed; will be NULL if the
354 * operation is successfull
357 peer_info_cb (void *cb_cls,
358 struct GNUNET_TESTBED_Operation *op,
359 const struct GNUNET_TESTBED_PeerInformation *pinfo,
362 struct GNUNET_PeerIdentity *p;
365 GNUNET_assert (NULL == emsg);
367 p = (struct GNUNET_PeerIdentity *) cb_cls;
369 if (pinfo->pit == GNUNET_TESTBED_PIT_IDENTITY)
371 *p = *pinfo->result.id;
372 num_retrieved_peer_ids++;
373 if (num_retrieved_peer_ids == num_peers)
374 for (i = 0; i < num_peers; i++)
375 testbed_operations[i] =
376 GNUNET_TESTBED_service_connect (NULL, peers[i], "consensus", connect_complete, NULL,
377 connect_adapter, disconnect_adapter, &consensus_handles[i]);
384 GNUNET_TESTBED_operation_done (op);
389 * Signature of a main function for a testcase.
392 * @param h the run handle
393 * @param num_peers number of peers in 'peers'
394 * @param started_peers handle to peers run in the testbed. NULL upon timeout (see
395 * GNUNET_TESTBED_test_run()).
396 * @param links_succeeded the number of overlay link connection attempts that
398 * @param links_failed the number of overlay link connection attempts that
402 test_master (void *cls,
403 struct GNUNET_TESTBED_RunHandle *h,
404 unsigned int num_peers,
405 struct GNUNET_TESTBED_Peer **started_peers,
406 unsigned int links_succeeded,
407 unsigned int links_failed)
411 GNUNET_log_setup ("gnunet-consensus", "INFO", NULL);
413 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "test master\n");
415 peers = started_peers;
417 peer_ids = GNUNET_malloc (num_peers * sizeof (struct GNUNET_PeerIdentity));
419 results_for_peer = GNUNET_malloc (num_peers * sizeof (unsigned int));
420 consensus_handles = GNUNET_malloc (num_peers * sizeof (struct ConsensusHandle *));
421 testbed_operations = GNUNET_malloc (num_peers * sizeof (struct ConsensusHandle *));
423 for (i = 0; i < num_peers; i++)
424 GNUNET_TESTBED_peer_get_information (peers[i],
425 GNUNET_TESTBED_PIT_IDENTITY,
432 run (void *cls, char *const *args, const char *cfgfile,
433 const struct GNUNET_CONFIGURATION_Handle *cfg)
435 static char *session_str = "gnunet-consensus/test";
437 int topology_cmp_result;
439 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, "testbed", "OVERLAY_TOPOLOGY", &topology))
442 "'OVERLAY_TOPOLOGY' not found in 'testbed' config section, "
443 "seems like you passed the wrong configuration file\n");
447 topology_cmp_result = strcasecmp (topology, "NONE");
448 GNUNET_free (topology);
450 if (0 == topology_cmp_result)
453 "'OVERLAY_TOPOLOGY' set to 'NONE', "
454 "seems like you passed the wrong configuration file\n");
458 if (num_peers < replication)
460 fprintf (stderr, "k must be <=n\n");
464 start = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (), consensus_delay);
465 deadline = GNUNET_TIME_absolute_add (start, conclude_timeout);
467 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
468 "running gnunet-consensus\n");
470 GNUNET_CRYPTO_hash (session_str, strlen(session_str), &session_id);
472 (void) GNUNET_TESTBED_test_run ("gnunet-consensus",
484 main (int argc, char **argv)
486 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
487 { 'n', "num-peers", NULL,
488 gettext_noop ("number of peers in consensus"),
489 GNUNET_YES, &GNUNET_GETOPT_set_uint, &num_peers },
490 { 'k', "value-replication", NULL,
491 gettext_noop ("how many peers (random selection without replacement) receive one value?"),
492 GNUNET_YES, &GNUNET_GETOPT_set_uint, &replication },
493 { 'x', "num-values", NULL,
494 gettext_noop ("number of values"),
495 GNUNET_YES, &GNUNET_GETOPT_set_uint, &num_values },
496 { 't', "timeout", NULL,
497 gettext_noop ("consensus timeout"),
498 GNUNET_YES, &GNUNET_GETOPT_set_relative_time, &conclude_timeout },
499 { 'd', "delay", NULL,
500 gettext_noop ("delay until consensus starts"),
501 GNUNET_YES, &GNUNET_GETOPT_set_relative_time, &consensus_delay },
502 { 's', "statistics", NULL,
503 gettext_noop ("write statistics to file"),
504 GNUNET_YES, &GNUNET_GETOPT_set_filename, &statistics_filename },
505 { 'V', "verbose", NULL,
506 gettext_noop ("be more verbose (print received values)"),
507 GNUNET_NO, &GNUNET_GETOPT_set_one, &verbose },
508 GNUNET_GETOPT_OPTION_END
510 conclude_timeout = GNUNET_TIME_UNIT_SECONDS;
511 GNUNET_PROGRAM_run2 (argc, argv, "gnunet-consensus-profiler",
513 options, &run, NULL, GNUNET_YES);