2 This file is part of GNUnet.
3 (C) 2011, 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., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
21 * @file nse/gnunet-nse-profiler.c
23 * @brief Profiling driver for the network size estimation service.
24 * Generally, the profiler starts a given number of peers,
25 * then churns some off, waits a certain amount of time, then
26 * churns again, and repeats.
29 * - need to enable user to specify topology options
30 * - need to check for leaks (especially FD leaks)
34 #include "gnunet_testbed_service.h"
35 #include "gnunet_nse_service.h"
39 * Information we track for a peer in the testbed.
44 * Prev reference in DLL.
49 * Next reference in DLL.
54 * Handle with testbed.
56 struct GNUNET_TESTBED_Peer *daemon;
59 * Testbed operation to connect to NSE service.
61 struct GNUNET_TESTBED_Operation *nse_op;
64 * Handle to statistics service of the peer.
66 struct GNUNET_STATISTICS_Handle *stats;
69 * Testbed operation to connect to statistics service.
71 struct GNUNET_TESTBED_Operation *stats_op;
74 * Task scheduled to get statistics from this peer.
76 GNUNET_SCHEDULER_TaskIdentifier stats_task;
81 * Context for the stats task?
87 * How many messages have peers received during the test.
89 unsigned long long total_nse_received_messages;
92 * How many messages have peers send during the test (should be == received).
94 unsigned long long total_nse_transmitted_messages;
97 * How many messages have travelled an edge in both directions.
99 unsigned long long total_nse_cross;
102 * How many extra messages per edge (corrections) have been received.
104 unsigned long long total_nse_extra;
107 * How many messages have been discarded.
109 unsigned long long total_discarded;
114 * Head of DLL of peers we monitor closely.
116 static struct NSEPeer *peer_head;
119 * Tail of DLL of peers we monitor closely.
121 static struct NSEPeer *peer_tail;
124 * Return value from 'main' (0 == success)
129 * Be verbose (configuration option)
134 * Name of the file with the hosts to run the test over (configuration option)
136 static char *hosts_file;
139 * IP address of this system, as seen by the rest of the system (configuration option)
141 static char *controller_ip;
144 * Maximum number of peers in the test.
146 static unsigned int num_peers;
149 * Total number of rounds to execute.
151 static unsigned int num_rounds;
154 * Current round we are in.
156 static unsigned int current_round;
159 * Array of size 'num_rounds' with the requested number of peers in the given round.
161 static unsigned int *num_peers_in_round;
164 * How many peers are running right now?
166 static unsigned int peers_running;
169 * Specification for the numbers of peers to have in each round.
171 static char *num_peer_spec;
174 * Handles to all of the running peers.
176 static struct GNUNET_TESTBED_Peer **daemons;
179 * Global configuration file
181 static struct GNUNET_CONFIGURATION_Handle *testing_cfg;
184 * Maximum number of connections to NSE services.
186 static unsigned int connection_limit;
189 * Total number of connections in the whole network.
191 static unsigned int total_connections;
194 * File to report results to.
196 static struct GNUNET_DISK_FileHandle *output_file;
199 * Filename to log results to.
201 static char *output_filename;
204 * File to log connection info, statistics to.
206 static struct GNUNET_DISK_FileHandle *data_file;
209 * Filename to log connection info, statistics to.
211 static char *data_filename;
214 * How long to wait before triggering next round?
217 static struct GNUNET_TIME_Relative wait_time = { 60 * 1000 };
220 * How often do we query for statistics during a round?
223 static struct GNUNET_TIME_Relative interval = { 1000 };
226 * Name of the file where we write the topology for each round; NULL for
229 static char *topology_file;
232 * List of hosts we use for the testbed.
234 static struct GNUNET_TESTBED_Host **hosts;
237 * Size of the 'hosts' array.
239 static unsigned int num_hosts;
242 * Handle to the master controller.
244 static struct GNUNET_TESTBED_Controller *controller;
247 * Controller start handle.
249 static struct GNUNET_TESTBED_ControllerProc *copro;
254 static struct GNUNET_TESTBED_Testbed *testbed;
258 * Clean up all of the monitoring connections to NSE and
259 * STATISTICS that we keep to selected peers.
262 close_monitor_connections ()
266 while (NULL != (pos = peer_head))
268 if (NULL != pos->nse_op)
269 GNUNET_TESTBED_operation_done (pos->nse_op);
270 if (NULL != pos->stats_op)
271 GNUNET_TESTBED_operation_done (pos->stats_op);
272 GNUNET_CONTAINER_DLL_remove (peer_head, peer_tail, pos);
273 if (GNUNET_SCHEDULER_NO_TASK != pos->stats_task)
274 GNUNET_SCHEDULER_cancel (pos->stats_task);
281 * Task run on shutdown; cleans up everything.
287 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
289 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ending test.\n");
290 close_monitor_connections ();
292 GNUNET_TESTBED_destroy (testbed);
293 if (NULL != controller)
294 GNUNET_TESTBED_controller_disconnect (controller);
296 GNUNET_TESTBED_controller_stop (copro);
297 while (0 < num_hosts)
298 GNUNET_TESTBED_host_destroy (hosts[--num_hosts]);
299 // FIXME: what about closing other files!?
300 if (NULL != data_file)
301 GNUNET_DISK_file_close (data_file);
306 * Callback to call when network size estimate is updated.
308 * @param cls closure with the 'struct NSEPeer' providing the update
309 * @param timestamp server timestamp
310 * @param estimate the value of the current network size estimate
311 * @param std_dev standard deviation (rounded down to nearest integer)
312 * of the size estimation values seen
316 handle_estimate (void *cls,
317 struct GNUNET_TIME_Absolute timestamp,
318 double estimate, double std_dev)
320 struct NSEPeer *peer = cls;
321 char output_buffer[512];
324 if (NULL == output_file)
327 "Received network size estimate from peer %p. Size: %f std.dev. %f\n",
328 peer, estimate, std_dev);
331 size = GNUNET_snprintf (output_buffer,
332 sizeof (output_buffer),
333 "%p %llu %llu %f %f %f\n",
336 GNUNET_NSE_log_estimate_to_n (estimate), estimate,
338 if (size != GNUNET_DISK_file_write (output_file, output_buffer, size))
339 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
340 "Unable to write to file!\n");
345 * Process core statistic values.
348 * @param subsystem name of subsystem that created the statistic
349 * @param name the name of the datum
350 * @param value the current value
351 * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not
352 * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration
355 core_stats_iterator (void *cls, const char *subsystem, const char *name,
356 uint64_t value, int is_persistent)
358 struct NSEPeer *peer = cls;
359 char output_buffer[512];
362 if (NULL == output_file)
364 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
365 "%p -> %s [%s]: %llu\n",
366 peer, subsystem, name, value);
370 GNUNET_snprintf (output_buffer,
371 sizeof (output_buffer),
374 subsystem, name, value);
375 if (size != GNUNET_DISK_file_write (output_file, output_buffer, size))
376 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Unable to write to file!\n");
382 * Continuation called by "get_stats" function once we are done.
385 * @param success GNUNET_OK if statistics were
386 * successfully obtained, GNUNET_SYSERR if not.
389 core_stats_cont (void *cls, int success);
393 * Function invoked periodically to get the statistics.
395 * @param cls 'struct NSEPeer' to get stats from
396 * @param tc scheduler context
399 core_get_stats (void *cls,
400 const struct GNUNET_SCHEDULER_TaskContext *tc)
402 struct NSEPeer *peer = cls;
404 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
406 GNUNET_TESTBED_operation_done (peer->stats_op);
408 peer->stats_op = NULL;
411 /* FIXME: code duplication! */
412 GNUNET_STATISTICS_get (peer->stats, "core", NULL,
413 GNUNET_TIME_UNIT_FOREVER_REL,
415 &core_stats_iterator, peer);
416 GNUNET_STATISTICS_get (peer->stats, "transport", NULL,
417 GNUNET_TIME_UNIT_FOREVER_REL,
419 &core_stats_iterator, peer);
420 GNUNET_STATISTICS_get (peer->stats, "nse", NULL,
421 GNUNET_TIME_UNIT_FOREVER_REL,
423 &core_stats_iterator, peer);
424 peer->stats_task = GNUNET_SCHEDULER_NO_TASK;
429 * Continuation called by "get_stats" function.
432 * @param success GNUNET_OK if statistics were
433 * successfully obtained, GNUNET_SYSERR if not.
436 core_stats_cont (void *cls,
439 struct NSEPeer *peer = cls;
441 if (GNUNET_OK != success)
443 peer->stats_task = GNUNET_SCHEDULER_add_delayed (interval,
444 &core_get_stats, peer);
449 * Adapter function called to establish a connection to
450 * statistics service.
453 * @param cfg configuration of the peer to connect to; will be available until
454 * GNUNET_TESTBED_operation_done() is called on the operation returned
455 * from GNUNET_TESTBED_service_connect()
456 * @return service handle to return in 'op_result', NULL on error
459 statistics_connect_adapter (void *cls,
460 const struct GNUNET_CONFIGURATION_Handle *cfg)
462 return GNUNET_STATISTICS_create ("<driver>",
468 * Adapter function called to destroy a connection to
469 * statistics service.
472 * @param op_result service handle returned from the connect adapter
475 statistics_disconnect_adapter (void *cls,
478 GNUNET_STATISTICS_destroy (op_result, GNUNET_NO);
483 * Function called by testbed once we are connected to stats service.
485 * @param cls the 'struct NSEPeer' for which we connected to stats
486 * @param op connect operation handle
487 * @param ca_result handle to stats service
488 * @param emsg error message on failure
492 struct GNUNET_TESTBED_Operation *op,
496 struct NSEPeer *current_peer = cls;
498 if (NULL == ca_result)
500 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
501 "Failed to connect to statistics service: %s\n",
503 GNUNET_SCHEDULER_shutdown ();
506 current_peer->stats = ca_result;
507 GNUNET_STATISTICS_get (current_peer->stats, "core", NULL,
508 GNUNET_TIME_UNIT_FOREVER_REL,
510 &core_stats_iterator, current_peer);
511 GNUNET_STATISTICS_get (current_peer->stats, "transport", NULL,
512 GNUNET_TIME_UNIT_FOREVER_REL,
514 &core_stats_iterator, current_peer);
515 GNUNET_STATISTICS_get (current_peer->stats, "nse", NULL,
516 GNUNET_TIME_UNIT_FOREVER_REL,
518 &core_stats_iterator, current_peer);
523 * Adapter function called to establish a connection to
526 * @param cls closure (the 'struct NSEPeer')
527 * @param cfg configuration of the peer to connect to; will be available until
528 * GNUNET_TESTBED_operation_done() is called on the operation returned
529 * from GNUNET_TESTBED_service_connect()
530 * @return service handle to return in 'op_result', NULL on error
533 nse_connect_adapter (void *cls,
534 const struct GNUNET_CONFIGURATION_Handle *cfg)
536 struct NSEPeer *current_peer = cls;
538 return GNUNET_NSE_connect (cfg, &handle_estimate, current_peer);
543 * Adapter function called to destroy a connection to
547 * @param op_result service handle returned from the connect adapter
550 nse_disconnect_adapter (void *cls,
553 GNUNET_NSE_disconnect (op_result);
558 * Task run to connect to the NSE and statistics services to a subset of
559 * all of the running peers.
562 connect_nse_service ()
564 struct NSEPeer *current_peer;
567 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting to nse service of peers\n");
568 for (i = 0; i < num_peers; i++)
570 if ((connection_limit > 0) &&
571 (num_peers > connection_limit) &&
572 (0 != (i % (num_peers / connection_limit))))
574 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
575 "nse-profiler: connecting to nse service of peer %d\n", i);
576 current_peer = GNUNET_malloc (sizeof (struct NSEPeer));
577 current_peer->daemon = daemons[i];
579 = GNUNET_TESTBED_service_connect (NULL,
580 current_peer->daemon,
583 &nse_connect_adapter,
584 &nse_disconnect_adapter,
586 current_peer->stats_op
587 = GNUNET_TESTBED_service_connect (NULL,
588 current_peer->daemon,
590 &stat_run, current_peer,
591 &statistics_connect_adapter,
592 &statistics_disconnect_adapter,
594 GNUNET_CONTAINER_DLL_insert (peer_head, peer_tail, current_peer);
600 * Task that starts/stops peers to move to the next round.
602 * @param cls NULL, unused
603 * @param tc scheduler context (unused)
606 next_round (void *cls,
607 const struct GNUNET_SCHEDULER_TaskContext *tc);
611 * Continuation called by the "get_all" and "get" functions at the
612 * end of a round. Obtains the final statistics and writes them to
613 * the file, then either starts the next round, or, if this was the
614 * last round, terminates the run.
616 * @param cls struct StatsContext
617 * @param op operation handle
618 * @param emsg error message, NULL on success
621 stats_finished_callback (void *cls,
622 struct GNUNET_TESTBED_Operation *op,
625 struct StatsContext *stats_context = cls;
631 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
632 "Failed to get statistics: %s\n",
634 GNUNET_SCHEDULER_shutdown ();
635 GNUNET_free (stats_context);
638 if (NULL != data_file)
640 /* Stats lookup successful, write out data */
642 GNUNET_snprintf (buf, sizeof (buf),
643 "TOTAL_NSE_RECEIVED_MESSAGES_%u: %u \n",
645 stats_context->total_nse_received_messages);
646 GNUNET_DISK_file_write (data_file, buf, buf_len);
648 GNUNET_snprintf (buf, sizeof (buf),
649 "TOTAL_NSE_TRANSMITTED_MESSAGES_%u: %u\n",
651 stats_context->total_nse_transmitted_messages);
652 GNUNET_DISK_file_write (data_file, buf, buf_len);
654 GNUNET_snprintf (buf, sizeof (buf),
655 "TOTAL_NSE_CROSS_%u: %u \n",
657 stats_context->total_nse_cross);
658 GNUNET_DISK_file_write (data_file, buf, buf_len);
660 GNUNET_snprintf (buf, sizeof (buf),
661 "TOTAL_NSE_EXTRA_%u: %u \n",
663 stats_context->total_nse_extra);
664 GNUNET_DISK_file_write (data_file, buf, buf_len);
666 GNUNET_snprintf (buf, sizeof (buf),
667 "TOTAL_NSE_DISCARDED_%u: %u \n",
669 stats_context->total_discarded);
670 GNUNET_DISK_file_write (data_file, buf, buf_len);
672 GNUNET_SCHEDULER_add_now (&next_round, NULL);
673 GNUNET_free (stats_context);
678 * Callback function to process statistic values.
680 * @param cls struct StatsContext
681 * @param peer the peer the statistics belong to
682 * @param subsystem name of subsystem that created the statistic
683 * @param name the name of the datum
684 * @param value the current value
685 * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not
686 * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration
689 statistics_iterator (void *cls,
690 const struct GNUNET_TESTBED_Peer *peer,
691 const char *subsystem, const char *name, uint64_t value,
694 struct StatsContext *stats_context = cls;
698 if (0 != strcmp (subsystem, "nse"))
700 if (0 == strcmp (name, "# flood messages received"))
702 stats_context->total_nse_received_messages += value;
703 if ( (verbose > 1) &&
704 (NULL != data_file) )
707 GNUNET_snprintf (buf, sizeof (buf),
710 GNUNET_DISK_file_write (data_file, buf, buf_len);
713 if (0 == strcmp (name, "# flood messages transmitted"))
715 stats_context->total_nse_transmitted_messages += value;
716 if ( (verbose > 1) &&
717 (NULL != data_file) )
720 GNUNET_snprintf (buf, sizeof (buf),
721 "%p %u TRANSMITTED\n",
723 GNUNET_DISK_file_write (data_file, buf, buf_len);
726 if (0 == strcmp (name, "# cross messages"))
727 stats_context->total_nse_cross += value;
728 if (0 == strcmp (name, "# extra messages"))
729 stats_context->total_nse_extra += value;
730 if (0 == strcmp (name, "# flood messages discarded (clock skew too large)"))
731 stats_context->total_discarded += value;
737 * Function called upon completion of the node start/stop operations
738 * for the current round. Writes the new topology to disk.
743 char temp_output_file[1024];
745 if (NULL != topology_file)
747 GNUNET_snprintf (temp_output_file, sizeof (temp_output_file),
749 topology_file, current_round);
750 GNUNET_TESTBED_overlay_write_topology_to_file (controller,
757 * We're at the end of a round. Stop monitoring, write total
758 * number of connections to log and get full stats. Then trigger
761 * @param cls unused, NULL
765 finish_round (void *cls,
766 const struct GNUNET_SCHEDULER_TaskContext *tc)
768 struct StatsContext *stats_context;
772 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
773 "Have %u connections\n",
775 if (NULL != data_file)
777 buf_len = GNUNET_snprintf (buf, sizeof (buf),
778 "CONNECTIONS_0: %u\n",
780 GNUNET_DISK_file_write (data_file, buf, buf_len);
782 close_monitor_connections ();
783 stats_context = GNUNET_malloc (sizeof (struct StatsContext));
784 GNUNET_TESTBED_get_statistics (num_peers_in_round[current_round],
786 &statistics_iterator,
787 &stats_finished_callback,
793 * We have reached the desired number of peers for the current round.
794 * Run it (by connecting and monitoring a few peers and waiting the
795 * specified delay before finishing the round).
801 connect_nse_service ();
802 GNUNET_SCHEDULER_add_delayed (wait_time,
809 * Task run at the end of a round. Disconnect from all monitored
810 * peers; then get statistics from *all* peers.
812 * @param cls NULL, unused
816 next_round (void *cls,
817 const struct GNUNET_SCHEDULER_TaskContext *tc)
821 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "disconnecting nse service of peers\n");
824 if (current_round == num_rounds)
826 /* this was the last round, terminate */
827 GNUNET_SCHEDULER_shutdown ();
830 if (num_peers_in_round[current_round] == peers_running)
832 /* no need to churn, just run next round */
837 /* start peers if we have too few */
838 for (i=peers_running;i<num_peers_in_round[current_round];i++)
839 GNUNET_TESTBED_peer_start (NULL, daemons[i], NULL, NULL);
841 /* stop peers if we have too many */
842 for (i=num_peers_in_round[current_round];i<peers_running;i++)
843 GNUNET_TESTBED_peer_stop (daemons[i], NULL, NULL);
848 * Function that will be called whenever something in the
851 * @param cls closure, NULL
852 * @param event information on what is happening
855 master_controller_cb (void *cls,
856 const struct GNUNET_TESTBED_EventInformation *event)
860 case GNUNET_TESTBED_ET_PEER_START:
862 if (num_peers_in_round[current_round] == peers_running)
865 case GNUNET_TESTBED_ET_PEER_STOP:
867 if (num_peers_in_round[current_round] == peers_running)
870 case GNUNET_TESTBED_ET_CONNECT:
873 case GNUNET_TESTBED_ET_DISCONNECT:
883 controller_start_cb (void *cls,
884 const struct GNUNET_CONFIGURATION_Handle *cfg,
887 if (GNUNET_OK != status)
890 GNUNET_SCHEDULER_shutdown ();
893 num_hosts = GNUNET_TESTBED_hosts_load_from_file (hosts_file,
898 "Failed to read host information from `%s'\n",
902 controller = GNUNET_TESTBED_controller_connect (cfg,
905 &master_controller_cb, NULL);
907 testbed = GNUNET_TESTBED_create (controller,
911 0 /* FIXME: topology */,
912 NULL /* FIXME: topology options */);
917 * Actual main function that runs the emulation.
920 * @param args remaining args, unused
921 * @param cfgfile name of the configuration
922 * @param cfg configuration handle
925 run (void *cls, char *const *args, const char *cfgfile,
926 const struct GNUNET_CONFIGURATION_Handle *cfg)
932 testing_cfg = GNUNET_CONFIGURATION_dup (cfg);
933 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting daemons.\n");
935 GNUNET_CONFIGURATION_set_value_string (testing_cfg, "testing",
936 "use_progressbars", "YES");
937 if (NULL == num_peer_spec)
939 fprintf (stderr, "You need to specify the number of peers to run\n");
942 for (tok = strtok (num_peer_spec, ","); NULL != tok; tok = strtok (NULL, ","))
944 if (1 != sscanf (tok, "%u", &num))
946 fprintf (stderr, "You need to specify numbers, not `%s'\n", tok);
951 fprintf (stderr, "Refusing to run a round with 0 peers\n");
954 GNUNET_array_grow (num_peers_in_round, num_rounds, num);
955 num_peers = GNUNET_MAX (num_peers, num);
959 fprintf (stderr, "Refusing to run a testbed with no rounds\n");
962 daemons = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Peer*) * num_peers);
963 if ( (NULL != data_filename) &&
964 (NULL == (data_file =
965 GNUNET_DISK_file_open (data_filename,
966 GNUNET_DISK_OPEN_READWRITE |
967 GNUNET_DISK_OPEN_TRUNCATE |
968 GNUNET_DISK_OPEN_CREATE,
969 GNUNET_DISK_PERM_USER_READ |
970 GNUNET_DISK_PERM_USER_WRITE))) )
971 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
975 if ( (NULL != output_filename) &&
976 (NULL == (output_file =
977 GNUNET_DISK_file_open (output_filename,
978 GNUNET_DISK_OPEN_READWRITE |
979 GNUNET_DISK_OPEN_CREATE,
980 GNUNET_DISK_PERM_USER_READ |
981 GNUNET_DISK_PERM_USER_WRITE))) )
982 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open",
986 (copro = GNUNET_TESTBED_controller_start (controller_ip, NULL,
988 &controller_start_cb, NULL)))
991 "Failed to start controller\n");
994 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
995 &shutdown_task, NULL);
1002 * @return 0 on success
1005 main (int argc, char *const *argv)
1007 static struct GNUNET_GETOPT_CommandLineOption options[] = {
1008 {'C', "connections", "COUNT",
1009 gettext_noop ("limit to the number of connections to NSE services, 0 for none"),
1010 1, &GNUNET_GETOPT_set_string, &num_peer_spec},
1011 {'d', "details", "FILENAME",
1012 gettext_noop ("name of the file for writing connection information and statistics"),
1013 1, &GNUNET_GETOPT_set_string, &data_filename},
1014 {'H', "hosts", "FILENAME",
1015 gettext_noop ("name of the file with the login information for the testbed"),
1016 1, &GNUNET_GETOPT_set_string, &hosts_file},
1017 {'i', "ip", "CONTROLLER_IP",
1018 gettext_noop ("IP address of this system as seen by the rest of the testbed"),
1019 1, &GNUNET_GETOPT_set_string, &controller_ip},
1020 {'I', "interval", "DELAY",
1021 gettext_noop ("delay between queries to statistics during a round"),
1022 1, &GNUNET_GETOPT_set_relative_time, &interval},
1023 {'t', "topology", "FILENAME",
1024 gettext_noop ("prefix of the filenames we use for writing the topology for each round"),
1025 1, &GNUNET_GETOPT_set_string, &topology_file},
1026 {'o', "output", "FILENAME",
1027 gettext_noop ("name of the file for writing the main results"),
1028 1, &GNUNET_GETOPT_set_string, &output_filename},
1029 {'p', "peers", "NETWORKSIZESPEC",
1030 gettext_noop ("Number of peers to run in each round, separated by commas"),
1031 1, &GNUNET_GETOPT_set_string, &num_peer_spec},
1032 {'V', "verbose", NULL,
1033 gettext_noop ("be verbose (print progress information)"),
1034 0, &GNUNET_GETOPT_increment_value, &verbose},
1035 {'w', "wait", "DELAY",
1036 gettext_noop ("delay between rounds"),
1037 1, &GNUNET_GETOPT_set_relative_time, &wait_time},
1038 GNUNET_GETOPT_OPTION_END
1040 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
1042 GNUNET_log_setup ("nse-profiler", "WARNING", NULL);
1044 GNUNET_PROGRAM_run (argc, argv, "nse-profiler",
1046 ("Measure quality and performance of the NSE service."),
1047 options, &run, NULL))
1052 /* end of nse-profiler.c */