summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPekka Paalanen <pekka.paalanen@collabora.co.uk>2015-04-10 14:39:13 +0300
committerPekka Paalanen <pekka.paalanen@collabora.co.uk>2015-04-15 12:42:51 +0300
commit5b279121086274a18912de77865f83d637094739 (patch)
tree67484323720745e5c74fadb0950f4a96d8f4f89c
parent1f45bd6565607049c7bcf707f2fdaedbb16bc926 (diff)
lowlevel-blt-bench: add test name parser and self-test
This patch is inspired by "lowlevel-blt-bench: Parse test name strings in general case" by Ben Avison. From Ben's commit message: "There are many types of composite operation that are useful to benchmark but which are omitted from the table. Continually having to add extra entries to the table is a nuisance and is prone to human error, so this patch adds the ability to break down unknow strings of the format <operation>_<src>[_<mask]_<dst>[_ca] where bitmap formats are specified by number of bits of each component (assumed in ARGB order) or 'n' to indicate a solid source or mask." Add the parser to lowlevel-blt-bench.c, but do not hook it up to the command line just yet. Instead, make it run a self-test. As we now dynamically parse strings similar to the test names in the huge table 'tests_tbl', we should make sure we can parse the old well-known test names and produce exactly the same test parameters. The self-test goes through this old table and verifies the parsing results. Unfortunately the old table is not exactly consistent, it contains some special cases that cannot be produced by the parsing rules. Whether these special cases are intentional or just an oversight is not always clear. Anyway, add a small table to reproduce the special cases verbatim. If we wanted, we could remove the big old table in a follow-up commit, but then we would also lose the parser self-test. The point of this whole excercise to let lowlevel-blt-bench recognize novel test patterns in the future, following exactly the conventions used in the old table. Ben, from what I see, this parser has one major difference to what you wrote. For a solid mask, your parser uses a8r8g8b8 format, while mine uses a8 which comes from the old table. Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> Reviewed-by: Ben Avison <bavison@riscosopen.org>
-rw-r--r--test/lowlevel-blt-bench.c231
1 files changed, 228 insertions, 3 deletions
diff --git a/test/lowlevel-blt-bench.c b/test/lowlevel-blt-bench.c
index 3da094a..7c1711b 100644
--- a/test/lowlevel-blt-bench.c
+++ b/test/lowlevel-blt-bench.c
@@ -587,7 +587,7 @@ bench_composite (char * testname,
#define PIXMAN_OP_OUT_REV (PIXMAN_OP_OUT_REVERSE)
-struct
+struct test_entry
{
char *testname;
int src_fmt;
@@ -596,8 +596,11 @@ struct
int mask_fmt;
int mask_flags;
int dst_fmt;
-}
-tests_tbl[] =
+};
+
+typedef struct test_entry test_entry_t;
+
+static const test_entry_t tests_tbl[] =
{
{ "add_8_8_8", PIXMAN_a8, 0, PIXMAN_OP_ADD, PIXMAN_a8, 0, PIXMAN_a8 },
{ "add_n_8_8", PIXMAN_a8r8g8b8, 1, PIXMAN_OP_ADD, PIXMAN_a8, 0, PIXMAN_a8 },
@@ -719,6 +722,226 @@ tests_tbl[] =
{ "rpixbuf", PIXMAN_x8b8g8r8, 0, PIXMAN_OP_SRC, PIXMAN_a8b8g8r8, 0, PIXMAN_a8b8g8r8 },
};
+static const test_entry_t special_patterns[] =
+{
+ { "add_n_2x10", PIXMAN_a2r10g10b10, 1, PIXMAN_OP_ADD, PIXMAN_null, 0, PIXMAN_x2r10g10b10 },
+ { "add_n_2a10", PIXMAN_a2r10g10b10, 1, PIXMAN_OP_ADD, PIXMAN_null, 0, PIXMAN_a2r10g10b10 },
+ { "src_n_2x10", PIXMAN_a2r10g10b10, 1, PIXMAN_OP_SRC, PIXMAN_null, 0, PIXMAN_x2r10g10b10 },
+ { "src_n_2a10", PIXMAN_a2r10g10b10, 1, PIXMAN_OP_SRC, PIXMAN_null, 0, PIXMAN_a2r10g10b10 },
+ { "src_0888_8888_rev", PIXMAN_b8g8r8, 0, PIXMAN_OP_SRC, PIXMAN_null, 0, PIXMAN_x8r8g8b8 },
+ { "src_0888_0565_rev", PIXMAN_b8g8r8, 0, PIXMAN_OP_SRC, PIXMAN_null, 0, PIXMAN_r5g6b5 },
+ { "src_n_8", PIXMAN_a8, 1, PIXMAN_OP_SRC, PIXMAN_null, 0, PIXMAN_a8 },
+ { "pixbuf", PIXMAN_x8b8g8r8, 0, PIXMAN_OP_SRC, PIXMAN_a8b8g8r8, 0, PIXMAN_a8r8g8b8 },
+ { "rpixbuf", PIXMAN_x8b8g8r8, 0, PIXMAN_OP_SRC, PIXMAN_a8b8g8r8, 0, PIXMAN_a8b8g8r8 },
+};
+
+/* Returns the sub-string's end pointer in string. */
+static const char *
+copy_sub_string (char *buf,
+ const char *string,
+ const char *scan_from,
+ const char *end)
+{
+ const char *delim;
+ size_t n;
+
+ delim = strchr (scan_from, '_');
+ if (!delim)
+ delim = end;
+
+ n = delim - string;
+ strncpy(buf, string, n);
+ buf[n] = '\0';
+
+ return delim;
+}
+
+static pixman_op_t
+parse_longest_operator (char *buf, const char **strp, const char *end)
+{
+ const char *p = *strp;
+ const char *sub_end;
+ const char *best_end = p;
+ pixman_op_t best_op = PIXMAN_OP_NONE;
+ pixman_op_t op;
+
+ while (p < end)
+ {
+ sub_end = copy_sub_string (buf, *strp, p, end);
+ op = operator_from_string (buf);
+ p = sub_end + 1;
+
+ if (op != PIXMAN_OP_NONE)
+ {
+ best_end = p;
+ best_op = op;
+ }
+ }
+
+ *strp = best_end;
+ return best_op;
+}
+
+static pixman_format_code_t
+parse_format (char *buf, const char **p, const char *end)
+{
+ pixman_format_code_t format;
+ const char *delim;
+
+ if (*p >= end)
+ return PIXMAN_null;
+
+ delim = copy_sub_string (buf, *p, *p, end);
+ format = format_from_string (buf);
+
+ if (format != PIXMAN_null)
+ *p = delim + 1;
+
+ return format;
+}
+
+static int
+parse_test_pattern (test_entry_t *test, const char *pattern)
+{
+ const char *p = pattern;
+ const char *end = pattern + strlen (pattern);
+ char buf[1024];
+ pixman_format_code_t format[3];
+ int i;
+
+ if (strlen (pattern) > sizeof (buf) - 1)
+ return -1;
+
+ /* Special cases that the parser cannot produce. */
+ for (i = 0; i < ARRAY_LENGTH (special_patterns); i++)
+ {
+ if (strcmp (pattern, special_patterns[i].testname) == 0)
+ {
+ *test = special_patterns[i];
+ return 0;
+ }
+ }
+
+ /* Extract operator, may contain delimiters,
+ * so take the longest string that matches.
+ */
+ test->op = parse_longest_operator (buf, &p, end);
+ if (test->op == PIXMAN_OP_NONE)
+ return -1;
+
+ /* extract up to three pixel formats */
+ format[0] = parse_format (buf, &p, end);
+ format[1] = parse_format (buf, &p, end);
+ format[2] = parse_format (buf, &p, end);
+
+ if (format[0] == PIXMAN_null || format[1] == PIXMAN_null)
+ return -1;
+
+ /* recognize CA flag */
+ test->mask_flags = 0;
+ if (p < end)
+ {
+ if (strcmp (p, "ca") == 0)
+ test->mask_flags |= CA_FLAG;
+ else
+ return -1; /* trailing garbage */
+ }
+
+ test->src_fmt = format[0];
+ if (format[2] == PIXMAN_null)
+ {
+ test->mask_fmt = PIXMAN_null;
+ test->dst_fmt = format[1];
+ }
+ else
+ {
+ test->mask_fmt = format[1];
+ test->dst_fmt = format[2];
+ }
+
+ test->src_flags = 0;
+ if (test->src_fmt == PIXMAN_solid)
+ {
+ test->src_fmt = PIXMAN_a8r8g8b8;
+ test->src_flags |= SOLID_FLAG;
+ }
+
+ if (test->mask_fmt == PIXMAN_solid)
+ {
+ test->mask_fmt = PIXMAN_a8;
+ test->mask_flags |= SOLID_FLAG;
+ }
+
+ return 0;
+}
+
+static int
+check_int (int got, int expected, const char *name, const char *field)
+{
+ if (got == expected)
+ return 0;
+
+ printf ("%s: %s failure: expected %d, got %d.\n",
+ name, field, expected, got);
+
+ return 1;
+}
+
+static int
+check_format (int got, int expected, const char *name, const char *field)
+{
+ if (got == expected)
+ return 0;
+
+ printf ("%s: %s failure: expected %s (%#x), got %s (%#x).\n",
+ name, field,
+ format_name (expected), expected,
+ format_name (got), got);
+
+ return 1;
+}
+
+static void
+parser_self_test (void)
+{
+ const test_entry_t *ent;
+ test_entry_t test;
+ int fails = 0;
+ int i;
+
+ for (i = 0; i < ARRAY_LENGTH (tests_tbl); i++)
+ {
+ ent = &tests_tbl[i];
+
+ if (parse_test_pattern (&test, ent->testname) < 0)
+ {
+ printf ("parsing failed for '%s'\n", ent->testname);
+ fails++;
+ continue;
+ }
+
+ fails += check_format (test.src_fmt, ent->src_fmt,
+ ent->testname, "src_fmt");
+ fails += check_format (test.mask_fmt, ent->mask_fmt,
+ ent->testname, "mask_fmt");
+ fails += check_format (test.dst_fmt, ent->dst_fmt,
+ ent->testname, "dst_fmt");
+ fails += check_int (test.src_flags, ent->src_flags,
+ ent->testname, "src_flags");
+ fails += check_int (test.mask_flags, ent->mask_flags,
+ ent->testname, "mask_flags");
+ fails += check_int (test.op, ent->op, ent->testname, "op");
+ }
+
+ if (fails)
+ {
+ printf ("Parser self-test failed.\n");
+ exit (EXIT_FAILURE);
+ }
+
+ printf ("Parser self-test complete.\n");
+}
+
int
main (int argc, char *argv[])
{
@@ -754,6 +977,8 @@ main (int argc, char *argv[])
return 1;
}
+ parser_self_test ();
+
src = aligned_malloc (4096, BUFSIZE * 3);
memset (src, 0xCC, BUFSIZE * 3);
dst = src + (BUFSIZE / 4);