version 0.2
[org.ibex.arenaj.git] / src / org / ibex / arenaj / GCBench.java
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.
5 //
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
23 //      size.
24 //
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.
29 //
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
38 //      times.
39 //
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
46
47 public class GCBench {
48
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;
54
55     public static int zap(Object o) { return o==null ? -1 : ((Integer)o).intValue(); }
56
57     // Nodes used by a tree of a given size
58     static int TreeSize(int i) {
59         return ((1 << (i + 1)) - 1);
60     }
61
62     // Number of iterations to use for a given tree depth
63     static int NumIters(int i) {
64         return 2 * TreeSize(kStretchTreeDepth) / TreeSize(i);
65     }
66
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) {
70         if (iDepth<=0) {
71             return;
72         } else {
73             iDepth--;
74             thisNode.left  = new Node();
75             thisNode.right = new Node();
76             Populate (iDepth, thisNode.left);
77             Populate (iDepth, thisNode.right);
78         }
79     }
80
81     // Build tree bottom-up
82     void doMakeTree(int iDepth) { MakeTree(iDepth); }
83     Node MakeTree(int iDepth) {
84         if (iDepth<=0) {
85             return new Node();
86         } else {
87             Node l = MakeTree(iDepth-1);
88             Node r = MakeTree(iDepth-1);
89             Node ret = new Node();
90             ret.left = l;
91             ret.right = r;
92             return ret;
93         }
94     }
95
96     static void PrintDiagnostics() {
97         long lFreeMemory = Runtime.getRuntime().freeMemory();
98         long lTotalMemory = Runtime.getRuntime().totalMemory();
99
100         System.out.print(" Total memory available="
101                          + lTotalMemory + " bytes");
102         System.out.println("  Free memory=" + lFreeMemory + " bytes");
103     }
104
105     void TimeConstruction(int depth) {
106         Node    root;
107         long    tStart, tFinish;
108         int     iNumIters = NumIters(depth);
109         GCBench tempTree;
110
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);
117             tempTree = null;
118         }
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);
126             tempTree = null;
127         }
128         tFinish = System.currentTimeMillis();
129         System.out.println("\tBottom up construction took "
130                            + (tFinish - tStart) + "msecs");
131                 
132     }
133
134     public static void main(String args[]) {
135         Node    root;
136         Node    longLivedTree;
137         Node    tempTree;
138         long    tStart, tFinish;
139         long    tElapsed;
140
141
142         System.out.println("Garbage Collector Test");
143         System.out.println(
144                            " Stretching memory with a binary tree of depth "
145                            + kStretchTreeDepth);
146         PrintDiagnostics();
147         tStart = System.currentTimeMillis();
148
149         // Stretch the memory space quickly
150         GCBench gcb = new GCBench();
151         gcb.doMakeTree(kStretchTreeDepth);
152         gcb = null;
153
154         // Create a long lived object
155         System.out.println(
156                            " Creating a long-lived binary tree of depth " +
157                            kLongLivedTreeDepth);
158         GCBench ll = new GCBench();
159         ll.Populate(kLongLivedTreeDepth);
160
161         /*
162         // Create long-lived array, filling half of it
163         System.out.println(
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) {
168             array[i] = 1.0/i;
169         }
170         */
171         PrintDiagnostics();
172
173         for (int d = kMinTreeDepth; d <= kMaxTreeDepth; d += 2) {
174             ll.TimeConstruction(d);
175         }
176         /*
177         if (longLivedTree == null || array[1000] != 1.0/1000)
178             System.out.println("Failed");
179         */
180         // fake reference to LongLivedTree
181         // and array
182         // to keep them from being optimized away
183
184         tFinish = System.currentTimeMillis();
185         tElapsed = tFinish-tStart;
186         PrintDiagnostics();
187         System.out.println("Completed in " + tElapsed + "ms.");
188     }
189
190     private class Node implements Gladiator {
191         Node left, right;
192         int i, j;
193         //Node(Node l, Node r) { left = l; right = r; }
194         Node() { }
195     }
196
197 } // class JavaGC