[Pixman] [PATCH 2/2] test: Add new thread-test program

Lennart Sorensen lsorense at csclub.uwaterloo.ca
Mon Sep 30 07:03:24 PDT 2013


On Sat, Sep 28, 2013 at 10:04:02PM -0400, Søren Sandmann wrote:
> From: Søren Sandmann Pedersen <ssp at redhat.com>
> 
> This test program allocates an array of 16 * 7 uint32_ts and spawns 16
> threads that each use 7 of the allocated uint32_ts as a destination
> image for a large number of composite operations. Each thread then
> computes and returns a checksum for the image. Finally, the main
> thread computes a checksum of the checksums and verifies that it
> matches expectations.
> 
> The purpose of this test is catch errors where memory outside images
> is read and then written back. Such out-of-bounds accesses are broken
> when multiple threads are involved, because the threads will race to
> read and write the shared memory.
> 
> V2:
> - Incorporate fixes from Siarhei for endianness and undefined behavior
>   regarding argument evaluation
> - Make the images 7 pixels wide since the bug only happens when the
>   composite width is greater than 4.
> - Compute a checksum of the checksums so that you don't have to
>   update 16 values if something changes.
> ---
>  test/Makefile.am      |   6 +-
>  test/Makefile.sources |   1 +
>  test/thread-test.c    | 197 ++++++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 201 insertions(+), 3 deletions(-)
>  create mode 100644 test/thread-test.c
> 
> diff --git a/test/Makefile.am b/test/Makefile.am
> index 5d901d5..80f3537 100644
> --- a/test/Makefile.am
> +++ b/test/Makefile.am
> @@ -1,8 +1,8 @@
>  include $(top_srcdir)/test/Makefile.sources
>  
> -AM_CFLAGS = $(OPENMP_CFLAGS)
> -AM_LDFLAGS = $(OPENMP_CFLAGS) $(TESTPROGS_EXTRA_LDFLAGS)
> -LDADD = libutils.la $(top_builddir)/pixman/libpixman-1.la -lm  $(PNG_LIBS)
> +AM_CFLAGS = $(OPENMP_CFLAGS) $(PTHREAD_CFLAGS)$
What is that trailing '$' for?

