[cairo] Multithreaded cairo-perf

Chris Wilson chris at chris-wilson.co.uk
Thu Mar 22 18:17:02 PDT 2007


The recently introduced solid pattern cache has triggered a fresh set of
bad reference assertion failures, which are probably due to the lack of
atomic reference counting and highlight a lack of concurrency testing
performed by the Cairo test suite. This patch allows cairo-perf to be
run across multiple threads. It introduces a -t <int> cmdline option which
causes the creation of <int> threads where each thread runs all the perf
cases sequentially. The patch is a WIP as it makes no attempt to manage
the output from multiple threads nor provide a portable threading
interface, but it does enable concurrency testing.

Comments?
--
Chris Wilson
-------------- next part --------------
diff --git a/perf/box-outline.c b/perf/box-outline.c
index 74dd19a..7eadce8 100644
--- a/perf/box-outline.c
+++ b/perf/box-outline.c
@@ -41,7 +41,7 @@
  */
 
 static cairo_perf_ticks_t
-box_outline_stroke (cairo_t *cr, int width, int height)
+box_outline_stroke (cairo_perf_timer_t *timer, cairo_t *cr, int width, int height)
 {
     cairo_set_source_rgb (cr, 0, 0, 1); /* blue */
     cairo_paint (cr);
@@ -52,17 +52,17 @@ box_outline_stroke (cairo_t *cr, int width, int height)
     cairo_set_line_width (cr, 1.0);
     cairo_set_source_rgb (cr, 1, 0, 0); /* red */
 
-    cairo_perf_timer_start ();
+    cairo_perf_timer_start (timer);
 
     cairo_stroke (cr);
 
-    cairo_perf_timer_stop ();
+    cairo_perf_timer_stop (timer);
 
-    return cairo_perf_timer_elapsed ();
+    return cairo_perf_timer_elapsed (timer);
 }
 
 static cairo_perf_ticks_t
-box_outline_fill (cairo_t *cr, int width, int height)
+box_outline_fill (cairo_perf_timer_t *timer, cairo_t *cr, int width, int height)
 {
     cairo_set_source_rgb (cr, 0, 0, 1); /* blue */
     cairo_paint (cr);
@@ -76,18 +76,18 @@ box_outline_fill (cairo_t *cr, int width, int height)
     cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
     cairo_set_source_rgb (cr, 0, 1, 0); /* green */
 
-    cairo_perf_timer_start ();
+    cairo_perf_timer_start (timer);
 
     cairo_fill (cr);
 
-    cairo_perf_timer_stop ();
+    cairo_perf_timer_stop (timer);
 
-    return cairo_perf_timer_elapsed ();
+    return cairo_perf_timer_elapsed (timer);
 }
 
 void
 box_outline (cairo_perf_t *perf, cairo_t *cr, int width, int height)
 {
-    cairo_perf_run (perf, "box-outline-stroke", box_outline_stroke);
-    cairo_perf_run (perf, "box-outline-fill", box_outline_fill);
+    cairo_perf_run (perf, cr, "box-outline-stroke", box_outline_stroke);
+    cairo_perf_run (perf, cr, "box-outline-fill", box_outline_fill);
 }
