1 package org.ibex.arenaj;
2 // This is adapted from a benchmark written by John Ellis and Pete Kovac
3 // of Post Communications.
4 // It was modified by Hans Boehm of Silicon Graphics.
6 // This is no substitute for real applications. No actual application
7 // is likely to behave in exactly this way. However, this benchmark was
8 // designed to be more representative of real applications than other
9 // Java GC benchmarks of which we are aware.
10 // It attempts to model those properties of allocation requests that
11 // are important to current GC techniques.
12 // It is designed to be used either to obtain a single overall performance
13 // number, or to give a more detailed estimate of how collector
14 // performance varies with object lifetimes. It prints the time
15 // required to allocate and collect balanced binary trees of various
16 // sizes. Smaller trees result in shorter object lifetimes. Each cycle
17 // allocates roughly the same amount of memory.
18 // Two data structures are kept around during the entire process, so
19 // that the measured performance is representative of applications
20 // that maintain some live in-memory data. One of these is a tree
21 // containing many pointers. The other is a large array containing
22 // double precision floating point numbers. Both should be of comparable
25 // The results are only really meaningful together with a specification
26 // of how much memory was used. It is possible to trade memory for
27 // better time performance. This benchmark should be run in a 32 MB
28 // heap, though we don't currently know how to enforce that uniformly.
30 // Unlike the original Ellis and Kovac benchmark, we do not attempt
31 // measure pause times. This facility should eventually be added back
32 // in. There are several reasons for omitting it for now. The original
33 // implementation depended on assumptions about the thread scheduler
34 // that don't hold uniformly. The results really measure both the
35 // scheduler and GC. Pause time measurements tend to not fit well with
36 // current benchmark suites. As far as we know, none of the current
37 // commercial Java implementations seriously attempt to minimize GC pause
40 // Known deficiencies:
41 // - No way to check on memory use
42 // - No cyclic data structures
43 // - No attempt to measure variation with object size
44 // - Results are sensitive to locking cost, but we dont
45 // check for proper locking
47 public class GCBench {
49 public static final int kStretchTreeDepth = 18; // about 16Mb
50 public static final int kLongLivedTreeDepth = 16; // about 4Mb
51 public static final int kArraySize = 500000; // about 4Mb
52 public static final int kMinTreeDepth = 4;
53 public static final int kMaxTreeDepth = 16;
55 public static int zap(Object o) { return o==null ? -1 : ((Integer)o).intValue(); }
57 // Nodes used by a tree of a given size
58 static int TreeSize(int i) {
59 return ((1 << (i + 1)) - 1);
62 // Number of iterations to use for a given tree depth
63 static int NumIters(int i) {
64 return 2 * TreeSize(kStretchTreeDepth) / TreeSize(i);
67 // Build tree top down, assigning to older objects.
68 void Populate(int iDepth) { Populate(iDepth, new Node()); }
69 void Populate(int iDepth, Node thisNode) {
74 thisNode.left = new Node();
75 thisNode.right = new Node();
76 Populate (iDepth, thisNode.left);
77 Populate (iDepth, thisNode.right);
81 // Build tree bottom-up
82 void doMakeTree(int iDepth) { MakeTree(iDepth); }
83 Node MakeTree(int iDepth) {
87 Node l = MakeTree(iDepth-1);
88 Node r = MakeTree(iDepth-1);
89 Node ret = new Node();
96 static void PrintDiagnostics() {
97 long lFreeMemory = Runtime.getRuntime().freeMemory();
98 long lTotalMemory = Runtime.getRuntime().totalMemory();
100 System.out.print(" Total memory available="
101 + lTotalMemory + " bytes");
102 System.out.println(" Free memory=" + lFreeMemory + " bytes");
105 void TimeConstruction(int depth) {
107 long tStart, tFinish;
108 int iNumIters = NumIters(depth);
111 System.out.println("Creating " + iNumIters +
112 " trees of depth " + depth);
113 tStart = System.currentTimeMillis();
114 for (int i = 0; i < iNumIters; ++i) {
115 tempTree = new GCBench();
116 tempTree.Populate(depth);
119 tFinish = System.currentTimeMillis();
120 System.out.println("\tTop down construction took "
121 + (tFinish - tStart) + "msecs");
122 tStart = System.currentTimeMillis();
123 for (int i = 0; i < iNumIters; ++i) {
124 tempTree = new GCBench();
125 tempTree.doMakeTree(depth);
128 tFinish = System.currentTimeMillis();
129 System.out.println("\tBottom up construction took "
130 + (tFinish - tStart) + "msecs");
134 public static void main(String args[]) {
138 long tStart, tFinish;
142 System.out.println("Garbage Collector Test");
144 " Stretching memory with a binary tree of depth "
145 + kStretchTreeDepth);
147 tStart = System.currentTimeMillis();
149 // Stretch the memory space quickly
150 GCBench gcb = new GCBench();
151 gcb.doMakeTree(kStretchTreeDepth);
154 // Create a long lived object
156 " Creating a long-lived binary tree of depth " +
157 kLongLivedTreeDepth);
158 GCBench ll = new GCBench();
159 ll.Populate(kLongLivedTreeDepth);
162 // Create long-lived array, filling half of it
164 " Creating a long-lived array of "
165 + kArraySize + " doubles");
166 double array[] = new double[kArraySize];
167 for (int i = 0; i < kArraySize/2; ++i) {
173 for (int d = kMinTreeDepth; d <= kMaxTreeDepth; d += 2) {
174 ll.TimeConstruction(d);
177 if (longLivedTree == null || array[1000] != 1.0/1000)
178 System.out.println("Failed");
180 // fake reference to LongLivedTree
182 // to keep them from being optimized away
184 tFinish = System.currentTimeMillis();
185 tElapsed = tFinish-tStart;
187 System.out.println("Completed in " + tElapsed + "ms.");
190 private class Node implements Gladiator {
193 //Node(Node l, Node r) { left = l; right = r; }