GNUnet  0.11.x
gnunet-consensus-profiler.c
Go to the documentation of this file.
1 /*
2  This file is part of GNUnet
3  Copyright (C) 2012 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 
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet_time_lib.h"
30 #include "gnunet_testbed_service.h"
31 
32 static unsigned int num_peers = 2;
33 
34 static unsigned int replication = 1;
35 
36 static unsigned int num_values = 5;
37 
39 
41 
43 
45 
46 static unsigned int num_connected_handles;
47 
48 static struct GNUNET_TESTBED_Peer **peers;
49 
51 
52 static unsigned int num_retrieved_peer_ids;
53 
55 
56 static unsigned int peers_done = 0;
57 
58 static int dist_static;
59 
60 static unsigned *results_for_peer;
61 
66 static char *statistics_filename;
67 
72 static FILE *statistics_file;
73 
74 static int verbose;
75 
80 
85 
86 
94 static void
95 controller_cb (void *cls,
96  const struct GNUNET_TESTBED_EventInformation *event)
97 {
98  GNUNET_assert (0);
99 }
100 
101 
102 static void
104  struct
106  *op,
107  const char *emsg)
108 {
109  GNUNET_assert (NULL == emsg);
111  if (NULL != statistics_file)
112  fclose (statistics_file);
113  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "got statistics, shutting down\n");
115 }
116 
117 
129 static int
130 statistics_cb (void *cls,
131  const struct GNUNET_TESTBED_Peer *peer,
132  const char *subsystem,
133  const char *name,
134  uint64_t value,
135  int is_persistent)
136 {
137  if (NULL != statistics_file)
138  {
139  fprintf (statistics_file, "P%u\t%s\t%s\t%lu\n", GNUNET_TESTBED_get_index (
140  peer), subsystem, name, (unsigned long) value);
141  }
142  return GNUNET_OK;
143 }
144 
145 
146 static void
147 destroy (void *cls)
148 {
149  struct GNUNET_CONSENSUS_Handle *consensus = cls;
150 
152  "destroying consensus\n");
153  GNUNET_CONSENSUS_destroy (consensus);
154  peers_done++;
155  if (peers_done == num_peers)
156  {
157  unsigned int i;
158  for (i = 0; i < num_peers; i++)
159  GNUNET_TESTBED_operation_done (testbed_operations[i]);
160  for (i = 0; i < num_peers; i++)
161  printf ("P%u got %u of %u elements\n",
162  i,
163  results_for_peer[i],
164  num_values);
165  if (NULL != statistics_filename)
166  statistics_file = fopen (statistics_filename, "w");
167  GNUNET_TESTBED_get_statistics (num_peers, peers, NULL, NULL,
170  NULL);
171  }
172 }
173 
174 
182 static void
183 conclude_cb (void *cls)
184 {
185  struct GNUNET_CONSENSUS_Handle **chp = cls;
186 
188  "consensus %d done\n",
189  (int) (chp - consensus_handles));
191 }
192 
193 
194 static void
195 generate_indices (int *indices)
196 {
197  int j;
198 
199  j = 0;
200  while (j < replication)
201  {
202  int n;
203  int k;
204  int repeat;
206  repeat = GNUNET_NO;
207  for (k = 0; k < j; k++)
208  if (indices[k] == n)
209  {
210  repeat = GNUNET_YES;
211  break;
212  }
213  if (GNUNET_NO == repeat)
214  indices[j++] = n;
215  }
216 }
217 
218 
219 static void
221 {
222  int unique_indices[replication];
223  unsigned int i;
224  unsigned int j;
225  struct GNUNET_HashCode val;
226  struct GNUNET_SET_Element element;
227 
228  if (dist_static)
229  {
230  for (i = 0; i < num_values; i++)
231  {
233 
234  element.data = &val;
235  element.size = sizeof(val);
236  for (j = 0; j < replication; j++)
237  {
238  GNUNET_CONSENSUS_insert (consensus_handles[j],
239  &element,
240  NULL, NULL);
241  }
242  }
243  }
244  else
245  {
246  for (i = 0; i < num_values; i++)
247  {
248  generate_indices (unique_indices);
250 
251  element.data = &val;
252  element.size = sizeof(val);
253  for (j = 0; j < replication; j++)
254  {
255  int cid;
256 
257  cid = unique_indices[j];
258  GNUNET_CONSENSUS_insert (consensus_handles[cid],
259  &element,
260  NULL, NULL);
261  }
262  }
263  }
264 
266  "all elements inserted, calling conclude\n");
267 
268  for (i = 0; i < num_peers; i++)
269  GNUNET_CONSENSUS_conclude (consensus_handles[i],
270  conclude_cb, &consensus_handles[i]);
271 }
272 
273 
283 static void
284 connect_complete (void *cls,
286  void *ca_result,
287  const char *emsg)
288 {
289  if (NULL != emsg)
290  {
292  "testbed connect emsg: %s\n",
293  emsg);
294  GNUNET_assert (0);
295  }
296 
298 
300  "connect complete\n");
301 
303  {
304  do_consensus ();
305  }
306 }
307 
308 
309 static void
310 new_element_cb (void *cls,
311  const struct GNUNET_SET_Element *element)
312 {
313  struct GNUNET_CONSENSUS_Handle **chp = cls;
314  int idx = chp - consensus_handles;
315 
316  GNUNET_assert (NULL != cls);
317 
318  results_for_peer[idx]++;
319 
320  GNUNET_assert (sizeof(struct GNUNET_HashCode) == element->size);
321 
322  if (GNUNET_YES == verbose)
323  {
324  printf ("P%d received %s\n",
325  idx,
326  GNUNET_h2s ((struct GNUNET_HashCode *) element->data));
327  }
328 }
329 
330 
341 static void *
342 connect_adapter (void *cls,
343  const struct GNUNET_CONFIGURATION_Handle *cfg)
344 {
345  struct GNUNET_CONSENSUS_Handle **chp = cls;
346  struct GNUNET_CONSENSUS_Handle *consensus;
347 
348  chp = (struct GNUNET_CONSENSUS_Handle **) cls;
349 
351  "connect adapter, %d peers\n",
352  num_peers);
353  consensus = GNUNET_CONSENSUS_create (cfg,
354  num_peers, peer_ids,
355  &session_id,
356  start,
357  deadline,
358  &new_element_cb, chp);
359  *chp = (struct GNUNET_CONSENSUS_Handle *) consensus;
360  return consensus;
361 }
362 
363 
371 static void
372 disconnect_adapter (void *cls, void *op_result)
373 {
374  /* FIXME: what to do here? */
376  "disconnect adapter called\n");
377 }
378 
379 
389 static void
390 peer_info_cb (void *cb_cls,
392  const struct GNUNET_TESTBED_PeerInformation *pinfo,
393  const char *emsg)
394 {
395  struct GNUNET_PeerIdentity *p;
396  int i;
397 
398  GNUNET_assert (NULL == emsg);
399 
400  p = (struct GNUNET_PeerIdentity *) cb_cls;
401 
402  if (pinfo->pit == GNUNET_TESTBED_PIT_IDENTITY)
403  {
404  *p = *pinfo->result.id;
407  for (i = 0; i < num_peers; i++)
408  testbed_operations[i] =
409  GNUNET_TESTBED_service_connect (NULL, peers[i], "consensus",
410  connect_complete, NULL,
412  &consensus_handles[i]);
413  }
414  else
415  {
416  GNUNET_assert (0);
417  }
418 
420 }
421 
422 
436 static void
437 test_master (void *cls,
438  struct GNUNET_TESTBED_RunHandle *h,
439  unsigned int num_peers,
440  struct GNUNET_TESTBED_Peer **started_peers,
441  unsigned int links_succeeded,
442  unsigned int links_failed)
443 {
444  int i;
445 
446  GNUNET_log_setup ("gnunet-consensus", "INFO", NULL);
447 
448  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "test master\n");
449 
450  peers = started_peers;
451 
452  peer_ids = GNUNET_malloc (num_peers * sizeof(struct GNUNET_PeerIdentity));
453 
454  results_for_peer = GNUNET_malloc (num_peers * sizeof(unsigned int));
455  consensus_handles = GNUNET_malloc (num_peers * sizeof(struct
456  ConsensusHandle *));
457  testbed_operations = GNUNET_malloc (num_peers * sizeof(struct
458  ConsensusHandle *));
459 
460  for (i = 0; i < num_peers; i++)
463  peer_info_cb,
464  &peer_ids[i]);
465 }
466 
467 
468 static void
469 run (void *cls, char *const *args, const char *cfgfile,
470  const struct GNUNET_CONFIGURATION_Handle *cfg)
471 {
472  static char *session_str = "gnunet-consensus/test";
473  char *topology;
474  int topology_cmp_result;
475 
476  if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, "testbed",
477  "OVERLAY_TOPOLOGY",
478  &topology))
479  {
480  fprintf (stderr,
481  "'OVERLAY_TOPOLOGY' not found in 'testbed' config section, "
482  "seems like you passed the wrong configuration file\n");
483  return;
484  }
485 
486  topology_cmp_result = strcasecmp (topology, "NONE");
487  GNUNET_free (topology);
488 
489  if (0 == topology_cmp_result)
490  {
491  fprintf (stderr,
492  "'OVERLAY_TOPOLOGY' set to 'NONE', "
493  "seems like you passed the wrong configuration file\n");
494  return;
495  }
496 
497  if (num_peers < replication)
498  {
499  fprintf (stderr, "k must be <=n\n");
500  return;
501  }
502 
506 
508  "running gnunet-consensus\n");
509 
510  GNUNET_CRYPTO_hash (session_str, strlen (session_str), &session_id);
511 
512  (void) GNUNET_TESTBED_test_run ("gnunet-consensus",
513  cfgfile,
514  num_peers,
515  0,
517  NULL,
518  test_master,
519  NULL);
520 }
521 
522 
523 int
524 main (int argc, char **argv)
525 {
526  struct GNUNET_GETOPT_CommandLineOption options[] = {
528  "num-peers",
529  NULL,
530  gettext_noop ("number of peers in consensus"),
531  &num_peers),
532 
534  "value-replication",
535  NULL,
536  gettext_noop (
537  "how many peers (random selection without replacement) receive one value?"),
538  &replication),
539 
541  "num-values",
542  NULL,
543  gettext_noop ("number of values"),
544  &num_values),
545 
547  "timeout",
548  NULL,
549  gettext_noop ("consensus timeout"),
551 
552 
554  "delay",
555  NULL,
556  gettext_noop (
557  "delay until consensus starts"),
558  &consensus_delay),
559 
561  "statistics",
562  "FILENAME",
563  gettext_noop ("write statistics to file"),
565 
567  "dist-static",
568  gettext_noop (
569  "distribute elements to a static subset of good peers"),
570  &dist_static),
571 
573  "verbose",
574  gettext_noop (
575  "be more verbose (print received values)"),
576  &verbose),
577 
579  };
580 
582  GNUNET_PROGRAM_run2 (argc, argv, "gnunet-consensus-profiler",
583  "help",
584  options, &run, NULL, GNUNET_YES);
585  return 0;
586 }
struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_option_relative_time(char shortName, const char *name, const char *argumentHelp, const char *description, struct GNUNET_TIME_Relative *val)
Allow user to specify a struct GNUNET_TIME_Relative (using human-readable "fancy" time)...
static struct GNUNET_TIME_Relative conclude_timeout
static void do_consensus()
struct GNUNET_TESTBED_Operation * GNUNET_TESTBED_get_statistics(unsigned int num_peers, struct GNUNET_TESTBED_Peer **peers, const char *subsystem, const char *name, GNUNET_TESTBED_StatisticsIterator proc, GNUNET_TESTBED_OperationCompletionCallback cont, void *cls)
Convenience method that iterates over all (running) peers and retrieves all statistics from each peer...
static char * subsystem
Set to subsystem that we&#39;re going to get stats for (or NULL for all).
void GNUNET_CONSENSUS_destroy(struct GNUNET_CONSENSUS_Handle *consensus)
Destroy a consensus handle (free all state associated with it, no longer call any of the callbacks)...
static int statistics_cb(void *cls, const struct GNUNET_TESTBED_Peer *peer, const char *subsystem, const char *name, uint64_t value, int is_persistent)
Callback function to process statistic values from all peers.
static const struct GNUNET_CONFIGURATION_Handle * cfg
Configuration we are using.
Definition: gnunet-abd.c:36
int GNUNET_PROGRAM_run2(int argc, char *const *argv, const char *binaryName, const char *binaryHelp, const struct GNUNET_GETOPT_CommandLineOption *options, GNUNET_PROGRAM_Main task, void *task_cls, int run_without_scheduler)
Run a standard GNUnet command startup sequence (initialize loggers and configuration, parse options).
Definition: program.c:141
static void test_master(void *cls, struct GNUNET_TESTBED_RunHandle *h, unsigned int num_peers, struct GNUNET_TESTBED_Peer **started_peers, unsigned int links_succeeded, unsigned int links_failed)
Signature of a main function for a testcase.
Element stored in a set.
int GNUNET_TESTBED_test_run(const char *testname, const char *cfg_filename, unsigned int num_peers, uint64_t event_mask, GNUNET_TESTBED_ControllerCallback cc, void *cc_cls, GNUNET_TESTBED_TestMaster test_master, void *test_master_cls)
Convenience method for running a "simple" test on the local system with a single call from &#39;main&#39;...
enum GNUNET_TESTBED_PeerInformationType pit
Peer information type; captures which of the types in the &#39;op_result&#39; is actually in use...
uint32_t GNUNET_CRYPTO_random_u32(enum GNUNET_CRYPTO_Quality mode, uint32_t i)
Produce a random value.
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
static int op_result(struct GNUNET_OP_Handle *h, uint64_t op_id, int64_t result_code, const void *data, uint16_t data_size, void **ctx, uint8_t cancel)
Remove an operation, and call its result callback (unless it was cancelled).
Definition: op.c:245
#define GNUNET_TIME_UNIT_SECONDS
One second.
static unsigned * results_for_peer
static unsigned int replication
Argument to GNUNET_TESTBED_ControllerCallback with details about the event.
static unsigned int num_connected_handles
static struct GNUNET_HashCode session_id
#define GNUNET_NO
Definition: gnunet_common.h:78
const char * GNUNET_h2s(const struct GNUNET_HashCode *hc)
Convert a hash value to a string (for printing debug messages).
#define GNUNET_OK
Named constants for return values.
Definition: gnunet_common.h:75
enum GNUNET_TESTBED_TopologyOption topology
The topology to generate.
struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_add(struct GNUNET_TIME_Absolute start, struct GNUNET_TIME_Relative duration)
Add a given relative duration to the given start time.
Definition: time.c:395
Definition of a command line option.
void GNUNET_CONSENSUS_insert(struct GNUNET_CONSENSUS_Handle *consensus, const struct GNUNET_SET_Element *element, GNUNET_CONSENSUS_InsertDoneCallback idc, void *idc_cls)
Insert an element in the set being reconsiled.
static struct GNUNET_TIME_Absolute start
Start time for all consensuses.
static unsigned int num_values
void GNUNET_SCHEDULER_shutdown(void)
Request the shutdown of a scheduler.
Definition: scheduler.c:526
struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_OPTION_END
Definition: 002.c:13
static struct GNUNET_ARM_Handle * h
Connection with ARM.
Definition: gnunet-arm.c:99
const void * data
Actual data of the element.
Opaque handle to an abstract operation to be executed by the testing framework.
static void statistics_done_cb(void *cls, struct GNUNET_TESTBED_Operation *op, const char *emsg)
static void controller_cb(void *cls, const struct GNUNET_TESTBED_EventInformation *event)
Signature of the event handler function called by the respective event controller.
static char * statistics_filename
The profiler will write statistics for all peers to the file with this name.
struct GNUNET_PeerIdentity * id
The identity of the peer.
struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_option_filename(char shortName, const char *name, const char *argumentHelp, const char *description, char **str)
Allow user to specify a filename (automatically path expanded).
struct GNUNET_TESTBED_Operation * GNUNET_TESTBED_service_connect(void *op_cls, struct GNUNET_TESTBED_Peer *peer, const char *service_name, GNUNET_TESTBED_ServiceConnectCompletionCallback cb, void *cb_cls, GNUNET_TESTBED_ConnectAdapter ca, GNUNET_TESTBED_DisconnectAdapter da, void *cada_cls)
Connect to a service offered by the given peer.
static struct GNUNET_OS_Process * p
Helper process we started.
Definition: gnunet-qr.c:59
void GNUNET_CRYPTO_hash_create_random(enum GNUNET_CRYPTO_Quality mode, struct GNUNET_HashCode *result)
Create a random hash code.
Definition: crypto_hash.c:144
static char * value
Value of the record to add/remove.
static int verbose
static struct GNUNET_PeerIdentity * peer_ids
void GNUNET_CRYPTO_hash(const void *block, size_t size, struct GNUNET_HashCode *ret)
Compute hash of a given block.
Definition: crypto_hash.c:48
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_now(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run as soon as possible.
Definition: scheduler.c:1280
static void conclude_cb(void *cls)
Called when a conclusion was successful.
static FILE * statistics_file
The profiler will write statistics for all peers to this file.
static void generate_indices(int *indices)
void GNUNET_TESTBED_operation_done(struct GNUNET_TESTBED_Operation *operation)
This function is used to signal that the event information (struct GNUNET_TESTBED_EventInformation) f...
Definition: testbed_api.c:2044
A 512-bit hashcode.
struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_get(void)
Get the current time.
Definition: time.c:118
static int dist_static
struct GNUNET_TESTBED_Operation * GNUNET_TESTBED_peer_get_information(struct GNUNET_TESTBED_Peer *peer, enum GNUNET_TESTBED_PeerInformationType pit, GNUNET_TESTBED_PeerInfoCallback cb, void *cb_cls)
Request information about a peer.
static struct GNUNET_TESTBED_Operation ** testbed_operations
int GNUNET_CONFIGURATION_get_value_string(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, char **value)
Get a configuration value that should be a string.
struct GNUNET_TESTBED_Peer * peer
The peer associated with this model.
static void run(void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg)
static struct GNUNET_TIME_Relative consensus_delay
static struct GNUNET_TESTBED_Peer ** peers
static unsigned int num_peers
static void disconnect_adapter(void *cls, void *op_result)
Adapter function called to destroy a connection to a service.
The identity of the host (wraps the signing key of the peer).
What is the identity of the peer? Returns a &#39;const struct GNUNET_PeerIdentity *&#39;. ...
configuration data
Definition: configuration.c:85
const char * name
static unsigned int peers_done
struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_option_flag(char shortName, const char *name, const char *description, int *val)
Allow user to specify a flag (which internally means setting an integer to 1/GNUNET_YES/GNUNET_OK.
uint32_t GNUNET_TESTBED_get_index(const struct GNUNET_TESTBED_Peer *peer)
Return the index of the peer inside of the total peer array, aka.
Definition: testbed_api.c:2321
uint16_t size
Number of bytes in the buffer pointed to by data.
#define GNUNET_log(kind,...)
static void peer_info_cb(void *cb_cls, struct GNUNET_TESTBED_Operation *op, const struct GNUNET_TESTBED_PeerInformation *pinfo, const char *emsg)
Callback to be called when the requested peer information is available.
void GNUNET_CONSENSUS_conclude(struct GNUNET_CONSENSUS_Handle *consensus, GNUNET_CONSENSUS_ConcludeCallback conclude, void *conclude_cls)
We are done with inserting new elements into the consensus; try to conclude the consensus within a gi...
static unsigned int num_retrieved_peer_ids
static void * connect_adapter(void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg)
Adapter function called to establish a connection to a service.
Handle for the service.
Definition: consensus_api.c:40
static struct GNUNET_TIME_Absolute deadline
Deadline for all consensuses.
static struct GNUNET_CONSENSUS_Handle ** consensus_handles
Time for absolute times used by GNUnet, in microseconds.
#define GNUNET_YES
Definition: gnunet_common.h:77
struct GNUNET_CONSENSUS_Handle * GNUNET_CONSENSUS_create(const struct GNUNET_CONFIGURATION_Handle *cfg, unsigned int num_peers, const struct GNUNET_PeerIdentity *peers, const struct GNUNET_HashCode *session_id, struct GNUNET_TIME_Absolute start, struct GNUNET_TIME_Absolute deadline, GNUNET_CONSENSUS_ElementCallback new_element_cb, void *new_element_cls)
Create a consensus session.
static void destroy(void *cls)
struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_option_uint(char shortName, const char *name, const char *argumentHelp, const char *description, unsigned int *val)
Allow user to specify an unsigned int.
int GNUNET_log_setup(const char *comp, const char *loglevel, const char *logfile)
Setup logging.
static struct GNUNET_ARM_Operation * op
Current operation.
Definition: gnunet-arm.c:144
A peer controlled by the testing framework.
union GNUNET_TESTBED_PeerInformation::@61 result
The result of the get information operation; Choose according to the pit.
int main(int argc, char **argv)
static void connect_complete(void *cls, struct GNUNET_TESTBED_Operation *op, void *ca_result, const char *emsg)
Callback to be called when a service connect operation is completed.
No good quality of the operation is needed (i.e., random numbers can be pseudo-random).
#define GNUNET_malloc(size)
Wrapper around malloc.
#define GNUNET_free(ptr)
Wrapper around free.
static void new_element_cb(void *cls, const struct GNUNET_SET_Element *element)
Time for relative time used by GNUnet, in microseconds.
Data returned from GNUNET_TESTBED_peer_get_information.
#define gettext_noop(String)
Definition: gettext.h:69