aboutsummaryrefslogtreecommitdiff
path: root/src/statistics/functions.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/statistics/functions.c')
-rw-r--r--src/statistics/functions.c656
1 files changed, 656 insertions, 0 deletions
diff --git a/src/statistics/functions.c b/src/statistics/functions.c
new file mode 100644
index 00000000..143860e7
--- /dev/null
+++ b/src/statistics/functions.c
@@ -0,0 +1,656 @@
1/*
2 This file is part of GNUnet
3 (C) 2004, 2005, 2006, 2008 Christian Grothoff (and other contributing authors)
4
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 2, or (at your
8 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 General Public License for more details.
14
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., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19
20*/
21
22#include "platform.h"
23#include "gnunetgtk_common.h"
24#include <GNUnet/gnunet_util_cron.h>
25#include <GNUnet/gnunet_stats_lib.h>
26#include <GNUnet/gnunet_getoption_lib.h>
27#include <GNUnet/gnunet_protocols.h>
28#include "functions.h"
29
30#define FUNCTIONS_DEBUG GNUNET_NO
31
32static StatPair *lastStatValues;
33
34static unsigned int lsv_size;
35
36static struct GNUNET_ClientServerConnection *sock;
37
38static struct GNUNET_Mutex *lock;
39
40static long connectionGoal;
41
42static unsigned long long banddown;
43
44static unsigned long long bandup;
45
46static struct GNUNET_GE_Context *ectx;
47
48static struct GNUNET_GC_Configuration *cfg;
49
50static struct GNUNET_CronManager *cron;
51
52static int
53getStatValue (unsigned long long *value,
54 unsigned long long *lvalue,
55 GNUNET_CronTime * dtime, const char *optName, int monotone)
56{
57 unsigned int i;
58
59 *value = 0;
60 if (lvalue != NULL)
61 *lvalue = 0;
62 for (i = 0; i < lsv_size; i++)
63 {
64 if (0 == strcmp (optName, lastStatValues[i].statName))
65 {
66 *value = lastStatValues[i].value;
67 if (lvalue != NULL)
68 *lvalue = lastStatValues[i].lvalue;
69 if (dtime != NULL)
70 *dtime = lastStatValues[i].delta;
71 if ((monotone == GNUNET_YES) && (lvalue != NULL)
72 && (*lvalue > *value))
73 return GNUNET_SYSERR; /* gnunetd restart? */
74 return GNUNET_OK;
75 }
76 }
77#if FUNCTIONS_DEBUG
78 GNUNET_GE_LOG (ectx,
79 GNUNET_GE_ERROR | GNUNET_GE_DEVELOPER | GNUNET_GE_ADMIN |
80 GNUNET_GE_USER | GNUNET_GE_BULK,
81 "Statistic not found: `%s'\n", optName);
82#endif
83 return GNUNET_SYSERR;
84}
85
86static void
87updateConnectionGoal (void *unused)
88{
89 char *cmh;
90 char *availableDown;
91 char *availableUp;
92
93 GNUNET_mutex_lock (lock);
94 cmh =
95 GNUNET_get_daemon_configuration_value (sock, "gnunetd",
96 "connection-max-hosts");
97 availableDown =
98 GNUNET_get_daemon_configuration_value (sock, "LOAD",
99 "MAXNETDOWNBPSTOTAL");
100 availableUp =
101 GNUNET_get_daemon_configuration_value (sock, "LOAD", "MAXNETUPBPSTOTAL");
102 GNUNET_mutex_unlock (lock);
103 if (cmh == NULL)
104 connectionGoal = 0;
105 else
106 connectionGoal = atol (cmh);
107 if (availableDown == NULL)
108 banddown = 0;
109 else
110 banddown = atol (availableDown);
111 if (availableUp == NULL)
112 bandup = 0;
113 else
114 bandup = atol (availableUp);
115
116 GNUNET_free_non_null (cmh);
117 GNUNET_free_non_null (availableDown);
118 GNUNET_free_non_null (availableUp);
119}
120
121static int
122getConnectedNodesStat (const void *closure, gfloat ** data)
123{
124 unsigned long long val;
125
126 if (connectionGoal == 0)
127 return GNUNET_SYSERR;
128 if (GNUNET_OK !=
129 getStatValue (&val, NULL, NULL, "# of connected peers", GNUNET_NO))
130 return GNUNET_SYSERR;
131 data[0][0] = ((gfloat) val) / connectionGoal;
132 return GNUNET_OK;
133}
134
135static int
136getLoadStat (const void *closure, gfloat ** data)
137{
138 unsigned long long valc;
139 unsigned long long vali;
140 unsigned long long valu;
141 unsigned long long vald;
142
143 if (GNUNET_OK !=
144 getStatValue (&valc, NULL, NULL, "% of allowed cpu load", GNUNET_NO))
145 return GNUNET_SYSERR;
146 if (GNUNET_OK !=
147 getStatValue (&vali, NULL, NULL, "% of allowed io load", GNUNET_NO))
148 return GNUNET_SYSERR;
149 if (GNUNET_OK != getStatValue (&valu,
150 NULL, NULL, "% of allowed network load (up)",
151 GNUNET_NO))
152 return GNUNET_SYSERR;
153 if (GNUNET_OK != getStatValue (&vald,
154 NULL, NULL,
155 "% of allowed network load (down)",
156 GNUNET_NO))
157 return GNUNET_SYSERR;
158 data[0][0] = (gfloat) valc / 100.0;
159 data[0][1] = (gfloat) vali / 100.0;
160 data[0][2] = (gfloat) valu / 100.0;
161 data[0][3] = (gfloat) vald / 100.0;
162 return GNUNET_OK;
163}
164
165static int
166getQuotaStat (const void *closure, gfloat ** data)
167{
168 unsigned long long allowed;
169 unsigned long long have;
170
171 data[0][0] = 0;
172 data[0][1] = 0;
173 if ((GNUNET_OK == getStatValue (&allowed,
174 NULL, NULL, "# bytes allowed in datastore",
175 GNUNET_NO)) &&
176 (allowed != 0) &&
177 (GNUNET_OK ==
178 getStatValue (&have, NULL, NULL, "# bytes in datastore", GNUNET_NO)))
179 data[0][0] = ((gfloat) have) / allowed;
180 if ((GNUNET_OK == getStatValue (&allowed,
181 NULL, NULL, "# max bytes allowed in dstore",
182 GNUNET_NO)) &&
183 (allowed != 0) &&
184 (GNUNET_OK ==
185 getStatValue (&have, NULL, NULL, "# bytes in dstore", GNUNET_NO)))
186 data[0][1] = ((gfloat) have) / allowed;
187 return GNUNET_OK;
188}
189
190static int
191getTrafficRecvStats (const void *closure, gfloat ** data)
192{
193 unsigned long long total;
194 unsigned long long noise;
195 unsigned long long content;
196 unsigned long long queries;
197 unsigned long long hellos;
198 unsigned long long rlimit;
199 unsigned long long ltotal;
200 unsigned long long lnoise;
201 unsigned long long lcontent;
202 unsigned long long lqueries;
203 unsigned long long lhellos;
204 unsigned long long lrlimit;
205 GNUNET_CronTime dtime;
206 char *buffer;
207
208 if (GNUNET_OK !=
209 getStatValue (&total, &ltotal, &dtime, "# bytes received", GNUNET_YES))
210 return GNUNET_SYSERR;
211 if (GNUNET_OK != getStatValue (&noise,
212 &lnoise, NULL, "# bytes of noise received",
213 GNUNET_YES))
214 return GNUNET_SYSERR;
215 buffer = GNUNET_malloc (512);
216 GNUNET_snprintf (buffer, 512, "# bytes received of type %d",
217 GNUNET_P2P_PROTO_GAP_RESULT);
218 if (GNUNET_OK !=
219 getStatValue (&content, &lcontent, NULL, buffer, GNUNET_YES))
220 {
221 content = 0;
222 lcontent = 0;
223 }
224 GNUNET_snprintf (buffer, 512, "# bytes received of type %d",
225 GNUNET_P2P_PROTO_HELLO);
226 if (GNUNET_OK != getStatValue (&hellos, &lhellos, NULL, buffer, GNUNET_YES))
227 {
228 hellos = 0;
229 lhellos = 0;
230 }
231 GNUNET_snprintf (buffer, 512, "# bytes received of type %d",
232 GNUNET_P2P_PROTO_GAP_QUERY);
233 if (GNUNET_OK !=
234 getStatValue (&queries, &lqueries, NULL, buffer, GNUNET_YES))
235 {
236 queries = 0;
237 lqueries = 0;
238 }
239 if (GNUNET_OK != getStatValue (&rlimit,
240 &lrlimit,
241 NULL,
242 "# total bytes per second receive limit",
243 GNUNET_NO))
244 {
245 rlimit = 0;
246 lrlimit = 0;
247 }
248 GNUNET_free (buffer);
249 if (banddown == 0)
250 return GNUNET_SYSERR;
251
252 total -= ltotal;
253 noise -= lnoise;
254 queries -= lqueries;
255 content -= lcontent;
256 hellos -= lhellos;
257 if (banddown <= 0)
258 {
259 data[0][0] = 0.0;
260 data[0][1] = 0.0;
261 data[0][2] = 0.0;
262 data[0][3] = 0.0;
263 data[0][4] = 0.0;
264 data[0][5] = 0.0;
265 return GNUNET_OK;
266 }
267 data[0][0] = ((gfloat) noise) / (banddown * dtime / GNUNET_CRON_SECONDS); /* red */
268 data[0][1] = ((gfloat) (content + noise)) / (banddown * dtime / GNUNET_CRON_SECONDS); /* green */
269 data[0][2] = ((gfloat) (queries + content + noise)) / (banddown * dtime / GNUNET_CRON_SECONDS); /* yellow */
270 data[0][3] = ((gfloat) (queries + content + noise + hellos)) / (banddown * dtime / GNUNET_CRON_SECONDS); /* blue */
271 data[0][4] = ((gfloat) total) / (banddown * dtime / GNUNET_CRON_SECONDS); /* gray */
272 data[0][5] = (gfloat) rlimit / banddown; /* magenta */
273#if 0
274 printf ("I: %f %f %f %f\n", data[0][0], data[0][1], data[0][2]);
275#endif
276 return GNUNET_OK;
277}
278
279static int
280getTrafficSendStats (const void *closure, gfloat ** data)
281{
282 unsigned long long total;
283 unsigned long long noise;
284 unsigned long long content;
285 unsigned long long queries;
286 unsigned long long hellos;
287 unsigned long long slimit;
288 unsigned long long ltotal;
289 unsigned long long lnoise;
290 unsigned long long lcontent;
291 unsigned long long lqueries;
292 unsigned long long lhellos;
293 unsigned long long lslimit;
294 GNUNET_CronTime dtime;
295 char *buffer;
296
297 if (GNUNET_OK != getStatValue (&total,
298 &ltotal, &dtime, "# bytes transmitted",
299 GNUNET_YES))
300 return GNUNET_SYSERR;
301 if (GNUNET_OK !=
302 getStatValue (&noise, &lnoise, NULL, "# bytes noise sent", GNUNET_YES))
303 return GNUNET_SYSERR;
304 buffer = GNUNET_malloc (512);
305 GNUNET_snprintf (buffer,
306 512, "# bytes transmitted of type %d",
307 GNUNET_P2P_PROTO_GAP_RESULT);
308 if (GNUNET_OK !=
309 getStatValue (&content, &lcontent, NULL, buffer, GNUNET_YES))
310 {
311 content = 0;
312 lcontent = 0;
313 }
314 GNUNET_snprintf (buffer,
315 512, "# bytes transmitted of type %d",
316 GNUNET_P2P_PROTO_GAP_QUERY);
317 if (GNUNET_OK !=
318 getStatValue (&queries, &lqueries, NULL, buffer, GNUNET_YES))
319 {
320 queries = 0;
321 lqueries = 0;
322 }
323 GNUNET_snprintf (buffer, 512, "# bytes transmitted of type %d",
324 GNUNET_P2P_PROTO_HELLO);
325 if (GNUNET_OK != getStatValue (&hellos, &lhellos, NULL, buffer, GNUNET_YES))
326 {
327 queries = 0;
328 lqueries = 0;
329 }
330 if (GNUNET_OK != getStatValue (&slimit,
331 &lslimit,
332 NULL, "# total bytes per second send limit",
333 GNUNET_NO))
334 {
335 slimit = 0;
336 lslimit = 0;
337 }
338 GNUNET_free (buffer);
339 if (bandup == 0)
340 return GNUNET_SYSERR;
341 total -= ltotal;
342 noise -= lnoise;
343 queries -= lqueries;
344 content -= lcontent;
345 hellos -= lhellos;
346 if (bandup <= 0)
347 {
348 data[0][0] = 0.0;
349 data[0][1] = 0.0;
350 data[0][2] = 0.0;
351 data[0][3] = 0.0;
352 data[0][4] = 0.0;
353 data[0][5] = 0.0;
354 return GNUNET_OK;
355 }
356 data[0][0] = ((gfloat) noise) / (bandup * dtime / GNUNET_CRON_SECONDS); /* red */
357 data[0][1] = ((gfloat) (noise + content)) / (bandup * dtime / GNUNET_CRON_SECONDS); /* green */
358 data[0][2] = ((gfloat) (noise + content + queries)) / (bandup * dtime / GNUNET_CRON_SECONDS); /* yellow */
359 data[0][3] = ((gfloat) (noise + content + queries + hellos)) / (bandup * dtime / GNUNET_CRON_SECONDS); /* blue */
360 data[0][4] = ((gfloat) total) / (bandup * dtime / GNUNET_CRON_SECONDS); /* grey */
361 data[0][5] = ((gfloat) slimit) / bandup; /* magenta */
362#if 0
363 printf ("O: %f %f %f %f\n", data[0][0], data[0][1], data[0][2], data[0][3]);
364#endif
365 return GNUNET_OK;
366}
367
368static int
369getTrustStats (const void *closure, gfloat ** data)
370{
371 unsigned long long spent;
372 unsigned long long earned;
373 unsigned long long awarded;
374 unsigned long long lspent;
375 unsigned long long learned;
376 unsigned long long lawarded;
377 unsigned long long max;
378
379 if (GNUNET_OK != getStatValue (&spent,
380 &lspent, NULL, "# trust spent", GNUNET_YES))
381 return GNUNET_SYSERR;
382 if (GNUNET_OK != getStatValue (&earned,
383 &learned,
384 NULL, "# trust earned", GNUNET_YES))
385 return GNUNET_SYSERR;
386 if (GNUNET_OK != getStatValue (&awarded,
387 &lawarded,
388 NULL, "# gap total trust awarded",
389 GNUNET_YES))
390 return GNUNET_SYSERR;
391 max = spent;
392 if (earned > max)
393 max = earned;
394 if (awarded > max)
395 max = awarded;
396 data[0][0] = 0.0;
397 if (max > 0)
398 {
399 data[0][0] = (1.0 * spent) / max;
400 data[0][1] = (1.0 * earned) / max;
401 data[0][2] = (1.0 * awarded) / max;
402 }
403 else
404 {
405 data[0][0] = 0.0;
406 data[0][1] = 0.0;
407 data[0][2] = 0.0;
408 }
409 return GNUNET_OK;
410}
411
412static int
413getEffectivenessStats (const void *closure, gfloat ** data)
414{
415 unsigned long long total; /* total number of queries passed on to remote */
416 unsigned long long success; /* responses forwarded (including local and remote) */
417 unsigned long long ltotal;
418 unsigned long long lsuccess;
419
420 if (GNUNET_OK != getStatValue (&total,
421 &ltotal,
422 NULL,
423 "# gap requests total sent", GNUNET_YES))
424 return GNUNET_SYSERR;
425 if (GNUNET_OK != getStatValue (&success,
426 &lsuccess,
427 NULL, "# gap routes succeeded", GNUNET_YES))
428 return GNUNET_SYSERR;
429 if (total > 0)
430 data[0][0] = 1.0 * success / total;
431 else
432 data[0][0] = 0.0;
433 return GNUNET_OK;
434}
435
436
437static int
438statsProcessor (const char *optName, unsigned long long value, void *data)
439{
440 /**
441 * Keep track of last match (or, more precisely, position
442 * of next expected match) since 99.99% of the time we
443 * go over the same stats in the same order and thus
444 * this will predict correctly).
445 */
446 static unsigned int last;
447 GNUNET_CronTime *delta = data;
448 unsigned int j;
449 unsigned int found;
450
451 if (last >= lsv_size)
452 last = 0;
453 j = last;
454 found = -1;
455 if ((j < lsv_size) && (0 == strcmp (optName, lastStatValues[j].statName)))
456 found = j;
457 if (found == (unsigned int) -1)
458 {
459 for (j = 0; j < lsv_size; j++)
460 {
461 if (0 == strcmp (optName, lastStatValues[j].statName))
462 {
463 found = j;
464 break;
465 }
466 }
467 }
468 if (found == (unsigned int) -1)
469 {
470 found = lsv_size;
471 GNUNET_array_grow (lastStatValues, lsv_size, lsv_size + 1);
472 lastStatValues[found].statName = GNUNET_strdup (optName);
473 }
474 lastStatValues[found].lvalue = lastStatValues[found].value;
475 lastStatValues[found].value = value;
476 lastStatValues[found].delta = *delta;
477 last = found + 1;
478 return GNUNET_OK;
479}
480
481struct UpdateClosure
482{
483 GNUNET_CronTime delta;
484 int is_running;
485};
486
487/*
488 * Update the status bar indicator about daemon and connexions status
489 */
490static void *
491updateDaemonStatus (void *cls)
492{
493 struct UpdateClosure *uc = cls;
494 unsigned long long connected_peers;
495
496 if (uc->is_running)
497 {
498 if (GNUNET_OK !=
499 getStatValue (&connected_peers, NULL, NULL,
500 "# of connected peers", GNUNET_NO))
501 GNUNET_GTK_display_daemon_status (GNUNET_GTK_STATUS_UNKNOWN, 0);
502 else if (connected_peers > 0)
503 GNUNET_GTK_display_daemon_status (GNUNET_GTK_STATUS_CONNECTED,
504 connected_peers);
505 else
506 GNUNET_GTK_display_daemon_status (GNUNET_GTK_STATUS_DISCONNECTED, 0);
507 }
508 else
509 GNUNET_GTK_display_daemon_status (GNUNET_GTK_STATUS_NODAEMON, 0);
510 return NULL;
511}
512
513/**
514 * Cron-job that updates all stat values.
515 */
516static void
517updateStatValues (void *unused)
518{
519 static GNUNET_CronTime lastUpdate;
520 GNUNET_CronTime now;
521 struct UpdateClosure uc;
522
523 now = GNUNET_get_time ();
524 uc.delta = now - lastUpdate;
525 uc.is_running = GNUNET_OK == GNUNET_test_daemon_running (ectx, cfg);
526 GNUNET_mutex_lock (lock);
527 if (GNUNET_OK ==
528 GNUNET_STATS_get_statistics (ectx, sock, &statsProcessor, &uc.delta))
529 lastUpdate = now;
530 GNUNET_GTK_save_call (&updateDaemonStatus, (void *) &uc);
531 GNUNET_mutex_unlock (lock);
532}
533
534
535StatEntry stats[] = {
536 {
537 gettext_noop ("Connectivity"),
538 gettext_noop ("# connected nodes (100% = connection table size)"),
539 &getConnectedNodesStat,
540 NULL,
541 1,
542 GNUNET_NO,
543 }
544 ,
545 {
546 gettext_noop ("System load"),
547 gettext_noop
548 ("CPU load (red), IO load (green), Network upload (yellow), Network download (blue)"),
549 &getLoadStat,
550 NULL,
551 4,
552 GNUNET_NO,
553 }
554 ,
555 {
556 gettext_noop ("Datastore capacity"),
557 gettext_noop ("Persistent file-sharing data (red) and DHT cache (green)"),
558 &getQuotaStat,
559 NULL,
560 2,
561 GNUNET_NO,
562 }
563 ,
564 {
565 gettext_noop ("Inbound Traffic"),
566 gettext_noop
567 ("Noise (red), Content (green), Queries (yellow), Hellos (blue), other (gray), limit (magenta)"),
568 &getTrafficRecvStats,
569 NULL,
570 6,
571 5,
572 }
573 ,
574 {
575 gettext_noop ("Outbound Traffic"),
576 gettext_noop
577 ("Noise (red), Content (green), Queries (yellow), Hellos (blue), other (gray), limit (magenta)"),
578 &getTrafficSendStats,
579 NULL,
580 6,
581 5,
582 }
583 ,
584 {
585 gettext_noop ("Trust"),
586 gettext_noop ("Spent (red), Earned (green) and Awarded (yellow)"),
587 &getTrustStats,
588 NULL,
589 3,
590 GNUNET_NO,
591 }
592 ,
593 {
594 gettext_noop ("Routing Effectiveness"),
595 gettext_noop ("Average (red) effectiveness (100% = perfect)"),
596 &getEffectivenessStats,
597 NULL,
598 1,
599 GNUNET_NO,
600 }
601 ,
602 {
603 NULL,
604 NULL,
605 NULL,
606 NULL,
607 0,
608 GNUNET_NO,
609 }
610 ,
611};
612
613static unsigned long long UPDATE_INTERVAL;
614
615void
616init_functions (struct GNUNET_GE_Context *e,
617 struct GNUNET_GC_Configuration *c)
618{
619 ectx = e;
620 cfg = c;
621 GNUNET_GC_get_configuration_value_number (cfg,
622 "GNUNET-GTK",
623 "STATS-INTERVAL",
624 1,
625 99 * GNUNET_CRON_YEARS,
626 30 * GNUNET_CRON_SECONDS,
627 &UPDATE_INTERVAL);
628 sock = GNUNET_client_connection_create (ectx, cfg);
629 lock = GNUNET_mutex_create (GNUNET_NO);
630 cron = GNUNET_GTK_get_cron_manager ();
631 GNUNET_cron_add_job (cron,
632 &updateStatValues, UPDATE_INTERVAL, UPDATE_INTERVAL,
633 NULL);
634 GNUNET_cron_add_job (cron, &updateConnectionGoal, 5 * GNUNET_CRON_SECONDS,
635 5 * GNUNET_CRON_MINUTES, NULL);
636 updateStatValues (NULL);
637}
638
639void
640done_functions ()
641{
642 unsigned int i;
643
644 GNUNET_cron_del_job (cron, &updateConnectionGoal, 5 * GNUNET_CRON_MINUTES,
645 NULL);
646 GNUNET_cron_del_job (cron, &updateStatValues, UPDATE_INTERVAL, NULL);
647 GNUNET_mutex_destroy (lock);
648 GNUNET_client_connection_destroy (sock);
649 for (i = 0; i < lsv_size; i++)
650 GNUNET_free (lastStatValues[i].statName);
651 GNUNET_array_grow (lastStatValues, lsv_size, 0);
652 sock = NULL;
653}
654
655
656/* end of functions.c */