[sysprof/wip/chergert/mem-preload] memprof: more rendering work on visualizer
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [sysprof/wip/chergert/mem-preload] memprof: more rendering work on visualizer
- Date: Thu, 6 Feb 2020 22:15:46 +0000 (UTC)
commit 3d0f89edaaaa72573e6edd6bb74e22339ea47b0a
Author: Christian Hergert <chergert redhat com>
Date: Thu Feb 6 14:15:32 2020 -0800
memprof: more rendering work on visualizer
src/libsysprof-ui/sysprof-memprof-visualizer.c | 128 ++++++++++++++++++-------
1 file changed, 94 insertions(+), 34 deletions(-)
---
diff --git a/src/libsysprof-ui/sysprof-memprof-visualizer.c b/src/libsysprof-ui/sysprof-memprof-visualizer.c
index 9137d77..4e20753 100644
--- a/src/libsysprof-ui/sysprof-memprof-visualizer.c
+++ b/src/libsysprof-ui/sysprof-memprof-visualizer.c
@@ -22,6 +22,9 @@
#define G_LOG_DOMAIN "sysprof-memprof-visualizer"
+#include <math.h>
+
+#include "sysprof-color-cycle.h"
#include "sysprof-memprof-visualizer.h"
typedef struct
@@ -33,6 +36,7 @@ typedef struct
gint64 duration;
GdkRGBA fg;
GdkRGBA bg;
+ guint scale;
} DrawContext;
struct _SysprofMemprofVisualizer
@@ -99,19 +103,56 @@ sysprof_memprof_visualizer_new (void)
return g_object_new (SYSPROF_TYPE_MEMPROF_VISUALIZER, NULL);
}
+static guint64
+get_max_alloc (SysprofCaptureReader *reader)
+{
+ SysprofCaptureFrameType type;
+ guint64 ret = 0;
+
+ while (sysprof_capture_reader_peek_type (reader, &type))
+ {
+ const SysprofCaptureAllocation *ev;
+
+ if (type == SYSPROF_CAPTURE_FRAME_MEMORY_ALLOC)
+ {
+ if (!(ev = sysprof_capture_reader_read_memory_alloc (reader)))
+ break;
+ }
+ else if (type == SYSPROF_CAPTURE_FRAME_MEMORY_ALLOC)
+ {
+ if (!(ev = sysprof_capture_reader_read_memory_free (reader)))
+ break;
+ }
+ else
+ {
+ if (!sysprof_capture_reader_skip (reader))
+ break;
+ continue;
+ }
+
+ ret = MAX (ret, ev->alloc_size);
+ }
+
+ sysprof_capture_reader_reset (reader);
+
+ return ret;
+}
+
static void
sysprof_memprof_visualizer_draw_worker (GTask *task,
gpointer source_object,
gpointer task_data,
GCancellable *cancellable)
{
+ static const gdouble dashes[] = { 1.0, 2.0 };
DrawContext *draw = task_data;
SysprofCaptureFrameType type;
+ GdkRGBA mid;
cairo_t *cr;
- guint8 *data;
guint counter = 0;
- gint stride;
- gint r, g, b;
+ guint64 max_alloc;
+ gint midpt;
+ gdouble log_max;
g_assert (G_IS_TASK (task));
g_assert (draw != NULL);
@@ -119,34 +160,34 @@ sysprof_memprof_visualizer_draw_worker (GTask *task,
g_assert (draw->reader != NULL);
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+ max_alloc = get_max_alloc (draw->reader);
+ log_max = log10 (max_alloc);
+ midpt = draw->alloc.height / 2;
+
/* Fill background first */
cr = cairo_create (draw->surface);
gdk_cairo_rectangle (cr, &draw->alloc);
gdk_cairo_set_source_rgba (cr, &draw->bg);
cairo_fill (cr);
- cairo_destroy (cr);
- stride = cairo_image_surface_get_stride (draw->surface);
- data = cairo_image_surface_get_data (draw->surface);
+ /* Draw mid-point line */
+ mid = draw->fg;
+ mid.alpha *= 0.4;
+ cairo_set_line_width (cr, 1.0);
+ gdk_cairo_set_source_rgba (cr, &mid);
+ cairo_move_to (cr, 0, midpt);
+ cairo_line_to (cr, draw->alloc.width, midpt);
+ cairo_set_dash (cr, dashes, G_N_ELEMENTS (dashes), 0);
+ cairo_stroke (cr);
- if (data == NULL)
- {
- g_task_return_new_error (task,
- G_IO_ERROR,
- G_IO_ERROR_INVALID_DATA,
- "No data from image surface to access");
- return;
- }
-
- r = draw->fg.red * 255;
- g = draw->fg.green * 255;
- b = draw->fg.blue * 255;
+ /* Setup to draw our pixels */
+ gdk_cairo_set_source_rgba (cr, &draw->fg);
/* Now draw data points */
while (sysprof_capture_reader_peek_type (draw->reader, &type))
{
const SysprofCaptureAllocation *ev;
- guint8 *pptr;
+ gdouble l;
gint x;
gint y;
@@ -154,7 +195,10 @@ sysprof_memprof_visualizer_draw_worker (GTask *task,
if G_UNLIKELY (++counter == 1000)
{
if (g_task_return_error_if_cancelled (task))
- return;
+ {
+ cairo_destroy (cr);
+ return;
+ }
counter = 0;
}
@@ -176,15 +220,21 @@ sysprof_memprof_visualizer_draw_worker (GTask *task,
if (ev == NULL)
break;
+ l = log10 (ev->alloc_size);
+
x = (ev->frame.time - draw->begin_time) / (gdouble)draw->duration * draw->alloc.width;
- y = 0;
+ y = midpt - ((l / log_max) * midpt);
- pptr = data + ((stride * y) + (x * 3));
- pptr[0] = r;
- pptr[1] = g;
- pptr[2] = b;
+ /* Fill immediately instead of batching draws so that
+ * we don't take a lot of memory to hold on to the
+ * path while drawing.
+ */
+ cairo_rectangle (cr, x, y, 1, 1);
+ cairo_fill (cr);
}
+ cairo_destroy (cr);
+
g_task_return_boolean (task, TRUE);
}
@@ -217,13 +267,12 @@ draw_finished (GObject *object,
static gboolean
sysprof_memprof_visualizer_begin_draw (SysprofMemprofVisualizer *self)
{
+ g_autoptr(SysprofColorCycle) cycle = NULL;
g_autoptr(GTask) task = NULL;
GtkStyleContext *style_context;
GtkAllocation alloc;
GtkStateFlags state;
DrawContext *draw;
- GdkWindow *window;
- gint scale;
g_assert (SYSPROF_IS_MEMPROF_VISUALIZER (self));
@@ -237,22 +286,34 @@ sysprof_memprof_visualizer_begin_draw (SysprofMemprofVisualizer *self)
alloc.width == 0 || alloc.height == 0)
return G_SOURCE_REMOVE;
+ cycle = sysprof_color_cycle_new ();
+
+ /* Some GPUs (Intel) cannot deal with graphics textures larger than
+ * 8000x8000. So here we are going to cheat a bit and just use that as our
+ * max, and scale when drawing. The biggest issue here is that long term we
+ * need a tiling solution that lets us render lots of tiles and then draw
+ * them as necessary.
+ */
+ if (alloc.width > 8000)
+ alloc.width = 8000;
+
draw = g_atomic_rc_box_new0 (DrawContext);
draw->alloc.width = alloc.width;
draw->alloc.height = alloc.height;
draw->reader = sysprof_capture_reader_copy (self->reader);
draw->begin_time = self->begin_time;
draw->duration = self->duration;
+ draw->scale = gtk_widget_get_scale_factor (GTK_WIDGET (self));
+ sysprof_color_cycle_next (cycle, &draw->fg);
- /* Create a surface to draw to */
- window = gtk_widget_get_window (GTK_WIDGET (self));
- scale = gtk_widget_get_scale_factor (GTK_WIDGET (self));
- draw->surface = gdk_window_create_similar_image_surface (window, CAIRO_FORMAT_RGB24, alloc.width,
alloc.height, scale);
+ draw->surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24,
+ alloc.width * draw->scale,
+ alloc.height * draw->scale);
+ cairo_surface_set_device_scale (draw->surface, draw->scale, draw->scale);
/* Get our styles to render with so we can do off-main-thread */
state = gtk_widget_get_state_flags (GTK_WIDGET (self));
style_context = gtk_widget_get_style_context (GTK_WIDGET (self));
- gtk_style_context_get_color (style_context, state, &draw->fg);
/* Takin the render cost for render_background() isn't worth it on the
* main thread. The main thing we want here is an opaque surface that we
* can quickly draw as a texture when rendering.
@@ -327,7 +388,6 @@ sysprof_memprof_visualizer_draw (GtkWidget *widget,
gtk_widget_get_allocation (widget, &alloc);
cairo_save (cr);
- cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
cairo_rectangle (cr, 0, 0, alloc.width, alloc.height);
/* We might be drawing an updated image in the background, and this
@@ -344,7 +404,7 @@ sysprof_memprof_visualizer_draw (GtkWidget *widget,
}
cairo_set_source_surface (cr, self->surface, 0, 0);
- cairo_fill (cr);
+ cairo_paint (cr);
cairo_restore (cr);
return GDK_EVENT_PROPAGATE;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]