diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2008-04-28 22:44:13 +0100 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2008-04-28 22:44:13 +0100 |
commit | 648a14ae1b2e830c6cd588224abed08b32407e8d (patch) | |
tree | 117c3d576b9934b1ecb0731630fe49e156b7b5cf | |
parent | 845ae9bc7d895f0a264d20d4049e95a8b86e5bcd (diff) |
Show fractions of callstack in tooltip.
-rw-r--r-- | src/summary-chart.c | 71 | ||||
-rw-r--r-- | src/summary-view.c | 144 | ||||
-rw-r--r-- | src/summary.c | 117 | ||||
-rw-r--r-- | src/summary.h | 5 |
4 files changed, 220 insertions, 117 deletions
diff --git a/src/summary-chart.c b/src/summary-chart.c index 193252e..4744419 100644 --- a/src/summary-chart.c +++ b/src/summary-chart.c @@ -502,6 +502,18 @@ _summary_chart_get_sum_for_cursor (SummaryChart *self, gint x, gint y) return &self->others; } +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_chart_query_tooltip (GtkWidget *widget, gint x, @@ -511,7 +523,9 @@ summary_chart_query_tooltip (GtkWidget *widget, { SummaryChart *self = (SummaryChart *) widget; struct _sum_allocator *sum; - Allocator *A; + const Allocator *A; + GtkWidget *label; + PangoAttrList *attrs = NULL; GString *string; gchar *text; gchar bytes[160], blocks[80], calls[80]; @@ -539,7 +553,13 @@ summary_chart_query_tooltip (GtkWidget *widget, A = sum->largest; if (A != NULL) { const gchar *main_fn, *last; - guint n, m, depth, n_allocs; + guint n, m, depth, n_allocs, last_allocs = 0; + GSList *list; + PangoRectangle ink_rect, logical_rect; + + ink_rect.x = ink_rect.y = 0; + ink_rect.width = ink_rect.height = 12; + logical_rect = ink_rect; n_allocs = A->time_tail->n_allocs; if (! allocators_store_is_cumulative (self->store) && @@ -561,18 +581,60 @@ summary_chart_query_tooltip (GtkWidget *widget, depth = n; main_fn = app_get_main_function (app_get (widget)); + attrs = pango_attr_list_new (); + list = _sum_allocators_get_allocators (sum); last = NULL; + last_allocs = 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; + gint fraction; + PangoAttribute *attr; + 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 (self->store) && + 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'); + + fraction = (this_allocs * 1024 / sum->count) << 10; + if (last_allocs) + fraction |= this_allocs * 1024 / last_allocs - this_allocs / last_allocs; + attr = pango_attr_shape_new_with_data (&ink_rect, + &logical_rect, + GINT_TO_POINTER (fraction), + NULL, NULL); + attr->start_index = string->len; + g_string_append (string, BULLET); + attr->end_index = string->len; + + g_string_append_c (string, '\t'); g_string_append (string, A->frames[m]->function_srcloc); + + pango_attr_list_insert (attrs, attr); + 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; @@ -587,9 +649,12 @@ summary_chart_query_tooltip (GtkWidget *widget, } text = g_string_free (string, FALSE); - gtk_tooltip_set_text (tooltip, text); + label = summary_tooltip_label (text, attrs); + gtk_tooltip_set_custom (tooltip, label); g_free (text); + pango_attr_list_unref (attrs); + return TRUE; } diff --git a/src/summary-view.c b/src/summary-view.c index 15f0dd5..e24945a 100644 --- a/src/summary-view.c +++ b/src/summary-view.c @@ -113,74 +113,6 @@ 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) { @@ -202,13 +134,12 @@ summary_view_query_tooltip (GtkWidget *widget, { SummaryView * self = (SummaryView *) widget; GtkTreeModel *model = gtk_tree_view_get_model (&self->tv); + PangoRectangle ink_rect, logical_rect; + PangoAttrList *attrs; 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; const Allocator *A; @@ -216,10 +147,10 @@ summary_view_query_tooltip (GtkWidget *widget, guint last_allocs; GString *string; const gchar *main_fn; - guint n, m, i, depth, n_allocs; + guint n, m, depth, n_allocs; const gchar *last; - gint fraction[NUM_CALLERS]; - gchar *text, *p; + gint fraction; + gchar *text; gchar calls[80]; gint len; @@ -262,15 +193,21 @@ summary_view_query_tooltip (GtkWidget *widget, break; depth = n; + ink_rect.x = ink_rect.y = 0; + ink_rect.width = ink_rect.height = 12; + logical_rect = ink_rect; + + attrs = pango_attr_list_new (); 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) { + PangoAttribute *attr; 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); @@ -288,15 +225,26 @@ summary_view_query_tooltip (GtkWidget *widget, prev = &l->next; } } + g_string_append_c (string, '\n'); g_string_append_c (string, '\t'); + + fraction = (this_allocs * 1024 / sum->count) << 10; + if (last_allocs) + fraction |= this_allocs * 1024 / last_allocs - this_allocs / last_allocs; + attr = pango_attr_shape_new_with_data (&ink_rect, + &logical_rect, + GINT_TO_POINTER (fraction), + NULL, NULL); + attr->start_index = string->len; g_string_append (string, BULLET); + attr->end_index = string->len; + 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++; + + pango_attr_list_insert (attrs, attr); + last = A->frames[m]->function_srcloc; last_allocs = this_allocs; } else @@ -319,44 +267,12 @@ summary_view_query_tooltip (GtkWidget *widget, text = g_string_free (string, FALSE); - 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); + label = summary_tooltip_label (text, attrs); gtk_tooltip_set_custom (tooltip, label); g_free (text); + pango_attr_list_unref (attrs); + return TRUE; } diff --git a/src/summary.c b/src/summary.c index 69be7ce..b098149 100644 --- a/src/summary.c +++ b/src/summary.c @@ -218,3 +218,120 @@ summary_update (Summary *summary, Client *client) gtk_widget_queue_draw ((GtkWidget *) summary); /* XXX */ } + + +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; +} + +GtkWidget * +summary_tooltip_label (const gchar *text, PangoAttrList *attrs) +{ + GtkWidget *label; + + label = gtk_label_new (text); + gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_MIDDLE); + gtk_label_set_width_chars (GTK_LABEL (label), 120); + + if (attrs != NULL) { + PangoRectangle ink_rect, logical_rect; + PangoLayout *layout; + PangoAttrIterator *iter; + + 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); + + iter = pango_attr_list_get_iterator (attrs); + do { + PangoAttribute *attr; + + attr = pango_attr_iterator_get (iter, PANGO_ATTR_SHAPE); + if (attr != NULL) { + PangoAttrShape *shape = (PangoAttrShape *) attr; + shape->ink_rect = ink_rect; + shape->logical_rect = logical_rect; + } + } while (pango_attr_iterator_next (iter)); + pango_attr_iterator_destroy (iter); + + /* workaround http://bugzilla.gnome.org/show_bug.cgi?id=437533 */ + 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); + gtk_label_set_attributes (GTK_LABEL (label), attrs); + } + + return label; +} diff --git a/src/summary.h b/src/summary.h index 5537d4a..217e305 100644 --- a/src/summary.h +++ b/src/summary.h @@ -26,10 +26,15 @@ #include "allocators.h" +#define BULLET "•" + GtkWidget * summary_view_new (AllocatorsStore *store); GtkWidget * summary_chart_new (AllocatorsStore *store); +GtkWidget * +summary_tooltip_label (const gchar *text, PangoAttrList *attrs); + #endif /* SUMMARY_H */ |