summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2008-04-28 22:44:13 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2008-04-28 22:44:13 +0100
commit648a14ae1b2e830c6cd588224abed08b32407e8d (patch)
tree117c3d576b9934b1ecb0731630fe49e156b7b5cf
parent845ae9bc7d895f0a264d20d4049e95a8b86e5bcd (diff)
Show fractions of callstack in tooltip.
-rw-r--r--src/summary-chart.c71
-rw-r--r--src/summary-view.c144
-rw-r--r--src/summary.c117
-rw-r--r--src/summary.h5
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 */