winpr/synch: improve barrier test
authorNorbert Federa <norbert.federa@thincast.com>
Mon, 6 Jun 2016 13:33:16 +0000 (15:33 +0200)
committerNorbert Federa <norbert.federa@thincast.com>
Mon, 6 Jun 2016 13:41:05 +0000 (15:41 +0200)
The SYNCHRONIZATION_BARRIER_FLAGS_SPIN_ONLY flag caused this test
to run extremely long if the system has very few processors.
Although this is expected (thread starvation) this will cause a
intolerably long execution time for automated tests.
Changed the number of threads to be calculated dyamically based
on the number of processors.
Also do proper cleanup to prevent memory leaks.

winpr/libwinpr/synch/test/TestSynchBarrier.c

index c738cd6..b7977b7 100644 (file)
@@ -3,31 +3,31 @@
 #include <winpr/synch.h>
 #include <winpr/thread.h>
 #include <winpr/interlocked.h>
+#include <winpr/sysinfo.h>
 
 #include "../synch.h"
 
 static SYNCHRONIZATION_BARRIER gBarrier;
 static HANDLE gStartEvent = NULL;
-
-static LONG gThreadCount = 0;
-static LONG gTrueCount   = 0;
-static LONG gFalseCount  = 0;
 static LONG gErrorCount  = 0;
 
-#define LOOP_COUNT      200
-#define THREAD_COUNT    32
-#define MAX_SLEEP_MS    16
+#define MAX_SLEEP_MS    32
 
-#define EXPECTED_TRUE_COUNT  LOOP_COUNT
-#define EXPECTED_FALSE_COUNT (LOOP_COUNT * (THREAD_COUNT - 1))
+struct test_params
+{
+       LONG threadCount;
+       LONG trueCount;
+       LONG falseCount;
+       DWORD loops;
+       DWORD flags;
+};
 
 
 DWORD WINAPI test_synch_barrier_thread(LPVOID lpParam)
 {
        BOOL status = FALSE;
-       DWORD i, tnum = InterlockedIncrement(&gThreadCount) - 1;
-
-       DWORD dwFlags = *(DWORD*)lpParam;
+       struct test_params* p = (struct test_params*)lpParam;
+       DWORD i, tnum = InterlockedIncrement(&p->threadCount) - 1;
 
        //printf("Thread #%03u entered.\n", tnum);
 
@@ -40,16 +40,16 @@ DWORD WINAPI test_synch_barrier_thread(LPVOID lpParam)
 
        //printf("Thread #%03u unblocked.\n", tnum);
 
-       for (i = 0; i < LOOP_COUNT && gErrorCount == 0; i++)
+       for (i = 0; i < p->loops && gErrorCount == 0; i++)
        {
                /* simulate different execution times before the barrier */
                Sleep(rand() % MAX_SLEEP_MS);
-               status = EnterSynchronizationBarrier(&gBarrier, dwFlags);
+               status = EnterSynchronizationBarrier(&gBarrier, p->flags);
                //printf("Thread #%03u status: %s\n", tnum, status ? "TRUE" : "FALSE");
                if (status)
-                       InterlockedIncrement(&gTrueCount);
+                       InterlockedIncrement(&p->trueCount);
                else
-                       InterlockedIncrement(&gFalseCount);
+                       InterlockedIncrement(&p->falseCount);
        }
 out:
        //printf("Thread #%03u leaving.\n", tnum);
@@ -57,21 +57,35 @@ out:
 }
 
 
