msgQ test: Now also reports performance of STL-based variant of msg Q
[charm.git] / tests / charm++ / queue / pgm.C
1 #include <iostream>
2 #include <cstdlib>
3 #include <cstdio>
4 #include <vector>
5
6 using std::cerr;
7 using std::endl;
8 using std::sprintf;
9
10 #include "queueing.h"
11 #include "msgq.h"
12 #include "main.decl.h"
13
14 #define CmiFree free
15
16 #define RUN_TEST(f) do { \
17   ++tests; \
18   if (f()) { \
19     ++success; \
20   } else { \
21     ++fail; \
22     cerr << "Test \"" #f "\" failed" << endl; \
23   } \
24 } while (0)
25
26 // A newly created Queue should be empty, which corresponds to a
27 // length of 0
28 bool test_empty()
29 {
30   Queue q = CqsCreate();
31   bool result = (0 == CqsLength(q)) && (1 == CqsEmpty(q));
32   CqsDelete(q);
33   return result;
34 }
35
36 // Enqueueing an element should show that there is an element
37 // present. We should get the same thing back when we dequeue
38 //
39 // The queue is not allowed to dereference the void* we give it
40 bool test_one()
41 {
42   Queue q = CqsCreate();
43   void *p = 0;
44   CqsEnqueue(q, p);
45   bool result = (1 == CqsLength(q)) && (0 == CqsEmpty(q));
46   void *r;
47   CqsDequeue(q, &r);
48   result &= (r == p) 
49     && (0 == CqsLength(q)) 
50     && (1 == CqsEmpty(q));
51   CqsDelete(q);
52   return result;
53 }
54
55 // Put two in, see if we get the same two back. Order unspecified
56 bool test_two()
57 {
58   Queue q = CqsCreate();
59   void *i = 0, *j = (char *)1;
60   void *r, *s;
61   CqsEnqueue(q, i);
62   CqsEnqueue(q, j);
63   bool result = (2 == CqsLength(q));
64   CqsDequeue(q, &r);
65   CqsDequeue(q, &s);
66   result &= (r == i && s == j) || (r == j && s == i);
67   result &= 1 == CqsEmpty(q);
68   CqsDelete(q);
69   return result;
70 }
71
72 bool test_fifo()
73 {
74   Queue q = CqsCreate();
75   void *i = (char *)1, *j = (char *)2, *k = (char *)3;
76   void *r, *s, *t;
77   CqsEnqueueFifo(q, i);
78   CqsEnqueueFifo(q, j);
79   CqsEnqueueFifo(q, k);
80   CqsDequeue(q, &r);
81   CqsDequeue(q, &s);
82   CqsDequeue(q, &t);
83   bool result = (r == i) && (s == j) && (t == k);
84   CqsDelete(q);
85   return result;
86 }
87
88 bool test_lifo()
89 {
90   Queue q = CqsCreate();
91   void *i = (char *)1, *j = (char *)2, *k = (char *)3;
92   void *r, *s, *t;
93   CqsEnqueueLifo(q, i);
94   CqsEnqueueLifo(q, j);
95   CqsEnqueueLifo(q, k);
96   CqsDequeue(q, &r);
97   CqsDequeue(q, &s);
98   CqsDequeue(q, &t);
99   bool result = (r == k) && (s == j) && (t == i);
100   CqsDelete(q);
101   return result;
102 }
103
104 bool test_enqueue_mixed()
105 {
106   Queue q = CqsCreate();
107   void *i = (char *)1, *j = (char *)2, *k = (char *)3;
108   void *r, *s, *t;
109   CqsEnqueueFifo(q, i);
110   CqsEnqueueFifo(q, j);
111   CqsEnqueueLifo(q, k);
112   CqsDequeue(q, &r);
113   CqsDequeue(q, &s);
114   CqsDequeue(q, &t);
115   bool result = (r == k) && (s == i) && (t == j);
116   CqsDelete(q);
117   return result;
118 }
119
120 static bool findEntry(void ** const e, int num, void * const t)
121 {
122     for (int i = 0; i < num; ++i)
123     {
124         if (e[i] == t)
125             return true;
126     }
127     return false;
128 }
129
130 bool test_enumerate()
131 {
132   Queue q = CqsCreate();
133   void *i = (char *)1, *j = (char *)2, *k = (char *)3;
134   void **e;
135   CqsEnqueueFifo(q, i);
136   CqsEnqueueFifo(q, j);
137   CqsEnqueueLifo(q, k);
138   CqsEnumerateQueue(q, &e);
139   int n = CqsLength(q);
140   bool result = findEntry(e, n, i) && findEntry(e, n, j) && findEntry(e, n, k);
141   CmiFree(e);
142   CqsDelete(q);
143   return result;
144 }
145
146 bool test_general_fifo()
147 {
148   Queue q = CqsCreate();
149   void *i = (char *)1, *j = (char *)2, *k = (char *)3;
150   CqsEnqueueGeneral(q, i, CQS_QUEUEING_FIFO, 1, 0);
151   CqsEnqueueGeneral(q, j, CQS_QUEUEING_FIFO, 2, 0);
152   CqsEnqueueGeneral(q, k, CQS_QUEUEING_FIFO, 42, 0);
153   void *r, *s, *t;
154   CqsDequeue(q, &r);
155   CqsDequeue(q, &s);
156   CqsDequeue(q, &t);
157   bool result = (r == i) && (s == j) && (t == k);
158   CqsDelete(q);
159   return result;
160 }
161
162 bool test_general_ififo()
163 {
164   Queue q = CqsCreate();
165   void *i = (char *)1, *j = (char *)2, *k = (char *)3;
166   unsigned int a = -1, b = 0, c = 1;
167   CqsEnqueueGeneral(q, i, CQS_QUEUEING_IFIFO, 8*sizeof(int), &c);
168   CqsEnqueueGeneral(q, j, CQS_QUEUEING_IFIFO, 8*sizeof(int), &b);
169   CqsEnqueueGeneral(q, k, CQS_QUEUEING_IFIFO, 8*sizeof(int), &a);
170   void *r, *s, *t;
171   CqsDequeue(q, &r);
172   CqsDequeue(q, &s);
173   CqsDequeue(q, &t);
174   bool result = (r == k) && (s == j) && (t == i);
175   CqsDelete(q);
176   return result;
177 }
178
179 double timePerOp_general_ififo(int qBaseSize = 256)
180 {
181   Queue q = CqsCreate();
182   int qBatchSize = 1<<4;
183   int numIters   = 1<<16;
184
185   std::vector<char> msgs(qBaseSize + qBatchSize);
186   std::vector<unsigned int> prios(qBaseSize + qBatchSize);
187
188   for (int i = 0; i < qBaseSize + qBatchSize; i++)
189       prios[i] = std::rand();
190
191   for (int i = 0; i < qBaseSize; i++)
192       CqsEnqueueGeneral(q, (void*)&msgs[i], CQS_QUEUEING_IFIFO, 8*sizeof(int), &prios[i]);
193
194   double startTime = CmiWallTimer();
195   for (int i = 0; i < numIters; i++)
196   {
197       for (int j = qBaseSize; j < qBaseSize+qBatchSize; j++)
198         CqsEnqueueGeneral(q, (void*)&msgs[j], CQS_QUEUEING_IFIFO, 8*sizeof(int), &prios[j]);
199       void *m;
200       for (int j = qBaseSize; j < qBaseSize+qBatchSize; j++)
201         CqsDequeue(q, &m);
202   }
203
204   CqsDelete(q);
205   return 1000000 * (CmiWallTimer() - startTime) / (numIters * qBatchSize * 2);
206 }
207
208
209 double timePerOp_stlQ(int qBaseSize = 256)
210 {
211   msgQ<int> q;
212   int qBatchSize = 1<<4;
213   int numIters   = 1<<16;
214
215   std::vector<char> msgs(qBaseSize + qBatchSize);
216   std::vector<unsigned int> prios(qBaseSize + qBatchSize);
217
218   for (int i = 0; i < qBaseSize + qBatchSize; i++)
219       prios[i] = std::rand();
220
221   for (int i = 0; i < qBaseSize; i++)
222       q.enq((msg_t*)&msgs[i], prios[i]);
223
224   double startTime = CmiWallTimer();
225   for (int i = 0; i < numIters; i++)
226   {
227       for (int j = qBaseSize; j < qBaseSize+qBatchSize; j++)
228           q.enq((msg_t*)&msgs[j], prios[j]);
229       void *m;
230       for (int j = qBaseSize; j < qBaseSize+qBatchSize; j++)
231         q.deq();
232   }
233
234   return 1000000 * (CmiWallTimer() - startTime) / (numIters * qBatchSize * 2);
235 }
236
237
238 bool perftest_general_ififo()
239 {
240   CkPrintf("Reporting time per enqueue / dequeue operation for charm's underlying mixed priority queue\n");
241   CkPrintf("\n  Q length     time/op(us)\n");
242   for (int i = 16; i <= 2048; i *= 2)
243     CkPrintf("%10d %15f\n", i, timePerOp_general_ififo(i));
244
245   printf("Reporting time per enqueue / dequeue operation for an STL version of the same Q functionality\n");
246   printf("\n  Q length     time/op(us)\n");
247   for (int i = 16; i <= 2048; i *= 2)
248     printf("%10d %15f\n", i, timePerOp_stlQ(i));
249
250   return true;
251 }
252
253
254 #if 0
255 // Template for new harness-driven tests
256 bool test_foo()
257 {
258   Queue q = CqsCreate();
259   
260   bool result = ;
261   CqsDelete(q);
262   return result;
263 }
264 #endif
265
266 struct main : public CBase_main
267 {
268   main(CkArgMsg *)
269   {
270     int tests = 0, success = 0, fail = 0;
271     char message[100];
272
273     RUN_TEST(test_empty);
274     RUN_TEST(test_one);
275     RUN_TEST(test_two);
276     RUN_TEST(test_fifo);
277     RUN_TEST(test_lifo);
278     RUN_TEST(test_enqueue_mixed);
279     RUN_TEST(test_enumerate);
280     RUN_TEST(test_general_fifo);
281     RUN_TEST(test_general_ififo);
282     RUN_TEST(perftest_general_ififo);
283
284     if (fail) {
285       sprintf(message, "%d/%d tests failed\n", fail, tests);
286       CkAbort(message);
287     }
288     else {
289       CkPrintf("All %d tests passed\n", tests);
290       CkExit();
291     }
292   }
293
294 };
295
296 #include "main.def.h"