aboutsummaryrefslogtreecommitdiff
path: root/src/statistics
diff options
context:
space:
mode:
authorJulius Bünger <buenger@mytum.de>2018-06-16 12:47:01 +0200
committerJulius Bünger <buenger@mytum.de>2018-06-16 13:03:50 +0200
commit298776c4185d99d2d64f9ff84d1eb662f2f16db7 (patch)
tree34ddc3a9f6b627430f521eb2201e59c741a1f76c /src/statistics
parent9770f389335fee2ce4683e6506f5cfeb98875490 (diff)
downloadgnunet-298776c4185d99d2d64f9ff84d1eb662f2f16db7.tar.gz
gnunet-298776c4185d99d2d64f9ff84d1eb662f2f16db7.zip
statistics-cli: add -t for printing statistics of testbed nodes
Diffstat (limited to 'src/statistics')
-rw-r--r--src/statistics/gnunet-statistics.c473
1 files changed, 434 insertions, 39 deletions
diff --git a/src/statistics/gnunet-statistics.c b/src/statistics/gnunet-statistics.c
index 648fc89bb..2aefcadee 100644
--- a/src/statistics/gnunet-statistics.c
+++ b/src/statistics/gnunet-statistics.c
@@ -39,6 +39,11 @@ static int ret;
39static char *subsystem; 39static char *subsystem;
40 40
41/** 41/**
42 * The path of the testbed data.
43 */
44static char *path_testbed;
45
46/**
42 * 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).
43 */ 48 */
44static char *name; 49static char *name;
@@ -79,10 +84,192 @@ static unsigned long long set_val;
79static int set_value; 84static int set_value;
80 85
81/** 86/**
82 * Handle for pending GET operation. 87 * @brief Representation of all (testbed) nodes.
83 */ 88 */
84static struct GNUNET_STATISTICS_GetHandle *gh; 89static struct Node {
90 /**
91 * @brief Index of the node in this array.
92 */
93 unsigned index_node;
94
95 /**
96 * @brief Configuration handle for this node
97 */
98 struct GNUNET_CONFIGURATION_Handle *conf;
99
100 /**
101 * Handle for pending GET operation.
102 */
103 struct GNUNET_STATISTICS_GetHandle *gh;
104
105 /**
106 * @brief Statistics handle nodes.
107 */
108 struct GNUNET_STATISTICS_Handle *handle;
109 /**
110 * @brief Identifier for shutdown task for this node.
111 */
112 struct GNUNET_SCHEDULER_Task *shutdown_task;
113} *nodes;
85 114
115/**
116 * @brief Number of configurations of all (testbed) nodes.
117 */
118static unsigned num_nodes;
119
120/**
121 * @brief Set of values for a combination of subsystem and name.
122 */
123struct ValueSet
124{
125 /**
126 * @brief Subsystem of the valueset.
127 */
128 char *subsystem;
129
130 /**
131 * @brief Name of the valueset.
132 */
133 char *name;
134
135 /**
136 * @brief The values.
137 */
138 uint64_t *values;
139
140 /**
141 * @brief Persistence of the values.
142 */
143 int is_persistent;
144};
145
146/**
147 * @brief Collection of all values (represented with #ValueSet).
148 */
149static struct GNUNET_CONTAINER_MultiHashMap *values;
150
151/**
152 * @brief Number of nodes that have their values ready.
153 */
154static int num_nodes_ready;
155
156/**
157 * @brief Create a new #ValueSet
158 *
159 * @param subsystem Subsystem of the valueset.
160 * @param name Name of the valueset.
161 * @param num_values Number of values in valueset - number of peers.
162 * @param is_persistent Persistence status of values.
163 *
164 * @return Newly allocated #ValueSet.
165 */
166static struct ValueSet *
167new_value_set (const char *subsystem,
168 const char *name,
169 unsigned num_values,
170 int is_persistent)
171{
172 struct ValueSet *value_set;
173
174 value_set = GNUNET_new (struct ValueSet);
175 value_set->subsystem = GNUNET_strdup (subsystem);
176 value_set->name = GNUNET_strdup (name);
177 value_set->values = GNUNET_new_array (num_values, uint64_t);
178 value_set->is_persistent = persistent;
179 return value_set;
180}
181
182/**
183 * @brief Print the (collected) values.
184 *
185 * Implements #GNUNET_CONTAINER_HashMapIterator.
186 *
187 * @param cls Closure - unused
188 * @param key #GNUNET_HashCode key of #GNUNET_CONTAINER_MultiHashMap iterator -
189 * unused
190 * @param value Values represented as #ValueSet.
191 *
192 * @return GNUNET_YES - continue iteration.
193 */
194static int
195printer (void *cls,
196 const struct GNUNET_HashCode *key,
197 void *value)
198{
199 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get();
200 const char *now_str;
201 struct ValueSet *value_set = value;
202
203 if (quiet == GNUNET_NO)
204 {
205 if (GNUNET_YES == watch)
206 {
207 now_str = GNUNET_STRINGS_absolute_time_to_string (now);
208 FPRINTF (stdout,
209 "%24s %s%12s %50s: ",
210 now_str,
211 value_set->is_persistent ? "!" : " ",
212 value_set->subsystem,
213 _(value_set->name));
214 }
215 else
216 {
217 FPRINTF (stdout,
218 "%s%12s %50s: ",
219 value_set->is_persistent ? "!" : " ",
220 value_set->subsystem,
221 _(value_set->name));
222 }
223 }
224 for (unsigned i = 0; i < num_nodes; i++)
225 {
226 FPRINTF (stdout,
227 "%16llu",
228 (unsigned long long) value_set->values[i]);
229 }
230 FPRINTF (stdout, "\n");
231 GNUNET_free (value_set->subsystem);
232 GNUNET_free (value_set->name);
233 GNUNET_free (value_set->values);
234 GNUNET_free (value_set);
235 return GNUNET_YES;
236}
237
238/**
239 * @brief Called once all statistic values are available.
240 *
241 * Implements #GNUNET_STATISTICS_Callback
242 *
243 * @param cls Closure - The index of the node.
244 * @param succes Whether statistics were obtained successfully.
245 */
246static void
247continuation_print (void *cls,
248 int success)
249{
250 const unsigned index_node = *(unsigned *) cls;
251
252 nodes[index_node].gh = NULL;
253 if (GNUNET_OK != success)
254 {
255 if (NULL == remote_host)
256 FPRINTF (stderr,
257 "%s",
258 _("Failed to obtain statistics.\n"));
259 else
260 FPRINTF (stderr,
261 _("Failed to obtain statistics from host `%s:%llu'\n"),
262 remote_host,
263 remote_port);
264 ret = 1;
265 }
266 num_nodes_ready++;
267 if (num_nodes_ready == num_nodes)
268 {
269 GNUNET_CONTAINER_multihashmap_iterate (values, printer, NULL);
270 GNUNET_SCHEDULER_shutdown();
271 }
272}
86 273
87/** 274/**
88 * Callback function to process statistic values. 275 * Callback function to process statistic values.
@@ -95,11 +282,11 @@ static struct GNUNET_STATISTICS_GetHandle *gh;
95 * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration 282 * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration
96 */ 283 */
97static int 284static int
98printer (void *cls, 285printer_watch (void *cls,
99 const char *subsystem, 286 const char *subsystem,
100 const char *name, 287 const char *name,
101 uint64_t value, 288 uint64_t value,
102 int is_persistent) 289 int is_persistent)
103{ 290{
104 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get(); 291 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get();
105 const char *now_str; 292 const char *now_str;
@@ -135,7 +322,6 @@ printer (void *cls,
135 return GNUNET_OK; 322 return GNUNET_OK;
136} 323}
137 324
138
139/** 325/**
140 * Function called last by the statistics code. 326 * Function called last by the statistics code.
141 * 327 *
@@ -147,7 +333,10 @@ static void
147cleanup (void *cls, 333cleanup (void *cls,
148 int success) 334 int success)
149{ 335{
150 gh = NULL; 336 for (unsigned i = 0; i < num_nodes; i++)
337 {
338 nodes[i].gh = NULL;
339 }
151 if (GNUNET_OK != success) 340 if (GNUNET_OK != success)
152 { 341 {
153 if (NULL == remote_host) 342 if (NULL == remote_host)
@@ -164,6 +353,55 @@ cleanup (void *cls,
164 GNUNET_SCHEDULER_shutdown (); 353 GNUNET_SCHEDULER_shutdown ();
165} 354}
166 355
356/**
357 * @brief Iterate over statistics values and store them in #values.
358 * They will be printed once all are available.
359 *
360 * @param cls Cosure - Node index.
361 * @param subsystem Subsystem of the value.
362 * @param name Name of the value.
363 * @param value Value itself.
364 * @param is_persistent Persistence.
365 *
366 * @return GNUNET_OK - continue.
367 */
368static int
369collector (void *cls,
370 const char *subsystem,
371 const char *name,
372 uint64_t value,
373 int is_persistent)
374{
375 const unsigned index_node = *(unsigned *) cls;
376 struct GNUNET_HashCode *key;
377 struct GNUNET_HashCode hc;
378 char *subsys_name;
379 unsigned len_subsys_name;
380 struct ValueSet *value_set;
381
382 len_subsys_name = strlen (subsystem) + 3 + strlen (name) + 1;
383 subsys_name = GNUNET_malloc (len_subsys_name);
384 SPRINTF (subsys_name, "%s---%s", subsystem, name);
385 key = &hc;
386 GNUNET_CRYPTO_hash (subsys_name, len_subsys_name, key);
387 GNUNET_free (subsys_name);
388 if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (values, key))
389 {
390 // get
391 value_set = GNUNET_CONTAINER_multihashmap_get (values, key);
392 }
393 else
394 {
395 // new
396 value_set = new_value_set (subsystem, name, num_nodes, is_persistent);
397 }
398 // write
399 value_set->values[index_node] = value;
400 // put
401 GNUNET_CONTAINER_multihashmap_put (values, key, value_set,
402 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
403 return GNUNET_OK;
404}
167 405
168/** 406/**
169 * Function run on shutdown to clean up. 407 * Function run on shutdown to clean up.
@@ -173,10 +411,30 @@ cleanup (void *cls,
173static void 411static void
174shutdown_task (void *cls) 412shutdown_task (void *cls)
175{ 413{
176 struct GNUNET_STATISTICS_Handle *h = cls; 414 const unsigned index_node = *(unsigned *) cls;
415 struct GNUNET_STATISTICS_Handle *h;
416 struct GNUNET_STATISTICS_GetHandle *gh;
177 417
418 nodes[index_node].shutdown_task = NULL;
419 if ( (NULL != path_testbed) &&
420 (NULL != nodes[index_node].conf) )
421 {
422 GNUNET_CONFIGURATION_destroy (nodes[index_node].conf);
423 nodes[index_node].conf = NULL;
424 }
425
426 h = nodes[index_node].handle;
427 gh = nodes[index_node].gh;
178 if (NULL == h) 428 if (NULL == h)
429 {
430 num_nodes_ready--;
431 if (0 == num_nodes_ready)
432 {
433 GNUNET_array_grow (nodes, num_nodes, 0);
434 GNUNET_CONTAINER_multihashmap_destroy (values);
435 }
179 return; 436 return;
437 }
180 if (NULL != gh) 438 if (NULL != gh)
181 { 439 {
182 GNUNET_STATISTICS_get_cancel (gh); 440 GNUNET_STATISTICS_get_cancel (gh);
@@ -186,14 +444,21 @@ shutdown_task (void *cls)
186 (NULL != subsystem) && 444 (NULL != subsystem) &&
187 (NULL != name) ) 445 (NULL != name) )
188 GNUNET_assert (GNUNET_OK == 446 GNUNET_assert (GNUNET_OK ==
189 GNUNET_STATISTICS_watch_cancel (h, 447 GNUNET_STATISTICS_watch_cancel (h,
190 subsystem, 448 subsystem,
191 name, 449 name,
192 &printer, 450 &printer_watch,
193 h)); 451 &nodes[index_node].index_node));
194 GNUNET_STATISTICS_destroy (h, 452 GNUNET_STATISTICS_destroy (h,
195 GNUNET_NO); 453 GNUNET_NO);
196 h = NULL; 454 h = NULL;
455
456 num_nodes_ready--;
457 if (0 == num_nodes_ready)
458 {
459 GNUNET_array_grow (nodes, num_nodes, 0);
460 GNUNET_CONTAINER_multihashmap_destroy (values);
461 }
197} 462}
198 463
199 464
@@ -205,8 +470,8 @@ shutdown_task (void *cls)
205static void 470static void
206main_task (void *cls) 471main_task (void *cls)
207{ 472{
208 const struct GNUNET_CONFIGURATION_Handle *cfg = cls; 473 unsigned index_node = *(unsigned *) cls;
209 struct GNUNET_STATISTICS_Handle *h; 474 const struct GNUNET_CONFIGURATION_Handle *cfg = nodes[index_node].conf;
210 475
211 if (set_value) 476 if (set_value)
212 { 477 {
@@ -226,23 +491,23 @@ main_task (void *cls)
226 ret = 1; 491 ret = 1;
227 return; 492 return;
228 } 493 }
229 h = GNUNET_STATISTICS_create (subsystem, 494 nodes[index_node].handle = GNUNET_STATISTICS_create (subsystem,
230 cfg); 495 cfg);
231 if (NULL == h) 496 if (NULL == nodes[index_node].handle)
232 { 497 {
233 ret = 1; 498 ret = 1;
234 return; 499 return;
235 } 500 }
236 GNUNET_STATISTICS_set (h, 501 GNUNET_STATISTICS_set (nodes[index_node].handle,
237 name, 502 name,
238 (uint64_t) set_val, 503 (uint64_t) set_val,
239 persistent); 504 persistent);
240 GNUNET_STATISTICS_destroy (h, 505 GNUNET_STATISTICS_destroy (nodes[index_node].handle,
241 GNUNET_YES); 506 GNUNET_YES);
242 h = NULL; 507 nodes[index_node].handle = NULL;
243 return; 508 return;
244 } 509 }
245 if (NULL == (h = GNUNET_STATISTICS_create ("gnunet-statistics", 510 if (NULL == (nodes[index_node].handle = GNUNET_STATISTICS_create ("gnunet-statistics",
246 cfg))) 511 cfg)))
247 { 512 {
248 ret = 1; 513 ret = 1;
@@ -251,13 +516,13 @@ main_task (void *cls)
251 if (GNUNET_NO == watch) 516 if (GNUNET_NO == watch)
252 { 517 {
253 if (NULL == 518 if (NULL ==
254 (gh = GNUNET_STATISTICS_get (h, 519 (nodes[index_node].gh = GNUNET_STATISTICS_get (nodes[index_node].handle,
255 subsystem, 520 subsystem,
256 name, 521 name,
257 &cleanup, 522 &continuation_print,
258 &printer, 523 &collector,
259 h)) ) 524 &nodes[index_node].index_node)) )
260 cleanup (h, 525 cleanup (nodes[index_node].handle,
261 GNUNET_SYSERR); 526 GNUNET_SYSERR);
262 } 527 }
263 else 528 else
@@ -266,30 +531,128 @@ main_task (void *cls)
266 (NULL == name) ) 531 (NULL == name) )
267 { 532 {
268 printf (_("No subsystem or name given\n")); 533 printf (_("No subsystem or name given\n"));
269 GNUNET_STATISTICS_destroy (h, 534 GNUNET_STATISTICS_destroy (nodes[index_node].handle,
270 GNUNET_NO); 535 GNUNET_NO);
271 h = NULL; 536 nodes[index_node].handle = NULL;
272 ret = 1; 537 ret = 1;
273 return; 538 return;
274 } 539 }
275 if (GNUNET_OK != 540 if (GNUNET_OK !=
276 GNUNET_STATISTICS_watch (h, 541 GNUNET_STATISTICS_watch (nodes[index_node].handle,
277 subsystem, 542 subsystem,
278 name, 543 name,
279 &printer, 544 &printer_watch,
280 h)) 545 &nodes[index_node].index_node))
281 { 546 {
282 fprintf (stderr, 547 fprintf (stderr,
283 _("Failed to initialize watch routine\n")); 548 _("Failed to initialize watch routine\n"));
284 GNUNET_SCHEDULER_add_now (&shutdown_task, 549 nodes[index_node].shutdown_task =
285 h); 550 GNUNET_SCHEDULER_add_now (&shutdown_task,
551 &nodes[index_node].index_node);
286 return; 552 return;
287 } 553 }
288 } 554 }
289 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, 555 nodes[index_node].shutdown_task =
290 h); 556 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
557 &nodes[index_node].index_node);
291} 558}
292 559
560/**
561 * @brief Iter over content of a node's directory to check for existence of a
562 * config file.
563 *
564 * Implements #GNUNET_FileNameCallback
565 *
566 * @param cls pointer to indicate success
567 * @param filename filename inside the directory of the potential node
568 *
569 * @return to continue iteration or not to
570 */
571static int
572iter_check_config (void *cls,
573 const char *filename)
574{
575 if (0 == strncmp (GNUNET_STRINGS_get_short_name (filename), "config", 6))
576 {
577 /* Found the config - stop iteration successfully */
578 GNUNET_array_grow (nodes, num_nodes, num_nodes+1);
579 nodes[num_nodes-1].conf = GNUNET_CONFIGURATION_create();
580 nodes[num_nodes-1].index_node = num_nodes-1;
581 if (GNUNET_OK != GNUNET_CONFIGURATION_load (nodes[num_nodes-1].conf, filename))
582 {
583 FPRINTF (stderr, "Failed loading config `%s'\n", filename);
584 return GNUNET_SYSERR;
585 }
586 return GNUNET_NO;
587 }
588 else
589 {
590 /* Continue iteration */
591 return GNUNET_OK;
592 }
593}
594
595/**
596 * @brief Iterates over filenames in testbed directory.
597 *
598 * Implements #GNUNET_FileNameCallback
599 *
600 * Checks if the file is a directory for a testbed node
601 * and counts the nodes.
602 *
603 * @param cls counter of nodes
604 * @param filename full path of the file in testbed
605 *
606 * @return status whether to continue iteration
607 */
608static int
609iter_testbed_path (void *cls,
610 const char *filename)
611{
612 unsigned index_node;
613
614 GNUNET_assert (NULL != filename);
615 if (1 == SSCANF (GNUNET_STRINGS_get_short_name (filename),
616 "%u",
617 &index_node))
618 {
619 if (-1 == GNUNET_DISK_directory_scan (filename,
620 iter_check_config,
621 NULL))
622 {
623 /* This is probably no directory for a testbed node
624 * Go on with iteration */
625 return GNUNET_OK;
626 }
627 return GNUNET_OK;
628 }
629 return GNUNET_OK;
630}
631
632/**
633 * @brief Count the number of nodes running in the testbed
634 *
635 * @param path_testbed path to the testbed data
636 *
637 * @return number of running nodes
638 */
639static int
640discover_testbed_nodes (const char *path_testbed)
641{
642 int num_dir_entries;
643
644 num_dir_entries = GNUNET_DISK_directory_scan (path_testbed,
645 iter_testbed_path,
646 NULL);
647 if (-1 == num_dir_entries)
648 {
649 FPRINTF (stderr,
650 "Failure during scanning directory `%s'\n",
651 path_testbed);
652 return -1;
653 }
654 return 0;
655}
293 656
294/** 657/**
295 * Main function that will be run by the scheduler. 658 * Main function that will be run by the scheduler.
@@ -361,8 +724,34 @@ run (void *cls,
361 "PORT", 724 "PORT",
362 remote_port); 725 remote_port);
363 } 726 }
364 GNUNET_SCHEDULER_add_now (&main_task, 727 if (NULL == path_testbed)
365 c); 728 {
729 values = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
730 GNUNET_array_grow (nodes, num_nodes, 1);
731 nodes[0].index_node = 0;
732 nodes[0].conf = c;
733 GNUNET_SCHEDULER_add_now (&main_task, &nodes[0].index_node);
734 }
735 else
736 {
737 if (GNUNET_YES == watch)
738 {
739 printf (_("Not able to watch testbed nodes (yet - feel free to implement)\n"));
740 ret = 1;
741 return;
742 }
743 values = GNUNET_CONTAINER_multihashmap_create (4, GNUNET_NO);
744 if (-1 == discover_testbed_nodes (path_testbed))
745 {
746 return;
747 }
748 /* For each config/node collect statistics */
749 for (unsigned i = 0; i < num_nodes; i++)
750 {
751 GNUNET_SCHEDULER_add_now (&main_task,
752 &nodes[i].index_node);
753 }
754 }
366} 755}
367 756
368 757
@@ -394,6 +783,12 @@ main (int argc, char *const *argv)
394 gettext_noop ("limit output to the given SUBSYSTEM"), 783 gettext_noop ("limit output to the given SUBSYSTEM"),
395 &subsystem), 784 &subsystem),
396 785
786 GNUNET_GETOPT_option_filename ('t',
787 "testbed",
788 "TESTBED",
789 gettext_noop ("path to the folder containing the testbed data"),
790 &path_testbed),
791
397 GNUNET_GETOPT_option_flag ('q', 792 GNUNET_GETOPT_option_flag ('q',
398 "quiet", 793 "quiet",
399 gettext_noop ("just print the statistics value"), 794 gettext_noop ("just print the statistics value"),