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.cpu;
042:
043: import org.netbeans.lib.profiler.global.CommonConstants;
044: import org.netbeans.lib.profiler.utils.IntSorter;
045: import org.netbeans.lib.profiler.utils.LongSorter;
046: import org.netbeans.lib.profiler.utils.StringSorter;
047:
048: /**
049: * Container for CPU profiling results in the flat profile form. Supports sorting this
050: * data by each column and filtering it as many times as needed (only the external representation
051: * is changed in that case; internally data remains the same). This class is an abstract superclass
052: * of concrete subclasses in which the data is either backed by CPUCCTContainer or not.
053: *
054: * @author Misha Dmitriev
055: * @author Jiri Sedlacek
056: */
057: public abstract class FlatProfileContainer {
058: //~ Static fields/initializers -----------------------------------------------------------------------------------------------
059:
060: public static final int SORT_BY_NAME = 1;
061: public static final int SORT_BY_TIME = 2;
062: public static final int SORT_BY_SECONDARY_TIME = 3;
063: public static final int SORT_BY_INV_NUMBER = 4;
064:
065: // This variable is used to remember the timestamp (absolute or thread-CPU) used to calculate percentage
066: // numbers, between invocations of "Get results", i.e. creations of new objects of this class.
067: protected static boolean staticUsePrimaryTime;
068:
069: //~ Instance fields ----------------------------------------------------------------------------------------------------------
070:
071: protected int[] methodIds;
072: protected final char[] methodMarks;
073: protected int[] nInvocations;
074: protected float[] percent;
075: protected long[] timeInMcs0;
076: protected long[] timeInMcs1;
077: protected boolean collectingTwoTimeStamps;
078: protected long nTotalInvocations;
079: private int nRows; // Number of methods currently displayed
080: // nRows may be < totalMethods due to user setting up a filter for flat profile data
081: private int totalMethods; // Number of methods with non-zero number of invocations
082:
083: //~ Constructors -------------------------------------------------------------------------------------------------------------
084:
085: public FlatProfileContainer(long[] timeInMcs0, long[] timeInMcs1,
086: int[] nInvocations, char[] marks, int nMethods) {
087: this .timeInMcs0 = timeInMcs0;
088: this .timeInMcs1 = timeInMcs1;
089: this .nInvocations = nInvocations;
090: this .methodMarks = marks;
091: totalMethods = nMethods;
092: }
093:
094: //~ Methods ------------------------------------------------------------------------------------------------------------------
095:
096: public boolean isCollectingTwoTimeStamps() {
097: return collectingTwoTimeStamps;
098: }
099:
100: public int getMethodIdAtRow(int row) {
101: return methodIds[row];
102: }
103:
104: public abstract String getMethodNameAtRow(int row);
105:
106: public int getNInvocationsAtRow(int row) {
107: return nInvocations[row];
108: }
109:
110: public int getNRows() {
111: return nRows;
112: }
113:
114: public long getNTotalInvocations() {
115: return nTotalInvocations;
116: }
117:
118: public float getPercentAtRow(int row) {
119: return percent[row];
120: }
121:
122: public long getTimeInMcs0AtRow(int row) {
123: return timeInMcs0[row];
124: }
125:
126: public long getTimeInMcs1AtRow(int row) {
127: return timeInMcs1[row];
128: }
129:
130: public abstract double getWholeGraphNetTime0();
131:
132: public abstract double getWholeGraphNetTime1();
133:
134: public void filterOriginalData(String[] filters, int type,
135: double valueFilter) {
136: // percent = null;
137: if (((type == CommonConstants.FILTER_NONE) || (filters == null) || filters[0]
138: .equals(""))
139: && (valueFilter == 0.0d)) { // NOI18N
140: nRows = totalMethods; // Effectively removes all filtering
141:
142: return;
143: }
144:
145: // Now go through all methods and move those that don't pass filter to the end of the array
146: nRows = totalMethods;
147:
148: for (int i = 0; i < nRows; i++) {
149: if (!passedFilters(getMethodNameAtRow(i), filters, type)/*|| ! passedValueFilter (getPercentAtRow(i), valueFilter) */) {
150: int endIdx = --nRows;
151:
152: if (i >= endIdx) {
153: continue;
154: }
155:
156: // Swap the current element and the one at (nRows - 1) index
157: int tmp = methodIds[i];
158: methodIds[i] = methodIds[endIdx];
159: methodIds[endIdx] = tmp;
160:
161: long time = timeInMcs0[i];
162: timeInMcs0[i] = timeInMcs0[endIdx];
163: timeInMcs0[endIdx] = time;
164:
165: if (collectingTwoTimeStamps) {
166: time = timeInMcs1[i];
167: timeInMcs1[i] = timeInMcs1[endIdx];
168: timeInMcs1[endIdx] = time;
169: }
170:
171: tmp = nInvocations[i];
172: nInvocations[i] = nInvocations[endIdx];
173: nInvocations[endIdx] = tmp;
174: i--; // Because we've just put an unchecked element at the current position
175: }
176: }
177: }
178:
179: public void sortBy(int sortCrit, boolean order) {
180: switch (sortCrit) {
181: case SORT_BY_NAME:
182: sortDataByMethodName(order);
183:
184: break;
185: case SORT_BY_TIME:
186: sortDataByTime(true, order);
187:
188: break;
189: case SORT_BY_SECONDARY_TIME:
190: sortDataByTime(false, order);
191:
192: break;
193: case SORT_BY_INV_NUMBER:
194: sortDataByInvNumber(order);
195:
196: break;
197: }
198: }
199:
200: protected void removeZeroInvocationEntries() {
201: nRows = 0;
202:
203: // Note that at index 0 we always have a "Thread" quazi-method, that we shouldn't take into account
204: for (int i = 1; i < totalMethods; i++) {
205: if (nInvocations[i] > 0) {
206: nRows++;
207: }
208: }
209:
210: long[] oldTime0 = timeInMcs0;
211: long[] oldTime1 = timeInMcs1;
212: int[] oldNInvocations = nInvocations;
213:
214: timeInMcs0 = new long[nRows];
215:
216: if (collectingTwoTimeStamps) {
217: timeInMcs1 = new long[nRows];
218: }
219:
220: nInvocations = new int[nRows];
221: methodIds = new int[nRows];
222:
223: int k = 0;
224:
225: for (int i = 1; i < totalMethods; i++) {
226: if (oldNInvocations[i] > 0) {
227: long time = oldTime0[i];
228:
229: if (time < 0) {
230: time = 0; // Replace possible negative time entries with 0
231: }
232:
233: timeInMcs0[k] = time;
234:
235: if (collectingTwoTimeStamps) {
236: time = oldTime1[i];
237:
238: if (time < 0) {
239: time = 0;
240: }
241:
242: timeInMcs1[k] = time;
243: }
244:
245: nInvocations[k] = oldNInvocations[i];
246: nTotalInvocations += oldNInvocations[i];
247: methodIds[k] = i;
248: k++;
249: }
250: }
251:
252: totalMethods = nRows;
253: }
254:
255: private void calculatePercent(boolean usePrimaryTime) {
256: percent = new float[nRows];
257:
258: double wholeNetTime = getWholeGraphNetTime0();
259: long[] tpm = timeInMcs0;
260:
261: if (collectingTwoTimeStamps && (!usePrimaryTime)) {
262: wholeNetTime = getWholeGraphNetTime1();
263: tpm = timeInMcs1;
264: }
265:
266: for (int i = 0; i < nRows; i++) {
267: percent[i] = (float) ((wholeNetTime > 0) ? ((double) tpm[i]
268: / wholeNetTime * 100) : 0);
269: }
270:
271: staticUsePrimaryTime = usePrimaryTime;
272: }
273:
274: private boolean passedFilter(String value, String filter, int type) {
275: // Case sensitive comparison:
276: /*switch (type) {
277: case CommonConstants.FILTER_STARTS_WITH:
278: return value.startsWith(filter);
279: case CommonConstants.FILTER_CONTAINS:
280: return value.indexOf(filter) != -1;
281: case CommonConstants.FILTER_ENDS_WITH:
282: return value.endsWith(filter);
283: case CommonConstants.FILTER_EQUALS:
284: return value.equals(filter);
285: case CommonConstants.FILTER_REGEXP:
286: return value.matches(filter);
287: }*/
288:
289: // Case insensitive comparison (except regexp):
290: switch (type) {
291: case CommonConstants.FILTER_STARTS_WITH:
292: return value.regionMatches(true, 0, filter, 0, filter
293: .length()); // case insensitive startsWith, optimized
294: case CommonConstants.FILTER_CONTAINS:
295: return value.toLowerCase().indexOf(filter.toLowerCase()) != -1; // case insensitive indexOf, NOT OPTIMIZED
296: case CommonConstants.FILTER_ENDS_WITH:
297:
298: // case insensitive endsWith, optimized
299: return value.regionMatches(true, value.length()
300: - filter.length(), filter, 0, filter.length());
301: case CommonConstants.FILTER_EQUALS:
302: return value.equalsIgnoreCase(filter); // case insensitive equals
303: case CommonConstants.FILTER_REGEXP:
304: return value.matches(filter); // still case sensitive!
305: }
306:
307: return false;
308: }
309:
310: private boolean passedFilters(String value, String[] filters,
311: int type) {
312: for (int i = 0; i < filters.length; i++) {
313: if (passedFilter(value, filters[i], type)) {
314: return true;
315: }
316: }
317:
318: return false;
319: }
320:
321: private void sortDataByInvNumber(boolean sortOrder) {
322: if ((percent == null) || (percent.length != nRows)) {
323: calculatePercent(staticUsePrimaryTime);
324: }
325:
326: (new IntSorter(nInvocations, 0, nRows) {
327: protected void swap(int a, int b) {
328: super .swap(a, b);
329:
330: long tmp;
331: tmp = timeInMcs0[a];
332: timeInMcs0[a] = timeInMcs0[b];
333: timeInMcs0[b] = tmp;
334:
335: if (collectingTwoTimeStamps) {
336: tmp = timeInMcs1[a];
337: timeInMcs1[a] = timeInMcs1[b];
338: timeInMcs1[b] = tmp;
339: }
340:
341: int itmp = methodIds[a];
342: methodIds[a] = methodIds[b];
343: methodIds[b] = itmp;
344:
345: if (percent != null) {
346: float ftmp = percent[a];
347: percent[a] = percent[b];
348: percent[b] = ftmp;
349: }
350: }
351: }).sort(sortOrder);
352: }
353:
354: private void sortDataByMethodName(boolean sortOrder) {
355: String[] fullMethodNames = new String[nRows];
356:
357: if ((percent == null) || (percent.length != nRows)) {
358: calculatePercent(staticUsePrimaryTime);
359: }
360:
361: for (int i = 0; i < nRows; i++) {
362: fullMethodNames[i] = getMethodNameAtRow(i);
363: }
364:
365: (new StringSorter(fullMethodNames, 0, nRows) {
366: protected void swap(int a, int b) {
367: super .swap(a, b);
368:
369: long tmp;
370: tmp = timeInMcs0[a];
371: timeInMcs0[a] = timeInMcs0[b];
372: timeInMcs0[b] = tmp;
373:
374: if (collectingTwoTimeStamps) {
375: tmp = timeInMcs1[a];
376: timeInMcs1[a] = timeInMcs1[b];
377: timeInMcs1[b] = tmp;
378: }
379:
380: int itmp = methodIds[a];
381: methodIds[a] = methodIds[b];
382: methodIds[b] = itmp;
383: itmp = nInvocations[a];
384: nInvocations[a] = nInvocations[b];
385: nInvocations[b] = itmp;
386:
387: if (percent != null) {
388: float ftmp = percent[a];
389: percent[a] = percent[b];
390: percent[b] = ftmp;
391: }
392: }
393: }).sort(sortOrder);
394: }
395:
396: private void sortDataByTime(boolean usePrimaryTime,
397: boolean sortOrder) {
398: long[] tpmA = null;
399: long[] tpmB = null;
400:
401: // Percentage is recalculated every time, since it depends on whether primary/secondary time is used
402: if ((percent == null)
403: || (usePrimaryTime != staticUsePrimaryTime)
404: || (percent.length != nRows)) {
405: calculatePercent(usePrimaryTime);
406: }
407:
408: if (collectingTwoTimeStamps) {
409: if (usePrimaryTime) {
410: tpmA = timeInMcs0;
411: tpmB = timeInMcs1;
412: } else {
413: tpmA = timeInMcs1;
414: tpmB = timeInMcs0;
415: }
416: } else {
417: tpmA = timeInMcs0;
418: }
419:
420: final long[] tpmBF = tpmB;
421:
422: (new LongSorter(tpmA, 0, nRows) {
423: protected void swap(int a, int b) {
424: super .swap(a, b);
425:
426: long tmp;
427:
428: if (collectingTwoTimeStamps) {
429: tmp = tpmBF[a];
430: tpmBF[a] = tpmBF[b];
431: tpmBF[b] = tmp;
432: }
433:
434: int itmp = methodIds[a];
435: methodIds[a] = methodIds[b];
436: methodIds[b] = itmp;
437: itmp = nInvocations[a];
438: nInvocations[a] = nInvocations[b];
439: nInvocations[b] = itmp;
440:
441: if (percent != null) {
442: float ftmp = percent[a];
443: percent[a] = percent[b];
444: percent[b] = ftmp;
445: }
446: }
447: }).sort(sortOrder);
448:
449: // Next, sort the methods with zero time by the number of invocations
450: int len = nRows - 1;
451:
452: while ((len >= 0) && (tpmA[len] == 0)) {
453: len--;
454: }
455:
456: if (len < (nRows - 1)) {
457: (new IntSorter(nInvocations, len + 1, nRows - len - 1) {
458: protected void swap(int a, int b) {
459: super .swap(a, b);
460:
461: long tmp;
462:
463: if (collectingTwoTimeStamps) {
464: tmp = tpmBF[a];
465: tpmBF[a] = tpmBF[b];
466: tpmBF[b] = tmp;
467: }
468:
469: int itmp = methodIds[a];
470: methodIds[a] = methodIds[b];
471: methodIds[b] = itmp;
472: }
473: }).sort(sortOrder);
474: }
475: }
476: }
|