pixman: Branch 'master' - 5 commits

Siarhei Siamashka siamashka at kemper.freedesktop.org
Thu Jun 3 12:50:48 PDT 2010


 configure.ac                 |    4 +
 test/Makefile.am             |    3 +
 test/blitters-test-bisect.rb |   43 ----------------
 test/blitters-test.c         |   84 +++-----------------------------
 test/fuzzer-find-diff.pl     |   68 ++++++++++++++++++++++++++
 test/scaling-test-bisect.rb  |   38 --------------
 test/scaling-test.c          |   72 ++++-----------------------
 test/utils.c                 |  111 +++++++++++++++++++++++++++++++++++++++++++
 test/utils.h                 |   10 +++
 9 files changed, 216 insertions(+), 217 deletions(-)

New commits:
commit cfc4e38852dc244198a9bfcab07d9014bba21d53
Author: Siarhei Siamashka <siarhei.siamashka at nokia.com>
Date:   Wed May 12 01:34:57 2010 +0300

    test: added OpenMP support for better utilization of multiple CPU cores
    
    Some of the tests are quite heavy CPU users and may benefit from
    using multiple CPU cores, so the programs from 'test' directory
    are now built with OpenMP support. OpenMP is easy to use, portable
    and also takes care of making a decision about how many threads
    to spawn.

diff --git a/configure.ac b/configure.ac
index c9d0c66..56a6e4d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -77,6 +77,10 @@ AC_CHECK_FUNCS([getisax])
 AC_C_BIGENDIAN
 AC_C_INLINE
 
+# Check for OpenMP support (only supported by autoconf >=2.62)
+OPENMP_CFLAGS=
+m4_ifdef([AC_OPENMP], [AC_OPENMP], [AC_SUBST(OPENMP_CFLAGS)])
+
 AC_CHECK_SIZEOF(long)
 
 # Checks for Sun Studio compilers
diff --git a/test/Makefile.am b/test/Makefile.am
index 4ef6b45..d0019ef 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -1,3 +1,6 @@
+AM_CFLAGS = @OPENMP_CFLAGS@
+AM_LDFLAGS = @OPENMP_CFLAGS@
+
 TEST_LDADD = $(top_builddir)/pixman/libpixman-1.la
 INCLUDES = -I$(top_srcdir)/pixman -I$(top_builddir)/pixman
 
diff --git a/test/utils.c b/test/utils.c
index 9cfd9fa..e9b29c8 100644
--- a/test/utils.c
+++ b/test/utils.c
@@ -286,6 +286,8 @@ fuzzer_test_main (const char *test_name,
 	n2 = default_number_of_iterations;
     }
 
