From: jzhou Date: Wed, 14 Jul 2010 22:49:09 +0000 (+0000) Subject: Add benchmarks for multicore gc X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=f1e336f8c12c5f1fbdef70cbb5cd07bb57b8d0c5;p=IRC.git Add benchmarks for multicore gc --- diff --git a/Robust/src/Benchmarks/Scheduling/GC/GCBench/GCBench.java b/Robust/src/Benchmarks/Scheduling/GC/GCBench/GCBench.java new file mode 100644 index 00000000..2db25116 --- /dev/null +++ b/Robust/src/Benchmarks/Scheduling/GC/GCBench/GCBench.java @@ -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 index 00000000..612d13fe --- /dev/null +++ b/Robust/src/Benchmarks/Scheduling/GC/MTree/Node.java @@ -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 index 00000000..19f34df6 --- /dev/null +++ b/Robust/src/Benchmarks/Scheduling/GC/MTree/TestRunner.java @@ -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 index 00000000..ea2fffcb --- /dev/null +++ b/Robust/src/Benchmarks/Scheduling/GC/MTree/macrotest_tree.java @@ -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}); +}