diff options
Diffstat (limited to 'src/summary-view.c')
-rw-r--r-- | src/summary-view.c | 181 |
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); } |