[Pixman] [PATCH 6/7] lowlevel-blt-bench: add test name parser and self-test

Pekka Paalanen ppaalanen at gmail.com
Mon Apr 13 04:31:41 PDT 2015


From: Pekka Paalanen <pekka.paalanen at collabora.co.uk>

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 at collabora.co.uk>
---
 test/lowlevel-blt-bench.c | 231 +++++++++++++++++++++++++++++++++++++++++++++-
 1 file 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);
-- 
2.0.5



More information about the Pixman mailing list