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

Pekka Paalanen ppaalanen at gmail.com
Tue Apr 14 03:28:51 PDT 2015


On Wed,  8 Apr 2015 14:20:09 +0100
Ben Avison <bavison at riscosopen.org> wrote:

> ---
>  .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
...
> + * 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 */

Hi,

you asked about reading the cache sizes; I have no idea about that.

> +#define PAGE_SIZE (4 * 1024)

Hm, sysconf(3) has PAGESIZE query, but I don't know if it is
appropriate here. I also tend to forget that Windows might be relevant
for Pixman.

I think this #define is just fine for now. It clearly documents what
the number is.

> +
> +typedef struct box_48_16 box_48_16_t;

...

> +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;

Space before opening paren.

> +
> +    *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;

Empty line.

> +    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
> +}

...

> +int
> +parse_fixed_argument (char *arg, pixman_fixed_t *value)
> +{
> +    char *tailptr;

Empty line.

> +    *value = pixman_double_to_fixed (strtod (arg, &tailptr));

Empty line.

> +    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");

Hmm. Should I maybe add another, or modify, function to print the list
of recognized pixel formats and operators into utils.c?

Like list_formats() and list_operators(), but printing also the aliases
somehow?

Well, it's not important. Maybe one day.

Any reason we shouldn't use the same test pattern here as
lowlevel-blt-bench is parsing? Just for the op/src/mask/dst.
I suppose I could in the future move the pattern parser into utils, and
plug in the self-test there.

> +        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);

Ah, but you use a different way to set CA. Any reason to differ from
lowlevel-blt-bench?

> +    }
> +
> +    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;
> +}

This is looking better and better. Once we have discussed all the
topics in my earlier email, and landed the lowlevel-blt-bench parser
and lookup table stuff, I think it would be time for the final revision
of this patch.


Thanks,
pq


More information about the Pixman mailing list