aboutsummaryrefslogtreecommitdiff
path: root/src/service/nse/gnunet-nse-profiler.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/service/nse/gnunet-nse-profiler.c')
-rw-r--r--src/service/nse/gnunet-nse-profiler.c921
1 files changed, 921 insertions, 0 deletions
diff --git a/src/service/nse/gnunet-nse-profiler.c b/src/service/nse/gnunet-nse-profiler.c
new file mode 100644
index 000000000..4b256bc52
--- /dev/null
+++ b/src/service/nse/gnunet-nse-profiler.c
@@ -0,0 +1,921 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2011, 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/**
21 * @file nse/gnunet-nse-profiler.c
22 *
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.
27 * @author Christian Grothoff
28 * @author Nathan Evans
29 * @author Sree Harsha Totakura
30 */
31
32#include "platform.h"
33#include "gnunet_testbed_service.h"
34#include "gnunet_nse_service.h"
35
36/**
37 * Generic loggins shorthand
38 */
39#define LOG(kind, ...) GNUNET_log (kind, __VA_ARGS__)
40
41/**
42 * Debug logging shorthand
43 */
44#define LOG_DEBUG(...) LOG (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
45
46
47/**
48 * Information we track for a peer in the testbed.
49 */
50struct NSEPeer
51{
52 /**
53 * Prev reference in DLL.
54 */
55 struct NSEPeer *prev;
56
57 /**
58 * Next reference in DLL.
59 */
60 struct NSEPeer *next;
61
62 /**
63 * Handle with testbed.
64 */
65 struct GNUNET_TESTBED_Peer *daemon;
66
67 /**
68 * Testbed operation to connect to NSE service.
69 */
70 struct GNUNET_TESTBED_Operation *nse_op;
71
72 /**
73 * Testbed operation to connect to statistics service
74 */
75 struct GNUNET_TESTBED_Operation *stat_op;
76
77 /**
78 * Handle to the statistics service
79 */
80 struct GNUNET_STATISTICS_Handle *sh;
81};
82
83
84/**
85 * Operation map entry
86 */
87struct OpListEntry
88{
89 /**
90 * DLL next ptr
91 */
92 struct OpListEntry *next;
93
94 /**
95 * DLL prev ptr
96 */
97 struct OpListEntry *prev;
98
99 /**
100 * The testbed operation
101 */
102 struct GNUNET_TESTBED_Operation *op;
103
104 /**
105 * Depending on whether we start or stop NSE service at the peer set this to 1
106 * or -1
107 */
108 int delta;
109};
110
111
112/**
113 * Head of DLL of peers we monitor closely.
114 */
115static struct NSEPeer *peer_head;
116
117/**
118 * Tail of DLL of peers we monitor closely.
119 */
120static struct NSEPeer *peer_tail;
121
122/**
123 * Return value from 'main' (0 == success)
124 */
125static int ok;
126
127/**
128 * Be verbose (configuration option)
129 */
130static unsigned int verbose;
131
132/**
133 * Name of the file with the hosts to run the test over (configuration option)
134 */
135static char *hosts_file;
136
137/**
138 * Maximum number of peers in the test.
139 */
140static unsigned int num_peers;
141
142/**
143 * Total number of rounds to execute.
144 */
145static unsigned int num_rounds;
146
147/**
148 * Current round we are in.
149 */
150static unsigned int current_round;
151
152/**
153 * Array of size 'num_rounds' with the requested number of peers in the given round.
154 */
155static unsigned int *num_peers_in_round;
156
157/**
158 * How many peers are running right now?
159 */
160static unsigned int peers_running;
161
162/**
163 * Specification for the numbers of peers to have in each round.
164 */
165static char *num_peer_spec;
166
167/**
168 * Handles to all of the running peers.
169 */
170static struct GNUNET_TESTBED_Peer **daemons;
171
172/**
173 * Global configuration file
174 */
175static struct GNUNET_CONFIGURATION_Handle *testing_cfg;
176
177/**
178 * Maximum number of connections to NSE services.
179 */
180static unsigned int connection_limit;
181
182/**
183 * Total number of connections in the whole network.
184 */
185static unsigned int total_connections;
186
187/**
188 * File to report results to.
189 */
190static struct GNUNET_DISK_FileHandle *output_file;
191
192/**
193 * Filename to log results to.
194 */
195static char *output_filename;
196
197/**
198 * File to log connection info, statistics to.
199 */
200static struct GNUNET_DISK_FileHandle *data_file;
201
202/**
203 * Filename to log connection info, statistics to.
204 */
205static char *data_filename;
206
207/**
208 * How long to wait before triggering next round?
209 * Default: 60 s.
210 */
211static struct GNUNET_TIME_Relative wait_time = { 60 * 1000 };
212
213/**
214 * DLL head for operation list
215 */
216static struct OpListEntry *oplist_head;
217
218/**
219 * DLL tail for operation list
220 */
221static struct OpListEntry *oplist_tail;
222
223/**
224 * Task running each round of the experiment.
225 */
226static struct GNUNET_SCHEDULER_Task *round_task;
227
228
229/**
230 * Clean up all of the monitoring connections to NSE and
231 * STATISTICS that we keep to selected peers.
232 */
233static void
234close_monitor_connections ()
235{
236 struct NSEPeer *pos;
237 struct OpListEntry *oplist_entry;
238
239 while (NULL != (pos = peer_head))
240 {
241 if (NULL != pos->nse_op)
242 GNUNET_TESTBED_operation_done (pos->nse_op);
243 if (NULL != pos->stat_op)
244 GNUNET_TESTBED_operation_done (pos->stat_op);
245 GNUNET_CONTAINER_DLL_remove (peer_head, peer_tail, pos);
246 GNUNET_free (pos);
247 }
248 while (NULL != (oplist_entry = oplist_head))
249 {
250 GNUNET_CONTAINER_DLL_remove (oplist_head, oplist_tail, oplist_entry);
251 GNUNET_TESTBED_operation_done (oplist_entry->op);
252 GNUNET_free (oplist_entry);
253 }
254}
255
256
257/**
258 * Task run on shutdown; cleans up everything.
259 *
260 * @param cls unused
261 */
262static void
263shutdown_task (void *cls)
264{
265 LOG_DEBUG ("Ending test.\n");
266 close_monitor_connections ();
267 if (NULL != round_task)
268 {
269 GNUNET_SCHEDULER_cancel (round_task);
270 round_task = NULL;
271 }
272 if (NULL != data_file)
273 {
274 GNUNET_DISK_file_close (data_file);
275 data_file = NULL;
276 }
277 if (NULL != output_file)
278 {
279 GNUNET_DISK_file_close (output_file);
280 output_file = NULL;
281 }
282 if (NULL != testing_cfg)
283 {
284 GNUNET_CONFIGURATION_destroy (testing_cfg);
285 testing_cfg = NULL;
286 }
287}
288
289
290/**
291 * Callback to call when network size estimate is updated.
292 *
293 * @param cls closure with the 'struct NSEPeer' providing the update
294 * @param timestamp server timestamp
295 * @param estimate the value of the current network size estimate
296 * @param std_dev standard deviation (rounded down to nearest integer)
297 * of the size estimation values seen
298 */
299static void
300handle_estimate (void *cls,
301 struct GNUNET_TIME_Absolute timestamp,
302 double estimate,
303 double std_dev)
304{
305 struct NSEPeer *peer = cls;
306 char output_buffer[512];
307 size_t size;
308
309 if (NULL == output_file)
310 {
311 fprintf (stderr,
312 "Received network size estimate from peer %p. Size: %f std.dev. %f\n",
313 peer,
314 estimate,
315 std_dev);
316 return;
317 }
318 size = GNUNET_snprintf (output_buffer,
319 sizeof(output_buffer),
320 "%p %u %llu %f %f %f\n",
321 peer,
322 peers_running,
323 (unsigned long long) timestamp.abs_value_us,
324 GNUNET_NSE_log_estimate_to_n (estimate),
325 estimate,
326 std_dev);
327 if (size != GNUNET_DISK_file_write (output_file, output_buffer, size))
328 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Unable to write to file!\n");
329}
330
331
332/**
333 * Adapter function called to establish a connection to
334 * NSE service.
335 *
336 * @param cls closure (the 'struct NSEPeer')
337 * @param cfg configuration of the peer to connect to; will be available until
338 * GNUNET_TESTBED_operation_done() is called on the operation returned
339 * from GNUNET_TESTBED_service_connect()
340 * @return service handle to return in 'op_result', NULL on error
341 */
342static void *
343nse_connect_adapter (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg)
344{
345 struct NSEPeer *current_peer = cls;
346
347 return GNUNET_NSE_connect (cfg, &handle_estimate, current_peer);
348}
349
350
351/**
352 * Adapter function called to destroy a connection to
353 * NSE service.
354 *
355 * @param cls closure
356 * @param op_result service handle returned from the connect adapter
357 */
358static void
359nse_disconnect_adapter (void *cls, void *op_result)
360{
361 GNUNET_NSE_disconnect (op_result);
362}
363
364
365/**
366 * Callback function to process statistic values.
367 *
368 * @param cls `struct NSEPeer`
369 * @param subsystem name of subsystem that created the statistic
370 * @param name the name of the datum
371 * @param value the current value
372 * @param is_persistent #GNUNET_YES if the value is persistent, #GNUNET_NO if not
373 * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration
374 */
375static int
376stat_iterator (void *cls,
377 const char *subsystem,
378 const char *name,
379 uint64_t value,
380 int is_persistent)
381{
382 char *output_buffer;
383 struct GNUNET_TIME_Absolute now;
384 int size;
385 unsigned int flag;
386
387 GNUNET_assert (NULL != data_file);
388 now = GNUNET_TIME_absolute_get ();
389 flag = strcasecmp (subsystem, "core");
390 if (0 != flag)
391 flag = 1;
392 size = GNUNET_asprintf (&output_buffer,
393 "%llu %llu %u\n",
394 (unsigned long long) now.abs_value_us / 1000LL / 1000LL,
395 (unsigned long long) value,
396 flag);
397 if (0 > size)
398 {
399 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Error formatting output buffer.\n");
400 GNUNET_free (output_buffer);
401 return GNUNET_SYSERR;
402 }
403 if (size != GNUNET_DISK_file_write (data_file, output_buffer, (size_t) size))
404 {
405 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Unable to write to file!\n");
406 GNUNET_free (output_buffer);
407 return GNUNET_SYSERR;
408 }
409 GNUNET_free (output_buffer);
410 return GNUNET_OK;
411}
412
413
414/**
415 * Called to open a connection to the peer's statistics
416 *
417 * @param cls peer context
418 * @param cfg configuration of the peer to connect to; will be available until
419 * GNUNET_TESTBED_operation_done() is called on the operation returned
420 * from GNUNET_TESTBED_service_connect()
421 * @return service handle to return in 'op_result', NULL on error
422 */
423static void *
424stat_connect_adapter (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg)
425{
426 struct NSEPeer *peer = cls;
427
428 peer->sh = GNUNET_STATISTICS_create ("nse-profiler", cfg);
429 return peer->sh;
430}
431
432
433/**
434 * Called to disconnect from peer's statistics service
435 *
436 * @param cls peer context
437 * @param op_result service handle returned from the connect adapter
438 */
439static void
440stat_disconnect_adapter (void *cls, void *op_result)
441{
442 struct NSEPeer *peer = cls;
443
444 GNUNET_break (GNUNET_OK ==
445 GNUNET_STATISTICS_watch_cancel (peer->sh,
446 "core",
447 "# peers connected",
448 stat_iterator,
449 peer));
450 GNUNET_break (GNUNET_OK ==
451 GNUNET_STATISTICS_watch_cancel (peer->sh,
452 "nse",
453 "# peers connected",
454 stat_iterator,
455 peer));
456 GNUNET_STATISTICS_destroy (op_result, GNUNET_NO);
457 peer->sh = NULL;
458}
459
460
461/**
462 * Called after successfully opening a connection to a peer's statistics
463 * service; we register statistics monitoring for CORE and NSE here.
464 *
465 * @param cls the callback closure from functions generating an operation
466 * @param op the operation that has been finished
467 * @param ca_result the service handle returned from GNUNET_TESTBED_ConnectAdapter()
468 * @param emsg error message in case the operation has failed; will be NULL if
469 * operation has executed successfully.
470 */
471static void
472stat_comp_cb (void *cls,
473 struct GNUNET_TESTBED_Operation *op,
474 void *ca_result,
475 const char *emsg)
476{
477 struct GNUNET_STATISTICS_Handle *sh = ca_result;
478 struct NSEPeer *peer = cls;
479
480 if (NULL != emsg)
481 {
482 GNUNET_break (0);
483 return;
484 }
485 GNUNET_break (GNUNET_OK == GNUNET_STATISTICS_watch (sh,
486 "core",
487 "# peers connected",
488 stat_iterator,
489 peer));
490 GNUNET_break (GNUNET_OK == GNUNET_STATISTICS_watch (sh,
491 "nse",
492 "# peers connected",
493 stat_iterator,
494 peer));
495}
496
497
498/**
499 * Task run to connect to the NSE and statistics services to a subset of
500 * all of the running peers.
501 */
502static void
503connect_nse_service ()
504{
505 struct NSEPeer *current_peer;
506 unsigned int i;
507 unsigned int connections;
508
509 if (0 == connection_limit)
510 return;
511 LOG_DEBUG ("Connecting to nse service of peers\n");
512 connections = 0;
513 for (i = 0; i < num_peers_in_round[current_round]; i++)
514 {
515 if ((num_peers_in_round[current_round] > connection_limit) &&
516 (0 != (i % (num_peers_in_round[current_round] / connection_limit))))
517 continue;
518 LOG_DEBUG ("Connecting to nse service of peer %d\n", i);
519 current_peer = GNUNET_new (struct NSEPeer);
520 current_peer->daemon = daemons[i];
521 current_peer->nse_op =
522 GNUNET_TESTBED_service_connect (NULL,
523 current_peer->daemon,
524 "nse",
525 NULL,
526 NULL,
527 &nse_connect_adapter,
528 &nse_disconnect_adapter,
529 current_peer);
530 if (NULL != data_file)
531 current_peer->stat_op =
532 GNUNET_TESTBED_service_connect (NULL,
533 current_peer->daemon,
534 "statistics",
535 stat_comp_cb,
536 current_peer,
537 &stat_connect_adapter,
538 &stat_disconnect_adapter,
539 current_peer);
540 GNUNET_CONTAINER_DLL_insert (peer_head, peer_tail, current_peer);
541 if (++connections == connection_limit)
542 break;
543 }
544}
545
546
547/**
548 * Task that starts/stops peers to move to the next round.
549 *
550 * @param cls NULL, unused
551 */
552static void
553next_round (void *cls);
554
555
556/**
557 * We're at the end of a round. Stop monitoring, write total
558 * number of connections to log and get full stats. Then trigger
559 * the next round.
560 *
561 * @param cls unused, NULL
562 */
563static void
564finish_round (void *cls)
565{
566 LOG (GNUNET_ERROR_TYPE_INFO, "Have %u connections\n", total_connections);
567 close_monitor_connections ();
568 round_task = GNUNET_SCHEDULER_add_now (&next_round, NULL);
569}
570
571
572/**
573 * We have reached the desired number of peers for the current round.
574 * Run it (by connecting and monitoring a few peers and waiting the
575 * specified delay before finishing the round).
576 */
577static void
578run_round ()
579{
580 LOG_DEBUG ("Running round %u\n", current_round);
581 connect_nse_service ();
582 GNUNET_SCHEDULER_add_delayed (wait_time, &finish_round, NULL);
583}
584
585
586/**
587 * Creates an oplist entry and adds it to the oplist DLL
588 */
589static struct OpListEntry *
590make_oplist_entry ()
591{
592 struct OpListEntry *entry;
593
594 entry = GNUNET_new (struct OpListEntry);
595 GNUNET_CONTAINER_DLL_insert_tail (oplist_head, oplist_tail, entry);
596 return entry;
597}
598
599
600/**
601 * Callback to be called when NSE service is started or stopped at peers
602 *
603 * @param cls NULL
604 * @param op the operation handle
605 * @param emsg NULL on success; otherwise an error description
606 */
607static void
608manage_service_cb (void *cls,
609 struct GNUNET_TESTBED_Operation *op,
610 const char *emsg)
611{
612 struct OpListEntry *entry = cls;
613
614 GNUNET_TESTBED_operation_done (entry->op);
615 if (NULL != emsg)
616 {
617 LOG (GNUNET_ERROR_TYPE_ERROR, "Failed to start/stop NSE at a peer\n");
618 GNUNET_SCHEDULER_shutdown ();
619 return;
620 }
621 GNUNET_assert (0 != entry->delta);
622 peers_running += entry->delta;
623 GNUNET_CONTAINER_DLL_remove (oplist_head, oplist_tail, entry);
624 GNUNET_free (entry);
625 if (num_peers_in_round[current_round] == peers_running)
626 run_round ();
627}
628
629
630/**
631 * Adjust the number of running peers to match the required number of running
632 * peers for the round
633 */
634static void
635adjust_running_peers ()
636{
637 struct OpListEntry *entry;
638 unsigned int i;
639
640 /* start peers if we have too few */
641 for (i = peers_running; i < num_peers_in_round[current_round]; i++)
642 {
643 entry = make_oplist_entry ();
644 entry->delta = 1;
645 entry->op = GNUNET_TESTBED_peer_manage_service (NULL,
646 daemons[i],
647 "nse",
648 &manage_service_cb,
649 entry,
650 1);
651 }
652 /* stop peers if we have too many */
653 for (i = num_peers_in_round[current_round]; i < peers_running; i++)
654 {
655 entry = make_oplist_entry ();
656 entry->delta = -1;
657 entry->op = GNUNET_TESTBED_peer_manage_service (NULL,
658 daemons[i],
659 "nse",
660 &manage_service_cb,
661 entry,
662 0);
663 }
664}
665
666
667/**
668 * Task run at the end of a round. Disconnect from all monitored
669 * peers; then get statistics from *all* peers.
670 *
671 * @param cls NULL, unused
672 */
673static void
674next_round (void *cls)
675{
676 round_task = NULL;
677 LOG_DEBUG ("Disconnecting nse service of peers\n");
678 current_round++;
679 if (current_round == num_rounds)
680 {
681 /* this was the last round, terminate */
682 ok = 0;
683 GNUNET_SCHEDULER_shutdown ();
684 return;
685 }
686 if (num_peers_in_round[current_round] == peers_running)
687 {
688 /* no need to churn, just run next round */
689 run_round ();
690 return;
691 }
692 adjust_running_peers ();
693}
694
695
696/**
697 * Function that will be called whenever something in the
698 * testbed changes.
699 *
700 * @param cls closure, NULL
701 * @param event information on what is happening
702 */
703static void
704master_controller_cb (void *cls,
705 const struct GNUNET_TESTBED_EventInformation *event)
706{
707 switch (event->type)
708 {
709 case GNUNET_TESTBED_ET_CONNECT:
710 total_connections++;
711 break;
712
713 case GNUNET_TESTBED_ET_DISCONNECT:
714 total_connections--;
715 break;
716
717 default:
718 break;
719 }
720}
721
722
723/**
724 * Signature of a main function for a testcase.
725 *
726 * @param cls NULL
727 * @param h the run handle
728 * @param num_peers_ number of peers in 'peers'
729 * @param peers handle to peers run in the testbed. NULL upon timeout (see
730 * GNUNET_TESTBED_test_run()).
731 * @param links_succeeded the number of overlay link connection attempts that
732 * succeeded
733 * @param links_failed the number of overlay link connection attempts that
734 * failed
735 */
736static void
737test_master (void *cls,
738 struct GNUNET_TESTBED_RunHandle *h,
739 unsigned int num_peers_,
740 struct GNUNET_TESTBED_Peer **peers,
741 unsigned int links_succeeded,
742 unsigned int links_failed)
743{
744 if (NULL == peers)
745 {
746 GNUNET_SCHEDULER_shutdown ();
747 return;
748 }
749 daemons = peers;
750 GNUNET_break (num_peers_ == num_peers);
751 peers_running = num_peers;
752 if (num_peers_in_round[current_round] == peers_running)
753 {
754 /* no need to churn, just run the starting round */
755 run_round ();
756 return;
757 }
758 adjust_running_peers ();
759}
760
761
762/**
763 * Actual main function that runs the emulation.
764 *
765 * @param cls unused
766 * @param args remaining args, unused
767 * @param cfgfile name of the configuration
768 * @param cfg configuration handle
769 */
770static void
771run (void *cls,
772 char *const *args,
773 const char *cfgfile,
774 const struct GNUNET_CONFIGURATION_Handle *cfg)
775{
776 char *tok;
777 uint64_t event_mask;
778 unsigned int num;
779
780 ok = 1;
781 testing_cfg = GNUNET_CONFIGURATION_dup (cfg);
782 LOG_DEBUG ("Starting daemons.\n");
783 if (NULL == num_peer_spec)
784 {
785 fprintf (stderr, "You need to specify the number of peers to run\n");
786 return;
787 }
788 for (tok = strtok (num_peer_spec, ","); NULL != tok; tok = strtok (NULL, ","))
789 {
790 if (1 != sscanf (tok, "%u", &num))
791 {
792 fprintf (stderr, "You need to specify numbers, not `%s'\n", tok);
793 return;
794 }
795 if (0 == num)
796 {
797 fprintf (stderr, "Refusing to run a round with 0 peers\n");
798 return;
799 }
800 GNUNET_array_append (num_peers_in_round, num_rounds, num);
801 num_peers = GNUNET_MAX (num_peers, num);
802 }
803 if (0 == num_peers)
804 {
805 fprintf (stderr, "Refusing to run a testbed with no rounds\n");
806 return;
807 }
808 if ((NULL != data_filename) &&
809 (NULL ==
810 (data_file = GNUNET_DISK_file_open (data_filename,
811 GNUNET_DISK_OPEN_READWRITE
812 | GNUNET_DISK_OPEN_TRUNCATE
813 | GNUNET_DISK_OPEN_CREATE,
814 GNUNET_DISK_PERM_USER_READ
815 | GNUNET_DISK_PERM_USER_WRITE))))
816 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", data_filename);
817
818 if ((NULL != output_filename) &&
819 (NULL ==
820 (output_file = GNUNET_DISK_file_open (output_filename,
821 GNUNET_DISK_OPEN_READWRITE
822 | GNUNET_DISK_OPEN_CREATE,
823 GNUNET_DISK_PERM_USER_READ
824 | GNUNET_DISK_PERM_USER_WRITE))))
825 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", output_filename);
826 event_mask = 0LL;
827 event_mask |= (1LL << GNUNET_TESTBED_ET_PEER_START);
828 event_mask |= (1LL << GNUNET_TESTBED_ET_PEER_STOP);
829 event_mask |= (1LL << GNUNET_TESTBED_ET_CONNECT);
830 event_mask |= (1LL << GNUNET_TESTBED_ET_DISCONNECT);
831 GNUNET_TESTBED_run (hosts_file,
832 cfg,
833 num_peers,
834 event_mask,
835 master_controller_cb,
836 NULL, /* master_controller_cb cls */
837 &test_master,
838 NULL); /* test_master cls */
839 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
840}
841
842
843/**
844 * Main function.
845 *
846 * @return 0 on success
847 */
848int
849main (int argc, char *const *argv)
850{
851 struct GNUNET_GETOPT_CommandLineOption options[] =
852 { GNUNET_GETOPT_option_uint (
853 'C',
854 "connections",
855 "COUNT",
856 gettext_noop (
857 "limit to the number of connections to NSE services, 0 for none"),
858 &connection_limit),
859 GNUNET_GETOPT_option_string (
860 'd',
861 "details",
862 "FILENAME",
863 gettext_noop (
864 "name of the file for writing connection information and statistics"),
865 &data_filename),
866
867 GNUNET_GETOPT_option_string (
868 'H',
869 "hosts",
870 "FILENAME",
871 gettext_noop (
872 "name of the file with the login information for the testbed"),
873 &hosts_file),
874
875 GNUNET_GETOPT_option_string (
876 'o',
877 "output",
878 "FILENAME",
879 gettext_noop ("name of the file for writing the main results"),
880 &output_filename),
881
882
883 GNUNET_GETOPT_option_string (
884 'p',
885 "peers",
886 "NETWORKSIZESPEC",
887 gettext_noop (
888 "Number of peers to run in each round, separated by commas"),
889 &num_peer_spec),
890
891 GNUNET_GETOPT_option_increment_uint (
892 'V',
893 "verbose",
894 gettext_noop ("be verbose (print progress information)"),
895 &verbose),
896
897 GNUNET_GETOPT_option_relative_time ('w',
898 "wait",
899 "DELAY",
900 gettext_noop ("delay between rounds"),
901 &wait_time),
902 GNUNET_GETOPT_OPTION_END };
903
904 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
905 return 2;
906 if (
907 GNUNET_OK !=
908 GNUNET_PROGRAM_run (argc,
909 argv,
910 "nse-profiler",
911 gettext_noop (
912 "Measure quality and performance of the NSE service."),
913 options,
914 &run,
915 NULL))
916 ok = 1;
917 return ok;
918}
919
920
921/* end of nse-profiler.c */