Commit af9fbd17 authored by Chris Wilson's avatar Chris Wilson

Introduce a new compositor architecture

Having spent the last dev cycle looking at how we could specialize the
compositors for various backends, we once again look for the
commonalities in order to reduce the duplication. In part this is
motivated by the idea that spans is a good interface for both the
existent GL backend and pixman, and so they deserve a dedicated
compositor. xcb/xlib target an identical rendering system and so they
should be using the same compositor, and it should be possible to run
that same compositor locally against pixman to generate reference tests.
Signed-off-by: Chris Wilson's avatarChris Wilson <chris@chris-wilson.co.uk>

P.S. This brings massive upheaval (read breakage) I've tried delaying in
order to fix as many things as possible but now this one patch does far,
far, far too much. Apologies in advance for breaking your favourite
backend, but trust me in that the end result will be much better. :)
parent 0540bf38
......@@ -31,7 +31,6 @@
#if CAIRO_HAS_XLIB_XRENDER_SURFACE
#include <cairo-xlib-xrender.h>
#endif
#include <cairo-xlib-surface-private.h>
#include <X11/Xutil.h> /* for XDestroyImage */
......@@ -412,6 +411,7 @@ _cairo_boilerplate_xlib_window_create_surface (const char *name,
cairo_status_t
cairo_boilerplate_xlib_surface_disable_render (cairo_surface_t *abstract_surface)
{
#if 0
/* The following stunt doesn't work with xlib-xcb because it doesn't use
* cairo_xlib_surface_t for its surfaces. Sadly, there is no sane
* alternative, so we can't disable render with xlib-xcb.
......@@ -439,6 +439,7 @@ cairo_boilerplate_xlib_surface_disable_render (cairo_surface_t *abstract_surface
#if CAIRO_XLIB_SURFACE_HAS_BUGGY_REPEAT
surface->buggy_repeat = TRUE;
#endif
#endif
#endif
return CAIRO_STATUS_SUCCESS;
......
......@@ -683,16 +683,12 @@ cairo_boilerplate_get_image_target (cairo_content_t content)
if (cairo_boilerplate_targets == NULL)
_cairo_boilerplate_register_all ();
for (list = cairo_boilerplate_targets; list != NULL; list = list->next) {
const cairo_boilerplate_target_t *target = list->target;
if (target->expected_type == CAIRO_SURFACE_TYPE_IMAGE &&
target->content == content)
{
return target;
}
switch (content) {
default:
case CAIRO_CONTENT_ALPHA: return NULL;
case CAIRO_CONTENT_COLOR: return &builtin_targets[1];
case CAIRO_CONTENT_COLOR_ALPHA: return &builtin_targets[0];
}
return NULL;
}
const cairo_boilerplate_target_t *
......
......@@ -202,11 +202,11 @@ CAIRO_ENABLE_SURFACE_BACKEND(skia, Skia, no, [
[skia_DIR="`pwd`/../skia"])
AC_ARG_WITH([skia-bulid],
[AS_HELP_STRING([--with-skia-build=(Release|Debug)]
[build of skia to link with, default is Relese])],
[build of skia to link with, default is Release])],
[skia_BUILD="$withval"],
[skia_BUILD="Release"])
skia_NONPKGCONFIG_CFLAGS="-I$skia_DIR/include/config -I$skia_DIR/include/core -I$skia_DIR/include/effects"
if test "x$(skia_BUILD)" = x"Relese"; then
if test "x$skia_BUILD" = x"Release"; then
skia_NONPKGCONFIG_CFLAGS="-DSK_RELEASE -DSK_CAN_USE_FLOAT $skia_NONPKGCONFIG_CFLAGS"
fi
skia_NONPKGCONFIG_LIBS="--start-group $skia_DIR/out/$skia_BUILD/obj.target/gyp/libeffects.a $skia_DIR/out/$skia_BUILD/obj.target/gyp/libimages.a $skia_DIR/out/$skia_BUILD/obj.target/gyp/libutils.a $skia_DIR/out/$skia_BUILD/obj.target/gyp/libopts.a $skia_DIR/out/$skia_BUILD/obj.target/gyp/libcore.a -end-group"
......
libcairoperf_sources = \
cairo-perf.c \
cairo-perf.c \
cairo-perf-report.c \
cairo-stats.c \
$(NULL)
......
......@@ -73,7 +73,7 @@ print_change_bar (double change,
double max_change,
int use_utf)
{
int units_per_cell = (int) ceil (max_change / CHANGE_BAR_WIDTH);
int units_per_cell = ceil (max_change / CHANGE_BAR_WIDTH);
static char const *ascii_boxes[8] = {
"****","***" ,"***", "**",
"**", "*", "*", ""
......@@ -369,7 +369,7 @@ main (int argc,
if (args.num_filenames) {
reports = xcalloc (args.num_filenames, sizeof (cairo_perf_report_t));
for (i = 0; i < args.num_filenames; i++) {
cairo_perf_report_load (&reports[i], args.filenames[i],
cairo_perf_report_load (&reports[i], args.filenames[i], i,
test_report_cmp_name);
printf ("loaded: %s, %d tests\n",
args.filenames[i], reports[i].tests_count);
......@@ -377,7 +377,7 @@ main (int argc,
} else {
args.num_filenames = 1;
reports = xcalloc (args.num_filenames, sizeof (cairo_perf_report_t));
cairo_perf_report_load (&reports[0], NULL, test_report_cmp_name);
cairo_perf_report_load (&reports[0], NULL, 0, test_report_cmp_name);
}
cairo_perf_reports_compare (reports, args.num_filenames, &args.options);
......
......@@ -161,16 +161,14 @@ test_diff_print_binary (test_diff_t *diff,
else
printf ("%5s %26s", diff->tests[0]->backend, diff->tests[0]->name);
if (diff->tests[0]->size) {
printf (" %6.2f (%.2f %4.2f%%) -> %6.2f (%.2f %4.2f%%): %5.2fx ",
diff->tests[0]->stats.min_ticks / diff->tests[0]->stats.ticks_per_ms,
diff->tests[0]->stats.median_ticks / diff->tests[0]->stats.ticks_per_ms,
diff->tests[0]->stats.std_dev * 100,
diff->tests[1]->stats.min_ticks / diff->tests[1]->stats.ticks_per_ms,
diff->tests[1]->stats.median_ticks / diff->tests[1]->stats.ticks_per_ms,
diff->tests[1]->stats.std_dev * 100,
fabs (diff->change));
}
printf (" %6.2f (%.2f %4.2f%%) -> %6.2f (%.2f %4.2f%%): %5.2fx ",
diff->tests[0]->stats.min_ticks / diff->tests[0]->stats.ticks_per_ms,
diff->tests[0]->stats.median_ticks / diff->tests[0]->stats.ticks_per_ms,
diff->tests[0]->stats.std_dev * 100,
diff->tests[1]->stats.min_ticks / diff->tests[1]->stats.ticks_per_ms,
diff->tests[1]->stats.median_ticks / diff->tests[1]->stats.ticks_per_ms,
diff->tests[1]->stats.std_dev * 100,
fabs (diff->change));
if (diff->change > 1.0)
printf ("speedup\n");
......@@ -191,24 +189,32 @@ test_diff_print_multi (test_diff_t *diff,
double test_time;
double change;
printf ("%s (backend: %s-%s, size: %d)\n",
diff->tests[0]->name,
diff->tests[0]->backend,
diff->tests[0]->content,
diff->tests[0]->size);
if (diff->tests[0]->size) {
printf ("%s (backend: %s-%s, size: %d)\n",
diff->tests[0]->name,
diff->tests[0]->backend,
diff->tests[0]->content,
diff->tests[0]->size);
} else {
printf ("%s (backend: %s)\n",
diff->tests[0]->name,
diff->tests[0]->backend);
}
for (i = 0; i < diff->num_tests; i++) {
test_time = diff->tests[i]->stats.min_ticks;
if (! options->use_ticks)
test_time /= diff->tests[i]->stats.ticks_per_ms;
change = diff->max / test_time;
printf ("%8s %6.2f: %5.2fx ",
diff->tests[i]->configuration,
printf ("[%d] %6.2f: %5.2fx ",
diff->tests[i]->fileno,
diff->tests[i]->stats.min_ticks / diff->tests[i]->stats.ticks_per_ms,
change);
if (options->print_change_bars)
print_change_bar (change, max_change, options->use_utf);
else
printf("\n");
}
printf("\n");
......@@ -476,8 +482,11 @@ main (int argc,
reports = xmalloc (args.num_filenames * sizeof (cairo_perf_report_t));
for (i = 0; i < args.num_filenames; i++ )
cairo_perf_report_load (&reports[i], args.filenames[i], NULL);
for (i = 0; i < args.num_filenames; i++ ) {
cairo_perf_report_load (&reports[i], args.filenames[i], i, NULL);
printf ("[%d] %s\n", i, args.filenames[i]);
}
printf ("\n");
cairo_perf_reports_compare (reports, args.num_filenames, &args.options);
......
......@@ -50,12 +50,13 @@
#define CAIRO_PERF_ITERATIONS_DEFAULT 100
#define CAIRO_PERF_LOW_STD_DEV 0.03
#define CAIRO_PERF_STABLE_STD_DEV_COUNT 5
#define CAIRO_PERF_ITERATION_MS_DEFAULT 2000
#define CAIRO_PERF_STABLE_STD_DEV_COUNT 5
#define CAIRO_PERF_ITERATION_MS_DEFAULT 2000
#define CAIRO_PERF_ITERATION_MS_FAST 5
typedef struct _cairo_perf_case {
CAIRO_PERF_DECL (*run);
CAIRO_PERF_RUN_DECL (*run);
cairo_bool_t (*enabled) (cairo_perf_t *perf);
unsigned int min_size;
unsigned int max_size;
} cairo_perf_case_t;
......@@ -251,7 +252,7 @@ cairo_perf_run (cairo_perf_t *perf,
cairo_boilerplate_content (perf->target->content));
else
cairo_save (perf->cr);
times[i] = perf_func (perf->cr, perf->size, perf->size, loops) / loops;
times[i] = perf_func (perf->cr, perf->size, perf->size, loops) ;
if (similar)
cairo_pattern_destroy (cairo_pop_group (perf->cr));
else
......@@ -263,7 +264,7 @@ cairo_perf_run (cairo_perf_t *perf,
_content_to_string (perf->target->content, similar),
name, perf->size,
_cairo_time_to_double (_cairo_time_from_s (1.)) / 1000.);
printf (" %lld", (long long) times[i]);
printf (" %lld", (long long) (times[i] / (double) loops));
} else if (! perf->exact_iterations) {
if (i > 0) {
_cairo_stats_compute (&stats, times, i+1);
......@@ -287,18 +288,18 @@ cairo_perf_run (cairo_perf_t *perf,
if (count_func != NULL) {
double count = count_func (perf->cr, perf->size, perf->size);
fprintf (perf->summary,
"%10lld %#8.3f %#8.3f %#5.2f%% %3d: %.2f\n",
(long long) stats.min_ticks,
_cairo_time_to_s (stats.min_ticks) * 1000.0,
_cairo_time_to_s (stats.median_ticks) * 1000.0,
"%10lld/%d %#8.3f %#8.3f %#5.2f%% %3d: %.2f\n",
(long long) stats.min_ticks, loops,
_cairo_time_to_s (stats.min_ticks) * 1000.0 / loops,
_cairo_time_to_s (stats.median_ticks) * 1000.0 / loops,
stats.std_dev * 100.0, stats.iterations,
count / _cairo_time_to_s (stats.min_ticks));
} else {
fprintf (perf->summary,
"%10lld %#8.3f %#8.3f %#5.2f%% %3d\n",
(long long) stats.min_ticks,
_cairo_time_to_s (stats.min_ticks) * 1000.0,
_cairo_time_to_s (stats.median_ticks) * 1000.0,
"%10lld/%d %#8.3f %#8.3f %#5.2f%% %3d\n",
(long long) stats.min_ticks, loops,
_cairo_time_to_s (stats.min_ticks) * 1000.0 / loops,
_cairo_time_to_s (stats.median_ticks) * 1000.0 / loops,
stats.std_dev * 100.0, stats.iterations);
}
fflush (perf->summary);
......@@ -491,6 +492,9 @@ main (int argc,
for (j = 0; perf_cases[j].run; j++) {
const cairo_perf_case_t *perf_case = &perf_cases[j];
if (! perf_case->enabled (&perf))
continue;
for (perf.size = perf_case->min_size;
perf.size <= perf_case->max_size;
perf.size *= 2)
......@@ -536,42 +540,48 @@ main (int argc,
return 0;
}
#define FUNC(f) f, f##_enabled
const cairo_perf_case_t perf_cases[] = {
{ paint, 64, 512},
{ paint_with_alpha, 64, 512},
{ fill, 64, 512},
{ stroke, 64, 512},
{ text, 64, 512},
{ glyphs, 64, 512},
{ mask, 64, 512},
{ line, 32, 512},
{ curve, 32, 512},
{ disjoint, 64, 512},
{ hatching, 64, 512},
{ tessellate, 100, 100},
{ subimage_copy, 16, 512},
{ hash_table, 16, 16},
{ pattern_create_radial, 16, 16},
{ zrusin, 415, 415},
{ world_map, 800, 800},
{ box_outline, 100, 100},
{ mosaic, 800, 800 },
{ long_lines, 100, 100},
{ unaligned_clip, 100, 100},
{ rectangles, 512, 512},
{ rounded_rectangles, 512, 512},
{ long_dashed_lines, 512, 512},
{ composite_checker, 16, 512},
{ twin, 800, 800},
{ dragon, 1024, 1024 },
{ pythagoras_tree, 768, 768 },
{ intersections, 512, 512 },
{ many_strokes, 32, 512 },
{ wide_strokes, 32, 512 },
{ many_fills, 32, 512 },
{ wide_fills, 32, 512 },
{ many_curves, 32, 512 },
{ spiral, 512, 512 },
{ wave, 500, 500 },
{ FUNC(pixel), 1, 1 },
{ FUNC(paint), 64, 512},
{ FUNC(paint_with_alpha), 64, 512},
{ FUNC(fill), 64, 512},
{ FUNC(stroke), 64, 512},
{ FUNC(text), 64, 512},
{ FUNC(glyphs), 64, 512},
{ FUNC(mask), 64, 512},
{ FUNC(line), 32, 512},
{ FUNC(a1_line), 32, 512},
{ FUNC(curve), 32, 512},
{ FUNC(a1_curve), 32, 512},
{ FUNC(disjoint), 64, 512},
{ FUNC(hatching), 64, 512},
{ FUNC(tessellate), 100, 100},
{ FUNC(subimage_copy), 16, 512},
{ FUNC(hash_table), 16, 16},
{ FUNC(pattern_create_radial), 16, 16},
{ FUNC(zrusin), 415, 415},
{ FUNC(world_map), 800, 800},
{ FUNC(box_outline), 100, 100},
{ FUNC(mosaic), 800, 800 },
{ FUNC(long_lines), 100, 100},
{ FUNC(unaligned_clip), 100, 100},
{ FUNC(rectangles), 512, 512},
{ FUNC(rounded_rectangles), 512, 512},
{ FUNC(long_dashed_lines), 512, 512},
{ FUNC(composite_checker), 16, 512},
{ FUNC(twin), 800, 800},
{ FUNC(dragon), 1024, 1024 },
{ FUNC(sierpinski), 32, 1024 },
{ FUNC(pythagoras_tree), 768, 768 },
{ FUNC(intersections), 512, 512 },
{ FUNC(many_strokes), 32, 512 },
{ FUNC(wide_strokes), 32, 512 },
{ FUNC(many_fills), 32, 512 },
{ FUNC(wide_fills), 32, 512 },
{ FUNC(many_curves), 32, 512 },
{ FUNC(spiral), 512, 512 },
{ FUNC(wave), 500, 500 },
{ FUNC(fill_clip), 16, 512 },
{ NULL }
};
......@@ -110,6 +110,7 @@ do { \
static test_report_status_t
test_report_parse (test_report_t *report,
int fileno,
char *line,
char *configuration)
{
......@@ -137,6 +138,7 @@ test_report_parse (test_report_t *report,
skip_space ();
report->fileno = fileno;
report->configuration = configuration;
parse_string (report->backend);
end = strrchr (report->backend, '.');
......@@ -369,7 +371,7 @@ cairo_perf_report_sort_and_compute_stats (cairo_perf_report_t *report,
void
cairo_perf_report_load (cairo_perf_report_t *report,
const char *filename,
const char *filename, int id,
int (*cmp) (const void *, const void *))
{
FILE *file;
......@@ -401,6 +403,7 @@ cairo_perf_report_load (cairo_perf_report_t *report,
report->tests_size = 16;
report->tests = xmalloc (report->tests_size * sizeof (test_report_t));
report->tests_count = 0;
report->fileno = id;
if (filename == NULL) {
file = stdin;
......@@ -425,7 +428,7 @@ cairo_perf_report_load (cairo_perf_report_t *report,
break;
status = test_report_parse (&report->tests[report->tests_count],
line, report->configuration);
id, line, report->configuration);
if (status == TEST_REPORT_STATUS_ERROR)
fprintf (stderr, "Ignoring unrecognized line %d of %s:\n%s",
line_number, filename, line);
......
......@@ -79,7 +79,7 @@ basename_no_ext (char *path)
name = basename (path);
dot = strchr (name, '.');
dot = strrchr (name, '.');
if (dot)
*dot = '\0';
......@@ -108,6 +108,7 @@ struct trace {
void *closure;
cairo_surface_t *surface;
cairo_bool_t observe;
int tile_size;
};
cairo_bool_t
......@@ -132,7 +133,7 @@ cairo_perf_can_run (cairo_perf_t *perf,
return TRUE;
copy = xstrdup (name);
dot = strchr (copy, '.');
dot = strrchr (copy, '.');
if (dot != NULL)
*dot = '\0';
......@@ -435,6 +436,7 @@ parse_options (cairo_perf_t *perf,
perf->raw = FALSE;
perf->observe = FALSE;
perf->list_only = FALSE;
perf->tile_size = 0;
perf->names = NULL;
perf->num_names = 0;
perf->summary = stdout;
......@@ -443,7 +445,7 @@ parse_options (cairo_perf_t *perf,
perf->num_exclude_names = 0;
while (1) {
c = _cairo_getopt (argc, argv, "i:x:lsrvc");
c = _cairo_getopt (argc, argv, "t:i:x:lsrvc");
if (c == -1)
break;
......@@ -457,6 +459,14 @@ parse_options (cairo_perf_t *perf,
exit (1);
}
break;
case 't':
perf->tile_size = 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;
......@@ -489,6 +499,11 @@ parse_options (cairo_perf_t *perf,
}
}
if (perf->observe && perf->tile_size) {
fprintf (stderr, "Can't mix observer and tiling. Sorry.\n");
exit (1);
}
if (verbose && perf->summary == NULL)
perf->summary = stderr;
#if HAVE_UNISTD_H
......@@ -535,6 +550,79 @@ have_trace_filenames (cairo_perf_t *perf)
return FALSE;
}
static void
_tiling_surface_finish (cairo_surface_t *observer,
cairo_surface_t *target,
void *closure)
{
struct trace *args = closure;
cairo_surface_t *surface;
cairo_content_t content;
cairo_rectangle_t r;
int width, height;
int x, y, w, h;
cairo_recording_surface_get_extents (target, &r);
w = r.width;
h = r.height;
content = cairo_surface_get_content (target);
for (y = 0; y < h; y += args->tile_size) {
height = args->tile_size;
if (y + height > h)
height = h - y;
for (x = 0; x < w; x += args->tile_size) {
cairo_t *cr;
width = args->tile_size;
if (x + width > w)
width = w - x;
/* XXX to correctly observe the playback we would need
* to replay the target onto the observer directly.
*/
surface = args->target->create_similar (args->surface,
content, width, height);
cr = cairo_create (surface);
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
cairo_set_source_surface (cr, target, -x, -y);
cairo_paint (cr);
cairo_destroy (cr);
cairo_surface_destroy (surface);
}
}
}
static cairo_surface_t *
_tiling_surface_create (void *closure,
cairo_content_t content,
double width,
double height,
long uid)
{
cairo_rectangle_t r;
cairo_surface_t *surface, *observer;
r.x = r.y = 0;
r.width = width;
r.height = height;
surface = cairo_recording_surface_create (content, &r);
observer = cairo_surface_create_observer (surface,
CAIRO_SURFACE_OBSERVER_NORMAL);
cairo_surface_destroy (surface);
cairo_surface_observer_add_finish_callback (observer,
_tiling_surface_finish,
closure);
return observer;
}
static void
cairo_perf_trace (cairo_perf_t *perf,
const cairo_boilerplate_target_t *target,
......@@ -549,7 +637,7 @@ cairo_perf_trace (cairo_perf_t *perf,
char *trace_cpy, *name;
const cairo_script_interpreter_hooks_t hooks = {
&args,
_similar_surface_create,
perf->tile_size ? _tiling_surface_create : _similar_surface_create,
NULL, /* surface_destroy */
_context_create,
NULL, /* context_destroy */
......@@ -557,6 +645,7 @@ cairo_perf_trace (cairo_perf_t *perf,
NULL /* copy_page */
};
args.tile_size = perf->tile_size;
args.observe = perf->observe;
trace_cpy = xstrdup (trace);
......@@ -648,26 +737,30 @@ cairo_perf_trace (cairo_perf_t *perf,
}
cairo_script_interpreter_run (csi, trace);
line_no = cairo_script_interpreter_get_line_number (csi);
/* Finish before querying timings in case we are using an intermediate
* target and so need to destroy all surfaces before rendering
* commences.
*/
cairo_script_interpreter_finish (csi);
if (perf->observe) {
cairo_device_t *observer = cairo_surface_get_device (args.surface);
times[i] = _cairo_time_from_s (1.e9 * cairo_device_observer_elapsed (observer));
paint[i] = _cairo_time_from_s (1.e9 * cairo_device_observer_paint_elapsed (observer));
mask[i] = _cairo_time_from_s (1.e9 * cairo_device_observer_mask_elapsed (observer));
stroke[i] = _cairo_time_from_s (1.e9 * cairo_device_observer_stroke_elapsed (observer));
fill[i] = _cairo_time_from_s (1.e9 * cairo_device_observer_fill_elapsed (observer));
glyphs[i] = _cairo_time_from_s (1.e9 * cairo_device_observer_glyphs_elapsed (observer));
times[i] = _cairo_time_from_s (1.e-9 * cairo_device_observer_elapsed (observer));
paint[i] = _cairo_time_from_s (1.e-9 * cairo_device_observer_paint_elapsed (observer));
mask[i] = _cairo_time_from_s (1.e-9 * cairo_device_observer_mask_elapsed (observer));
stroke[i] = _cairo_time_from_s (1.e-9 * cairo_device_observer_stroke_elapsed (observer));
fill[i] = _cairo_time_from_s (1.e-9 * cairo_device_observer_fill_elapsed (observer));
glyphs[i] = _cairo_time_from_s (1.e-9 * cairo_device_observer_glyphs_elapsed (observer));
} else {
clear_surface (args.surface); /* queue a write to the sync'ed surface */
cairo_perf_timer_stop ();
times[i] = cairo_perf_timer_elapsed ();
}
cairo_script_interpreter_finish (csi);
scache_clear ();
line_no = cairo_script_interpreter_get_line_number (csi);
cairo_surface_destroy (args.surface);
if (target->cleanup)
......@@ -766,28 +859,28 @@ cairo_perf_trace (cairo_perf_t *perf,
fprintf (perf->summary,
" %#9.3f", _cairo_time_to_s (stats.median_ticks));
_cairo_stats_compute (&stats, paint, i+1);
_cairo_stats_compute (&stats, paint, i);
fprintf (perf->summary,
" %#9.3f", _cairo_time_to_s (stats.median_ticks));
_cairo_stats_compute (&stats, mask, i+1);
_cairo_stats_compute (&stats, mask, i);
fprintf (perf->summary,
" %#9.3f", _cairo_time_to_s (stats.median_ticks));
_cairo_stats_compute (&stats, fill, i+1);
_cairo_stats_compute (&stats, fill, i);
fprintf (perf->summary,
" %#9.3f", _cairo_time_to_s (stats.median_ticks));
_cairo_stats_compute (&stats, stroke, i+1);
_cairo_stats_compute (&stats, stroke, i);
fprintf (perf->summary,
" %#9.3f", _cairo_time_to_s (stats.median_ticks));
_cairo_stats_compute (&stats, glyphs, i+1);
_cairo_stats_compute (&stats, glyphs, i);
fprintf (perf->summary,
" %#9.3f", _cairo_time_to_s (stats.median_ticks));
fprintf (perf->summary,
" %5d\n", i+1);
" %5d\n", i);
} else {
fprintf (perf->summary,
"%#8.3f %#8.3f %#6.2f%% %4d/%d\n",
......@@ -807,11 +900,6 @@ out:
perf->test_number++;
free (trace_cpy);
cairo_debug_reset_static_data ();
#if HAVE_FCFINI
FcFini ();
#endif
}
static void
......
......@@ -83,6 +83,8 @@ typedef struct _cairo_perf {
double ms_per_iteration;
cairo_bool_t fast_and_sloppy;