KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javolution > realtime > AllocationProfile


1 /*
2  * Javolution - Java(TM) Solution for Real-Time and Embedded Systems
3  * Copyright (C) 2005 - Javolution (http://javolution.org/)
4  * All rights reserved.
5  *
6  * Permission to use, copy, modify, and distribute this software is
7  * freely granted, provided that this notice is preserved.
8  */

9 package javolution.realtime;
10
11 import java.io.InputStream;
12 import java.io.OutputStream;
13 import java.io.PrintStream;
14
15 import javolution.JavolutionError;
16 import javolution.io.Utf8StreamReader;
17 import javolution.io.Utf8StreamWriter;
18 import javolution.lang.Reflection;
19 import javolution.lang.TextBuilder;
20 import javolution.lang.TypeFormat;
21
22 import j2me.io.File;
23 import j2me.io.FileInputStream;
24 import j2me.io.FileNotFoundException;
25 import j2me.io.FileOutputStream;
26 import j2me.lang.IllegalStateException;
27
28 /**
29  * <p> This class represents a view of the current {@link ObjectFactory
30  * object factories} allocation profile; it facilitates class initialization
31  * and object pre-allocation based on previous or current allocation
32  * profile.</p>
33  *
34  * <p> Preallocations can be performed at start-up (using the allocation profile
35  * saved from previous executions) or at any appropriate time. For example:
36  * <pre>
37  * void main(String[]) {
38  * AllocationProfile.load(); // Loads allocation profile from previous executions.
39  * for (Music music = getMusicToPlay(); music != null; music = music.getNext()) {
40  * AllocationProfile.preallocate(); // Delay ok, not started yet.
41  * play(music); // Real-time and fast (no object creation and no gc).
42  * }
43  * AllocationProfile.save(); // Saves allocation profile (optional).
44  * }</pre></p>
45  *
46  * <p> Once loaded, the allocation profile is updated automatically during
47  * program execution. Allocation profiles are typically generated from
48  * test runs (from an initially empty profile) and contain the maximum
49  * number of allocations between preallocations or the stack maximum size
50  * for threads executing within a {@link PoolContext}.
51  * Here is an example of profile data (which can be manually edited):<pre>
52  * javolution.util.FastSet$1 20
53  * javolution.util.FastList$1 120
54  * javolution.util.FastList$2 0
55  * javolution.util.FastList$Node$1 5074
56  * javolution.util.FastList$FastListIterator$1 10002
57  * javolution.xml.CharacterData$1 3</pre></p>
58  *
59  * <p> To further decrease "first use" execution time, application might
60  * also consider using {@link javolution.lang.PersistentReference
61  * PersistentReference} to hold complex data structures to setup at
62  * start-up.</p>
63  *
64  * @author <a HREF="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
65  * @version 3.1, March 12, 2005
66  */

