Logo Search packages:      
Sourcecode: jmp version File versions  Download package

heapgraph.c

#include <stdio.h>
#include <stdlib.h>
#include <gtk/gtk.h>
#include <gdk/gdk.h>
#include <jmp.h>
#include <heapgraph.h>
#include <gtkutils.h>

static GtkWidget* drawing_area;
static GdkPixmap* pixmap = NULL;
static GdkGC* green;
static GdkGC* pink;

/** memory usage labels */
static GtkWidget* heap_memory;
static GtkWidget* memory_usage;
static GtkWidget* filtered_memory_usage;

/** this is the list for values, 
 *  even indices = heap values, 
 *  odd indices = currently filtered heap value 
 */
static int* values;

/** We use wrap around so we may start anywhere in the 
 *  above array. 
 */
static int startindex = 0;

/** Current number of values. 0 <= num_values <= width. */
static int num_values = 0;
static int width = 0;
static int height = 0;
static int last_max = 0;

/* Create a new backing pixmap of the appropriate size */
static gint configure_event (GtkWidget         *widget,
                             GdkEventConfigure *event) {
    if (pixmap) {
      g_object_unref (pixmap);
      /* handle better in the future... */
      values = realloc (values, 3 * widget->allocation.width * sizeof (*values));   
    } else {
      values = malloc (3 * widget->allocation.width * sizeof (*values));
    }
    width = widget->allocation.width;
    height = widget->allocation.height;
    startindex = 0;
    num_values = 0;
    last_max = 0;
    
    pixmap = gdk_pixmap_new (widget->window,
                       widget->allocation.width,
                       widget->allocation.height,
                       -1);
    gdk_draw_rectangle (pixmap,
                  widget->style->white_gc,
                  TRUE,
                  0, 0,
                  widget->allocation.width,
                  widget->allocation.height); 
    
    if (green == NULL) {
      GdkColor col;
      GdkColor colp;
      GdkColormap* colmap;
      colmap = gdk_colormap_get_system ();

      green = gdk_gc_new (GDK_DRAWABLE (pixmap));
      col.red = 0; 
      col.green = 65535;
      col.blue = 0;
      col.pixel = -1;
      gdk_colormap_alloc_color (colmap, &col, FALSE, TRUE);
      if (col.pixel != -1) {
          gdk_gc_set_foreground (green, &col);
      } else {
          fprintf (stderr, "Could not allocate green color.");
          g_object_unref (green);
          green = drawing_area->style->bg_gc[GTK_STATE_PRELIGHT];
      }

      pink = gdk_gc_new (GDK_DRAWABLE (pixmap));
      colp.red = 65535; 
      colp.green = 49152;
      colp.blue = 49152;
      colp.pixel = -1;
      gdk_colormap_alloc_color (colmap, &colp, FALSE, TRUE);
      if (colp.pixel != -1) {
          gdk_gc_set_foreground (pink, &colp);
      } else {
          fprintf (stderr, "Could not allocate pink color.");
          g_object_unref (pink);
          pink = drawing_area->style->fg_gc[GTK_STATE_PRELIGHT];
      }
    }    
    return TRUE;
}

/* Redraw the screen from the backing pixmap */
static gint expose_event (GtkWidget      *widget,
                          GdkEventExpose *event) {
    if (event->area.width == 1 || startindex == 0) {
      gdk_draw_drawable (widget->window,
                     widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
                     pixmap,
                     event->area.x, event->area.y,  /* xsrc,  ysrc */
                     event->area.x, event->area.y,  /* xdest, ydest */
                     event->area.width, event->area.height);    
    } else {
      /* TODO verify that sx1, w1 and w2 are correct. 
       *      it seems they are but I am not sure max 
       *      diff is 1 (one) /robo.
       */
      int sx1 = event->area.x + startindex;
      int w1 = event->area.width - sx1;
      int w2 = startindex;
      
      gdk_draw_drawable (widget->window,
                     widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
                     pixmap,
                     sx1, event->area.y,            /* xsrc,  ysrc */
                     event->area.x, event->area.y,  /* xdest, ydest */
                     w1, event->area.height);    
      
      gdk_draw_drawable (widget->window,
                     widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
                     pixmap,
                     0, event->area.y,            /* xsrc,  ysrc */
                     w1, event->area.y,           /* xdest, ydest */
                     w2, event->area.height); 
    }
    return FALSE;
}

/** add a label pair (static text + settable text) to the box */
static void add_label (GtkWidget** l, char* txt, GtkWidget* hbox) {
    GtkWidget* label = gtk_label_new (txt);
    /* set it to zero until we get real values, 
       using "" looks odd and confusing. */
    *l = gtk_label_new (_("0"));  
    gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 5);
    gtk_box_pack_start (GTK_BOX (hbox), *l, FALSE, TRUE, 5);
}

