gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] r18501 - in gnunet-gtk: contrib src/statistics


From: gnunet
Subject: [GNUnet-SVN] r18501 - in gnunet-gtk: contrib src/statistics
Date: Wed, 7 Dec 2011 23:03:34 +0100

Author: grothoff
Date: 2011-12-07 23:03:34 +0100 (Wed, 07 Dec 2011)
New Revision: 18501

Modified:
   gnunet-gtk/contrib/gnunet_statistics_gtk_main_window.glade
   gnunet-gtk/src/statistics/gnunet-statistics-gtk.c
Log:
-towards gnunet-statistics-gtk

Modified: gnunet-gtk/contrib/gnunet_statistics_gtk_main_window.glade
===================================================================
--- gnunet-gtk/contrib/gnunet_statistics_gtk_main_window.glade  2011-12-07 
21:27:12 UTC (rev 18500)
+++ gnunet-gtk/contrib/gnunet_statistics_gtk_main_window.glade  2011-12-07 
22:03:34 UTC (rev 18501)
@@ -2,24 +2,6 @@
 <interface>
   <requires lib="gtk+" version="2.20"/>
   <!-- interface-naming-policy project-wide -->
-  <object class="GtkListStore" id="GNUNET_STATISTICS_GTK_list_store">
-    <columns>
-      <!-- column-name peer_identity -->
-      <column type="gchararray"/>
-      <!-- column-name number_of_known_addresses -->
-      <column type="guint"/>
-      <!-- column-name country_name -->
-      <column type="gchararray"/>
-      <!-- column-name country_flag -->
-      <column type="GdkPixbuf"/>
-      <!-- column-name bandwidth_in -->
-      <column type="guint64"/>
-      <!-- column-name bandwidth_out -->
-      <column type="guint64"/>
-      <!-- column-name addresses -->
-      <column type="gchararray"/>
-    </columns>
-  </object>
   <object class="GtkWindow" id="GNUNET_STATISTICS_GTK_main_window">
     <property name="title" translatable="yes">gnunet-statistics-gtk</property>
     <property name="window_position">center</property>
@@ -68,9 +50,10 @@
             <property name="visible">True</property>
             <property name="can_focus">True</property>
             <child>
-              <object class="GtkImage" 
id="GNUNET_STATISTICS_GTK_main_notebook_connectivity_image">
+              <object class="GtkDrawingArea" 
id="GNUNET_STATISTICS_GTK_main_notebook_connectivity_drawingarea">
                 <property name="visible">True</property>
-                <property name="stock">gtk-missing-image</property>
+                <signal name="expose_event" 
handler="GNUNET_STATISTICS_connection_graph_expose"/>
+                <signal name="configure_event" 
handler="GNUNET_STATISTICS_connection_graph_configure"/>
               </object>
             </child>
             <child type="tab">
@@ -84,9 +67,8 @@
               </packing>
             </child>
             <child>
-              <object class="GtkImage" 
id="GNUNET_STATISTICS_GTK_main_notebook_traffic_image">
+              <object class="GtkDrawingArea" 
id="GNUNET_STATISTICS_GTK_main_notebook_traffic_drawingarea">
                 <property name="visible">True</property>
-                <property name="stock">gtk-missing-image</property>
               </object>
               <packing>
                 <property name="position">1</property>
@@ -104,9 +86,8 @@
               </packing>
             </child>
             <child>
-              <object class="GtkImage" 
id="GNUNET_STATISTICS_GTK_main_notebook_storage_image">
+              <object class="GtkDrawingArea" 
id="GNUNET_STATISTICS_GTK_main_notebook_storage_drawingarea">
                 <property name="visible">True</property>
-                <property name="stock">gtk-missing-image</property>
               </object>
               <packing>
                 <property name="position">2</property>
@@ -131,16 +112,4 @@
       </object>
     </child>
   </object>
-  <object class="GtkAdjustment" id="adjustment3">
-    <property name="upper">100</property>
-    <property name="step_increment">1</property>
-    <property name="page_increment">10</property>
-    <property name="page_size">10</property>
-  </object>
-  <object class="GtkAdjustment" id="adjustment4">
-    <property name="upper">100</property>
-    <property name="step_increment">1</property>
-    <property name="page_increment">10</property>
-    <property name="page_size">10</property>
-  </object>
 </interface>

