Add benchmarks for multicore gc
authorjzhou <jzhou>
Wed, 14 Jul 2010 22:49:09 +0000 (22:49 +0000)
committerjzhou <jzhou>
Wed, 14 Jul 2010 22:49:09 +0000 (22:49 +0000)
Robust/src/Benchmarks/Scheduling/GC/GCBench/GCBench.java [new file with mode: 0644]
Robust/src/Benchmarks/Scheduling/GC/MTree/Node.java [new file with mode: 0644]
Robust/src/Benchmarks/Scheduling/GC/MTree/TestRunner.java [new file with mode: 0644]
Robust/src/Benchmarks/Scheduling/GC/MTree/macrotest_tree.java [new file with mode: 0644]

diff --git a/Robust/src/Benchmarks/Scheduling/GC/GCBench/GCBench.java b/Robust/src/Benchmarks/Scheduling/GC/GCBench/GCBench.java
new file mode 100644 (file)
index 0000000..2db2511
--- /dev/null
@@ -0,0 +1,225 @@
+/** Bamboo Version  
+ * Ported by: Jin Zhou  07/14/10
+ * **/
+
+//This is adapted from a benchmark written by John Ellis and Pete Kovac
+//of Post Communications.
+//It was modified by Hans Boehm of Silicon Graphics.
+
+//This is no substitute for real applications.  No actual application
+//is likely to behave in exactly this way.  However, this benchmark was
+//designed to be more representative of real applications than other
+//Java GC benchmarks of which we are aware.
+//It attempts to model those properties of allocation requests that
+//are important to current GC techniques.
+//It is designed to be used either to obtain a single overall performance
+//number, or to give a more detailed estimate of how collector
+//performance varies with object lifetimes.  It prints the time
+//required to allocate and collect balanced binary trees of various
+//sizes.  Smaller trees result in shorter object lifetimes.  Each cycle
+//allocates roughly the same amount of memory.
+//Two data structures are kept around during the entire process, so
+//that the measured performance is representative of applications
+//that maintain some live in-memory data.  One of these is a tree
+//containing many pointers.  The other is a large array containing
+//double precision floating point numbers.  Both should be of comparable
+//size.
+
+//The results are only really meaningful together with a specification
+//of how much memory was used.  It is possible to trade memory for
+//better time performance.  This benchmark should be run in a 32 MB
+//heap, though we don't currently know how to enforce that uniformly.
+
+//Unlike the original Ellis and Kovac benchmark, we do not attempt
+//measure pause times.  This facility should eventually be added back
+//in.  There are several reasons for omitting it for now.  The original
+//implementation depended on assumptions about the thread scheduler
+//that don't hold uniformly.  The results really measure both the
+//scheduler and GC.  Pause time measurements tend to not fit well with
+//current benchmark suites.  As far as we know, none of the current
+//commercial Java implementations seriously attempt to minimize GC pause
+//times.
+
+//Known deficiencies:
+//- No way to check on memory use
+//- No cyclic data structures
+//- No attempt to measure variation with object size
+//- Results are sensitive to locking cost, but we dont
+//check for proper locking
+
+task t1(StartupObject s{initialstate}) {
+  //System.printString("task t1\n");
+
+  int threadnum = 62;
+  for(int i = 0; i < threadnum; ++i) {
+    TestRunner gcb = new TestRunner(){run};
+  }
+
+  taskexit(s{!initialstate});
+}
+
+task t2(TestRunner gcb{run}) {
+  //System.printString("task t2\n");
+  gcb.run();
+  taskexit(gcb{!run});
+}
+
+
+class Node {
+  Node left, right;
+  int i, j;
+  Node(Node l, Node r) { left = l; right = r; }
+  Node() { }
+}
+
+public class TestRunner {
+  
+  flag run;
+
+  public static final int kStretchTreeDepth;//    = 18;        // about 16Mb
+  public static final int kLongLivedTreeDepth;//  = 16;  // about 4Mb
+  public static final int kArraySize;//  = 500000;  // about 4Mb
+  public static final int kMinTreeDepth;// = 4;
+  public static final int kMaxTreeDepth;// = 16;
+  
+  public TestRunner() {
+    kStretchTreeDepth    = 12;// 1/2Mb 18;  // about 16Mb
+    kLongLivedTreeDepth  = 10; // 1/8Mb 16;  // about 4Mb
+    kArraySize  = 125000/16; // 1/8Mb 500000;  // about 4Mb
+    kMinTreeDepth = 4;
+    kMaxTreeDepth = 16;
+  }
+
+  // Nodes used by a tree of a given size
+  int TreeSize(int i) {
+    return ((1 << (i + 1)) - 1);
+  }
+
+  // Number of iterations to use for a given tree depth
+  int NumIters(int i) {
+    return 2 * TreeSize(kStretchTreeDepth) / TreeSize(i);
+  }
+
+  // Build tree top down, assigning to older objects. 
+  void Populate(int iDepth, Node thisNode) {
+    if (iDepth<=0) {
+      return;
+    } else {
+      iDepth--;
+      thisNode.left  = new Node();
+      thisNode.right = new Node();
+      Populate (iDepth, thisNode.left);
+      Populate (iDepth, thisNode.right);
+    }
+  }
+
+  // Build tree bottom-up
+  Node MakeTree(int iDepth) {
+    if (iDepth<=0) {
+      return new Node();
+    } else {
+      return new Node(MakeTree(iDepth-1),
+          MakeTree(iDepth-1));
+    }
+  }
+
+  /*static void PrintDiagnostics() {
+    long lFreeMemory = Runtime.getRuntime().freeMemory();
+    long lTotalMemory = Runtime.getRuntime().totalMemory();
+
+    System.out.print(" Total memory available="
+        + lTotalMemory + " bytes");
+    System.out.println("  Free memory=" + lFreeMemory + " bytes");
+  }*/
+
+  void TimeConstruction(int depth) {
+    Node    root;
+    //long    tStart, tFinish;
+    int        iNumIters = NumIters(depth);
+    Node       tempTree;
+
+    /*System.out.println("Creating " + iNumIters +
+        " trees of depth " + depth);
+    tStart = System.currentTimeMillis();*/
+    for (int i = 0; i < iNumIters; ++i) {
+      tempTree = new Node();
+      Populate(depth, tempTree);
+      tempTree = null;
+    }
+    /*tFinish = System.currentTimeMillis();
+    System.out.println("\tTop down construction took "
+        + (tFinish - tStart) + "msecs");
+    tStart = System.currentTimeMillis();*/
+    for (int i = 0; i < iNumIters; ++i) {
+      tempTree = MakeTree(depth);
+      tempTree = null;
+    }
+    /*tFinish = System.currentTimeMillis();
+    System.out.println("\tBottom up construction took "
+        + (tFinish - tStart) + "msecs");*/
+
+  }
+  
+  public void stretch() {
+    Node    root;
+    Node    longLivedTree;
+    Node    tempTree;
+    /*long  tStart, tFinish;
+    long    tElapsed;*/
+
+
+    /*System.out.println("Garbage Collector Test");
+    System.out.println(
+        " Stretching memory with a binary tree of depth "
+        + kStretchTreeDepth);
+    PrintDiagnostics();
+    tStart = System.currentTimeMillis();*/
+
+    // Stretch the memory space quickly
+    tempTree = MakeTree(kStretchTreeDepth);
+    tempTree = null;
+  }
+
+  public void run() {
+    Node       root;
+    Node       longLivedTree;
+    
+    // Stretch the memory space quickly
+    stretch();
+
+    // Create a long lived object
+    /*System.out.println(
+        " Creating a long-lived binary tree of depth " +
+        kLongLivedTreeDepth);*/
+    longLivedTree = new Node();
+    Populate(kLongLivedTreeDepth, longLivedTree);
+
+    // Create long-lived array, filling half of it
+    /*System.out.println(
+        " Creating a long-lived array of "
+        + kArraySize + " doubles");*/
+    float array[] = new float[kArraySize];
+    for (int i = 0; i < kArraySize/2; ++i) {
+      array[i] = 1.0f/i;
+    }
+    //PrintDiagnostics();
+
+    for (int d = kMinTreeDepth; d <= kMaxTreeDepth; d += 2) {
+      TimeConstruction(d);
+    }
+
+    if (longLivedTree == null || array[1000] != 1.0f/1000) {
+      //System.out.println("Failed");
+      System.printI(0xa0);
+      System.printI((int)(array[1000]*1000000));
+    }
+    // fake reference to LongLivedTree
+    // and array
+    // to keep them from being optimized away
+
+    /*tFinish = System.currentTimeMillis();
+    tElapsed = tFinish-tStart;
+    PrintDiagnostics();
+    System.out.println("Completed in " + tElapsed + "ms.");*/
+  }
+} // class JavaGC
diff --git a/Robust/src/Benchmarks/Scheduling/GC/MTree/Node.java b/Robust/src/Benchmarks/Scheduling/GC/MTree/Node.java
new file mode 100644 (file)
index 0000000..612d13f
--- /dev/null
@@ -0,0 +1,112 @@
+class Node {
+  int m_key;
+       int m_value;
+       Node m_left;
+       Node m_right;
+    Node m_parent;
+
+       public Node() {
+               // an empty node
+               this.m_key = -1;
+               this.m_value = -1;
+               this.m_left = null;
+               this.m_right = null;
+        this.m_parent = null;
+       }
+
+       public Node(int key,
+                           int value) {
+               this.m_key = key;
+               this.m_value = value;
+               this.m_left = null;
+               this.m_right = null;
+        this.m_parent = null;
+       }
+    
+    public int getKey() {
+      return this.m_key;
+    }
+
+    public void setParent(Node p) {
+      this.m_parent = p;
+    }
+    
+       public void setLeftChild(int key,
+                             int value) {
+      Node n = new Node(key, value);
+      this.m_left = n;
+      n.setParent(this);
+       }
+
+       public void setRightChild(int key,
+                              int value) {
+      Node n = new Node(key, value);
+      this.m_right = n;
+      n.setParent(this);
+       }
+
+       public boolean insert(int key,
+                          int value,
+                          boolean candelete) {
+      if(this.m_key == -1) {
+        // empty tree
+        this.m_key = key;
+        this.m_value = value;
+      } else {
+        if(this.m_key == key) {
+          // collision
+          replace(key, value);
+          return false;
+        } else if(this.m_key > key) {
+          if(this.m_left == null) {
+            // no left subtree
+            if(candelete) {
+              // replace this node with the new node
+              replace(key, value);
+              return false;
+            } else {
+              setLeftChild(key, value);
+            }
+          } else {
+            // insert into the left subtree
+            return this.m_left.insert(key, value, candelete);
+          }
+        } else if(this.m_key < key) {
+          if(this.m_right == null) {
+            // no right subtree
+            if(candelete) {
+              replace(key, value);
+              return false;
+            } else {
+              setRightChild(key, value);
+            }
+          } else {
+            // insert into the right subtree
+            return this.m_right.insert(key, value, candelete);
+          }
+        }
+      }
+      return true;
+    }
+    
+    public void replace(int key,
+                        int value) {
+      Node n = new Node(key, value);
+      n.m_left = this.m_left;
+      n.m_right = this.m_right;
+      n.m_parent = this.m_parent;
+      if(this.m_parent != null) {
+        if(this.m_parent.getKey() > key) {
+          this.m_parent.m_left = n;
+        } else {
+          this.m_parent.m_right = n;
+        }
+      }
+         if(this.m_left != null) {
+               this.m_left.m_parent = n;
+         }
+         if(this.m_right != null) {
+               this.m_right.m_parent = n;
+         }
+    }
+}
diff --git a/Robust/src/Benchmarks/Scheduling/GC/MTree/TestRunner.java b/Robust/src/Benchmarks/Scheduling/GC/MTree/TestRunner.java
new file mode 100644 (file)
index 0000000..19f34df
--- /dev/null
@@ -0,0 +1,35 @@
+class TestRunner {
+       flag run;
+
+       int m_index;
+    int m_size;
+    int m_nodenum;
+       Node m_tree; // The root of a BST
+
+       public TestRunner(int index,
+                      int size,
+                      int nodenum) {
+               this.m_index = index;
+        this.m_size = size;
+        this.m_nodenum = nodenum;
+               this.m_tree = new Node();
+       }
+
+       public void run() {
+      // Randomly generate new (key, value) pair and insert into the tree
+      // If have collision, simply throw away the old node
+      // The tree can hold m_size nodes at most, if it has reached the 
+      // limitation of m_size, then replace the node whose key is the 
+         // closest to the new key.
+      Random rand = new Random(m_index);
+      while(this.m_nodenum-- > 0) {
+        // Generate a new (key, value) pair
+        int key = Math.abs(rand.nextInt());
+        int value = Math.abs(rand.nextInt());
+        if(this.m_tree.insert(key, value, !(this.m_size > 0))) {
+          // insert a new node
+          this.m_size--;
+        }
+      }
+       }
+}
diff --git a/Robust/src/Benchmarks/Scheduling/GC/MTree/macrotest_tree.java b/Robust/src/Benchmarks/Scheduling/GC/MTree/macrotest_tree.java
new file mode 100644 (file)
index 0000000..ea2fffc
--- /dev/null
@@ -0,0 +1,18 @@
+task t1(StartupObject s{initialstate}) {
+       //System.printString("task t1\n");
+       
+       int threadnum = 62;
+    int size = 21500;
+    int nodenum = size*10;
+       for(int i = 0; i < threadnum; ++i) {
+               TestRunner tr = new TestRunner(i, size, nodenum){run};
+       }
+
+       taskexit(s{!initialstate});
+}
+
+task t2(TestRunner tr{run}) {
+       //System.printString("task t2\n");
+       tr.run();
+       taskexit(tr{!run});
+}