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.results.CCTNode;
046: import org.netbeans.lib.profiler.utils.StringUtils;
047: import org.netbeans.lib.profiler.utils.formatting.MethodNameFormatterFactory;
048: import java.util.ResourceBundle;
049:
050: /**
051: * Presentation-Time Memory Profiling Calling Context Tree (CCT) Node. Used "as is" for Object Allocation
052: * profiling, and used as a base class for PresoObjLivenessCCTNode. Contains additional functionality
053: * to map jmethodIDs (integer identifiers automatically assigned to methods by the JVM, that are returned
054: * by stack trace routines) to method names. This includes sending a request to the server to get method
055: * names/signatures for given jmethodIDs.
056: *
057: * @author Tomas Hurka
058: * @author Misha Dmitriev
059: */
060: public class PresoObjAllocCCTNode implements CCTNode {
061: //~ Static fields/initializers -----------------------------------------------------------------------------------------------
062:
063: private static final String VM_ALLOC_CLASS = "org.netbeans.lib.profiler.server.ProfilerRuntimeMemory"; // NOI18N
064: private static final String VM_ALLOC_METHOD = "traceVMObjectAlloc"; // NOI18N
065: private static final String VM_ALLOC_TEXT = ResourceBundle
066: .getBundle(
067: "org.netbeans.lib.profiler.results.memory.Bundle") // NOI18N
068: .getString("PresoObjAllocCCTNode_VMAllocMsg"); // NOI18N
069: public static final int SORT_BY_NAME = 1;
070: public static final int SORT_BY_ALLOC_OBJ_SIZE = 2;
071: public static final int SORT_BY_ALLOC_OBJ_NUMBER = 3;
072:
073: //~ Instance fields ----------------------------------------------------------------------------------------------------------
074:
075: public long nCalls;
076: public long totalObjSize;
077: PresoObjAllocCCTNode parent;
078: String className;
079: String methodName;
080: String methodSig;
081: String nodeName;
082: PresoObjAllocCCTNode[] children;
083: int methodId;
084:
085: //~ Constructors -------------------------------------------------------------------------------------------------------------
086:
087: protected PresoObjAllocCCTNode(RuntimeMemoryCCTNode rtNode) {
088: methodId = rtNode.methodId;
089:
090: if (rtNode instanceof RuntimeObjAllocTermCCTNode) {
091: RuntimeObjAllocTermCCTNode rtTermNode = (RuntimeObjAllocTermCCTNode) rtNode;
092: nCalls += rtTermNode.nCalls;
093: totalObjSize += rtTermNode.totalObjSize;
094: }
095: }
096:
097: //~ Methods ------------------------------------------------------------------------------------------------------------------
098:
099: public static void getNamesForMethodIdsFromVM(
100: ProfilerClient profilerClient,
101: RuntimeMemoryCCTNode[] allStackRoots)
102: throws ClientUtils.TargetAppOrVMTerminated {
103: if (allStackRoots == null) {
104: return; // Can happen if this is called too early
105: }
106:
107: for (int i = 0; i < allStackRoots.length; i++) {
108: if (allStackRoots[i] != null) {
109: checkMethodIdForNodeFromVM(allStackRoots[i]);
110: }
111: }
112:
113: JMethodIdTable.getDefault()
114: .getNamesForMethodIds(profilerClient);
115: }
116:
117: public static PresoObjAllocCCTNode createPresentationCCTFromSnapshot(
118: MemoryResultsSnapshot snapshot,
119: RuntimeMemoryCCTNode rootRuntimeNode, String classTypeName) {
120: PresoObjAllocCCTNode rootNode = generateMirrorNode(rootRuntimeNode);
121: assignNamesToNodesFromSnapshot(snapshot, rootNode,
122: classTypeName);
123:
124: return rootNode;
125: }
126:
127: public static PresoObjAllocCCTNode createPresentationCCTFromVM(
128: ProfilerClient profilerClient,
129: RuntimeMemoryCCTNode rootRuntimeNode, String classTypeName)
130: throws ClientUtils.TargetAppOrVMTerminated {
131: PresoObjAllocCCTNode rootNode = generateMirrorNode(rootRuntimeNode);
132: assignNamesToNodesFromVM(profilerClient, rootNode,
133: classTypeName);
134:
135: return rootNode;
136: }
137:
138: public CCTNode getChild(int index) {
139: if (index < children.length) {
140: return children[index];
141: } else {
142: return null;
143: }
144: }
145:
146: public CCTNode[] getChildren() {
147: return children;
148: }
149:
150: public int getIndexOfChild(Object child) {
151: for (int i = 0; i < children.length; i++) {
152: if ((PresoObjAllocCCTNode) child == children[i]) {
153: return i;
154: }
155: }
156:
157: return -1;
158: }
159:
160: public String[] getMethodClassNameAndSig() {
161: return new String[] { className, methodName, methodSig };
162: }
163:
164: public int getNChildren() {
165: if (children != null) {
166: return children.length;
167: } else {
168: return 0;
169: }
170: }
171:
172: public String getNodeName() {
173: if (methodId != 0) {
174: return nodeName;
175: } else {
176: return className;
177: }
178: }
179:
180: public CCTNode getParent() {
181: return parent;
182: }
183:
184: public void sortChildren(int sortBy, boolean sortOrder) {
185: int nChildren = getNChildren();
186:
187: if (nChildren == 0) {
188: return;
189: }
190:
191: for (int i = 0; i < nChildren; i++) {
192: children[i].sortChildren(sortBy, sortOrder);
193: }
194:
195: if (nChildren > 1) {
196: switch (sortBy) {
197: case SORT_BY_NAME:
198: sortChildrenByName(sortOrder);
199:
200: break;
201: case SORT_BY_ALLOC_OBJ_SIZE:
202: sortChildrenByAllocObjSize(sortOrder);
203:
204: break;
205: case SORT_BY_ALLOC_OBJ_NUMBER:
206: sortChildrenByAllocObjNumber(sortOrder);
207:
208: break;
209: }
210: }
211: }
212:
213: public String toString() {
214: return getNodeName();
215: }
216:
217: protected static void assignNamesToNodesFromSnapshot(
218: MemoryResultsSnapshot snapshot,
219: PresoObjAllocCCTNode rootNode, String classTypeName) {
220: rootNode.className = StringUtils
221: .userFormClassName(classTypeName);
222: rootNode
223: .setFullClassAndMethodInfo(snapshot.getJMethodIdTable());
224: }
225:
226: protected static void assignNamesToNodesFromVM(
227: ProfilerClient profilerClient,
228: PresoObjAllocCCTNode rootNode, String classTypeName)
229: throws ClientUtils.TargetAppOrVMTerminated {
230: JMethodIdTable.getDefault()
231: .getNamesForMethodIds(profilerClient);
232: rootNode.className = StringUtils
233: .userFormClassName(classTypeName);
234: rootNode.setFullClassAndMethodInfo(JMethodIdTable.getDefault());
235: }
236:
237: protected static PresoObjAllocCCTNode generateMirrorNode(
238: RuntimeMemoryCCTNode rtNode) {
239: PresoObjAllocCCTNode this Node = new PresoObjAllocCCTNode(rtNode);
240: Object nodeChildren = rtNode.children;
241:
242: if (nodeChildren != null) {
243: if (nodeChildren instanceof RuntimeMemoryCCTNode) {
244: this Node.children = new PresoObjAllocCCTNode[1];
245:
246: PresoObjAllocCCTNode child = generateMirrorNode((RuntimeMemoryCCTNode) nodeChildren);
247: this Node.children[0] = child;
248: child.parent = this Node;
249: this Node.nCalls += child.nCalls;
250: this Node.totalObjSize += child.totalObjSize;
251: } else {
252: RuntimeMemoryCCTNode[] ar = (RuntimeMemoryCCTNode[]) nodeChildren;
253: int nChildren = ar.length;
254:
255: if (nChildren > 0) {
256: this Node.children = new PresoObjAllocCCTNode[nChildren];
257:
258: for (int i = 0; i < nChildren; i++) {
259: PresoObjAllocCCTNode child = generateMirrorNode(ar[i]);
260: this Node.children[i] = child;
261: child.parent = this Node;
262: this Node.nCalls += child.nCalls;
263: this Node.totalObjSize += child.totalObjSize;
264: }
265: }
266: }
267: }
268:
269: return this Node;
270: }
271:
272: protected boolean setFullClassAndMethodInfo(
273: JMethodIdTable methodIdTable) {
274: if (methodId != 0) {
275: JMethodIdTable.JMethodIdTableEntry entry = methodIdTable
276: .getEntry(methodId);
277: className = entry.className.replace('/', '.'); // NOI18N
278: methodName = entry.methodName;
279: methodSig = entry.methodSig;
280:
281: if (VM_ALLOC_CLASS.equals(className)
282: && VM_ALLOC_METHOD.equals(methodName)) { // special handling of ProfilerRuntimeMemory.traceVMObjectAlloc
283: nodeName = VM_ALLOC_TEXT;
284: } else {
285: nodeName = MethodNameFormatterFactory.getDefault()
286: .getFormatter().formatMethodName(className,
287: methodName, methodSig).toFormatted();
288: }
289: }
290:
291: // If any object allocations that happen in our own code are caught (which shouldn't happen),
292: // make sure to conceal this data here.
293: boolean this NodeOk = !className
294: .equals("org.netbeans.lib.profiler.server.ProfilerServer"); // NOI18N
295: boolean childrenOk = true;
296:
297: if (children != null) {
298: for (int i = 0; i < children.length; i++) {
299: if (!children[i]
300: .setFullClassAndMethodInfo(methodIdTable)) {
301: childrenOk = false;
302: children[i] = null;
303: }
304: }
305: }
306:
307: if (!childrenOk) {
308: // Determine the number of non-null children and create a new children array
309: int newLen = 0;
310:
311: for (int i = 0; i < children.length; i++) {
312: newLen += ((children[i] != null) ? 1 : 0);
313: }
314:
315: boolean hasNonNullChildren = (newLen > 0);
316:
317: if (!hasNonNullChildren) {
318: children = null;
319: } else {
320: PresoObjAllocCCTNode[] newChildren = new PresoObjAllocCCTNode[newLen];
321: int idx = 0;
322:
323: for (int i = 0; i < children.length; i++) {
324: if (children[i] != null) {
325: newChildren[idx++] = children[i];
326: }
327: }
328:
329: children = newChildren;
330: }
331:
332: if ((methodName == null)
333: || (methodName.equals("main") && methodSig // NOI18N
334: .equals("([Ljava/lang/String;)V"))) { // NOI18N
335:
336: return true;
337: } else {
338: return hasNonNullChildren;
339: }
340: } else {
341: return this NodeOk;
342: }
343: }
344:
345: protected static void checkMethodIdForNodeFromVM(
346: RuntimeMemoryCCTNode rtNode) {
347: if (rtNode.methodId != 0) {
348: JMethodIdTable.getDefault().checkMethodId(rtNode.methodId);
349: }
350:
351: Object nodeChildren = rtNode.children;
352:
353: if (nodeChildren != null) {
354: if (nodeChildren instanceof RuntimeMemoryCCTNode) {
355: checkMethodIdForNodeFromVM((RuntimeMemoryCCTNode) nodeChildren);
356: } else {
357: RuntimeMemoryCCTNode[] ar = (RuntimeMemoryCCTNode[]) nodeChildren;
358:
359: for (int i = 0; i < ar.length; i++) {
360: checkMethodIdForNodeFromVM(ar[i]);
361: }
362: }
363: }
364: }
365:
366: protected void sortChildrenByAllocObjNumber(boolean sortOrder) {
367: int len = children.length;
368: long[] values = new long[len];
369:
370: for (int i = 0; i < len; i++) {
371: values[i] = children[i].nCalls;
372: }
373:
374: sortLongs(values, sortOrder);
375: }
376:
377: protected void sortChildrenByAllocObjSize(boolean sortOrder) {
378: int len = children.length;
379: long[] values = new long[len];
380:
381: for (int i = 0; i < len; i++) {
382: values[i] = children[i].totalObjSize;
383: }
384:
385: sortLongs(values, sortOrder);
386: }
387:
388: protected void sortChildrenByName(boolean sortOrder) {
389: int len = children.length;
390: String[] values = new String[len];
391:
392: for (int i = 0; i < len; i++) {
393: values[i] = children[i].getNodeName();
394: }
395:
396: sortStrings(values, sortOrder);
397: }
398:
399: protected void sortFloats(float[] values, boolean sortOrder) {
400: int len = values.length;
401:
402: // Just the insertion sort - we will never get really large arrays here
403: for (int i = 0; i < len; i++) {
404: for (int j = i; (j > 0)
405: && ((sortOrder == false) ? (values[j - 1] < values[j])
406: : (values[j - 1] > values[j])); j--) {
407: float tmp = values[j];
408: values[j] = values[j - 1];
409: values[j - 1] = tmp;
410:
411: PresoObjAllocCCTNode tmpCh = children[j];
412: children[j] = children[j - 1];
413: children[j - 1] = tmpCh;
414: }
415: }
416: }
417:
418: protected void sortInts(int[] values, boolean sortOrder) {
419: int len = values.length;
420:
421: // Just the insertion sort - we will never get really large arrays here
422: for (int i = 0; i < len; i++) {
423: for (int j = i; (j > 0)
424: && ((sortOrder == false) ? (values[j - 1] < values[j])
425: : (values[j - 1] > values[j])); j--) {
426: int tmp = values[j];
427: values[j] = values[j - 1];
428: values[j - 1] = tmp;
429:
430: PresoObjAllocCCTNode tmpCh = children[j];
431: children[j] = children[j - 1];
432: children[j - 1] = tmpCh;
433: }
434: }
435: }
436:
437: protected void sortLongs(long[] values, boolean sortOrder) {
438: int len = values.length;
439:
440: // Just the insertion sort - we will never get really large arrays here
441: for (int i = 0; i < len; i++) {
442: for (int j = i; (j > 0)
443: && ((sortOrder == false) ? (values[j - 1] < values[j])
444: : (values[j - 1] > values[j])); j--) {
445: long tmp = values[j];
446: values[j] = values[j - 1];
447: values[j - 1] = tmp;
448:
449: PresoObjAllocCCTNode tmpCh = children[j];
450: children[j] = children[j - 1];
451: children[j - 1] = tmpCh;
452: }
453: }
454: }
455:
456: protected void sortStrings(String[] values, boolean sortOrder) {
457: int len = values.length;
458:
459: // Just the insertion sort - we will never get really large arrays here
460: for (int i = 0; i < len; i++) {
461: for (int j = i; (j > 0)
462: && ((sortOrder == false) ? (values[j - 1]
463: .compareTo(values[j]) < 0) : (values[j - 1]
464: .compareTo(values[j]) > 0)); j--) {
465: String tmp = values[j];
466: values[j] = values[j - 1];
467: values[j - 1] = tmp;
468:
469: PresoObjAllocCCTNode tmpCh = children[j];
470: children[j] = children[j - 1];
471: children[j - 1] = tmpCh;
472: }
473: }
474: }
475: }
|