67 public final class AllocationProfile {
68
69     /**
70      * Holds UTF8 reader.
71      */

72     private static final Utf8StreamReader READER = new Utf8StreamReader();
73
74     /**
75      * Holds UTF8 writer.
76      */

77     private static final Utf8StreamWriter WRITER = new Utf8StreamWriter();
78
79     /**
80      * Holds class name read/written.
81      */

82     private static final TextBuilder ClassName = new TextBuilder();
83
84     /**
85      * Holds counter read/written.
86      */

87     private static final TextBuilder Counter = new TextBuilder();
88
89     /**
90      * Holds the overflow handler.
91      */

92     volatile static Runnable OverflowHandler;
93
94     /**
95      * Default constructor.
96      */

97     private AllocationProfile() {
98     }
99
100     /**
101      * Enables/disables allocation profiling.
102      *
103      * @param isEnabled <code>true</code> if allocation profile is enabled;
104      * <code>false</code> otherwise.
105      */

106     public static void setEnabled(boolean isEnabled) {
107         ObjectFactory.IsAllocationProfileEnabled = isEnabled;
108     }
109
110     /**
111      * Indicates if allocation profiling is enabled.
112      *
113      * @return <code>true</code> if allocation profile is enabled;
114      * <code>false</code> otherwise.
115      */

116     public static boolean isEnabled() {
117         return ObjectFactory.IsAllocationProfileEnabled;
118     }
119
120     /**
121      * Loads the allocation profile previously {@link #save saved}
122      * (equivalent to <code>load(new FileInputStream("profile.txt"))</code>).
123      * Allocation profiling is automatically {@link #setEnabled enabled}.
124      *
125      * @see #load(InputStream)
126      */

127     public static void load() {
128         File file = new File("profile.txt");
129         if (file.exists()) {
130             try {
131                 load(new FileInputStream(file));
132             } catch (FileNotFoundException e) {
133                 throw new JavolutionError(e);
134             }
135         } else {
136             ObjectFactory.IsAllocationProfileEnabled = true;
137             System.err.println("No initial allocation profile.");
138         }
139     }
140
141     /**
142      * Loads the allocation profile from the specified input stream and
143      * initialize classes having {@link ObjectFactory} instances (same
144      * classes and same order as it occured when the allocation profile was
145      * saved).
146      * Allocation profiling is automatically {@link #setEnabled enabled}.
147      *
148      * @param in the input stream holding the allocation profile.
149      */

150     public static synchronized void load(InputStream in) {
151         try {
152             READER.setInputStream(in);
153             for (int c = READER.read(); c >= 0; c = READER.read()) {
154                 if (c <= ' ')
155                     continue; // Ignores any spacing character.
156

157                 // Reads class name.
158
ClassName.append((char) c);
159                 for (c = READER.read(); c > ' '; c = READER.read()) {
160                     ClassName.append((char) c);
161                 }
162
163                 // Reads counter on the same line (if any).
164
while ((c >= 0) && (c != '\n') && (c <= ' ')) {
165                     c = READER.read();
166                 }
167                 if (c > ' ') { // Find one.
168
Counter.append((char) c);
169                     for (c = READER.read(); c > ' '; c = READER.read()) {
170                         Counter.append((char) c);
171                     }
172                 }
173
174                 // Process line.
175
String factoryName = ClassName.toString();
176                 Class factoryClass = Reflection.getClass(factoryName);
177                 ClassName.reset();
178
179                 // Initializes container class.
180
int sep = factoryName.lastIndexOf('$');
181                 Reflection.getClass(factoryName.substring(0, sep));
182
183                 // Searched for object factory.
184
ObjectFactory factory = null;
185                 for (int j = 0; j < ObjectFactory.Count; j++) {
186                     if (ObjectFactory.INSTANCES[j].getClass() == factoryClass) {
187                         factory = ObjectFactory.INSTANCES[j];
188                         break;
189                     }
190                 }
191
192                 // Setup factory.
193
if (factory != null) {
194                     if (Counter.length() > 0) {
195                         factory._preallocatedCount = TypeFormat
196                                 .parseInt(Counter);
197                         Counter.reset();
198                     }
199                 } else {
200                     throw new Error("Factory class: " + factoryClass
201                             + " not found");
202                 }
203             }
204         } catch (Throwable e) {
205             throw new JavolutionError(e);
206         } finally {
207             READER.reset();
208             ClassName.reset();
209             Counter.reset();
210             ObjectFactory.IsAllocationProfileEnabled = true;
211         }
212     }
213
214     /**
215      * Saves the current allocation profile (equivalent to
216      * <code>save(new FileOutputStream("profile.txt"))</code>).
217      *
218      * @throws IllegalStateException if allocation profiling is disabled.
219      * @see #save(OutputStream)
220      */

221     public static void save() {
222         File file = new File("profile.txt");
223         try {
224             save(new FileOutputStream(file));
225         } catch (FileNotFoundException e) {
226             throw new JavolutionError(e);
227         }
228     }
229
230     /**
231      * Saves the current allocation profile to the specified output source
232      * destination.
233      *
234      * @param out the target destination.
235      * @throws IllegalStateException if allocation profiling is disabled.
236      */

237     public static synchronized void save(OutputStream out) {
238         if (!ObjectFactory.IsAllocationProfileEnabled) {
239             throw new IllegalStateException("Allocation profiling disabled");
240         }
241         try {
242             WRITER.setOutputStream(out);
243             for (int i = 0; i < ObjectFactory.Count; i++) {
244                 ObjectFactory factory = ObjectFactory.INSTANCES[i];
245                 WRITER.write(factory.getClass().getName());
246                 WRITER.write(' ');
247                 int maxCount = factory._allocatedCount > factory._preallocatedCount ? factory._allocatedCount
248                         : factory._preallocatedCount;
249                 Counter.append(maxCount);
250                 WRITER.write(Counter);
251                 Counter.reset();
252                 WRITER.write('\n');
253             }
254             WRITER.close();
255         } catch (Throwable e) {
256             throw new JavolutionError(e);
257         } finally {
258             WRITER.reset();
259             Counter.reset();
260         }
261     }
262
263     /**
264      * Preallocates object based upon the current allocation profile.
265      * In case of repetitive preallocations, as many objects are created
266      * as it has been consumed since the last preallocation.
267      *
268      * @throws IllegalStateException if allocation profiling is disabled.
269      */

270     public static synchronized void preallocate() {
271         if (ObjectFactory.IsAllocationProfileEnabled) {
272             for (int i = 0; i < ObjectFactory.Count;) {
273                 ObjectFactory.INSTANCES[i++].preallocate();
274             }
275         } else {
276             throw new IllegalStateException("Allocation profiling disabled");
277         }
278     }
279
280     /**
281      * Resets the current allocation profile. Allocation/preallocation
282      * counters are reset; all preallocation pools are disposed
283      * (preallocated objects can then be garbage collected).
284      *
285      * @throws IllegalStateException if allocation profiling is disabled.
286      */

287     public static void reset() {
288         if (ObjectFactory.IsAllocationProfileEnabled) {
289             for (int i = 0; i < ObjectFactory.Count;) {
290                 ObjectFactory.INSTANCES[i++].reset();
291             }
292         } else {
293             throw new IllegalStateException("Allocation profiling disabled");
294         }
295     }
296
297     /**
298      * Sets the handler to call when a factory exceeds its quota of
299      * pre-allocated object. The default handler ignores such event.
300      */

301     public static void setOverflowHandler(Runnable handler) {
302         AllocationProfile.OverflowHandler = handler;
303     }
304
305     /**
306      * Prints the current allocation profile statistics.
307      *
308      * @param out the stream to use for output (e.g. <code>System.out</code>)
309      */

310     public static void print(PrintStream out) {
311         synchronized (out) {
312             if (ObjectFactory.IsAllocationProfileEnabled) {
313                 out.println("Current Allocation Profile:");
314                 for (int i = 0; i < ObjectFactory.Count;) {
315                     ObjectFactory factory = ObjectFactory.INSTANCES[i++];
316                     if (factory._allocatedCount == 0)
317                         continue;
318                     out.println(factory.getClass().getName()
319                             + " has allocated " + factory._allocatedCount + " "
320                             + factory._productClass.getName() + " out of "
321                             + factory._preallocatedCount);
322
323                 }
324             } else {
325                 out.print("Allocation profiling disabled");
326             }
327             out.println();
328         }
329     }
330
331 }
Popular Tags