[cairo-commit] 3 commits - configure.ac src/cairo-clip-polygon.c src/cairo-clip-private.h src/cairo-surface-observer.c src/cairo-surface-observer-private.h

Chris Wilson ickle at kemper.freedesktop.org
Thu Aug 18 06:16:11 PDT 2011


 configure.ac                         |    2 
 src/cairo-clip-polygon.c             |   17 
 src/cairo-clip-private.h             |    3 
 src/cairo-surface-observer-private.h |   31 +
 src/cairo-surface-observer.c         |  654 ++++++++++++++++++++++++++++-------
 5 files changed, 582 insertions(+), 125 deletions(-)

New commits:
commit 2f020c4ade1d26a01605cd908bdaa983e7fe1106
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu Aug 18 14:10:20 2011 +0100

    obsever: include the operation timings
    
    Seeing the relative amounts of time spent in each operation and the
    slowest one of each, gives further insight into the peculiarities of a
    trace. And hopefully point out areas of improvement.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/configure.ac b/configure.ac
index 71f8bf3..c7c167e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -622,7 +622,7 @@ dnl ===========================================================================
 
 CAIRO_ENABLE_SURFACE_BACKEND(mime, mime, always)
 CAIRO_ENABLE_SURFACE_BACKEND(recording, recording, always)
