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