001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: * The Original Software is NetBeans. The Initial Developer of the Original
026: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
027: * Microsystems, Inc. All Rights Reserved.
028: *
029: * If you wish your version of this file to be governed by only the CDDL
030: * or only the GPL Version 2, indicate your decision by adding
031: * "[Contributor] elects to include this software in this distribution
032: * under the [CDDL or GPL Version 2] license." If you do not indicate a
033: * single choice of license, a recipient has the option to distribute
034: * your version of this file under either the CDDL, the GPL Version 2 or
035: * to extend the choice of license to its licensees as provided above.
036: * However, if you add GPL Version 2 code and therefore, elected the GPL
037: * Version 2 license, then the option applies only if the new code is
038: * made subject to such option by the copyright holder.
039: */
040:
041: package org.netbeans.lib.profiler.results.memory;
042:
043: import org.netbeans.lib.profiler.ProfilerClient;
044: import org.netbeans.lib.profiler.client.ClientUtils;
045: import org.netbeans.lib.profiler.global.ProfilingSessionStatus;
046: import org.netbeans.lib.profiler.results.ResultsSnapshot;
047: import java.io.DataInputStream;
048: import java.io.DataOutputStream;
049: import java.io.IOException;
050: import java.util.HashSet;
051: import java.util.Set;
052: import java.util.logging.Level;
053:
054: /**
055: * Results snapshot for Memory Profiling.
056: *
057: * @author Ian Formanek
058: */
059: public abstract class MemoryResultsSnapshot extends ResultsSnapshot {
060: //~ Instance fields ----------------------------------------------------------------------------------------------------------
061:
062: private JMethodIdTable table;
063: private String[] classNames;
064:
065: /** [0-nProfiledClasses] total size in bytes for tracked instances of this class */
066: private long[] objectsSizePerClass;
067:
068: /** [0-nProfiledClasses] class Id -> root of its allocation traces tree */
069: private RuntimeMemoryCCTNode[] stacksForClasses;
070:
071: /** total number of profiled classes */
072: private int nProfiledClasses;
073:
074: //~ Constructors -------------------------------------------------------------------------------------------------------------
075:
076: public MemoryResultsSnapshot() {
077: } // No-arg constructor needed for above serialization methods to work
078:
079: public MemoryResultsSnapshot(long beginTime, long timeTaken,
080: MemoryCCTProvider provider, ProfilerClient client)
081: throws ClientUtils.TargetAppOrVMTerminated {
082: super (beginTime, timeTaken);
083:
084: // TODO [performance]: profile for performance - specifically which of the actions below is most time consuming
085: ProfilingSessionStatus status = client.getStatus();
086: status.beginTrans(false);
087:
088: try {
089: performInit(client, provider);
090:
091: nProfiledClasses = provider.getNProfiledClasses();
092:
093: int len = 0;
094:
095: if (provider.getObjectsSizePerClass() != null) {
096: //System.err.println("mcgb.objectsSizePerClass len is: "+mcgb.objectsSizePerClass.length);
097: len = provider.getObjectsSizePerClass().length;
098: objectsSizePerClass = new long[len];
099: System.arraycopy(provider.getObjectsSizePerClass(), 0,
100: objectsSizePerClass, 0, len);
101: } /*else {
102: System.err.println("mcgb.objectsSizePerClass is NULL");
103: } */
104: String[] s_classNames = status.getClassNames();
105: // len = s_classNames.length;
106: len = nProfiledClasses;
107: //System.err.println("status.classNames.length is: "+len );
108: classNames = new String[len];
109: System.arraycopy(s_classNames, 0, classNames, 0, len);
110:
111: // System.out.println("Created snapshot [" + timeTaken + "] with " + classNames.length + " classes; nProfiledClasses = " + nProfiledClasses);
112: if ((provider.getStacksForClasses() != null)
113: && checkContainsStacks(provider
114: .getStacksForClasses())) {
115: stacksForClasses = new RuntimeMemoryCCTNode[provider
116: .getStacksForClasses().length];
117:
118: Set ids = new HashSet(10000);
119:
120: for (int i = 0; i < stacksForClasses.length; i++) {
121: if (provider.getStacksForClasses()[i] != null) {
122: stacksForClasses[i] = (RuntimeMemoryCCTNode) provider
123: .getStacksForClasses()[i].clone();
124: stacksForClasses[i].addAllJMethodIds(ids);
125: }
126: }
127:
128: // if we are taking allocation stack traces, we need to obtain names and signatures for all methods
129: Integer[] array = new Integer[ids.size()];
130: ids.toArray(array);
131:
132: int[] primArray = new int[ids.size()];
133:
134: for (int j = 0; j < array.length; j++) {
135: primArray[j] = array[j].intValue();
136: }
137:
138: // System.err.println("Going to ask for jmethodId names: len:"+primArray.length);
139: // for (int i = 0; i < primArray.length; i++) {
140: // System.err.println("value ["+i+"] = " + primArray[i]);
141: // }
142: String[][] methodNames = client
143: .getMethodNamesForJMethodIds(primArray);
144: // System.err.println("Returned size is: "+methodNames.length + "x" + methodNames[0].length);
145: table = new JMethodIdTable(primArray, methodNames);
146: }
147: } finally {
148: status.endTrans();
149:
150: if (LOGGER.isLoggable(Level.FINEST)) {
151: debugValues();
152: }
153: }
154: }
155:
156: //~ Methods ------------------------------------------------------------------------------------------------------------------
157:
158: public String getClassName(int classId) {
159: return classNames[classId];
160: }
161:
162: public String[] getClassNames() {
163: return classNames;
164: }
165:
166: public JMethodIdTable getJMethodIdTable() {
167: return table;
168: }
169:
170: public int getNProfiledClasses() {
171: return nProfiledClasses;
172: }
173:
174: public long[] getObjectsSizePerClass() {
175: return objectsSizePerClass;
176: }
177:
178: public boolean containsStacks() {
179: return stacksForClasses != null;
180: }
181:
182: /**
183: * Creates a presentation-time allocation stack traces CCT for given classId.
184: *
185: * @param classId Class ID of the class whose allocation stack traces we request
186: * @param dontShowZeroLiveObjAllocPaths If true, allocation paths with zero live objects will not be included in CCT
187: * @return presentation-time CCT with allocation stack traces or null if none are available
188: */
189: public PresoObjAllocCCTNode createPresentationCCT(int classId,
190: boolean dontShowZeroLiveObjAllocPaths) {
191: if (stacksForClasses == null) {
192: return null;
193: }
194:
195: RuntimeMemoryCCTNode rootNode = stacksForClasses[classId];
196:
197: if (rootNode == null) {
198: return null;
199: }
200:
201: return createPresentationCCT(rootNode, classId,
202: dontShowZeroLiveObjAllocPaths);
203: }
204:
205: public void readFromStream(DataInputStream in) throws IOException {
206: super .readFromStream(in);
207:
208: nProfiledClasses = in.readInt();
209: classNames = new String[nProfiledClasses];
210: objectsSizePerClass = new long[nProfiledClasses];
211:
212: for (int i = 0; i < nProfiledClasses; i++) {
213: classNames[i] = in.readUTF();
214: objectsSizePerClass[i] = in.readLong();
215: }
216:
217: if (in.readBoolean()) {
218: int len = in.readInt();
219: //System.err.println("Read len: " +len);
220: stacksForClasses = new RuntimeMemoryCCTNode[len];
221:
222: for (int i = 0; i < len; i++) {
223: int type = in.readInt();
224:
225: //System.err.println(" [" + i + "] = " + type);
226: if (type != 0) {
227: stacksForClasses[i] = RuntimeMemoryCCTNode
228: .create(type);
229: stacksForClasses[i].readFromStream(in);
230: }
231: }
232:
233: if (in.readBoolean()) {
234: table = new JMethodIdTable();
235: table.readFromStream(in);
236: }
237: }
238:
239: if (LOGGER.isLoggable(Level.FINEST)) {
240: debugValues();
241: }
242: }
243:
244: //---- Serialization support
245: public void writeToStream(DataOutputStream out) throws IOException {
246: super .writeToStream(out);
247:
248: out.writeInt(nProfiledClasses);
249:
250: for (int i = 0; i < nProfiledClasses; i++) {
251: out.writeUTF(classNames[i]);
252: out.writeLong(objectsSizePerClass[i]);
253: }
254:
255: out.writeBoolean(stacksForClasses != null);
256:
257: if (stacksForClasses != null) {
258: out.writeInt(stacksForClasses.length);
259:
260: //.err.println("Stored len: " +stacksForClasses.length);
261: for (int i = 0; i < stacksForClasses.length; i++) {
262: if (stacksForClasses[i] == null) {
263: //System.err.println(" [" + i + "] = 0");
264: out.writeInt(0);
265: } else {
266: out.writeInt(stacksForClasses[i].getType());
267: //System.err.println(" [" + i + "] = " + stacksForClasses[i].getType());
268: stacksForClasses[i].writeToStream(out);
269: }
270: }
271:
272: out.writeBoolean(table != null);
273:
274: if (table != null) {
275: table.writeToStream(out);
276: }
277: }
278: }
279:
280: /**
281: * Will create presentation CCT for call stacks for given root node.
282: *
283: * @param rootNode The root node that contains allocation stack traces data
284: * @param classId Id of class whose allocations we are requesting
285: * @param dontShowZeroLiveObjAllocPaths if true, allocation paths with zero live objects will not be included
286: * @return a non-null instance of the root of presentation-time allocations CCT
287: */
288: protected abstract PresoObjAllocCCTNode createPresentationCCT(
289: RuntimeMemoryCCTNode rootNode, int classId,
290: boolean dontShowZeroLiveObjAllocPaths);
291:
292: protected abstract void performInit(ProfilerClient client,
293: MemoryCCTProvider provider)
294: throws ClientUtils.TargetAppOrVMTerminated;
295:
296: private boolean checkContainsStacks(
297: RuntimeMemoryCCTNode[] stacksForClasses) {
298: for (int i = 0; i < stacksForClasses.length; i++) {
299: RuntimeMemoryCCTNode stacksForClass = stacksForClasses[i];
300:
301: if (stacksForClass == null) {
302: continue;
303: }
304:
305: if (stacksForClass instanceof RuntimeObjAllocTermCCTNode) {
306: continue;
307: }
308:
309: if (stacksForClass instanceof RuntimeObjLivenessTermCCTNode) {
310: continue;
311: }
312:
313: return true;
314: }
315:
316: return false; // no data but term nodes or nulls
317: }
318:
319: void debugValues() {
320: LOGGER.finest("nProfiledClasses: " + nProfiledClasses); // NOI18N
321: LOGGER.finest("stacksForClasses.length: "
322: + debugLength(stacksForClasses)); // NOI18N
323: LOGGER.finest("objectsSizePerClass.length: "
324: + debugLength(objectsSizePerClass));
325: LOGGER.finest("classNames.length: " + debugLength(classNames)); // NOI18N
326: LOGGER.finest("table: "
327: + ((table == null) ? "null" : table.debug())); // NOI18N
328: }
329: }
|