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 java.io.DataInputStream;
044: import java.io.DataOutputStream;
045: import java.io.IOException;
046: import java.util.ArrayList;
047: import java.util.HashMap;
048: import java.util.Iterator;
049: import java.util.Map;
050:
051: /**
052: * Class representing a difference between two snapshots,
053: * diffing only values available in AllocMemoryResultsSnapshot
054: *
055: * @author Tomas Hurka
056: * @author Jiri Sedlacek
057: */
058: public class AllocMemoryResultsDiff extends AllocMemoryResultsSnapshot {
059: //~ Instance fields ----------------------------------------------------------------------------------------------------------
060:
061: private String[] classNames;
062: private int[] objectsCounts;
063: private long[] objectsSizePerClass;
064: private int nClasses;
065: private long maxObjectsSizePerClassDiff;
066: private long minObjectsSizePerClassDiff;
067:
068: //~ Constructors -------------------------------------------------------------------------------------------------------------
069:
070: public AllocMemoryResultsDiff(AllocMemoryResultsSnapshot snapshot1,
071: AllocMemoryResultsSnapshot snapshot2) {
072: computeDiff(snapshot1, snapshot2);
073: }
074:
075: //~ Methods ------------------------------------------------------------------------------------------------------------------
076:
077: public long getBeginTime() {
078: return -1;
079: }
080:
081: public String getClassName(int classId) {
082: return null;
083: }
084:
085: public String[] getClassNames() {
086: return classNames;
087: }
088:
089: public JMethodIdTable getJMethodIdTable() {
090: return null;
091: }
092:
093: public long getMaxObjectsSizePerClassDiff() {
094: return maxObjectsSizePerClassDiff;
095: }
096:
097: public long getMinObjectsSizePerClassDiff() {
098: return minObjectsSizePerClassDiff;
099: }
100:
101: public int getNProfiledClasses() {
102: return nClasses;
103: }
104:
105: public int[] getObjectsCounts() {
106: return objectsCounts;
107: }
108:
109: public long[] getObjectsSizePerClass() {
110: return objectsSizePerClass;
111: }
112:
113: public long getTimeTaken() {
114: return -1;
115: }
116:
117: public boolean containsStacks() {
118: return false;
119: }
120:
121: public PresoObjAllocCCTNode createPresentationCCT(int classId,
122: boolean dontShowZeroLiveObjAllocPaths) {
123: return null;
124: }
125:
126: public void readFromStream(DataInputStream in) throws IOException {
127: throw new UnsupportedOperationException(
128: "Persistence not supported for snapshot comparison"); // NOI18N
129: }
130:
131: //---- Serialization support
132: public void writeToStream(DataOutputStream out) throws IOException {
133: throw new UnsupportedOperationException(
134: "Persistence not supported for snapshot comparison"); // NOI18N
135: }
136:
137: protected PresoObjAllocCCTNode createPresentationCCT(
138: RuntimeMemoryCCTNode rootNode, int classId,
139: boolean dontShowZeroLiveObjAllocPaths) {
140: return null;
141: }
142:
143: private void computeDiff(AllocMemoryResultsSnapshot snapshot1,
144: AllocMemoryResultsSnapshot snapshot2) {
145: // must detect the minimum, same approach as in SnapshotAllocResultsPanel.fetchResultsFromSnapshot()
146: int s1nClasses = Math.min(snapshot1.getNProfiledClasses(),
147: snapshot1.getObjectsCounts().length);
148: s1nClasses = Math.min(s1nClasses, snapshot1
149: .getObjectsSizePerClass().length);
150:
151: int s2nClasses = Math.min(snapshot2.getNProfiledClasses(),
152: snapshot2.getObjectsCounts().length);
153: s2nClasses = Math.min(s2nClasses, snapshot2
154: .getObjectsSizePerClass().length);
155:
156: // temporary cache for creating diff
157: HashMap classNamesIdxMap = new HashMap(s1nClasses);
158: ArrayList objCountsArr = new ArrayList(s1nClasses);
159: ArrayList objSizesArr = new ArrayList(s1nClasses);
160:
161: // fill the cache with negative values from snapshot1
162: String[] s1ClassNames = snapshot1.getClassNames();
163: int[] s1ObjectsCount = snapshot1.getObjectsCounts();
164: long[] s1ObjectsSizes = snapshot1.getObjectsSizePerClass();
165:
166: for (int i = 0; i < s1nClasses; i++) {
167: Integer classIdx = (Integer) classNamesIdxMap
168: .get(s1ClassNames[i]);
169:
170: if (classIdx != null) { // duplicate classname - add objCountsArr and objSizesArr to original classname
171:
172: int index = classIdx.intValue();
173: Integer objCount = (Integer) objCountsArr.get(index);
174: Long objSize = (Long) objSizesArr.get(index);
175:
176: objCountsArr.set(index, new Integer(objCount.intValue()
177: - s1ObjectsCount[i]));
178: objSizesArr.set(index, new Long(objSize.longValue()
179: - s1ObjectsSizes[i]));
180: } else {
181: classNamesIdxMap.put(s1ClassNames[i], new Integer(
182: objCountsArr.size()));
183: objCountsArr.add(new Integer(0 - s1ObjectsCount[i]));
184: objSizesArr.add(new Long(0 - s1ObjectsSizes[i]));
185: }
186: }
187:
188: // create diff using values from snapshot2
189: String[] s2ClassNames = snapshot2.getClassNames();
190: int[] s2ObjectsCount = snapshot2.getObjectsCounts();
191: long[] s2ObjectsSizes = snapshot2.getObjectsSizePerClass();
192:
193: for (int i = 0; i < s2nClasses; i++) {
194: String className = s2ClassNames[i];
195: int objectsCount = s2ObjectsCount[i];
196: long objectsSize = s2ObjectsSizes[i];
197:
198: Integer classIdx = (Integer) classNamesIdxMap
199: .get(className);
200: int classIndex;
201:
202: if (classIdx != null) {
203: // class already present in snapshot1
204: classIndex = classIdx.intValue();
205:
206: if ((objectsCount != 0)
207: || (((Integer) objCountsArr.get(classIndex))
208: .intValue() != 0)) { // Do not add classes not displayed in compared snapshots (zero instances number)
209: objCountsArr.set(classIndex, new Integer(
210: ((Integer) objCountsArr.get(classIndex))
211: .intValue()
212: + objectsCount));
213: objSizesArr.set(classIndex, new Long(
214: ((Long) objSizesArr.get(classIndex))
215: .longValue()
216: + objectsSize));
217: } else {
218: classNamesIdxMap.remove(className); // Remove classname that should not be displayed
219: }
220: } else {
221: // class not present in snapshot1
222: if (objectsCount != 0) { // Do not add classes not displayed in compared snapshots (zero instances number)
223: classNamesIdxMap.put(className, new Integer(
224: objCountsArr.size()));
225: objCountsArr.add(new Integer(objectsCount));
226: objSizesArr.add(new Long(objectsSize));
227: }
228: }
229: }
230:
231: // move the diff to instance variables
232: nClasses = classNamesIdxMap.size();
233: classNames = new String[nClasses];
234: objectsCounts = new int[nClasses];
235: objectsSizePerClass = new long[nClasses];
236: minObjectsSizePerClassDiff = Long.MAX_VALUE;
237: maxObjectsSizePerClassDiff = Long.MIN_VALUE;
238:
239: Iterator classNamesIter = classNamesIdxMap.entrySet()
240: .iterator();
241: int index = 0;
242:
243: while (classNamesIter.hasNext()) {
244: Map.Entry entry = (Map.Entry) classNamesIter.next();
245: String className = (String) entry.getKey();
246: int classIndex = ((Integer) entry.getValue()).intValue();
247:
248: classNames[index] = className;
249: objectsCounts[index] = ((Integer) objCountsArr
250: .get(classIndex)).intValue();
251: objectsSizePerClass[index] = ((Long) objSizesArr
252: .get(classIndex)).longValue();
253:
254: minObjectsSizePerClassDiff = Math.min(
255: minObjectsSizePerClassDiff,
256: objectsSizePerClass[index]);
257: maxObjectsSizePerClassDiff = Math.max(
258: maxObjectsSizePerClassDiff,
259: objectsSizePerClass[index]);
260:
261: index++;
262: }
263:
264: if ((minObjectsSizePerClassDiff > 0)
265: && (maxObjectsSizePerClassDiff > 0)) {
266: minObjectsSizePerClassDiff = 0;
267: } else if ((minObjectsSizePerClassDiff < 0)
268: && (maxObjectsSizePerClassDiff < 0)) {
269: maxObjectsSizePerClassDiff = 0;
270: }
271: }
272: }
|