aboutsummaryrefslogtreecommitdiff
path: root/src/statistics/gnunet-statistics.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/statistics/gnunet-statistics.c')
-rw-r--r--src/statistics/gnunet-statistics.c588
1 files changed, 513 insertions, 75 deletions
diff --git a/src/statistics/gnunet-statistics.c b/src/statistics/gnunet-statistics.c
index 159afda53..a92faa3d7 100644
--- a/src/statistics/gnunet-statistics.c
+++ b/src/statistics/gnunet-statistics.c
@@ -2,20 +2,18 @@
2 This file is part of GNUnet. 2 This file is part of GNUnet.
3 Copyright (C) 2001, 2002, 2004-2007, 2009, 2016 GNUnet e.V. 3 Copyright (C) 2001, 2002, 2004-2007, 2009, 2016 GNUnet e.V.
4 4
5 GNUnet is free software; you can redistribute it and/or modify 5 GNUnet is free software: you can redistribute it and/or modify it
6 it under the terms of the GNU General Public License as published 6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation; either version 3, or (at your 7 by the Free Software Foundation, either version 3 of the License,
8 option) any later version. 8 or (at your option) any later version.
9 9
10 GNUnet is distributed in the hope that it will be useful, but 10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of 11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details. 13 Affero General Public License for more details.
14 14
15 You should have received a copy of the GNU General Public License 15 You should have received a copy of the GNU Affero General Public License
16 along with GNUnet; see the file COPYING. If not, write to the 16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/ 17*/
20 18
21/** 19/**
@@ -41,6 +39,11 @@ static int ret;
41static char *subsystem; 39static char *subsystem;
42 40
43/** 41/**
42 * The path of the testbed data.
43 */
44static char *path_testbed;
45
46/**
44 * Set to the specific stat value that we are after (or NULL for all). 47 * Set to the specific stat value that we are after (or NULL for all).
45 */ 48 */
46static char *name; 49static char *name;
@@ -61,6 +64,11 @@ static int watch;
61static int quiet; 64static int quiet;
62 65
63/** 66/**
67 * @brief Separator string for csv.
68 */
69static char *csv_separator;
70
71/**
64 * Remote host 72 * Remote host
65 */ 73 */
66static char *remote_host; 74static char *remote_host;
@@ -81,10 +89,169 @@ static unsigned long long set_val;
81static int set_value; 89static int set_value;
82 90
83/** 91/**
84 * Handle for pending GET operation. 92 * @brief Representation of all (testbed) nodes.
93 */
94static struct Node {
95 /**
96 * @brief Index of the node in this array.
97 */
98 unsigned index_node;
99
100 /**
101 * @brief Configuration handle for this node
102 */
103 struct GNUNET_CONFIGURATION_Handle *conf;
104
105 /**
106 * Handle for pending GET operation.
107 */
108 struct GNUNET_STATISTICS_GetHandle *gh;
109
110 /**
111 * @brief Statistics handle nodes.
112 */
113 struct GNUNET_STATISTICS_Handle *handle;
114 /**
115 * @brief Identifier for shutdown task for this node.
116 */
117 struct GNUNET_SCHEDULER_Task *shutdown_task;
118} *nodes;
119
120/**
121 * @brief Number of configurations of all (testbed) nodes.
122 */
123static unsigned num_nodes;
124
125/**
126 * @brief Set of values for a combination of subsystem and name.
127 */
128struct ValueSet
129{
130 /**
131 * @brief Subsystem of the valueset.
132 */
133 char *subsystem;
134
135 /**
136 * @brief Name of the valueset.
137 */
138 char *name;
139
140 /**
141 * @brief The values.
142 */
143 uint64_t *values;
144
145 /**
146 * @brief Persistence of the values.
147 */
148 int is_persistent;
149};
150
151/**
152 * @brief Collection of all values (represented with #ValueSet).
153 */
154static struct GNUNET_CONTAINER_MultiHashMap *values;
155
156/**
157 * @brief Number of nodes that have their values ready.
158 */
159static int num_nodes_ready;
160
161/**
162 * @brief Number of nodes that have their values ready.
163 */
164static int num_nodes_ready_shutdown;
165
166/**
167 * @brief Create a new #ValueSet
168 *
169 * @param subsystem Subsystem of the valueset.
170 * @param name Name of the valueset.
171 * @param num_values Number of values in valueset - number of peers.
172 * @param is_persistent Persistence status of values.
173 *
174 * @return Newly allocated #ValueSet.
85 */ 175 */
86static struct GNUNET_STATISTICS_GetHandle *gh; 176static struct ValueSet *
177new_value_set (const char *subsystem,
178 const char *name,
179 unsigned num_values,
180 int is_persistent)
181{
182 struct ValueSet *value_set;
183
184 value_set = GNUNET_new (struct ValueSet);
185 value_set->subsystem = GNUNET_strdup (subsystem);
186 value_set->name = GNUNET_strdup (name);
187 value_set->values = GNUNET_new_array (num_values, uint64_t);
188 value_set->is_persistent = persistent;
189 return value_set;
190}
87 191
192/**
193 * @brief Print the (collected) values.
194 *
195 * Implements #GNUNET_CONTAINER_HashMapIterator.
196 *
197 * @param cls Closure - unused
198 * @param key #GNUNET_HashCode key of #GNUNET_CONTAINER_MultiHashMap iterator -
199 * unused
200 * @param value Values represented as #ValueSet.
201 *
202 * @return GNUNET_YES - continue iteration.
203 */
204static int
205printer (void *cls,
206 const struct GNUNET_HashCode *key,
207 void *value)
208{
209 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get();
210 const char *now_str;
211 struct ValueSet *value_set = value;
212
213 if (quiet == GNUNET_NO)
214 {
215 if (GNUNET_YES == watch)
216 {
217 now_str = GNUNET_STRINGS_absolute_time_to_string (now);
218 FPRINTF (stdout,
219 "%24s%s %s%s%12s%s %50s%s ",
220 now_str,
221 csv_separator,
222 value_set->is_persistent ? "!" : " ",
223 csv_separator,
224 value_set->subsystem,
225 csv_separator,
226 _(value_set->name),
227 (0 == strlen (csv_separator) ? ":": csv_separator));
228 }
229 else
230 {
231 FPRINTF (stdout,
232 "%s%s%12s%s %50s%s ",
233 value_set->is_persistent ? "!" : " ",
234 csv_separator,
235 value_set->subsystem,
236 csv_separator,
237 _(value_set->name),
238 (0 == strlen (csv_separator) ? ":": csv_separator));
239 }
240 }
241 for (unsigned i = 0; i < num_nodes; i++)
242 {
243 FPRINTF (stdout,
244 "%16llu%s",
245 (unsigned long long) value_set->values[i],
246 csv_separator);
247 }
248 FPRINTF (stdout, "\n");
249 GNUNET_free (value_set->subsystem);
250 GNUNET_free (value_set->name);
251 GNUNET_free (value_set->values);
252 GNUNET_free (value_set);
253 return GNUNET_YES;
254}
88 255
89/** 256/**
90 * Callback function to process statistic values. 257 * Callback function to process statistic values.
@@ -97,11 +264,11 @@ static struct GNUNET_STATISTICS_GetHandle *gh;
97 * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration 264 * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration
98 */ 265 */
99static int 266static int
100printer (void *cls, 267printer_watch (void *cls,
101 const char *subsystem, 268 const char *subsystem,
102 const char *name, 269 const char *name,
103 uint64_t value, 270 uint64_t value,
104 int is_persistent) 271 int is_persistent)
105{ 272{
106 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get(); 273 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get();
107 const char *now_str; 274 const char *now_str;
@@ -112,21 +279,28 @@ printer (void *cls,
112 { 279 {
113 now_str = GNUNET_STRINGS_absolute_time_to_string (now); 280 now_str = GNUNET_STRINGS_absolute_time_to_string (now);
114 FPRINTF (stdout, 281 FPRINTF (stdout,
115 "%24s %s%12s %50s: %16llu\n", 282 "%24s%s %s%s%12s%s %50s%s %16llu\n",
116 now_str, 283 now_str,
284 csv_separator,
117 is_persistent ? "!" : " ", 285 is_persistent ? "!" : " ",
286 csv_separator,
118 subsystem, 287 subsystem,
119 _(name), 288 csv_separator,
120 (unsigned long long) value); 289 _(name),
290 (0 == strlen (csv_separator) ? ":": csv_separator),
291 (unsigned long long) value);
121 } 292 }
122 else 293 else
123 { 294 {
124 FPRINTF (stdout, 295 FPRINTF (stdout,
125 "%s%12s %50s: %16llu\n", 296 "%s%s%12s%s %50s%s %16llu\n",
126 is_persistent ? "!" : " ", 297 is_persistent ? "!" : " ",
298 csv_separator,
127 subsystem, 299 subsystem,
128 _(name), 300 csv_separator,
129 (unsigned long long) value); 301 _(name),
302 (0 == strlen (csv_separator) ? ":": csv_separator),
303 (unsigned long long) value);
130 } 304 }
131 } 305 }
132 else 306 else
@@ -137,6 +311,111 @@ printer (void *cls,
137 return GNUNET_OK; 311 return GNUNET_OK;
138} 312}
139 313
314/**
315 * @brief Clean all data structures related to given node.
316 *
317 * Also clears global structures if we are the last node to clean.
318 *
319 * @param cls the index of the node
320 */
321static void
322clean_node (void *cls)
323{
324 const unsigned index_node = *(unsigned *) cls;
325 struct GNUNET_STATISTICS_Handle *h;
326 struct GNUNET_STATISTICS_GetHandle *gh;
327
328 if ( (NULL != path_testbed) && /* were issued with -t <testbed-path> option */
329 (NULL != nodes[index_node].conf) )
330 {
331 GNUNET_CONFIGURATION_destroy (nodes[index_node].conf);
332 nodes[index_node].conf = NULL;
333 }
334
335 h = nodes[index_node].handle;
336 gh = nodes[index_node].gh;
337
338 if (NULL != gh)
339 {
340 GNUNET_STATISTICS_get_cancel (gh);
341 gh = NULL;
342 }
343 if (GNUNET_YES == watch)
344 {
345 GNUNET_assert (GNUNET_OK ==
346 GNUNET_STATISTICS_watch_cancel (h,
347 subsystem,
348 name,
349 &printer_watch,
350 &nodes[index_node].index_node));
351 }
352
353 if (NULL != h)
354 {
355 GNUNET_STATISTICS_destroy (h, GNUNET_NO);
356 h = NULL;
357 }
358
359 num_nodes_ready_shutdown++;
360 if (num_nodes == num_nodes_ready_shutdown)
361 {
362 GNUNET_array_grow (nodes, num_nodes, 0);
363 GNUNET_CONTAINER_multihashmap_destroy (values);
364 }
365}
366
367/**
368 * @brief Print and shutdown
369 *
370 * @param cls unused
371 */
372static void
373print_finish (void *cls)
374{
375 GNUNET_CONTAINER_multihashmap_iterate (values, printer, NULL);
376 GNUNET_SCHEDULER_shutdown();
377}
378
379/**
380 * @brief Called once all statistic values are available.
381 *
382 * Implements #GNUNET_STATISTICS_Callback
383 *
384 * @param cls Closure - The index of the node.
385 * @param succes Whether statistics were obtained successfully.
386 */
387static void
388continuation_print (void *cls,
389 int success)
390{
391 const unsigned index_node = *(unsigned *) cls;
392
393 nodes[index_node].gh = NULL;
394 if (GNUNET_OK != success)
395 {
396 if (NULL == remote_host)
397 FPRINTF (stderr,
398 "%s",
399 _("Failed to obtain statistics.\n"));
400 else
401 FPRINTF (stderr,
402 _("Failed to obtain statistics from host `%s:%llu'\n"),
403 remote_host,
404 remote_port);
405 ret = 1;
406 }
407 if (NULL != nodes[index_node].shutdown_task)
408 {
409 GNUNET_SCHEDULER_cancel (nodes[index_node].shutdown_task);
410 nodes[index_node].shutdown_task = NULL;
411 }
412 GNUNET_SCHEDULER_add_now (clean_node, &nodes[index_node].index_node);
413 num_nodes_ready++;
414 if (num_nodes_ready == num_nodes)
415 {
416 GNUNET_SCHEDULER_add_now (print_finish, NULL);
417 }
418}
140 419
141/** 420/**
142 * Function called last by the statistics code. 421 * Function called last by the statistics code.
@@ -149,7 +428,10 @@ static void
149cleanup (void *cls, 428cleanup (void *cls,
150 int success) 429 int success)
151{ 430{
152 gh = NULL; 431 for (unsigned i = 0; i < num_nodes; i++)
432 {
433 nodes[i].gh = NULL;
434 }
153 if (GNUNET_OK != success) 435 if (GNUNET_OK != success)
154 { 436 {
155 if (NULL == remote_host) 437 if (NULL == remote_host)
@@ -166,39 +448,56 @@ cleanup (void *cls,
166 GNUNET_SCHEDULER_shutdown (); 448 GNUNET_SCHEDULER_shutdown ();
167} 449}
168 450
169
170/** 451/**
171 * Function run on shutdown to clean up. 452 * @brief Iterate over statistics values and store them in #values.
453 * They will be printed once all are available.
454 *
455 * @param cls Cosure - Node index.
456 * @param subsystem Subsystem of the value.
457 * @param name Name of the value.
458 * @param value Value itself.
459 * @param is_persistent Persistence.
172 * 460 *
173 * @param cls the statistics handle 461 * @return GNUNET_OK - continue.
174 */ 462 */
175static void 463static int
176shutdown_task (void *cls) 464collector (void *cls,
465 const char *subsystem,
466 const char *name,
467 uint64_t value,
468 int is_persistent)
177{ 469{
178 struct GNUNET_STATISTICS_Handle *h = cls; 470 const unsigned index_node = *(unsigned *) cls;
179 471 struct GNUNET_HashCode *key;
180 if (NULL == h) 472 struct GNUNET_HashCode hc;
181 return; 473 char *subsys_name;
182 if (NULL != gh) 474 unsigned len_subsys_name;
475 struct ValueSet *value_set;
476
477 len_subsys_name = strlen (subsystem) + 3 + strlen (name) + 1;
478 subsys_name = GNUNET_malloc (len_subsys_name);
479 SPRINTF (subsys_name, "%s---%s", subsystem, name);
480 key = &hc;
481 GNUNET_CRYPTO_hash (subsys_name, len_subsys_name, key);
482 GNUNET_free (subsys_name);
483 if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (values, key))
183 { 484 {
184 GNUNET_STATISTICS_get_cancel (gh); 485 // get
185 gh = NULL; 486 value_set = GNUNET_CONTAINER_multihashmap_get (values, key);
186 } 487 }
187 if ( (GNUNET_YES == watch) && 488 else
188 (NULL != subsystem) && 489 {
189 (NULL != name) ) 490 // new
190 GNUNET_assert (GNUNET_OK == 491 value_set = new_value_set (subsystem, name, num_nodes, is_persistent);
191 GNUNET_STATISTICS_watch_cancel (h, 492 }
192 subsystem, 493 // write
193 name, 494 value_set->values[index_node] = value;
194 &printer, 495 // put
195 h)); 496 GNUNET_CONTAINER_multihashmap_put (values, key, value_set,
196 GNUNET_STATISTICS_destroy (h, 497 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
197 GNUNET_NO); 498 return GNUNET_OK;
198 h = NULL;
199} 499}
200 500
201
202/** 501/**
203 * Main task that does the actual work. 502 * Main task that does the actual work.
204 * 503 *
@@ -207,8 +506,8 @@ shutdown_task (void *cls)
207static void 506static void
208main_task (void *cls) 507main_task (void *cls)
209{ 508{
210 const struct GNUNET_CONFIGURATION_Handle *cfg = cls; 509 unsigned index_node = *(unsigned *) cls;
211 struct GNUNET_STATISTICS_Handle *h; 510 const struct GNUNET_CONFIGURATION_Handle *cfg = nodes[index_node].conf;
212 511
213 if (set_value) 512 if (set_value)
214 { 513 {
@@ -228,23 +527,23 @@ main_task (void *cls)
228 ret = 1; 527 ret = 1;
229 return; 528 return;
230 } 529 }
231 h = GNUNET_STATISTICS_create (subsystem, 530 nodes[index_node].handle = GNUNET_STATISTICS_create (subsystem,
232 cfg); 531 cfg);
233 if (NULL == h) 532 if (NULL == nodes[index_node].handle)
234 { 533 {
235 ret = 1; 534 ret = 1;
236 return; 535 return;
237 } 536 }
238 GNUNET_STATISTICS_set (h, 537 GNUNET_STATISTICS_set (nodes[index_node].handle,
239 name, 538 name,
240 (uint64_t) set_val, 539 (uint64_t) set_val,
241 persistent); 540 persistent);
242 GNUNET_STATISTICS_destroy (h, 541 GNUNET_STATISTICS_destroy (nodes[index_node].handle,
243 GNUNET_YES); 542 GNUNET_YES);
244 h = NULL; 543 nodes[index_node].handle = NULL;
245 return; 544 return;
246 } 545 }
247 if (NULL == (h = GNUNET_STATISTICS_create ("gnunet-statistics", 546 if (NULL == (nodes[index_node].handle = GNUNET_STATISTICS_create ("gnunet-statistics",
248 cfg))) 547 cfg)))
249 { 548 {
250 ret = 1; 549 ret = 1;
@@ -253,13 +552,13 @@ main_task (void *cls)
253 if (GNUNET_NO == watch) 552 if (GNUNET_NO == watch)
254 { 553 {
255 if (NULL == 554 if (NULL ==
256 (gh = GNUNET_STATISTICS_get (h, 555 (nodes[index_node].gh = GNUNET_STATISTICS_get (nodes[index_node].handle,
257 subsystem, 556 subsystem,
258 name, 557 name,
259 &cleanup, 558 &continuation_print,
260 &printer, 559 &collector,
261 h)) ) 560 &nodes[index_node].index_node)) )
262 cleanup (h, 561 cleanup (nodes[index_node].handle,
263 GNUNET_SYSERR); 562 GNUNET_SYSERR);
264 } 563 }
265 else 564 else
@@ -268,30 +567,128 @@ main_task (void *cls)
268 (NULL == name) ) 567 (NULL == name) )
269 { 568 {
270 printf (_("No subsystem or name given\n")); 569 printf (_("No subsystem or name given\n"));
271 GNUNET_STATISTICS_destroy (h, 570 GNUNET_STATISTICS_destroy (nodes[index_node].handle,
272 GNUNET_NO); 571 GNUNET_NO);
273 h = NULL; 572 nodes[index_node].handle = NULL;
274 ret = 1; 573 ret = 1;
275 return; 574 return;
276 } 575 }
277 if (GNUNET_OK != 576 if (GNUNET_OK !=
278 GNUNET_STATISTICS_watch (h, 577 GNUNET_STATISTICS_watch (nodes[index_node].handle,
279 subsystem, 578 subsystem,
280 name, 579 name,
281 &printer, 580 &printer_watch,
282 h)) 581 &nodes[index_node].index_node))
283 { 582 {
284 fprintf (stderr, 583 fprintf (stderr,
285 _("Failed to initialize watch routine\n")); 584 _("Failed to initialize watch routine\n"));
286 GNUNET_SCHEDULER_add_now (&shutdown_task, 585 nodes[index_node].shutdown_task =
287 h); 586 GNUNET_SCHEDULER_add_now (&clean_node,
587 &nodes[index_node].index_node);
288 return; 588 return;
289 } 589 }
290 } 590 }
291 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, 591 nodes[index_node].shutdown_task =
292 h); 592 GNUNET_SCHEDULER_add_shutdown (&clean_node,
593 &nodes[index_node].index_node);
594}
595
596/**
597 * @brief Iter over content of a node's directory to check for existence of a
598 * config file.
599 *
600 * Implements #GNUNET_FileNameCallback
601 *
602 * @param cls pointer to indicate success
603 * @param filename filename inside the directory of the potential node
604 *
605 * @return to continue iteration or not to
606 */
607static int
608iter_check_config (void *cls,
609 const char *filename)
610{
611 if (0 == strncmp (GNUNET_STRINGS_get_short_name (filename), "config", 6))
612 {
613 /* Found the config - stop iteration successfully */
614 GNUNET_array_grow (nodes, num_nodes, num_nodes+1);
615 nodes[num_nodes-1].conf = GNUNET_CONFIGURATION_create();
616 nodes[num_nodes-1].index_node = num_nodes-1;
617 if (GNUNET_OK != GNUNET_CONFIGURATION_load (nodes[num_nodes-1].conf, filename))
618 {
619 FPRINTF (stderr, "Failed loading config `%s'\n", filename);
620 return GNUNET_SYSERR;
621 }
622 return GNUNET_NO;
623 }
624 else
625 {
626 /* Continue iteration */
627 return GNUNET_OK;
628 }
293} 629}
294 630
631/**
632 * @brief Iterates over filenames in testbed directory.
633 *
634 * Implements #GNUNET_FileNameCallback
635 *
636 * Checks if the file is a directory for a testbed node
637 * and counts the nodes.
638 *
639 * @param cls counter of nodes
640 * @param filename full path of the file in testbed
641 *
642 * @return status whether to continue iteration
643 */
644static int
645iter_testbed_path (void *cls,
646 const char *filename)
647{
648 unsigned index_node;
649
650 GNUNET_assert (NULL != filename);
651 if (1 == SSCANF (GNUNET_STRINGS_get_short_name (filename),
652 "%u",
653 &index_node))
654 {
655 if (-1 == GNUNET_DISK_directory_scan (filename,
656 iter_check_config,
657 NULL))
658 {
659 /* This is probably no directory for a testbed node
660 * Go on with iteration */
661 return GNUNET_OK;
662 }
663 return GNUNET_OK;
664 }
665 return GNUNET_OK;
666}
667
668/**
669 * @brief Count the number of nodes running in the testbed
670 *
671 * @param path_testbed path to the testbed data
672 *
673 * @return number of running nodes
674 */
675static int
676discover_testbed_nodes (const char *path_testbed)
677{
678 int num_dir_entries;
679
680 num_dir_entries = GNUNET_DISK_directory_scan (path_testbed,
681 iter_testbed_path,
682 NULL);
683 if (-1 == num_dir_entries)
684 {
685 FPRINTF (stderr,
686 "Failure during scanning directory `%s'\n",
687 path_testbed);
688 return -1;
689 }
690 return 0;
691}
295 692
296/** 693/**
297 * Main function that will be run by the scheduler. 694 * Main function that will be run by the scheduler.
@@ -311,6 +708,7 @@ run (void *cls,
311 708
312 c = (struct GNUNET_CONFIGURATION_Handle *) cfg; 709 c = (struct GNUNET_CONFIGURATION_Handle *) cfg;
313 set_value = GNUNET_NO; 710 set_value = GNUNET_NO;
711 if (NULL == csv_separator) csv_separator = "";
314 if (NULL != args[0]) 712 if (NULL != args[0])
315 { 713 {
316 if (1 != SSCANF (args[0], 714 if (1 != SSCANF (args[0],
@@ -363,8 +761,34 @@ run (void *cls,
363 "PORT", 761 "PORT",
364 remote_port); 762 remote_port);
365 } 763 }
366 GNUNET_SCHEDULER_add_now (&main_task, 764 if (NULL == path_testbed)
367 c); 765 {
766 values = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
767 GNUNET_array_grow (nodes, num_nodes, 1);
768 nodes[0].index_node = 0;
769 nodes[0].conf = c;
770 GNUNET_SCHEDULER_add_now (&main_task, &nodes[0].index_node);
771 }
772 else
773 {
774 if (GNUNET_YES == watch)
775 {
776 printf (_("Not able to watch testbed nodes (yet - feel free to implement)\n"));
777 ret = 1;
778 return;
779 }
780 values = GNUNET_CONTAINER_multihashmap_create (4, GNUNET_NO);
781 if (-1 == discover_testbed_nodes (path_testbed))
782 {
783 return;
784 }
785 /* For each config/node collect statistics */
786 for (unsigned i = 0; i < num_nodes; i++)
787 {
788 GNUNET_SCHEDULER_add_now (&main_task,
789 &nodes[i].index_node);
790 }
791 }
368} 792}
369 793
370 794
@@ -396,6 +820,18 @@ main (int argc, char *const *argv)
396 gettext_noop ("limit output to the given SUBSYSTEM"), 820 gettext_noop ("limit output to the given SUBSYSTEM"),
397 &subsystem), 821 &subsystem),
398 822
823 GNUNET_GETOPT_option_string ('S',
824 "csv-separator",
825 "CSV_SEPARATOR",
826 gettext_noop ("use as csv separator"),
827 &csv_separator),
828
829 GNUNET_GETOPT_option_filename ('t',
830 "testbed",
831 "TESTBED",
832 gettext_noop ("path to the folder containing the testbed data"),
833 &path_testbed),
834
399 GNUNET_GETOPT_option_flag ('q', 835 GNUNET_GETOPT_option_flag ('q',
400 "quiet", 836 "quiet",
401 gettext_noop ("just print the statistics value"), 837 gettext_noop ("just print the statistics value"),
@@ -411,11 +847,13 @@ main (int argc, char *const *argv)
411 "REMOTE", 847 "REMOTE",
412 gettext_noop ("connect to remote host"), 848 gettext_noop ("connect to remote host"),
413 &remote_host), 849 &remote_host),
850
414 GNUNET_GETOPT_option_ulong ('o', 851 GNUNET_GETOPT_option_ulong ('o',
415 "port", 852 "port",
416 "PORT", 853 "PORT",
417 gettext_noop ("port for remote host"), 854 gettext_noop ("port for remote host"),
418 &remote_port), 855 &remote_port),
856
419 GNUNET_GETOPT_OPTION_END 857 GNUNET_GETOPT_OPTION_END
420 }; 858 };
421 remote_port = 0; 859 remote_port = 0;