static void
cairo_perf_reports_compare (cairo_perf_report_t		*reports,
			    int				 num_reports,
			    cairo_perf_report_options_t	*options)
{
    int i;
    test_report_t **tests, *min_test;
    test_diff_t *diff, *diffs;
    int num_diffs, max_diffs;
    double max_change;
    double test_time;
    int seen_non_null;
    cairo_bool_t printed_speedup = FALSE;
    cairo_bool_t printed_slowdown = FALSE;

    assert (num_reports >= 2);

    tests = xmalloc (num_reports * sizeof (test_report_t *));

    max_diffs = reports[0].tests_count;
    for (i = 0; i < num_reports; i++) {
	tests[i] = reports[i].tests;
	if (reports[i].tests_count > max_diffs)
	    max_diffs = reports[i].tests_count;
    }

    diff = diffs = xmalloc (max_diffs * sizeof (test_diff_t));

    num_diffs = 0;
    while (1) {
	/* We expect iterations values of 0 when multiple raw reports
	 * for the same test have been condensed into the stats of the
	 * first. So we just skip these later reports that have no
	 * stats. */
	seen_non_null = 0;
	for (i = 0; i < num_reports; i++) {
	    while (tests[i]->name && tests[i]->stats.iterations == 0)
		tests[i]++;
	    if (tests[i]->name)
		seen_non_null++;
	}

	if (seen_non_null < 2)
	    break;

	/* Find the minimum of all current tests, (we have to do this
	 * in case some reports don't have a particular test). */
	for (i = 0; i < num_reports; i++) {
	    if (tests[i]->name) {
		min_test = tests[i];
		break;
	    }
	}
	for (++i; i < num_reports; i++) {
	    if (tests[i]->name &&
		test_report_cmp_backend_then_name (tests[i], min_test) < 0)
	    {
		min_test = tests[i];
	    }
	}

	/* For each report that has the current test, record it into
	 * the diff structure. */
	diff->num_tests = 0;
	diff->tests = xmalloc (num_reports * sizeof (test_diff_t));
	for (i = 0; i < num_reports; i++) {
	    if (tests[i]->name &&
		test_report_cmp_backend_then_name (tests[i], min_test) == 0)
	    {
		test_time = tests[i]->stats.min_ticks;
		if (! options->use_ticks)
		    test_time /= tests[i]->stats.ticks_per_ms;
		if (diff->num_tests == 0) {
		    diff->min = test_time;
		    diff->max = test_time;
		} else {
		    if (test_time < diff->min)
			diff->min = test_time;
		    if (test_time > diff->max)
			diff->max = test_time;
		}
		diff->tests[diff->num_tests++] = tests[i];
		tests[i]++;
	    }
	}
	diff->change = diff->max / diff->min;

	if (num_reports == 2) {
	    double old_time, new_time;
	    if (diff->num_tests == 1) {
		printf ("Only in %s: %s %s\n",
			diff->tests[0]->configuration,
			diff->tests[0]->backend,
			diff->tests[0]->name);
		continue;
	    }
	    old_time = diff->tests[0]->stats.min_ticks;
	    new_time = diff->tests[1]->stats.min_ticks;
	    if (! options->use_ticks) {
		old_time /= diff->tests[0]->stats.ticks_per_ms;
		new_time /= diff->tests[1]->stats.ticks_per_ms;
	    }
	    diff->change = old_time / new_time;
	    if (diff->change < 1.0)
		diff->change = - 1.0 / diff->change;
	}

	diff++;
	num_diffs++;
    }
    if (num_diffs < 2)
	goto DONE;

    if (num_reports == 2)
	qsort (diffs, num_diffs, sizeof (test_diff_t),
	       test_diff_cmp_speedup_before_slowdown);
    else
	qsort (diffs, num_diffs, sizeof (test_diff_t), test_diff_cmp);

    max_change = 1.0;
    for (i = 0; i < num_diffs; i++) {
	if (fabs (diffs[i].change) > max_change)
	    max_change = fabs (diffs[i].change);
    }

    if (num_reports == 2)
	printf ("old: %s\n"
		"new: %s\n",
		diffs->tests[0]->configuration,
		diffs->tests[1]->configuration);

    for (i = 0; i < num_diffs; i++) {
	diff = &diffs[i];

	/* Discard as uninteresting a change which is less than the
	 * minimum change required, (default may be overriden on
	 * command-line). */
	if (fabs (diff->change) - 1.0 < options->min_change)
	    continue;

	if (num_reports == 2) {
	    if (diff->change > 1.0 && ! printed_speedup) {
		printf ("Speedups\n"
			"========\n");
		printed_speedup = TRUE;
	    }
	    if (diff->change < 1.0 && ! printed_slowdown) {
		printf ("Slowdowns\n"
			"=========\n");
		printed_slowdown = TRUE;
	    }
	    test_diff_print_binary (diff, max_change, options);
	} else {
	    test_diff_print_multi (diff, max_change, options);
	}
    }

 DONE:
    for (i = 0; i < num_diffs; i++)
	free (diffs[i].tests);
    free (diffs);
    free (tests);
}
Example #2
0
static test_case_t *
test_cases_from_reports (cairo_perf_report_t *reports,
	                 int num_reports)
{
    test_case_t *cases, *c;
    test_report_t **tests;
    int i, j;
    int num_tests;

    num_tests = 0;
    for (i = 0; i < num_reports; i++) {
	for (j = 0; reports[i].tests[j].name != NULL; j++)
	    ;
	if (j > num_tests)
	    num_tests = j;
    }

    cases = xcalloc (num_tests+1, sizeof (test_case_t));
    tests = xmalloc (num_reports * sizeof (test_report_t *));
    for (i = 0; i < num_reports; i++)
	tests[i] = reports[i].tests;

    c = cases;
    while (1) {
	int seen_non_null;
	test_report_t *min_test;

	/* We expect iterations values of 0 when multiple raw reports
	 * for the same test have been condensed into the stats of the
	 * first. So we just skip these later reports that have no
	 * stats. */
	seen_non_null = 0;
	for (i = 0; i < num_reports; i++) {
	    while (tests[i]->name && tests[i]->stats.iterations == 0)
		tests[i]++;
	    if (tests[i]->name)
		seen_non_null++;
	}

	if (seen_non_null < 2)
	    break;

	/* Find the minimum of all current tests, (we have to do this
	 * in case some reports don't have a particular test). */
	for (i = 0; i < num_reports; i++) {
	    if (tests[i]->name) {
		min_test = tests[i];
		break;
	    }
	}
	for (++i; i < num_reports; i++) {
	    if (tests[i]->name &&
		test_report_cmp_backend_then_name (tests[i], min_test) < 0)
	    {
		min_test = tests[i];
	    }
	}

	c->min_test = min_test;
	c->backend = min_test->backend;
	c->content = min_test->content;
	c->name = min_test->name;
	c->size = min_test->size;
	c->baseline = min_test->stats.min_ticks;
	c->min = c->max = 1.;
	c->shown = TRUE;
	name_to_color (c->name, &c->color);

	for (i = 0; i < num_reports; i++) {
	    if (tests[i]->name &&
		test_report_cmp_backend_then_name (tests[i], min_test) == 0)
	    {
		tests[i]++;
		break;
	    }
	}

	for (++i; i < num_reports; i++) {
	    if (tests[i]->name &&
		test_report_cmp_backend_then_name (tests[i], min_test) == 0)
	    {
		double v = tests[i]->stats.min_ticks / c->baseline;
		if (v < c->min)
		    c->min = v;
		if (v > c->max)
		    c->max = v;
		tests[i]++;
	    }
	}

	c++;
    }
    free (tests);

    return cases;
}