Modified: gnunet-gtk/src/statistics/gnunet-statistics-gtk.c
===================================================================
--- gnunet-gtk/src/statistics/gnunet-statistics-gtk.c   2011-12-07 21:27:12 UTC 
(rev 18500)
+++ gnunet-gtk/src/statistics/gnunet-statistics-gtk.c   2011-12-07 22:03:34 UTC 
(rev 18501)
@@ -24,20 +24,87 @@
  * @author Christian Grothoff
  */
 #include "gnunet_gtk.h"
+
+#include <gnunet/gnunet_util_lib.h>
 #include <gnunet/gnunet_statistics_service.h>
 
+#define MAX_HISTORY 1280
 
+
 /**
- * Information we track for each peer outside of the model.
+ * Information about a value we received.
  */
-struct Statistics
+struct HistoricValue
 {
+  /**
+   * A value we recorded.
+   */
+  uint64_t value;
 
+  /**
+   * Time when the value was recorded.
+   */
+  struct GNUNET_TIME_Absolute timestamp;
+};
 
+
+/**
+ * Historic information we recorded for a value.
+ */
+struct ValueHistory
+{
+
+  /**
+   * Name of the subsystem.
+   */
+  char *subsystem;
+
+  /**
+   * Name of the statistic.
+   */
+  char *name;
+
+  /**
+   * Recent values for this number.
+   */
+  struct HistoricValue history[MAX_HISTORY];
+
+  /**
+   * Last offset we wrote to in history.
+   */
+  unsigned int last_history_offset;
+
+  /**
+   * Number of valid entries in the history.
+   */
+  unsigned int history_size;
 };
 
 
 /**
+ * Information about how to plot certain values.
+ */
+struct PlotInfo
+{
+  /**
+   * Subsystem originating the value to plot.
+   */
+  const char *subsystem;
+
+  /**
+   * Name of the value to plot.
+   */
+  const char *name;
+
+  /**
+   * Name of color to use when plotting.
+   */
+  const char *color_name;
+  
+};
+
+
+/**
  * Handle to our main loop.
  */
 static struct GNUNET_GTK_MainLoop *ml;
@@ -52,19 +119,111 @@
  */
 static struct GNUNET_STATISTICS_Handle *statistics;
 
+/**
+ * Map from keys (subsystem+value) to 'struct ValueHistory'.
+ */
+static struct GNUNET_CONTAINER_MultiHashMap *stat_map;
 
+/**
+ * Task that refreshes connection graphic.
+ */
+static GNUNET_SCHEDULER_TaskIdentifier connection_task;
 
 /**
- * Get cfg.
+ * Pixmap where we have the connection image.
  */
