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

class_window.c

#include <stdio.h>
#include <stdlib.h>
#include <jni.h>
#include <jvmpi.h>
#include <gtk/gtk.h>
#include <gtkutils.h>
#include <jmp-config.h>
#include <hash.h>
#include <jmp.h>
#include <ui.h>
#include <cls.h>
#include <classlist_menu.h>
#include <comparators.h>
#include <dumper.h>
#include <class_window.h>
#include <heapgraph.h>

static GtkWidget* class_window;
static cls** classlist = NULL;
static int classes_count = 0;

/** A class to show total numbers in class info window. */
static cls* total = NULL;

static GtkListStore *object_list = NULL;
static int object_list_size = 0;
static GtkWidget *class_statusbar;

static int max_class_rows = 100;

int get_class_rows () {
    return max_class_rows;
}

void set_class_rows (int rows) {
    max_class_rows = rows;
}

/** array of the class compare functions... */
static int ((*cls_comprs[])(const void* v1, const void* v2)) = { cls_compr_name, 
                                                 cls_compr_instance, 
                                                 cls_compr_max_instance, 
                                                 cls_compr_size,
                                                 cls_compr_instance_gc,
                                                 cls_compr_tenure};

/** our current comparator */
static int (*cls_compr) (const void* v1, const void* v2) = cls_compr_size;

static void cls_column_clicked (GtkWidget *treeviewcolumn, gpointer user_data) {
    int column = (int)user_data;
    if (cls_comprs[column] != NULL) {
      if (cls_compr != cls_comprs[column]) {
          cls_compr = cls_comprs[column];
      }
    } else {
      fprintf (stdout, "Sort order not yet implemented.\n");
    }
}

static void build_object_window () {
    GtkWidget *vbox;
    GtkWidget* scroller;
    GtkWidget* tree;
    GtkTreeSelection* select;

    GtkWidget* jmpwin = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    gtk_signal_connect (GTK_OBJECT (jmpwin), "delete_event",
                  GTK_SIGNAL_FUNC (ignore_delete_event), NULL);
    gtk_signal_connect (GTK_OBJECT (jmpwin), "destroy",
                  GTK_SIGNAL_FUNC (destroy), NULL);
    gtk_window_set_title (GTK_WINDOW (jmpwin), _("Java Memory Profiler - Objects"));
    scroller = gtk_scrolled_window_new (NULL, NULL);
    vbox = gtk_vbox_new (FALSE, 0);
    gtk_container_add (GTK_CONTAINER (jmpwin), vbox);
    gtk_box_pack_start (GTK_BOX (vbox), scroller, TRUE, TRUE, 0);

    object_list = gtk_list_store_new (ON_COLUMNS, G_TYPE_STRING, G_TYPE_LONG, 
                              G_TYPE_LONG, G_TYPE_STRING, G_TYPE_LONG, 
                              G_TYPE_DOUBLE, G_TYPE_POINTER);
    
    tree = gtk_tree_view_new_with_model (GTK_TREE_MODEL (object_list));
    add_column (tree, _("Class"), OCLASS_COLUMN, (gpointer)0, cls_column_clicked, 200, 0);
    add_column (tree, _("Instances"), OINSTANCE_COLUMN, (gpointer)1, cls_column_clicked, 80, 1);
    add_column (tree, _("Max instances"), OINSTANCE_MAX_COLUMN, (gpointer)2, cls_column_clicked, 80, 1);
    add_column (tree, _("Size"), OSIZE_COLUMN, (gpointer)3, cls_column_clicked, 80, 1);
    add_column (tree, _("#GC"), OGC_COLUMN, (gpointer)4, cls_column_clicked, 80, 1);
    add_column (tree, _("Tenure"), OTENURE_COLUMN, (gpointer)5, cls_column_clicked, 80, 1);
    gtk_tree_view_set_headers_clickable (GTK_TREE_VIEW (tree), TRUE);
    gtk_container_add (GTK_CONTAINER (scroller), tree);
    select = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree));
    g_signal_connect (G_OBJECT (select), "changed",
                  G_CALLBACK (olist_row_changed),
                  object_list);
    gtk_signal_connect (GTK_OBJECT(tree), "button_press_event",
                  GTK_SIGNAL_FUNC (olist_button_handler), 
                  NULL);

    class_statusbar = gtk_statusbar_new ();
    gtk_box_pack_start (GTK_BOX (vbox), class_statusbar, FALSE, FALSE, 0);

    gtk_widget_set_usize (jmpwin, 550, 200);
    gtk_widget_show_all (jmpwin);
    class_window = jmpwin;
}

