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

method_window.c

#include <stdio.h>
#include <stdlib.h>
#include <jni.h>
#include <jvmpi.h>
#include <gtk/gtk.h>
#include <gtkutils.h>
#include <hash.h>
#include <jmp.h>
#include <methodlist_menu.h>
#include <comparators.h>
#include <method_window.h>
#include <method.h>
#include <cls.h>
#include <dumper.h>

static GtkWidget* method_window;
static method** methodlist = NULL;
static int methods_count = 0;

static GtkListStore *method_list = NULL;
static int method_list_size = 0;
static GtkWidget *method_statusbar;

static int max_method_rows = 100;


int get_method_rows () {
    return max_method_rows;
}

void set_method_rows (int rows) {
    max_method_rows = rows;
}

/** array of method compare functions... */
static int ((*method_comprs[])(const void* v1, const void* v2)) = { method_compr_class, 
                                                    method_compr_class, 
                                                    method_compr_time, 
                                                    method_compr_calls,
                                                    method_compr_hold_time,
                                                    method_compr_total_time,
                                                    method_compr_total_time_per_call,
                                                    method_compr_objects,
                                                    method_compr_objpercall,
                                                    method_compr_bytes,
};


/** The current method comparator */
static int (*method_compr) (const void* v1, const void* v2) = method_compr_time;

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

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

    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 - Methods"));
    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);
    
    method_list = gtk_list_store_new (MN_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, 
                              G_TYPE_STRING, G_TYPE_LONG, G_TYPE_STRING,
                              G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT, 
                              G_TYPE_STRING, G_TYPE_POINTER);
    
    tree = gtk_tree_view_new_with_model (GTK_TREE_MODEL (method_list));
    add_column (tree, _("Class"), MCLASS_COLUMN, (gpointer)0, method_column_clicked, 200, 0);
    add_column (tree, _("Method"), MMETHOD_NAME_COLUMN, (gpointer)1, method_column_clicked, 200, 0);
    add_column (tree, _("secs"), MSECS_COLUMN, (gpointer)2, method_column_clicked, 80, 1);
    add_column (tree, _("calls"), MCALLS_COLUMN, (gpointer)3, method_column_clicked, 80, 1);
    add_column (tree, _("subs sec"), MSUBS_COLUN, (gpointer)4, method_column_clicked, 80, 1);
    add_column (tree, _("total"), MTOTAL_COLUMN, (gpointer)5, method_column_clicked, 80, 1);
    add_column (tree, _("total/call"), MTOTAL_CALL_COLUMN, (gpointer)6, method_column_clicked, 80, 1);
    add_column (tree, _ ("objects"), MOBJECTS_COLUMN, (gpointer) 7, method_column_clicked, 80, 1);
    add_column (tree, _ ("objs/call"), MOBJSCALL_COLUMN, (gpointer) 8, method_column_clicked, 80, 1);
    add_column (tree, _ ("bytes"), MBYTES_COLUMN, (gpointer) 9, method_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 (mlist_row_changed),
                  method_list);
    gtk_signal_connect (GTK_OBJECT(tree), "button_press_event",
                  GTK_SIGNAL_FUNC (mlist_button_handler), 
                  NULL);

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

    gtk_widget_set_usize (jmpwin, 800, 200);
    gtk_widget_show_all (jmpwin);
    method_window = jmpwin;
}

void setup_method_tracing () {
    if (method_list == NULL)
      build_method_window ();
}

void quit_method_window () {
    if (methodlist)
      free (methodlist);
    methodlist = NULL;
    if (method_window)
      gtk_widget_destroy (method_window);
}

static void get_time_string (char* buf, size_t len, jlong val) {
    jlong jsec = val / 1000000000ll;
    jlong jnsec = (val % 1000000000ll) / 1000;
    snprintf (buf, len, "%lld.%06lld", jsec, jnsec);
}

static long safe_div(long a, int b) {
      if(b>0)
            return a/b;
      return 0;
}

static jlong safe_div_jlong(jlong a, int b) {
      if(b>0)
            return a/b;
      return 0;
}

/** Count the number of methodods that have used any time. */
static void count_methods (void* data) {
    method* m = (method*)data;
    if (!methodtime_is_zero (&m->time_used) &&
      cls_get_filtered (method_get_owner (m)))
      methods_count++;
}

