aboutsummaryrefslogtreecommitdiff
path: root/src/plugins/stats/statistics.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/stats/statistics.c')
-rw-r--r--src/plugins/stats/statistics.c949
1 files changed, 949 insertions, 0 deletions
diff --git a/src/plugins/stats/statistics.c b/src/plugins/stats/statistics.c
new file mode 100644
index 00000000..e8347fce
--- /dev/null
+++ b/src/plugins/stats/statistics.c
@@ -0,0 +1,949 @@
1/*
2 This file is part of GNUnet
3
4 GNUnet is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published
6 by the Free Software Foundation; either version 2, or (at your
7 option) any later version.
8
9 GNUnet is distributed in the hope that it will be useful, but
10 WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with GNUnet; see the file COPYING. If not, write to the
16 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 Boston, MA 02111-1307, USA.
18
19 Portions of this code were adopted from the
20 gnome-system-monitor v2.0.5, (C) 2001 Kevin Vandersloot
21
22
23 Todo:
24 - add any more StatEntries, update menu accordingly.
25*/
26
27#include "gnunet_afs_esed2.h"
28#include "statistics.h"
29#include "helper.h"
30#include "main.h"
31#include <glib.h>
32
33#define UPDATE_INTERVAL (30 * cronSECONDS)
34
35typedef struct {
36 char * statName;
37 long long value;
38 long long lvalue;
39 cron_t delta;
40} StatPair;
41
42static StatPair * lastStatValues;
43static unsigned int lsv_size;
44static cron_t lastUpdate;
45static Mutex lock;
46
47static void updateStatValues(GNUNET_TCP_SOCKET * sock) {
48 STATS_CS_MESSAGE * statMsg;
49 CS_HEADER csHdr;
50 unsigned int count;
51 unsigned int i;
52 int j;
53 int mpos;
54 int found;
55 char * optName;
56 cron_t now;
57 cron_t prev;
58
59 cronTime(&now);
60 MUTEX_LOCK(&lock);
61 if (now - lastUpdate < UPDATE_INTERVAL) {
62 MUTEX_UNLOCK(&lock);
63 return;
64 }
65 prev = lastUpdate;
66 lastUpdate = now;
67 csHdr.size
68 = htons(sizeof(CS_HEADER));
69 csHdr.tcpType
70 = htons(STATS_CS_PROTO_GET_STATISTICS);
71 if (SYSERR == writeToSocket(sock,
72 &csHdr)) {
73 MUTEX_UNLOCK(&lock);
74 return;
75 }
76 statMsg
77 = MALLOC(MAX_BUFFER_SIZE);
78 statMsg->totalCounters
79 = htonl(1); /* to ensure we enter the loop */
80 count = 0;
81 while ( count < ntohl(statMsg->totalCounters) ) {
82 if (SYSERR == readFromSocket(sock,
83 (CS_HEADER**)&statMsg)) {
84 FREE(statMsg);
85 MUTEX_UNLOCK(&lock);
86 return;
87 }
88 if (ntohs(statMsg->header.size) < sizeof(STATS_CS_MESSAGE)) {
89 BREAK();
90 break;
91 }
92 mpos = sizeof(unsigned long long) * ntohl(statMsg->statCounters);
93 if ( ((char*)(((STATS_CS_MESSAGE_GENERIC*)statMsg)->values))
94 [ntohs(statMsg->header.size) - sizeof(STATS_CS_MESSAGE) - 1] != '\0') {
95 BREAK();
96 break;
97 }
98 for (i=0;i<ntohl(statMsg->statCounters);i++) {
99 optName = &((char*)(((STATS_CS_MESSAGE_GENERIC*)statMsg)->values))[mpos];
100 if ( (mpos > ntohs(statMsg->header.size) - sizeof(STATS_CS_MESSAGE)) ||
101 (mpos + strlen(optName) + 1 >
102 ntohs(statMsg->header.size) - sizeof(STATS_CS_MESSAGE)) ) {
103 BREAK();
104 break; /* out of bounds! */
105 }
106 found = -1;
107 for (j=0;j<lsv_size;j++)
108 if (0 == strcmp(optName,
109 lastStatValues[j].statName))
110 found = j;
111 if (found == -1) {
112 found = lsv_size;
113 GROW(lastStatValues,
114 lsv_size,
115 lsv_size+1);
116 lastStatValues[found].statName
117 = STRDUP(optName);
118 }
119 lastStatValues[found].lvalue
120 = lastStatValues[found].value;
121 lastStatValues[found].value
122 = ntohll(((STATS_CS_MESSAGE_GENERIC*)statMsg)->values[i]);
123 lastStatValues[found].delta
124 = now-prev;
125 mpos += strlen(optName)+1;
126 }
127 count += ntohl(statMsg->statCounters);
128 } /* end while */
129 FREE(statMsg);
130 MUTEX_UNLOCK(&lock);
131}
132
133static int getStatValue(long long * value,
134 long long * lvalue,
135 cron_t * dtime,
136 GNUNET_TCP_SOCKET * sock,
137 const char * optName) {
138 unsigned int i;
139
140 *value = 0;
141 if (lvalue != NULL)
142 *lvalue = 0;
143 updateStatValues(sock);
144 MUTEX_LOCK(&lock);
145 for (i=0;i<lsv_size;i++) {
146 if (0 == strcmp(optName,
147 lastStatValues[i].statName)) {
148 *value = lastStatValues[i].value;
149 if (lvalue != NULL)
150 *lvalue = lastStatValues[i].lvalue;
151 if (dtime != NULL)
152 *dtime = lastStatValues[i].delta;
153 MUTEX_UNLOCK(&lock);
154 return OK;
155 }
156 }
157 MUTEX_UNLOCK(&lock);
158 return SYSERR;
159}
160
161/**
162 * Callback function to obtain the latest stats
163 * data for this stat display.
164 */
165typedef int (*UpdateData)(GNUNET_TCP_SOCKET * sock,
166 const void * closure,
167 gfloat ** data);
168
169static int getConnectedNodesStat(GNUNET_TCP_SOCKET * sock,
170 const void * closure,
171 gfloat ** data) {
172 long long val;
173 char * cmh;
174 long cval;
175
176 cmh = getConfigurationOptionValue(sock,
177 "gnunetd",
178 "connection-max-hosts");
179 if (cmh == NULL)
180 return SYSERR;
181 cval = atol(cmh);
182 FREE(cmh);
183 if (OK != getStatValue(&val,
184 NULL,
185 NULL,
186 sock,
187 _("# currently connected nodes")))
188 return SYSERR;
189 data[0][0] = 0.8 * val / cval;
190 return OK;
191}
192
193static int getCPULoadStat(GNUNET_TCP_SOCKET * sock,
194 const void * closure,
195 gfloat ** data) {
196 long long val;
197
198 if (OK != getStatValue(&val,
199 NULL,
200 NULL,
201 sock,
202 _("% of allowed cpu load")))
203 return SYSERR;
204 data[0][0] = val / 125.0;
205 return OK;
206}
207
208static const unsigned short afs_protocol_messages_queries[] = {
209 AFS_p2p_PROTO_QUERY,
210 AFS_p2p_PROTO_NSQUERY,
211 0,
212};
213
214static const unsigned short afs_protocol_messages_content[] = {
215 AFS_p2p_PROTO_3HASH_RESULT,
216 AFS_p2p_PROTO_CHK_RESULT,
217 AFS_p2p_PROTO_SBLOCK_RESULT,
218 0,
219};
220
221static int getTrafficRecvStats(GNUNET_TCP_SOCKET * sock,
222 const void * closure,
223 gfloat ** data) {
224 long long total;
225 long long noise;
226 long long content;
227 long long queries;
228 long long ltotal;
229 long long lnoise;
230 long long lcontent;
231 long long lqueries;
232 long long band;
233 long long tmp;
234 long long ltmp;
235 cron_t dtime;
236 char * available;
237 char * buffer;
238 int i;
239
240 MUTEX_LOCK(&lock);
241 if (OK != getStatValue(&total,
242 &ltotal,
243 &dtime,
244 sock,
245 _("# bytes decrypted")))
246 return SYSERR;
247 if (OK != getStatValue(&noise,
248 &lnoise,
249 NULL,
250 sock,
251 _("# bytes of noise received")))
252 return SYSERR;
253 i = 0;
254 content = lcontent = 0;
255 buffer = MALLOC(512);
256 while (afs_protocol_messages_content[i] != 0) {
257 SNPRINTF(buffer,
258 512,
259 _("# bytes received of type %d"),
260 afs_protocol_messages_content[i++]);
261 if (OK == getStatValue(&tmp,
262 &ltmp,
263 NULL,
264 sock,
265 buffer)) {
266 content += tmp;
267 lcontent += ltmp;
268 }
269 }
270 i = 0;
271 while (afs_protocol_messages_queries[i] != 0) {
272 SNPRINTF(buffer,
273 512,
274 _("# bytes received of type %d"),
275 afs_protocol_messages_queries[i++]);
276 if (OK == getStatValue(&tmp,
277 &ltmp,
278 NULL,
279 sock,
280 buffer)) {
281 queries += tmp;
282 lqueries += ltmp;
283 }
284 }
285 FREE(buffer);
286 MUTEX_UNLOCK(&lock);
287 available = getConfigurationOptionValue(sock,
288 "LOAD",
289 "MAXNETDOWNBPSTOTAL");
290 if (available == NULL)
291 return SYSERR;
292 band = atol(available) * dtime / cronSECONDS;
293 FREE(available);
294 total -= ltotal;
295 noise -= lnoise;
296 queries -= lqueries;
297 content -= lcontent;
298 if (band <= 0) {
299 data[0][0] = 0.0;
300 data[0][1] = 0.0;
301 data[0][2] = 0.0;
302 data[0][3] = 0.0;
303 return OK;
304 }
305 data[0][0] = 0.8 * noise / band; /* red */
306 data[0][1] = 0.8 * (content+noise) / band; /* green */
307 data[0][2] = 0.8 * (queries+content+noise) / band; /* yellow */
308 data[0][3] = 0.8 * total / band; /* blue */
309 /*printf("I: %f %f %f\n",
310 data[0][0],
311 data[0][1],
312 data[0][2]);*/
313
314 return OK;
315}
316
317
318 static int getTrafficSendStats(GNUNET_TCP_SOCKET * sock,
319 const void * closure,
320 gfloat ** data) {
321 long long total;
322 long long noise;
323 long long content;
324 long long queries;
325 long long ltotal;
326 long long lnoise;
327 long long lcontent;
328 long long lqueries;
329 long long band;
330 long long tmp;
331 long long ltmp;
332 cron_t dtime;
333 char * available;
334 char * buffer;
335 int i;
336
337 MUTEX_LOCK(&lock);
338 if (OK != getStatValue(&total,
339 &ltotal,
340 &dtime,
341 sock,
342 _("# encrypted bytes sent")))
343 return SYSERR;
344 if (OK != getStatValue(&noise,
345 &lnoise,
346 NULL,
347 sock,
348 _("# bytes noise sent")))
349 return SYSERR;
350 i = 0;
351 content = lcontent = 0;
352 buffer = MALLOC(512);
353 while (afs_protocol_messages_content[i] != 0) {
354 SNPRINTF(buffer,
355 512,
356 _("# bytes transmitted of type %d"),
357 afs_protocol_messages_content[i++]);
358 if (OK == getStatValue(&tmp,
359 &ltmp,
360 NULL,
361 sock,
362 buffer)) {
363 content += tmp;
364 lcontent += ltmp;
365 }
366 }
367 i = 0;
368 while (afs_protocol_messages_queries[i] != 0) {
369 SNPRINTF(buffer,
370 512,
371 _("# bytes received of type %d"),
372 afs_protocol_messages_queries[i++]);
373 if (OK == getStatValue(&tmp,
374 &ltmp,
375 NULL,
376 sock,
377 buffer)) {
378 queries += tmp;
379 lqueries += ltmp;
380 }
381 }
382 FREE(buffer);
383 MUTEX_UNLOCK(&lock);
384 available = getConfigurationOptionValue(sock,
385 "LOAD",
386 "MAXNETUPBPSTOTAL");
387 if (available == NULL)
388 return SYSERR;
389 band = atol(available) * dtime / cronSECONDS;
390 FREE(available);
391 total -= ltotal;
392 noise -= lnoise;
393 queries -= lqueries;
394 content -= lcontent;
395 if (band <= 0) {
396 data[0][0] = 0.0;
397 data[0][1] = 0.0;
398 data[0][2] = 0.0;
399 data[0][3] = 0.0;
400 return OK;
401 }
402 data[0][0] = 0.8 * noise / band; /* red */
403 data[0][1] = 0.8 * (noise + content) / band; /* green */
404 data[0][2] = 0.8 * (noise + content + queries) / band; /* yellow */
405 data[0][3] = 0.8 * total / band; /* yellow */
406 /* printf("O: %f %f %f\n",
407 data[0][0],
408 data[0][1],
409 data[0][2]);*/
410
411 return OK;
412}
413
414
415
416typedef struct SE_ {
417 char * paneName;
418 char * frameName;
419 UpdateData getData;
420 void * get_closure;
421 unsigned int count;
422 int fill; /* YES / NO */
423} StatEntry;
424
425#define STATS_COUNT 4
426
427static StatEntry stats[] = {
428 {
429 gettext_noop("Connectivity"),
430 gettext_noop("# connected nodes (100% = connection table size)"),
431 &getConnectedNodesStat,
432 NULL,
433 1,
434 NO,
435 },
436 {
437 gettext_noop("CPU load"),
438 gettext_noop("CPU load (in percent of allowed load)"),
439 &getCPULoadStat,
440 NULL,
441 1,
442 NO,
443 },
444 {
445 gettext_noop("Inbound Traffic"),
446 gettext_noop("Noise (red), Content (green), Queries (yellow), other (blue)"),
447 &getTrafficRecvStats,
448 NULL,
449 4,
450 YES,
451 },
452 {
453 gettext_noop("Outbound Traffic"),
454 gettext_noop("Noise (red), Content (green), Queries (yellow), other (blue)"),
455 &getTrafficSendStats,
456 NULL,
457 4,
458 YES,
459 },
460 {
461 NULL,
462 NULL,
463 NULL,
464 NULL,
465 1,
466 NO,
467 },
468};
469
470
471/**
472 * Remove the active page from the notebook.
473 */
474static void statClose(void) {
475 gint pagenr;
476
477 pagenr = gtk_notebook_get_current_page(notebook);
478 gtk_notebook_remove_page(notebook, pagenr);
479 /* Need to refresh the widget --
480 This forces the widget to redraw itself. */
481 gtk_widget_draw(GTK_WIDGET(notebook), NULL);
482}
483
484static GtkItemFactoryEntry statWindowMenu[] = {
485 {
486 gettext_noop("/Close display"),
487 NULL,
488 statClose,
489 0,
490 "<Item>"
491 }
492};
493static gint statWindowMenuItems
494 = sizeof (statWindowMenu) / sizeof (statWindowMenu[0]);
495
496
497/**
498 */
499static void addClosePopupMenu(GtkWidget * widget) {
500 GtkWidget * menu;
501 GtkItemFactory * popupFactory;
502
503 popupFactory = gtk_item_factory_new(GTK_TYPE_MENU, "<main>",
504 NULL);
505 gtk_item_factory_create_items(popupFactory,
506 statWindowMenuItems,
507 statWindowMenu,
508 NULL);
509 menu = gtk_item_factory_get_widget(popupFactory, "<main>");
510 gtk_signal_connect(GTK_OBJECT(widget),
511 "button_press_event",
512 GTK_SIGNAL_FUNC(popupCallback),
513 menu);
514}
515
516
517typedef struct {
518 gint type;
519 guint count;
520 guint speed;
521 guint draw_width, draw_height;
522 guint num_points;
523 guint allocated;
524 GdkColor *colors;
525 gfloat **data, **odata;
526 guint data_size;
527 gint colors_allocated;
528 GtkWidget *main_widget;
529 GtkWidget *disp;
530 GtkWidget *label;
531 GdkPixmap *pixmap;
532 GdkGC *gc;
533 int timer_index;
534 gboolean draw;
535 GNUNET_TCP_SOCKET * sock;
536 int statIdx;
537} LoadGraph;
538
539#define MAX_COLOR 4
540
541typedef struct {
542 gint graph_update_interval;
543 GdkColor bg_color;
544 GdkColor frame_color;
545 GdkColor mem_color[MAX_COLOR];
546} ProcConfig;
547
548typedef struct ProcData {
549 ProcConfig config;
550 LoadGraph *mem_graph;
551 int statIdx;
552} ProcData;
553
554#define GNOME_PAD_SMALL 2
555#define FRAME_WIDTH 0
556
557
558/**
559 * Redraws the backing pixmap for the load graph and updates the window
560 */
561static void load_graph_draw(LoadGraph *g) {
562 guint i;
563 guint j;
564 gint dely;
565 float delx;
566
567 if (!g->disp->window)
568 return;
569
570 g->draw_width = g->disp->allocation.width;
571 g->draw_height = g->disp->allocation.height;
572
573 if (!g->pixmap)
574 g->pixmap = gdk_pixmap_new (g->disp->window,
575 g->draw_width, g->draw_height,
576 gtk_widget_get_visual (g->disp)->depth);
577
578 /* Create GC if necessary. */
579 if (!g->gc) {
580 g->gc = gdk_gc_new (g->disp->window);
581 gdk_gc_copy (g->gc, g->disp->style->white_gc);
582 }
583
584 /* Allocate colors. */
585 if (!g->colors_allocated) {
586 GdkColormap *colormap;
587
588 colormap = gdk_window_get_colormap (g->disp->window);
589 for (i=0;i<2+g->count;i++)
590 gdk_color_alloc (colormap, &(g->colors [i]));
591
592 g->colors_allocated = 1;
593 }
594 /* Erase Rectangle */
595 gdk_gc_set_foreground (g->gc, &(g->colors [0]));
596 gdk_draw_rectangle (g->pixmap,
597 g->gc,
598 TRUE, 0, 0,
599 g->disp->allocation.width,
600 g->disp->allocation.height);
601
602 /* draw frame */
603 gdk_gc_set_foreground (g->gc, &(g->colors [1]));
604 gdk_draw_rectangle (g->pixmap,
605 g->gc,
606 FALSE, 0, 0,
607 g->draw_width,
608 g->disp->allocation.height);
609
610 dely = g->draw_height / 5;
611 for (i = 1; i <5; i++) {
612 gint y1 = g->draw_height + 1 - i * dely;
613 gdk_draw_line (g->pixmap, g->gc,
614 0, y1, g->draw_width, y1);
615 }
616
617 gdk_gc_set_line_attributes (g->gc, 2, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_MITER );
618 delx = (float)g->draw_width / ( g->num_points - 1);
619
620 for (j=0;j<g->count;j++) {
621 gdk_gc_set_foreground (g->gc, &(g->colors [j + 2]));
622 for (i = 0; i < g->num_points - 1; i++) {
623 gint x1 = i * delx;
624 gint x2 = (i + 1) * delx;
625 gint y1 = g->data[i][j] * g->draw_height - 1;
626 gint y2 = g->data[i+1][j] * g->draw_height - 1;
627
628 if ((g->data[i][j] != -1) && (g->data[i+1][j] != -1)) {
629 if (stats[g->statIdx].fill == NO) {
630 gdk_draw_line(g->pixmap, g->gc,
631 g->draw_width - x2,
632 g->draw_height - y2,
633 g->draw_width - x1,
634 g->draw_height - y1);
635 } else {
636 GdkPoint points[4];
637
638 points[0].x = g->draw_width - x2;
639 points[0].y = g->draw_height - y2;
640 points[1].x = g->draw_width - x1;
641 points[1].y = g->draw_height - y1;
642 points[2].x = g->draw_width - x1;
643 points[3].x = g->draw_width - x2;
644 if (j == 0) {
645 points[2].y = g->draw_height;
646 points[3].y = g->draw_height;
647 } else {
648 gint ly1 = g->data[i][j-1] * g->draw_height - 1;
649 gint ly2 = g->data[i+1][j-1] * g->draw_height - 1;
650 points[2].y = g->draw_height - ly1;
651 points[3].y = g->draw_height - ly2;
652 }
653 gdk_draw_polygon(g->pixmap,
654 g->gc,
655 1,
656 points,
657 4);
658 }
659 }
660 }
661 }
662
663 gdk_gc_set_line_attributes (g->gc, 1, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_MITER );
664
665 gdk_draw_pixmap (g->disp->window,
666 g->disp->style->fg_gc [GTK_WIDGET_STATE(g->disp)],
667 g->pixmap,
668 0, 0,
669 0, 0,
670 g->disp->allocation.width,
671 g->disp->allocation.height);
672}
673
674
675/* Updates the load graph when the timeout expires */
676static int load_graph_update(LoadGraph *g) {
677 guint i;
678 guint j;
679
680 for (i=0;i<g->num_points;i++)
681 memcpy(g->odata[i],
682 g->data[i],
683 g->data_size * g->count);
684 stats[g->statIdx].getData(g->sock,
685 stats[g->statIdx].get_closure,
686 g->data);
687 for (i=0;i<g->num_points-1;i++)
688 for (j=0;j<g->count;j++)
689 g->data[i+1][j] = g->odata[i][j];
690 if (g->draw)
691 load_graph_draw (g);
692 return TRUE;
693}
694
695static void load_graph_unalloc (LoadGraph *g) {
696 int i;
697 if (!g->allocated)
698 return;
699 for (i = 0; i < g->num_points; i++) {
700 FREE(g->data[i]);
701 FREE(g->odata[i]);
702 }
703 FREE(g->data);
704 FREE(g->odata);
705 g->data = g->odata = NULL;
706 if (g->pixmap) {
707 gdk_pixmap_unref(g->pixmap);
708 g->pixmap = NULL;
709 }
710 g->allocated = FALSE;
711}
712
713static void load_graph_alloc (LoadGraph *g) {
714 int i;
715 int j;
716
717 if (g->allocated)
718 return;
719
720 g->data = MALLOC(sizeof(gfloat *) * g->num_points);
721 g->odata = MALLOC(sizeof(gfloat*) * g->num_points);
722 g->data_size = sizeof (gfloat);
723 for (i = 0; i < g->num_points; i++) {
724 g->data[i] = MALLOC(g->data_size * g->count);
725 g->odata[i] = MALLOC(g->data_size * g->count);
726 }
727 for (i=0;i<g->num_points;i++)
728 for (j=0;j<g->count;j++)
729 g->data[i][j] = -1;
730 g->allocated = TRUE;
731}
732
733static gint load_graph_configure(GtkWidget *widget,
734 GdkEventConfigure *event,
735 gpointer data_ptr) {
736 LoadGraph *c = (LoadGraph *) data_ptr;
737
738 if (c->pixmap) {
739 gdk_pixmap_unref (c->pixmap);
740 c->pixmap = NULL;
741 }
742
743 if (!c->pixmap)
744 c->pixmap = gdk_pixmap_new (widget->window,
745 widget->allocation.width,
746 widget->allocation.height,
747 gtk_widget_get_visual (c->disp)->depth);
748 gdk_draw_rectangle (c->pixmap,
749 widget->style->black_gc,
750 TRUE, 0,0,
751 widget->allocation.width,
752 widget->allocation.height);
753 gdk_draw_pixmap (widget->window,
754 c->disp->style->fg_gc [GTK_WIDGET_STATE(widget)],
755 c->pixmap,
756 0, 0,
757 0, 0,
758 c->disp->allocation.width,
759 c->disp->allocation.height);
760
761 load_graph_draw (c);
762 return TRUE;
763}
764
765static gint load_graph_expose(GtkWidget *widget,
766 GdkEventExpose *event,
767 gpointer data_ptr) {
768 LoadGraph *g = (LoadGraph *) data_ptr;
769
770 gdk_draw_pixmap (widget->window,
771 widget->style->fg_gc [GTK_WIDGET_STATE(widget)],
772 g->pixmap,
773 event->area.x, event->area.y,
774 event->area.x, event->area.y,
775 event->area.width, event->area.height);
776 return FALSE;
777}
778
779static void load_graph_stop (LoadGraph *g) {
780 if (g->timer_index != -1) {
781 gtk_timeout_remove (g->timer_index);
782 g->timer_index = -1;
783 }
784 if (!g)
785 return;
786 g->draw = FALSE;
787}
788
789static void load_graph_destroy(GtkWidget *widget,
790 gpointer data_ptr) {
791 LoadGraph *g = (LoadGraph *) data_ptr;
792 load_graph_stop(g);
793 if (g->timer_index != -1)
794 gtk_timeout_remove (g->timer_index);
795 if (g->sock != NULL)
796 releaseClientSocket(g->sock);
797 load_graph_unalloc(g);
798 FREE(g->colors);
799 FREE(g);
800}
801
802static LoadGraph * load_graph_new(ProcData *procdata) {
803 LoadGraph *g;
804 unsigned int i;
805
806 if ( (procdata->statIdx < 0) ||
807 (procdata->statIdx >= STATS_COUNT) ) {
808 BREAK();
809 return NULL;
810 }
811 if (stats[procdata->statIdx].count > MAX_COLOR) {
812 BREAK();
813 return NULL;
814 }
815
816 g = MALLOC(sizeof(LoadGraph));
817 g->sock = getClientSocket();
818 g->statIdx = procdata->statIdx;
819 g->count = stats[g->statIdx].count;
820 g->speed = procdata->config.graph_update_interval;
821 g->num_points = 600;
822 g->colors = MALLOC(sizeof(GdkColor) * (2+g->count));
823 g->colors[0] = procdata->config.bg_color;
824 g->colors[1] = procdata->config.frame_color;
825 for (i=0;i<g->count;i++)
826 g->colors[2+i] = procdata->config.mem_color[i];
827 g->timer_index = -1;
828 g->draw = FALSE;
829 g->main_widget = gtk_vbox_new (FALSE, FALSE);
830 gtk_widget_show (g->main_widget);
831 g->disp = gtk_drawing_area_new();
832 gtk_widget_show (g->disp);
833 gtk_signal_connect (GTK_OBJECT (g->disp),
834 "expose_event",
835 GTK_SIGNAL_FUNC (load_graph_expose), g);
836 gtk_signal_connect (GTK_OBJECT(g->disp),
837 "configure_event",
838 GTK_SIGNAL_FUNC (load_graph_configure), g);
839 gtk_signal_connect (GTK_OBJECT(g->disp),
840 "destroy",
841 GTK_SIGNAL_FUNC (load_graph_destroy), g);
842 gtk_widget_add_events(g->disp, GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK);
843 gtk_box_pack_start(GTK_BOX (g->main_widget), g->disp, TRUE, TRUE, 0);
844 load_graph_alloc(g);
845 gtk_widget_show_all (g->main_widget);
846 g->timer_index = gtk_timeout_add(g->speed,
847 (GtkFunction) load_graph_update, g);
848
849 return g;
850}
851
852static void load_graph_start(LoadGraph *g) {
853 if (!g)
854 return;
855
856 if (g->timer_index == -1)
857 g->timer_index = gtk_timeout_add(g->speed,
858 (GtkFunction) load_graph_update, g);
859
860 g->draw = TRUE;
861}
862
863static GtkWidget * create_sys_view(ProcData * procdata) {
864 GtkWidget * mem_frame;
865 LoadGraph * mem_graph;
866
867 mem_graph = load_graph_new(procdata);
868 procdata->mem_graph = mem_graph;
869 if (mem_graph == NULL)
870 return NULL; /* oops */
871 mem_frame = gtk_frame_new(_(stats[procdata->statIdx].frameName));
872 gtk_container_add(GTK_CONTAINER(mem_frame),
873 mem_graph->main_widget);
874 gtk_container_set_border_width(GTK_CONTAINER(mem_graph->main_widget),
875 GNOME_PAD_SMALL);
876 gtk_container_set_border_width (GTK_CONTAINER(mem_frame),
877 GNOME_PAD_SMALL);
878 gtk_widget_show(mem_frame);
879 addClosePopupMenu(mem_frame);
880 return mem_frame;
881}
882
883
884static GtkWidget * create_main_window(int stat) {
885 GtkWidget *sys_box;
886 ProcData procdata;
887
888
889 memset(&procdata, 0, sizeof(ProcData));
890 procdata.config.graph_update_interval
891 = UPDATE_INTERVAL / cronMILLIS;
892 procdata.statIdx = stat;
893 gdk_color_parse("black",
894 &procdata.config.bg_color);
895 gdk_color_parse("gray",
896 &procdata.config.frame_color);
897 gdk_color_parse("red",
898 &procdata.config.mem_color[0]);
899 gdk_color_parse("green",
900 &procdata.config.mem_color[1]);
901 gdk_color_parse("yellow",
902 &procdata.config.mem_color[2]);
903 gdk_color_parse("blue",
904 &procdata.config.mem_color[3]);
905 GNUNET_ASSERT(MAX_COLOR == 4);
906 sys_box = create_sys_view(&procdata);
907 if (sys_box == NULL)
908 return NULL;
909 load_graph_start(procdata.mem_graph);
910 return sys_box;
911}
912
913
914/**
915 * Display the statistics.
916 */
917void displayStatistics(GtkWidget * widget,
918 gpointer data) {
919 int dptr;
920 GtkWidget * wid;
921
922 dptr = (int) data;
923 if ( (dptr < 0) ||
924 (dptr >= STATS_COUNT) ) {
925 BREAK();
926 } else {
927 wid = create_main_window(dptr);
928 if (wid != NULL)
929 addToNotebook(_(stats[dptr].paneName),
930 wid);
931 }
932}
933
934void initGTKStatistics() {
935 MUTEX_CREATE_RECURSIVE(&lock);
936}
937
938void doneGTKStatistics() {
939 unsigned int i;
940 for (i=0;i<lsv_size;i++)
941 FREE(lastStatValues[i].statName);
942 GROW(lastStatValues,
943 lsv_size,
944 0);
945 MUTEX_DESTROY(&lock);
946}
947
948
949/* end of statistics.c */