[PATCH 7/7] vcomp110: Add test for C2VectParallel().

Paul Gofman pgofman at codeweavers.com
Mon Feb 8 17:44:17 CST 2021


Signed-off-by: Paul Gofman <pgofman at codeweavers.com>
---
 configure.ac                    |   1 +
 dlls/vcomp110/tests/Makefile.in |   4 +
 dlls/vcomp110/tests/vcomp110.c  | 278 ++++++++++++++++++++++++++++++++
 3 files changed, 283 insertions(+)
 create mode 100644 dlls/vcomp110/tests/Makefile.in
 create mode 100644 dlls/vcomp110/tests/vcomp110.c

diff --git a/configure.ac b/configure.ac
index 980ea3fb655..852024e0310 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3741,6 +3741,7 @@ WINE_CONFIG_MAKEFILE(dlls/vcomp)
 WINE_CONFIG_MAKEFILE(dlls/vcomp/tests)
 WINE_CONFIG_MAKEFILE(dlls/vcomp100)
 WINE_CONFIG_MAKEFILE(dlls/vcomp110)
+WINE_CONFIG_MAKEFILE(dlls/vcomp110/tests)
 WINE_CONFIG_MAKEFILE(dlls/vcomp120)
 WINE_CONFIG_MAKEFILE(dlls/vcomp140)
 WINE_CONFIG_MAKEFILE(dlls/vcomp90)