void setup_class_tracing () {
    if (total == NULL)
      total = cls_new (_("Total"), _("Total"), NULL, 0, 0, NULL, 0, NULL);
    if (object_list == NULL)
      build_object_window ();
}

void quit_class_window () {
    if (total != NULL)
      cls_free (total);
    if (classlist)
      free (classlist);
    if (class_window)
      gtk_widget_destroy (class_window);    
    total = NULL;
    classlist = NULL;
}

/** Count the number of classes that have more than zero instances. */
static void count_classes (void* data, cls_usage** cu) {
    cls* c = (cls*)data;
    /* fill in filtered class usage.. */
    if (cls_get_instances (c) != 0 && 
      cls_get_filtered (c)) {
      classes_count++;
      cu[0]->totalAlloced += c->usage.totalAlloced;
      cu[0]->totalInstances += c->usage.totalInstances;
      cu[0]->maximumInstances += c->usage.maximumInstances;
      cu[0]->totalGC += c->usage.totalGC;
      cu[0]->totalAllocLevel += c->usage.totalAllocLevel;
    }
    /* fill in heap usage. */
    cu[1]->totalAlloced += c->usage.totalAlloced;
    cu[1]->totalInstances += c->usage.totalInstances;
    cu[1]->maximumInstances += c->usage.maximumInstances;
    cu[1]->totalGC += c->usage.totalGC; 
    cu[1]->totalAllocLevel += c->usage.totalAllocLevel; 
}

/** Add a row to the array of data. */
static void add_class_row (void* data) {
    cls* c = (cls*)data;    
    if (cls_get_instances (c) != 0 && 
      (c == total || cls_get_filtered (c)))
      classlist[classes_count++] = c;
}

static double get_tenure (cls* c) {
    double n = cls_get_instances (c);
    return 
      (get_current_gc_level () * n - cls_get_tenure (c)) / n;
}

/** Add a row to the gtk CList (update the ui). */
static void add_class_row_to_list (cls* c, int row, GtkTreeIter* iter) {
    int fast = 0;

    if (row < object_list_size) {
      cls* c2;
      gtk_tree_model_get (GTK_TREE_MODEL (object_list), iter, OOBJECT_COLUMN, &c2, -1);
      if (c == c2) {
          if (!cls_check_modified (c)) {
            gtk_tree_model_iter_next (GTK_TREE_MODEL (object_list), iter);
            return;
          }
          fast = 1;
      }
    } else {
      gtk_list_store_append (object_list, iter);
    }
    
    if (fast) {
      gtk_list_store_set (object_list, iter,
                      OINSTANCE_COLUMN, cls_get_instances (c),
                      OINSTANCE_MAX_COLUMN, cls_get_max_instances (c),
                      OSIZE_COLUMN, format_num (cls_get_size (c)),
                      OGC_COLUMN, cls_get_total_gc (c),
                      OTENURE_COLUMN, get_tenure (c),
                      -1);
    } else {
      gtk_list_store_set (object_list, iter,
                      OCLASS_COLUMN, cls_get_name (c),
                      OINSTANCE_COLUMN, cls_get_instances (c), 
                      OINSTANCE_MAX_COLUMN, cls_get_max_instances (c),
                      OSIZE_COLUMN, format_num (cls_get_size (c)),
                      OGC_COLUMN, cls_get_total_gc (c),
                      OTENURE_COLUMN, get_tenure (c),
                      OOBJECT_COLUMN, c,
                      -1);
    }
    cls_set_modified (c, 0);
    gtk_tree_model_iter_next (GTK_TREE_MODEL (object_list), iter);
}

