remove double export of xseg symbols
[archipelago] / xseg / xtypes / xq_test.c
1 #define _GNU_SOURCE
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <math.h>
5 #include <pthread.h>
6 #include <sys/time.h>
7 #include <assert.h>
8
9 #include "xq.h"
10
11 struct item {
12     long   seed;
13     double seed_sin;
14     long   seed_times_sin;
15     long   seed_xor_times;
16 };
17
18 void item_calculate(struct item *item) {
19     item->seed_sin = sin(item->seed | 1);
20     item->seed_times_sin = (double)(item->seed | 1) * item->seed_sin;
21     item->seed_xor_times = item->seed ^ item->seed_times_sin;
22 }
23
24 int item_verify(struct item *item) {
25     struct item t;
26
27     t.seed = item->seed;
28     item_calculate(&t);
29
30     /*
31     printf("seed %ld, sin: %lf, times: %ld, xor: %ld\n",
32            item->seed, item->seed_sin, item->seed_times_sin, item->seed_xor_times);
33     */
34
35     if (t.seed_sin       != item->seed_sin       ||
36         t.seed_times_sin != item->seed_times_sin ||
37         t.seed_xor_times != item->seed_xor_times) {
38         printf("seed %ld, sin: %lf, times: %ld, xor: %ld\n",
39                item->seed, item->seed_sin, item->seed_times_sin, item->seed_xor_times);
40         return 0;
41     }
42
43     return 1;
44 }
45
46 int basic_sanity_test(struct xq *q) {
47     xqindex t, r;
48
49     //printf("append_tail 9183\n");
50     r = xq_append_tail(q, 9183, 0);
51     //xq_print(q);
52     //printf("\n");
53     assert(r != Noneidx);
54
55     //printf("pop_head 9183\n");
56     r = xq_pop_head(q, 0);
57     //xq_print(q);
58     //printf("\n");
59     assert(r == 9183);
60
61     //printf("append_head 1834\n");
62     r = xq_append_head(q, 1834, 0);
63     //xq_print(q);
64     //printf("\n");
65     assert(r != Noneidx);
66
67     //printf("pop_tail 1834\n");
68     r = xq_pop_tail(q, 0);
69     //xq_print(q);
70     //printf("\n");
71     assert(r == 1834);
72
73     //printf("append_tail 3814\n");
74     xq_append_tail(q, 3814, 0);
75     //xq_print(q);
76     //printf("\n");
77
78     //printf("append_head 5294\n");
79     xq_append_head(q, 5294, 0);
80     //xq_print(q);
81     //printf("\n");
82
83     //printf("append_tail 1983\n");
84     r = xq_append_tail(q, 1983, 0);
85     //xq_print(q);
86     //printf("\n");
87     assert(r != Noneidx);
88
89     //printf("pop_tail 1983\n");
90     r = xq_pop_tail(q, 0);
91     //xq_print(q);
92     //printf("\n");
93     assert(r == 1983);
94
95     //printf("append_head 8134\n");
96     r = xq_append_head(q, 8134, 0);
97     //xq_print(q);
98     //printf("\n");
99     assert(r != Noneidx);
100
101     //printf("pop_head 8134\n");
102     r = xq_pop_head(q, 0);
103     //xq_print(q);
104     //printf("\n");
105     assert(r == 8134);
106
107     //printf("pop_tail 3814\n");
108     r = xq_pop_tail(q, 0);
109     //xq_print(q);
110     //printf("\n");
111     assert(r == 3814);
112
113     //printf("pop_head 5294\n");
114     r = xq_pop_head(q, 0);
115     //xq_print(q);
116     //printf("\n");
117     assert(r == 5294);
118
119     //printf("pop_tail Noneidx\n");
120     r = xq_pop_tail(q, 0);
121     //xq_print(q);
122     //printf("\n");
123     assert(r == Noneidx);
124
125     //printf("pop_head Noneidx\n");
126     r = xq_pop_head(q, 0);
127     //xq_print(q);
128     //printf("\n");
129     assert(r == Noneidx);
130
131     xqindex qsize = q->size;
132     for (t = 0; t < qsize; t += 1) {
133          r = xq_append_tail(q, t, 0);
134          //if (r == Noneidx) printf("Noneidx: %lu\n", (unsigned long)t);
135          //xq_print(q);
136          assert(r != Noneidx);
137     }
138
139     //xq_print(q);
140
141     for (t = qsize-1; t != Noneidx; t -= 1) {
142          r = xq_pop_tail(q, 0);
143          assert(t == r);
144          //printf("%lu vs %lu\n", t, (unsigned long)xq_pop_tail(q));
145     }
146
147     return 0;
148 }
149
150 struct thread_data {
151     long loops;
152     struct xq *q;
153     struct item *items;
154     struct random_data *rdata;
155     long size;
156     int id;
157 };
158
159 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
160
161 void *random_test_thread(void *arg) {
162     struct thread_data *th = arg;
163     long loops = th->loops;
164     struct xq *q = th->q;
165     struct item *items = th->items;
166     //struct random_data *rdata = th->rdata;
167     int id = th->id;
168     long i;
169
170
171     /*
172     pthread_mutex_lock(&mutex);
173     printf("---->\n");
174     xq_print(&q[0]);
175     xq_print(&q[1]);
176     printf("<----\n");
177     pthread_mutex_unlock(&mutex);
178     */
179
180     for (i = 0; i < loops; i++) {
181          int32_t rand;
182          xqindex xqi;
183
184          if ((i & (1024*1024 -1)) == 0) {
185              printf("%d %ld\n", id, i);
186          }
187
188          //random_r(rdata, &rand);
189          rand = random();
190
191          switch (rand & 3) {
192          case 0:
193              xqi = xq_pop_tail(&q[0], arg);
194              if (xqi == Noneidx) goto unlock;
195              items[xqi].seed = rand;
196              item_calculate(&items[xqi]);
197              xq_append_head(&q[1], xqi, arg);
198              break;
199          case 1:
200              xqi = xq_pop_head(&q[0], arg);
201              if (xqi == Noneidx) goto unlock;
202              items[xqi].seed = rand;
203              item_calculate(&items[xqi]);
204              xq_append_tail(&q[1], xqi, arg);
205              break;
206          case 2:
207              xqi = xq_pop_tail(&q[1], arg);
208              if (xqi == Noneidx) goto unlock;
209              items[xqi].seed = rand;
210              item_calculate(&items[xqi]);
211              xq_append_head(&q[0], xqi, arg);
212              break;
213          case 3:
214              xqi = xq_pop_head(&q[1], arg);
215              if (xqi == Noneidx) goto unlock;
216              items[xqi].seed = rand;
217              item_calculate(&items[xqi]);
218              xq_append_tail(&q[0], xqi, arg);
219              break;
220          }
221     unlock:
222          ;
223     }
224
225     return NULL;
226 }
227
228 int error(const char *msg) {
229     perror(msg);
230     return 1;
231 }
232
233 int random_test(long seed, long nr_threads, long loops, xqindex qsize, struct xq *q) {
234     srandom(seed);
235
236     struct thread_data *th = malloc(nr_threads * sizeof(struct thread_data));
237     if (!th) return error("malloc");
238
239     long t, r;
240
241     struct item *items = malloc(qsize * sizeof(struct item));
242     if (!items) return error("malloc");
243
244     for (t = 0; t < qsize; t += 1) item_calculate(&items[t]);
245
246     for (t = 0; t < qsize; t += 4) {
247          xq_append_tail(&q[0], t+0, 0);
248          xq_append_head(&q[0], t+1, 0);
249          xq_append_tail(&q[1], t+2, 0);
250          xq_append_head(&q[1], t+3, 0);
251     }
252
253     pthread_t *threads = malloc(nr_threads * sizeof(pthread_t));
254     if (!threads) return error("malloc");
255
256     //struct random_data *rdata = malloc(nr_threads * sizeof(struct random_data));
257     //if (!rdata) return error("malloc");
258
259     for (t = 0; t < nr_threads; t++) {
260          th[t].id = t;
261          th[t].loops = loops;
262          th[t].size = qsize;
263          th[t].q = q;
264          //th[t].rdata = &rdata[t];
265          th[t].items = items;
266          //srandom_r(random(), th[t].rdata);
267     }
268
269     for (t = 0; t < nr_threads; t++) {
270          r = pthread_create(&threads[t], NULL, random_test_thread, &th[t]);
271          if (r) return error("pthread_create");
272     }
273
274     for (t = 0; t < nr_threads; t++) {
275          pthread_join(threads[t], NULL);
276     }
277
278     int errors = 0;
279     for (t = 0; t < qsize; t++) {
280          if (!item_verify(&items[t])) {
281              errors ++;
282              printf("error: item %ld\n", t);
283          };
284     }
285
286     return errors;
287 }
288
289 struct xq q[2];
290
291 int main(int argc, char **argv) {
292     int r;
293
294     if (argc < 5) {
295         printf("Usage: struct xqest <seed> <nr_threads> <nr_loops> <qsize>\n");
296         return 1;
297     }
298
299     long seed = atol(argv[1]);
300     int nr_threads = atoi(argv[2]);
301     long loops = atol(argv[3]);
302     long qsize = atol(argv[4]);
303
304     if (nr_threads < 0) nr_threads = 2;
305     if (loops < 0) loops = 1000;
306     if (qsize < 0) qsize = 1000;
307
308     xq_alloc_empty(&q[0], qsize);
309     xq_alloc_empty(&q[1], qsize);
310     qsize = q[0].size;
311     assert(q[1].size == qsize);
312
313     r = basic_sanity_test(&q[0]);
314     if (r) return r;
315     printf("basic sanity test complete.\n");
316
317     struct timeval tv0, tv1;
318     gettimeofday(&tv0, NULL);
319     r = random_test(seed, nr_threads, loops, qsize, q);
320     gettimeofday(&tv1, NULL);
321     double seconds = tv1.tv_sec + tv1.tv_usec/1000000.0 - tv0.tv_sec - tv0.tv_usec / 1000000.0;
322     printf("random multi-thread test complete with %d errors in %lf seconds\n", r, seconds);
323     if (r) return r;
324
325     return 0;
326 }