msgQ test: separate the unit tests for the STL variant from charm's default q tests
authorRamprasad Venkataraman <ramv@illinois.edu>
Sat, 23 Jun 2012 07:15:59 +0000 (02:15 -0500)
committerRamprasad Venkataraman <ramv@illinois.edu>
Thu, 28 Jun 2012 16:01:35 +0000 (11:01 -0500)
tests/charm++/queue/Makefile
tests/charm++/queue/msgqtest.C [new file with mode: 0644]
tests/charm++/queue/pgm.C

index e462eef79dd876ba79af3ddb808095e83ed0dabe..af074f52bad9c7f95807a3416e841b0f7aed4038 100644 (file)
@@ -1,14 +1,18 @@
 CHARMC := ../../../bin/charmc
 CXX := $(CHARMC) $(OPTS)
 
-all: pgm
-test: pgm
+TARGETS = pgm msgqtest
+all: $(TARGETS)
+test: $(TARGETS)
        ./charmrun ./pgm $(TESTOPTS)
+       ./charmrun ./msgqtest $(TESTOPTS)
 
 pgm.C: main.decl.h
 
+msgqtest.C: main.decl.h
+
 main.decl.h: test.ci
        $(CHARMC) $<
 
 clean:
-       rm -f pgm *.o *.decl.h *.def.h charmrun pgm.exe pgm.pdb pgm.ilk
+       rm -f $(TARGETS) *.o *.decl.h *.def.h charmrun pgm.exe pgm.pdb pgm.ilk
diff --git a/tests/charm++/queue/msgqtest.C b/tests/charm++/queue/msgqtest.C
new file mode 100644 (file)
index 0000000..bb3e974
--- /dev/null
@@ -0,0 +1,258 @@
+#include <cstdio>
+#include <cstdlib>
+#include <vector>
+
+using std::sprintf;
+
+#include "main.decl.h"
+#include "msgq.h"
+
+#define RUN_TEST(f) do { \
+  ++tests; \
+  if (f()) { \
+    ++success; \
+  } else { \
+    ++fail; \
+    CkPrintf("Test \"" #f "\" failed\n"); \
+  } \
+} while (0)
+
+// A newly created msgQ should be empty, which corresponds to a
+// length of 0
+bool test_empty()
+{
+  msgQ<int> q;
+  bool result = (0 == q.size()) && (q.empty());
+  return result;
+}
+
+// Enqueueing an element should show that there is an element
+// present. We should get the same thing back when we dequeue
+//
+// The queue is not allowed to dereference the void* we give it
+bool test_one()
+{
+  msgQ<int> q;
+  void *p = 0;
+  q.enq(p);
+  bool result = (1 == q.size()) && (!q.empty());
+  void *r;
+  r = (void*)q.deq();
+  result &= (r == p)
+    && (0 == q.size())
+    && (q.empty());
+  return result;
+}
+
+// Put two in, see if we get the same two back. Order unspecified
+bool test_two()
+{
+  msgQ<int> q;
+  void *i = 0, *j = (char *)1;
+  void *r, *s;
+  q.enq(i);
+  q.enq(j);
+  bool result = (2 == q.size());
+  r = (void*)q.deq();
+  s = (void*)q.deq();
+  result &= (r == i && s == j) || (r == j && s == i);
+  result &= 1 == q.empty();
+  return result;
+}
+
+bool test_fifo()
+{
+  msgQ<int> q;
+  void *i = (char *)1, *j = (char *)2, *k = (char *)3;
+  void *r, *s, *t;
+  q.enq(i);
+  q.enq(j);
+  q.enq(k);
+  r = (void*)q.deq();
+  s = (void*)q.deq();
+  t = (void*)q.deq();
+  bool result = (r == i) && (s == j) && (t == k);
+  return result;
+}
+
+bool test_lifo()
+{
+  msgQ<int> q;
+  void *i = (char *)1, *j = (char *)2, *k = (char *)3;
+  void *r, *s, *t;
+  q.enq(i, 0, false);
+  q.enq(j, 0, false);
+  q.enq(k, 0, false);
+  r = (void*)q.deq();
+  s = (void*)q.deq();
+  t = (void*)q.deq();
+  bool result = (r == k) && (s == j) && (t == i);
+  return result;
+}
+
+bool test_enqueue_mixed()
+{
+  msgQ<int> q;
+  void *i = (char *)1, *j = (char *)2, *k = (char *)3;
+  void *r, *s, *t;
+  q.enq(i);
+  q.enq(j);
+  q.enq(k, 0, false);
+  r = (void*)q.deq();
+  s = (void*)q.deq();
+  t = (void*)q.deq();
+  bool result = (r == k) && (s == i) && (t == j);
+  return result;
+}
+
+static bool findEntry(void ** const e, int num, void * const t)
+{
+    for (int i = 0; i < num; ++i)
+    {
+       if (e[i] == t)
+           return true;
+    }
+    return false;
+}
+
+bool test_enumerate()
+{
+  msgQ<int> q;
+  void *i = (char *)1, *j = (char *)2, *k = (char *)3;
+  q.enq(i);
+  q.enq(j);
+  q.enq(k, 0, false);
+  void **e = new void*[q.size()];
+  q.enumerate(e, e + q.size());
+  int n = q.size();
+  bool result = findEntry(e, n, i) && findEntry(e, n, j) && findEntry(e, n, k);
+  return result;
+}
+
+bool test_stl_ififo()
+{
+  msgQ<int> q;
+  void *i = (char *)1, *j = (char *)2, *k = (char *)3, *l = (char*)4;
+  unsigned int a = -1, b = 0, c = 1, d = -1;
+  q.enq(i, d, true);
+  q.enq(j, c);
+  q.enq(k, b);
+  q.enq(l, a);
+  void *r, *s, *t, *u;
+  r = (void*)q.deq();
+  s = (void*)q.deq();
+  t = (void*)q.deq();
+  u = (void*)q.deq();
+  bool result = (r == i) && (s == l) && (t == k) && (u == j);
+  return result;
+}
+
+const int qSizeMin   = 1<<4;
+const int qSizeMax   = 1<<12;
+const int qBatchSize = 1<<4;
+const int numIters   = 1<<16;
+const int numMsgs    = 1<<7;
+
+std::vector<char> msgs(qSizeMax + numMsgs);
+std::vector<unsigned int> prios(qSizeMax + numMsgs);
+
+
+double timePerOp_stlQ(int qBaseSize = 256)
+{
+  msgQ<int> q;
+
+  for (int i = 0; i < qBaseSize; i++)
+      q.enq((msg_t*)&msgs[i], prios[i]);
+
+  double startTime = CmiWallTimer();
+  for (int i = 0; i < numIters; i++)
+  {
+    for (int strt = qBaseSize; strt < qBaseSize + numMsgs; strt += qBatchSize)
+    {
+      for (int j = strt; j < strt + qBatchSize; j++)
+        q.enq((msg_t*)&msgs[j], prios[j]);
+      void *m;
+      for (int j = 0; j < qBatchSize; j++)
+        q.deq();
+    }
+  }
+
+  return 1000000 * (CmiWallTimer() - startTime) / (numIters * numMsgs * 2);
+}
+
+
+bool perftest_general_ififo()
+{
+  #if CMK_HAS_STD_UNORDERED_MAP
+  CkPrintf("The STL variant of the msg q is using a std::unordered_map\n");
+  #else
+  CkPrintf("The STL variant of the msg q is using a std::map\n");
+  #endif
+
+  CkPrintf("Reporting time per enqueue / dequeue operation (us) for an STL-based msg Q\n"
+           "Nprios (row) is the number of different priority values that are used.\n"
+           "Qlen (col) is the base length of the queue on which the enq/deq operations are timed\n"
+          );
+
+  CkPrintf("\nversion  Nprios");
+  for (int i = qSizeMin; i <= qSizeMax; i*=2)
+    CkPrintf("%10d", i);
+
+  // Charm applications typically have a small/moderate number of different message priorities
+  for (int hl = 16; hl < 128; hl *=2)
+  {
+    std::srand(42);
+    for (int i = 0; i < qSizeMax + numMsgs; i++)
+      prios[i] = std::rand() % hl;
+
+    CkPrintf("\n    stl %7d", hl);
+    for (int i = qSizeMin; i <= qSizeMax; i *= 2)
+      CkPrintf("%10.4f", timePerOp_stlQ(i));
+  }
+
+  CkPrintf("\n");
+  return true;
+}
+
+
+#if 0
+// Template for new harness-driven tests
+bool test_foo()
+{
+  msgQ<int> q;
+
+  bool result = ;
+  return result;
+}
+#endif
+
+
+struct main : public CBase_main
+{
+ main(CkArgMsg *)
+ {
+  int tests = 0, success = 0, fail = 0;
+  char message[100];
+
+  RUN_TEST(test_empty);
+  RUN_TEST(test_one);
+  RUN_TEST(test_two);
+  RUN_TEST(test_fifo);
+  RUN_TEST(test_lifo);
+  RUN_TEST(test_enqueue_mixed);
+  RUN_TEST(test_enumerate);
+  RUN_TEST(test_stl_ififo);
+  RUN_TEST(perftest_general_ififo);
+  if (fail) {
+    sprintf(message, "%d/%d tests failed\n", fail, tests);
+    CkAbort(message);
+  }
+  else {
+    CkPrintf("All %d stl msgQ tests passed\n", tests);
+    CkExit();
+  }
+ }
+};
+
+#include "main.def.h"
+
index 35a9f627172120d2ee86a7622bb2d6475fc3252e..294c888a66b426f064f47c625233fbaa1edf9897 100644 (file)
@@ -8,7 +8,6 @@ using std::endl;
 using std::sprintf;
 
 #include "queueing.h"