+    #pragma omp parallel for reduction(+:checksum) default(none) \
+					shared(n1, n2, test_function, verbose)
     for (i = n1; i <= n2; i++)
     {
 	uint32_t crc = test_function (i, 0);
diff --git a/test/utils.h b/test/utils.h
index 161635f..26a244c 100644
--- a/test/utils.h
+++ b/test/utils.h
@@ -7,6 +7,7 @@
  */
 
 extern uint32_t lcg_seed;
+#pragma omp threadprivate(lcg_seed)
 
 static inline uint32_t
 lcg_rand (void)
commit f905ebb03d8ed8a3ceb76c84a10735aa209168d3
Author: Siarhei Siamashka <siarhei.siamashka at nokia.com>
Date:   Wed May 12 00:10:04 2010 +0300

    test: scaling-test updated to use new fuzzer_test_main() function

diff --git a/test/scaling-test-bisect.rb b/test/scaling-test-bisect.rb
deleted file mode 100644
index ab34262..0000000
--- a/test/scaling-test-bisect.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-#!/usr/bin/env ruby
-
-if not ARGV[0] or not ARGV[1] then
-    printf("Please provide two 'scaling-test' static binaries in the command line.\n\n")
-    printf("The first should be linked with the correct reference pixman library.\n")
-    printf("The second binrary should be linked with the pixman library to be tested.\n")
-    exit(0)
-end
-
-$MAX = 3000000
-$MIN = 1
-$AVG = 0
-
-if `#{ARGV[0]} #{$MAX} 2>/dev/null` == `#{ARGV[1]} #{$MAX} 2>/dev/null` then
-    printf("test ok\n")
-    exit(0)
-end
-
-printf("test failed, bisecting...\n")
-
-while $MAX != $MIN + 1 do
-    $AVG = (($MIN + $MAX) / 2).to_i
-    res1 = `#{ARGV[0]} #{$AVG} 2>/dev/null`
-    res2 = `#{ARGV[1]} #{$AVG} 2>/dev/null`
-    if res1 != res2 then
-        $MAX = $AVG
-    else
-        $MIN = $AVG
-    end
-end
-
-printf("-- ref --\n")
-printf("%s\n", `#{ARGV[0]} -#{$MAX}`)
-printf("-- new --\n")
-printf("%s\n", `#{ARGV[1]} -#{$MAX}`)
-
-printf("\nFailed test number is %d, you can reproduce the problematic conditions\n", $MAX)
-printf("by running 'scaling-test -%d'\n", $MAX)
diff --git a/test/scaling-test.c b/test/scaling-test.c
index 2977290..16583d0 100644
--- a/test/scaling-test.c
+++ b/test/scaling-test.c
@@ -1,24 +1,11 @@
 /*
- * Test program, which can detect problems with nearest neighbout scaling
- * implementation. Also SRC and OVER opetations tested for 16bpp and 32bpp
- * images.
+ * Test program, which can detect some problems with nearest neighbour
+ * and bilinear scaling in pixman. Testing is done by running lots
+ * of random SRC and OVER compositing operations a8r8g8b8, x8a8r8g8b8
+ * and r5g6b5 color formats.
  *
- * Just run it without any command line arguments, and it will report either
- *   "scaling test passed" - everything is ok
- *   "scaling test failed!" - there is some problem
- *
- * In the case of failure, finding the problem involves the following steps:
- * 1. Get the reference 'scaling-test' binary. It makes sense to disable all
- *    the cpu specific optimizations in pixman and also configure it with
- *    '--disable-shared' option. Those who are paranoid can also tweak the
- *    sources to disable all fastpath functions. The resulting binary
- *    can be renamed to something like 'scaling-test.ref'.
- * 2. Compile the buggy binary (also with the '--disable-shared' option).
- * 3. Run 'ruby scaling-test-bisect.rb ./scaling-test.ref ./scaling-test'
- * 4. Look at the information about failed case (destination buffer content
- *    will be shown) and try to figure out what is wrong. It is possible
- *    to use debugging print to stderr in pixman to get more information,
- *    this does not interfere with the testing script.
+ * Script 'fuzzer-find-diff.pl' can be used to narrow down the problem in
+ * the case of test failure.
  */
 #include <assert.h>
 #include <stdlib.h>
@@ -35,8 +22,7 @@
  * Composite operation with pseudorandom images
  */
 uint32_t
-test_composite (uint32_t initcrc,
-		int      testnum,
+test_composite (int      testnum,
 		int      verbose)
 {
     int                i;
@@ -239,53 +225,17 @@ test_composite (uint32_t initcrc,
     pixman_image_unref (src_img);
     pixman_image_unref (dst_img);
 
-    crc32 = compute_crc32 (initcrc, dstbuf, dst_stride * dst_height);
+    crc32 = compute_crc32 (0, dstbuf, dst_stride * dst_height);
     free (srcbuf);
     free (dstbuf);
     return crc32;
 }
 
 int
-main (int   argc, char *argv[])
+main (int argc, const char *argv[])
 {
-    int      i, n = 0;
-    uint32_t crc = 0;
-
     pixman_disable_out_of_bounds_workaround ();
 
-    if (argc >= 2)
-	n = atoi (argv[1]);
-
-    if (n == 0) n = 3000000;
-
-    if (n < 0)
-    {
-	crc = test_composite (0, -n, 1);
-	printf ("crc32=%08X\n", crc);
-    }
-    else
-    {
-	for (i = 1; i <= n; i++)
-	    crc = test_composite (crc, i, 0);
-
-	printf ("crc32=%08X\n", crc);
-
-	if (n == 3000000)
-	{
-	    /* predefined value for running with all the fastpath functions disabled  */
-	    /* it needs to be updated every time changes are introduced to this program! */
-
-	    if (crc == 0x2168ACD1)
-	    {
-		printf ("scaling test passed\n");
-	    }
-	    else
-	    {
-		printf ("scaling test failed!\n");
-		return 1;
-	    }
-	}
-    }
-
-    return 0;
+    return fuzzer_test_main("scaling", 3000000, 0x7833766A,
+			    test_composite, argc, argv);
 }
commit be387701a5b44e68110d5c9df07924d1029e87ac
Author: Siarhei Siamashka <siarhei.siamashka at nokia.com>
Date:   Tue May 11 23:21:05 2010 +0300

    test: blitters-test updated to use new fuzzer_test_main() function

diff --git a/test/blitters-test-bisect.rb b/test/blitters-test-bisect.rb
deleted file mode 100644
index 62ff782..0000000
--- a/test/blitters-test-bisect.rb
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env ruby
-
-if not ARGV[0] or not ARGV[1] then
-    printf("Please provide two 'blitters-test' static binaries in the command line.\n\n")
-    printf("The first should be linked with a correct reference pixman library.\n")
-    printf("The second binary should be linked with a pixman library which needs to be tested.\n")
-    exit(0)
-end
-
-def test_range(min, max)
-    if `#{ARGV[0]} #{min} #{max} 2>/dev/null` == `#{ARGV[1]} #{min} #{max} 2>/dev/null` then
-        return
-    end
-    while max != min + 1 do
-        avg = ((min + max) / 2).to_i
-        res1 = `#{ARGV[0]} #{min} #{avg} 2>/dev/null`
-        res2 = `#{ARGV[1]} #{min} #{avg} 2>/dev/null`
-        if res1 != res2 then
-            max = avg
-        else
-            min = avg
-        end
-    end
-    return max
-end
-
-base = 1
-while true do
-    # run infinitely, processing 100000 test cases per iteration
-    printf("running tests %d-%d\n", base, base + 100000 - 1);
-    res = test_range(base, base + 100000 - 1)
-    if res then
-        printf("-- ref --\n")
-        printf("%s\n", `#{ARGV[0]} -#{res}`)
-        printf("-- new --\n")
-        printf("%s\n", `#{ARGV[1]} -#{res}`)
-
-        printf("\nFailed test %d, you can reproduce the problematic conditions by running\n", res)
-        printf("#{ARGV[1]} -%d\n", res)
-        exit(1)
-    end
-    base += 100000
-end
diff --git a/test/blitters-test.c b/test/blitters-test.c
index 18f871e..673e52f 100644
--- a/test/blitters-test.c
+++ b/test/blitters-test.c
@@ -2,24 +2,8 @@
  * Test program, which stresses the use of different color formats and
  * compositing operations.
  *
- * Just run it without any command line arguments, and it will report either
- *   "blitters test passed" - everything is ok
- *   "blitters test failed!" - there is some problem
- *
- * In the case of failure, finding the problem involves the following steps:
- * 1. Get the reference 'blitters-test' binary. It makes sense to disable all
- *    the cpu specific optimizations in pixman and also configure it with
- *    '--disable-shared' option. Those who are paranoid can also tweak the
- *    sources to disable all fastpath functions. The resulting binary
- *    can be renamed to something like 'blitters-test.ref'.
- * 2. Compile the buggy binary (also with the '--disable-shared' option).
- * 3. Run 'ruby blitters-test-bisect.rb ./blitters-test.ref ./blitters-test'
- * 4. Look at the information about failed case (destination buffer content
- *    will be shown) and try to figure out what is wrong. Loading
- *    test program in gdb, specifying failed test number in the command
- *    line with '-' character prepended and setting breakpoint on
- *    'pixman_image_composite' function can provide detailed information
- *    about function arguments
+ * Script 'fuzzer-find-diff.pl' can be used to narrow down the problem in
+ * the case of test failure.
  */
 #include <assert.h>
 #include <stdlib.h>
@@ -260,7 +244,7 @@ static pixman_format_code_t mask_fmt_list[] = {
  * Composite operation with pseudorandom images
  */
 uint32_t
-test_composite (uint32_t initcrc, int testnum, int verbose)
+test_composite (int testnum, int verbose)
 {
     int i;
     pixman_image_t *src_img = NULL;
@@ -410,15 +394,15 @@ test_composite (uint32_t initcrc, int testnum, int verbose)
 	printf ("---\n");
     }
 
-    free_random_image (initcrc, src_img, -1);
-    crc32 = free_random_image (initcrc, dst_img, dst_fmt);
+    free_random_image (0, src_img, -1);
+    crc32 = free_random_image (0, dst_img, dst_fmt);
 
     if (mask_img)
     {
 	if (srcbuf == maskbuf)
 	    pixman_image_unref(mask_img);
 	else
-	    free_random_image (initcrc, mask_img, -1);
+	    free_random_image (0, mask_img, -1);
     }
 
 
@@ -438,60 +422,10 @@ initialize_palette (void)
 }
 
 int
-main (int argc, char *argv[])
+main (int argc, const char *argv[])
 {
-    int i, n1 = 1, n2 = 0;
-    uint32_t crc = 0;
-    int verbose = getenv ("VERBOSE") != NULL;
-
     initialize_palette();
 
-    if (argc >= 3)
-    {
-	n1 = atoi (argv[1]);
-	n2 = atoi (argv[2]);
-    }
-    else if (argc >= 2)
-    {
-	n2 = atoi (argv[1]);
-    }
-    else
-    {
-	n1 = 1;
-	n2 = 2000000;
-    }
-
-    if (n2 < 0)
-    {
-	crc = test_composite (0, abs (n2), 1);
-	printf ("crc32=%08X\n", crc);
-    }
-    else
-    {
-	for (i = n1; i <= n2; i++)
-	{
-	    crc = test_composite (crc, i, 0);
-
-	    if (verbose)
-		printf ("%d: %08X\n", i, crc);
-	}
-	printf ("crc32=%08X\n", crc);
-
-	if (n2 == 2000000)
-	{
-	    /* Predefined value for running with all the fastpath functions
-	       disabled. It needs to be updated every time when changes are
-	       introduced to this program or behavior of pixman changes! */
-	    if (crc == 0x8F9F7DC1)
-	    {
-		printf ("blitters test passed\n");
-	    }
-	    else
-	    {
-		printf ("blitters test failed!\n");
-		return 1;
-	    }
-	}
-    }
-    return 0;
+    return fuzzer_test_main("blitters", 2000000, 0x2CFE57ED,
+			    test_composite, argc, argv);
 }
commit 9ed9abd1541a0353ba4234dc77dd46d6b8771d88
Author: Siarhei Siamashka <siarhei.siamashka at nokia.com>
Date:   Tue May 11 22:57:48 2010 +0300

    test: blitters-test-bisect.rb converted to perl
    
    This new script can be used to run continuously to compare two test
    programs based on fuzzer_test_main() function from 'util.c' and
    narrow down to a single problematic test from the batch which results
    in different behavior.

diff --git a/test/fuzzer-find-diff.pl b/test/fuzzer-find-diff.pl
new file mode 100644
index 0000000..53d9b8d
--- /dev/null
+++ b/test/fuzzer-find-diff.pl
@@ -0,0 +1,68 @@
+#!/usr/bin/env perl
+
+$usage = "Usage:
+  fuzzer-find-diff.pl reference_binary new_binary [number_of_tests_to_run]
+
+The first two input arguments are the commands to run the test programs
+based on fuzzer_test_main() function from 'util.c' (preferably they should
+be statically compiled, this can be achieved via '--disable-shared' pixman
+configure option). The third optional argument is the number of test rounds
+to run (if not specified, then testing runs infinitely or until some problem
+is detected).
+
+Usage examples:
+  fuzzer-find-diff.pl ./blitters-test-with-sse-disabled ./blitters-test 9000000
+  fuzzer-find-diff.pl ./blitters-test \"ssh ppc64_host /path/to/blitters-test\"
+";
+
+$#ARGV >= 1 or die $usage;
+
+$batch_size = 10000;
+
+if ($#ARGV >= 2) {
+    $number_of_tests = int($ARGV[2]);
+} else {
+    $number_of_tests = -1
+}
+
+sub test_range {
+    my $min = shift;
+    my $max = shift;
+
+    if (`$ARGV[0] $min $max 2>/dev/null` eq `$ARGV[1] $min $max 2>/dev/null`) {
+        return;
+    }
+
+    while ($max != $min + 1) {
+        my $avg = int(($min + $max) / 2);
+        my $res1 = `$ARGV[0] $min $avg 2>/dev/null`;
+        my $res2 = `$ARGV[1] $min $avg 2>/dev/null`;
+        if ($res1 ne $res2) {
+            $max = $avg;
+        } else {
+            $min = $avg;
+        }
+    }
+    return $max;
+}
+
+$base = 1;
+while ($number_of_tests <= 0 || $base <= $number_of_tests) {
+    printf("testing %-12d\r", $base + $batch_size - 1);
+    my $res = test_range($base, $base + $batch_size - 1);
+    if ($res) {
+        printf("Failure: results are different for test %d:\n", $res);
+
+        printf("\n-- ref --\n");
+        print `$ARGV[0] $res`;
+        printf("-- new --\n");
+        print `$ARGV[1] $res`;
+
+        printf("The problematic conditions can be reproduced by running:\n");
+        printf("$ARGV[1] %d\n", $res);
+
+        exit(1);
+    }
+    $base += $batch_size;
+}
+printf("Success: %d tests finished\n", $base - 1);
commit 30c3e91c3f97cf3d5932ba639d8ac126b83efb70
Author: Siarhei Siamashka <siarhei.siamashka at nokia.com>
Date:   Tue May 11 22:46:47 2010 +0300

    test: main loop from blitters-test added as a new function to utils.c
    
    This new generalized function can be reused in both blitters-test
    and scaling-test. Final checksum calculation changed in order to make
    it parallelizable (it is a sum of individual 32-bit values returned
    by a callback function, which is now responsible for running test-specific
    code). Return values may be crc32, some other hash or even just zero on
    success and non-zero on error (in this case, the expected result of the
    whole test run should be 0).

diff --git a/test/utils.c b/test/utils.c
index 58cd100..9cfd9fa 100644
--- a/test/utils.c
+++ b/test/utils.c
@@ -206,3 +206,112 @@ make_random_bytes (int n_bytes)
 
     return bytes;
 }
+
+/*
+ * A function, which can be used as a core part of the test programs,
+ * intended to detect various problems with the help of fuzzing input
+ * to pixman API (according to some templates, aka "smart" fuzzing).
+ * Some general information about such testing can be found here:
+ * http://en.wikipedia.org/wiki/Fuzz_testing
+ *
+ * It may help detecting:
+ *  - crashes on bad handling of valid or reasonably invalid input to
+ *    pixman API.
+ *  - deviations from the behavior of older pixman releases.
+ *  - deviations from the behavior of the same pixman release, but
+ *    configured in a different way (for example with SIMD optimizations
+ *    disabled), or running on a different OS or hardware.
+ *
+ * The test is performed by calling a callback function a huge number
+ * of times. The callback function is expected to run some snippet of
+ * pixman code with pseudorandom variations to the data feeded to
+ * pixman API. A result of running each callback function should be
+ * some deterministic value which depends on test number (test number
+ * can be used as a seed for PRNG). When 'verbose' argument is nonzero,
+ * callback function is expected to print to stdout some information
+ * about what it does.
+ *
+ * Return values from many small tests are accumulated together and
+ * used as final checksum, which can be compared to some expected
+ * value. Running the tests not individually, but in a batch helps
+ * to reduce process start overhead and also allows to parallelize
+ * testing and utilize multiple CPU cores.
+ *
+ * The resulting executable can be run without any arguments. In
+ * this case it runs a batch of tests starting from 1 and up to
+ * 'default_number_of_iterations'. The resulting checksum is
+ * compared with 'expected_checksum' and FAIL or PASS verdict
+ * depends on the result of this comparison.
+ *
+ * If the executable is run with 2 numbers provided as command line
+ * arguments, they specify the starting and ending numbers for a test
+ * batch.
+ *
+ * If the executable is run with only one number provided as a command
+ * line argument, then this number is used to call the callback function
+ * once, and also with verbose flag set.
+ */
+int
+fuzzer_test_main (const char *test_name,
+		  int         default_number_of_iterations,
+		  uint32_t    expected_checksum,
+		  uint32_t    (*test_function)(int testnum, int verbose),
+		  int         argc,
+		  const char *argv[])
+{
+    int i, n1 = 1, n2 = 0;
+    uint32_t checksum = 0;
+    int verbose = getenv ("VERBOSE") != NULL;
+
+    if (argc >= 3)
+    {
+	n1 = atoi (argv[1]);
+	n2 = atoi (argv[2]);
+	if (n2 < n1)
+	{
+	    printf ("invalid test range\n");
+	    return 1;
+	}
+    }
+    else if (argc >= 2)
+    {
+	n2 = atoi (argv[1]);
+	checksum = test_function (n2, 1);
+	printf ("%d: checksum=%08X\n", n2, checksum);
+	return 0;
+    }
+    else
+    {
+	n1 = 1;
+	n2 = default_number_of_iterations;
+    }
+
+    for (i = n1; i <= n2; i++)
+    {
+	uint32_t crc = test_function (i, 0);
+	if (verbose)
+	    printf ("%d: %08X\n", i, crc);
+	checksum += crc;
+    }
+
+    if (n1 == 1 && n2 == default_number_of_iterations)
+    {
+	if (checksum == expected_checksum)
+	{
+	    printf ("%s test passed (checksum=%08X)\n",
+		    test_name, checksum);
+	}
+	else
+	{
+	    printf ("%s test failed! (checksum=%08X, expected %08X)\n",
+		    test_name, checksum, expected_checksum);
+	    return 1;
+	}
+    }
+    else
+    {
+	printf ("%d-%d: checksum=%08X\n", n1, n2, checksum);
+    }
+
+    return 0;
+}
diff --git a/test/utils.h b/test/utils.h
index fb1ccec..161635f 100644
--- a/test/utils.h
+++ b/test/utils.h
@@ -43,3 +43,12 @@ image_endian_swap (pixman_image_t *img, int bpp);
 /* Generate n_bytes random bytes in malloced memory */
 uint8_t *
 make_random_bytes (int n_bytes);
+
+/* main body of the fuzzer test */
+int
+fuzzer_test_main (const char *test_name,
+		  int         default_number_of_iterations,
+		  uint32_t    expected_checksum,
+		  uint32_t    (*test_function)(int testnum, int verbose),
+		  int         argc,
+		  const char *argv[]);


More information about the xorg-commit mailing list