a5558632c4e21b60fc77d15726815f5dc08ea178
[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   std::vector<double> timings;
187   timings.reserve(256);
188   // Charm applications typically have a small/moderate number of different message priorities
189   for (int hl = 16; hl <= 128; hl *=2)
190   {
191     std::srand(42);
192     for (int i = 0; i < qSizeMax + numMsgs; i++)
193       prios[i] = std::rand() % hl;
194
195     for (int i = qSizeMin; i <= qSizeMax; i *= 2)
196       timings.push_back( timePerOp_stlQ(i) );
197   }
198
199   #if CMK_HAS_STD_UNORDERED_MAP
200   CkPrintf("The STL variant of the msg q is using a std::unordered_map\n");
201   #else
202   CkPrintf("The STL variant of the msg q is using a std::map\n");
203   #endif
204
205   CkPrintf("Reporting time per enqueue / dequeue operation (us) for an STL-based msg Q\n"
206            "Nprios (row) is the number of different priority values that are used.\n"
207            "Qlen (col) is the base length of the queue on which the enq/deq operations are timed\n"
208           );
209
210   CkPrintf("\nversion  Nprios");
211   for (int i = qSizeMin; i <= qSizeMax; i*=2)
212     CkPrintf("%10d", i);
213
214   for (int hl = 16, j=0; hl <= 128; hl *=2)
215   {
216     CkPrintf("\n    stl %7d", hl);
217     for (int i = qSizeMin; i <= qSizeMax; i *= 2, j++)
218       CkPrintf("%10.4f", timings[j]);
219   }
220
221   CkPrintf("\n");
222   return true;
223 }
224
225
226 #if 0
227 // Template for new harness-driven tests
228 bool test_foo()
229 {
230   msgQ<int> q;
231
232   bool result = ;
233   return result;
234 }
235 #endif
236
237
238 struct main : public CBase_main
239 {
240  main(CkArgMsg *)
241  {
242   int tests = 0, success = 0, fail = 0;
243   char message[100];
244
245   RUN_TEST(test_empty);
246   RUN_TEST(test_one);
247   RUN_TEST(test_two);
248   RUN_TEST(test_fifo);
249   RUN_TEST(test_lifo);
250   RUN_TEST(test_enqueue_mixed);
251   RUN_TEST(test_enumerate);
252   RUN_TEST(test_stl_ififo);
253   RUN_TEST(perftest_general_ififo);
254   if (fail) {
255     sprintf(message, "%d/%d tests failed\n", fail, tests);
256     CkAbort(message);
257   }
258   else {
259     CkPrintf("All %d stl msgQ tests passed\n", tests);
260     CkExit();
261   }
262  }
263 };
264
265 #include "main.def.h"
266