-static const struct GNUNET_CONFIGURATION_Handle *
-get_configuration ()
+static GdkPixmap *connection_pixmap;
+
+/**
+ * How often do we refresh?
+ */
+static struct GNUNET_TIME_Relative refresh_delay;
+
+
+/**
+ * Obtain key for 'stat_map' for a given subsystem and name.
+ *
+ * @param subsystem subsystem
+ * @param name name
+ * @param key set to the hash map key
+ */
+static void
+get_key (const char *subsystem,
+        const char *name,
+        GNUNET_HashCode *key)
 {
-  return GNUNET_GTK_main_loop_get_configuration (ml);
+  GNUNET_HashCode h1;
+  GNUNET_HashCode h2;
+  
+  GNUNET_CRYPTO_hash (subsystem, strlen(subsystem), &h1);
+  GNUNET_CRYPTO_hash (name, strlen(name), &h2);
+  GNUNET_CRYPTO_hash_xor (&h1, &h2, key);
 }
 
 
 /**
+ * Callback function to process statistic values.
+ *
+ * @param cls the 'struct ValueHistory' to update
+ * @param subsystem name of subsystem that created the statistic
+ * @param name the name of the datum
+ * @param value the current value
+ * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not
+ * @return GNUNET_OK to continue
+ */
+static int 
+process_value_update (void *cls, const char *subsystem,
+                     const char *name, uint64_t value,
+                     int is_persistent)
+{
+  struct ValueHistory *vh = cls;
+  GNUNET_HashCode key;
+
+  get_key (subsystem, name, &key);
+  if (++vh->last_history_offset == MAX_HISTORY)
+    vh->last_history_offset = 0;
+  if (vh->history_size < MAX_HISTORY)
+    vh->history_size++;
+  vh->history[vh->last_history_offset].value = value;
+  vh->history[vh->last_history_offset].timestamp = GNUNET_TIME_absolute_get 
();  
+  return GNUNET_OK;
+}
+
+
+/**
+ * Begin monitoring a particular value.
+ *
+ * @param subsystem name of subsystem that created the statistic
+ * @param name the name of the datum
+ */
+static void
+monitor (const char *subsystem,
+        const char *name)
+{
+  GNUNET_HashCode key;
+  struct ValueHistory *vh;
+
+  get_key (subsystem, name, &key);
+  vh = GNUNET_CONTAINER_multihashmap_get (stat_map, &key);
+  if (NULL != vh)
+    return;
+  vh = GNUNET_malloc (sizeof (struct ValueHistory));
+  vh->subsystem = GNUNET_strdup (subsystem);
+  vh->name = GNUNET_strdup (name);
+  GNUNET_assert (GNUNET_OK ==
+                GNUNET_CONTAINER_multihashmap_put (stat_map,
+                                                   &key,
+                                                   vh,
+                                                   
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
+  GNUNET_STATISTICS_watch (statistics,
+                          subsystem,
+                          name,
+                          &process_value_update,
+                          vh);
+}
+
+
+/**
  * Get an object from the main window.
  *
  * @param name name of the object
@@ -78,6 +237,179 @@
 
 
 /**
+ * Actually draw a plot based on collected data.
+ *
+ * @param widget size and style information for the plot
+ * @param info what to draw
+ * @return pixmap with the drawing
+ */
+static GdkPixmap *
+create_plot (GtkWidget *widget,
+            const struct PlotInfo *info)
+{
+  GdkPixmap *ret;
+  GdkGC *gc;
+  unsigned int i;
+  GNUNET_HashCode key;
+  struct ValueHistory *vh;
+  GdkColor color;
+  GdkColormap *colormap;
+
+  ret = gdk_pixmap_new (widget->window,
+                       widget->allocation.width,
+                       widget->allocation.height,
+                       gtk_widget_get_visual (widget)->depth);
+  colormap = gdk_window_get_colormap (widget->window);
+  gc = gdk_gc_new (widget->window);
+  gdk_gc_copy (gc, widget->style->white_gc);
+  gdk_color_parse ("black", &color);
+  gdk_colormap_alloc_color (colormap, &color, TRUE, TRUE);
+  gdk_gc_set_foreground (gc, &color);
+  gdk_draw_rectangle (GDK_DRAWABLE (ret),
+                      widget->style->black_gc,
+                      TRUE, 0, 0,
+                      widget->allocation.width, 
+                     widget->allocation.height);
+  for (i=0; NULL != info[i].subsystem; i++)
+  {
+    get_key (info[i].subsystem, info[i].name, &key);
+    vh = GNUNET_CONTAINER_multihashmap_get (stat_map, &key);
+    if (NULL == vh)
+      continue;
+    gdk_color_parse (info[i].color_name, &color);
+    gdk_colormap_alloc_color (colormap, &color, TRUE, TRUE);
+    gdk_gc_set_foreground (gc, &color);
+    
+    
+
+  }
+
+  // FIXME
+  return ret;
+}
+
+
+/**
+ * Redraw the 'connection_pixmap'.
+ *
+ * @param widget where to render it to in the end (also for size to use)
+ */
+static void
+plot_connection_graph (GtkWidget *widget)
+{
+  static const struct PlotInfo connection_data[] = 
+    {
+      { "core", "entries in session map", "white" },
+      { NULL, NULL, NULL}
+    };
+  if (NULL != connection_pixmap)
+  {
+    gdk_pixmap_unref (connection_pixmap);
+    connection_pixmap = NULL;
+  }
+  connection_pixmap = create_plot (widget,
+                                  connection_data);
+}
+
+
+/**
+ * Part of the connection graph got re-exposed; refresh the area.
+ *
+ * @param widget the drawing area of the connection graph
+ * @param event expose event
+ * @param data_ptr unused
+ * @return FALSE
+ */
+gint
+GNUNET_STATISTICS_connection_graph_expose (GtkWidget * widget,
+                                          GdkEventExpose * event, 
+                                          gpointer data_ptr)
+{
+  gdk_draw_pixmap (widget->window,
+                   widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
+                   connection_pixmap,
+                   event->area.x, event->area.y,
+                   event->area.x, event->area.y,
+                   event->area.width, event->area.height);
+  return FALSE;
+}
+
+
+/**
+ * The window size was changed, forcing us to re-draw the connection
+ * graph.
+ *
+ * @param widget the drawing area of the connection graph
+ * @param event configure event
+ * @param data_ptr unused
+ * @return TRUE
+ */
+gint
+GNUNET_STATISTICS_connection_graph_configure (GtkWidget * widget,
+                                             GdkEventConfigure * event, 
+                                             gpointer data_ptr)
+{
+  plot_connection_graph (widget);
+  gdk_draw_pixmap (widget->window,
+                   widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
+                   connection_pixmap,
+                   0, 0,
+                   0, 0,
+                   widget->allocation.width, widget->allocation.height);
+  return TRUE;
+}
+
+
+/**
+ * Refresh the 'connections' graphic.
+ *
+ * @param cls closure
+ * @param tc scheduler context
+ */
+static void
+refresh_connections (void *cls,
+                    const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  GtkWidget *area;
+
+  connection_task = GNUNET_SCHEDULER_add_delayed (refresh_delay,
+                                                 &refresh_connections,
+                                                 NULL);
+  area = GTK_WIDGET (get_object 
("GNUNET_STATISTICS_GTK_main_notebook_connectivity_drawingarea"));
+  plot_connection_graph (area);
+  gdk_draw_pixmap (area->window,
+                   area->style->fg_gc[GTK_WIDGET_STATE (area)],
+                   connection_pixmap,
+                   0, 0,
+                   0, 0,
+                   area->allocation.width, 
+                  area->allocation.height);
+}
+
+
+/**
+ * Free entries in the value history.
+ *
+ * @param cls unused
+ * @param key unused
+ * @param value 'struct ValueHistory' to free
+ * @return GNUNET_OK (continue iteration)
+ */
+static int
+free_history (void *cls,
+             const GNUNET_HashCode *key,
+             void *value)
+{
+  struct ValueHistory *vh = value;
+
+  GNUNET_free (vh->subsystem);
+  GNUNET_free (vh->name);
+  GNUNET_free (vh);
+  return GNUNET_OK;
+}
+
+
+/**
  * Task run on shutdown.
  *
  * @param cls unused
@@ -88,6 +420,9 @@
 {
   GNUNET_STATISTICS_destroy (statistics, GNUNET_NO);
   statistics = NULL;
+  GNUNET_CONTAINER_multihashmap_iterate (stat_map, &free_history, NULL);
+  GNUNET_CONTAINER_multihashmap_destroy (stat_map);
+  stat_map = NULL;
 }
 
 
@@ -99,6 +434,16 @@
 {
   GNUNET_GTK_tray_icon_destroy ();
   GNUNET_GTK_main_loop_quit (ml);
+  if (connection_task != GNUNET_SCHEDULER_NO_TASK)
+  {
+    GNUNET_SCHEDULER_cancel (connection_task);
+    connection_task = GNUNET_SCHEDULER_NO_TASK;
+  }
+  if (NULL != connection_pixmap)
+  {
+    gdk_pixmap_unref (connection_pixmap);
+    connection_pixmap = NULL;
+  }
   GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
 }
 
@@ -110,19 +455,40 @@
 static void
 run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
+  static const struct 
+  { 
+    const char *subsystem; 
+    const char *name; 
+  } moma[] =
+      {
+       { "core", "entries in session map" },
+       { NULL, NULL }
+      };
   GtkWidget *main_window;
+  unsigned int i;
 
   ml = cls;
   statistics = GNUNET_STATISTICS_create ("gnunet-statistics-gtk",
-                                        get_configuration());
+                                        GNUNET_GTK_main_loop_get_configuration 
(ml));
   if (NULL == statistics)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                _("Failed to initiate connection with statistics service\n"));
     return;
   }
+  stat_map = GNUNET_CONTAINER_multihashmap_create (128);
   GNUNET_GTK_set_icon_search_path ();
   GNUNET_GTK_setup_nls ();
+  refresh_delay = GNUNET_TIME_UNIT_SECONDS; /* fixme: make option / cmd-line 
option */
+
+  i = 0;
+  while (moma[i].subsystem != NULL)
+  {
+    monitor (moma[i].subsystem,
+            moma[i].name);
+    i++;
+  }
+  
   /* setup main window */
   main_window = GTK_WIDGET (get_object ("GNUNET_STATISTICS_GTK_main_window"));
   gtk_window_maximize (GTK_WINDOW (main_window));
@@ -130,6 +496,9 @@
                                "gnunet-gtk" /* FIXME: different icon? */ ,
                                "gnunet-statistics-gtk");
 
+  /* FIXME: only schedule this task if the respective tab is open!? */
+  connection_task = GNUNET_SCHEDULER_add_now (&refresh_connections, NULL);
+
   /* make GUI visible */
   if (!tray_only)
   {




reply via email to

[Prev in Thread] Current Thread [Next in Thread]