summaryrefslogtreecommitdiff
path: root/src/summary-view.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/summary-view.c')
-rw-r--r--src/summary-view.c181
1 files changed, 174 insertions, 7 deletions
diff --git a/src/summary-view.c b/src/summary-view.c
index 5e962b8..15f0dd5 100644
--- a/src/summary-view.c
+++ b/src/summary-view.c
@@ -27,6 +27,10 @@
#include "allocators.h"
#include "summary.h"
+#ifndef _
+#define _(x) x
+#endif
+
typedef struct _summary_view {
GtkTreeView tv;
} SummaryView;
@@ -109,6 +113,86 @@ summary_view_button_press (GtkWidget *widget, GdkEventButton *ev)
return ret;
}
+#define BULLET "•"
+
+static void
+pie_chart_shape_renderer (cairo_t *cr,
+ PangoAttrShape *attr,
+ gboolean do_path,
+ gpointer data)
+{
+ gint angle1 = GPOINTER_TO_INT (attr->data) & 1023;
+ gint angle2 = GPOINTER_TO_INT (attr->data) / 1024;
+ double x, y;
+
+ if (do_path)
+ return;
+
+ cairo_get_current_point (cr, &x, &y);
+
+ cairo_new_sub_path (cr);
+ cairo_arc (cr,
+ x + 0.5 / PANGO_SCALE * attr->logical_rect.width,
+ y - 0.5 / PANGO_SCALE * attr->logical_rect.height,
+ .5 / PANGO_SCALE * MIN (attr->ink_rect.width, attr->ink_rect.height - 1),
+ 0, 2 * G_PI);
+ cairo_set_line_width (cr, 1.);
+ cairo_stroke (cr);
+
+ cairo_move_to (cr,
+ x + 0.5 / PANGO_SCALE * attr->logical_rect.width,
+ y - 0.5 / PANGO_SCALE * attr->logical_rect.height);
+ cairo_arc (cr,
+ x + 0.5 / PANGO_SCALE * attr->logical_rect.width,
+ y - 0.5 / PANGO_SCALE * attr->logical_rect.height,
+ .5 / PANGO_SCALE * MIN (attr->ink_rect.width, attr->ink_rect.height),
+ -G_PI/2, -G_PI/2 + 2 * G_PI * angle2 / 1024.);
+ cairo_fill (cr);
+
+ cairo_move_to (cr,
+ x + 0.5 / PANGO_SCALE * attr->logical_rect.width,
+ y - 0.5 / PANGO_SCALE * attr->logical_rect.height);
+ cairo_arc (cr,
+ x + 0.5 / PANGO_SCALE * attr->logical_rect.width,
+ y - 0.5 / PANGO_SCALE * attr->logical_rect.height,
+ .25 / PANGO_SCALE * MIN (attr->ink_rect.width, attr->ink_rect.height),
+ -G_PI/2, -G_PI/2 + 2 * G_PI * angle1 / 1024.);
+ cairo_set_source_rgb (cr, .5, .5, .5);
+ cairo_fill (cr);
+
+}
+
+static gboolean
+label_show_layout (GtkWidget *widget, GdkEventExpose *ev)
+{
+ cairo_t *cr;
+ gint x,y;
+
+ cr = gdk_cairo_create (widget->window);
+ gdk_cairo_region (cr, ev->region);
+ cairo_clip (cr);
+
+ gtk_label_get_layout_offsets (GTK_LABEL (widget), &x, &y);
+ cairo_move_to (cr, x, y);
+
+ pango_cairo_show_layout (cr, gtk_label_get_layout (GTK_LABEL (widget)));
+ cairo_destroy (cr);
+
+ return TRUE;
+}
+
+static GSList *
+_sum_allocators_get_allocators (struct _sum_allocator *sum)
+{
+ GSList *l, *list = NULL;
+ guint n;
+ for (n = 0; n < G_N_ELEMENTS (sum->ht); n++) {
+ for (l = sum->ht[n]; l != NULL; l = g_slist_next (l))
+ list = g_slist_prepend (list, l->data);
+ }
+ return list;
+}
+
static gboolean
summary_view_query_tooltip (GtkWidget *widget,
gint x,
@@ -118,17 +202,24 @@ summary_view_query_tooltip (GtkWidget *widget,
{
SummaryView * self = (SummaryView *) widget;
GtkTreeModel *model = gtk_tree_view_get_model (&self->tv);
+ GtkWidget *label;
GtkTreePath *path;
GtkTreeViewColumn *column;
GtkTreeIter iter;
+ PangoAttrList *attrs;
+ PangoRectangle ink_rect, logical_rect;
+ PangoLayout *layout;
gint cell_x, cell_y;
struct _sum_allocator *sum;
- Allocator *A;
+ const Allocator *A;
+ GSList *list;
+ guint last_allocs;
GString *string;
const gchar *main_fn;
- guint n, m, depth;
+ guint n, m, i, depth, n_allocs;
const gchar *last;
- gchar *text;
+ gint fraction[NUM_CALLERS];
+ gchar *text, *p;
gchar calls[80];
gint len;
@@ -151,31 +242,69 @@ summary_view_query_tooltip (GtkWidget *widget,
return FALSE;
A = sum->largest;
+
+ n_allocs = A->time_tail->n_allocs;
+ if (! allocators_store_is_cumulative ((AllocatorsStore *) model) &&
+ A->time_tail->prev)
+ {
+ n_allocs -= A->time_tail->freed;
+ }
+
string = g_string_new ("Most frequent allocation callsite, ");
- len = g_snprintf (calls + 40, 40, "%u", A->time_tail->n_allocs);
+ len = g_snprintf (calls + 40, 40, "%u", n_allocs);
pretty_print_number (calls + 40, len, calls);
g_string_append (string, calls);
g_string_append_printf (string, " calls (%.1f%%)",
- A->time_tail->n_allocs * 100. / sum->count);
+ n_allocs * 100. / sum->count);
for (n = 0; n < A->n_frames; n++)
if (A->frames[n]->function == A->alloc_fn)
break;
depth = n;
+ list = _sum_allocators_get_allocators (sum);
main_fn = app_get_main_function (app_get (widget));
last = NULL;
+ last_allocs = 0;
+ i = 0;
for (m = n; m < MIN (n + NUM_CALLERS, A->n_frames); m++) {
if (A->frames[m]->function_srcloc != last) {
+ GSList *l, *next, **prev;
+ guint this_allocs = 0;
+ for (l = list, prev = &list; l != NULL; l = next) {
+ const Allocator *AA = l->data;
+ next = g_slist_next (l);
+ if (A->frames[m] != AA->frames[m]) {
+ g_slist_free1 (l);
+ *prev = next;
+ } else {
+ n_allocs = AA->time_tail->n_allocs;
+ if (! allocators_store_is_cumulative ((AllocatorsStore *) model) &&
+ AA->time_tail->prev)
+ {
+ n_allocs -= AA->time_tail->freed;
+ }
+ this_allocs += n_allocs;
+ prev = &l->next;
+ }
+ }
g_string_append_c (string, '\n');
g_string_append_c (string, '\t');
+ g_string_append (string, BULLET);
+ g_string_append_c (string, '\t');
g_string_append (string, A->frames[m]->function_srcloc);
+ fraction[i] = (this_allocs * 1024 / sum->count) << 10;
+ if (last_allocs)
+ fraction[i] |= this_allocs * 1024 / last_allocs - this_allocs / last_allocs;
+ i++;
last = A->frames[m]->function_srcloc;
+ last_allocs = this_allocs;
} else
n++;
if (A->frames[m]->function == main_fn)
break;
}
+ g_slist_free (list);
g_string_append (string, "\n\nAllocation stack:");
last = NULL;
@@ -188,8 +317,44 @@ summary_view_query_tooltip (GtkWidget *widget,
}
}
+
text = g_string_free (string, FALSE);
- gtk_tooltip_set_text (tooltip, text);
+ label = gtk_label_new (text);
+
+ layout = gtk_widget_create_pango_layout (label, "O");
+ pango_layout_get_extents (layout, NULL, &logical_rect);
+ ink_rect.x = 1;
+ ink_rect.y = -logical_rect.height + 1;
+ ink_rect.width = logical_rect.height - 2;
+ ink_rect.height = logical_rect.height - 2;
+ logical_rect.x = 0;
+ logical_rect.y = -logical_rect.height;
+ logical_rect.width = logical_rect.width;
+ g_object_unref (layout);
+
+ g_signal_connect (label, "expose-event",
+ G_CALLBACK (label_show_layout), NULL);
+ pango_cairo_context_set_shape_renderer (
+ gtk_widget_get_pango_context (label),
+ pie_chart_shape_renderer,
+ NULL, NULL);
+ attrs = pango_attr_list_new ();
+ i = 0;
+ for (p = text; (p = strstr (p, BULLET)); p += strlen (BULLET)) {
+ PangoAttribute *attr;
+
+ attr = pango_attr_shape_new_with_data (&ink_rect,
+ &logical_rect,
+ GINT_TO_POINTER (fraction[i++]),
+ NULL, NULL);
+ attr->start_index = p - text;
+ attr->end_index = attr->start_index + strlen (BULLET);
+
+ pango_attr_list_insert (attrs, attr);
+ }
+ gtk_label_set_attributes (GTK_LABEL (label), attrs);
+ pango_attr_list_unref (attrs);
+ gtk_tooltip_set_custom (tooltip, label);
g_free (text);
return TRUE;
@@ -288,5 +453,7 @@ summary_view_init (SummaryView *self)
GtkWidget *
summary_view_new (AllocatorsStore *store)
{
- return g_object_new (summary_view_get_type (), "model", store, NULL);
+ return g_object_new (summary_view_get_type (),
+ "model", store,
+ NULL);
}