summaryrefslogtreecommitdiff
path: root/perf/cairo-perf-diff-files.c
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2008-10-16 11:56:19 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2008-10-19 09:36:53 +0100
commitf2ff7944264c23cbec856be3e85f240a93184f80 (patch)
tree0c14c7d36b71bcb92bf244b6eede1eec5b4aa4ea /perf/cairo-perf-diff-files.c
parent41c8eefc6d432ab213f6f405c3d6346adb7f7931 (diff)
downloadcairo-f2ff7944264c23cbec856be3e85f240a93184f80.tar.gz
[perf] A crude tool to visualise performance changes across a series.
Generate a cairo-perf-diff graph for a series of commits in order to be able to identify significant commits. Still very crude, but minimally functional.
Diffstat (limited to 'perf/cairo-perf-diff-files.c')
-rw-r--r--perf/cairo-perf-diff-files.c458
1 files changed, 0 insertions, 458 deletions
diff --git a/perf/cairo-perf-diff-files.c b/perf/cairo-perf-diff-files.c
index 9098c91cb..9b9f5f97d 100644
--- a/perf/cairo-perf-diff-files.c
+++ b/perf/cairo-perf-diff-files.c
@@ -27,10 +27,6 @@
#include "cairo-perf.h"
-/* We use _GNU_SOURCE for getline and strndup if available. */
-#ifndef _GNU_SOURCE
-# define _GNU_SOURCE
-#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -38,50 +34,6 @@
#include <ctype.h>
#include <math.h>
#include <assert.h>
-#ifdef HAVE_LIBGEN_H
-#include <libgen.h>
-#endif
-
-typedef struct _test_report {
- int id;
- const char *configuration;
- char *backend;
- char *content;
- char *name;
- int size;
-
- /* The samples only exists for "raw" reports */
- cairo_perf_ticks_t *samples;
- unsigned int samples_size;
- unsigned int samples_count;
-
- /* The stats are either read directly or computed from samples.
- * If the stats have not yet been computed from samples, then
- * iterations will be 0. */
- cairo_stats_t stats;
-} test_report_t;
-
-typedef struct _test_diff {
- test_report_t **tests;
- int num_tests;
- double min;
- double max;
- double change;
-} test_diff_t;
-
-typedef struct _cairo_perf_report {
- char *configuration;
- const char *name;
- test_report_t *tests;
- int tests_size;
- int tests_count;
-} cairo_perf_report_t;
-
-typedef enum {
- TEST_REPORT_STATUS_SUCCESS,
- TEST_REPORT_STATUS_COMMENT,
- TEST_REPORT_STATUS_ERROR
-} test_report_status_t;
typedef struct _cairo_perf_report_options {
double min_change;
@@ -96,416 +48,6 @@ typedef struct _cairo_perf_diff_files_args {
cairo_perf_report_options_t options;
} cairo_perf_diff_files_args_t;
-/* 'ssize_t' does not exist in the C standard on win32.
- * We use 'ptrdiff_t', which is nearly equivalent. */
-#ifdef _MSC_VER
-typedef ptrdiff_t ssize_t;
-#endif
-
-#ifndef __USE_GNU
-static ssize_t
-getline (char **lineptr, size_t *n, FILE *stream);
-
-static char *
-strndup (const char *s, size_t n);
-#endif
-
-#ifdef _MSC_VER
-static long long
-strtoll(const char *nptr, char **endptr, int base);
-
-static char *
-basename(char *path);
-#endif
-
-/* Ad-hoc parsing, macros with a strong dependence on the calling
- * context, and plenty of other ugliness is here. But at least it's
- * not perl... */
-#define parse_error(...) fprintf(stderr, __VA_ARGS__); return TEST_REPORT_STATUS_ERROR;
-#define skip_char(c) \
-do { \
- if (*s && *s == (c)) { \
- s++; \
- } else { \
- parse_error ("expected '%c' but found '%c'", c, *s); \
- } \
-} while (0)
-#define skip_space() while (*s && (*s == ' ' || *s == '\t')) s++;
-#define parse_int(result) \
-do { \
- (result) = strtol (s, &end, 10); \
- if (*s && end != s) { \
- s = end; \
- } else { \
- parse_error("expected integer but found %s", s); \
- } \
-} while (0)
-#define parse_long_long(result) \
-do { \
- (result) = strtoll (s, &end, 10); \
- if (*s && end != s) { \
- s = end; \
- } else { \
- parse_error("expected integer but found %s", s); \
- } \
-} while (0)
-#define parse_double(result) \
-do { \
- (result) = strtod (s, &end); \
- if (*s && end != s) { \
- s = end; \
- } else { \
- parse_error("expected floating-point value but found %s", s); \
- } \
-} while (0)
-/* Here a string is simply a sequence of non-whitespace */
-#define parse_string(result) \
-do { \
- for (end = s; *end; end++) \
- if (isspace (*end)) \
- break; \
- (result) = strndup (s, end - s); \
- if ((result) == NULL) { \
- fprintf (stderr, "Out of memory.\n"); \
- exit (1); \
- } \
- s = end; \
-} while (0)
-
-static test_report_status_t
-test_report_parse (test_report_t *report, char *line, char *configuration)
-{
- char *end;
- char *s = line;
- cairo_bool_t is_raw = FALSE;
- double min_time, median_time;
-
- /* The code here looks funny unless you understand that these are
- * all macro calls, (and then the code just looks sick). */
- if (*s == '\n')
- return TEST_REPORT_STATUS_COMMENT;
-
- skip_char ('[');
- skip_space ();
- if (*s == '#')
- return TEST_REPORT_STATUS_COMMENT;
- if (*s == '*') {
- s++;
- is_raw = TRUE;
- } else {
- parse_int (report->id);
- }
- skip_char (']');
-
- skip_space ();
-
- report->configuration = configuration;
- parse_string (report->backend);
- end = strrchr (report->backend, '-');
- if (*end)
- *end++ = '\0';
- report->content = end;
-
- skip_space ();
-
- parse_string (report->name);
- end = strrchr (report->name, '-');
- if (*end)
- *end++ = '\0';
- report->size = atoi (end);
-
- skip_space ();
-
- report->samples = NULL;
- report->samples_size = 0;
- report->samples_count = 0;
-
- if (is_raw) {
- parse_double (report->stats.ticks_per_ms);
- skip_space ();
-
- report->samples_size = 5;
- report->samples = xmalloc (report->samples_size * sizeof (cairo_perf_ticks_t));
- do {
- if (report->samples_count == report->samples_size) {
- report->samples_size *= 2;
- report->samples = xrealloc (report->samples,
- report->samples_size * sizeof (cairo_perf_ticks_t));
- }
- parse_long_long (report->samples[report->samples_count++]);
- skip_space ();
- } while (*s && *s != '\n');
- report->stats.iterations = 0;
- skip_char ('\n');
- } else {
- parse_double (report->stats.min_ticks);
- skip_space ();
-
- parse_double (min_time);
- report->stats.ticks_per_ms = report->stats.min_ticks / min_time;
-
- skip_space ();
-
- parse_double (median_time);
- report->stats.median_ticks = median_time * report->stats.ticks_per_ms;
-
- skip_space ();
-
- parse_double (report->stats.std_dev);
- report->stats.std_dev /= 100.0;
- skip_char ('%');
-
- skip_space ();
-
- parse_int (report->stats.iterations);
-
- skip_space ();
- skip_char ('\n');
- }
-
- return TEST_REPORT_STATUS_SUCCESS;
-}
-
-/* We conditionally provide a custom implementation of getline and strndup
- * as needed. These aren't necessary full-fledged general purpose
- * implementations. They just get the job done for our purposes.
- */
-#ifndef __USE_GNU
-#define POORMANS_GETLINE_BUFFER_SIZE (65536)
-static ssize_t
-getline (char **lineptr, size_t *n, FILE *stream)
-{
- if (!*lineptr)
- {
- *n = POORMANS_GETLINE_BUFFER_SIZE;
- *lineptr = (char *) malloc (*n);
- }
-
- if (!fgets (*lineptr, *n, stream))
- return -1;
-
- if (!feof (stream) && !strchr (*lineptr, '\n'))
- {
- fprintf (stderr, "The poor man's implementation of getline in "
- __FILE__ " needs a bigger buffer. Perhaps it's "
- "time for a complete implementation of getline.\n");
- exit (0);
- }
-
- return strlen (*lineptr);
-}
-#undef POORMANS_GETLINE_BUFFER_SIZE
-
-static char *
-strndup (const char *s, size_t n)
-{
- size_t len;
- char *sdup;
-
- if (!s)
- return NULL;
-
- len = strlen (s);
- len = (n < len ? n : len);
- sdup = (char *) malloc (len + 1);
- if (sdup)
- {
- memcpy (sdup, s, len);
- sdup[len] = '\0';
- }
-
- return sdup;
-}
-#endif /* ifndef __USE_GNU */
-
-/* We provide hereafter a win32 implementation of the basename
- * and strtoll functions which are not available otherwise.
- * The basename function is fully compliant to its GNU specs.
- */
-#ifdef _MSC_VER
-long long
-strtoll(const char *nptr, char **endptr, int base)
-{
- return _atoi64(nptr);
-}
-
-static char *
-basename(char *path)
-{
- char *end, *s;
-
- end = (path + strlen(path) - 1);
- while (end && (end >= path + 1) && (*end == '/')) {
- *end = '\0';
- end--;
- }
-
- s = strrchr(path, '/');
- if (s) {
- if (s == end) {
- return s;
- } else {
- return s+1;
- }
- } else {
- return path;
- }
-}
-#endif /* ifndef _MSC_VER */
-
-static int
-test_report_cmp_backend_then_name (const void *a, const void *b)
-{
- const test_report_t *a_test = a;
- const test_report_t *b_test = b;
-
- int cmp;
-
- cmp = strcmp (a_test->backend, b_test->backend);
- if (cmp)
- return cmp;
-
- cmp = strcmp (a_test->content, b_test->content);
- if (cmp)
- return cmp;
-
- /* A NULL name is a list-termination marker, so force it last. */
- if (a_test->name == NULL)
- if (b_test->name == NULL)
- return 0;
- else
- return 1;
- else if (b_test->name == NULL)
- return -1;
-
- cmp = strcmp (a_test->name, b_test->name);
- if (cmp)
- return cmp;
-
- if (a_test->size < b_test->size)
- return -1;
- if (a_test->size > b_test->size)
- return 1;
-
- return 0;
-}
-
-static void
-cairo_perf_report_sort_and_compute_stats (cairo_perf_report_t *report)
-{
- test_report_t *base, *next, *last, *t;
-
- /* First we sort, since the diff needs both lists in the same
- * order */
- qsort (report->tests, report->tests_count, sizeof (test_report_t),
- test_report_cmp_backend_then_name);
-
- /* The sorting also brings all related raw reports together so we
- * can condense them and compute the stats.
- */
- base = &report->tests[0];
- last = &report->tests[report->tests_count - 1];
- while (base <= last) {
- next = base+1;
- if (next <= last) {
- while (next <= last &&
- test_report_cmp_backend_then_name (base, next) == 0)
- {
- next++;
- }
- if (next != base) {
- unsigned int new_samples_count = base->samples_count;
- for (t = base + 1; t < next; t++)
- new_samples_count += t->samples_count;
- if (new_samples_count > base->samples_size) {
- base->samples_size = new_samples_count;
- base->samples = xrealloc (base->samples,
- base->samples_size * sizeof (cairo_perf_ticks_t));
- }
- for (t = base + 1; t < next; t++) {
- memcpy (&base->samples[base->samples_count], t->samples,
- t->samples_count * sizeof (cairo_perf_ticks_t));
- base->samples_count += t->samples_count;
- }
- }
- }
- if (base->samples)
- _cairo_stats_compute (&base->stats, base->samples, base->samples_count);
- base = next;
- }
-}
-
-static void
-cairo_perf_report_load (cairo_perf_report_t *report, const char *filename)
-{
- FILE *file;
- test_report_status_t status;
- int line_number = 0;
- char *line = NULL;
- size_t line_size = 0;
- char *configuration;
- char *dot;
- char *baseName;
-
- configuration = xmalloc (strlen (filename) * sizeof (char) + 1);
- strcpy (configuration, filename);
- baseName = strdup (basename (configuration));
- report->configuration = xmalloc (strlen (filename) * sizeof (char) + 1);
- strcpy(report->configuration, baseName);
- free (configuration);
- dot = strrchr (report->configuration, '.');
- if (dot)
- *dot = '\0';
-
- report->name = filename;
- report->tests_size = 16;
- report->tests = xmalloc (report->tests_size * sizeof (test_report_t));
- report->tests_count = 0;
-
- file = fopen (filename, "r");
- if (file == NULL) {
- fprintf (stderr, "Failed to open %s: %s\n",
- filename, strerror (errno));
- exit (1);
- }
-
- while (1) {
- if (report->tests_count == report->tests_size) {
- report->tests_size *= 2;
- report->tests = xrealloc (report->tests,
- report->tests_size * sizeof (test_report_t));
- }
-
- line_number++;
- if (getline (&line, &line_size, file) == -1)
- break;
-
- status = test_report_parse (&report->tests[report->tests_count],
- line, report->configuration);
- if (status == TEST_REPORT_STATUS_ERROR)
- fprintf (stderr, "Ignoring unrecognized line %d of %s:\n%s",
- line_number, filename, line);
- if (status == TEST_REPORT_STATUS_SUCCESS)
- report->tests_count++;
- /* Do nothing on TEST_REPORT_STATUS_COMMENT */
- }
-
- if (line)
- free (line);
-
- fclose (file);
-
- cairo_perf_report_sort_and_compute_stats (report);
-
- /* Add one final report with a NULL name to terminate the list. */
- if (report->tests_count == report->tests_size) {
- report->tests_size *= 2;
- report->tests = xrealloc (report->tests,
- report->tests_size * sizeof (test_report_t));
- }
- report->tests[report->tests_count].name = NULL;
-}
-
static int
test_diff_cmp_speedup_before_slowdown (const void *a, const void *b)
{