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.common;
042:
043: import org.netbeans.lib.profiler.ProfilerClient;
044: import org.netbeans.lib.profiler.TargetAppRunner;
045: import org.netbeans.lib.profiler.client.ClientUtils;
046: import org.netbeans.lib.profiler.client.ClientUtils.SourceCodeSelection;
047: import org.netbeans.lib.profiler.common.event.ProfilingStateEvent;
048: import org.netbeans.lib.profiler.common.event.ProfilingStateListener;
049: import org.netbeans.lib.profiler.common.filters.DefinedFilterSets;
050: import org.netbeans.lib.profiler.common.filters.GlobalFilters;
051: import org.netbeans.lib.profiler.global.CommonConstants;
052: import org.netbeans.lib.profiler.instrumentation.BadLocationException;
053: import org.netbeans.lib.profiler.instrumentation.InstrumentationException;
054: import org.netbeans.lib.profiler.results.monitor.VMTelemetryDataManager;
055: import org.netbeans.lib.profiler.results.threads.ThreadsDataManager;
056: import sun.misc.Service;
057: import java.io.IOException;
058: import java.util.Iterator;
059: import java.util.Vector;
060: import javax.swing.*;
061:
062: /** An abstract superclass representing the entire Profiler. The Profiler class should add a "state" on top of the
063: * underlying JFluid engine, providing easier access to its various functions.
064: *
065: * A concrete subclass would implement the abstract methods in a specific way (integrated into an IDE, standalone GUI
066: * tool, non-gui tool, etc.).
067: *
068: * This class can also be used by any profiling code to obtain the concrete implementation of the Profiler at any given
069: * moment by calling the getDefault () method. Such parts, if they only need to call methods of the Profiler class
070: * and/or any of the underlying libraries (jfluid.jar, jfluid-ui.jar) would then be independent of a concrete form of
071: * the profiler, whether it if GUI/Non-GUI or Integrated/Standalone.
072: *
073: * @author Tomas Hurka
074: * @author Ian Formanek
075: */
076: public abstract class Profiler {
077: //~ Static fields/initializers -----------------------------------------------------------------------------------------------
078:
079: // Profiling states
080: public static final int PROFILING_INACTIVE = 1; // no profiling session in progress
081: public static final int PROFILING_STARTED = 2; // profiling session started but TA not yet running
082: public static final int PROFILING_RUNNING = 4; // profiling session in progress and TA running
083: public static final int PROFILING_PAUSED = 8; // profiling session in progress and TA paused (all threads suspended)
084: public static final int PROFILING_STOPPED = 16; // profiling session finished, some results still available
085: public static final int PROFILING_IN_TRANSITION = 128; // profiling state is in transition between states
086:
087: // Profiling modes
088: public static final int MODE_ATTACH = 0;
089: public static final int MODE_PROFILE = 1;
090:
091: // Logging & error management
092:
093: /** Message that would be useful for tracing events but which need not be a problem. */
094: public static final int INFORMATIONAL = 1;
095:
096: /** Something went wrong in the software, but it is continuing and the user need not be bothered. */
097: public static final int WARNING = 2;
098:
099: /** Something the user should be aware of. */
100: public static final int USER = 4;
101:
102: /** Something went wrong, though it can be recovered. */
103: public static final int EXCEPTION = 8;
104:
105: /** Serious problem, application may be crippled. */
106: public static final int ERROR = 16;
107: private static final boolean DEBUG = System
108: .getProperty("org.netbeans.lib.profiler.common.Profiler") != null; // NOI18N
109: private static Profiler defaultProfiler;
110:
111: //~ Instance fields ----------------------------------------------------------------------------------------------------------
112:
113: private Vector profilingStateListeners;
114: private int currentProfilingState = PROFILING_INACTIVE;
115:
116: //~ Methods ------------------------------------------------------------------------------------------------------------------
117:
118: public static synchronized Profiler getDefault() {
119: if (defaultProfiler == null) {
120: final Iterator it = Service.providers(Profiler.class);
121:
122: if (it.hasNext()) {
123: defaultProfiler = (Profiler) it.next();
124:
125: if ((defaultProfiler != null) && DEBUG) {
126: System.err
127: .println("Default Profiler succesfully installed: "
128: + defaultProfiler); // NOI18N
129: }
130: }
131:
132: if (defaultProfiler == null) {
133: throw new InternalError("Should never happen"); // NOI18N
134: }
135: }
136:
137: return defaultProfiler;
138: }
139:
140: /** Obtains a state for agent listening on given port, checking whether it has the expected agentId.
141: *
142: * @param host Ignored for now
143: * @param port Port number to be used to communicate with the agent
144: * @param agentId Expected agent Id
145: * @return the state of the agent
146: * @see CommonConstants.AGENT_STATE_CONNECTED
147: * @see CommonConstants.AGENT_STATE_DIFFERENT_ID
148: * @see CommonConstants.AGENT_STATE_NOT_RUNNING
149: * @see CommonConstants.AGENT_STATE_OTHER_SESSION_IN_PROGRESS
150: * @see CommonConstants.AGENT_STATE_READY_DIRECT
151: * @see CommonConstants.AGENT_STATE_READY_DYNAMIC
152: */
153: public abstract int getAgentState(String host, int port, int agentId);
154:
155: public abstract SessionSettings getCurrentSessionSettings();
156:
157: public abstract DefinedFilterSets getDefinedFilterSets();
158:
159: public abstract GlobalFilters getGlobalFilters();
160:
161: public abstract GlobalProfilingSettings getGlobalProfilingSettings();
162:
163: public abstract ProfilingSettings getLastProfilingSettings();
164:
165: public abstract int getProfilingMode();
166:
167: public abstract int getProfilingState();
168:
169: public abstract TargetAppRunner getTargetAppRunner();
170:
171: public abstract ThreadsDataManager getThreadsManager();
172:
173: public abstract void setThreadsMonitoringEnabled(boolean enabled);
174:
175: public abstract boolean getThreadsMonitoringEnabled();
176:
177: public abstract VMTelemetryDataManager getVMTelemetryManager();
178:
179: public abstract boolean attachToApp(
180: ProfilingSettings profilingSettings, AttachSettings as);
181:
182: public abstract boolean connectToStartedApp(
183: ProfilingSettings profilingSettings,
184: SessionSettings sessionSettings);
185:
186: public abstract void detachFromApp();
187:
188: /** Displays a user-level message with error. Can be run from any thread.
189: * @param message The error message to display
190: */
191: public abstract void displayError(String message);
192:
193: /** Displays a user-level message with information. Can be run from any thread.
194: * @param message The message to display
195: */
196: public abstract void displayInfo(String message);
197:
198: /** Displays a user-level message with warning. Can be run from any thread.
199: * @param message The warning message to display
200: */
201: public abstract void displayWarning(String message);
202:
203: public abstract void instrumentSelectedRoots(
204: ClientUtils.SourceCodeSelection[] rootMethods)
205: throws ClassNotFoundException, InstrumentationException,
206: BadLocationException, IOException, ClassFormatError,
207: ClientUtils.TargetAppOrVMTerminated;
208:
209: /** Silently log a message. This is not intended for user-level error notification, but rather for
210: * internal messages that would be logged based on the severity level.
211: *
212: * @param severity The severity of the problem
213: * @param message The message to log
214: */
215: public abstract void log(int severity, String message);
216:
217: public abstract void modifyCurrentProfiling(
218: ProfilingSettings profilingSettings);
219:
220: /** Notify the user about an internal error. This is not intended for user-level error notification, but rather for
221: * internal unexpected problems that usually represent a bug in our code.
222: *
223: * @param severity The severity of the problem
224: * @param e The exception that occured
225: */
226: public abstract void notifyException(int severity, Exception e);
227:
228: public abstract void openJavaSource(String classname,
229: String methodName, String methodSig);
230:
231: public abstract boolean profileClass(
232: ProfilingSettings profilingSettings,
233: SessionSettings sessionSettings);
234:
235: public abstract boolean rerunAvaliable();
236:
237: public abstract void rerunLastProfiling();
238:
239: public abstract boolean runCalibration(boolean checkForSaved,
240: String jvmExecutable, String jdkString, int architecture);
241:
242: public abstract boolean shutdownBlockedAgent(String host, int port,
243: int agentId);
244:
245: public abstract void stopApp();
246:
247: // ProfilingStateListener stuff
248: public final void addProfilingStateListener(
249: final ProfilingStateListener profilingStateListener) {
250: if (profilingStateListeners == null) {
251: profilingStateListeners = new Vector();
252: }
253:
254: if (!profilingStateListeners.contains(profilingStateListener)) {
255: profilingStateListeners.add(profilingStateListener);
256: profilingStateListener
257: .profilingStateChanged(new ProfilingStateEvent(-1,
258: currentProfilingState, defaultProfiler));
259: profilingStateListener.instrumentationChanged(-1,
260: getTargetAppRunner().getProfilerClient()
261: .getCurrentInstrType());
262: }
263: }
264:
265: public boolean prepareInstrumentation(
266: ProfilingSettings profilingSettings) {
267: try {
268: final ProfilerClient client = getTargetAppRunner()
269: .getProfilerClient();
270: final int oldInstrType = client.getStatus().currentInstrType;
271:
272: switch (profilingSettings.getProfilingType()) {
273: case ProfilingSettings.PROFILE_MONITOR:
274: client.removeAllInstrumentation();
275:
276: break;
277: case ProfilingSettings.PROFILE_MEMORY_ALLOCATIONS:
278: client
279: .initiateMemoryProfInstrumentation(CommonConstants.INSTR_OBJECT_ALLOCATIONS);
280:
281: break;
282: case ProfilingSettings.PROFILE_MEMORY_LIVENESS:
283: client
284: .initiateMemoryProfInstrumentation(CommonConstants.INSTR_OBJECT_LIVENESS);
285:
286: break;
287: case ProfilingSettings.PROFILE_CPU_ENTIRE:
288: case ProfilingSettings.PROFILE_CPU_PART:
289: instrumentSelectedRoots(profilingSettings
290: .getInstrumentationMethods());
291:
292: break;
293: case ProfilingSettings.PROFILE_CPU_STOPWATCH:
294:
295: SourceCodeSelection[] fragment = new SourceCodeSelection[] { profilingSettings
296: .getCodeFragmentSelection() };
297: client.initiateCodeRegionInstrumentation(fragment);
298:
299: break;
300: }
301:
302: fireInstrumentationChanged(oldInstrType,
303: client.getStatus().currentInstrType);
304:
305: return true;
306: } catch (ClientUtils.TargetAppOrVMTerminated e) {
307: displayError(e.getMessage());
308: e.printStackTrace(System.err);
309: } catch (InstrumentationException e) {
310: displayError(e.getMessage());
311: e.printStackTrace(System.err);
312: } catch (BadLocationException e) {
313: displayError(e.getMessage());
314: e.printStackTrace(System.err);
315: } catch (ClassNotFoundException e) {
316: displayError(e.getMessage());
317: e.printStackTrace(System.err);
318: } catch (IOException e) {
319: displayError(e.getMessage());
320: } catch (ClassFormatError e) {
321: displayError(e.getMessage());
322: }
323:
324: return false;
325: }
326:
327: public final boolean profilingInProgress() {
328: final int state = getProfilingState();
329:
330: return ((state == PROFILING_PAUSED) || (state == PROFILING_RUNNING));
331: }
332:
333: public final void removeProfilingStateListener(
334: final ProfilingStateListener profilingStateListener) {
335: if (profilingStateListeners != null) {
336: profilingStateListeners.remove(profilingStateListener);
337: }
338: }
339:
340: public static void debug(String s) {
341: if (DEBUG) {
342: System.err.println("Profiler.DEBUG: " + s); // NOI18N
343: }
344: }
345:
346: public static void debug(Exception e) {
347: if (DEBUG) {
348: System.err.print("Profiler.DEBUG: "); // NOI18N
349: e.printStackTrace(System.err);
350: }
351: }
352:
353: public abstract String getLibsDir();
354:
355: public abstract int getPlatformArchitecture(String platformName);
356:
357: public abstract String getPlatformJDKVersion(String platformName);
358:
359: public abstract String getPlatformJavaFile(String platformName);
360:
361: protected final void fireInstrumentationChanged(
362: final int oldInstrType, final int currentInstrType) {
363: if (profilingStateListeners == null) {
364: return;
365: }
366:
367: final Vector toNotify;
368:
369: synchronized (this ) {
370: toNotify = (Vector) profilingStateListeners.clone();
371: }
372:
373: final Iterator iterator = toNotify.iterator();
374: final Runnable r = new Runnable() {
375: public void run() {
376: while (iterator.hasNext()) {
377: ((ProfilingStateListener) iterator.next())
378: .instrumentationChanged(oldInstrType,
379: currentInstrType);
380: }
381: }
382: };
383:
384: if (SwingUtilities.isEventDispatchThread()) {
385: r.run();
386: } else {
387: SwingUtilities.invokeLater(r);
388: }
389: }
390:
391: protected final void fireProfilingStateChange(
392: final int oldProfilingState, final int newProfilingState) {
393: currentProfilingState = newProfilingState;
394:
395: if (profilingStateListeners == null) {
396: return;
397: }
398:
399: if (oldProfilingState == newProfilingState) {
400: return;
401: }
402:
403: final Vector toNotify;
404:
405: synchronized (this ) {
406: toNotify = (Vector) profilingStateListeners.clone();
407: }
408:
409: final Iterator iterator = toNotify.iterator();
410: final ProfilingStateEvent event = new ProfilingStateEvent(
411: oldProfilingState, newProfilingState, this );
412: final Runnable r = new Runnable() {
413: public void run() {
414: while (iterator.hasNext()) {
415: ((ProfilingStateListener) iterator.next())
416: .profilingStateChanged(event);
417: }
418: }
419: };
420:
421: if (SwingUtilities.isEventDispatchThread()) {
422: r.run();
423: } else {
424: SwingUtilities.invokeLater(r);
425: }
426: }
427:
428: protected final void fireThreadsMonitoringChange() {
429: if (profilingStateListeners == null) {
430: return;
431: }
432:
433: final Vector toNotify;
434:
435: synchronized (this ) {
436: toNotify = (Vector) profilingStateListeners.clone();
437: }
438:
439: final Iterator iterator = toNotify.iterator();
440: final Runnable r = new Runnable() {
441: public void run() {
442: while (iterator.hasNext()) {
443: ((ProfilingStateListener) iterator.next())
444: .threadsMonitoringChanged();
445: }
446: }
447: };
448:
449: if (SwingUtilities.isEventDispatchThread()) {
450: r.run();
451: } else {
452: SwingUtilities.invokeLater(r);
453: }
454: }
455: }
|