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 
198  j = 0;
199  while (j < replication)
200  {
201  int n;
202  int k;
203  int repeat;
205  repeat = GNUNET_NO;
206  for (k = 0; k < j; k++)
207  if (indices[k] == n)
208  {
209  repeat = GNUNET_YES;
210  break;
211  }
212  if (GNUNET_NO == repeat)
213  indices[j++] = n;
214  }
215 }
216 
217 
218 static void
220 {
221  int unique_indices[replication];
222  unsigned int i;
223  unsigned int j;
224  struct GNUNET_HashCode val;
225  struct GNUNET_SET_Element element;
226 
227  if (dist_static)
228  {
229  for (i = 0; i < num_values; i++)
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
285  void *ca_result,
286  const char *emsg)
287 {
288  if (NULL != emsg)
289  {
291  "testbed connect emsg: %s\n",
292  emsg);
293  GNUNET_assert(0);
294  }
295 
297 
299  "connect complete\n");
300 
302  {
303  do_consensus();
304  }
305 }
306 
307 
308 static void
309 new_element_cb(void *cls,
310  const struct GNUNET_SET_Element *element)
311 {
312  struct GNUNET_CONSENSUS_Handle **chp = cls;
313  int idx = chp - consensus_handles;
314 
315  GNUNET_assert(NULL != cls);
316 
317  results_for_peer[idx]++;
318 
319  GNUNET_assert(sizeof(struct GNUNET_HashCode) == element->size);
320 
321  if (GNUNET_YES == verbose)
322  {
323  printf("P%d received %s\n",
324  idx,
325  GNUNET_h2s((struct GNUNET_HashCode *)element->data));
326  }
327 }
328 
329 
340 static void *
341 connect_adapter(void *cls,
342  const struct GNUNET_CONFIGURATION_Handle *cfg)
343 {
344  struct GNUNET_CONSENSUS_Handle **chp = cls;
345  struct GNUNET_CONSENSUS_Handle *consensus;
346 
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[] = {
520  "num-peers",
521  NULL,
522  gettext_noop("number of peers in consensus"),
523  &num_peers),
524 
526  "value-replication",
527  NULL,
528  gettext_noop("how many peers (random selection without replacement) receive one value?"),
529  &replication),
530 
532  "num-values",
533  NULL,
534  gettext_noop("number of values"),
535  &num_values),
536 
538  "timeout",
539  NULL,
540  gettext_noop("consensus timeout"),
542 
543 
545  "delay",
546  NULL,
547  gettext_noop("delay until consensus starts"),
548  &consensus_delay),
549 
551  "statistics",
552  "FILENAME",
553  gettext_noop("write statistics to file"),
555 
557  "dist-static",
558  gettext_noop("distribute elements to a static subset of good peers"),
559  &dist_static),
560 
562  "verbose",
563  gettext_noop("be more verbose (print received values)"),
564  &verbose),
565 
567  };
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:140
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:243
#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: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:517
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:1264
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:2037
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:83
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:2314
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: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