-CAIRO_ENABLE_SURFACE_BACKEND(observer, observer, always)
+CAIRO_ENABLE_SURFACE_BACKEND(observer, observer, always, observer_LIBS=-lrt)
 CAIRO_ENABLE_SURFACE_BACKEND(tee, tee, no)
 CAIRO_ENABLE_SURFACE_BACKEND(xml, xml, no, [
     use_xml=$have_libz
diff --git a/src/cairo-surface-observer-private.h b/src/cairo-surface-observer-private.h
index ed05f96..9e18868 100644
--- a/src/cairo-surface-observer-private.h
+++ b/src/cairo-surface-observer-private.h
@@ -70,8 +70,22 @@ struct clip {
 };
 
 typedef struct _cairo_observation cairo_observation_t;
+typedef struct _cairo_observation_record cairo_observation_record_t;
 typedef struct _cairo_device_observer cairo_device_observer_t;
 
+struct _cairo_observation_record {
+    cairo_operator_t op;
+    int source;
+    int mask;
+    int num_glyphs;
+    int path;
+    int fill_rule;
+    double tolerance;
+    int antialias;
+    int clip;
+    double elapsed;
+};
+
 struct _cairo_observation {
     int num_surfaces;
     int num_contexts;
@@ -80,15 +94,19 @@ struct _cairo_observation {
     /* XXX put interesting stats here! */
 
     struct paint {
+	double elapsed;
 	unsigned int count;
 	struct extents extents;
 	unsigned int operators[NUM_OPERATORS];
 	struct pattern source;
 	struct clip clip;
 	unsigned int noop;
+
+	cairo_observation_record_t slowest;
     } paint;
 
     struct mask {
+	double elapsed;
 	unsigned int count;
 	struct extents extents;
 	unsigned int operators[NUM_OPERATORS];
@@ -96,9 +114,12 @@ struct _cairo_observation {
 	struct pattern mask;
 	struct clip clip;
 	unsigned int noop;
+
+	cairo_observation_record_t slowest;
     } mask;
 
     struct fill {
+	double elapsed;
 	unsigned int count;
 	struct extents extents;
 	unsigned int operators[NUM_OPERATORS];
@@ -108,9 +129,12 @@ struct _cairo_observation {
 	unsigned int fill_rule[NUM_FILL_RULE];
 	struct clip clip;
 	unsigned int noop;
+
+	cairo_observation_record_t slowest;
     } fill;
 
     struct stroke {
+	double elapsed;
 	unsigned int count;
 	struct extents extents;
 	unsigned int operators[NUM_OPERATORS];
@@ -122,15 +146,20 @@ struct _cairo_observation {
 	struct stat line_width;
 	struct clip clip;
 	unsigned int noop;
+
+	cairo_observation_record_t slowest;
     } stroke;
 
     struct glyphs {
+	double elapsed;
 	unsigned int count;
 	struct extents extents;
 	unsigned int operators[NUM_OPERATORS];
 	struct pattern source;
 	struct clip clip;
 	unsigned int noop;
+
+	cairo_observation_record_t slowest;
     } glyphs;
 };
 
diff --git a/src/cairo-surface-observer.c b/src/cairo-surface-observer.c
index a9b5537..06be2c2 100644
--- a/src/cairo-surface-observer.c
+++ b/src/cairo-surface-observer.c
@@ -128,18 +128,17 @@ get_pattern_surface (const cairo_pattern_t *pattern)
     return ((cairo_surface_pattern_t *)pattern)->surface;
 }
 
-static void
-add_pattern (struct pattern *stats,
-	     const cairo_pattern_t *source,
-	     const cairo_surface_t *target)
+static int
+classify_pattern (const cairo_pattern_t *pattern,
+		  const cairo_surface_t *target)
 {
     int classify;
 
-    switch (source->type) {
+    switch (pattern->type) {
     case CAIRO_PATTERN_TYPE_SURFACE:
-	if (get_pattern_surface (source)->type == target->type)
+	if (get_pattern_surface (pattern)->type == target->type)
 	    classify = 0;
-	else if (get_pattern_surface (source)->type == CAIRO_SURFACE_TYPE_RECORDING)
+	else if (get_pattern_surface (pattern)->type == CAIRO_SURFACE_TYPE_RECORDING)
 	    classify = 1;
 	else
 	    classify = 2;
@@ -158,13 +157,20 @@ add_pattern (struct pattern *stats,
 	classify = 6;
 	break;
     }
-    stats->type[classify]++;
+    return classify;
 }
 
 static void
-add_path (struct path *stats,
-	  const cairo_path_fixed_t *path,
-	  cairo_bool_t is_fill)
+add_pattern (struct pattern *stats,
+	     const cairo_pattern_t *pattern,
+	     const cairo_surface_t *target)
+{
+    stats->type[classify_pattern(pattern, target)]++;
+}
+
+static int
+classify_path (const cairo_path_fixed_t *path,
+	       cairo_bool_t is_fill)
 {
     int classify;
 
@@ -182,12 +188,20 @@ add_path (struct path *stats,
     if (classify == 1 && ! path->fill_maybe_region)
 	classify = 2;
     classify = 3 + path->has_curve_to != 0;
-    stats->type[classify]++;
+
+    return classify;
 }
 
 static void
-add_clip (struct clip *stats,
-	  const cairo_clip_t *clip)
+add_path (struct path *stats,
+	  const cairo_path_fixed_t *path,
+	  cairo_bool_t is_fill)
+{
+    stats->type[classify_path(path, is_fill)]++;
+}
+
+static int
+classify_clip (const cairo_clip_t *clip)
 {
     int classify;
 
@@ -204,7 +218,14 @@ add_clip (struct clip *stats,
     else
 	classify = 5;
 
-    stats->type[classify]++;
+    return classify;
+}
+
+static void
+add_clip (struct clip *stats,
+	  const cairo_clip_t *clip)
+{
+    stats->type[classify_clip (clip)]++;
 }
 
 static void
@@ -407,6 +428,161 @@ _cairo_surface_observer_unmap_image (void *abstract_surface,
     return surface->target->backend->unmap_image (surface->target, image);
 }
 
+static void
+record_paint (cairo_observation_record_t *r,
+	      cairo_surface_t *target,
+	      cairo_operator_t op,
+	      const cairo_pattern_t *source,
+	      const cairo_clip_t *clip,
+	      double elapsed)
+{
+    r->op = op;
+    r->source = classify_pattern (source, target);
+    r->mask = -1;
+    r->num_glyphs = -1;
+    r->path = -1;
+    r->fill_rule = -1;
+    r->tolerance = -1;
+    r->antialias = -1;
+    r->clip = classify_clip (clip);
+    r->elapsed = elapsed;
+}
+
+static void
+record_mask (cairo_observation_record_t *r,
+	     cairo_surface_t *target,
+	     cairo_operator_t op,
+	     const cairo_pattern_t *source,
+	     const cairo_pattern_t *mask,
+	     const cairo_clip_t *clip,
+	     double elapsed)
+{
+    r->op = op;
+    r->source = classify_pattern (source, target);
+    r->mask = classify_pattern (mask, target);
+    r->num_glyphs = -1;
+    r->path = -1;
+    r->fill_rule = -1;
+    r->tolerance = -1;
+    r->antialias = -1;
+    r->clip = classify_clip (clip);
+    r->elapsed = elapsed;
+}
+
+static void
+record_fill (cairo_observation_record_t *r,
+	     cairo_surface_t		*target,
+	     cairo_operator_t		op,
+	     const cairo_pattern_t	*source,
+	     const cairo_path_fixed_t	*path,
+	     cairo_fill_rule_t		 fill_rule,
+	     double			 tolerance,
+	     cairo_antialias_t		 antialias,
+	     const cairo_clip_t		*clip,
+	     double elapsed)
+{
+    r->op = op;
+    r->source = classify_pattern (source, target);
+    r->mask = -1;
+    r->num_glyphs = -1;
+    r->path = classify_path (path, TRUE);
+    r->fill_rule = fill_rule;
+    r->tolerance = tolerance;
+    r->antialias = antialias;
+    r->clip = classify_clip (clip);
+    r->elapsed = elapsed;
+}
+
+static void
+record_stroke (cairo_observation_record_t *r,
+	       cairo_surface_t		*target,
+	       cairo_operator_t		op,
+	       const cairo_pattern_t	*source,
+	       const cairo_path_fixed_t	*path,
+	       const cairo_stroke_style_t	*style,
+	       const cairo_matrix_t	*ctm,
+	       const cairo_matrix_t	*ctm_inverse,
+	       double			 tolerance,
+	       cairo_antialias_t	 antialias,
+	       const cairo_clip_t	*clip,
+	       double			 elapsed)
+{
+    r->op = op;
+    r->source = classify_pattern (source, target);
+    r->mask = -1;
+    r->num_glyphs = -1;
+    r->path = classify_path (path, FALSE);
+    r->fill_rule = -1;
+    r->tolerance = tolerance;
+    r->antialias = antialias;
+    r->clip = classify_clip (clip);
+    r->elapsed = elapsed;
+}
+
+static void
+record_glyphs (cairo_observation_record_t *r,
+	       cairo_surface_t		*target,
+	       cairo_operator_t		op,
+	       const cairo_pattern_t	*source,
+	       cairo_glyph_t		*glyphs,
+	       int			 num_glyphs,
+	       cairo_scaled_font_t	*scaled_font,
+	       const cairo_clip_t	*clip,
+	       double			 elapsed)
+{
+    r->op = op;
+    r->source = classify_pattern (source, target);
+    r->mask = -1;
+    r->path = -1;
+    r->num_glyphs = num_glyphs;
+    r->fill_rule = -1;
+    r->tolerance = -1;
+    r->antialias = -1;
+    r->clip = classify_clip (clip);
+    r->elapsed = elapsed;
+}
+
+static void
+start_timer (struct timespec *ts)
+{
+    clock_gettime (CLOCK_MONOTONIC, ts);
+}
+
+static double
+stop_timer (const struct timespec *then)
+{
+    struct timespec now;
+    double elapsed;
+
+    clock_gettime (CLOCK_MONOTONIC, &now);
+
+    elapsed = now.tv_nsec - then->tv_nsec;
+    elapsed += 1e9 * (now.tv_sec - then->tv_sec);
+    return elapsed;
+}
+
+static void
+sync (cairo_surface_t *target, int x, int y)
+{
+    cairo_rectangle_t extents;
+
+    extents.x = x;
+    extents.y = y;
+    extents.width = 1;
+    extents.height = 1;
+
+    cairo_surface_unmap_image (target,
+			       cairo_surface_map_to_image (target,
+							   &extents));
+}
+
+static void
+midpt (const cairo_composite_rectangles_t *extents, int *x, int *y)
+{
+    *x = extents->bounded.x + extents->bounded.width / 2;
+    *y = extents->bounded.y + extents->bounded.height / 2;
+}
+
 static cairo_int_status_t
 _cairo_surface_observer_paint (void *abstract_surface,
 			       cairo_operator_t op,
@@ -418,6 +594,9 @@ _cairo_surface_observer_paint (void *abstract_surface,
     cairo_composite_rectangles_t composite;
     cairo_rectangle_int_t extents;
     cairo_int_status_t status;
+    struct timespec ts;
+    double elapsed;
+    int x, y;
 
     /* XXX device locking */
 
@@ -442,14 +621,33 @@ _cairo_surface_observer_paint (void *abstract_surface,
 	return status;
     }
 
+    midpt (&composite, &x, &y);
+
     add_extents (&surface->log.paint.extents, &composite);
     add_extents (&device->log.paint.extents, &composite);
     _cairo_composite_rectangles_fini (&composite);
 
-    /* XXX time? */
-    return _cairo_surface_paint (surface->target,
-				 op, source,
-				 clip);
+    start_timer (&ts);
+    status =  _cairo_surface_paint (surface->target,
+				    op, source,
+				    clip);
+    if (unlikely (status))
+	return status;
+
+    sync (surface->target, x, y);
+    elapsed = stop_timer (&ts);
+
+    if (elapsed > surface->log.paint.slowest.elapsed)
+	record_paint (&surface->log.paint.slowest,
+		      surface->target, op, source, clip, elapsed);
+    surface->log.paint.elapsed += elapsed;
+
+    if (elapsed > device->log.paint.slowest.elapsed)
+	record_paint (&device->log.paint.slowest,
+		      surface->target, op, source, clip, elapsed);
+    device->log.paint.elapsed += elapsed;
+
+    return CAIRO_STATUS_SUCCESS;
 }
 
 static cairo_int_status_t
@@ -464,6 +662,9 @@ _cairo_surface_observer_mask (void *abstract_surface,
     cairo_composite_rectangles_t composite;
     cairo_rectangle_int_t extents;
     cairo_int_status_t status;
+    struct timespec ts;
+    double elapsed;
+    int x, y;
 
     surface->log.mask.count++;
     surface->log.mask.operators[op]++;
@@ -488,13 +689,33 @@ _cairo_surface_observer_mask (void *abstract_surface,
 	return status;
     }
 
+    midpt (&composite, &x, &y);
+
     add_extents (&surface->log.mask.extents, &composite);
     add_extents (&device->log.mask.extents, &composite);
     _cairo_composite_rectangles_fini (&composite);
 
-    return _cairo_surface_mask (surface->target,
-				op, source, mask,
-				clip);
+    start_timer (&ts);
+    status =  _cairo_surface_mask (surface->target,
+				   op, source, mask,
+				   clip);
+    if (unlikely (status))
+	return status;
+
+    sync (surface->target, x, y);
+    elapsed = stop_timer (&ts);
+
+    if (elapsed > surface->log.mask.slowest.elapsed)
+	record_mask (&surface->log.mask.slowest,
+		     surface->target, op, source, mask, clip, elapsed);
+    surface->log.mask.elapsed += elapsed;
+
+    if (elapsed > device->log.mask.slowest.elapsed)
+	record_mask (&device->log.mask.slowest,
+		      surface->target, op, source, mask, clip, elapsed);
+    device->log.mask.elapsed += elapsed;
+
+    return CAIRO_STATUS_SUCCESS;
 }
 
 static cairo_int_status_t
@@ -512,6 +733,9 @@ _cairo_surface_observer_fill (void			*abstract_surface,
     cairo_composite_rectangles_t composite;
     cairo_rectangle_int_t extents;
     cairo_int_status_t status;
+    struct timespec ts;
+    double elapsed;
+    int x, y;
 
     surface->log.fill.count++;
     surface->log.fill.operators[op]++;
@@ -540,14 +764,38 @@ _cairo_surface_observer_fill (void			*abstract_surface,
 	return status;
     }
 
+    midpt (&composite, &x, &y);
+
     add_extents (&surface->log.fill.extents, &composite);
     add_extents (&device->log.fill.extents, &composite);
     _cairo_composite_rectangles_fini (&composite);
 
-    return _cairo_surface_fill (surface->target,
-				op, source, path,
-				fill_rule, tolerance, antialias,
-				clip);
+    start_timer (&ts);
+    status = _cairo_surface_fill (surface->target,
+				  op, source, path,
+				  fill_rule, tolerance, antialias,
+				  clip);
+    if (unlikely (status))
+	return status;
+
+    sync (surface->target, x, y);
+    elapsed = stop_timer (&ts);
+
+    if (elapsed > surface->log.fill.slowest.elapsed)
+	record_fill (&surface->log.fill.slowest,
+		     surface->target, op, source, path,
+		     fill_rule, tolerance, antialias,
+		     clip, elapsed);
+    surface->log.fill.elapsed += elapsed;
+
+    if (elapsed > device->log.fill.slowest.elapsed)
+	record_fill (&device->log.fill.slowest,
+		     surface->target, op, source, path,
+		     fill_rule, tolerance, antialias,
+		     clip, elapsed);
+    device->log.fill.elapsed += elapsed;
+
+    return CAIRO_STATUS_SUCCESS;
 }
 
 static cairo_int_status_t
@@ -567,6 +815,9 @@ _cairo_surface_observer_stroke (void				*abstract_surface,
     cairo_composite_rectangles_t composite;
     cairo_rectangle_int_t extents;
     cairo_int_status_t status;
+    struct timespec ts;
+    double elapsed;
+    int x, y;
 
     surface->log.stroke.count++;
     surface->log.stroke.operators[op]++;
@@ -598,15 +849,41 @@ _cairo_surface_observer_stroke (void				*abstract_surface,
 	return status;
     }
 
+    midpt (&composite, &x, &y);
+
     add_extents (&surface->log.stroke.extents, &composite);
     add_extents (&device->log.stroke.extents, &composite);
     _cairo_composite_rectangles_fini (&composite);
 
-    return _cairo_surface_stroke (surface->target,
+    start_timer (&ts);
+    status = _cairo_surface_stroke (surface->target,
 				  op, source, path,
 				  style, ctm, ctm_inverse,
 				  tolerance, antialias,
 				  clip);
+    if (unlikely (status))
+	return status;
+
+    sync (surface->target, x, y);
+    elapsed = stop_timer (&ts);
+
+    if (elapsed > surface->log.stroke.slowest.elapsed)
+	    record_stroke (&surface->log.stroke.slowest,
+			   surface->target, op, source, path,
+			   style, ctm,ctm_inverse,
+			   tolerance, antialias,
+			   clip, elapsed);
+    surface->log.stroke.elapsed += elapsed;
+
+    if (elapsed > device->log.stroke.slowest.elapsed)
+	record_stroke (&device->log.stroke.slowest,
+		       surface->target, op, source, path,
+		       style, ctm, ctm_inverse,
+		       tolerance, antialias,
+		       clip, elapsed);
+    device->log.stroke.elapsed += elapsed;
+
+    return CAIRO_STATUS_SUCCESS;
 }
 
 static cairo_int_status_t
@@ -624,6 +901,9 @@ _cairo_surface_observer_glyphs (void			*abstract_surface,
     cairo_composite_rectangles_t composite;
     cairo_rectangle_int_t extents;
     cairo_int_status_t status;
+    struct timespec ts;
+    double elapsed;
+    int x, y;
 
     surface->log.glyphs.count++;
     surface->log.glyphs.operators[op]++;
@@ -649,17 +929,41 @@ _cairo_surface_observer_glyphs (void			*abstract_surface,
 	return status;
     }
 
+    midpt (&composite, &x, &y);
+
     add_extents (&surface->log.glyphs.extents, &composite);
     add_extents (&device->log.glyphs.extents, &composite);
     _cairo_composite_rectangles_fini (&composite);
 
     *remaining_glyphs = 0;
-    return _cairo_surface_show_text_glyphs (surface->target, op, source,
+    start_timer (&ts);
+    status = _cairo_surface_show_text_glyphs (surface->target, op, source,
 					    NULL, 0,
 					    glyphs, num_glyphs,
 					    NULL, 0, 0,
 					    scaled_font,
 					    clip);
+    if (unlikely (status))
+	return status;
+
+    sync (surface->target, x, y);
+    elapsed = stop_timer (&ts);
+
+    if (elapsed > surface->log.glyphs.slowest.elapsed)
+	    record_glyphs (&surface->log.glyphs.slowest,
+			   surface->target, op, source,
+			   glyphs, num_glyphs, scaled_font,
+			   clip, elapsed);
+    surface->log.glyphs.elapsed += elapsed;
+
+    if (elapsed > device->log.glyphs.slowest.elapsed)
+	record_glyphs (&device->log.glyphs.slowest,
+		       surface->target, op, source,
+		       glyphs, num_glyphs, scaled_font,
+		       clip, elapsed);
+    device->log.glyphs.elapsed += elapsed;
+
+    return CAIRO_STATUS_SUCCESS;
 }
 
 static cairo_status_t
@@ -907,145 +1211,190 @@ print_array (cairo_output_stream_t *stream,
 				     i < j -1 ? "," : "");
 }
 
+static const char *operator_names[] = {
+    "CLEAR",	/* CAIRO_OPERATOR_CLEAR */
+
+    "SOURCE",	/* CAIRO_OPERATOR_SOURCE */
+    "OVER",		/* CAIRO_OPERATOR_OVER */
+    "IN",		/* CAIRO_OPERATOR_IN */
+    "OUT",		/* CAIRO_OPERATOR_OUT */
+    "ATOP",		/* CAIRO_OPERATOR_ATOP */
+
+    "DEST",		/* CAIRO_OPERATOR_DEST */
+    "DEST_OVER",	/* CAIRO_OPERATOR_DEST_OVER */
+    "DEST_IN",	/* CAIRO_OPERATOR_DEST_IN */
+    "DEST_OUT",	/* CAIRO_OPERATOR_DEST_OUT */
+    "DEST_ATOP",	/* CAIRO_OPERATOR_DEST_ATOP */
+
+    "XOR",		/* CAIRO_OPERATOR_XOR */
+    "ADD",		/* CAIRO_OPERATOR_ADD */
+    "SATURATE",	/* CAIRO_OPERATOR_SATURATE */
+
+    "MULTIPLY",	/* CAIRO_OPERATOR_MULTIPLY */
+    "SCREEN",	/* CAIRO_OPERATOR_SCREEN */
+    "OVERLAY",	/* CAIRO_OPERATOR_OVERLAY */
+    "DARKEN",	/* CAIRO_OPERATOR_DARKEN */
+    "LIGHTEN",	/* CAIRO_OPERATOR_LIGHTEN */
+    "DODGE",	/* CAIRO_OPERATOR_COLOR_DODGE */
+    "BURN",		/* CAIRO_OPERATOR_COLOR_BURN */
+    "HARD_LIGHT",	/* CAIRO_OPERATOR_HARD_LIGHT */
+    "SOFT_LIGHT",	/* CAIRO_OPERATOR_SOFT_LIGHT */
+    "DIFFERENCE",	/* CAIRO_OPERATOR_DIFFERENCE */
+    "EXCLUSION",	/* CAIRO_OPERATOR_EXCLUSION */
+    "HSL_HUE",	/* CAIRO_OPERATOR_HSL_HUE */
+    "HSL_SATURATION", /* CAIRO_OPERATOR_HSL_SATURATION */
+    "HSL_COLOR",	/* CAIRO_OPERATOR_HSL_COLOR */
+    "HSL_LUMINOSITY" /* CAIRO_OPERATOR_HSL_LUMINOSITY */
+};
 static void
 print_operators (cairo_output_stream_t *stream, unsigned int *array)
 {
-    static const char *names[] = {
-	"CLEAR",	/* CAIRO_OPERATOR_CLEAR */
-
-	"SOURCE",	/* CAIRO_OPERATOR_SOURCE */
-	"OVER",		/* CAIRO_OPERATOR_OVER */
-	"IN",		/* CAIRO_OPERATOR_IN */
-	"OUT",		/* CAIRO_OPERATOR_OUT */
-	"ATOP",		/* CAIRO_OPERATOR_ATOP */
-
-	"DEST",		/* CAIRO_OPERATOR_DEST */
-	"DEST_OVER",	/* CAIRO_OPERATOR_DEST_OVER */
-	"DEST_IN",	/* CAIRO_OPERATOR_DEST_IN */
-	"DEST_OUT",	/* CAIRO_OPERATOR_DEST_OUT */
-	"DEST_ATOP",	/* CAIRO_OPERATOR_DEST_ATOP */
-
-	"XOR",		/* CAIRO_OPERATOR_XOR */
-	"ADD",		/* CAIRO_OPERATOR_ADD */
-	"SATURATE",	/* CAIRO_OPERATOR_SATURATE */
-
-	"MULTIPLY",	/* CAIRO_OPERATOR_MULTIPLY */
-	"SCREEN",	/* CAIRO_OPERATOR_SCREEN */
-	"OVERLAY",	/* CAIRO_OPERATOR_OVERLAY */
-	"DARKEN",	/* CAIRO_OPERATOR_DARKEN */
-	"LIGHTEN",	/* CAIRO_OPERATOR_LIGHTEN */
-	"DODGE",	/* CAIRO_OPERATOR_COLOR_DODGE */
-	"BURN",		/* CAIRO_OPERATOR_COLOR_BURN */
-	"HARD_LIGHT",	/* CAIRO_OPERATOR_HARD_LIGHT */
-	"SOFT_LIGHT",	/* CAIRO_OPERATOR_SOFT_LIGHT */
-	"DIFFERENCE",	/* CAIRO_OPERATOR_DIFFERENCE */
-	"EXCLUSION",	/* CAIRO_OPERATOR_EXCLUSION */
-	"HSL_HUE",	/* CAIRO_OPERATOR_HSL_HUE */
-	"HSL_SATURATION", /* CAIRO_OPERATOR_HSL_SATURATION */
-	"HSL_COLOR",	/* CAIRO_OPERATOR_HSL_COLOR */
-	"HSL_LUMINOSITY" /* CAIRO_OPERATOR_HSL_LUMINOSITY */
-    };
-
     _cairo_output_stream_printf (stream, "  op:");
-    print_array (stream, array, names, NUM_OPERATORS);
+    print_array (stream, array, operator_names, NUM_OPERATORS);
     _cairo_output_stream_printf (stream, "\n");
 }
 
+static const char *fill_rule_names[] = {
+    "non-zero",
+    "even-odd",
+};
+static void
+print_fill_rule (cairo_output_stream_t *stream, unsigned int *array)
+{
+    _cairo_output_stream_printf (stream, "  fill rule:");
+    print_array (stream, array, fill_rule_names, ARRAY_LENGTH(fill_rule_names));
+    _cairo_output_stream_printf (stream, "\n");
+}
+
+static const char *cap_names[] = {
+    "butt",		/* CAIRO_LINE_CAP_BUTT */
+    "round",	/* CAIRO_LINE_CAP_ROUND */
+    "square"	/* CAIRO_LINE_CAP_SQUARE */
+};
 static void
 print_line_caps (cairo_output_stream_t *stream, unsigned int *array)
 {
-    static const char *names[] = {
-	"butt",		/* CAIRO_LINE_CAP_BUTT */
-	"round",	/* CAIRO_LINE_CAP_ROUND */
-	"square"	/* CAIRO_LINE_CAP_SQUARE */
-    };
     _cairo_output_stream_printf (stream, "  caps:");
-    print_array (stream, array, names, NUM_CAPS);
+    print_array (stream, array, cap_names, NUM_CAPS);
     _cairo_output_stream_printf (stream, "\n");
 }
 
+static const char *join_names[] = {
+    "miter",	/* CAIRO_LINE_JOIN_MITER */
+    "round",	/* CAIRO_LINE_JOIN_ROUND */
+    "bevel",	/* CAIRO_LINE_JOIN_BEVEL */
+};
 static void
 print_line_joins (cairo_output_stream_t *stream, unsigned int *array)
 {
-    static const char *names[] = {
-	"miter",	/* CAIRO_LINE_JOIN_MITER */
-	"round",	/* CAIRO_LINE_JOIN_ROUND */
-	"bevel",	/* CAIRO_LINE_JOIN_BEVEL */
-    };
     _cairo_output_stream_printf (stream, "  joins:");
-    print_array (stream, array, names, NUM_JOINS);
+    print_array (stream, array, join_names, NUM_JOINS);
     _cairo_output_stream_printf (stream, "\n");
 }
 
+static const char *antialias_names[] = {
+    "default",
+    "none",
+    "gray",
+    "subpixel"
+};
 static void
 print_antialias (cairo_output_stream_t *stream, unsigned int *array)
 {
-    static const char *names[] = {
-	"default",
-	"none",
-	"gray",
-	"subpixel"
-    };
     _cairo_output_stream_printf (stream, "  antialias:");
-    print_array (stream, array, names, NUM_ANTIALIAS);
+    print_array (stream, array, antialias_names, NUM_ANTIALIAS);
     _cairo_output_stream_printf (stream, "\n");
 }
 
+static const char *pattern_names[] = {
+    "native",
+    "record",
+    "other surface",
+    "solid",
+    "linear",
+    "radial",
+    "mesh"
+};
 static void
 print_pattern (cairo_output_stream_t *stream,
 	       const char *name,
 	       const struct pattern *p)
 {
-    static const char *names[] = {
-	"native",
-	"record",
-	"other surface",
-	"solid",
-	"linear",
-	"radial",
-	"mesh"
-    };
     _cairo_output_stream_printf (stream, "  %s:", name);
-    print_array (stream, p->type, names, ARRAY_LENGTH (names));
+    print_array (stream, p->type, pattern_names, ARRAY_LENGTH (pattern_names));
     _cairo_output_stream_printf (stream, "\n");
 }
 
+static const char *path_names[] = {
+    "empty",
+    "pixel-aligned",
+    "rectliinear",
+    "straight",
+    "curved",
+};
 static void
 print_path (cairo_output_stream_t *stream,
 	    const struct path *p)
 {
-    static const char *names[] = {
-	"empty",
-	"pixel-aligned",
-	"rectliinear",
-	"straight",
-	"curved",
-    };
     _cairo_output_stream_printf (stream, "  path:");
-    print_array (stream, p->type, names, ARRAY_LENGTH (names));
+    print_array (stream, p->type, path_names, ARRAY_LENGTH (path_names));
     _cairo_output_stream_printf (stream, "\n");
 }
 
+static const char *clip_names[] = {
+    "none",
+    "region",
+    "boxes",
+    "single path",
+    "polygon",
+    "general",
+};
 static void
 print_clip (cairo_output_stream_t *stream, const struct clip *c)
 {
-    static const char *names[] = {
-	"none",
-	"region",
-	"boxes",
-	"single path",
-	"polygon",
-	"general",
-    };
     _cairo_output_stream_printf (stream, "  clip:");
-    print_array (stream, c->type, names, ARRAY_LENGTH (names));
+    print_array (stream, c->type, clip_names, ARRAY_LENGTH (clip_names));
     _cairo_output_stream_printf (stream, "\n");
 }
 
 static void
+print_record (cairo_output_stream_t *stream,
+	      cairo_observation_record_t *r)
+{
+    _cairo_output_stream_printf (stream, "  op: %s\n", operator_names[r->op]);
+    _cairo_output_stream_printf (stream, "  source: %s\n",
+				 pattern_names[r->source]);
+    if (r->mask != -1)
+	_cairo_output_stream_printf (stream, "  mask: %s\n",
+				     pattern_names[r->mask]);
+    if (r->num_glyphs != -1)
+	_cairo_output_stream_printf (stream, "  num_glyphs: %d\n",
+				     r->num_glyphs);
+    if (r->path != -1)
+	_cairo_output_stream_printf (stream, "  path: %s\n",
+				    path_names[r->path]);
+    if (r->fill_rule != -1)
+	_cairo_output_stream_printf (stream, "  fill rule: %s\n",
+				     fill_rule_names[r->fill_rule]);
+    if (r->antialias != -1)
+	_cairo_output_stream_printf (stream, "  antialias: %s\n",
+				     antialias_names[r->antialias]);
+    _cairo_output_stream_printf (stream, "  clip: %s\n", clip_names[r->clip]);
+    _cairo_output_stream_printf (stream, "  elapsed: %f ns\n", r->elapsed);
+}
+
+static double percent (double a, double b)
+{
+    /* Fake %.1f */
+    return round (a*1000 / b) / 10;
+}
+
+static void
 _cairo_observation_print (cairo_output_stream_t *stream,
-				  cairo_observation_t *log)
+			  cairo_observation_t *log)
 {
+    double total;
+
     _cairo_output_stream_printf (stream, "surfaces: %d\n",
 				 log->num_surfaces);
     _cairo_output_stream_printf (stream, "contexts: %d\n",
@@ -1053,38 +1402,75 @@ _cairo_observation_print (cairo_output_stream_t *stream,
     _cairo_output_stream_printf (stream, "sources acquired: %d\n",
 				 log->num_sources_acquired);
 
-    _cairo_output_stream_printf (stream, "paint: count %d [no-op %d]\n",
-				 log->paint.count, log->paint.noop);
+    total = 0;
+    total += log->paint.elapsed;
+    total += log->mask.elapsed;
+    total += log->fill.elapsed;
+    total += log->stroke.elapsed;
+    total += log->glyphs.elapsed;
+
+    _cairo_output_stream_printf (stream, "paint: count %d [no-op %d], elapsed %f [%f%%]\n",
+				 log->paint.count, log->paint.noop,
+				 log->paint.elapsed,
+				 percent (log->paint.elapsed, total));
     if (log->paint.count) {
 	print_extents (stream, &log->paint.extents);
 	print_operators (stream, log->paint.operators);
 	print_pattern (stream, "source", &log->paint.source);
 	print_clip (stream, &log->paint.clip);
+
+	_cairo_output_stream_printf (stream, "slowest paint: %f%%\n",
+				     percent (log->paint.slowest.elapsed,
+					      log->paint.elapsed));
+	print_record (stream, &log->paint.slowest);
+
+	_cairo_output_stream_printf (stream, "\n");
     }
 
-    _cairo_output_stream_printf (stream, "mask: count %d [no-op %d]\n",
-				 log->mask.count, log->mask.noop);
+    _cairo_output_stream_printf (stream, "mask: count %d [no-op %d], elapsed %f [%f%%]\n",
+				 log->mask.count, log->mask.noop,
+				 log->mask.elapsed,
+				 percent (log->mask.elapsed, total));
     if (log->mask.count) {
 	print_extents (stream, &log->mask.extents);
 	print_operators (stream, log->mask.operators);
 	print_pattern (stream, "source", &log->mask.source);
 	print_pattern (stream, "mask", &log->mask.mask);
 	print_clip (stream, &log->mask.clip);
+
+	_cairo_output_stream_printf (stream, "slowest mask: %f%%\n",
+				     percent (log->mask.slowest.elapsed,
+					      log->mask.elapsed));
+	print_record (stream, &log->mask.slowest);
+
+	_cairo_output_stream_printf (stream, "\n");
     }
 
-    _cairo_output_stream_printf (stream, "fill: count %d [no-op %d]\n",
-				 log->fill.count, log->fill.noop);
+    _cairo_output_stream_printf (stream, "fill: count %d [no-op %d], elaspsed %f [%f%%]\n",
+				 log->fill.count, log->fill.noop,
+				 log->fill.elapsed,
+				 percent (log->fill.elapsed, total));
     if (log->fill.count) {
 	print_extents (stream, &log->fill.extents);
 	print_operators (stream, log->fill.operators);
 	print_pattern (stream, "source", &log->fill.source);
 	print_path (stream, &log->fill.path);
+	print_fill_rule (stream, log->fill.fill_rule);
 	print_antialias (stream, log->fill.antialias);
 	print_clip (stream, &log->fill.clip);
+
+	_cairo_output_stream_printf (stream, "slowest fill: %f%%\n",
+				     percent (log->fill.slowest.elapsed,
+					      log->fill.elapsed));
+	print_record (stream, &log->fill.slowest);
+
+	_cairo_output_stream_printf (stream, "\n");
     }
 
-    _cairo_output_stream_printf (stream, "stroke: count %d [no-op %d]\n",
-				 log->stroke.count, log->stroke.noop);
+    _cairo_output_stream_printf (stream, "stroke: count %d [no-op %d], elapsed %f [%f%%]\n",
+				 log->stroke.count, log->stroke.noop,
+				 log->stroke.elapsed,
+				 percent (log->stroke.elapsed, total));
     if (log->stroke.count) {
 	print_extents (stream, &log->stroke.extents);
 	print_operators (stream, log->stroke.operators);
@@ -1094,15 +1480,31 @@ _cairo_observation_print (cairo_output_stream_t *stream,
 	print_line_caps (stream, log->stroke.caps);
 	print_line_joins (stream, log->stroke.joins);
 	print_clip (stream, &log->stroke.clip);
+
+	_cairo_output_stream_printf (stream, "slowest stroke: %f%%\n",
+				     percent (log->stroke.slowest.elapsed,
+					      log->stroke.elapsed));
+	print_record (stream, &log->stroke.slowest);
+
+	_cairo_output_stream_printf (stream, "\n");
     }
 
-    _cairo_output_stream_printf (stream, "glyphs: count %d [no-op %d]\n",
-				 log->glyphs.count, log->glyphs.noop);
+    _cairo_output_stream_printf (stream, "glyphs: count %d [no-op %d], elasped %f [%f%%]\n",
+				 log->glyphs.count, log->glyphs.noop,
+				 log->glyphs.elapsed,
+				 percent (log->glyphs.elapsed, total));
     if (log->glyphs.count) {
 	print_extents (stream, &log->glyphs.extents);
 	print_operators (stream, log->glyphs.operators);
 	print_pattern (stream, "source", &log->glyphs.source);
 	print_clip (stream, &log->glyphs.clip);
+
+	_cairo_output_stream_printf (stream, "slowest glyphs: %f%%\n",
+				     percent (log->glyphs.slowest.elapsed,
+					      log->glyphs.elapsed));
+	print_record (stream, &log->glyphs.slowest);
+
+	_cairo_output_stream_printf (stream, "\n");
     }
 }
 
commit 4d5502503c2c6f3c04cf21750ba71caafecf06d8
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu Aug 18 12:41:20 2011 +0100

    observer: put a comma between array items when printing
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/cairo-surface-observer.c b/src/cairo-surface-observer.c
index 4baf709..a9b5537 100644
--- a/src/cairo-surface-observer.c
+++ b/src/cairo-surface-observer.c
@@ -902,8 +902,9 @@ print_array (cairo_output_stream_t *stream,
 
     sort_order (order, j, (void *)array);
     for (i = 0; i < j; i++)
-	_cairo_output_stream_printf (stream, " %d %s",
-				     array[order[i]], names[order[i]]);
+	_cairo_output_stream_printf (stream, " %d %s%s",
+				     array[order[i]], names[order[i]],
+				     i < j -1 ? "," : "");
 }
 
 static void
commit d03b0057b2865b2d51f80d874f030e52ee0c4aca
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu Aug 18 12:37:57 2011 +0100

    observer: further classify general clips
    
    A clip with only a single path or can be reduced to a single polygon are
    easier to handle than a clip containing a mixture of paths (typically
    ANTIALIAS_NONE vs ANTIALIAS_DEFAULT).
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/cairo-clip-polygon.c b/src/cairo-clip-polygon.c
index 19da15d..0e1968d 100644
--- a/src/cairo-clip-polygon.c
+++ b/src/cairo-clip-polygon.c
@@ -125,3 +125,20 @@ _cairo_clip_get_polygon (const cairo_clip_t *clip,
 
     return CAIRO_STATUS_SUCCESS;
 }
+
+cairo_bool_t
+_cairo_clip_is_polygon (const cairo_clip_t *clip)
+{
+    if (_cairo_clip_is_all_clipped (clip))
+	return TRUE;
+
+    /* If there is no clip, we need an infinite polygon */
+    if (clip == NULL)
+	return FALSE;
+
+    if (clip->path == NULL)
+	return TRUE;
+
+    /* check that residual is all of the same type/tolerance */
+    return can_convert_to_polygon (clip);
+}
diff --git a/src/cairo-clip-private.h b/src/cairo-clip-private.h
index f2cfd63..3ebcb0e 100644
--- a/src/cairo-clip-private.h
+++ b/src/cairo-clip-private.h
@@ -204,6 +204,9 @@ _cairo_clip_copy_rectangle_list (cairo_clip_t *clip, cairo_gstate_t *gstate);
 cairo_private cairo_rectangle_list_t *
 _cairo_rectangle_list_create_in_error (cairo_status_t status);
 
+cairo_private cairo_bool_t
+_cairo_clip_is_polygon (const cairo_clip_t *clip);
+
 cairo_private cairo_int_status_t
 _cairo_clip_get_polygon (const cairo_clip_t *clip,
 			 cairo_polygon_t *polygon,
diff --git a/src/cairo-surface-observer-private.h b/src/cairo-surface-observer-private.h
index 7383a73..ed05f96 100644
--- a/src/cairo-surface-observer-private.h
+++ b/src/cairo-surface-observer-private.h
@@ -66,7 +66,7 @@ struct path {
 };
 
 struct clip {
-    unsigned int type[4]; /* none, region, boxes, general */
+    unsigned int type[6]; /* none, region, boxes, single path, polygon, general */
 };
 
 typedef struct _cairo_observation cairo_observation_t;
diff --git a/src/cairo-surface-observer.c b/src/cairo-surface-observer.c
index 3bd9682..4baf709 100644
--- a/src/cairo-surface-observer.c
+++ b/src/cairo-surface-observer.c
@@ -197,11 +197,14 @@ add_clip (struct clip *stats,
 	classify = 1;
     else if (clip->path == NULL)
 	classify = 2;
-    else
+    else if (clip->path->prev == NULL)
 	classify = 3;
+    else if (_cairo_clip_is_polygon (clip))
+	classify = 4;
+    else
+	classify = 5;
 
     stats->type[classify]++;
-
 }
 
 static void
@@ -1029,7 +1032,9 @@ print_clip (cairo_output_stream_t *stream, const struct clip *c)
 	"none",
 	"region",
 	"boxes",
-	"general path",
+	"single path",
+	"polygon",
+	"general",
     };
     _cairo_output_stream_printf (stream, "  clip:");
     print_array (stream, c->type, names, ARRAY_LENGTH (names));


More information about the cairo-commit mailing list