1// TEST_CONFIG
2
3#include "test.h"
4
5#include <stdlib.h>
6#include <pthread.h>
7#include <objc/runtime.h>
8#include <objc/objc-sync.h>
9#include <Foundation/NSObject.h>
10
11// synchronized stress test
12// 2-D grid of counters and locks. 
13// Each thread increments all counters some number of times.
14// To increment:
15// * thread picks a target [row][col]
16// * thread locks all locks [row][0] to [row][col], possibly recursively
17// * thread increments counter [row][col]
18// * thread unlocks all of the locks
19
20#if defined(__arm__)
21// 16 / 4 / 3 / 1024*8 test takes about 30s on 2nd gen iPod touch
22#define THREADS 16
23#define ROWS 4
24#define COLS 3
25#define COUNT 1024*8
26#else
27// 64 / 4 / 3 / 1024*8 test takes about 20s on 4x2.6GHz Mac Pro
28#define THREADS 64
29#define ROWS 4
30#define COLS 3
31#define COUNT 1024*8
32#endif
33
34static id locks[ROWS][COLS];
35static int counts[ROWS][COLS];
36
37
38static void *threadfn(void *arg)
39{
40    int n, d;
41    int depth = 1 + (int)(intptr_t)arg % 4;
42
43    objc_registerThreadWithCollector();
44
45    for (n = 0; n < COUNT; n++) {
46        int rrr = rand() % ROWS;
47        int ccc = rand() % COLS;
48        int rr, cc;
49        for (rr = 0; rr < ROWS; rr++) {
50            int r = (rrr+rr) % ROWS;
51            for (cc = 0; cc < COLS; cc++) {
52                int c = (ccc+cc) % COLS;
53                int l;
54
55                // Lock [r][0..c]
56                // ... in that order to prevent deadlock
57                for (l = 0; l <= c; l++) {
58                    for (d = 0; d < depth; d++) {
59                        int err = objc_sync_enter(locks[r][l]);
60                        testassert(err == OBJC_SYNC_SUCCESS);
61                    }
62                }
63                
64                // Increment count [r][c]
65                counts[r][c]++;
66                
67                // Unlock [r][0..c]
68                // ... in that order to increase contention
69                for (l = 0; l <= c; l++) {
70                    for (d = 0; d < depth; d++) {
71                        int err = objc_sync_exit(locks[r][l]);
72                        testassert(err == OBJC_SYNC_SUCCESS);
73                    }
74                }
75            }
76        }
77    }
78    
79    return NULL;
80}
81
82int main()
83{
84    pthread_t threads[THREADS];
85    int r, c, t;
86
87    for (r = 0; r < ROWS; r++) {
88        for (c = 0; c < COLS; c++) {
89            locks[r][c] = [[NSObject alloc] init];
90        }
91    }
92
93    // Start the threads
94    for (t = 0; t < THREADS; t++) {
95        pthread_create(&threads[t], NULL, &threadfn, (void*)(intptr_t)t);
96    }
97
98    // Wait for threads to finish
99    for (t = 0; t < THREADS; t++) {
100        pthread_join(threads[t], NULL);
101    }
102    
103    // Verify locks: all should be available
104    // Verify counts: all should be THREADS*COUNT
105    for (r = 0; r < ROWS; r++) {
106        for (c = 0; c < COLS; c++) {
107            int err = objc_sync_enter(locks[r][c]);
108            testassert(err == OBJC_SYNC_SUCCESS);
109            testassert(counts[r][c] == THREADS*COUNT);
110        }
111    }
112
113    succeed(__FILE__);
114}
115