> +AM_LDFLAGS = $(OPENMP_CFLAGS) $(TESTPROGS_EXTRA_LDFLAGS) $(PTHREAD_LDFLAGS)
> +LDADD = libutils.la $(top_builddir)/pixman/libpixman-1.la -lm  $(PNG_LIBS) $(PTHREAD_LIBS)
>  AM_CPPFLAGS = -I$(top_srcdir)/pixman -I$(top_builddir)/pixman $(PNG_CFLAGS)
>  
>  libutils_la_SOURCES = $(libutils_sources) $(libutils_headers)
> diff --git a/test/Makefile.sources b/test/Makefile.sources
> index 2fabdb5..2ae5d9f 100644
> --- a/test/Makefile.sources
> +++ b/test/Makefile.sources
> @@ -13,6 +13,7 @@ TESTPROGRAMS =			\
>  	infinite-loop		\
>  	trap-crasher		\
>  	alpha-loop		\
> +	thread-test		\
>  	scaling-crash-test	\
>  	scaling-helpers-test	\
>  	gradient-crash-test	\
> diff --git a/test/thread-test.c b/test/thread-test.c
> new file mode 100644
> index 0000000..f24c31d
> --- /dev/null
> +++ b/test/thread-test.c
> @@ -0,0 +1,197 @@
> +#include <config.h>
> +
> +#ifndef HAVE_PTHREADS
> +
> +int main ()
> +{
> +    printf ("Skipped thread-test - pthreads not supported\n");
> +    return 0;
> +}
> +
> +#else
> +
> +#include <stdlib.h>
> +#include <pthread.h>
> +#include "utils.h"
> +
> +typedef struct
> +{
> +    int       thread_no;
> +    uint32_t *dst_buf;
> +} info_t;
> +
> +static const pixman_op_t operators[] = 
> +{
> +    PIXMAN_OP_SRC,
> +    PIXMAN_OP_OVER,
> +    PIXMAN_OP_ADD,
> +    PIXMAN_OP_CLEAR,
> +    PIXMAN_OP_SRC,
> +    PIXMAN_OP_DST,
> +    PIXMAN_OP_OVER,
> +    PIXMAN_OP_OVER_REVERSE,
> +    PIXMAN_OP_IN,
> +    PIXMAN_OP_IN_REVERSE,
> +    PIXMAN_OP_OUT,
> +    PIXMAN_OP_OUT_REVERSE,
> +    PIXMAN_OP_ATOP,
> +    PIXMAN_OP_ATOP_REVERSE,
> +    PIXMAN_OP_XOR,
> +    PIXMAN_OP_ADD,
> +    PIXMAN_OP_SATURATE,
> +    PIXMAN_OP_DISJOINT_CLEAR,
> +    PIXMAN_OP_DISJOINT_SRC,
> +    PIXMAN_OP_DISJOINT_DST,
> +    PIXMAN_OP_DISJOINT_OVER,
> +    PIXMAN_OP_DISJOINT_OVER_REVERSE,
> +    PIXMAN_OP_DISJOINT_IN,
> +    PIXMAN_OP_DISJOINT_IN_REVERSE,
> +    PIXMAN_OP_DISJOINT_OUT,
> +    PIXMAN_OP_DISJOINT_OUT_REVERSE,
> +    PIXMAN_OP_DISJOINT_ATOP,
> +    PIXMAN_OP_DISJOINT_ATOP_REVERSE,
> +    PIXMAN_OP_DISJOINT_XOR,
> +    PIXMAN_OP_CONJOINT_CLEAR,
> +    PIXMAN_OP_CONJOINT_SRC,
> +    PIXMAN_OP_CONJOINT_DST,
> +    PIXMAN_OP_CONJOINT_OVER,
> +    PIXMAN_OP_CONJOINT_OVER_REVERSE,
> +    PIXMAN_OP_CONJOINT_IN,
> +    PIXMAN_OP_CONJOINT_IN_REVERSE,
> +    PIXMAN_OP_CONJOINT_OUT,
> +    PIXMAN_OP_CONJOINT_OUT_REVERSE,
> +    PIXMAN_OP_CONJOINT_ATOP,
> +    PIXMAN_OP_CONJOINT_ATOP_REVERSE,
> +    PIXMAN_OP_CONJOINT_XOR,
> +    PIXMAN_OP_MULTIPLY,
> +    PIXMAN_OP_SCREEN,
> +    PIXMAN_OP_OVERLAY,
> +    PIXMAN_OP_DARKEN,
> +    PIXMAN_OP_LIGHTEN,
> +    PIXMAN_OP_COLOR_DODGE,
> +    PIXMAN_OP_COLOR_BURN,
> +    PIXMAN_OP_HARD_LIGHT,
> +    PIXMAN_OP_DIFFERENCE,
> +    PIXMAN_OP_EXCLUSION,
> +};
> +
> +static const pixman_format_code_t formats[] =
> +{
> +    PIXMAN_a8r8g8b8,
> +    PIXMAN_r5g6b5,
> +    PIXMAN_a8,
> +    PIXMAN_a4,
> +    PIXMAN_a1,
> +    PIXMAN_b5g6r5,
> +    PIXMAN_r8g8b8a8,
> +    PIXMAN_a4r4g4b4
> +};
> +
> +#define N_ROUNDS 8192
> +
> +#define RAND_ELT(arr)							\
> +    arr[prng_rand() % ARRAY_LENGTH (arr)]
> +
> +#define DEST_WIDTH (7)
> +
> +static void *
> +thread (void *data)
> +{
> +    info_t *info = data;
> +    uint32_t crc32 = 0x0;
> +    uint32_t src_buf[64];
> +    pixman_image_t *dst_img, *src_img;
> +    int i;
> +
> +    prng_srand (info->thread_no);
> +
> +    for (i = 0; i < N_ROUNDS; ++i)
> +    {
> +	pixman_op_t op;
> +	int rand1, rand2;
> +
> +	prng_randmemset (info->dst_buf, DEST_WIDTH * sizeof (uint32_t), 0);
> +	prng_randmemset (src_buf, sizeof (src_buf), 0);
> +
> +	src_img = pixman_image_create_bits (
> +	    RAND_ELT (formats), 4, 4, src_buf, 16);
> +	dst_img = pixman_image_create_bits (
> +	    RAND_ELT (formats), DEST_WIDTH, 1, info->dst_buf,
> +	    DEST_WIDTH * sizeof (uint32_t));
> +
> +	image_endian_swap (src_img);
> +	image_endian_swap (dst_img);
> +	
> +	rand2 = prng_rand() % 4;
> +	rand1 = prng_rand() % 4;
> +	op = RAND_ELT (operators);
> +
> +	pixman_image_composite32 (
> +	    op,
> +	    src_img, NULL, dst_img,
> +	    rand1, rand2, 0, 0, 0, 0, DEST_WIDTH, 1);
> +
> +	crc32 = compute_crc32_for_image (crc32, dst_img);
> +
> +	pixman_image_unref (src_img);
> +	pixman_image_unref (dst_img);
> +    }
> +
> +    return (void *)(uintptr_t)crc32;
> +}
> +
> +static inline uint32_t
> +byteswap32 (uint32_t x)
> +{
> +    return ((x & ((uint32_t)0xFF << 24)) >> 24) |
> +           ((x & ((uint32_t)0xFF << 16)) >>  8) |
> +           ((x & ((uint32_t)0xFF <<  8)) <<  8) |
> +           ((x & ((uint32_t)0xFF <<  0)) << 24);
> +}
> +
> +int
> +main (void)
> +{
> +    uint32_t dest[16 * DEST_WIDTH];
> +    info_t info[16] = { { 0 } };
> +    pthread_t threads[16];
> +    void *retvals[16];
> +    uint32_t crc32s[16], crc32;
> +    int i;
> +
> +    for (i = 0; i < 16; ++i)
> +    {
> +	info[i].thread_no = i;
> +	info[i].dst_buf = &dest[i * DEST_WIDTH];
> +    }
> +
> +    for (i = 0; i < 16; ++i)
> +	pthread_create (&threads[i], NULL, thread, &info[i]);
> +
> +    for (i = 0; i < 16; ++i)
> +	pthread_join (threads[i], &retvals[i]);
> +
> +    for (i = 0; i < 16; ++i)
> +    {
> +	crc32s[i] = (uintptr_t)retvals[i];
> +
> +	if (is_little_endian())
> +	    crc32s[i] = byteswap32 (crc32s[i]);
> +    }
> +
> +    crc32 = compute_crc32 (0, crc32s, sizeof crc32s);
> +
> +#define EXPECTED 0xFD497D8D
> +
> +    if (crc32 != EXPECTED)
> +    {
> +	printf ("thread-test failed. Got checksum 0x%08X, expected 0x%08X\n",
> +		crc32, EXPECTED);
> +	return 1;
> +    }
> +
> +    return 0;
> +}
> +
> +#endif
> +
> -- 
> 1.7.11.7

-- 
Len Sorensen


More information about the Pixman mailing list