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.threads;
042:
043: import org.netbeans.lib.profiler.client.MonitoredData;
044: import org.netbeans.lib.profiler.results.DataManager;
045: import java.util.Hashtable;
046:
047: /**
048: * A class that holds data about threads history (state changes) during a
049: * profiling session. It consumes/processes data obtained from the server via the
050: * MonitoredData class, but translates them into data structures more efficient for
051: * presentation. A listener is provided for those who want to be notified about
052: * newly arrived data.
053: *
054: * @author Jiri Sedlacek
055: * @author Ian Formanek
056: * @author Misha Dmitriev
057: */
058: public class ThreadsDataManager extends DataManager {
059: //~ Instance fields ----------------------------------------------------------------------------------------------------------
060:
061: private Hashtable idToIndex = new Hashtable(30);
062: private ThreadData[] threadData; // Per-thread array of points at which thread's state changes
063: private boolean supportsSleepingState = true;
064: private boolean threadsMonitoringEnabled = true;
065: private long endTime; // Timestamp of threadData end
066: private long startTime; // Timestamp of threadData start
067:
068: //~ Constructors -------------------------------------------------------------------------------------------------------------
069:
070: /**
071: * Creates a new instance of ThreadsDataManager
072: */
073: public ThreadsDataManager() {
074: reset();
075: }
076:
077: //~ Methods ------------------------------------------------------------------------------------------------------------------
078:
079: /**
080: * Returns the timestamp representing end time of collecting threadData (timestamp of last valid threadData record).
081: */
082: public synchronized long getEndTime() {
083: return endTime;
084: }
085:
086: // --- Public interface ---------------------------------------------------------------
087:
088: /**
089: * Returns the timestamp representing start time of collecting threadData (timestamp of first threadData record).
090: */
091: public synchronized long getStartTime() {
092: return startTime;
093: }
094:
095: public synchronized void setSupportsSleepingStateMonitoring(
096: boolean supportsSleepingState) {
097: this .supportsSleepingState = supportsSleepingState;
098: }
099:
100: public synchronized String getThreadClassName(int index) {
101: return threadData[index].getClassName();
102: }
103:
104: public synchronized ThreadData getThreadData(int index) {
105: return threadData[index];
106: }
107:
108: public synchronized String getThreadName(int index) {
109: return threadData[index].getName();
110: }
111:
112: /**
113: * Returns the number of currently monitored threads
114: */
115: public synchronized int getThreadsCount() {
116: return threadData.length;
117: }
118:
119: public synchronized void setThreadsMonitoringEnabled(boolean enabled) {
120: if (threadsMonitoringEnabled == enabled) {
121: return;
122: }
123:
124: threadsMonitoringEnabled = enabled;
125:
126: if (!threadsMonitoringEnabled) { // clear accumulated data, except thread ids and names
127:
128: for (int i = 0; i < threadData.length; i++) {
129: threadData[i].clearStates();
130: }
131: }
132: }
133:
134: /**
135: * Returns <CODE>true</CODE> if there are some monitored threads
136: */
137: public synchronized boolean hasData() {
138: return (getThreadsCount() != 0);
139: }
140:
141: /**
142: * Convert the data received from the server on this iteration into the internal compressed format,
143: * and notify listeners
144: */
145: public synchronized void processData(MonitoredData monitoredData) {
146: //debugData ();
147: if (monitoredData.getNThreads() == 0) {
148: return;
149: }
150:
151: int max = threadData.length;
152: int newThreadsNum = monitoredData.getNNewThreads();
153:
154: // Set the timestamp of first data
155: if (max == 0) {
156: startTime = monitoredData.getStateTimestamps()[0];
157: }
158:
159: // 1. process newly created threads
160: if (newThreadsNum > 0) {
161: addNewThreads(monitoredData.getNewThreadNames(),
162: monitoredData.getNewThreadClassNames());
163:
164: int[] newIds = monitoredData.getNewThreadIds();
165:
166: for (int i = 0; i < newThreadsNum; i++) {
167: idToIndex.put(new Integer(newIds[i]), new Integer(i
168: + max)); // add new threads to the end of the array
169: }
170: }
171:
172: // 2. process all threads data
173: if (threadsMonitoringEnabled) {
174: int[] threadIds = monitoredData.getThreadIds();
175: long[] timestamps = monitoredData.getStateTimestamps();
176: byte[][] states = monitoredData.getThreadStates();
177: int nThreads = monitoredData.getNThreads();
178: int nStates = monitoredData.getNThreadStates();
179:
180: if (nStates == 0) {
181: return;
182: }
183:
184: for (int threadIdx = 0; threadIdx < nThreads; threadIdx++) {
185: Integer intIndex = (Integer) idToIndex.get(new Integer(
186: threadIds[threadIdx]));
187: int index = intIndex.intValue();
188: byte[] threadStates = states[threadIdx];
189: ThreadData tData = threadData[index];
190:
191: for (int stampIdx = 0; stampIdx < nStates; stampIdx++) {
192: long timeStamp = timestamps[stampIdx];
193: byte state = threadStates[stampIdx];
194: byte lastState = tData.getLastState();
195:
196: if ((lastState == ThreadData.NO_STATE)
197: || (lastState != state)) {
198: tData.add(timeStamp, state);
199: }
200: }
201: }
202:
203: endTime = timestamps[nStates - 1]; // end timestamp is updated
204: fireDataChanged(); // all listeners are notified about threadData change */
205: } else {
206: // in this mode we are only tracking thread ids and names, not thread states
207: }
208: }
209:
210: /**
211: * Resets the threadData - clears timestamps and threadData store.
212: */
213: public synchronized void reset() {
214: startTime = 0;
215: endTime = 0;
216: threadData = new ThreadData[0];
217: idToIndex.clear();
218: fireDataReset(); // all listeners are notified about threadData change
219: }
220:
221: public synchronized boolean supportsSleepingStateMonitoring() {
222: return supportsSleepingState;
223: }
224:
225: // --- Private implementation ---------------------------------------------------------------
226:
227: /**
228: * Enlarges internal array of threads' threadData stores according to newly created threads
229: */
230: private void addNewThreads(String[] newNames, String[] newClassNames) {
231: int newSize = newNames.length + threadData.length;
232: ThreadData[] tmpData = new ThreadData[newSize];
233:
234: if (threadData.length > 0) {
235: System.arraycopy(threadData, 0, tmpData, 0,
236: threadData.length);
237: }
238:
239: for (int i = threadData.length, idx = 0; i < newSize; i++, idx++) {
240: tmpData[i] = new ThreadData(newNames[idx],
241: newClassNames[idx]);
242: }
243:
244: threadData = tmpData;
245: }
246:
247: // private void debugData() {
248: // System.err.print("start time: " + startTime); // NOI18N
249: // System.err.print(", end time: " + endTime); // NOI18N
250: // System.err.println(", delta time: " + (endTime - startTime)); // NOI18N
251: //
252: // System.err.println("number of threads: " + threadData.length); // NOI18N
253: // //new Exception("Stack trace").printStackTrace(System.err);
254: // for (int i = 0; i < threadData.length; i++) {
255: // System.err.println(
256: // "thread [" + i + "] = " + threadData[i].getName() + " class " + threadData[i].getClassName() // NOI18N
257: // );
258: // }
259: // }
260: }
|