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