GNUnet  0.10.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 (peer), subsystem, name, (unsigned long) value);
140  }
141  return GNUNET_OK;
142 }
143 
144 
145 static void
146 destroy (void *cls)
147 {
148  struct GNUNET_CONSENSUS_Handle *consensus = cls;
149 
151  "destroying consensus\n");
152  GNUNET_CONSENSUS_destroy (consensus);
153  peers_done++;
154  if (peers_done == num_peers)
155  {
156  unsigned int i;
157  for (i = 0; i < num_peers; i++)
158  GNUNET_TESTBED_operation_done (testbed_operations[i]);
159  for (i = 0; i < num_peers; i++)
160  printf ("P%u got %u of %u elements\n",
161  i,
162  results_for_peer[i],
163  num_values);
164  if (NULL != statistics_filename)
165  statistics_file = fopen (statistics_filename, "w");
166  GNUNET_TESTBED_get_statistics (num_peers, peers, NULL, NULL,
169  NULL);
170  }
171 }
172 
173 
181 static void
182 conclude_cb (void *cls)
183 {
184  struct GNUNET_CONSENSUS_Handle **chp = cls;
185 
187  "consensus %d done\n",
188  (int) (chp - consensus_handles));
190 }
191 
192 
193 static void
194 generate_indices (int *indices)
195 {
196  int j;
197  j = 0;
198  while (j < replication)
199  {
200  int n;
201  int k;
202  int repeat;
204  repeat = GNUNET_NO;
205  for (k = 0; k < j; k++)
206  if (indices[k] == n)
207  {
208  repeat = GNUNET_YES;
209  break;
210  }
211  if (GNUNET_NO == repeat)
212  indices[j++] = n;
213  }
214 }
215 
216 
217 static void
219 {
220  int unique_indices[replication];
221  unsigned int i;
222  unsigned int j;
223  struct GNUNET_HashCode val;
224  struct GNUNET_SET_Element element;
225 
226  if (dist_static)
227  {
228  for (i = 0; i < num_values; i++)
229  {
230 
232 
233  element.data = &val;
234  element.size = sizeof (val);
235  for (j = 0; j < replication; j++)
236  {
237  GNUNET_CONSENSUS_insert (consensus_handles[j],
238  &element,
239  NULL, NULL);
240  }
241  }
242  }
243  else
244  {
245  for (i = 0; i < num_values; i++)
246  {
247  generate_indices (unique_indices);
249 
250  element.data = &val;
251  element.size = sizeof (val);
252  for (j = 0; j < replication; j++)
253  {
254  int cid;
255 
256  cid = unique_indices[j];
257  GNUNET_CONSENSUS_insert (consensus_handles[cid],
258  &element,
259  NULL, NULL);
260  }
261  }
262  }
263 
265  "all elements inserted, calling conclude\n");
266 
267  for (i = 0; i < num_peers; i++)
268  GNUNET_CONSENSUS_conclude (consensus_handles[i],
269  conclude_cb, &consensus_handles[i]);
270 }
271 
272 
282 static void
283 connect_complete (void *cls,
285  void *ca_result,
286  const char *emsg)
287 {
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  chp = (struct GNUNET_CONSENSUS_Handle **) cls;
348 
350  "connect adapter, %d peers\n",
351  num_peers);
352  consensus = GNUNET_CONSENSUS_create (cfg,
353  num_peers, peer_ids,
354  &session_id,
355  start,
356  deadline,
357  &new_element_cb, chp);
358  *chp = (struct GNUNET_CONSENSUS_Handle *) consensus;
359  return consensus;
360 }
361 
362 
370 static void
371 disconnect_adapter(void *cls, void *op_result)
372 {
373  /* FIXME: what to do here? */
375  "disconnect adapter called\n");
376 }
377 
378 
388 static void
389 peer_info_cb (void *cb_cls,
391  const struct GNUNET_TESTBED_PeerInformation *pinfo,
392  const char *emsg)
393 {
394  struct GNUNET_PeerIdentity *p;
395  int i;
396 
397  GNUNET_assert (NULL == emsg);
398 
399  p = (struct GNUNET_PeerIdentity *) cb_cls;
400 
401  if (pinfo->pit == GNUNET_TESTBED_PIT_IDENTITY)
402  {
403  *p = *pinfo->result.id;
406  for (i = 0; i < num_peers; i++)
407  testbed_operations[i] =
408  GNUNET_TESTBED_service_connect (NULL, peers[i], "consensus", connect_complete, NULL,
409  connect_adapter, disconnect_adapter, &consensus_handles[i]);
410  }
411  else
412  {
413  GNUNET_assert (0);
414  }
415 
417 }
418 
419 
433 static void
434 test_master (void *cls,
435  struct GNUNET_TESTBED_RunHandle *h,
436  unsigned int num_peers,
437  struct GNUNET_TESTBED_Peer **started_peers,
438  unsigned int links_succeeded,
439  unsigned int links_failed)
440 {
441  int i;
442 
443  GNUNET_log_setup ("gnunet-consensus", "INFO", NULL);
444 
445  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "test master\n");
446 
447  peers = started_peers;
448 
449  peer_ids = GNUNET_malloc (num_peers * sizeof (struct GNUNET_PeerIdentity));
450 
451  results_for_peer = GNUNET_malloc (num_peers * sizeof (unsigned int));
452  consensus_handles = GNUNET_malloc (num_peers * sizeof (struct ConsensusHandle *));
453  testbed_operations = GNUNET_malloc (num_peers * sizeof (struct ConsensusHandle *));
454 
455  for (i = 0; i < num_peers; i++)
458  peer_info_cb,
459  &peer_ids[i]);
460 }
461 
462 
463 static void
464 run (void *cls, char *const *args, const char *cfgfile,
465  const struct GNUNET_CONFIGURATION_Handle *cfg)
466 {
467  static char *session_str = "gnunet-consensus/test";
468  char *topology;
469  int topology_cmp_result;
470 
471  if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, "testbed", "OVERLAY_TOPOLOGY", &topology))
472  {
473  fprintf (stderr,
474  "'OVERLAY_TOPOLOGY' not found in 'testbed' config section, "
475  "seems like you passed the wrong configuration file\n");
476  return;
477  }
478 
479  topology_cmp_result = strcasecmp (topology, "NONE");
480  GNUNET_free (topology);
481 
482  if (0 == topology_cmp_result)
483  {
484  fprintf (stderr,
485  "'OVERLAY_TOPOLOGY' set to 'NONE', "
486  "seems like you passed the wrong configuration file\n");
487  return;
488  }
489 
490  if (num_peers < replication)
491  {
492  fprintf (stderr, "k must be <=n\n");
493  return;
494  }
495 
498 
500  "running gnunet-consensus\n");
501 
502  GNUNET_CRYPTO_hash (session_str, strlen(session_str), &session_id);
503 
504  (void) GNUNET_TESTBED_test_run ("gnunet-consensus",
505  cfgfile,
506  num_peers,
507  0,
509  NULL,
510  test_master,
511  NULL);
512 }
513 
514 
515 int
516 main (int argc, char **argv)
517 {
518  struct GNUNET_GETOPT_CommandLineOption options[] = {
519 
521  "num-peers",
522  NULL,
523  gettext_noop ("number of peers in consensus"),
524  &num_peers),
525 
527  "value-replication",
528  NULL,
529  gettext_noop ("how many peers (random selection without replacement) receive one value?"),
530  &replication),
531 
533  "num-values",
534  NULL,
535  gettext_noop ("number of values"),
536  &num_values),
537 
539  "timeout",
540  NULL,
541  gettext_noop ("consensus timeout"),
543 
544 
546  "delay",
547  NULL,
548  gettext_noop ("delay until consensus starts"),
549  &consensus_delay),
550 
552  "statistics",
553  "FILENAME",
554  gettext_noop ("write statistics to file"),
556 
558  "dist-static",
559  gettext_noop ("distribute elements to a static subset of good peers"),
560  &dist_static),
561 
563  "verbose",
564  gettext_noop ("be more verbose (print received values)"),
565  &verbose),
566 
568  };
570  GNUNET_PROGRAM_run2 (argc, argv, "gnunet-consensus-profiler",
571  "help",
572  options, &run, NULL, GNUNET_YES);
573  return 0;
574 }
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.
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
union GNUNET_TESTBED_PeerInformation::@64 result
The result of the get information operation; Choose according to the pit.
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:244
#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:81
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:78
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:393
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:524
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:94
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:138
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:44
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:1273
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:2046
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.
static struct GNUNET_CONFIGURATION_Handle * cfg
Our configuration.
Definition: gnunet-arm.c:104
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)
const char * name
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
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:2326
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:80
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:139
A peer controlled by the testing framework.
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