test/testatomic.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 16 Jan 2011 15:16:39 -0800
changeset 5004 0c72ae7b7cb2
parent 5003 3a95a2b93eb3
child 5006 8e8876e4aec6
permissions -rw-r--r--
Added native atomic operations for Windows, Mac OS X, and gcc compiler intrinsics.
Changed the CAS return value to bool, so it's efficient with OSAtomicCompareAndSwap32Barrier()
Added an atomic test adapted from code by Michael Davidsaver
     1 #include <stdio.h>
     2 #include "SDL.h"
     3 #include "SDL_assert.h"
     4 
     5 /*
     6   Absolutely basic tests just to see if we get the expected value
     7   after calling each function.
     8 */
     9 
    10 static
    11 char *
    12 tf(SDL_bool tf)
    13 {
    14     static char *t = "TRUE";
    15     static char *f = "FALSE";
    16 
    17     if (tf)
    18     {
    19        return t;
    20     }
    21 
    22     return f;
    23 }
    24 
    25 static
    26 void RunBasicTest()
    27 {
    28     int value;
    29     SDL_SpinLock lock = 0;
    30 
    31     SDL_bool tfret = SDL_FALSE;
    32 
    33     printf("\nspin lock---------------------------------------\n\n");
    34 
    35     SDL_AtomicLock(&lock);
    36     printf("AtomicLock                   lock=%d\n", lock);
    37     SDL_AtomicUnlock(&lock);
    38     printf("AtomicUnlock                 lock=%d\n", lock);
    39 
    40     printf("\natomic -----------------------------------------\n\n");
    41 
    42     SDL_atomic_t v;
    43      
    44     SDL_AtomicSet(&v, 0);
    45     tfret = SDL_AtomicSet(&v, 10) == 0;
    46     printf("AtomicSet(10)        tfret=%s val=%"PRIu32"\n", tf(tfret), SDL_AtomicGet(&v));
    47     tfret = SDL_AtomicAdd(&v, 10) == 10;
    48     printf("AtomicAdd(10)        tfret=%s val=%"PRIu32"\n", tf(tfret), SDL_AtomicGet(&v));
    49 
    50     SDL_AtomicSet(&v, 0);
    51     SDL_AtomicIncRef(&v);
    52     tfret = (SDL_AtomicGet(&v) == 1);
    53     printf("AtomicIncRef()       tfret=%s val=%"PRIu32"\n", tf(tfret), SDL_AtomicGet(&v));
    54     SDL_AtomicIncRef(&v);
    55     tfret = (SDL_AtomicGet(&v) == 2);
    56     printf("AtomicIncRef()       tfret=%s val=%"PRIu32"\n", tf(tfret), SDL_AtomicGet(&v));
    57     tfret = (SDL_AtomicDecRef(&v) == SDL_FALSE);
    58     printf("AtomicDecRef()       tfret=%s val=%"PRIu32"\n", tf(tfret), SDL_AtomicGet(&v));
    59     tfret = (SDL_AtomicDecRef(&v) == SDL_TRUE);
    60     printf("AtomicDecRef()       tfret=%s val=%"PRIu32"\n", tf(tfret), SDL_AtomicGet(&v));
    61 
    62     SDL_AtomicSet(&v, 10);
    63     tfret = (SDL_AtomicCAS(&v, 0, 20) == SDL_FALSE);
    64     printf("AtomicCAS()          tfret=%s val=%"PRIu32"\n", tf(tfret), SDL_AtomicGet(&v));
    65     value = SDL_AtomicGet(&v);
    66     tfret = (SDL_AtomicCAS(&v, value, 20) == SDL_TRUE);
    67     printf("AtomicCAS()          tfret=%s val=%"PRIu32"\n", tf(tfret), SDL_AtomicGet(&v));
    68 }
    69 
    70 /* Atomic operation test, adapted from code by Michael Davidsaver at:
    71     http://bazaar.launchpad.net/~mdavidsaver/epics-base/atomic/revision/12105#src/libCom/test/epicsAtomicTest.c
    72 */
    73 
    74 /* Tests semantics of atomic operations.  Also a stress test
    75  * to see if they are really atomic.
    76  *
    77  * Serveral threads adding to the same variable.
    78  * at the end the value is compared with the expected
    79  * and with a non-atomic counter.
    80  */
    81  
    82 /* Number of concurrent incrementers */
    83 #define NThreads 2
    84 #define CountInc 100
    85 #define VALBITS (sizeof(atomicValue)*8)
    86  
    87 #define atomicValue int
    88 #define CountTo ((atomicValue)((unsigned int)(1<<(VALBITS-1))-1))
    89 #define NInter (CountTo/CountInc/NThreads)
    90 #define Expect (CountTo-NInter*CountInc*NThreads)
    91  
    92 SDL_COMPILE_TIME_ASSERT(size, CountTo>0); /* check for rollover */
    93  
    94 static SDL_atomic_t good = { 42 };
    95  
    96 static atomicValue bad = 42;
    97  
    98 static SDL_atomic_t threadsRunning;
    99 
   100 static SDL_sem *threadDone;
   101  
   102 static
   103 int adder(void* junk)
   104 {
   105     unsigned long N=NInter;
   106     printf("Thread subtracting %d %lu times\n",CountInc,N);
   107     while (N--) {
   108         SDL_AtomicAdd(&good, -CountInc);
   109         bad-=CountInc;
   110     }
   111     SDL_AtomicAdd(&threadsRunning, -1);
   112     SDL_SemPost(threadDone);
   113     return 0;
   114 }
   115  
   116 static
   117 void runAdder(void)
   118 {
   119     Uint32 start, end;
   120     int T=NThreads;
   121  
   122     start = SDL_GetTicks();
   123  
   124     threadDone = SDL_CreateSemaphore(0);
   125 
   126     SDL_AtomicSet(&threadsRunning, NThreads);
   127 
   128     while (T--)
   129         SDL_CreateThread(adder, NULL);
   130  
   131     while (SDL_AtomicGet(&threadsRunning) > 0)
   132         SDL_SemWait(threadDone);
   133  
   134     SDL_DestroySemaphore(threadDone);
   135 
   136     end = SDL_GetTicks();
   137  
   138     printf("Finished in %f sec\n", (end - start) / 1000.f);
   139 }
   140  
   141 static
   142 void RunEpicTest()
   143 {
   144     int b;
   145     atomicValue v;
   146  
   147     printf("\nepic test---------------------------------------\n\n");
   148 
   149     printf("Size asserted to be >= 32-bit\n");
   150     SDL_assert(sizeof(atomicValue)>=4);
   151  
   152     printf("Check static initializer\n");
   153     v=SDL_AtomicGet(&good);
   154     SDL_assert(v==42);
   155  
   156     SDL_assert(bad==42);
   157  
   158     printf("Test negative values\n");
   159     SDL_AtomicSet(&good, -5);
   160     v=SDL_AtomicGet(&good);
   161     SDL_assert(v==-5);
   162  
   163     printf("Verify maximum value\n");
   164     SDL_AtomicSet(&good, CountTo);
   165     v=SDL_AtomicGet(&good);
   166     SDL_assert(v==CountTo);
   167  
   168     printf("Test compare and exchange\n");
   169  
   170     b=SDL_AtomicCAS(&good, 500, 43);
   171     SDL_assert(!b); /* no swap since CountTo!=500 */
   172     v=SDL_AtomicGet(&good);
   173     SDL_assert(v==CountTo); /* ensure no swap */
   174  
   175     b=SDL_AtomicCAS(&good, CountTo, 44);
   176     SDL_assert(!!b); /* will swap */
   177     v=SDL_AtomicGet(&good);
   178     SDL_assert(v==44);
   179  
   180     printf("Test Add\n");
   181  
   182     v=SDL_AtomicAdd(&good, 1);
   183     SDL_assert(v==44);
   184     v=SDL_AtomicGet(&good);
   185     SDL_assert(v==45);
   186  
   187     v=SDL_AtomicAdd(&good, 10);
   188     SDL_assert(v==45);
   189     v=SDL_AtomicGet(&good);
   190     SDL_assert(v==55);
   191  
   192     printf("Test Add (Negative values)\n");
   193  
   194     v=SDL_AtomicAdd(&good, -20);
   195     SDL_assert(v==55);
   196     v=SDL_AtomicGet(&good);
   197     SDL_assert(v==35);
   198  
   199     v=SDL_AtomicAdd(&good, -50); /* crossing zero down */
   200     SDL_assert(v==35);
   201     v=SDL_AtomicGet(&good);
   202     SDL_assert(v==-15);
   203  
   204     v=SDL_AtomicAdd(&good, 30); /* crossing zero up */
   205     SDL_assert(v==-15);
   206     v=SDL_AtomicGet(&good);
   207     SDL_assert(v==15);
   208  
   209     printf("Reset before count down test\n");
   210     SDL_AtomicSet(&good, CountTo);
   211     v=SDL_AtomicGet(&good);
   212     SDL_assert(v==CountTo);
   213  
   214     bad=CountTo;
   215     SDL_assert(bad==CountTo);
   216  
   217     printf("Counting down from %d, Expect %d remaining\n",CountTo,Expect);
   218     runAdder();
   219  
   220     v=SDL_AtomicGet(&good);
   221     printf("Atomic %d Non-Atomic %d\n",v,bad);
   222     SDL_assert(v==Expect);
   223     SDL_assert(bad!=Expect);
   224 }
   225 
   226 int
   227 main(int argc, char *argv[])
   228 {
   229     RunBasicTest();
   230     RunEpicTest();
   231     return 0;
   232 }