/** build the heap graph widget and return it. */
GtkWidget *get_heap_graph () {
    GtkWidget* vbox;
    GtkWidget* hbox;
    vbox = gtk_vbox_new (FALSE, 0);
    drawing_area = gtk_drawing_area_new ();
    gtk_widget_set_size_request (GTK_WIDGET (drawing_area), 500, 100);
    g_signal_connect (G_OBJECT (drawing_area), "expose_event",
                  G_CALLBACK (expose_event), NULL);
    g_signal_connect (G_OBJECT (drawing_area),"configure_event",
                  G_CALLBACK (configure_event), NULL);    
    gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK | 
                     GDK_LEAVE_NOTIFY_MASK);
    gtk_box_pack_start (GTK_BOX (vbox), drawing_area, TRUE, TRUE, 0);
    hbox = gtk_hbox_new (FALSE, 0);

    add_label (&heap_memory, _("Heap"), hbox);
    gtk_box_pack_start (GTK_BOX (hbox), gtk_vseparator_new (), TRUE, TRUE, 0);
    add_label (&memory_usage, _("Used"), hbox);
    gtk_box_pack_start (GTK_BOX (hbox), gtk_vseparator_new (), TRUE, TRUE, 0);
    add_label (&filtered_memory_usage, _("Filtered"), hbox);

    gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0);
    return vbox;
}

void add_heap_size_value (int current_heap_size, 
                    int current_filtered_heap_size, 
                    jlong heap_size) {
    if (num_values < width) {    
      values[3 * num_values] = current_heap_size;
      values[3 * num_values + 1] = current_filtered_heap_size;
      values[3 * num_values + 2] = (int)heap_size;
      num_values++; 
    } else {
      values[3 * startindex] = current_heap_size;
      values[3 * startindex + 1] = current_filtered_heap_size;
      values[3 * startindex + 2] = (int)heap_size;
      startindex++;
      startindex %= width;
    }
    update_heap_graph ();

    gtk_label_set_text (GTK_LABEL (heap_memory), 
                  format_num (heap_size));
    gtk_label_set_text (GTK_LABEL (memory_usage), 
                  format_num (current_heap_size));
    gtk_label_set_text (GTK_LABEL (filtered_memory_usage), 
                  format_num (current_filtered_heap_size));
}

/** draw one line of data. 
 * @param x the line to draw.
 * @param max the height of the graph.
 */
static void draw_line (int x, int max) {
    int h, f, t;
    h = (int)((double)values[3 * x] * height / max);
    f = (int)((double)values[3 * x + 1] * height / max);
    if (values[3 * x + 2] != 0) {
      t = (int)((double)values[3 * x + 2] * height / max);
      gdk_draw_line (pixmap, drawing_area->style->white_gc,
                   x, 0, x, height - t);
      gdk_draw_line (pixmap, 
                   (pink != NULL ? pink : 
                  drawing_area->style->bg_gc[GTK_STATE_PRELIGHT]),
                   x, height - t, x, height - h);
    } else {
      gdk_draw_line (pixmap, drawing_area->style->white_gc,
                   x, 0, x, height - h);
    }
    gdk_draw_line (pixmap, drawing_area->style->bg_gc[GTK_STATE_SELECTED], 
               x, height - h, x, height - f);
    gdk_draw_line (pixmap, 
               (green != NULL ? green : 
                drawing_area->style->bg_gc[GTK_STATE_PRELIGHT]), 
               x, height - f, x, height);
}

void update_heap_graph () {
    int max = 0;
    int i, x;
    /* find max value... */
    for (i = startindex, x = 0; x < num_values; x++, i++, i %= width) {
      /* if we have a heap size we use that, 
         otherwise we use the alloced size. */
      int h = values[3 * i + 2];
      int t = values[3 * i];
      if (h != 0)
          max = (h > max ? h : max);
      else
          max = (t > max ? t : max);
    }
    
    /* ok, this is not the most efficent way to draw, 
     * but it gets the job done. Whole graph may have to be
     * repainted if we have a different max value...
     * Feel free to improve.. /robo
     */
    if (last_max != max) {
      for (x = 0, i = startindex; x < num_values; x++, i++, i %= width)
          draw_line (i, max);
      gtk_widget_queue_draw_area (drawing_area, 0, 0, num_values, height);
    } else {
      /* start by drawing the new line. The pixmap is used as a ring buffer. */
      i = startindex + num_values - 1;
      i %= width;
      x = num_values - 1;
      draw_line (i, max);
      if (num_values == width) {
          /** have to move whole graph.. */
          gtk_widget_queue_draw_area (drawing_area, 0, 0, num_values, height);          
      } else {
          gtk_widget_queue_draw_area (drawing_area, x, 0, 1, height);   
      }
    }
    last_max = max;
}

/* Emacs Local Variables: */
/* Emacs mode:C */
/* Emacs c-indentation-style:"gnu" */
/* Emacs c-hanging-braces-alist:((brace-list-open)(brace-entry-open)(defun-open after)(substatement-open after)(block-close . c-snug-do-while)(extern-lang-open after)) */
/* Emacs c-cleanup-list:(brace-else-brace brace-elseif-brace space-before-funcall) */
/* Emacs c-basic-offset:4 */
/* Emacs End: */

Generated by  Doxygen 1.6.0   Back to index