static void cairo_perf_trace (cairo_perf_t *perf, const cairo_boilerplate_target_t *target, const char *trace) { cairo_surface_t *surface; void *closure; surface = (target->create_surface) (NULL, CAIRO_CONTENT_COLOR_ALPHA, 1, 1, 1, 1, CAIRO_BOILERPLATE_MODE_PERF, 0, &closure); if (surface == NULL) { fprintf (stderr, "Error: Failed to create target surface: %s\n", target->name); return; } cairo_perf_timer_set_synchronize (target->synchronize, closure); execute (perf, closure, surface, trace); cairo_surface_destroy (surface); if (target->cleanup) target->cleanup (closure); cairo_debug_reset_static_data (); #if HAVE_FCFINI FcFini (); #endif }
int main (int argc, char *argv[]) { int i, j; cairo_perf_t perf; cairo_surface_t *surface; parse_options (&perf, argc, argv); 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); } perf.targets = cairo_boilerplate_get_targets (&perf.num_targets, NULL); perf.times = xmalloc (perf.iterations * sizeof (cairo_perf_ticks_t)); for (i = 0; i < perf.num_targets; i++) { cairo_boilerplate_target_t *target = perf.targets[i]; if (! target_is_measurable (target)) continue; perf.target = target; perf.test_number = 0; for (j = 0; perf_cases[j].run; j++) { const cairo_perf_case_t *perf_case = &perf_cases[j]; for (perf.size = perf_case->min_size; perf.size <= perf_case->max_size; perf.size *= 2) { void *closure; surface = (target->create_surface) (NULL, target->content, perf.size, perf.size, perf.size, perf.size, CAIRO_BOILERPLATE_MODE_PERF, 0, &closure); if (surface == NULL) { fprintf (stderr, "Error: Failed to create target surface: %s\n", target->name); continue; } cairo_perf_timer_set_synchronize (target->synchronize, 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))); } cairo_destroy (perf.cr); cairo_surface_destroy (surface); if (target->cleanup) target->cleanup (closure); } } } cairo_perf_fini (&perf); return 0; }
static void cairo_perf_trace (cairo_perf_t *perf, const cairo_boilerplate_target_t *target, const char *trace) { static cairo_bool_t first_run = TRUE; unsigned int i; cairo_time_t *times, *paint, *mask, *fill, *stroke, *glyphs; cairo_stats_t stats = {0.0, 0.0}; struct trace args = { target }; int low_std_dev_count; char *trace_cpy, *name; const cairo_script_interpreter_hooks_t hooks = { &args, perf->tile_size ? _tiling_surface_create : _similar_surface_create, NULL, /* surface_destroy */ _context_create, NULL, /* context_destroy */ NULL, /* show_page */ NULL, /* copy_page */ _source_image_create, }; args.tile_size = perf->tile_size; args.observe = perf->observe; trace_cpy = xstrdup (trace); name = basename_no_ext (trace_cpy); if (perf->list_only) { printf ("%s\n", name); free (trace_cpy); return; } if (first_run) { if (perf->raw) { printf ("[ # ] %s.%-s %s %s %s ...\n", "backend", "content", "test-size", "ticks-per-ms", "time(ticks)"); } if (perf->summary) { if (perf->observe) { fprintf (perf->summary, "[ # ] %8s %28s %9s %9s %9s %9s %9s %9s %5s\n", "backend", "test", "total(s)", "paint(s)", "mask(s)", "fill(s)", "stroke(s)", "glyphs(s)", "count"); } else { fprintf (perf->summary, "[ # ] %8s %28s %8s %5s %5s %s\n", "backend", "test", "min(s)", "median(s)", "stddev.", "count"); } } first_run = FALSE; } times = perf->times; paint = times + perf->iterations; mask = paint + perf->iterations; stroke = mask + perf->iterations; fill = stroke + perf->iterations; glyphs = fill + perf->iterations; low_std_dev_count = 0; for (i = 0; i < perf->iterations && ! user_interrupt; i++) { cairo_script_interpreter_t *csi; cairo_status_t status; unsigned int line_no; args.surface = target->create_surface (NULL, CAIRO_CONTENT_COLOR_ALPHA, 1, 1, 1, 1, CAIRO_BOILERPLATE_MODE_PERF, &args.closure); fill_surface(args.surface); /* remove any clear flags */ if (perf->observe) { cairo_surface_t *obs; obs = cairo_surface_create_observer (args.surface, CAIRO_SURFACE_OBSERVER_NORMAL); cairo_surface_destroy (args.surface); args.surface = obs; } if (cairo_surface_status (args.surface)) { fprintf (stderr, "Error: Failed to create target surface: %s\n", target->name); return; } cairo_perf_timer_set_synchronize (target->synchronize, args.closure); if (i == 0) { describe (perf, args.closure); if (perf->summary) { fprintf (perf->summary, "[%3d] %8s %28s ", perf->test_number, perf->target->name, name); fflush (perf->summary); } } csi = cairo_script_interpreter_create (); cairo_script_interpreter_install_hooks (csi, &hooks); if (! perf->observe) { cairo_perf_yield (); cairo_perf_timer_start (); } 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.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 { fill_surface (args.surface); /* queue a write to the sync'ed surface */ cairo_perf_timer_stop (); times[i] = cairo_perf_timer_elapsed (); } scache_clear (); cairo_surface_destroy (args.surface); if (target->cleanup) target->cleanup (args.closure); status = cairo_script_interpreter_destroy (csi); if (status) { if (perf->summary) { fprintf (perf->summary, "Error during replay, line %d: %s\n", line_no, cairo_status_to_string (status)); } goto out; } if (perf->raw) { if (i == 0) printf ("[*] %s.%s %s.%d %g", perf->target->name, "rgba", name, 0, _cairo_time_to_double (_cairo_time_from_s (1)) / 1000.); printf (" %lld", (long long) times[i]); fflush (stdout); } else if (! perf->exact_iterations) { if (i > CAIRO_PERF_MIN_STD_DEV_COUNT) { _cairo_stats_compute (&stats, times, i+1); if (stats.std_dev <= CAIRO_PERF_LOW_STD_DEV) { if (++low_std_dev_count >= CAIRO_PERF_STABLE_STD_DEV_COUNT) break; } else { low_std_dev_count = 0; } } } if (perf->summary && perf->summary_continuous) { _cairo_stats_compute (&stats, times, i+1); fprintf (perf->summary, "\r[%3d] %8s %28s ", perf->test_number, perf->target->name, name); if (perf->observe) { fprintf (perf->summary, " %#9.3f", _cairo_time_to_s (stats.median_ticks)); _cairo_stats_compute (&stats, paint, i+1); fprintf (perf->summary, " %#9.3f", _cairo_time_to_s (stats.median_ticks)); _cairo_stats_compute (&stats, mask, i+1); fprintf (perf->summary, " %#9.3f", _cairo_time_to_s (stats.median_ticks)); _cairo_stats_compute (&stats, fill, i+1); fprintf (perf->summary, " %#9.3f", _cairo_time_to_s (stats.median_ticks)); _cairo_stats_compute (&stats, stroke, i+1); fprintf (perf->summary, " %#9.3f", _cairo_time_to_s (stats.median_ticks)); _cairo_stats_compute (&stats, glyphs, i+1); fprintf (perf->summary, " %#9.3f", _cairo_time_to_s (stats.median_ticks)); fprintf (perf->summary, " %5d", i+1); } else { fprintf (perf->summary, "%#8.3f %#8.3f %#6.2f%% %4d/%d", _cairo_time_to_s (stats.min_ticks), _cairo_time_to_s (stats.median_ticks), stats.std_dev * 100.0, stats.iterations, i+1); } fflush (perf->summary); } } user_interrupt = 0; if (perf->summary) { _cairo_stats_compute (&stats, times, i); if (perf->summary_continuous) { fprintf (perf->summary, "\r[%3d] %8s %28s ", perf->test_number, perf->target->name, name); } if (perf->observe) { fprintf (perf->summary, " %#9.3f", _cairo_time_to_s (stats.median_ticks)); _cairo_stats_compute (&stats, paint, i); fprintf (perf->summary, " %#9.3f", _cairo_time_to_s (stats.median_ticks)); _cairo_stats_compute (&stats, mask, i); fprintf (perf->summary, " %#9.3f", _cairo_time_to_s (stats.median_ticks)); _cairo_stats_compute (&stats, fill, i); fprintf (perf->summary, " %#9.3f", _cairo_time_to_s (stats.median_ticks)); _cairo_stats_compute (&stats, stroke, i); fprintf (perf->summary, " %#9.3f", _cairo_time_to_s (stats.median_ticks)); _cairo_stats_compute (&stats, glyphs, i); fprintf (perf->summary, " %#9.3f", _cairo_time_to_s (stats.median_ticks)); fprintf (perf->summary, " %5d\n", i); } else { fprintf (perf->summary, "%#8.3f %#8.3f %#6.2f%% %4d/%d\n", _cairo_time_to_s (stats.min_ticks), _cairo_time_to_s (stats.median_ticks), stats.std_dev * 100.0, stats.iterations, i); } fflush (perf->summary); } out: if (perf->raw) { printf ("\n"); fflush (stdout); } perf->test_number++; free (trace_cpy); }