X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Ftestbed%2Fgnunet-testbed-profiler.c;h=3bddfac09e99318c5da4739641e89c565e594d66;hb=f4d040c0f0dd2fef3d73b1f4532c76219f760f75;hp=256b9efa0fedfa33fbdf5755b3eaa1d6206c6b47;hpb=9a065e97118b882b4fb6f245b060f21aa1f3ee3b;p=oweals%2Fgnunet.git diff --git a/src/testbed/gnunet-testbed-profiler.c b/src/testbed/gnunet-testbed-profiler.c index 256b9efa0..3bddfac09 100644 --- a/src/testbed/gnunet-testbed-profiler.c +++ b/src/testbed/gnunet-testbed-profiler.c @@ -26,9 +26,81 @@ #include "platform.h" #include "gnunet_common.h" +#include "gnunet_util_lib.h" #include "gnunet_testbed_service.h" #include "testbed_api_hosts.h" +/** + * Generic loggins shorthand + */ +#define LOG(kind,...) \ + GNUNET_log (kind, __VA_ARGS__) + + +/** + * DLL of operations + */ +struct DLLOperation +{ + /** + * The testbed operation handle + */ + struct GNUNET_TESTBED_Operation *op; + + /** + * Closure + */ + void *cls; + + /** + * The next pointer for DLL + */ + struct DLLOperation *next; + + /** + * The prev pointer for DLL + */ + struct DLLOperation *prev; +}; + + +/** + * Availanle states during profiling + */ +enum State +{ + /** + * Initial state + */ + STATE_INIT = 0, + + /** + * Starting slaves + */ + STATE_SLAVES_STARTING, + + /** + * Creating peers + */ + STATE_PEERS_CREATING, + + /** + * Starting peers + */ + STATE_PEERS_STARTING, + + /** + * Linking peers + */ + STATE_PEERS_LINKING, + + /** + * Destroying peers; we can do this as the controller takes care of stopping a + * peer if it is running + */ + STATE_PEERS_DESTROYING +}; + /** * An array of hosts loaded from the hostkeys file @@ -40,16 +112,76 @@ static struct GNUNET_TESTBED_Host **hosts; */ static struct GNUNET_TESTBED_Peer **peers; +/* /\** */ +/* * Operation handle */ +/* *\/ */ +/* static struct GNUNET_TESTBED_Operation *op; */ + +/** + * Host registration handle + */ +static struct GNUNET_TESTBED_HostRegistrationHandle *reg_handle; + +/** + * Handle to the master controller process + */ +struct GNUNET_TESTBED_ControllerProc *mc_proc; + +/** + * Handle to the master controller + */ +struct GNUNET_TESTBED_Controller *mc; + +/** + * Handle to global configuration + */ +struct GNUNET_CONFIGURATION_Handle *cfg; + /** - * Operation handle + * Head of the operations list */ -static struct GNUNET_TESTBED_Operation *op; +struct DLLOperation *dll_op_head; + +/** + * Tail of the operations list + */ +struct DLLOperation *dll_op_tail; + +/** + * Peer linking - topology operation + */ +struct GNUNET_TESTBED_Operation *topology_op; /** * Abort task identifier */ static GNUNET_SCHEDULER_TaskIdentifier abort_task; +/** + * Shutdown task identifier + */ +static GNUNET_SCHEDULER_TaskIdentifier shutdown_task; + +/** + * Host registration task identifier + */ +static GNUNET_SCHEDULER_TaskIdentifier register_hosts_task; + +/** + * Global event mask for all testbed events + */ +uint64_t event_mask; + +/** + * The starting time of a profiling step + */ +struct GNUNET_TIME_Absolute prof_start_time; + +/** + * Duration profiling step has taken + */ +struct GNUNET_TIME_Relative prof_time; + /** * Current peer id */ @@ -65,11 +197,46 @@ static unsigned int num_peers; */ static unsigned int num_hosts; +/** + * Number of random links to be established between peers + */ +static unsigned int num_links; + +/** + * Number of timeout failures to tolerate + */ +static unsigned int num_cont_fails; + +/** + * Continuous failures during overlay connect operations + */ +static unsigned int cont_fails; + +/** + * Links which are successfully established + */ +static unsigned int established_links; + +/** + * Links which are not successfully established + */ +static unsigned int failed_links; + /** * Global testing status */ static int result; +/** + * current state of profiling + */ +enum State state; + +/** + * The topology we want to acheive + */ +enum GNUNET_TESTBED_TopologyOption topology; + /** * Shutdown nicely @@ -80,15 +247,34 @@ static int result; static void do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { + struct DLLOperation *dll_op; unsigned int nhost; + shutdown_task = GNUNET_SCHEDULER_NO_TASK; if (GNUNET_SCHEDULER_NO_TASK != abort_task) GNUNET_SCHEDULER_cancel (abort_task); - GNUNET_free_non_null (peers); + if (GNUNET_SCHEDULER_NO_TASK != register_hosts_task) + GNUNET_SCHEDULER_cancel (register_hosts_task); + if (NULL != reg_handle) + GNUNET_TESTBED_cancel_registration (reg_handle); + if (NULL != topology_op) + GNUNET_TESTBED_operation_done (topology_op); for (nhost = 0; nhost < num_hosts; nhost++) if (NULL != hosts[nhost]) GNUNET_TESTBED_host_destroy (hosts[nhost]); GNUNET_free_non_null (hosts); + while (NULL != (dll_op = dll_op_head)) + { + GNUNET_TESTBED_operation_done (dll_op->op); + GNUNET_CONTAINER_DLL_remove (dll_op_head, dll_op_tail, dll_op); + GNUNET_free (dll_op); + } + if (NULL != mc) + GNUNET_TESTBED_controller_disconnect (mc); + if (NULL != mc_proc) + GNUNET_TESTBED_controller_stop (mc_proc); + if (NULL != cfg) + GNUNET_CONFIGURATION_destroy (cfg); GNUNET_SCHEDULER_shutdown (); /* Stop scheduler to shutdown testbed run */ } @@ -102,25 +288,178 @@ do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) static void do_abort (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Profiling timedout -- Aborting\n"); + LOG (GNUNET_ERROR_TYPE_WARNING, "Aborting\n"); abort_task = GNUNET_SCHEDULER_NO_TASK; - GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); + result = GNUNET_SYSERR; + if (GNUNET_SCHEDULER_NO_TASK != shutdown_task) + GNUNET_SCHEDULER_cancel (shutdown_task); + shutdown_task = GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); +} + + + + + +/** + * Functions of this signature are called when a peer has been successfully + * started or stopped. + * + * @param cls the closure from GNUNET_TESTBED_peer_start/stop() + * @param emsg NULL on success; otherwise an error description + */ +static void +peer_churn_cb (void *cls, const char *emsg) +{ + struct DLLOperation *dll_op = cls; + struct GNUNET_TESTBED_Operation *op; + static unsigned int started_peers; + + op = dll_op->op; + GNUNET_CONTAINER_DLL_remove (dll_op_head, dll_op_tail, dll_op); + GNUNET_free (dll_op); + if (NULL != emsg) + { + LOG (GNUNET_ERROR_TYPE_WARNING, + _("An operation has failed while starting peers\n")); + GNUNET_TESTBED_operation_done (op); + GNUNET_SCHEDULER_cancel (abort_task); + abort_task = GNUNET_SCHEDULER_add_now (&do_abort, NULL); + return; + } + GNUNET_TESTBED_operation_done (op); + if (++started_peers == num_peers) + { + prof_time = GNUNET_TIME_absolute_get_duration (prof_start_time); + printf ("%u peers started successfully in %.2f seconds\n", + num_peers, ((double) prof_time.rel_value) / 1000.00); + fflush (stdout); + result = GNUNET_OK; + if ((0 == num_links) && (topology == GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI)) + { + shutdown_task = GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); + return; + } + state = STATE_PEERS_LINKING; + /* Do overlay connect */ + prof_start_time = GNUNET_TIME_absolute_get (); + switch (topology) + { + case GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI: + topology_op = + GNUNET_TESTBED_overlay_configure_topology (NULL, num_peers, peers, + topology, + num_links, + GNUNET_TESTBED_TOPOLOGY_DISABLE_AUTO_RETRY, + GNUNET_TESTBED_TOPOLOGY_OPTION_END); + break; + case GNUNET_TESTBED_TOPOLOGY_CLIQUE: + topology_op = + GNUNET_TESTBED_overlay_configure_topology (NULL, num_peers, peers, + topology, + GNUNET_TESTBED_TOPOLOGY_DISABLE_AUTO_RETRY, + GNUNET_TESTBED_TOPOLOGY_OPTION_END); + num_links = num_peers * (num_peers - 1); + break; + default: + GNUNET_assert (0); + } + } } /** - * Task to be executed when peers are ready + * Functions of this signature are called when a peer has been successfully + * created * - * @param cls NULL - * @param tc the task context + * @param cls the closure from GNUNET_TESTBED_peer_create() + * @param peer the handle for the created peer; NULL on any error during + * creation + * @param emsg NULL if peer is not NULL; else MAY contain the error description + */ +static void +peer_create_cb (void *cls, struct GNUNET_TESTBED_Peer *peer, const char *emsg) +{ + struct DLLOperation *dll_op = cls; + struct GNUNET_TESTBED_Peer **peer_ptr; + static unsigned int created_peers; + unsigned int peer_cnt; + + if (NULL != emsg) + { + LOG (GNUNET_ERROR_TYPE_WARNING, + _("Creating a peer failed. Error: %s\n"), emsg); + GNUNET_TESTBED_operation_done (dll_op->op); + GNUNET_CONTAINER_DLL_remove (dll_op_head, dll_op_tail, dll_op); + GNUNET_free (dll_op); + GNUNET_SCHEDULER_cancel (abort_task); + abort_task = GNUNET_SCHEDULER_add_now (&do_abort, NULL); + return; + } + peer_ptr = dll_op->cls; + GNUNET_assert (NULL == *peer_ptr); + *peer_ptr = peer; + GNUNET_TESTBED_operation_done (dll_op->op); + GNUNET_CONTAINER_DLL_remove (dll_op_head, dll_op_tail, dll_op); + GNUNET_free (dll_op); + if (++created_peers == num_peers) + { + prof_time = GNUNET_TIME_absolute_get_duration (prof_start_time); + printf ("%u peers created successfully in %.2f seconds\n", + num_peers, ((double) prof_time.rel_value) / 1000.00); + fflush (stdout); + /* Now peers are to be started */ + state = STATE_PEERS_STARTING; + prof_start_time = GNUNET_TIME_absolute_get (); + for (peer_cnt = 0; peer_cnt < num_peers; peer_cnt++) + { + dll_op = GNUNET_malloc (sizeof (struct DLLOperation)); + dll_op->op = GNUNET_TESTBED_peer_start (dll_op, peers[peer_cnt], + &peer_churn_cb, dll_op); + GNUNET_CONTAINER_DLL_insert_tail (dll_op_head, dll_op_tail, dll_op); + } + } +} + + +/** + * Function to print summary about how many overlay links we have made and how + * many failed */ static void -master_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +print_overlay_links_summary () { - result = GNUNET_OK; - GNUNET_assert (NULL != peers[0]); - op = GNUNET_TESTBED_peer_stop (peers[0], NULL, NULL); - GNUNET_assert (NULL != op); + prof_time = GNUNET_TIME_absolute_get_duration (prof_start_time); + printf ("\n%u links established in %.2f seconds\n", + established_links, ((double) prof_time.rel_value) / 1000.00); + printf ("%u links failed due to timeouts\n", failed_links); +} + + +/** + * Function to start peers + */ +static void +start_peers () +{ + struct DLLOperation *dll_op; + unsigned int peer_cnt; + + state = STATE_PEERS_CREATING; + prof_start_time = GNUNET_TIME_absolute_get (); + peers = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Peer *) + * num_peers); + for (peer_cnt = 0; peer_cnt < num_peers; peer_cnt++) + { + dll_op = GNUNET_malloc (sizeof (struct DLLOperation)); + dll_op->cls = &peers[peer_cnt]; + dll_op->op = GNUNET_TESTBED_peer_create (mc, + hosts + [peer_cnt % num_hosts], + cfg, + &peer_create_cb, + dll_op); + GNUNET_CONTAINER_DLL_insert_tail (dll_op_head, dll_op_tail, dll_op); + } } @@ -134,19 +473,97 @@ static void controller_event_cb (void *cls, const struct GNUNET_TESTBED_EventInformation *event) { + struct DLLOperation *dll_op; + struct GNUNET_TESTBED_Operation *op; - switch (event->type) + switch (state) { - case GNUNET_TESTBED_ET_PEER_START: - GNUNET_assert (NULL == peers[peer_id]); - GNUNET_assert (NULL != event->details.peer_start.peer); - peers[peer_id++] = event->details.peer_start.peer; + case STATE_SLAVES_STARTING: + switch (event->type) + { + case GNUNET_TESTBED_ET_OPERATION_FINISHED: + { + static unsigned int slaves_started; + + dll_op = event->details.operation_finished.op_cls; + GNUNET_CONTAINER_DLL_remove (dll_op_head, dll_op_tail, dll_op); + GNUNET_free (dll_op); + op = event->details.operation_finished.operation; + if (NULL != event->details.operation_finished.emsg) + { + LOG (GNUNET_ERROR_TYPE_WARNING, + _("An operation has failed while starting slaves\n")); + GNUNET_TESTBED_operation_done (op); + GNUNET_SCHEDULER_cancel (abort_task); + abort_task = GNUNET_SCHEDULER_add_now (&do_abort, NULL); + return; + } + GNUNET_TESTBED_operation_done (op); + /* Proceed to start peers */ + if (++slaves_started == num_hosts - 1) + { + printf ("%u controllers started successfully\n", num_hosts); + fflush (stdout); + start_peers (); + } + } + break; + default: + GNUNET_assert (0); + } break; - case GNUNET_TESTBED_ET_PEER_STOP: - GNUNET_assert (NULL != op); - GNUNET_TESTBED_operation_done (op); - GNUNET_assert (peers[0] == event->details.peer_stop.peer); - GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); + case STATE_PEERS_STARTING: + switch (event->type) + { + case GNUNET_TESTBED_ET_OPERATION_FINISHED: + /* Control reaches here when peer start fails */ + case GNUNET_TESTBED_ET_PEER_START: + /* we handle peer starts in peer_churn_cb */ + break; + default: + GNUNET_assert (0); + } + break; + case STATE_PEERS_LINKING: + switch (event->type) + { + case GNUNET_TESTBED_ET_OPERATION_FINISHED: + /* Control reaches here when a peer linking operation fails */ + if (NULL != event->details.operation_finished.emsg) + { + printf ("F"); + fflush (stdout); + failed_links++; + if (++cont_fails > num_cont_fails) + { + printf ("\nAborting due to very high failure rate"); + print_overlay_links_summary (); + GNUNET_SCHEDULER_cancel (abort_task); + abort_task = GNUNET_SCHEDULER_add_now (&do_abort, NULL); + return; + } + } + break; + case GNUNET_TESTBED_ET_CONNECT: + { + if (0 != cont_fails) + cont_fails--; + if (0 == established_links) + printf ("Establishing links. Please wait\n"); + printf ("."); + fflush (stdout); + established_links++; + } + break; + default: + GNUNET_assert (0); + } + if ((established_links + failed_links) == num_links) + { + print_overlay_links_summary (); + result = GNUNET_OK; + shutdown_task = GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); + } break; default: GNUNET_assert (0); @@ -154,24 +571,138 @@ controller_event_cb (void *cls, } +/** + * Task to register all hosts available in the global host list + * + * @param cls NULL + * @param tc the scheduler task context + */ +static void +register_hosts (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + + +/** + * Callback which will be called to after a host registration succeeded or failed + * + * @param cls the closure + * @param emsg the error message; NULL if host registration is successful + */ +static void +host_registration_completion (void *cls, const char *emsg) +{ + reg_handle = NULL; + if (NULL != emsg) + { + LOG (GNUNET_ERROR_TYPE_WARNING, + _("Host registration failed for a host. Error: %s\n"), emsg); + GNUNET_SCHEDULER_cancel (abort_task); + abort_task = GNUNET_SCHEDULER_add_now (&do_abort, NULL); + return; + } + register_hosts_task = GNUNET_SCHEDULER_add_now (®ister_hosts, NULL); +} + + +/** + * Task to register all hosts available in the global host list + * + * @param cls NULL + * @param tc the scheduler task context + */ +static void +register_hosts (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct DLLOperation *dll_op; + static unsigned int reg_host; + unsigned int slave; + + register_hosts_task = GNUNET_SCHEDULER_NO_TASK; + if (reg_host == num_hosts - 1) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "All hosts successfully registered\n"); + /* Start slaves */ + state = STATE_SLAVES_STARTING; + for (slave = 1; slave < num_hosts; slave++) + { + dll_op = GNUNET_malloc (sizeof (struct DLLOperation)); + dll_op->op = GNUNET_TESTBED_controller_link (dll_op, + mc, + hosts[slave], + hosts[0], + cfg, + GNUNET_YES); + GNUNET_CONTAINER_DLL_insert_tail (dll_op_head, dll_op_tail, dll_op); + } + return; + } + reg_handle = GNUNET_TESTBED_register_host (mc, hosts[++reg_host], + host_registration_completion, + NULL); +} + + +/** + * Callback to signal successfull startup of the controller process + * + * @param cls the closure from GNUNET_TESTBED_controller_start() + * @param config the configuration with which the controller has been started; + * NULL if status is not GNUNET_OK + * @param status GNUNET_OK if the startup is successfull; GNUNET_SYSERR if not, + * GNUNET_TESTBED_controller_stop() shouldn't be called in this case + */ +static void +status_cb (void *cls, const struct GNUNET_CONFIGURATION_Handle *config, int status) +{ + if (GNUNET_SCHEDULER_NO_TASK != abort_task) + GNUNET_SCHEDULER_cancel (abort_task); + if (GNUNET_OK != status) + { + mc_proc = NULL; + abort_task = GNUNET_SCHEDULER_add_now (&do_abort, NULL); + return; + } + event_mask = 0; + event_mask |= (1LL << GNUNET_TESTBED_ET_PEER_START); + event_mask |= (1LL << GNUNET_TESTBED_ET_PEER_STOP); + event_mask |= (1LL << GNUNET_TESTBED_ET_CONNECT); + event_mask |= (1LL << GNUNET_TESTBED_ET_DISCONNECT); + event_mask |= (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED); + mc = GNUNET_TESTBED_controller_connect (config, hosts[0], event_mask, + &controller_event_cb, NULL); + if (NULL == mc) + { + LOG (GNUNET_ERROR_TYPE_WARNING, + _("Unable to connect to master controller -- Check config\n")); + abort_task = GNUNET_SCHEDULER_add_now (&do_abort, NULL); + return; + } + if (num_hosts > 1) + register_hosts_task = GNUNET_SCHEDULER_add_now (®ister_hosts, NULL); + else + start_peers (); + abort_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, + &do_abort, NULL); +} + + /** * Main function that will be run by the scheduler. * * @param cls closure * @param args remaining command-line arguments * @param cfgfile name of the configuration file used (for saving, can be NULL!) - * @param cfg configuration + * @param config configuration */ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *config) { - uint64_t event_mask; unsigned int nhost; if (NULL == args[0]) { - FPRINTF (stderr, _("No hosts-file specified on command line\n")); + fprintf (stderr, _("No hosts-file specified on command line\n")); return; } if (0 == num_peers) @@ -182,31 +713,32 @@ run (void *cls, char *const *args, const char *cfgfile, num_hosts = GNUNET_TESTBED_hosts_load_from_file (args[0], &hosts); if (0 == num_hosts) { - FPRINTF (stderr, _("No hosts loaded\n")); + fprintf (stderr, _("No hosts loaded. Need atleast one host\n")); return; } for (nhost = 0; nhost < num_hosts; nhost++) { - if (GNUNET_YES != GNUNET_TESTBED_is_host_habitable (hosts[nhost])) + if (GNUNET_YES != GNUNET_TESTBED_is_host_habitable (hosts[nhost], config)) { - FPRINTF (stderr, _("Host %s cannot start testbed\n"), - GNUNET_TESTBED_host_get_hostname_ (hosts[nhost])); + fprintf (stderr, _("Host %s cannot start testbed\n"), + GNUNET_TESTBED_host_get_hostname_ (hosts[nhost])); break; } } if (num_hosts != nhost) { - GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); + fprintf (stderr, _("Exiting\n")); + shutdown_task = GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); return; } - peers = GNUNET_malloc (num_peers * sizeof (struct GNUNET_TESTBED_Peer *)); - event_mask = 0; - event_mask |= (1LL << GNUNET_TESTBED_ET_PEER_START); - event_mask |= (1LL << GNUNET_TESTBED_ET_PEER_STOP); - event_mask |= (1LL << GNUNET_TESTBED_ET_CONNECT); - event_mask |= (1LL << GNUNET_TESTBED_ET_DISCONNECT); - GNUNET_TESTBED_run (NULL, config, num_peers, event_mask, &controller_event_cb, - NULL, &master_task, NULL); + cfg = GNUNET_CONFIGURATION_dup (config); + mc_proc = + GNUNET_TESTBED_controller_start (GNUNET_TESTBED_host_get_hostname_ + (hosts[0]), + hosts[0], + cfg, + status_cb, + NULL); abort_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5), &do_abort, @@ -214,6 +746,41 @@ run (void *cls, char *const *args, const char *cfgfile, } +/** + * Set an option of type 'char *' from the command line. + * A pointer to this function should be passed as part of the + * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options + * of this type. It should be followed by a pointer to a value of + * type 'char *'. + * + * @param ctx command line processing context + * @param scls additional closure (will point to the 'char *', + * which will be allocated) + * @param option name of the option + * @param value actual value of the option (a string) + * @return GNUNET_OK to continue procesing; GNUNET_SYSERR to signal error + */ +int +set_topology (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, + void *scls, const char *option, const char *value) +{ + enum GNUNET_TESTBED_TopologyOption *val = scls; + + if (0 == strncasecmp ("CLIQUE", value, strlen ("CLIQUE"))) + { + *val = GNUNET_TESTBED_TOPOLOGY_CLIQUE; + return GNUNET_OK; + } + if (0 == strncasecmp ("RANDOM", value, strlen ("RANDOM"))) + { + *val = GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI; + return GNUNET_OK; + } + FPRINTF (stderr, "%s", _("Only `CLIQUE' and `RANDOM' are permitted.\n")); + return GNUNET_SYSERR; +} + + /** * Main function. * @@ -223,16 +790,25 @@ int main (int argc, char *const *argv) { static const struct GNUNET_GETOPT_CommandLineOption options[] = { - { 'n', "num-peers", "COUNT", - gettext_noop ("create COUNT number of peers"), - GNUNET_YES, &GNUNET_GETOPT_set_uint, &num_peers }, - { 'n', "num-peers", "COUNT", + { 'p', "num-peers", "COUNT", gettext_noop ("create COUNT number of peers"), GNUNET_YES, &GNUNET_GETOPT_set_uint, &num_peers }, + { 'n', "num-links", "COUNT", + gettext_noop ("create COUNT number of random links"), + GNUNET_YES, &GNUNET_GETOPT_set_uint, &num_links }, + { 'e', "num-errors", "COUNT", + gettext_noop ("tolerate COUNT number of continious timeout failures"), + GNUNET_YES, &GNUNET_GETOPT_set_uint, &num_cont_fails }, + { 't', "topology", "TOPOLOGY", + gettext_noop ("Try to acheive TOPOLOGY. This options takes either CLIQUE " + "or RANDOM. For CLIQUE the parameter -n is ignored. The " + "default is to acheive a random graph topology."), + GNUNET_YES, &set_topology, &topology }, GNUNET_GETOPT_OPTION_END }; int ret; + topology = GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI; if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv)) return 2; @@ -241,6 +817,7 @@ main (int argc, char *const *argv) GNUNET_PROGRAM_run (argc, argv, "gnunet-testbed-profiler [OPTIONS] hosts-file", _("Profiler for testbed"), options, &run, NULL); + GNUNET_free ((void*) argv); if (GNUNET_OK != ret) return ret; if (GNUNET_OK != result)