-#include "msgq.h"
 #include "main.decl.h"
 
 #define CmiFree free
@@ -176,25 +175,6 @@ bool test_general_ififo()
   return result;
 }
 
-bool test_stl_ififo()
-{
-  msgQ<int> q;
-  void *i = (char *)1, *j = (char *)2, *k = (char *)3, *l = (char*)4;
-  unsigned int a = -1, b = 0, c = 1, d = -1;
-  q.enq(i, d, true);
-  q.enq(j, c);
-  q.enq(k, b);
-  q.enq(l, a);
-  void *r, *s, *t, *u;
-  r = (void*)q.deq();
-  s = (void*)q.deq();
-  t = (void*)q.deq();
-  u = (void*)q.deq();
-  bool result = (r == i) && (s == l) && (t == k) && (u == j);
-  return result;
-}
-
-
 const int qSizeMin   = 1<<4;
 const int qSizeMax   = 1<<12;
 const int qBatchSize = 1<<4;
@@ -230,38 +210,8 @@ double timePerOp_general_ififo(int qBaseSize = 256)
 }
 
 
-double timePerOp_stlQ(int qBaseSize = 256)
-{
-  msgQ<int> q;
-
-  for (int i = 0; i < qBaseSize; i++)
-      q.enq((msg_t*)&msgs[i], prios[i]);
-
-  double startTime = CmiWallTimer();
-  for (int i = 0; i < numIters; i++)
-  {
-    for (int strt = qBaseSize; strt < qBaseSize + numMsgs; strt += qBatchSize)
-    {
-      for (int j = strt; j < strt + qBatchSize; j++)
-        q.enq((msg_t*)&msgs[j], prios[j]);
-      void *m;
-      for (int j = 0; j < qBatchSize; j++)
-        q.deq();
-    }
-  }
-
-  return 1000000 * (CmiWallTimer() - startTime) / (numIters * numMsgs * 2);
-}
-
-
 bool perftest_general_ififo()
 {
-  #if CMK_HAS_STD_UNORDERED_MAP
-  CkPrintf("The STL variant of the msg q is using a std::unordered_map\n");
-  #else
-  CkPrintf("The STL variant of the msg q is using a std::map\n");
-  #endif
-
   CkPrintf("Reporting time per enqueue / dequeue operation (us) for charm's underlying mixed priority queue\n"
            "Nprios (row) is the number of different priority values that are used.\n"
            "Qlen (col) is the base length of the queue on which the enq/deq operations are timed\n"
@@ -281,9 +231,6 @@ bool perftest_general_ififo()
     CkPrintf("\n  charm %7d", hl);
     for (int i = qSizeMin; i <= qSizeMax; i *= 2)
       CkPrintf("%10.4f", i, timePerOp_general_ififo(i));
-    CkPrintf("\n    stl %7d", hl);
-    for (int i = qSizeMin; i <= qSizeMax; i *= 2)
-      CkPrintf("%10.4f", i, timePerOp_stlQ(i));
   }
 
   CkPrintf("\n");
@@ -319,7 +266,6 @@ struct main : public CBase_main
     RUN_TEST(test_enumerate);
     RUN_TEST(test_general_fifo);
     RUN_TEST(test_general_ififo);
-    RUN_TEST(test_stl_ififo);
     RUN_TEST(perftest_general_ififo);
 
     if (fail) {