/** Add a row to the gtk CList (update the ui). */
static void add_method_row_to_list (method* m, int row, GtkTreeIter* iter) {
    char sec[64];
    char hsec[64];
    char tsec[64];
    char tsec_call[64];
    methodtime* mt;
    int fast = 0;

    if (row < method_list_size) {
      method* m2;
      gtk_tree_model_get (GTK_TREE_MODEL (method_list), iter, MMETHOD_COLUMN, &m2, -1);
      if (m == m2) {
          if (!method_check_modified (m)) {
            gtk_tree_model_iter_next (GTK_TREE_MODEL (method_list), iter);
            return;
          }
          fast = 1;         
      }
    } else {
      gtk_list_store_append (method_list, iter);
    }

    mt = method_get_time_used (m);
    get_time_string (sec, 64, mt->tv);
    get_time_string (hsec, 64, mt->tv_hold);
    get_time_string (tsec, 64, mt->tv + mt->tv_hold);
    get_time_string (tsec_call, 64, safe_div_jlong(mt->tv + mt->tv_hold, method_get_calls (m)));
    if (fast) {
      gtk_list_store_set (method_list, iter,
                      MSECS_COLUMN, sec,
                      MCALLS_COLUMN, method_get_calls (m),
                      MSUBS_COLUN, hsec,
                      MTOTAL_COLUMN, tsec,
                      MTOTAL_CALL_COLUMN, tsec_call,
                      MOBJECTS_COLUMN, method_get_allocated_objects (m),
                      MOBJSCALL_COLUMN, safe_div(method_get_allocated_objects (m), method_get_calls (m)),
                      MBYTES_COLUMN, format_num (method_get_allocated_memory (m)),
                      -1);
    } else {
      cls* c = method_get_owner (m);
      gtk_list_store_set (method_list, iter,
                      MCLASS_COLUMN, cls_get_name (c),
                      MMETHOD_NAME_COLUMN, method_get_method_jmpname (m),
                      MSECS_COLUMN, sec,
                      MCALLS_COLUMN, method_get_calls (m),
                      MSUBS_COLUN, hsec,
                      MTOTAL_COLUMN, tsec,
                      MMETHOD_COLUMN, m,
                      MTOTAL_CALL_COLUMN, tsec_call,
                      MOBJECTS_COLUMN, method_get_allocated_objects (m),
                      MOBJSCALL_COLUMN, safe_div(method_get_allocated_objects (m), method_get_calls (m)),
                      MBYTES_COLUMN, format_num (method_get_allocated_memory (m)),
                      -1);
    }
    method_set_modified (m, 0);
    gtk_tree_model_iter_next (GTK_TREE_MODEL (method_list), iter);
}

/** Add a row to the array of data. */
static void add_methods_row (void* data) {
    method* m = (method*)data;
    if (!methodtime_is_zero (&m->time_used) && 
      cls_get_filtered (method_get_owner (m)))
      methodlist[methods_count++] = m;
}

void update_method_tree (hashtab* methods) {
    char buf[64];
    int oldcount = methods_count;

    setup_method_tracing ();
    /* update the method list window.. */
    methods_count = 0;
    jmphash_lock (methods);
    jmphash_for_each ((jmphash_iter_f)count_methods, methods);
    if (oldcount != methods_count) {
      methodlist = realloc (methodlist, methods_count * sizeof (method*));
      /* TODO handle NULL here.. */
    }
    methods_count = 0;
    jmphash_for_each ((jmphash_iter_f)add_methods_row, methods);
    jmphash_unlock (methods);
    qsort (methodlist, methods_count, sizeof (method*), method_compr);
    update_tree (method_list, methods_count, max_method_rows, (void**)methodlist, 
             (add_row_func)add_method_row_to_list, method_list_size);
    method_list_size = 
      max_method_rows < methods_count ? max_method_rows : methods_count;
    snprintf (buf, 64, _("Showing %d methods out of %d"), 
            method_list_size, methods_count);
    set_status_internal (method_statusbar, buf, 0);
}

void dump_methods (hashtab* methods, FILE* f) {
    int i;
    int oldcount = 0;
    fprintf (f, "\n\n\nMethods\n");
    fprintf (f, "class name\tmethod\tsec\tcalls\tsubsec\t#alloced instances\t#alloced bytes\n");
    fprintf (f, "--------------------------------------------------------------\n");
    if (methods) {
      oldcount = methods_count;    
      methods_count = 0;
      jmphash_for_each ((jmphash_iter_f)count_methods, methods);
      if (oldcount != methods_count) 
          methodlist = realloc (methodlist, methods_count * sizeof (method*));
      methods_count = 0;
      jmphash_for_each ((jmphash_iter_f)add_methods_row, methods);
      qsort (methodlist, methods_count, sizeof (method*), method_compr);
      for (i = 0; i < methods_count; i++) 
          dump_method_row (methodlist[i], f);
    } else {
      fprintf (stderr, "methods hash is NULL, wont dump it\n");   
    }
}

/* 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