diff --git a/dlls/vcomp110/tests/Makefile.in b/dlls/vcomp110/tests/Makefile.in
new file mode 100644
index 00000000000..98fba09e5b4
--- /dev/null
+++ b/dlls/vcomp110/tests/Makefile.in
@@ -0,0 +1,4 @@
+TESTDLL = vcomp110.dll
+
+C_SRCS = \
+	vcomp110.c
diff --git a/dlls/vcomp110/tests/vcomp110.c b/dlls/vcomp110/tests/vcomp110.c
new file mode 100644
index 00000000000..c289535f25b
--- /dev/null
+++ b/dlls/vcomp110/tests/vcomp110.c
@@ -0,0 +1,278 @@
+/*
+ * Unit test suite for vcomp110
+ *
+ * Copyright 2021 Paul Gofman for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <stdio.h>
+#include "wine/test.h"
+
+static HMODULE vcomp_handle;
+
+static void  (CDECL   *pC2VectParallel)(int start, int end, int step, BOOL end_included, int thread_count,
+        BOOL dynamic_distribution, void *function, int nargs, ...);
+static int   (CDECL   *p_vcomp_get_thread_num)(void);
+static int   (CDECL   *pomp_get_num_threads)(void);
+static void  (CDECL   *pomp_set_num_threads)(int num_threads);
+static void  (CDECL   *p_vcomp_set_num_threads)(int num_threads);
+
+#define VCOMP_GET_PROC(func) \
+    do \
+    { \
+        p ## func = (void *)GetProcAddress(vcomp_handle, #func); \
+        if (!p ## func) trace("Failed to get address for %s\n", #func); \
+    } \
+    while (0)
+
+static BOOL init_vcomp(void)
+{
+    vcomp_handle = LoadLibraryA("vcomp110.dll");
+    if (!vcomp_handle)
+    {
+        win_skip("vcomp110.dll is not installed.\n");
+        return FALSE;
+    }
+
+    VCOMP_GET_PROC(C2VectParallel);
+    VCOMP_GET_PROC(_vcomp_get_thread_num);
+    VCOMP_GET_PROC(omp_get_num_threads);
+    VCOMP_GET_PROC(omp_set_num_threads);
+    VCOMP_GET_PROC(_vcomp_set_num_threads);
+
+    return TRUE;
+}
+
+#define TEST_C2VECTPARALLEL_MAX_THREADS 256
+#define TEST_C2VECTPARALLEL_MAX_VALUES 256
+#define TEST_C2VECTPARALLEL_MAX_CALLS 256
+
+struct C2VectParallel_test_data
+{
+    int start;
+    int end;
+    int step;
+    BOOL end_included;
+    int thread_count;
+    unsigned int expected_call_count;
+    unsigned int expected_dynamic_call_count;
+};
+
+static volatile LONG test_C2VectParallel_call_count;
+
+static void CDECL test_C2VectParallel_payload(int start, int end, void *test_parameter,
+        const struct C2VectParallel_test_data *test, unsigned int test_index, BOOL dynamic_distribution)
+{
+    int thread_count = test->thread_count ? test->thread_count : 5;
+    int thread = p_vcomp_get_thread_num();
+    int expected_start, expected_end;
+    int omp_num_threads;
+    int step_sign;
+
+    step_sign = test->step > 0 ? 1 : -1;
+
+    omp_num_threads = pomp_get_num_threads();
+
+    InterlockedIncrement(&test_C2VectParallel_call_count);
+
+    if ((test->end - test->start) / test->step < 2)
+    {
+        ok(omp_num_threads == 1, "Got unexpected omp_num_threads %u, thread_count %u, test %u.\n",
+                omp_num_threads, thread_count, test_index);
+        ok(!thread, "Got unexpected thread %d, test %u.\n", thread, test_index);
+        ok(start == test->start, "Got unexpected start %d, expected %d, thread %d, test %u.\n",
+                start, test->start, thread, test_index);
+        ok(end == test->end, "Got unexpected end %d, expected %d, thread %d, test %u.\n",
+                end, test->end, thread, test_index);
+        return;
+    }
+
+    ok(thread_count == omp_num_threads, "Got unexpected omp_num_threads %u, thread_count %u, test %u.\n",
+            omp_num_threads, thread_count, test_index);
+
+    ok(test_parameter == (void *)0xdeadbeef, "Got unexpected test_parameter %p.\n", test_parameter);
+
+    if (dynamic_distribution)
+    {
+        unsigned int remaining_count;
+        unsigned int loop_count = 0;
+
+        expected_start = test->start;
+        do
+        {
+            ++loop_count;
+            remaining_count = test->end - expected_start + test->step - step_sign * !test->end_included;
+            if (test->step < 0)
+                remaining_count = (unsigned int)-remaining_count / -test->step;
+            else
+                remaining_count /= test->step;
+
+            expected_end = expected_start + (remaining_count + thread_count - 1) / thread_count * test->step
+                    + step_sign * !test->end_included;
+
+            if ((expected_end - test->end) * step_sign > 0)
+                expected_end = test->end;
+            else
+                expected_end -= test->step;
+
+            if (expected_start == start)
+                break;
+
+            expected_start = expected_end - step_sign * !test->end_included + test->step;
+        }
+        while (loop_count < 100);
+        ok(loop_count < 100, "Could not match start %d after %u iterations, test %u.\n",
+                start, loop_count, test_index);
+    }
+    else
+    {
+        unsigned int step_count, steps_per_call, remainder;
+
+        step_count = test->end - test->start + test->step - step_sign * !test->end_included;
+        if (test->step < 0)
+            step_count = (unsigned int)-step_count / -test->step;
+        else
+            step_count /= test->step;
+
+        steps_per_call = step_count / thread_count;
+        remainder = step_count % thread_count;
+
+        if (thread < remainder)
+        {
+            expected_start = thread * (steps_per_call + 1);
+            expected_end = expected_start + steps_per_call + 1;
+        }
+        else if (thread < step_count)
+        {
+            expected_start = remainder + steps_per_call * thread;
+            expected_end = expected_start + steps_per_call;
+        }
+        else
+        {
+            expected_start = expected_end = 0;
+        }
+
+        expected_start = test->start + expected_start * test->step;
+        expected_end = test->start + expected_end * test->step;
+
+        expected_end -= test->step;
+        if (!test->end_included)
+            expected_end += step_sign;
+    }
+
+    ok(start == expected_start, "Got unexpected start %d, expected %d, thread %d, test %u.\n",
+            start, expected_start, thread, test_index);
+    ok(end == expected_end, "Got unexpected end %d, expected %d, start %d, thread %d, dynamic %#x, test %u.\n",
+            end, expected_end, start, thread, dynamic_distribution, test_index);
+}
+
+static void test_C2VectParallel(void)
+{
+    static const struct C2VectParallel_test_data tests[] =
+    {
+        {28, 28, 1, 0, 6, 1, 1},
+        {28, 28, 1, 1, 6, 1, 1},
+        {28, 29, 1, 0, 6, 1, 1},
+        {28, 29, 1, 1, 6, 1, 1},
+
+        /* Native generates calls from excessive threads with empty range here. */
+        {28, 30, 1, 0, 6, 6, 2},
+        {28, 31, 1, 0, 6, 6, 3},
+        {28, 33, 1, 0, 6, 6, 5},
+        {0, -2, -1, 0, 3, 3, 2},
+
+        /* But not in such cases. */
+        {28, 30, 1, 1, 6, 3, 3},
+        {28, 31, 2, 0, 6, 1, 1},
+        {28, 32, 2, 0, 6, 2, 2},
+
+        {28, 57, 1, 0, 6, 6, 13},
+        {28, 57, 1, 1, 6, 6, 13},
+        {28, 57, 4, 1, 6, 6, 7},
+        {28, 36, 4, 0, 6, 2, 2},
+        {28, 36, 4, 1, 6, 3, 3},
+        {36, 28, 4, 0, 6, 1, 1},
+        {36, 28, 4, 1, 6, 1, 1},
+        {57, 28, -1, 0, 6, 6, 13},
+        {57, 28, -1, 1, 6, 6, 13},
+        {36, 28, -4, 0, 6, 2, 2},
+        {36, 28, -4, 1, 6, 3, 3},
+        {28, 57, 1, 0, 0, 5, 11},
+        {-10, -2, 2, 1, 2, 2, 3},
+        {0x7ffffffd, 0x7fffffff, 1, 1, 2, 2, 2},
+        {-1, 0x7fffffff, 0x10000000, 1, 2, 1, 1},
+        {0, 0x7fffffff, 1, 0, 2, 2, 31},
+        {0, 0x7fffffff, 1, 1, 2, 2, 32},
+        {-10000, 0x7fffffff, 1, 1, 2, 1, 1},
+        {-10000, 0x7fffffff, 2, 1, 2, 1, 1},
+        {-10000, 0x7ffffff0, 2, 1, 2, 1, 1},
+        {-10000, 0x7fffffff - 10000, 1, 0, 1, 1, 1},
+        {-10000, 0x7fffffff - 10000, 1, 1, 1, 1, 1},
+        {-10000, 0x7fffffff - 10000, 1, 0, 2, 2, 31},
+        {-10000, 0x7fffffff - 10000, 1, 1, 2, 2, 32},
+        {-10000, 0x7fffffff - 10000, 2, 0, 2, 2, 31},
+        {-10000, 0x7fffffff - 10000, 2, 1, 2, 2, 31},
+        {0x80000001, 0, 2, 0, 3, 3, 51},
+        {0x80000001, 0, 2, 1, 3, 3, 51},
+        {0x80000000, 0x7fffffff, 1, 0, 3, 1, 1},
+        {0x80000000, 0x7fffffff, 1, 1, 3, 1, 1},
+        {0x80000000, 0x7fffffff, 2, 0, 3, 1, 1},
+        {0x80000000, 0x7fffffff, 2, 1, 3, 1, 1},
+        {0x80000001, 1, 1, 0, 3, 1, 1},
+        {0x80000001, 1, 1, 1, 3, 1, 1},
+        {0x80000001, 0, 1, 0, 3, 3, 52},
+        {0x80000001, 0, 1, 1, 3, 3, 52},
+        {28, 28, 1, 0, -1, 1, 1},
+#if 0
+        /* Causes division by zero in native vcomp. */
+        {28, 57, 0, 0, 6, 6},
+#endif
+    };
+    int num_threads;
+    unsigned int i;
+
+    pomp_set_num_threads(5);
+    p_vcomp_set_num_threads(3);
+    num_threads = pomp_get_num_threads();
+    ok(num_threads == 1, "Got unexpected num_threads %u.\n", num_threads);
+
+    for (i = 0; i < ARRAY_SIZE(tests); ++i)
+    {
+        const struct C2VectParallel_test_data *test = &tests[i];
+
+        test_C2VectParallel_call_count = 0;
+        pC2VectParallel(test->start, test->end, test->step, test->end_included, test->thread_count,
+                FALSE, test_C2VectParallel_payload, 6, (void *)0xdeadbeef, test, i, FALSE);
+        ok(test_C2VectParallel_call_count == test->expected_call_count,
+                "Got unexpected call count %u, expected %u, test %u.\n",
+                test_C2VectParallel_call_count, test->expected_call_count, i);
+
+        test_C2VectParallel_call_count = 0;
+        pC2VectParallel(test->start, test->end, test->step, test->end_included, test->thread_count,
+                ~0u, test_C2VectParallel_payload, 6, (void *)0xdeadbeef, test, i, TRUE);
+        ok(test_C2VectParallel_call_count == test->expected_dynamic_call_count,
+                "Got unexpected call count %u, expected %u, test %u.\n",
+                test_C2VectParallel_call_count, test->expected_dynamic_call_count, i);
+    }
+}
+
+START_TEST(vcomp110)
+{
+    if (!init_vcomp())
+        return;
+
+    test_C2VectParallel();
+}
-- 
2.29.2




More information about the wine-devel mailing list