static void clear_usage_data (cls_usage **cp) {
    cls_usage* cu = cp[0];
    cls_usage* hu = cp[1];
    
    cu->totalAlloced = 0;
    cu->totalInstances = 0;
    cu->maximumInstances = 0;
    cu->totalGC = 0;
    cu->totalAllocLevel = 0;
    hu->totalAlloced = 0;
    hu->totalInstances = 0;
    hu->maximumInstances = 0;
    hu->totalGC = 0;
    hu->totalAllocLevel = 0;
}

void update_class_tree (hashtab* classes) {
    cls_usage cu, hu;
    cls_usage* cp[2] = {&cu, &hu};
    char buf[64];
    int oldcount = classes_count;    
    classes_count = 0;

    clear_usage_data (cp);
    setup_class_tracing ();
    jmphash_lock (classes);
    jmphash_for_each_with_arg ((jmphash_iter_fa)count_classes, classes, cp); 
    classes_count++;
    add_heap_size_value (hu.totalAlloced, cu.totalAlloced, current_heap_size ());
    total->usage = cu;
    cls_set_modified (total, 1);
    if (oldcount != classes_count) {
      classlist = realloc (classlist, classes_count * sizeof (cls*));
      /* TODO handle NULL here */
    }
    classes_count = 0;
    add_class_row (total);
    jmphash_for_each ((jmphash_iter_f)add_class_row, classes);
    jmphash_unlock (classes);
    qsort (classlist, classes_count, sizeof (cls*), cls_compr); 
    update_tree (object_list, classes_count, max_class_rows, (void**)classlist, 
             (add_row_func)add_class_row_to_list, object_list_size);
    object_list_size = 
      max_class_rows < classes_count ? max_class_rows : classes_count;
    snprintf (buf, 64, _("Showing %d classes out of %d"), 
            object_list_size, classes_count);
    set_status_internal (class_statusbar, buf, 0);
}

void dump_classes (hashtab* classes, FILE* f) {
    int i;
    int oldcount = 0;
    cls_usage cu, hu;
    cls_usage* cp[2] = {&cu, &hu};

    fprintf (f, "\n\n\nClassdump\n");
    fprintf (f, "class_name\t#instaces\tmax #instances\tsize\t#GC\ttenure\n");
    fprintf (f, "--------------------------------------------------------------\n");
    if (classes) {
      classes_count = 0;
      
      clear_usage_data (cp);
      jmphash_for_each_with_arg ((jmphash_iter_fa)count_classes, classes, cp); 
      if (total == NULL) /* we should be synchronized so this wont give duplicates. */
          total = cls_new (_("Total"), _("Total"), NULL, 0, 0, NULL, 0, NULL);          
      total->usage = hu;
      cls_set_modified (total, 1);
      dump_class_row (total, f);
      total->usage = cu;
      cls_set_modified (total, 1);
      dump_class_row (total, f);
      if (oldcount != classes_count) 
          classlist = realloc (classlist, classes_count * sizeof (cls*));
      classes_count = 0;
      jmphash_for_each ((jmphash_iter_f)add_class_row, classes); 
      qsort (classlist, classes_count, sizeof (cls*), cls_compr);
      for (i = 0; i < classes_count; i++) 
          dump_class_row (classlist[i], f);     
    } else {
      fprintf (stderr, "classes hash is NULL, wont dump it\n");
    }
}

Generated by  Doxygen 1.6.0   Back to index