[Pixman] [PATCH] test: Add a new benchmarker targeting affine operations

Ben Avison bavison at riscosopen.org
Wed Apr 8 06:20:09 PDT 2015


---
 .gitignore            |    1 +
 test/Makefile.sources |    1 +
 test/affine-bench.c   |  394 +++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 396 insertions(+), 0 deletions(-)
 create mode 100644 test/affine-bench.c

diff --git a/.gitignore b/.gitignore
index 0f11496..7da6b6f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -46,6 +46,7 @@ demos/tri-test
 pixman/pixman-srgb.c
 pixman/pixman-version.h
 test/a1-trap-test
+test/affine-bench
 test/affine-test
 test/alpha-loop
 test/alphamap
diff --git a/test/Makefile.sources b/test/Makefile.sources
index c20c34b..8b0e855 100644
--- a/test/Makefile.sources
+++ b/test/Makefile.sources
@@ -37,6 +37,7 @@ OTHERPROGRAMS =                 \
 	radial-perf-test	\
         check-formats           \
 	scaling-bench		\
+	affine-bench            \
 	$(NULL)
 
 # Utility functions
diff --git a/test/affine-bench.c b/test/affine-bench.c
new file mode 100644
index 0000000..720d066
--- /dev/null
+++ b/test/affine-bench.c
@@ -0,0 +1,394 @@
+/*
+ * Copyright © 2014 RISC OS Open Ltd
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  The copyright holders make no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ *
+ * Author:  Ben Avison (bavison at riscosopen.org)
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdint.h>
+#include "utils.h"
+
+#ifdef HAVE_GETTIMEOFDAY
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+
+#define WIDTH  1920
+#define HEIGHT 1080
+#define MAX_L2CACHE_SIZE (8 * 1024 * 1024) /* How much data to read to flush all cached data to RAM */
+#define PAGE_SIZE (4 * 1024)
+
+typedef struct box_48_16 box_48_16_t;
+
+struct box_48_16
+{
+    pixman_fixed_48_16_t        x1;
+    pixman_fixed_48_16_t        y1;
+    pixman_fixed_48_16_t        x2;
+    pixman_fixed_48_16_t        y2;
+};
+
+static pixman_bool_t
+compute_transformed_extents (pixman_transform_t   *transform,
+                             const pixman_box32_t *extents,
+                             box_48_16_t          *transformed)
+{
+    pixman_fixed_48_16_t tx1, ty1, tx2, ty2;
+    pixman_fixed_t x1, y1, x2, y2;
+    int i;
+
+    x1 = pixman_int_to_fixed (extents->x1) + pixman_fixed_1 / 2;
+    y1 = pixman_int_to_fixed (extents->y1) + pixman_fixed_1 / 2;
+    x2 = pixman_int_to_fixed (extents->x2) - pixman_fixed_1 / 2;
+    y2 = pixman_int_to_fixed (extents->y2) - pixman_fixed_1 / 2;
+
+    if (!transform)
+    {
+        transformed->x1 = x1;
+        transformed->y1 = y1;
+        transformed->x2 = x2;
+        transformed->y2 = y2;
+
+        return TRUE;
+    }
+
+    tx1 = ty1 = INT64_MAX;
+    tx2 = ty2 = INT64_MIN;
+
+    for (i = 0; i < 4; ++i)
+    {
+        pixman_fixed_48_16_t tx, ty;
+        pixman_vector_t v;
+
+        v.vector[0] = (i & 0x01)? x1 : x2;
+        v.vector[1] = (i & 0x02)? y1 : y2;
+        v.vector[2] = pixman_fixed_1;
+
+        if (!pixman_transform_point (transform, &v))
+            return FALSE;
+
+        tx = (pixman_fixed_48_16_t)v.vector[0];
+        ty = (pixman_fixed_48_16_t)v.vector[1];
+
+        if (tx < tx1)
+            tx1 = tx;
+        if (ty < ty1)
+            ty1 = ty;
+        if (tx > tx2)
+            tx2 = tx;
+        if (ty > ty2)
+            ty2 = ty;
+    }
+
+    transformed->x1 = tx1;
+    transformed->y1 = ty1;
+    transformed->x2 = tx2;
+    transformed->y2 = ty2;
+
+    return TRUE;
+}
+
+static void
+create_image (uint32_t                   width,
+              uint32_t                   height,
+              pixman_format_code_t       format,
+              pixman_filter_t            filter,
+              const pixman_transform_t  *t,
+              uint32_t                 **bits,
+              pixman_image_t           **image)
+{
+    uint32_t stride = (width * PIXMAN_FORMAT_BPP(format) + 31) / 32 * 4;
+
+    *bits = aligned_malloc (PAGE_SIZE, stride * height);
+    memset (*bits, 0xCC, stride * height);
+    *image = pixman_image_create_bits (format, width, height, *bits, stride);
+    pixman_image_set_repeat (*image, PIXMAN_REPEAT_NORMAL);
+    pixman_image_set_filter (*image, filter, NULL, 0);
+}
+
+/* This needs to match the shortest cacheline length we expect to encounter */
+#define CACHE_CLEAN_INCREMENT 32
+
+static void
+flush_cache (void)
+{
+    static const char clean_space[MAX_L2CACHE_SIZE];
+    volatile const char *x = clean_space;
+    const char *clean_end = clean_space + sizeof clean_space;
+    while (x < clean_end)
+    {
+        (void) *x;
+        x += CACHE_CLEAN_INCREMENT;
+    }
+}
+
+/* Obtain current time in microseconds modulo 2^32 */
+uint32_t
+gettimei (void)
+{
+#ifdef HAVE_GETTIMEOFDAY
+    struct timeval tv;
+
+    gettimeofday (&tv, NULL);
+    return tv.tv_sec * 1000000 + tv.tv_usec;
+#else
+    return (uint64_t) clock () * 1000000 / CLOCKS_PER_SEC;
+#endif
+}
+
+static void
+pixman_image_composite_wrapper (pixman_composite_info_t *info)
+{
+    pixman_image_composite (info->op,
+                            info->src_image, info->mask_image, info->dest_image,
+                            info->src_x, info->src_y,
+                            info->mask_x, info->mask_y,
+                            info->dest_x, info->dest_y,
+                            info->width, info->height);
+}
+
+static void
+pixman_image_composite_empty (pixman_composite_info_t *info)
+{
+    pixman_image_composite (info->op,
+                            info->src_image, info->mask_image, info->dest_image,
+                            info->src_x, info->src_y,
+                            info->mask_x, info->mask_y,
+                            info->dest_x, info->dest_y,
+                            1, 1);
+}
+
+static void
+bench (pixman_op_t         op,
+       pixman_transform_t *t,
+       pixman_image_t     *src_image,
+       pixman_image_t     *mask_image,
+       pixman_image_t     *dest_image,
+       int32_t             src_x,
+       int32_t             src_y,
+       uint32_t            max_n,
+       uint32_t            max_time,
+       uint32_t           *ret_n,
+       uint32_t           *ret_time,
+       void              (*func) (pixman_composite_info_t *info))
+{
+    uint32_t n = 0;
+    uint32_t t0 = gettimei ();
+    uint32_t t1;
+    uint32_t x = 0;
+
+    do
+    {
+        pixman_composite_info_t info;
+
+        if (++x >= 64)
+            x = 0;
+
+        info.op = op;
+        info.src_image = src_image;
+        info.mask_image = mask_image;
+        info.dest_image = dest_image;
+        info.src_x = 0;
+        info.src_y = 0;
+        info.mask_x = 0;
+        info.mask_y = 0;
+        info.dest_x = 63 - x;
+        info.dest_y = 0;
+        info.width = WIDTH;
+        info.height = HEIGHT;
+
+        t->matrix[0][2] = pixman_int_to_fixed (src_x + x);
+        t->matrix[1][2] = pixman_int_to_fixed (src_y);
+        pixman_image_set_transform (src_image, t);
+
+        if (mask_image)
+            pixman_image_set_transform (mask_image, t);
+
+        func (&info);
+        t1 = gettimei ();
+    }
+    while (++n < max_n && (t1 - t0) < max_time);
+
+    if (ret_n)
+        *ret_n = n;
+
+    *ret_time = t1 - t0;
+}
+
+int
+parse_fixed_argument (char *arg, pixman_fixed_t *value)
+{
+    char *tailptr;
+    *value = pixman_double_to_fixed (strtod (arg, &tailptr));
+    return *tailptr == '\0';
+}
+
+int
+parse_arguments (int                   argc,
+                 char                 *argv[],
+                 pixman_transform_t   *t,
+                 pixman_op_t          *op,
+                 pixman_format_code_t *src_format,
+                 pixman_format_code_t *mask_format,
+                 pixman_format_code_t *dest_format)
+{
+    if (!parse_fixed_argument (*argv, &t->matrix[0][0]))
+        return 0;
+
+    if (*++argv == NULL)
+        return 1;
+
+    if (!parse_fixed_argument (*argv, &t->matrix[0][1]))
+        return 0;
+
+    if (*++argv == NULL)
+        return 1;
+
+    if (!parse_fixed_argument (*argv, &t->matrix[1][0]))
+        return 0;
+
+    if (*++argv == NULL)
+        return 1;
+
+    if (!parse_fixed_argument (*argv, &t->matrix[1][1]))
+        return 0;
+
+    if (*++argv == NULL)
+        return 1;
+
+    *op = operator_from_string (*argv);
+    if (*op == PIXMAN_OP_NONE)
+        return 0;
+
+    if (*++argv == NULL)
+        return 1;
+
+    *src_format = format_from_string (*argv);
+    if (*src_format == PIXMAN_null)
+        return 0;
+
+    ++argv;
+    if (argv[0] && argv[1])
+    {
+        *mask_format = format_from_string (*argv);
+        if (*mask_format == PIXMAN_null)
+            return 0;
+        ++argv;
+    }
+    if (*argv)
+    {
+        *dest_format = format_from_string (*argv);
+        if (*dest_format == PIXMAN_null)
+            return 0;
+    }
+    return 1;
+}
+
+int
+main (int argc, char *argv[])
+{
+    pixman_filter_t      filter      = PIXMAN_FILTER_NEAREST;
+    pixman_transform_t   t;
+    pixman_op_t          op          = PIXMAN_OP_SRC;
+    pixman_format_code_t src_format  = PIXMAN_a8r8g8b8;
+    pixman_format_code_t mask_format = 0;
+    pixman_format_code_t dest_format = PIXMAN_a8r8g8b8;
+
+    uint32_t *src, *mask, *dest;
+    pixman_image_t *src_image, *mask_image = NULL, *dest_image;
+    pixman_box32_t dest_box = { 0, 0, WIDTH, HEIGHT };
+    box_48_16_t transformed = { 0 };
+    int32_t xmin, ymin, xmax, ymax;
+    int32_t src_x, src_y;
+
+    pixman_transform_init_identity (&t);
+
+    ++argv;
+    if (*argv && (*argv)[0] == '-' && (*argv)[1] == 'n')
+    {
+        filter = PIXMAN_FILTER_NEAREST;
+        ++argv;
+        --argc;
+    }
+    if (*argv && (*argv)[0] == '-' && (*argv)[1] == 'b')
+    {
+        filter = PIXMAN_FILTER_BILINEAR;
+        ++argv;
+        --argc;
+    }
+    if (argc == 1 || !parse_arguments (argc, argv, &t, &op, &src_format, &mask_format, &dest_format))
+    {
+        printf ("Usage: affine-bench [-n] [-b] axx [axy] [ayx] [ayy] [combine type]\n");
+        printf ("                    [src format] [mask format] [dest format]\n");
+        printf ("  -n : nearest scaling (default)\n");
+        printf ("  -b : bilinear scaling\n");
+        printf ("  axx : x_out:x_in factor\n");
+        printf ("  axy : x_out:y_in factor (default 0)\n");
+        printf ("  ayx : y_out:x_in factor (default 0)\n");
+        printf ("  ayy : y_out:y_in factor (default 1)\n");
+        printf ("  combine type : src, over, in etc (default src)\n");
+        printf ("  src format : a8r8g8b8, r5g6b6 etc (default a8r8g8b8)\n");
+        printf ("  mask format : as for src format, but no mask used if omitted\n");
+        printf ("  dest format : as for src format (default a8r8g8b8)\n");
+        return EXIT_FAILURE;
+    }
+
+    compute_transformed_extents (&t, &dest_box, &transformed);
+    /* The source area is expanded by a tiny bit (8/65536th pixel)
+     * to match the calculation of the COVER_CLIP flags in analyze_extent()
+     */
+    xmin = pixman_fixed_to_int (transformed.x1 - 8 * pixman_fixed_e - pixman_fixed_1 / 2);
+    ymin = pixman_fixed_to_int (transformed.y1 - 8 * pixman_fixed_e - pixman_fixed_1 / 2);
+    xmax = pixman_fixed_to_int (transformed.x2 + 8 * pixman_fixed_e + pixman_fixed_1 / 2);
+    ymax = pixman_fixed_to_int (transformed.y2 + 8 * pixman_fixed_e + pixman_fixed_1 / 2);
+    src_x = -xmin;
+    src_y = -ymin;
+
+    create_image (xmax - xmin + 64, ymax - ymin + 1, src_format, filter, &t, &src, &src_image);
+
+    if (mask_format)
+    {
+        create_image (xmax - xmin + 64, ymax - ymin + 1, mask_format, filter, &t, &mask, &mask_image);
+        if ((PIXMAN_FORMAT_R(mask_format) || PIXMAN_FORMAT_G(mask_format) || PIXMAN_FORMAT_B(mask_format)))
+            pixman_image_set_component_alpha (mask_image, 1);
+    }
+
+    create_image (WIDTH + 64, HEIGHT, dest_format, filter, &t, &dest, &dest_image);
+
+    {
+        uint32_t n;  /* number of iterations in at least 5 seconds */
+        uint32_t t1; /* time taken to do n iterations, microseconds */
+        uint32_t t2; /* calling overhead for n iterations, microseconds */
+
+        flush_cache ();
+        bench (op, &t, src_image, mask_image, dest_image, src_x, src_y, UINT32_MAX, 5000000, &n, &t1, pixman_image_composite_wrapper);
+        bench (op, &t, src_image, mask_image, dest_image, src_x, src_y, n, UINT32_MAX, NULL, &t2, pixman_image_composite_empty);
+        /* The result indicates the output rate in megapixels/second */
+        printf ("%6.2f\n", (double) n * WIDTH * HEIGHT / (t1 - t2));
+    }
+
+    return EXIT_SUCCESS;
+}
-- 
1.7.5.4



More information about the Pixman mailing list