diff --git a/perf/cairo-perf-cover.c b/perf/cairo-perf-cover.c
index 53dc7b7..426f872 100644
--- a/perf/cairo-perf-cover.c
+++ b/perf/cairo-perf-cover.c
@@ -197,6 +197,7 @@ typedef void (*set_source_func_t) (cairo_t *cr, int width, int height);
 
 void
 cairo_perf_cover_sources_and_operators (cairo_perf_t		*perf,
+					cairo_t			*cr,
 					const char		*name,
 					cairo_perf_func_t	 perf_func)
 {
@@ -222,14 +223,14 @@ cairo_perf_cover_sources_and_operators (cairo_perf_t		*perf,
     };
 
     for (i = 0; i < ARRAY_SIZE (sources); i++) {
-	(sources[i].set_source) (perf->cr, perf->size, perf->size);
+	(sources[i].set_source) (cr, perf->size, perf->size);
 
 	for (j = 0; j < ARRAY_SIZE (operators); j++) {
-	    cairo_set_operator (perf->cr, operators[j].op);
+	    cairo_set_operator (cr, operators[j].op);
 
 	    xasprintf (&expanded_name, "%s_%s_%s",
 		       name, sources[i].name, operators[j].name);
-	    cairo_perf_run (perf, expanded_name, perf_func);
+	    cairo_perf_run (perf, cr, expanded_name, perf_func);
 	    free (expanded_name);
 	}
     }
diff --git a/perf/cairo-perf-posix.c b/perf/cairo-perf-posix.c
index 68637ef..b313606 100644
--- a/perf/cairo-perf-posix.c
+++ b/perf/cairo-perf-posix.c
@@ -65,11 +65,11 @@
 /* timers */
 
 #if defined(__i386__) || defined(__amd64__)
-static inline unsigned long
+static inline cairo_perf_ticks_t
 oil_profile_stamp_rdtsc (void)
 {
     unsigned long ts;
-    __asm__ __volatile__("rdtsc\n" : "=a" (ts) : : "edx");
+    __asm__ __volatile__("rdtsc\n" : "=a" (ts), :: "edx");
     return ts;
 }
 #define OIL_STAMP oil_profile_stamp_rdtsc
@@ -98,7 +98,7 @@ oil_profile_stamp_alpha(void)
 #endif
 
 #if defined(__s390__)
-static cairo_perf_ticks_t
+static inline cairo_perf_ticks_t
 oil_profile_stamp_s390(void)
 {
     uint64_t ts;
@@ -108,7 +108,7 @@ oil_profile_stamp_s390(void)
 #define OIL_STAMP oil_profile_stamp_s390
 #endif
 
-typedef struct _cairo_perf_timer
+struct _cairo_perf_timer
 {
 #ifdef OIL_STAMP
     cairo_perf_ticks_t start;
@@ -117,77 +117,98 @@ typedef struct _cairo_perf_timer
     struct timeval tv_start;
     struct timeval tv_stop;
 #endif
-} cairo_perf_timer_t;
 
-static cairo_perf_timer_t timer;
+    cairo_perf_timer_synchronize_t synchronize;
+    void *synchronize_closure;
+
+    cairo_perf_ticks_t tps;
+};
+
+
+cairo_perf_timer_t *
+cairo_perf_timer_create (void)
+{
+    cairo_perf_timer_t *timer = xmalloc (sizeof (cairo_perf_timer_t));
+
+    timer->synchronize = NULL;
+    timer->synchronize_closure = NULL;
+
+    timer->tps = 0;
+
+    return timer;
+}
+
+void
+cairo_perf_timer_destroy (cairo_perf_timer_t *timer)
+{
+    free (timer);
+}
 
-static cairo_perf_timer_synchronize_t cairo_perf_timer_synchronize = NULL;
-static void *cairo_perf_timer_synchronize_closure = NULL;
 void
-cairo_perf_timer_set_synchronize (cairo_perf_timer_synchronize_t	 synchronize,
+cairo_perf_timer_set_synchronize (cairo_perf_timer_t			*timer,
+	                          cairo_perf_timer_synchronize_t	 synchronize,
 				  void					*closure)
 {
-    cairo_perf_timer_synchronize = synchronize;
-    cairo_perf_timer_synchronize_closure = closure;
+    timer->synchronize = synchronize;
+    timer->synchronize_closure = closure;
 }
 
 void
-cairo_perf_timer_start (void) {
-    if (cairo_perf_timer_synchronize)
-	cairo_perf_timer_synchronize (cairo_perf_timer_synchronize_closure);
+cairo_perf_timer_start (cairo_perf_timer_t *timer) {
+    if (timer->synchronize)
+	timer->synchronize (timer->synchronize_closure);
 #ifdef OIL_STAMP
-    timer.start = OIL_STAMP ();
+    timer->start = OIL_STAMP ();
 #else
-    gettimeofday (&timer.tv_start, NULL);
+    gettimeofday (&timer->tv_start, NULL);
 #endif
 }
 
 void
-cairo_perf_timer_stop (void) {
-    if (cairo_perf_timer_synchronize)
-	cairo_perf_timer_synchronize (cairo_perf_timer_synchronize_closure);
+cairo_perf_timer_stop (cairo_perf_timer_t *timer) {
+    if (timer->synchronize)
+	timer->synchronize (timer->synchronize_closure);
 #ifdef OIL_STAMP
-    timer.stop = OIL_STAMP ();
+    timer->stop = OIL_STAMP ();
 #else
-    gettimeofday (&timer.tv_stop, NULL);
+    gettimeofday (&timer->tv_stop, NULL);
 #endif
 }
 
 cairo_perf_ticks_t
-cairo_perf_timer_elapsed (void) {
+cairo_perf_timer_elapsed (cairo_perf_timer_t *timer) {
     cairo_perf_ticks_t ticks;
 
 #ifdef OIL_STAMP
     /* Handle 32-bit wraparound of timer value */
-    if (timer.stop < timer.start)
-	timer.stop += 0x100000000ll;
-    ticks = (timer.stop - timer.start);
+    if (timer->stop < timer->start)
+	timer->stop += 0x100000000ll;
+    ticks = (timer->stop - timer->start);
 #else
-    ticks = (timer.tv_stop.tv_sec - timer.tv_start.tv_sec) * 1000000;
-    ticks += (timer.tv_stop.tv_usec - timer.tv_start.tv_usec);
+    ticks = (timer->tv_stop.tv_sec - timer->tv_start.tv_sec) * 1000000;
+    ticks += (timer->tv_stop.tv_usec - timer->tv_start.tv_usec);
 #endif
 
     return ticks;
 }
 
 cairo_perf_ticks_t
-cairo_perf_ticks_per_second (void) {
+cairo_perf_ticks_per_second (cairo_perf_timer_t *timer) {
 #ifdef OIL_STAMP
-    static cairo_perf_ticks_t tps = 0;
     /* XXX: This is obviously not stable in light of changing CPU speed. */
-    if (tps == 0) {
+    if (timer->tps == 0) {
 	struct timeval tv_start, tv_stop;
 	double tv_elapsed;
-	cairo_perf_timer_start ();
+	cairo_perf_timer_start (timer);
 	gettimeofday (&tv_start, NULL);
 	usleep (20000);
-	cairo_perf_timer_stop ();
+	cairo_perf_timer_stop (timer);
 	gettimeofday (&tv_stop, NULL);
 	tv_elapsed = ((tv_stop.tv_sec - tv_start.tv_sec) +
 		      + (tv_stop.tv_usec - tv_start.tv_usec) / 1000000.0);
-	tps = round (cairo_perf_timer_elapsed () / tv_elapsed);
+	timer->tps = round (cairo_perf_timer_elapsed (timer) / tv_elapsed);
     }
-    return tps;
+    return timer->tps;
 #else
     /* For gettimeofday the units are micro-seconds */
     return 1000000;
diff --git a/perf/cairo-perf.c b/perf/cairo-perf.c
index 44e842b..176e346 100644
--- a/perf/cairo-perf.c
+++ b/perf/cairo-perf.c
@@ -33,6 +33,9 @@
 #include <unistd.h>
 /* For basename */
 #include <libgen.h>
+/* For threading */
+#include <pthread.h>
+#include <errno.h>
 
 #ifdef HAVE_SCHED_H
 #include <sched.h>
@@ -42,13 +45,11 @@
 #define CAIRO_PERF_LOW_STD_DEV		0.03
 #define CAIRO_PERF_STABLE_STD_DEV_COUNT	5
 
-typedef struct _cairo_perf_case {
+static struct _cairo_perf_case {
     CAIRO_PERF_DECL (*run);
     unsigned int min_size;
     unsigned int max_size;
-} cairo_perf_case_t;
-
-cairo_perf_case_t perf_cases[];
+} perf_cases[];
 
 /* Some targets just aren't that interesting for performance testing,
  * (not least because many of these surface types use a meta-surface
@@ -105,6 +106,7 @@ _content_to_string (cairo_content_t content)
 
 void
 cairo_perf_run (cairo_perf_t		*perf,
+		cairo_t			*cr,
 		const char		*name,
 		cairo_perf_func_t	 perf_func)
 {
@@ -142,12 +144,12 @@ cairo_perf_run (cairo_perf_t		*perf,
 
     /* We run one iteration in advance to warm caches, etc. */
     cairo_perf_yield ();
-    (perf_func) (perf->cr, perf->size, perf->size);
+    (perf_func) (perf->timer, cr, perf->size, perf->size);
 
     low_std_dev_count = 0;
     for (i =0; i < perf->iterations; i++) {
 	cairo_perf_yield ();
-	times[i] = (perf_func) (perf->cr, perf->size, perf->size);
+	times[i] = (perf_func) (perf->timer, cr, perf->size, perf->size);
 
 	if (perf->raw) {
 	    if (i == 0)
@@ -155,7 +157,7 @@ cairo_perf_run (cairo_perf_t		*perf,
 			perf->target->name,
 			_content_to_string (perf->target->content),
 			name, perf->size,
-			cairo_perf_ticks_per_second () / 1000.0);
+			cairo_perf_ticks_per_second (perf->timer) / 1000.0);
 	    printf (" %lld", times[i]);
 	} else {
 	    if (i > 0) {
@@ -184,8 +186,8 @@ cairo_perf_run (cairo_perf_t		*perf,
 
 	printf ("%10lld %#8.3f %#8.3f %#5.2f%% %3d\n",
 		stats.min_ticks,
-		(stats.min_ticks * 1000.0) / cairo_perf_ticks_per_second (),
-		(stats.median_ticks * 1000.0) / cairo_perf_ticks_per_second (),
+		(stats.min_ticks * 1000.0) / cairo_perf_ticks_per_second (perf->timer),
+		(stats.median_ticks * 1000.0) / cairo_perf_ticks_per_second (perf->timer),
 		stats.std_dev * 100.0, stats.iterations);
     }
 
@@ -228,9 +230,10 @@ parse_options (cairo_perf_t *perf, int argc, char *argv[])
     perf->list_only = FALSE;
     perf->names = NULL;
     perf->num_names = 0;
+    perf->threads = 0;
 
     while (1) {
-	c = getopt (argc, argv, "i:lr");
+	c = getopt (argc, argv, "it:lr");
 	if (c == -1)
 	    break;
 
@@ -244,6 +247,14 @@ parse_options (cairo_perf_t *perf, int argc, char *argv[])
 		exit (1);
 	    }
 	    break;
+	case 't':
+	    perf->threads = strtoul (optarg, &end, 10);
+	    if (*end != '\0') {
+		fprintf (stderr, "Invalid argument for -t (not an integer): %s\n",
+			 optarg);
+		exit (1);
+	    }
+	    break;
 	case 'l':
 	    perf->list_only = TRUE;
 	    break;
@@ -298,79 +309,129 @@ check_cpu_affinity(void)
 #endif
 }
 
-int
-main (int argc, char *argv[])
+static void *
+run_perf_case (void *arg)
 {
-    int i, j;
-    cairo_perf_case_t *perf_case;
-    cairo_perf_t perf;
-    const char *cairo_test_target = getenv ("CAIRO_TEST_TARGET");
-    cairo_boilerplate_target_t *target;
+    cairo_perf_t *perf = arg;
+    const cairo_boilerplate_target_t *target = perf->target;
     cairo_surface_t *surface;
+    cairo_t *cr;
+    void *closure = NULL;
+    void *result = NULL;
+
+    surface = (target->create_surface) (NULL,
+					target->content,
+					perf->size, perf->size,
+					CAIRO_BOILERPLATE_MODE_PERF,
+					&closure);
+    cairo_perf_timer_set_synchronize (perf->timer,
+	                              target->synchronize,
+				      closure);
+
+    cr = cairo_create (surface);
+
+    perf->kase->run (perf, cr, perf->size, perf->size);
+
+    if (cairo_status (cr)) {
+	fprintf (stderr, "Error: Test left cairo in an error state: %s\n",
+		 cairo_status_to_string (cairo_status (cr)));
+	result = (void *)0x1;
+    }
 
-    parse_options (&perf, argc, argv);
+    cairo_destroy (cr);
+    cairo_surface_destroy (surface);
 
-    if (check_cpu_affinity()) {
-        fputs(
-            "NOTICE: cairo-perf and the X server should be bound to CPUs (either the same\n"
-            "or separate) on SMP systems. Not doing so causes random results when the X\n"
-            "server is moved to or from cairo-perf's CPU during the benchmarks:\n"
-            "\n"
-            "    $ sudo taskset -cp 0 $(pidof X)\n"
-            "    $ taskset -cp 1 $$\n"
-            "\n"
-            "See taskset(1) for information about changing CPU affinity.\n",
-            stderr);
-    }
+    if (target->cleanup)
+	target->cleanup (closure);
+
+    return result;
+}
+
+static void *
+run_perf_cases (void *arg)
+{
+    const cairo_perf_t *options = arg;
+    cairo_perf_t perf = *options;
+    const char *cairo_test_target = getenv ("CAIRO_TEST_TARGET");
+    int i, j;
+    long err = 0;
+
+    perf.timer = cairo_perf_timer_create ();
 
     for (i = 0; targets[i].name; i++) {
-	perf.target = target = &targets[i];
+	perf.target = &targets[i];
 	perf.test_number = 0;
 
-	if (! target_is_measurable (target))
+	if (! target_is_measurable (perf.target))
 	    continue;
-	if (cairo_test_target && ! strstr (cairo_test_target, target->name))
+	if (cairo_test_target &&
+	       	! strstr (cairo_test_target, perf.target->name))
 	    continue;
 
 	for (j = 0; perf_cases[j].run; j++) {
+	    perf.kase = &perf_cases[j];
 
-	    perf_case = &perf_cases[j];
-
-	    for (perf.size = perf_case->min_size;
-		 perf.size <= perf_case->max_size;
+	    for (perf.size = perf.kase->min_size;
+		 perf.size <= perf.kase->max_size;
 		 perf.size *= 2)
 	    {
-		surface = (target->create_surface) (NULL,
-						    target->content,
-						    perf.size, perf.size,
-						    CAIRO_BOILERPLATE_MODE_PERF,
-						    &target->closure);
-		cairo_perf_timer_set_synchronize (target->synchronize,
-						  target->closure);
-
-		perf.cr = cairo_create (surface);
-
-		perf_case->run (&perf, perf.cr, perf.size, perf.size);
-
-		if (cairo_status (perf.cr)) {
-		    fprintf (stderr, "Error: Test left cairo in an error state: %s\n",
-			     cairo_status_to_string (cairo_status (perf.cr)));
-		    exit (1);
-		}
+		err += !! run_perf_case (&perf);
+	    }
+	}
+    }
 
-		cairo_destroy (perf.cr);
-		cairo_surface_destroy (surface);
+    cairo_perf_timer_destroy (perf.timer);
 
-		if (target->cleanup)
-		    target->cleanup (target->closure);
+    return (void *) err;
+}
+
+int
+main (int argc, char *argv[])
+{
+    cairo_perf_t perf;
+    long err;
+
+    parse_options (&perf, argc, argv);
+
+    if (perf.threads) {
+	unsigned int i;
+	pthread_t *threads = xmalloc (sizeof (pthread_t) * perf.threads);
+	void *result;
+	for (i = 0; i < perf.threads; i++) {
+	    if (pthread_create (&threads[i], NULL,
+				run_perf_cases, &perf) < 0) {
+		fprintf (stderr, "Unable to create thread: %s\n",
+			strerror (errno));
+		exit (1);
 	    }
 	}
+	err = 0;
+	for (i = 0; i < perf.threads; i++) {
+	    pthread_join (threads[i], &result);
+	    err += !! result;
+	}
+	free (threads);
+    } else {
+	if (check_cpu_affinity()) {
+	    fputs(
+		    "NOTICE: cairo-perf and the X server should be bound to CPUs (either the same\n"
+		    "or separate) on SMP systems. Not doing so causes random results when the X\n"
+		    "server is moved to or from cairo-perf's CPU during the benchmarks:\n"
+		    "\n"
+		    "    $ sudo taskset -cp 0 $(pidof X)\n"
+		    "    $ taskset -cp 1 $$\n"
+		    "\n"
+		    "See taskset(1) for information about changing CPU affinity.\n",
+		    stderr);
+	}
+
+	err = (long) run_perf_cases (&perf);
     }
 
-    return 0;
+    return !! err;
 }
 
-cairo_perf_case_t perf_cases[] = {
+static cairo_perf_case_t perf_cases[] = {
     { paint,  256, 512},
     { fill,   64, 256},
     { stroke, 64, 256},
diff --git a/perf/cairo-perf.h b/perf/cairo-perf.h
index 1fef997..9240e81 100644
--- a/perf/cairo-perf.h
+++ b/perf/cairo-perf.h
@@ -35,34 +35,43 @@ typedef uint64_t cairo_perf_ticks_t;
 #include "cairo-stats.h"
 
 /* timers */
+typedef struct _cairo_perf_timer cairo_perf_timer_t;
 
+cairo_perf_timer_t *
+cairo_perf_timer_create (void);
 void
-cairo_perf_timer_start (void);
+cairo_perf_timer_destroy (cairo_perf_timer_t *timer);
+void
+cairo_perf_timer_start (cairo_perf_timer_t *timer);
 
 void
-cairo_perf_timer_stop (void);
+cairo_perf_timer_stop (cairo_perf_timer_t *timer);
 
 typedef void
 (*cairo_perf_timer_synchronize_t) (void *closure);
 
 void
-cairo_perf_timer_set_synchronize (cairo_perf_timer_synchronize_t	 synchronize,
+cairo_perf_timer_set_synchronize (cairo_perf_timer_t			*timer,
+	                          cairo_perf_timer_synchronize_t	 synchronize,
 				  void					*closure);
 
 cairo_perf_ticks_t
-cairo_perf_timer_elapsed (void);
+cairo_perf_timer_elapsed (cairo_perf_timer_t *timer);
 
 cairo_perf_ticks_t
-cairo_perf_ticks_per_second (void);
+cairo_perf_ticks_per_second (cairo_perf_timer_t *timer);
 
 /* yield */
 
 void
 cairo_perf_yield (void);
 
+typedef struct _cairo_perf_case cairo_perf_case_t;
+
 /* running a test case */
 typedef struct _cairo_perf {
     /* Options from command-line */
+    unsigned int threads;
     unsigned int iterations;
     cairo_bool_t exact_iterations;
     cairo_bool_t raw;
@@ -71,22 +80,25 @@ typedef struct _cairo_perf {
     unsigned int num_names;
 
     /* Stuff used internally */
+    cairo_perf_case_t *kase;
     cairo_boilerplate_target_t *target;
+    cairo_perf_timer_t *timer;
     unsigned int test_number;
     unsigned int size;
-    cairo_t *cr;
 } cairo_perf_t;
 
 typedef cairo_perf_ticks_t
-(*cairo_perf_func_t) (cairo_t *cr, int width, int height);
+(*cairo_perf_func_t) (cairo_perf_timer_t *timer, cairo_t *cr, int width, int height);
 
 void
 cairo_perf_run (cairo_perf_t		*perf,
+		cairo_t			*cr,
 		const char		*name,
 		cairo_perf_func_t	 perf_func);
 
 void
 cairo_perf_cover_sources_and_operators (cairo_perf_t		*perf,
+					cairo_t			*cr,
 					const char		*name,
 					cairo_perf_func_t	 perf_func);
 
diff --git a/perf/fill.c b/perf/fill.c
index 2a41355..32e0765 100644
--- a/perf/fill.c
+++ b/perf/fill.c
@@ -26,24 +26,24 @@
 #include "cairo-perf.h"
 
 static cairo_perf_ticks_t
-do_fill (cairo_t *cr, int width, int height)
+do_fill (cairo_perf_timer_t *timer, cairo_t *cr, int width, int height)
 {
     cairo_arc (cr,
 	       width/2.0, height/2.0,
 	       width/3.0,
 	       0, 2 * M_PI);
 
-    cairo_perf_timer_start ();
+    cairo_perf_timer_start (timer);
 
     cairo_fill (cr);
 
-    cairo_perf_timer_stop ();
+    cairo_perf_timer_stop (timer);
 
-    return cairo_perf_timer_elapsed ();
+    return cairo_perf_timer_elapsed (timer);
 }
 
 void
 fill (cairo_perf_t *perf, cairo_t *cr, int width, int height)
 {
-    cairo_perf_cover_sources_and_operators (perf, "fill", do_fill);
+    cairo_perf_cover_sources_and_operators (perf, cr, "fill", do_fill);
 }
diff --git a/perf/long-lines.c b/perf/long-lines.c
index 62e8e16..85d1d80 100644
--- a/perf/long-lines.c
+++ b/perf/long-lines.c
@@ -40,7 +40,7 @@ typedef enum { LONG_LINES_UNCROPPED, LONG_LINES_CROPPED } long_lines_crop_t;
 #define LONG_FACTOR  50.0
 
 static cairo_perf_ticks_t
-do_long_lines (cairo_t *cr, int width, int height, long_lines_crop_t crop)
+do_long_lines (cairo_perf_timer_t *timer, cairo_t *cr, int width, int height, long_lines_crop_t crop)
 {
     int i;
     double x, y, dx, dy, min_x, min_y, max_x, max_y;
@@ -67,7 +67,7 @@ do_long_lines (cairo_t *cr, int width, int height, long_lines_crop_t crop)
     dx = outer_width / NUM_LINES;
     dy = outer_height / NUM_LINES;
 
-    cairo_perf_timer_start ();
+    cairo_perf_timer_start (timer);
 
     for (i = 0; i < NUM_LINES; i++) {
 	cairo_move_to (cr, 0, 0);
@@ -90,28 +90,28 @@ do_long_lines (cairo_t *cr, int width, int height, long_lines_crop_t crop)
 	y += dy;
     }
 
-    cairo_perf_timer_stop ();
+    cairo_perf_timer_stop (timer);
 
     cairo_restore (cr);
 
-    return cairo_perf_timer_elapsed ();
+    return cairo_perf_timer_elapsed (timer);
 }
 
 static cairo_perf_ticks_t
-long_lines_uncropped (cairo_t *cr, int width, int height)
+long_lines_uncropped (cairo_perf_timer_t *timer, cairo_t *cr, int width, int height)
 {
-    return do_long_lines (cr, width, height, LONG_LINES_UNCROPPED);
+    return do_long_lines (timer, cr, width, height, LONG_LINES_UNCROPPED);
 }
 
 static cairo_perf_ticks_t
-long_lines_cropped (cairo_t *cr, int width, int height)
+long_lines_cropped (cairo_perf_timer_t *timer, cairo_t *cr, int width, int height)
 {
-    return do_long_lines (cr, width, height, LONG_LINES_CROPPED);
+    return do_long_lines (timer, cr, width, height, LONG_LINES_CROPPED);
 }
 
 void
 long_lines (cairo_perf_t *perf, cairo_t *cr, int width, int height)
 {
-    cairo_perf_run (perf, "long-lines-uncropped", long_lines_uncropped);
-    cairo_perf_run (perf, "long-lines-cropped", long_lines_cropped);
+    cairo_perf_run (perf, cr, "long-lines-uncropped", long_lines_uncropped);
+    cairo_perf_run (perf, cr, "long-lines-cropped", long_lines_cropped);
 }
diff --git a/perf/mosaic.c b/perf/mosaic.c
index 7172a9d..ad6b148 100644
--- a/perf/mosaic.c
+++ b/perf/mosaic.c
@@ -93,7 +93,7 @@ mosaic_next_path (cairo_t *cr, struct mosaic_region_iter *iter)
 }
 
 static cairo_perf_ticks_t
-mosaic_perform(cairo_t *cr, unsigned flags, int width, int height)
+mosaic_perform(cairo_perf_timer_t *timer, cairo_t *cr, unsigned flags, int width, int height)
 {
     struct mosaic_region_iter iter;
 
@@ -118,7 +118,7 @@ mosaic_perform(cairo_t *cr, unsigned flags, int width, int height)
      * tessellating them as dictated by the flags.  */
     mosaic_region_iter_init (&iter, flags & MOSAIC_CURVE_TO);
 
-    cairo_perf_timer_start ();
+    cairo_perf_timer_start (timer);
     while (mosaic_next_path (cr, &iter)) {
 	if (flags & MOSAIC_FILL) {
 	    cairo_fill (cr);
@@ -129,40 +129,40 @@ mosaic_perform(cairo_t *cr, unsigned flags, int width, int height)
 	    cairo_in_fill (cr, x, y);
 	}
     }
-    cairo_perf_timer_stop ();
+    cairo_perf_timer_stop (timer);
 
-    return cairo_perf_timer_elapsed ();
+    return cairo_perf_timer_elapsed (timer);
 }
 
 static cairo_perf_ticks_t
-mosaic_fill_curves (cairo_t *cr, int width, int height)
+mosaic_fill_curves (cairo_perf_timer_t *timer, cairo_t *cr, int width, int height)
 {
-    return mosaic_perform (cr, MOSAIC_FILL | MOSAIC_CURVE_TO, width, height);
+    return mosaic_perform (timer, cr, MOSAIC_FILL | MOSAIC_CURVE_TO, width, height);
 }
 
 static cairo_perf_ticks_t
-mosaic_fill_lines (cairo_t *cr, int width, int height)
+mosaic_fill_lines (cairo_perf_timer_t *timer, cairo_t *cr, int width, int height)
 {
-    return mosaic_perform (cr, MOSAIC_FILL | MOSAIC_LINE_TO, width, height);
+    return mosaic_perform (timer, cr, MOSAIC_FILL | MOSAIC_LINE_TO, width, height);
 }
 
 static cairo_perf_ticks_t
-mosaic_tessellate_lines (cairo_t *cr, int width, int height)
+mosaic_tessellate_lines (cairo_perf_timer_t *timer, cairo_t *cr, int width, int height)
 {
-    return mosaic_perform (cr, MOSAIC_TESSELLATE | MOSAIC_LINE_TO, width, height);
+    return mosaic_perform (timer, cr, MOSAIC_TESSELLATE | MOSAIC_LINE_TO, width, height);
 }
 
 static cairo_perf_ticks_t
-mosaic_tessellate_curves (cairo_t *cr, int width, int height)
+mosaic_tessellate_curves (cairo_perf_timer_t *timer, cairo_t *cr, int width, int height)
 {
-    return mosaic_perform (cr, MOSAIC_TESSELLATE | MOSAIC_CURVE_TO, width, height);
+    return mosaic_perform (timer, cr, MOSAIC_TESSELLATE | MOSAIC_CURVE_TO, width, height);
 }
 
 void
 mosaic (cairo_perf_t *perf, cairo_t *cr, int width, int height)
 {
-    cairo_perf_run (perf, "mosaic_fill_curves", mosaic_fill_curves);
-    cairo_perf_run (perf, "mosaic_fill_lines", mosaic_fill_lines);
-    cairo_perf_run (perf, "mosaic_tessellate_curves", mosaic_tessellate_curves);
-    cairo_perf_run (perf, "mosaic_tessellate_lines", mosaic_tessellate_lines);
+    cairo_perf_run (perf, cr, "mosaic_fill_curves", mosaic_fill_curves);
+    cairo_perf_run (perf, cr, "mosaic_fill_lines", mosaic_fill_lines);
+    cairo_perf_run (perf, cr, "mosaic_tessellate_curves", mosaic_tessellate_curves);
+    cairo_perf_run (perf, cr, "mosaic_tessellate_lines", mosaic_tessellate_lines);
 }
diff --git a/perf/paint.c b/perf/paint.c
index 6f75016..fad1743 100644
--- a/perf/paint.c
+++ b/perf/paint.c
@@ -26,19 +26,19 @@
 #include "cairo-perf.h"
 
 static cairo_perf_ticks_t
-do_paint (cairo_t *cr, int width, int height)
+do_paint (cairo_perf_timer_t *timer, cairo_t *cr, int width, int height)
 {
-    cairo_perf_timer_start ();
+    cairo_perf_timer_start (timer);
 
     cairo_paint (cr);
 
-    cairo_perf_timer_stop ();
+    cairo_perf_timer_stop (timer);
 
-    return cairo_perf_timer_elapsed ();
+    return cairo_perf_timer_elapsed (timer);
 }
 
 void
 paint (cairo_perf_t *perf, cairo_t *cr, int width, int height)
 {
-    cairo_perf_cover_sources_and_operators (perf, "paint", do_paint);
+    cairo_perf_cover_sources_and_operators (perf, cr, "paint", do_paint);
 }
diff --git a/perf/pattern_create_radial.c b/perf/pattern_create_radial.c
index 09f15a8..bc37175 100644
--- a/perf/pattern_create_radial.c
+++ b/perf/pattern_create_radial.c
@@ -56,12 +56,12 @@ generate_double_in_range (double min, double max)
 }
 
 static cairo_perf_ticks_t
-do_pattern_create_radial (cairo_t *cr, int width, int height)
+do_pattern_create_radial (cairo_perf_timer_t *timer, cairo_t *cr, int width, int height)
 {
     int i;
     cairo_pattern_t *pattern;
 
-    cairo_perf_timer_start ();
+    cairo_perf_timer_start (timer);
 
     for (i = 0; i < RADIALS_COUNT; i++)
     {
@@ -72,9 +72,9 @@ do_pattern_create_radial (cairo_t *cr, int width, int height)
         cairo_pattern_destroy (pattern);
     }
 
-    cairo_perf_timer_stop ();
+    cairo_perf_timer_stop (timer);
 
-    return cairo_perf_timer_elapsed ();
+    return cairo_perf_timer_elapsed (timer);
 }
 
 void
@@ -93,6 +93,7 @@ pattern_create_radial (cairo_perf_t *perf, cairo_t *cr, int width, int height)
         radials[i].radius1 = generate_double_in_range (0.0, 1000.0);
     }
 
-    cairo_perf_run (perf, "pattern_create_radial",
-                          do_pattern_create_radial);
+    cairo_perf_run (perf, cr,
+	            "pattern_create_radial",
+		    do_pattern_create_radial);
 }
diff --git a/perf/rectangles.c b/perf/rectangles.c
index 9fa89f5..1933e57 100644
--- a/perf/rectangles.c
+++ b/perf/rectangles.c
@@ -35,11 +35,11 @@ static struct
 } rects[RECTANGLE_COUNT];
 
 static cairo_perf_ticks_t
-do_rectangles (cairo_t *cr, int width, int height)
+do_rectangles (cairo_perf_timer_t *timer, cairo_t *cr, int width, int height)
 {
     int i;
 
-    cairo_perf_timer_start ();
+    cairo_perf_timer_start (timer);
 
     for (i = 0; i < RECTANGLE_COUNT; i++)
     {
@@ -48,9 +48,9 @@ do_rectangles (cairo_t *cr, int width, int height)
         cairo_fill (cr);
     }
 
-    cairo_perf_timer_stop ();
+    cairo_perf_timer_stop (timer);
 
-    return cairo_perf_timer_elapsed ();
+    return cairo_perf_timer_elapsed (timer);
 }
 
 void
@@ -67,5 +67,5 @@ rectangles (cairo_perf_t *perf, cairo_t *cr, int width, int height)
         rects[i].height = (rand () % (height / 10)) + 1;
     }
 
-    cairo_perf_run (perf, "rectangles", do_rectangles);
+    cairo_perf_run (perf, cr, "rectangles", do_rectangles);
 }
diff --git a/perf/stroke.c b/perf/stroke.c
index 0b4ea8e..bf8b98b 100644
--- a/perf/stroke.c
+++ b/perf/stroke.c
@@ -26,7 +26,7 @@
 #include "cairo-perf.h"
 
 static cairo_perf_ticks_t
-do_stroke (cairo_t *cr, int width, int height)
+do_stroke (cairo_perf_timer_t *timer, cairo_t *cr, int width, int height)
 {
     cairo_arc (cr,
 	       width/2.0, height/2.0,
@@ -34,18 +34,18 @@ do_stroke (cairo_t *cr, int width, int height)
 	       0, 2 * M_PI);
     cairo_close_path (cr);
 
-    cairo_perf_timer_start ();
+    cairo_perf_timer_start (timer);
 
     cairo_set_line_width (cr, width/5.0);
     cairo_stroke (cr);
 
-    cairo_perf_timer_stop ();
+    cairo_perf_timer_stop (timer);
 
-    return cairo_perf_timer_elapsed ();
+    return cairo_perf_timer_elapsed (timer);
 }
 
 void
 stroke (cairo_perf_t *perf, cairo_t *cr, int width, int height)
 {
-    cairo_perf_cover_sources_and_operators (perf, "stroke", do_stroke);
+    cairo_perf_cover_sources_and_operators (perf, cr, "stroke", do_stroke);
 }
diff --git a/perf/subimage_copy.c b/perf/subimage_copy.c
index 54f596f..44d2bb3 100644
--- a/perf/subimage_copy.c
+++ b/perf/subimage_copy.c
@@ -35,18 +35,18 @@
  */
 
 static cairo_perf_ticks_t
-do_subimage_copy (cairo_t *cr, int width, int height)
+do_subimage_copy (cairo_perf_timer_t *timer, cairo_t *cr, int width, int height)
 {
     cairo_rectangle (cr, 2, 2, 4, 4);
     cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
 
-    cairo_perf_timer_start ();
+    cairo_perf_timer_start (timer);
 
     cairo_fill (cr);
 
-    cairo_perf_timer_stop ();
+    cairo_perf_timer_stop (timer);
 
-    return cairo_perf_timer_elapsed ();
+    return cairo_perf_timer_elapsed (timer);
 }
 
 void
@@ -67,5 +67,5 @@ subimage_copy (cairo_perf_t *perf, cairo_t *cr, int width, int height)
     cairo_set_source_surface (cr, image, 0, 0);
     cairo_surface_destroy (image);
 
-    cairo_perf_run (perf, "subimage_copy", do_subimage_copy);
+    cairo_perf_run (perf, cr, "subimage_copy", do_subimage_copy);
 }
diff --git a/perf/tessellate.c b/perf/tessellate.c
index fc97db7..1bd6d40 100644
--- a/perf/tessellate.c
+++ b/perf/tessellate.c
@@ -99,14 +99,14 @@ point_t points[300] = {
 };
 
 static cairo_perf_ticks_t
-do_tessellate (cairo_t *cr, int num_points)
+do_tessellate (cairo_perf_timer_t *timer, cairo_t *cr, int num_points)
 {
     int i;
 
     for (i=0; i < num_points; i++)
 	cairo_line_to (cr, points[i].x, points[i].y);
 
-    cairo_perf_timer_start ();
+    cairo_perf_timer_start (timer);
 
     /* We'd like to measure just tessellation without
      * rasterization. For now, we can do that with cairo_in_fill. But
@@ -115,37 +115,37 @@ do_tessellate (cairo_t *cr, int num_points)
      * include tessellation. */
     cairo_in_fill (cr, 50, 50);
 
-    cairo_perf_timer_stop ();
+    cairo_perf_timer_stop (timer);
 
     cairo_new_path (cr);
 
-    return cairo_perf_timer_elapsed ();
+    return cairo_perf_timer_elapsed (timer);
 }
 
 static cairo_perf_ticks_t
-tessellate_16 (cairo_t *cr, int width, int height)
+tessellate_16 (cairo_perf_timer_t *timer, cairo_t *cr, int width, int height)
 {
-    return do_tessellate (cr, 16);
+    return do_tessellate (timer, cr, 16);
 }
 
 static cairo_perf_ticks_t
-tessellate_64 (cairo_t *cr, int width, int height)
+tessellate_64 (cairo_perf_timer_t *timer, cairo_t *cr, int width, int height)
 {
-    return do_tessellate (cr, 64);
+    return do_tessellate (timer, cr, 64);
 }
 
 static cairo_perf_ticks_t
-tessellate_256 (cairo_t *cr, int width, int height)
+tessellate_256 (cairo_perf_timer_t *timer, cairo_t *cr, int width, int height)
 {
-    return do_tessellate (cr, 256);
+    return do_tessellate (timer, cr, 256);
 }
 
 void
 tessellate (cairo_perf_t *perf, cairo_t *cr, int width, int height)
 {
-    cairo_perf_run (perf, "tessellate-16", tessellate_16);
-    cairo_perf_run (perf, "tessellate-64", tessellate_64);
-    cairo_perf_run (perf, "tessellate-256", tessellate_256);
+    cairo_perf_run (perf, cr, "tessellate-16", tessellate_16);
+    cairo_perf_run (perf, cr, "tessellate-64", tessellate_64);
+    cairo_perf_run (perf, cr, "tessellate-256", tessellate_256);
 }
 
 #if 0
diff --git a/perf/text.c b/perf/text.c
index de5e0cd..d547b95 100644
--- a/perf/text.c
+++ b/perf/text.c
@@ -26,14 +26,14 @@
 #include "cairo-perf.h"
 
 static cairo_perf_ticks_t
-do_text (cairo_t *cr, int width, int height)
+do_text (cairo_perf_timer_t *timer, cairo_t *cr, int width, int height)
 {
     const char text[] = "the jay, pig, fox, zebra and my wolves quack";
     int len = strlen (text);
     double x, y;
     int i = 0;
 
-    cairo_perf_timer_start ();
+    cairo_perf_timer_start (timer);
 
     cairo_set_font_size (cr, 9);
     do {
@@ -49,13 +49,13 @@ do_text (cairo_t *cr, int width, int height)
 	    i = 0;
     } while (y < height);
 
-    cairo_perf_timer_stop ();
+    cairo_perf_timer_stop (timer);
 
-    return cairo_perf_timer_elapsed ();
+    return cairo_perf_timer_elapsed (timer);
 }
 
 void
 text (cairo_perf_t *perf, cairo_t *cr, int width, int height)
 {
-    cairo_perf_cover_sources_and_operators (perf, "text", do_text);
+    cairo_perf_cover_sources_and_operators (perf, cr, "text", do_text);
 }
diff --git a/perf/unaligned-clip.c b/perf/unaligned-clip.c
index c7b9d21..f2a4c1d 100644
--- a/perf/unaligned-clip.c
+++ b/perf/unaligned-clip.c
@@ -29,11 +29,11 @@
 #include "cairo-perf.h"
 
 static cairo_perf_ticks_t
-do_unaligned_clip (cairo_t *cr, int width, int height)
+do_unaligned_clip (cairo_perf_timer_t *timer, cairo_t *cr, int width, int height)
 {
     cairo_save (cr);
 
-    cairo_perf_timer_start ();
+    cairo_perf_timer_start (timer);
     /* First a triangular clip that obviously isn't along device-pixel
      * boundaries. */
     cairo_move_to (cr, 50, 50);
@@ -52,15 +52,15 @@ do_unaligned_clip (cairo_t *cr, int width, int height)
     cairo_close_path (cr);
 
     cairo_clip (cr);
-    cairo_perf_timer_stop ();
+    cairo_perf_timer_stop (timer);
 
     cairo_restore (cr);
 
-    return cairo_perf_timer_elapsed ();
+    return cairo_perf_timer_elapsed (timer);
 }
 
 void
 unaligned_clip (cairo_perf_t *perf, cairo_t *cr, int width, int height)
 {
-    cairo_perf_run (perf, "unaligned_clip", do_unaligned_clip);
+    cairo_perf_run (perf, cr, "unaligned_clip", do_unaligned_clip);
 }
diff --git a/perf/world-map.c b/perf/world-map.c
index eef3619..9509844 100644
--- a/perf/world-map.c
+++ b/perf/world-map.c
@@ -47,12 +47,12 @@ typedef struct _wm_element {
 #include "world-map.h"
 
 static cairo_perf_ticks_t
-do_world_map (cairo_t *cr, int width, int height)
+do_world_map (cairo_perf_timer_t *timer, cairo_t *cr, int width, int height)
 {
     const wm_element_t *e;
     double cx, cy;
 
-    cairo_perf_timer_start ();
+    cairo_perf_timer_start (timer);
 
     cairo_set_source_rgb (cr, .68, .85, .90); /* lightblue */
     cairo_rectangle (cr, 0, 0, 800, 400);
@@ -95,13 +95,13 @@ do_world_map (cairo_t *cr, int width, int height)
 	e++;
     }
 
-    cairo_perf_timer_stop ();
+    cairo_perf_timer_stop (timer);
 
-    return cairo_perf_timer_elapsed ();
+    return cairo_perf_timer_elapsed (timer);
 }
 
 void
 world_map (cairo_perf_t *perf, cairo_t *cr, int width, int height)
 {
-    cairo_perf_run (perf, "world_map", do_world_map);
+    cairo_perf_run (perf, cr, "world_map", do_world_map);
 }
diff --git a/perf/zrusin.c b/perf/zrusin.c
index 6840775..a759764 100644
--- a/perf/zrusin.c
+++ b/perf/zrusin.c
@@ -45,11 +45,11 @@ zrusin_another_path (cairo_t *cr)
 }
 
 static cairo_perf_ticks_t
-zrusin_another_tessellate (cairo_t *cr, int width, int height)
+zrusin_another_tessellate (cairo_perf_timer_t *timer, cairo_t *cr, int width, int height)
 {
     zrusin_another_path (cr);
 
-    cairo_perf_timer_start ();
+    cairo_perf_timer_start (timer);
 
     /* We'd like to measure just tessellation without
      * rasterization. For now, we can do that with cairo_in_fill. But
@@ -58,33 +58,37 @@ zrusin_another_tessellate (cairo_t *cr, int width, int height)
      * include tessellation. */
     cairo_in_fill (cr, 50, 50);
 
-    cairo_perf_timer_stop ();
+    cairo_perf_timer_stop (timer);
 
     cairo_new_path (cr);
 
-    return cairo_perf_timer_elapsed ();
+    return cairo_perf_timer_elapsed (timer);
 }
 
 static cairo_perf_ticks_t
-zrusin_another_fill (cairo_t *cr, int width, int height)
+zrusin_another_fill (cairo_perf_timer_t *timer, cairo_t *cr, int width, int height)
 {
     zrusin_another_path (cr);
     cairo_set_source_rgb (cr, 0.0, 0.0, 0.8); /* blue */
 
-    cairo_perf_timer_start ();
+    cairo_perf_timer_start (timer);
 
     cairo_fill (cr);
 
-    cairo_perf_timer_stop ();
+    cairo_perf_timer_stop (timer);
 
     cairo_new_path (cr);
 
-    return cairo_perf_timer_elapsed ();
+    return cairo_perf_timer_elapsed (timer);
 }
 
 void
 zrusin (cairo_perf_t *perf, cairo_t *cr, int width, int height)
 {
-    cairo_perf_run (perf, "zrusin_another_tessellate", zrusin_another_tessellate);
-    cairo_perf_run (perf, "zrusin_another_fill", zrusin_another_fill);
+    cairo_perf_run (perf, cr,
+	            "zrusin_another_tessellate",
+		    zrusin_another_tessellate);
+    cairo_perf_run (perf, cr,
+	            "zrusin_another_fill",
+		    zrusin_another_fill);
 }


More information about the cairo mailing list