-BOOL TestSynchBarrierWithFlags(DWORD dwFlags)
+BOOL TestSynchBarrierWithFlags(DWORD dwFlags, DWORD dwThreads, DWORD dwLoops)
 {
-       HANDLE threads[THREAD_COUNT];
-       DWORD dwStatus;
+       HANDLE *threads;
+       struct test_params p;
+       DWORD dwStatus, expectedTrueCount, expectedFalseCount;
        int i;
 
-       gThreadCount = 0;
-       gTrueCount   = 0;
-       gFalseCount  = 0;
+       p.threadCount = 0;
+       p.trueCount   = 0;
+       p.falseCount  = 0;
+       p.loops = dwLoops;
+       p.flags = dwFlags;
 
-       printf("%s: >> Testing with EnterSynchronizationBarrier flags 0x%08x\n", __FUNCTION__, dwFlags);
+       expectedTrueCount = dwLoops;
+       expectedFalseCount = dwLoops * (dwThreads - 1);
+
+       printf("%s: >> Testing with flags 0x%08x. Using %u threads performing %u loops\n",
+                __FUNCTION__, dwFlags, dwThreads, dwLoops);
+
+       if (!(threads = calloc(dwThreads, sizeof(HANDLE))))
+       {
+               printf("%s: error allocatin thread array memory\n", __FUNCTION__);
+               return FALSE;
+       }
 
-       if (!InitializeSynchronizationBarrier(&gBarrier, THREAD_COUNT, -1))
+       if (!InitializeSynchronizationBarrier(&gBarrier, dwThreads, -1))
        {
                printf("%s: InitializeSynchronizationBarrier failed. GetLastError() = 0x%08x", __FUNCTION__, GetLastError());
+               free(threads);
                DeleteSynchronizationBarrier(&gBarrier);
                return FALSE;
        }
@@ -79,13 +93,14 @@ BOOL TestSynchBarrierWithFlags(DWORD dwFlags)
        if (!(gStartEvent = CreateEvent(NULL, TRUE, FALSE, NULL)))
        {
                printf("%s: CreateEvent failed with error 0x%08x", __FUNCTION__, GetLastError());
+               free(threads);
                DeleteSynchronizationBarrier(&gBarrier);
                return FALSE;
        }
 
-       for (i = 0; i < THREAD_COUNT; i++)
+       for (i = 0; i < dwThreads; i++)
        {
-               if (!(threads[i] = CreateThread(NULL, 0, test_synch_barrier_thread, &dwFlags, 0, NULL)))
+               if (!(threads[i] = CreateThread(NULL, 0, test_synch_barrier_thread, &p, 0, NULL)))
                {
                        printf("%s: CreateThread failed for thread #%u with error 0x%08x\n", __FUNCTION__, i, GetLastError());
                        InterlockedIncrement(&gErrorCount);
@@ -102,14 +117,25 @@ BOOL TestSynchBarrierWithFlags(DWORD dwFlags)
                        InterlockedIncrement(&gErrorCount);
                }
 
-               if (WAIT_OBJECT_0 != (dwStatus = WaitForMultipleObjects(i, threads, TRUE, INFINITE)))
+               while (i--)
                {
-                       printf("%s: WaitForMultipleObjects unexpectedly returned %u (error = 0x%08x)\n",
-                               __FUNCTION__, dwStatus, GetLastError());
-                       gErrorCount++;
+                       if (WAIT_OBJECT_0 != (dwStatus = WaitForSingleObject(threads[i], INFINITE)))
+                       {
+                               printf("%s: WaitForSingleObject(thread[%d] unexpectedly returned %u (error = 0x%08x)\n",
+                                       __FUNCTION__, i, dwStatus, GetLastError());
+                               InterlockedIncrement(&gErrorCount);
+                       }
+                       if (!CloseHandle(threads[i]))
+                       {
+                               printf("%s: CloseHandle(thread[%d]) failed with error = 0x%08x)\n",
+                                       __FUNCTION__, i, GetLastError());
+                               InterlockedIncrement(&gErrorCount);
+                       }
                }
        }
 
+       free(threads);
+
        if (!CloseHandle(gStartEvent))
        {
                printf("%s: CloseHandle(gStartEvent) failed with error = 0x%08x)\n",
@@ -119,15 +145,19 @@ BOOL TestSynchBarrierWithFlags(DWORD dwFlags)
 
        DeleteSynchronizationBarrier(&gBarrier);
 
-       if (gTrueCount != EXPECTED_TRUE_COUNT)
+       if (p.threadCount != dwThreads)
                InterlockedIncrement(&gErrorCount);
 
-       if (gFalseCount != EXPECTED_FALSE_COUNT)
+       if (p.trueCount != expectedTrueCount)
                InterlockedIncrement(&gErrorCount);
 
-       printf("%s: gErrorCount: %d\n", __FUNCTION__, gErrorCount);
-       printf("%s: gTrueCount:  %d (expected %d)\n", __FUNCTION__, gTrueCount, LOOP_COUNT);
-       printf("%s: gFalseCount: %d (expected %d)\n", __FUNCTION__, gFalseCount, LOOP_COUNT * (THREAD_COUNT - 1));
+       if (p.falseCount != expectedFalseCount)
+               InterlockedIncrement(&gErrorCount);
+
+       printf("%s: error count:  %d\n", __FUNCTION__, gErrorCount);
+       printf("%s: thread count: %d (expected %u)\n", __FUNCTION__, p.threadCount, dwThreads);
+       printf("%s: true count:   %d (expected %d)\n", __FUNCTION__, p.trueCount, expectedTrueCount);
+       printf("%s: false count:  %d (expected %d)\n", __FUNCTION__, p.falseCount, expectedFalseCount);
 
        if (gErrorCount > 0)
        {
@@ -141,6 +171,18 @@ BOOL TestSynchBarrierWithFlags(DWORD dwFlags)
 
 int TestSynchBarrier(int argc, char* argv[])
 {
+       SYSTEM_INFO sysinfo;
+       DWORD dwMaxThreads;
+       DWORD dwMinThreads;
+       DWORD dwNumLoops = 200;
+
+       GetNativeSystemInfo(&sysinfo);
+       printf("%s: Number of processors: %u\n", __FUNCTION__, sysinfo.dwNumberOfProcessors);
+       dwMinThreads = sysinfo.dwNumberOfProcessors;
+       dwMaxThreads = sysinfo.dwNumberOfProcessors * 4;
+       if (dwMaxThreads > 32)
+               dwMaxThreads = 32;
+
        /* Test invalid parameters */
        if (InitializeSynchronizationBarrier(&gBarrier, 0, -1))
        {
@@ -162,13 +204,13 @@ int TestSynchBarrier(int argc, char* argv[])
 
        /* Functional tests */
 
-       if (!TestSynchBarrierWithFlags(0))
+       if (!TestSynchBarrierWithFlags(0, dwMaxThreads, dwNumLoops))
                return -1;
 
-       if (!TestSynchBarrierWithFlags(SYNCHRONIZATION_BARRIER_FLAGS_SPIN_ONLY))
+       if (!TestSynchBarrierWithFlags(SYNCHRONIZATION_BARRIER_FLAGS_SPIN_ONLY, dwMinThreads, dwNumLoops))
                return -1;
 
-       if (!TestSynchBarrierWithFlags(SYNCHRONIZATION_BARRIER_FLAGS_BLOCK_ONLY))
+       if (!TestSynchBarrierWithFlags(SYNCHRONIZATION_BARRIER_FLAGS_BLOCK_ONLY, dwMaxThreads, dwNumLoops))
                return -1;
 
        printf("%s: Test successfully completed\n", __FUNCTION__);