KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > tctest > ClientMemoryReaperTestApp


1 /*
2  * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright
3  * notice. All rights reserved.
4  */

5 package com.tctest;
6
7 import com.tc.object.config.ConfigVisitor;
8 import com.tc.object.config.DSOClientConfigHelper;
9 import com.tc.object.config.TransparencyClassSpec;
10 import com.tc.simulator.app.ApplicationConfig;
11 import com.tc.simulator.listener.ListenerProvider;
12 import com.tc.util.Assert;
13 import com.tc.util.DebugUtil;
14 import com.tctest.restart.system.ObjectDataRestartTestApp;
15 import com.tctest.runner.AbstractErrorCatchingTransparentApp;
16
17 import java.security.SecureRandom JavaDoc;
18 import java.text.DateFormat JavaDoc;
19 import java.text.SimpleDateFormat JavaDoc;
20 import java.util.Date JavaDoc;
21 import java.util.HashMap JavaDoc;
22 import java.util.Map JavaDoc;
23 import java.util.Random JavaDoc;
24 import java.util.Vector JavaDoc;
25
26 /**
27  * All this test does is create many many objects so that if the Client side Memory Reaper doesnt run properly for some
28  * reason then it forces an OOME This test needs some tuning
29  */

30 public class ClientMemoryReaperTestApp extends AbstractErrorCatchingTransparentApp {
31   public static final String JavaDoc SYNCHRONOUS_WRITE = "synch-write";
32
33   private static final long OBJECT_COUNT = 2000;
34   private static final long MINIMUM_MEM_NEEDED = 60 * 1024 * 1024;
35   private static final int MEMORY_BLOCKS = 1024 * 1024;
36
37   final Map JavaDoc root = new HashMap JavaDoc();
38   final Vector JavaDoc unusedBytes = new Vector JavaDoc();
39   static long maxDepth = 1;
40   static int transient_mem_blocks_size = 0;
41
42   public ClientMemoryReaperTestApp(String JavaDoc appId, ApplicationConfig cfg, ListenerProvider listenerProvider) {
43     super(appId, cfg, listenerProvider);
44   }
45
46   public static void visitL1DSOConfig(ConfigVisitor visitor, DSOClientConfigHelper config) {
47     visitL1DSOConfig(visitor, config, new HashMap JavaDoc());
48   }
49
50   public static void visitL1DSOConfig(ConfigVisitor visitor, DSOClientConfigHelper config, Map JavaDoc optionalAttributes) {
51     DebugUtil.DEBUG = true;
52
53     boolean isSynchronousWrite = false;
54     if (optionalAttributes.size() > 0) {
55       isSynchronousWrite = Boolean.valueOf((String JavaDoc) optionalAttributes.get(ObjectDataRestartTestApp.SYNCHRONOUS_WRITE))
56           .booleanValue();
57     }
58
59     String JavaDoc testClass = ClientMemoryReaperTestApp.class.getName();
60     TransparencyClassSpec spec = config.getOrCreateSpec(testClass);
61     spec.addRoot("root", "root");
62     String JavaDoc methodExpression = "* " + testClass + ".getNode(..)";
63     config.addReadAutolock(methodExpression);
64     methodExpression = "* " + testClass + ".putNode(..)";
65     addWriteAutolock(config, isSynchronousWrite, methodExpression);
66     methodExpression = "* " + testClass + ".addNode(..)";
67     addWriteAutolock(config, isSynchronousWrite, methodExpression);
68
69     testClass = ClientMemoryReaperTestApp.Node.class.getName();
70     spec = config.getOrCreateSpec(testClass);
71     config.addTransient(testClass, "transientBytes");
72
73     DebugUtil.DEBUG = false;
74   }
75
76   private static void addWriteAutolock(DSOClientConfigHelper config, boolean isSynchronousWrite, String JavaDoc methodPattern) {
77     if (isSynchronousWrite) {
78       config.addSynchronousWriteAutolock(methodPattern);
79       debugPrintln("***** doing a synchronous write");
80     } else {
81       config.addWriteAutolock(methodPattern);
82     }
83   }
84
85   private static void debugPrintln(String JavaDoc s) {
86     if (DebugUtil.DEBUG) {
87       System.err.println(s);
88     }
89   }
90
91   public void runTest() {
92     log("App Id = " + getApplicationId() + " participation count = " + getParticipantCount() + " intensity = "
93         + getIntensity());
94
95     // This is not used as the same effect is attained by using DSO transient
96
if (false) initHeap();
97     initTransientMemBlockSize();
98
99     long objectCount = 0;
100     log("Objects to Create = " + OBJECT_COUNT);
101     final SecureRandom JavaDoc sr = new SecureRandom JavaDoc();
102     long seed = sr.nextLong();
103     log(" Seed for Random = " + seed);
104     Random JavaDoc r = new Random JavaDoc(seed);
105
106     int topLevelObjectCount = (int) (OBJECT_COUNT / 50);
107     while (objectCount++ <= OBJECT_COUNT) {
108       Object JavaDoc myKey = new Integer JavaDoc(r.nextInt(topLevelObjectCount));
109       Node n = getNode(myKey);
110       if (n == null) {
111         putNode(myKey, new Node(objectCount));
112       } else {
113         addNode(n, new Node(objectCount));
114       }
115       if (objectCount % 100 == 0) {
116         log("Objects created = " + objectCount);
117       }
118     }
119     log("Done !!");
120   }
121
122   private static synchronized void initTransientMemBlockSize() {
123     if (transient_mem_blocks_size > 0) {
124       log("Transient memory block size is already initialized to " + transient_mem_blocks_size);
125       return;
126     }
127     Runtime JavaDoc runtime = Runtime.getRuntime();
128     long max_memory = runtime.maxMemory();
129     if (max_memory == Long.MAX_VALUE) {
130       // With no upperbound it is possible that this test wont fail even when client memory reaper is broken.
131
throw new AssertionError JavaDoc("This test is memory sensitive. Please specify the max memory using -Xmx option. "
132                                + "Currently Max Memory is " + max_memory);
133     }
134     log("Max memory is " + max_memory);
135     transient_mem_blocks_size = (int) ((max_memory * 50) / (512 * 1024)); // 50KB for 512MB, so for max_memory ?
136
log("Transient memory block size is " + transient_mem_blocks_size);
137   }
138
139   private void initHeap() {
140     Runtime JavaDoc runtime = Runtime.getRuntime();
141     long max_memory = runtime.maxMemory();
142     if (max_memory == Long.MAX_VALUE || max_memory < MINIMUM_MEM_NEEDED) {
143       // With no upperbound it is possible that this test wont fail even when client memory reaper is broken.
144
throw new AssertionError JavaDoc("This test is memory sensitive. Please specify the max memory using -Xmx option. "
145                                + " Ideal value for this test is >= " + MINIMUM_MEM_NEEDED
146                                + ". Currently Max Memory is " + max_memory);
147     }
148     log("Max memory is " + max_memory);
149     long totalAllocations = 0;
150     // This is not fail proof, but worst case is a few extra allocations, (no of nodes * 1 MB)
151
synchronized (unusedBytes) {
152       while (max_memory > (runtime.totalMemory() + MINIMUM_MEM_NEEDED / 2) || runtime.freeMemory() > MINIMUM_MEM_NEEDED) {
153         final byte[] unused = new byte[MEMORY_BLOCKS];
154         unusedBytes.add(unused);
155         totalAllocations += MEMORY_BLOCKS;
156         log("Allocated " + unused.length + " bytes. Free memory = " + runtime.freeMemory() + ". Total memory = "
157             + runtime.totalMemory());
158       }
159     }
160     log("Total bytes allocated = " + totalAllocations);
161   }
162
163   static DateFormat JavaDoc formatter = new SimpleDateFormat JavaDoc("hh:mm:ss,S");
164
165   private static void log(String JavaDoc message) {
166     System.err.println(Thread.currentThread().getName() + " :: "
167                        + formatter.format(new Date JavaDoc(System.currentTimeMillis())) + " : " + message);
168   }
169
170   private void addNode(Node rootNode, Node node) {
171     synchronized (rootNode) {
172       rootNode.add(node);
173       // System.err.println("Added " + node + " to " + rootNode);
174
}
175   }
176
177   private synchronized static void setMaxDepth(long depth) {
178     if (maxDepth < depth) {
179       maxDepth = depth;
180       if (maxDepth % 10 == 0) {
181         log("Max Depth reached : " + maxDepth);
182       }
183     }
184   }
185
186   private void putNode(Object JavaDoc myKey, Node n) {
187     synchronized (root) {
188       root.put(myKey, n);
189     }
190   }
191
192   private Node getNode(Object JavaDoc myKey) {
193     synchronized (root) {
194       return (Node) root.get(myKey);
195     }
196   }
197
198   private static final class Node {
199     final long id; // Not necessarily unique as each node might create
200
// with
201
// the same id.
202
long lastAccess;
203     long level;
204
205     /* Just to make the object big */
206     byte[] transientBytes = new byte[transient_mem_blocks_size];
207
208     Node odd;
209     Node even;
210
211     Node(long id) {
212       this.id = id;
213       this.level = 0;
214       this.lastAccess = System.currentTimeMillis();
215     }
216
217     void add(Node c) {
218       this.lastAccess = System.currentTimeMillis();
219       if (this.transientBytes == null) {
220         // TODO:: Comeback :: If it is toooo deep, this can take quite some memory
221
this.transientBytes = new byte[transient_mem_blocks_size];
222       }
223       Assert.assertFalse(this == c);
224       if (c.id % 2 == 1) {
225         if (odd == null) {
226           odd = c;
227           c.level = this.level + 1;
228           setMaxDepth(c.level);
229         } else {
230           odd.add(c);
231         }
232       } else {
233         if (even == null) {
234           even = c;
235           c.level = this.level + 1;
236           setMaxDepth(c.level);
237         } else {
238           even.add(c);
239         }
240       }
241     }
242
243     public String JavaDoc toString() {
244       return "Node(" + id + ") : level = " + level + " : odd = " + (odd == null) + " : even = " + (even == null);
245     }
246
247   }
248
249 }
250
Popular Tags