org.netbeans.modules.profiler.NetBeansProfiler Maven / Gradle / Ivy
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.netbeans.modules.profiler;
import com.sun.tools.attach.AgentInitializationException;
import com.sun.tools.attach.AgentLoadException;
import com.sun.tools.attach.AttachNotSupportedException;
import com.sun.tools.attach.VirtualMachine;
import java.awt.BorderLayout;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.HierarchyEvent;
import java.awt.event.HierarchyListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.util.Collection;
import java.util.Iterator;
import java.util.Properties;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.SwingUtilities;
import javax.swing.border.EmptyBorder;
import org.netbeans.api.progress.ProgressHandle;
import org.netbeans.lib.profiler.ProfilerClient;
import org.netbeans.lib.profiler.ProfilerEngineSettings;
import org.netbeans.lib.profiler.ProfilerLogger;
import org.netbeans.lib.profiler.ProfilingEventListener;
import org.netbeans.lib.profiler.TargetAppRunner;
import org.netbeans.lib.profiler.classfile.ClassRepository;
import org.netbeans.lib.profiler.client.AppStatusHandler;
import org.netbeans.lib.profiler.client.ClientUtils;
import org.netbeans.lib.profiler.client.ProfilingPointsProcessor;
import org.netbeans.lib.profiler.common.*;
import org.netbeans.lib.profiler.filters.GenericFilter;
import org.netbeans.lib.profiler.global.CalibrationDataFileIO;
import org.netbeans.lib.profiler.global.CommonConstants;
import org.netbeans.lib.profiler.global.Platform;
import org.netbeans.lib.profiler.instrumentation.BadLocationException;
import org.netbeans.lib.profiler.instrumentation.InstrumentationException;
import org.netbeans.lib.profiler.results.CCTProvider;
import org.netbeans.lib.profiler.results.ProfilingResultsDispatcher;
import org.netbeans.lib.profiler.results.cpu.CPUCCTProvider;
import org.netbeans.lib.profiler.results.cpu.CPUProfilingResultListener;
import org.netbeans.lib.profiler.results.cpu.FlatProfileBuilder;
import org.netbeans.lib.profiler.results.cpu.cct.CCTResultsFilter;
import org.netbeans.lib.profiler.results.cpu.cct.TimeCollector;
import org.netbeans.lib.profiler.results.locks.LockProfilingResultListener;
import org.netbeans.lib.profiler.results.memory.MemoryCCTProvider;
import org.netbeans.lib.profiler.results.memory.MemoryProfilingResultsListener;
import org.netbeans.lib.profiler.results.monitor.VMTelemetryDataManager;
import org.netbeans.lib.profiler.results.threads.ThreadsDataManager;
import org.netbeans.lib.profiler.ui.SwingWorker;
import org.netbeans.lib.profiler.ui.monitor.VMTelemetryModels;
import org.netbeans.lib.profiler.wireprotocol.Command;
import org.netbeans.lib.profiler.wireprotocol.Response;
import org.netbeans.lib.profiler.wireprotocol.WireIO;
import org.netbeans.modules.profiler.api.JavaPlatform;
import org.netbeans.modules.profiler.api.ProfilerDialogs;
import org.netbeans.modules.profiler.api.ProfilerIDESettings;
import org.netbeans.modules.profiler.api.ProgressDisplayer;
import org.netbeans.modules.profiler.spi.SessionListener;
import org.netbeans.modules.profiler.ui.ProfilerProgressDisplayer;
import org.netbeans.modules.profiler.utilities.ProfilerUtils;
import org.openide.awt.Mnemonics;
import org.openide.awt.StatusDisplayer;
import org.openide.filesystems.FileObject;
import org.openide.util.Lookup;
import org.openide.util.NbBundle;
import org.openide.util.RequestProcessor;
import org.openide.windows.WindowManager;
/**
* The main class representing profiler integrated in the IDE
*
* List of properties that can be used to influence the profiler behavior:
* \"org.netbeans.lib.profiler.wireprotocol.WireIO\" - set to true to enable wire i/o debugging on profiler side
* \"org.netbeans.lib.profiler.wireprotocol.WireIO.agent\" - set to true to enable wire i/o debugging on profiled app side
*
* @author Tomas Hurka
* @author Ian Formanek
* @author Misha Dmitriev
* @author Jiri Sedlacek
*/
@NbBundle.Messages({
"NetBeansProfiler_ProgressDialogCaption=Progress...",
"NetBeansProfiler_EntireApplicationProfilingWarning=In the Entire Application profiling mode,\nprofiling data collection will not start\nuntil your application starts a new Thread,\nand will be done only for new Threads.\n\nConsider switching to \"Part of Application\" mode\nif you want to profile already running threads.",
"NetBeansProfiler_DirectoryDoesNotExistMessage=The directory does not exist.",
"NetBeansProfiler_DirectoryIsWriteProtectedMessage=The directory is write-protected.\nPlease make it writeable.",
"NetBeansProfiler_ErrorLoadingProfilingSettingsMessage=Error encountered while loading profiling settings: {0}",
"NetBeansProfiler_ErrorSavingProfilingSettingsMessage=Error encountered while saving global filters: {0}",
"NetBeansProfiler_ErrorSavingFilterSetsMessage=Error encountered while saving defined filter sets: {0}",
"NetBeansProfiler_ErrorSavingGlobalSettingsMessage=Error encountered while saving global settings: {0}",
"NetBeansProfiler_ErrorSavingAttachSettingsMessage=Error encountered while saving attach settings: {0}",
"NetBeansProfiler_CannotFindLibsMsg=Cannot find profiler libs directory",
"NetBeansProfiler_EngineInitFailedMsg=Failed to initialize the Profiler engine: {0}",
"NetBeansProfiler_InitialCalibrationMsg=Profiler will now perform an initial calibration of your machine and target JVM.\n\nThis calibration needs to be performed the first time you run the profiler to\nensure that timing results are accurate when profiling your application. To\nensure the calibration data is accurate, please make sure that other\napplications are not placing a noticeable load on your machine at this time.\n\nYou can run the calibration again using\n\"Tools | Options | Java | Profiler | General | Manage calibration data\"\n\nWarning: If your computer uses dynamic CPU frequency switching, please\ndisable it and do not use it when profiling.",
"NetBeansProfiler_MustCalibrateFirstMsg=Profiling will STOP now because the calibration data is missing or is corrupt.\n\nIf this is the first time you are using the profiler or target JVM on this machine,\nyou first need to run the calibration for your target JVM.\nThe obtained calibration data will be saved and re-used\non subsequent runs, so you will not see this message again.\n\nTo perform calibration, use\n\"Tools | Options | Java | Profiler | General | Manage calibration data\".\n\n",
"NetBeansProfiler_MustCalibrateFirstShortMsg=Calibration data missing.
Profiling cannot be started on this JDK. Please perform
profiler calibration first and start the profiling session again.",
"NetBeansProfiler_TerminateVMOnExitMsg=The profiled application has finished execution.\n Press OK to terminate the VM.",
"NetBeansProfiler_TakeSnapshotOnExitMsg=The profiled application has finished execution.\nDo you want to take a snapshot of the collected results?",
"NetBeansProfiler_TakeSnapshotOnExitDialogTitle=Application Finished",
"NetBeansProfiler_TargetAppNotRespondingMsg=The profiled application does not respond.\n Do you want to close the connection and stop profiling?",
"NetBeansProfiler_TargetAppNotRespondingDialogTitle=Question",
"NetBeansProfiler_ModifyingInstrumentationMsg=Modifying instrumentation...",
"NetBeansProfiler_StartingSession=Starting profiling session...",
"NetBeansProfiler_CancelBtn=&Cancel",
"NetBeansProfiler_AgentFailed=Make sure the process is not already being profiled.",
"NetBeansProfiler_MemorySamplingJava5=Memory sampling is not supported for Java 5.
Please run the profiled application using Java 6+ or use memory instrumentation."
})
public abstract class NetBeansProfiler extends Profiler {
//~ Inner Classes ------------------------------------------------------------------------------------------------------------
public static final class ProgressPanel implements AppStatusHandler.AsyncDialog {
private static final int MINIMUM_WIDTH = 350;
private volatile boolean opened;
private volatile boolean closed;
private JDialog dialog;
private final String message;
private final boolean showProgress;
private final Runnable cancelHandler;
private ProgressPanel(String message, boolean showProgress, Runnable cancelHandler) {
this.message = message;
this.showProgress = showProgress;
this.cancelHandler = cancelHandler;
}
@Override
public void close() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
if (!opened) closed = true;
else closeImpl();
}
});
}
@Override
public void display() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
initUI();
// RequestProcessor.getDefault().post(new Runnable() {
// public void run() {
if (!closed) dialog.setVisible(true);
// }
// });
}
});
}
private void initUI() {
Frame mainWindow = WindowManager.getDefault().getMainWindow();
dialog = new JDialog(mainWindow, Bundle.NetBeansProfiler_ProgressDialogCaption(), true);
JPanel panel = new JPanel(new BorderLayout(5, 5));
panel.setBorder(new EmptyBorder(15, 15, 15, 10));
panel.add(new JLabel(message), BorderLayout.NORTH);
if (showProgress) {
JProgressBar progress = new JProgressBar();
progress.setIndeterminate(true);
panel.add(progress, BorderLayout.SOUTH);
}
if (cancelHandler != null) {
JButton cancelButton = new JButton() {
protected void fireActionPerformed(ActionEvent e) {
close();
cancelHandler.run();
}
};
Mnemonics.setLocalizedText(cancelButton, Bundle.NetBeansProfiler_CancelBtn());
JPanel buttonPanel = new JPanel(new BorderLayout(0, 0));
buttonPanel.setBorder(new EmptyBorder(5, 15, 10, 10));
buttonPanel.add(cancelButton, BorderLayout.EAST);
dialog.add(panel, BorderLayout.NORTH);
dialog.add(buttonPanel, BorderLayout.SOUTH);
} else {
dialog.add(panel, BorderLayout.NORTH);
}
Dimension ps = panel.getPreferredSize();
panel.setPreferredSize(new Dimension(Math.max(ps.width, MINIMUM_WIDTH), ps.height));
dialog.pack();
dialog.setLocationRelativeTo(mainWindow);
dialog.addHierarchyListener(new HierarchyListener() {
public void hierarchyChanged(HierarchyEvent e) {
if ((e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) != 0 && dialog.isShowing()) {
dialog.removeHierarchyListener(this);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
opened = true;
if (closed) closeImpl();
}
});
}
}
});
dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
}
private void closeImpl() {
dialog.setVisible(false);
dialog.dispose();
}
}
// -- NetBeansProfiler-only callback classes ---------------------------------------------------------------------------
private final class IDEAppStatusHandler implements AppStatusHandler {
//~ Methods --------------------------------------------------------------------------------------------------------------
public AppStatusHandler.AsyncDialog getAsyncDialogInstance(String message, boolean showProgress, Runnable cancelHandler) {
return new ProgressPanel(message, showProgress, cancelHandler);
}
public boolean confirmWaitForConnectionReply() {
// FIXXX: should display a NotifyDescriptor.WARNING_MESSAGE confirmation!
return (!ProfilerDialogs.displayConfirmation(
Bundle.NetBeansProfiler_TargetAppNotRespondingMsg(),
Bundle.NetBeansProfiler_TargetAppNotRespondingDialogTitle()));
}
// The following methods should display messages asynchronously, i.e. they shouldn't block the current
// thread waiting for the user pressing OK.
public void displayError(final String msg) {
LOGGER.log(Level.WARNING, "IDEAppStatusHandler - error: {)}", msg); //NOI18N
ProfilerDialogs.displayError(msg);
}
// These method SHOULD wait for the user to press ok, since they may be used in a sequence of displayed
// panels, and the next one shouldn't be displayed before the previous one is read and understood.
public void displayErrorAndWaitForConfirm(final String msg) {
LOGGER.log(Level.WARNING, "IDEAppStatusHandler - errorAndWaitForConfirm: {0}", msg); //NOI18N
ProfilerDialogs.displayError(msg);
}
public void displayErrorWithDetailsAndWaitForConfirm(String shortMsg, String detailsMsg) {
ProfilerDialogs.displayError(shortMsg, null, detailsMsg);
}
public void displayNotification(final String msg) {
StatusDisplayer.getDefault().setStatusText(msg);
}
public void displayNotificationAndWaitForConfirm(final String msg) {
ProfilerDialogs.displayInfo(msg);
}
public void displayNotificationWithDetailsAndWaitForConfirm(String shortMsg, String detailsMsg) {
ProfilerDialogs.displayInfo(shortMsg, null, detailsMsg);
}
public void displayWarning(final String msg) {
LOGGER.log(Level.WARNING, "IDEAppStatusHandler - warning: {0}" ,msg); //NOI18N
ProfilerDialogs.displayWarning(msg);
}
public void displayWarningAndWaitForConfirm(final String msg) {
LOGGER.log(Level.WARNING, "IDEAppStatusHandler - warningAndWaitForConfirm: {0}", msg); //NOI18N
ProfilerDialogs.displayWarning(msg);
}
public void handleShutdown() {
// IDEUtils.runInEventDispatchThreadAndWait( // According to Issue 74914 this cannot run in AWT-EventQueue
// new Runnable() {
// public void run() {
// Asynchronously update live results if autorefresh is on
// if (LiveResultsWindow.hasDefault()) {
// LiveResultsWindow.getDefault().handleShutdown();
// }
if ((getTargetAppRunner().getProfilerClient().getCurrentInstrType() == CommonConstants.INSTR_NONE)
|| !ResultsManager.getDefault().resultsAvailable()) {
ProfilerDialogs.displayInfoDNSA(Bundle.NetBeansProfiler_TerminateVMOnExitMsg(), null, null, "NetBeansProfiler.handleShutdown.noResults", false); //NOI18N
} else if (ProfilerDialogs.displayConfirmationDNSA(Bundle.NetBeansProfiler_TakeSnapshotOnExitMsg(), Bundle.NetBeansProfiler_TakeSnapshotOnExitDialogTitle(), null, "NetBeansProfiler.handleShutdown", false)) { //NOI18N
ResultsManager.getDefault().takeSnapshot();
}
// }
// }
// );
}
public void pauseLiveUpdates() {
// LiveResultsWindow.setPaused(true);
}
public void resultsAvailable() {
ProfilingSettings ps = getLastProfilingSettings();
if (ps != null && ps.getProfilingType() == ProfilingSettings.PROFILE_CPU_SAMPLING) {
return;
}
ResultsManager.getDefault().resultsBecameAvailable();
}
public void resumeLiveUpdates() {
// LiveResultsWindow.setPaused(false);
}
public void takeSnapshot() {
ProfilerUtils.runInProfilerRequestProcessor(new Runnable() {
public void run() {
ResultsManager.getDefault().takeSnapshot();
}
});
}
}
//~ Static fields/initializers -----------------------------------------------------------------------------------------------
private static final Logger LOGGER = Logger.getLogger(NetBeansProfiler.class.getName());
// private static final String GLOBAL_FILTERS_FILENAME = "filters"; //NOI18N
// private static final String DEFINED_FILTERSETS_FILENAME = "filtersets"; //NOI18N
// private static final String DEFAULT_FILE_SUFFIX = "-default"; //NOI18N
private static boolean initialized = false;
//~ Instance fields ----------------------------------------------------------------------------------------------------------
//--- Modifying instrumentation progress -------------------------------------
boolean shouldDisplayDialog = true;
// TODO [release] set to obtain from property
// static boolean DEBUG = true; // System.getProperty("org.netbeans.modules.profiler.NetBeansProfiler") != null;
private final ProfilerIDESettings ideSettings = ProfilerIDESettings.getInstance();
private ProfilingMonitor monitor = null;
private TargetAppRunner targetAppRunner;
private FileObject profiledSingleFile;
final private ProfilerEngineSettings sharedSettings;
private final Object setupLock = new Object();
private ProfilingSettings lastProfilingSettings;
private Lookup.Provider profiledProject = null;
private SessionSettings lastSessionSettings;
private StringBuilder logMsgs = new StringBuilder();
private ThreadsDataManager threadsManager;
private VMTelemetryDataManager vmTelemetryManager;
private VMTelemetryModels vmTelemetryModels;
private boolean calibrating = false;
// ---------------------------------------------------------------------------
// Temporary workaround to refresh profiling points when LiveResultsWindow is not refreshing
// TODO: implement better approach for refreshing profiling points and remove this code
// private boolean processesProfilingPoints;
private boolean threadsMonitoringEnabled = false;
private boolean lockContentionMonitoringEnabled = false;
private boolean waitDialogOpen = false;
private int lastMode = MODE_PROFILE;
private int profilingMode = MODE_PROFILE;
private int profilingState = PROFILING_INACTIVE;
//~ Constructors -------------------------------------------------------------------------------------------------------------
public NetBeansProfiler() {
boolean initFailed = false;
sharedSettings = new ProfilerEngineSettings();
try {
String libsDir = getLibsDir();
if (libsDir == null) {
throw new IOException(Bundle.NetBeansProfiler_CannotFindLibsMsg());
}
sharedSettings.initialize(libsDir);
sharedSettings.setSeparateConsole(System.getProperty("org.netbeans.profiler.separateConsole") != null //NOI18N
); // change to true if something misbehaves and the TA VM does not start
sharedSettings.setTargetWindowRemains(System.getProperty("org.netbeans.profiler.targetWindowRemains") != null //NOI18N
); // use for testing when something misbehaves
} catch (RuntimeException e) {
ProfilerLogger.log(e);
ProfilerDialogs.displayError(e.getMessage());
initFailed = true;
} catch (IOException e) {
// #216809 - likely an unsupported system, just silently log the problem
LOGGER.log(Level.WARNING, Bundle.NetBeansProfiler_EngineInitFailedMsg(e.getLocalizedMessage()));
initFailed = true;
}
if (!initFailed) {
initialized = true;
new ServerStateMonitor(this);
}
}
//~ Methods ------------------------------------------------------------------------------------------------------------------
public static NetBeansProfiler getDefaultNB() {
return (NetBeansProfiler) getDefault();
}
// ---------------------------------------------------------------------------
public static boolean isInitialized() {
// make sure that the profiler is initialized
getDefaultNB();
return initialized;
}
public int getAgentState(String host, int port, int agentId) {
if (profilingState /*!= PROFILING_INACTIVE*/ == PROFILING_RUNNING) {
// profiling currently in progress, check port and id
if (port == getTargetAppRunner().getProfilerEngineSettings().getPortNo()) {
if (getTargetAppRunner().getProfilerClient().getCurrentAgentId() == agentId) {
return CommonConstants.AGENT_STATE_CONNECTED;
} else {
return CommonConstants.AGENT_STATE_DIFFERENT_ID;
}
}
}
Properties agentProps = getAgentProperties(port);
if (agentProps == null) {
return CommonConstants.AGENT_STATE_NOT_RUNNING;
} else {
try {
int id = Integer.parseInt(agentProps.getProperty("agent.id")); //NOI18N
if (id == agentId) {
String dynamic = agentProps.getProperty("dynamic"); //NOI18N
if ((dynamic == null) || "false".equals(dynamic)) { //NOI18N
return CommonConstants.AGENT_STATE_READY_DIRECT;
} else {
return CommonConstants.AGENT_STATE_READY_DYNAMIC;
}
} else {
return CommonConstants.AGENT_STATE_DIFFERENT_ID;
}
} catch (NumberFormatException e) {
return CommonConstants.AGENT_STATE_NOT_RUNNING;
}
}
}
public SessionSettings getCurrentSessionSettings() {
return lastSessionSettings;
}
public GlobalProfilingSettings getGlobalProfilingSettings() {
return ideSettings;
}
public ProfilingSettings getLastProfilingSettings() {
return lastProfilingSettings;
}
public abstract String getLibsDir();
public int getPlatformArchitecture(String platformName) {
JavaPlatform platform = JavaPlatform.getJavaPlatformById(platformName);
return platform.getPlatformArchitecture();
}
public String getPlatformJDKVersion(String platformName) {
JavaPlatform platform = JavaPlatform.getJavaPlatformById(platformName);
return platform.getPlatformJDKVersion();
}
public String getPlatformJavaFile(String platformName) {
JavaPlatform platform = JavaPlatform.getJavaPlatformById(platformName);
return platform.getPlatformJavaFile();
}
public int getProfilingMode() {
return profilingMode;
}
public int getProfilingState() {
return profilingState;
}
@Override
public int getServerState() {
if (monitor != null) {
return monitor.getServerState();
}
return CommonConstants.SERVER_RUNNING;
}
@Override
public int getServerProgress() {
if (monitor != null) {
return monitor.getServerProgress();
}
return CommonConstants.SERVER_PROGRESS_INDETERMINATE;
}
public synchronized TargetAppRunner getTargetAppRunner() {
if (initialized) {
if (targetAppRunner == null) {
// Initialize shared TargetAppRunner instance
targetAppRunner = new TargetAppRunner(sharedSettings, new IDEAppStatusHandler(), getProfilingPointsManager());
targetAppRunner.addProfilingEventListener(new ProfilingEventListener() {
@Override
public void targetAppStarted() {
if (calibrating) {
return;
}
changeStateTo(PROFILING_RUNNING);
}
@Override
public void targetAppStopped() {
if (calibrating) {
return;
}
changeStateTo(PROFILING_STOPPED);
}
@Override
public void targetAppSuspended() {
if (calibrating) {
return;
}
changeStateTo(PROFILING_PAUSED);
}
@Override
public void targetAppResumed() {
if (calibrating) {
return;
}
changeStateTo(PROFILING_RUNNING);
}
@Override
public void attachedToTarget() {
if (calibrating) {
return;
}
changeStateTo(PROFILING_RUNNING);
}
@Override
public void detachedFromTarget() {
if (calibrating) {
return;
}
getMonitor().stopDisplayingVM();
changeStateTo(PROFILING_INACTIVE);
}
@Override
public void targetVMTerminated() {
if (calibrating) {
return;
}
getMonitor().stopDisplayingVM();
changeStateTo(PROFILING_INACTIVE);
}
});
}
return targetAppRunner;
}
return null;
}
public synchronized ThreadsDataManager getThreadsManager() {
if (threadsManager == null) {
threadsManager = new ThreadsDataManager();
}
return threadsManager;
}
public void setThreadsMonitoringEnabled(final boolean enabled) {
getThreadsManager().setThreadsMonitoringEnabled(enabled);
if (threadsMonitoringEnabled == enabled) {
return;
}
threadsMonitoringEnabled = enabled;
fireThreadsMonitoringChange();
}
public boolean getThreadsMonitoringEnabled() {
return threadsMonitoringEnabled;
}
public void setLockContentionMonitoringEnabled(final boolean enabled) {
if (lockContentionMonitoringEnabled == enabled) {
return;
}
if (getProfilingState() == PROFILING_RUNNING) {
final TargetAppRunner runner = getTargetAppRunner();
final ProfilerEngineSettings settings = runner.getProfilerEngineSettings();
if (settings.isLockContentionMonitoringEnabled() != enabled && runner.targetJVMIsAlive()) {
settings.setLockContentionMonitoringEnabled(enabled);
try {
runner.getProfilerClient().sendSetInstrumentationParamsCmd(true);
} catch (ClientUtils.TargetAppOrVMTerminated ex) {
settings.setLockContentionMonitoringEnabled(!enabled);
ProfilerDialogs.displayError(ex.getMessage());
return;
}
}
}
lockContentionMonitoringEnabled = enabled;
fireLockContentionMonitoringChange();
}
public boolean getLockContentionMonitoringEnabled() {
return lockContentionMonitoringEnabled;
}
public synchronized VMTelemetryModels getVMTelemetryModels() {
if (vmTelemetryModels == null) {
vmTelemetryModels = new VMTelemetryModels(getVMTelemetryManager());
}
return vmTelemetryModels;
}
public synchronized VMTelemetryDataManager getVMTelemetryManager() {
if (vmTelemetryManager == null) {
vmTelemetryManager = new VMTelemetryDataManager();
}
return vmTelemetryManager;
}
/**
* Attaches to a running application using provided settings
*
* @param profilingSettings Settings to use for profiling
* @param attachSettings AttachSettings to use
* @return true if successfully attached, false otherwise
*/
public boolean attachToApp(final ProfilingSettings profilingSettings, final AttachSettings attachSettings) {
profilingMode = MODE_ATTACH;
ProgressHandle ph = ProgressHandle.createHandle(Bundle.NetBeansProfiler_StartingSession());
ph.setInitialDelay(500);
ph.start();
try {
if (getProfilingState() != PROFILING_INACTIVE) {
if (lastMode == MODE_ATTACH) {
detachFromApp(); // if attached, detach
} else if (getTargetAppRunner().targetJVMIsAlive()) {
getTargetAppRunner().terminateTargetJVM(); // otherwise kill current app if running
}
}
// remember profiling settings
lastProfilingSettings = profilingSettings;
lastSessionSettings = null;
lastMode = MODE_ATTACH;
final ProfilerEngineSettings sSettings = getTargetAppRunner().getProfilerEngineSettings();
profilingSettings.applySettings(sSettings); // can override the session settings
attachSettings.applySettings(sSettings);
//getThreadsManager().setSupportsSleepingStateMonitoring(
// Platform.supportsThreadSleepingStateMonitoring(sharedSettings.getTargetJDKVersionString()));
logActionConfig("attachToApp", profilingSettings, null, attachSettings, sSettings.getInstrumentationFilter()); // NOI18N
changeStateTo(PROFILING_STARTED);
cleanupBeforeProfiling(sSettings);
setThreadsMonitoringEnabled(profilingSettings.getThreadsMonitoringEnabled());
setLockContentionMonitoringEnabled(profilingSettings.getLockContentionMonitoringEnabled());
if (shouldOpenWindowsOnProfilingStart()) {
CommonUtils.runInEventDispatchThread(new Runnable() {
public void run() {
openWindowsOnProfilingStart();
}
});
}
if (attachSettings.isDirect()) { // Previously known as "attach on startup"
// The VM is already started with all necessary options and waiting for us to connect.
// Remote profiling case fits here too - it's distinguished in ProfilerClient using attachSettings.isRemote()
// perform the selected instrumentation - it will really start right after the target app starts
boolean success = false;
if (prepareInstrumentation(profilingSettings)) {
success = getTargetAppRunner().initiateSession(1, false) && getTargetAppRunner().attachToTargetVMOnStartup();
}
if (!success) {
changeStateTo(PROFILING_INACTIVE);
// change state back to inactive and fire, return false
return false;
}
} else if (attachSettings.isDynamic16()) {
String jar = getLibsDir() + "/jfluid-server-15.jar"; // NOI18N
String pid = String.valueOf(attachSettings.getPid());
String options = String.valueOf(attachSettings.getPort());
boolean success = false;
try {
loadAgentIntoTargetJVM(jar, options, pid);
if (prepareInstrumentation(profilingSettings)) {
success = getTargetAppRunner().initiateSession(2, false) && getTargetAppRunner().attachToTargetVM();
}
} catch (AgentInitializationException ex) {
ProfilerDialogs.displayError(ex.getMessage()+"\n"+Bundle.NetBeansProfiler_AgentFailed()); // NOI18N
ProfilerLogger.log(ex);
} catch (Exception ex) {
ProfilerDialogs.displayError(ex.getMessage());
ProfilerLogger.log(ex);
}
if (!success) {
changeStateTo(PROFILING_INACTIVE);
// change state back to inactive and fire, return false
return false;
}
} else {
throw new IllegalArgumentException("Invalid settings " + attachSettings); // NOI18N
}
return connectToApp();
} finally {
ph.finish();
}
}
private static void loadAgentIntoTargetJVM(final String jar, final String options, final String pid)
throws AttachNotSupportedException, IOException, AgentLoadException, AgentInitializationException {
VirtualMachine virtualMachine = VirtualMachine.attach(pid);
virtualMachine.loadAgent(jar,options);
}
// -- NetBeansProfiler-only public methods -----------------------------------------------------------------------------
public void checkAndUpdateState() {
// TODO: check & refactor to remove this
final boolean targetVMAlive = getTargetAppRunner().targetJVMIsAlive();
if (!targetVMAlive) {
changeStateTo(PROFILING_INACTIVE);
return;
}
final boolean running = getTargetAppRunner().targetAppIsRunning();
if (!running) {
changeStateTo(PROFILING_STOPPED);
return;
}
final boolean suspended = getTargetAppRunner().targetAppSuspended();
if (suspended) {
changeStateTo(PROFILING_PAUSED);
}
}
// used before starting a server for profiling, kills any agent which would cause collision on port and removes agent file
// does nothing if the agent is already profiling (port is used, covers both profiling from current or other IDE)
public boolean cleanForProfilingOnPort(int port) {
// profiling session communicating over the port currently in progress, nothing to do (will cause collision)
if (isProfilingRunningOnPort(port)) {
ProfilerLogger.severe(">>> Profiling session already running on port " + port
+ ", will cause collision when starting another agent on the same port."); // NOI18N
return false;
}
// there is an agent alive currently using the port, most likely profiling from within another IDE (will cause collision)
if (!shutdownAgent("localhost", port)) { // NOI18N
ProfilerLogger.severe(">>> Profiler agent already profiling on port " + port
+ " (communicating with another IDE?), will cause collision when starting another agent on the same port."); // NOI18N
return false;
}
File agentFile = getInfoFile(port);
// agent file exists, agent is still shutting down or in undefined state (hanging?)
if (agentFile.exists()) {
// returns true if agent file successfuly deleted, false otherwise (will cause server startup failure because initial STATE_INACTIVE)
boolean fileDeleted = waitForDeleteAgentFile(agentFile);
if (!fileDeleted) {
ProfilerLogger.severe(">>> Profiler agent identification file cannot be deleted for port " + port
+ ", will cause failure starting a server for profiling on the same port."); // NOI18N
}
return fileDeleted;
}
// agent file doesn't exist, there should be no collision starting new profiling session on port
return true;
}
/**
* Connects to an application started using the specified sessionSettings, and will start its profiling
* with the provided profilingSettings.
*
* @param profilingSettings Settings to use for profiling
* @param sessionSettings Session settings for profiling
* @return true if connected successfully, false otherwise
*/
@Override
public boolean connectToStartedApp(final ProfilingSettings profilingSettings, final SessionSettings sessionSettings) {
return connectToStartedApp(profilingSettings, sessionSettings, new AtomicBoolean());
}
/**
* Connects to an application started using the specified sessionSettings, and will start its profiling
* with the provided profilingSettings.
*
* @param profilingSettings Settings to use for profiling
* @param sessionSettings Session settings for profiling
* @param cancel shared cancel flag
* @return true if connected successfully, false otherwise
*/
public boolean connectToStartedApp(final ProfilingSettings profilingSettings, final SessionSettings sessionSettings, final AtomicBoolean cancel) {
profilingMode = MODE_PROFILE;
lastProfilingSettings = profilingSettings;
lastSessionSettings = sessionSettings;
lastMode = MODE_PROFILE;
ProgressHandle ph = ProgressHandle.createHandle(Bundle.NetBeansProfiler_StartingSession());
try {
ph.setInitialDelay(500);
ph.start();
if (getTargetAppRunner().targetJVMIsAlive()) {
getTargetAppRunner().terminateTargetJVM();
}
final ProfilerEngineSettings sSettings = getTargetAppRunner().getProfilerEngineSettings();
sessionSettings.applySettings(sSettings);
profilingSettings.applySettings(sSettings); // can override the session settings
sSettings.setInstrumentObjectInit(false); // clear instrument object.
//sSettings.setRemoteHost(""); // NOI18N // clear remote profiling host
//getThreadsManager().setSupportsSleepingStateMonitoring(
// Platform.supportsThreadSleepingStateMonitoring(sharedSettings.getTargetJDKVersionString()));
logActionConfig("connectToStartedApp", profilingSettings, sessionSettings, null, sSettings.getInstrumentationFilter()); // NOI18N
if (prepareProfilingSession(profilingSettings, sessionSettings)) {
RequestProcessor.getDefault().post(new Runnable() {
@Override
public void run() {
// should propagate the result of the following operation somehow; current workflow doesn't allow it
if (tryInitiateSession(sessionSettings, cancel)) {
connectToApp();
}
}
});
return true;
}
return false;
} finally {
ph.finish();
}
}
private boolean prepareProfilingSession(ProfilingSettings profilingSettings, SessionSettings sessionSettings) {
changeStateTo(PROFILING_STARTED);
cleanupBeforeProfiling(getTargetAppRunner().getProfilerEngineSettings());
setThreadsMonitoringEnabled(profilingSettings.getThreadsMonitoringEnabled());
setLockContentionMonitoringEnabled(profilingSettings.getLockContentionMonitoringEnabled());
if (shouldOpenWindowsOnProfilingStart()) {
CommonUtils.runInEventDispatchThread(new Runnable() {
public void run() {
openWindowsOnProfilingStart();
}
});
}
if (sessionSettings.getRemoteHost().isEmpty() && !CalibrationDataFileIO.validateCalibrationInput(
sessionSettings.getJavaVersionString(),sessionSettings.getJavaExecutable())) {
ProfilerDialogs.displayError(Bundle.NetBeansProfiler_MustCalibrateFirstShortMsg(), null, Bundle.NetBeansProfiler_MustCalibrateFirstMsg());
changeStateTo(PROFILING_INACTIVE);
return false; // failed, cannot proceed
}
// perform the selected instrumentation
if (!prepareInstrumentation(profilingSettings)) {
return false; // failed, cannot proceed
}
return true;
}
private boolean tryInitiateSession(SessionSettings sessionSettings, AtomicBoolean cancel) {
if (!targetAppRunner.initiateSession(sessionSettings.getRemoteHost().isEmpty() ? 0 : 1, false, cancel) || !targetAppRunner.connectToStartedVMAndStartTA()) {
changeStateTo(PROFILING_INACTIVE);
return false; // failed, cannot proceed
}
return true;
}
private boolean connectToApp() {
if (getTargetAppRunner().targetAppIsRunning()) {
getThreadsManager()
.setSupportsSleepingStateMonitoring(Platform.supportsThreadSleepingStateMonitoring(getTargetAppRunner().getProfilerEngineSettings().getTargetJDKVersionString()));
CommonUtils.runInEventDispatchThread(new Runnable() {
public void run() {
getMonitor().monitorVM(getTargetAppRunner());
}
});
return true;
} else {
// TODO: notify the user???
changeStateTo(PROFILING_INACTIVE);
return false; // failed, cannot proceed
}
}
public void detachFromApp() {
TargetAppRunner runner = getTargetAppRunner();
if (runner == null || !runner.targetJVMIsAlive()) return;
changeStateTo(PROFILING_IN_TRANSITION);
runner.prepareDetachFromTargetJVM();
if (runner.getProfilingSessionStatus().currentInstrType != CommonConstants.INSTR_NONE) {
// if (LiveResultsWindow.hasDefault()) LiveResultsWindow.getDefault().reset(); // see issue http://www.netbeans.org/issues/show_bug.cgi?id=68213
try {
runner.getProfilerClient().removeAllInstrumentation(false); // remove only the server side instrumentation
} catch (InstrumentationException e) {
ProfilerDialogs.displayError(e.getMessage());
}
}
runner.detachFromTargetJVM();
// targetAppRunner.getProfilerClient().resetClientData();
// TODO reset all profilingresultslisteners
// CPUCallGraphBuilder.resetCollectors();
// ResultsManager.getDefault().reset();
}
public void instrumentSelectedRoots(ClientUtils.SourceCodeSelection[] rootMethods)
throws ClassNotFoundException, InstrumentationException, BadLocationException, IOException,
ClassFormatError, ClientUtils.TargetAppOrVMTerminated {
final ProfilerClient client = getTargetAppRunner().getProfilerClient();
if (rootMethods.length == 0) {
ClientUtils.SourceCodeSelection selection = new ClientUtils.SourceCodeSelection(1); // spawned threads recursively
rootMethods = new ClientUtils.SourceCodeSelection[] { selection };
}
// Start the recursive code instrumentation
client.initiateRecursiveCPUProfInstrumentation(rootMethods);
}
public void log(int severity, final String message) {
switch (severity) {
case Profiler.INFORMATIONAL:
LOGGER.log(Level.INFO, message);
break;
case Profiler.WARNING:
LOGGER.log(Level.WARNING, message);
break;
case Profiler.EXCEPTION:
case Profiler.ERROR:
LOGGER.log(Level.SEVERE, message);
break;
default:
LOGGER.log(Level.FINEST, message);
break;
}
}
// ---------------------------------------------------------------------------
public void modifyCurrentProfiling(final ProfilingSettings profilingSettings) {
lastProfilingSettings = profilingSettings;
if (!targetAppRunner.targetJVMIsAlive()) {
return;
}
final ProfilerEngineSettings sharedSettings = getTargetAppRunner().getProfilerEngineSettings();
profilingSettings.applySettings(sharedSettings);
sharedSettings.setInstrumentObjectInit(true);
logActionConfig("modifyCurrentProfiling", profilingSettings, null, null, sharedSettings.getInstrumentationFilter()); //NOI18N
setThreadsMonitoringEnabled(profilingSettings.getThreadsMonitoringEnabled());
setLockContentionMonitoringEnabled(profilingSettings.getLockContentionMonitoringEnabled());
// SwingUtilities.invokeLater(new Runnable() {
// @Override
// public void run() {
// if (LiveResultsWindow.hasDefault())
// LiveResultsWindow.getDefault().handleCleanupBeforeProfiling();
// }
// });
ProfilerUtils.runInProfilerRequestProcessor(new Runnable() {
@Override
public void run() {
changeStateTo(PROFILING_IN_TRANSITION);
getTargetAppRunner().getAppStatusHandler().pauseLiveUpdates();
ResultsManager.getDefault().reset();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
AppStatusHandler.AsyncDialog waitDialog = getTargetAppRunner().getAppStatusHandler()
.getAsyncDialogInstance(Bundle.NetBeansProfiler_ModifyingInstrumentationMsg(), true, null);
waitDialog.display();
try {
prepareInstrumentation(profilingSettings);
changeStateTo(PROFILING_RUNNING);
} finally {
waitDialog.close();
getTargetAppRunner().getAppStatusHandler().resumeLiveUpdates();
}
}
});
}
public void notifyException(final int severity, final Exception e) {
switch (severity) {
case Profiler.INFORMATIONAL:
LOGGER.log(Level.INFO, null, e);
break;
case Profiler.WARNING:
LOGGER.log(Level.WARNING, null, e);
break;
default:
LOGGER.log(Level.SEVERE, null, e);
break;
}
}
public void openJavaSource(String className, String methodName, String methodSig) {
// openJavaSource(getProfiledProject(), className, methodName, methodSig);
}
public boolean processesProfilingPoints() {
ProfilingPointsProcessor ppp = getProfilingPointsManager();
if (ppp != null) {
return ppp.getSupportedProfilingPoints().length > 0;
}
return false;
}
/**
* Starts the TA described via sessionSettings, using profiling mode specified in profilingSettings.
*
* @param profilingSettings Settings to use for profiling
* @param sessionSettings Session settings for profiling
* @return true if target app successfully started, false otherwise
*/
public boolean profileClass(final ProfilingSettings profilingSettings, final SessionSettings sessionSettings) {
//final long time = System.currentTimeMillis();
profilingMode = MODE_PROFILE;
lastProfilingSettings = profilingSettings;
lastSessionSettings = sessionSettings;
lastMode = MODE_PROFILE;
if (getTargetAppRunner().targetJVMIsAlive()) {
getTargetAppRunner().terminateTargetJVM();
}
final ProfilerEngineSettings sSettings = getTargetAppRunner().getProfilerEngineSettings();
sessionSettings.applySettings(sSettings);
profilingSettings.applySettings(sSettings); // can override the session settings
sSettings.setRemoteHost(""); // NOI18N // clear remote profiling host
sSettings.setInstrumentObjectInit(false); // clear instrument object.
//getThreadsManager().setSupportsSleepingStateMonitoring(
// Platform.supportsThreadSleepingStateMonitoring(sharedSettings.getTargetJDKVersionString()));
logActionConfig("profileClass", profilingSettings, sessionSettings, null, sSettings.getInstrumentationFilter()); //NOI18N
changeStateTo(PROFILING_STARTED);
// System.err.println("--------------------------------------------- 2: "+ (System.currentTimeMillis() - time));
cleanupBeforeProfiling(sSettings);
setThreadsMonitoringEnabled(profilingSettings.getThreadsMonitoringEnabled());
setLockContentionMonitoringEnabled(profilingSettings.getLockContentionMonitoringEnabled());
// System.err.println("------------------------------------------ 3: "+ (System.currentTimeMillis() - time));
if (shouldOpenWindowsOnProfilingStart()) {
openWindowsOnProfilingStart();
}
// System.err.println("------------------------------------- 4: "+ (System.currentTimeMillis() - time));
final Window mainWindow = WindowManager.getDefault().getMainWindow();
// This call reduces the speedup for class instrumentation on the 2nd and further runs that we could otherwise
// have, but guarantees that if any classes have been recompiled in between runs, their most up-to-date copies will
// be used.
ProfilerUtils.runInProfilerRequestProcessor(new Runnable() {
public void run() {
final Cursor cursor = mainWindow.getCursor();
mainWindow.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
try {
if (!runCalibration(true, sessionSettings.getJavaExecutable(), sessionSettings.getJavaVersionString(),
sessionSettings.getSystemArchitecture())) {
ProfilerDialogs.displayError(Bundle.ProfilerModule_CalibrationFailedMessage());
changeStateTo(PROFILING_INACTIVE);
return; // failed, cannot proceed
}
// System.err.println("-----------------------------------5: "+ (System.currentTimeMillis() - time));
// perform the selected instrumentation
boolean success = prepareInstrumentation(profilingSettings);
// and run the target application
// System.err.println("---------------------------- 6: "+ (System.currentTimeMillis() - time));
success = success && getTargetAppRunner().startTargetVM() && getTargetAppRunner().initiateSession(0, false)
&& getTargetAppRunner().connectToStartedVMAndStartTA();
if (!success) {
changeStateTo(PROFILING_INACTIVE);
return;
}
// System.err.println("---------------------------- 7: "+ (System.currentTimeMillis() - time));
if (getTargetAppRunner().targetAppIsRunning()) {
getThreadsManager()
.setSupportsSleepingStateMonitoring(Platform.supportsThreadSleepingStateMonitoring(sSettings.getTargetJDKVersionString()));
CommonUtils.runInEventDispatchThread(new Runnable() {
public void run() {
// System.err.println("------------ 8: "+ (System.currentTimeMillis() - time));
getMonitor().monitorVM(getTargetAppRunner());
// System.err.println("------------------------ 9: "+ (System.currentTimeMillis() - time));
// System.err.println("------------------------ 11: "+ (System.currentTimeMillis() - time));
}
});
} else {
// TODO: notify the user???
changeStateTo(PROFILING_INACTIVE);
}
} finally {
mainWindow.setCursor(cursor);
}
}
});
// Syst---------------------------------------------------- Final: "+ (System.currentTimeMillis() - time));
return true;
}
protected boolean shouldOpenWindowsOnProfilingStart() {
return true;
}
// NOTE: used from com.sun.tools.visualvm.profiler.ProfilerSupport.calibrateJVM(),
// requires targetAppRunner to be configured correctly. Most likely you want to use
// runCalibration(boolean checkForSaved, String jvmExecutable, String jdkString, int architecture) !!!
public boolean runConfiguredCalibration() {
calibrating = true;
boolean result = targetAppRunner.calibrateInstrumentationCode();
calibrating = false;
return result;
}
public boolean runCalibration(boolean checkForSaved, String jvmExecutable, String jdkString, int architecture) {
calibrating = true;
ProfilerEngineSettings pes = getTargetAppRunner().getProfilerEngineSettings();
int savedPort = pes.getPortNo();
GenericFilter savedInstrFilter = pes.getInstrumentationFilter();
String savedJVMExeFile = pes.getTargetJVMExeFile();
String savedJDKVersionString = pes.getTargetJDKVersionString();
int savedArch = pes.getSystemArchitecture();
String savedCP = pes.getMainClassPath();
if (jvmExecutable != null) {
pes.setTargetJVMExeFile(jvmExecutable);
pes.setTargetJDKVersionString(jdkString);
pes.setSystemArchitecture(architecture);
}
pes.setPortNo(ideSettings.getCalibrationPortNo());
pes.setInstrumentationFilter(new GenericFilter());
pes.setMainClassPath(""); //NOI18N
boolean result = false;
if (checkForSaved) {
result = getTargetAppRunner().readSavedCalibrationData();
if (!result) {
ProfilerDialogs.displayInfo(Bundle.NetBeansProfiler_InitialCalibrationMsg());
result = getTargetAppRunner().calibrateInstrumentationCode();
}
// NOTE: use -Dprofiler.disableFTSRecalibration=true to skip fast
// timestamp recalibration for each profiling session on old
// linux kernels not supporting Time Stamp Counter.
if (!Boolean.getBoolean("profiler.disableFTSRecalibration")) { // NOI18N
boolean shouldCalibrate = false;
getTargetAppRunner().getProfilingSessionStatus().beginTrans(false);
try {
// the calibration was executed without the usage of "-XX:+UseLinuxPosixThreadCPUClocks" flag
// ---> recalibrate <---
shouldCalibrate = Platform.isLinux() &&
Platform.JDK_16_STRING.equals(pes.getTargetJDKVersionString()) &&
getTargetAppRunner().getProfilingSessionStatus().methodEntryExitCallTime[1] > 20000; // 20us
} finally {
getTargetAppRunner().getProfilingSessionStatus().endTrans();
}
if (shouldCalibrate) {
result = getTargetAppRunner().calibrateInstrumentationCode();
}
}
} else {
result = getTargetAppRunner().calibrateInstrumentationCode();
}
calibrating = false;
// restore original values
pes.setPortNo(savedPort);
pes.setInstrumentationFilter(savedInstrFilter);
pes.setTargetJDKVersionString(savedJDKVersionString);
pes.setSystemArchitecture(savedArch);
pes.setTargetJVMExeFile(savedJVMExeFile);
pes.setMainClassPath(savedCP);
return result;
}
public void setProfiledProject(Lookup.Provider project, FileObject singleFile) {
profiledProject = project;
profiledSingleFile = singleFile;
// SwingUtilities.invokeLater(new Runnable() {
// @Override
// public void run() {
// if (ProfilerControlPanel2.hasDefault())
// ProfilerControlPanel2.getDefault().setProfiledProject(profiledProject);
// }
// });
}
public Lookup.Provider getProfiledProject() {
return profiledProject;
}
public FileObject getProfiledSingleFile() {
return profiledSingleFile;
}
@Override
public boolean prepareInstrumentation(ProfilingSettings profilingSettings) {
teardownDispatcher();
setupDispatcher(profilingSettings);
// ClientUtils.SourceCodeSelection[] marks = MarkingEngine.getDefault().getMarkerMethods();
// profilingSettings.setInstrumentationMarkerMethods(marks);
profilingSettings.setInstrumentationMarkerMethods(new ClientUtils.SourceCodeSelection[0]);
return prepareInstrumentationImpl(profilingSettings);
}
private synchronized ProfilingMonitor getMonitor() {
if (monitor == null) {
monitor = new ProfilingMonitor();
monitor.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals(ProfilingMonitor.PROPERTY_SERVER_STATE)
|| evt.getPropertyName().equals(ProfilingMonitor.PROPERTY_SERVER_PROGRESS)) {
fireServerStateChanged(((ProfilingMonitor)evt.getSource()).getServerState(),
((ProfilingMonitor)evt.getSource()).getServerProgress());
}
}
});
}
return monitor;
}
private boolean prepareInstrumentationImpl(ProfilingSettings profilingSettings) {
try {
return super.prepareInstrumentation(profilingSettings);
} catch (ClientUtils.TargetAppOrVMTerminated e) {
ProfilerDialogs.displayWarning(e.getMessage());
e.printStackTrace(System.err);
} catch (InstrumentationException e) {
ProfilerDialogs.displayError(e.getMessage());
e.printStackTrace(System.err);
} catch (BadLocationException e) {
ProfilerDialogs.displayError(e.getMessage());
e.printStackTrace(System.err);
} catch (ClassNotFoundException e) {
ProfilerDialogs.displayError(e.getMessage());
e.printStackTrace(System.err);
} catch (IOException e) {
ProfilerDialogs.displayError(e.getMessage());
} catch (ClassFormatError e) {
ProfilerDialogs.displayError(e.getMessage());
}
return false;
}
// // TODO [ian] - perform saving of global settings differently
// public void saveFilters() {
// // 1. save global filters
// FileLock lock = null;
//
// try {
// Properties globalFiltersProps = new Properties();
// globalFilters.store(globalFiltersProps);
// ProfilerStorage.saveGlobalProperties(globalFiltersProps, GLOBAL_FILTERS_FILENAME);
// } catch (Exception e) {
// ProfilerLogger.log(e);
// ProfilerDialogs.displayError(
// Bundle.NetBeansProfiler_ErrorSavingProfilingSettingsMessage(e.getMessage()));
// } finally {
// if (lock != null) {
// lock.releaseLock();
// }
// }
//
// // 2. save defined Filter Sets
// lock = null;
//
// try {
// Properties definedFilterSetsProps = new Properties();
// definedFilterSets.store(definedFilterSetsProps);
// ProfilerStorage.saveGlobalProperties(definedFilterSetsProps, DEFINED_FILTERSETS_FILENAME);
// } catch (Exception e) {
// ProfilerLogger.log(e);
// ProfilerDialogs.displayError(
// Bundle.NetBeansProfiler_ErrorSavingFilterSetsMessage(e.getMessage()));
// } finally {
// if (lock != null) {
// lock.releaseLock();
// }
// }
// }
public void shutdown() {
getMonitor().stopUpdateThread();
}
// (synchronous - blocking) Used for stopping a server from a blocking state ready for direct attach (org.netbeans.modules.j2ee.deployment.profiler.spi.Profiler.shutdown())
// returns true if the agent was correctly finished from blocked state, false otherwise
public boolean shutdownBlockedAgent(String host, int port, int agentId) {
int state = getAgentState(host, port, agentId);
if (state == CommonConstants.AGENT_STATE_READY_DIRECT) {
Socket clientSocket = null;
ObjectOutputStream socketOut = null;
ObjectInputStream socketIn = null;
try {
clientSocket = new Socket(host, port);
clientSocket.setSoTimeout(100);
clientSocket.setTcpNoDelay(true); // Necessary at least on Solaris to avoid delays in e.g. readInt() etc.
socketOut = new ObjectOutputStream(clientSocket.getOutputStream());
socketIn = new ObjectInputStream(clientSocket.getInputStream());
WireIO wio = new WireIO(socketOut, socketIn);
wio.sendSimpleCommand(Command.TERMINATE_TARGET_JVM);
Object o = wio.receiveCommandOrResponse();
if (o instanceof Response && ((Response) o).isOK()) {
return true;
} else {
return false;
}
} catch (IOException e) {
return false;
} finally {
try {
if (socketIn != null) {
socketIn.close();
}
if (socketOut != null) {
socketOut.close();
}
if (clientSocket != null) {
clientSocket.close();
}
} catch (IOException e) {
ProfilerLogger.log(e);
}
}
} else {
return false;
}
}
public void stopApp() {
TargetAppRunner runner = getTargetAppRunner();
if (runner == null || !runner.targetJVMIsAlive()) return;
changeStateTo(PROFILING_IN_TRANSITION);
runner.terminateTargetJVM();
}
private Properties getAgentProperties(int port) {
File f = getInfoFile(port);
if (!f.exists()) {
return null; // No agent is running
}
BufferedInputStream bis = null;
try {
Properties props = new Properties();
FileInputStream fis = new FileInputStream(f);
bis = new BufferedInputStream(fis);
props.load(bis);
bis.close();
return props;
} catch (IOException e) {
// commented out, the file is sometimes deleted before creating FileInputStream,
// which results in FileNotFoundException. This actually means that the file doesn't exist
// and that the Profiler is connected, so silently returning null is correct.
//e.printStackTrace();
return null;
} finally {
if (bis != null) {
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private static File getInfoFile(int port) {
String homeDir = System.getProperty("user.home"); // NOI18N
return new File(homeDir + File.separator + ".nbprofiler" + File.separator + port); // NOI18N
}
// checks if there is a profiling session currently in progress communicating over specified port
private boolean isProfilingRunningOnPort(int port) {
return (profilingState == PROFILING_RUNNING) && (port == getTargetAppRunner().getProfilerEngineSettings().getPortNo());
}
private void changeStateTo(int newState) {
if (profilingState == newState) {
return;
}
final int oldProfilingState = profilingState;
profilingState = newState;
fireProfilingStateChange(oldProfilingState, profilingState);
if ((newState == PROFILING_INACTIVE) || (newState == PROFILING_STOPPED)) {
cleanupAfterProfiling();
}
if (newState == PROFILING_RUNNING && CommonConstants.JDK_15_STRING.
equals(getTargetAppRunner().getProfilerEngineSettings().getTargetJDKVersionString())) {
if (lastProfilingSettings.getProfilingType() == ProfilingSettings.PROFILE_MEMORY_SAMPLING)
SwingUtilities.invokeLater(new Runnable() { // Let the underlying dialogs close first
public void run() {
ProfilerDialogs.displayWarning(Bundle.NetBeansProfiler_MemorySamplingJava5());
}
});
}
}
protected void cleanupAfterProfiling() {
teardownDispatcher();
// MarkingEngine.getDefault().deconfigure();
ClassRepository.cleanup();
}
private void cleanupBeforeProfiling(ProfilerEngineSettings sharedSettings) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
NetBeansProfiler.this.getThreadsManager().reset();
NetBeansProfiler.this.getVMTelemetryManager().reset();
// if (LiveResultsWindow.hasDefault())
// LiveResultsWindow.getDefault().handleCleanupBeforeProfiling();
}
});
ResultsManager.getDefault().reset();
ClassRepository.clearCache();
ClassRepository.initClassPaths(sharedSettings.getWorkingDir(), sharedSettings.getVMClassPaths());
}
// private void displayWarningAboutEntireAppProfiling() {
// ProfilerDialogs.displayWarning(Bundle.NetBeansProfiler_EntireApplicationProfilingWarning());
// }
//
// // -- Package-Private stuff --------------------------------------------------------------------------------------------
// private void loadGlobalFilters() {
// try {
// Properties globalFiltersProps = new Properties();
// ProfilerStorage.loadGlobalProperties(globalFiltersProps, GLOBAL_FILTERS_FILENAME);
// globalFilters = new GlobalFilters();
// globalFilters.load(globalFiltersProps);
//
// Properties definedFilterSetsProps = new Properties();
// ProfilerStorage.loadGlobalProperties(definedFilterSetsProps, DEFINED_FILTERSETS_FILENAME);
// definedFilterSets = new DefinedFilterSets();
// definedFilterSets.load(definedFilterSetsProps);
// } catch (Exception e) {
// ProfilerLogger.log(e);
// ProfilerDialogs.displayError(
// Bundle.NetBeansProfiler_ErrorLoadingProfilingSettingsMessage(e.getMessage()));
// }
// }
// -- Private implementation -------------------------------------------------------------------------------------------
private void openWindowsOnProfilingStart() {
// int telemetryBehavior = ideSettings.getTelemetryOverviewBehavior();
// int threadsBehavior = ideSettings.getThreadsViewBehavior();
// int locksBehavior = ideSettings.getLockContentionViewBehavior();
//
// boolean threadsEnabled = lastProfilingSettings.getThreadsMonitoringEnabled();
// boolean lockContentionEnabled = lastProfilingSettings.getLockContentionMonitoringEnabled();
// int type = lastProfilingSettings.getProfilingType();
//
// // 1. Telemetry Overview
// if ((telemetryBehavior == ProfilerIDESettings.OPEN_ALWAYS)
// || ((telemetryBehavior == ProfilerIDESettings.OPEN_MONITORING) && (type == ProfilingSettings.PROFILE_MONITOR))) {
// TelemetryOverviewPanel.getDefault().open();
// TelemetryOverviewPanel.getDefault().requestVisible();
// }
//
// // 2. Threads view
// if (threadsEnabled) {
// if ((threadsBehavior == ProfilerIDESettings.OPEN_ALWAYS)
// || ((threadsBehavior == ProfilerIDESettings.OPEN_MONITORING) && (type == ProfilingSettings.PROFILE_MONITOR))) {
// ThreadsWindow.getDefault().open();
// ThreadsWindow.getDefault().requestVisible();
// }
// }
//
// // 3. Lock Contention view
// if (lockContentionEnabled) {
// if ((locksBehavior == ProfilerIDESettings.OPEN_ALWAYS)
// || ((locksBehavior == ProfilerIDESettings.OPEN_MONITORING) && (type == ProfilingSettings.PROFILE_MONITOR))) {
// LockContentionWindow.getDefault().showView();
// }
// }
//
// // 4. Live Results
// if ((ideSettings.getDisplayLiveResultsCPU()
// && ((type == ProfilingSettings.PROFILE_CPU_ENTIRE) || (type == ProfilingSettings.PROFILE_CPU_PART)
// || (type == ProfilingSettings.PROFILE_CPU_SAMPLING)))
// || (ideSettings.getDisplayLiveResultsFragment() && (type == ProfilingSettings.PROFILE_CPU_STOPWATCH))
// || (ideSettings.getDisplayLiveResultsMemory()
// && ((type == ProfilingSettings.PROFILE_MEMORY_ALLOCATIONS)
// || (type == ProfilingSettings.PROFILE_MEMORY_LIVENESS)
// || (type == ProfilingSettings.PROFILE_MEMORY_SAMPLING)))) {
// LiveResultsWindow.getDefault().open();
// LiveResultsWindow.getDefault().requestVisible();
// }
//
// // 5. Control Panel displayed always, and getting focus
// final ProfilerControlPanel2 controlPanel2 = ProfilerControlPanel2.getDefault();
// controlPanel2.open();
// controlPanel2.requestActive();
}
@NbBundle.Messages({
"MSG_StartingProfilerClient=Starting Profiler Client"
})
public boolean startEx(final ProfilingSettings profilingSettings, final SessionSettings sessionSettings, final AtomicBoolean cancel) {
final boolean[] rslt = new boolean[1];
final CountDownLatch latch = new CountDownLatch(1);
if (sessionSettings.getRemoteHost().isEmpty()&&(!CalibrationDataFileIO.validateCalibrationInput(sessionSettings.getJavaVersionString(), sessionSettings.getJavaExecutable())
|| !runCalibration(true, sessionSettings.getJavaExecutable(), sessionSettings.getJavaVersionString(),sessionSettings.getSystemArchitecture()))) {
ProfilerDialogs.displayError(Bundle.ProfilerModule_CalibrationFailedMessage());
return false;
}
new SwingWorker(false) {
volatile private ProgressDisplayer pd;
@Override
protected void doInBackground() {
if (isCancelled()) return;
connectToStartedApp(profilingSettings, sessionSettings, cancel);
}
@Override
protected void done() {
if (pd != null) {
pd.close();
pd = null;
}
rslt[0] = true;
latch.countDown();
}
@Override
protected void nonResponding() {
final SwingWorker thiz = this;
pd = ProfilerProgressDisplayer.getDefault().showProgress(Bundle.MSG_StartingProfilerClient(), new ProgressDisplayer.ProgressController() {
@Override
public boolean cancel() {
thiz.cancel();
return true;
}
});
}
@Override
protected void cancelled() {
if (pd != null) {
pd.close();
pd = null;
}
rslt[0] = false;
cancel.set(true);
latch.countDown();
}
@Override
protected int getWarmup() {
return 1500;
}
}.execute();
try {
latch.await();
return rslt[0];
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
return false;
}
public void setupDispatcher(ProfilingSettings profilingSettings) {
lastProfilingSettings = profilingSettings;
synchronized (setupLock) {
final Lookup.Provider project = getProfiledProject();
// configure call-context-tree dispatching infrastructure
CCTProvider cctProvider = null;
Collection cctListeners = null;
switch (profilingSettings.getProfilingType()) {
case ProfilingSettings.PROFILE_CPU_ENTIRE:
case ProfilingSettings.PROFILE_CPU_PART:
case ProfilingSettings.PROFILE_CPU_JDBC:
case ProfilingSettings.PROFILE_CPU_SAMPLING:
case ProfilingSettings.PROFILE_CPU_STOPWATCH: {
cctProvider = Lookup.getDefault().lookup(CPUCCTProvider.class);
cctListeners = Lookup.getDefault().lookupAll(CPUCCTProvider.Listener.class);
break;
}
case ProfilingSettings.PROFILE_MEMORY_ALLOCATIONS:
case ProfilingSettings.PROFILE_MEMORY_LIVENESS: {
cctProvider = Lookup.getDefault().lookup(MemoryCCTProvider.class);
cctListeners = Lookup.getDefault().lookupAll(MemoryCCTProvider.Listener.class);
break;
}
}
if ((cctProvider != null) && (cctListeners != null) && (cctListeners.size() > 0)) {
for (CCTProvider.Listener cctListener : cctListeners) {
if (LOGGER.isLoggable(Level.FINEST)) {
LOGGER.log(Level.FINEST, "Adding listener {0} to the provider {1}", new Object[]{cctListener.getClass().getName(), cctProvider.getClass().getName()});
}
cctProvider.addListener(cctListener);
}
} else {
if (LOGGER.isLoggable(Level.WARNING)) {
if (cctProvider == null) {
LOGGER.warning("Could not find a CCT provider in lookup!");
} else if ((cctListeners == null) || (cctListeners.isEmpty())) {
LOGGER.warning("Could not find listeners in lookup!");
}
}
}
for(SessionListener sl : Lookup.getDefault().lookupAll(SessionListener.class)) {
sl.onStartup(profilingSettings, project);
}
ProfilerClient client = getTargetAppRunner().getProfilerClient();
CCTResultsFilter filter = Lookup.getDefault().lookup(CCTResultsFilter.class);
if (filter != null) {
filter.reset(); // clean up the filter before reusing it
filter.setEvaluators(Lookup.getDefault().lookupAll(CCTResultsFilter.EvaluatorProvider.class));
}
// init context aware instances
FlatProfileBuilder fpb = Lookup.getDefault().lookup(FlatProfileBuilder.class);
TimeCollector tc = Lookup.getDefault().lookup(TimeCollector.class);
fpb.setContext(client, tc, filter);
Collection listeners = null;
switch (profilingSettings.getProfilingType()) {
case ProfilingSettings.PROFILE_CPU_PART:
case ProfilingSettings.PROFILE_CPU_JDBC:
case ProfilingSettings.PROFILE_CPU_ENTIRE:
case ProfilingSettings.PROFILE_CPU_SAMPLING: {
listeners = Lookup.getDefault().lookupAll(CPUProfilingResultListener.class);
for (Iterator iter = listeners.iterator(); iter.hasNext();) {
CPUProfilingResultListener listener = (CPUProfilingResultListener) iter.next();
ProfilingResultsDispatcher.getDefault().addListener(listener);
listener.startup(getTargetAppRunner().getProfilerClient());
}
break;
}
case ProfilingSettings.PROFILE_MEMORY_ALLOCATIONS:
case ProfilingSettings.PROFILE_MEMORY_LIVENESS: {
listeners = Lookup.getDefault().lookupAll(MemoryProfilingResultsListener.class);
for (Iterator iter = listeners.iterator(); iter.hasNext();) {
MemoryProfilingResultsListener listener = (MemoryProfilingResultsListener) iter.next();
ProfilingResultsDispatcher.getDefault().addListener(listener);
listener.startup(getTargetAppRunner().getProfilerClient());
}
break;
}
default: {
listeners = Lookup.getDefault().lookupAll(LockProfilingResultListener.class);
for (Iterator iter = listeners.iterator(); iter.hasNext();) {
LockProfilingResultListener listener = (LockProfilingResultListener) iter.next();
ProfilingResultsDispatcher.getDefault().addListener(listener);
listener.startup(getTargetAppRunner().getProfilerClient());
}
}
}
ProfilingPointsProcessor ppp = getProfilingPointsManager();
if (ppp != null) ppp.init(getProfiledProject());
ProfilingResultsDispatcher.getDefault().startup(client);
}
}
// Used for killing an agent which could cause a collision on port
// Returns true if TERMINATE_TARGET_JVM was invoked on agent (not necessarily killed!), false if the agent is already profiling (port is used)
private boolean shutdownAgent(String host, int port) {
if (port == -1) return false; // invalid port
Socket clientSocket = null;
ObjectOutputStream socketOut = null;
ObjectInputStream socketIn = null;
try {
clientSocket = new Socket(host, port);
clientSocket.setSoTimeout(100);
clientSocket.setTcpNoDelay(true); // Necessary at least on Solaris to avoid delays in e.g. readInt() etc.
socketOut = new ObjectOutputStream(clientSocket.getOutputStream());
socketIn = new ObjectInputStream(clientSocket.getInputStream());
WireIO wio = new WireIO(socketOut, socketIn);
wio.sendSimpleCommand(Command.TERMINATE_TARGET_JVM);
try {
Object o = wio.receiveCommandOrResponse();
} catch (Exception e) {
} // Throws SocketTimeoutException!
ProfilerLogger.warning(">>> An existing Profiler agent listening on port " + port
+ " was terminated to allow starting new profiling session on the same port."); // NOI18N
return true;
} catch (SocketTimeoutException e) { // port already in use
return false;
} catch (IOException e) {
return true;
} finally {
try {
if (socketIn != null) {
socketIn.close();
}
if (socketOut != null) {
socketOut.close();
}
if (clientSocket != null) {
clientSocket.close();
}
} catch (IOException e) {
// e.printStackTrace(System.err);
}
}
}
private void teardownDispatcher() {
synchronized (setupLock) {
ProfilingResultsDispatcher.getDefault().shutdown();
// Collection extends CCTProvider> cctProviders = Lookup.getDefault().lookupAll(CCTProvider.class);
// for(CCTProvider cctProvider : cctProviders) {
// cctProvider.removeAllListeners();
// }
// StatisticalModuleContainer statModulesContainer = Lookup.getDefault().lookup(StatisticalModuleContainer.class);
//
// if (statModulesContainer != null) {
// statModulesContainer.removeAllModules();
// }
// deconfigure the profiler client
ProfilerClient client = getTargetAppRunner().getProfilerClient();
client.registerFlatProfileProvider(null);
// // deconfigure the marking engine
// MarkingEngine.getDefault().deconfigure();
for(SessionListener sl : Lookup.getDefault().lookupAll(SessionListener.class)) {
sl.onShutdown();
}
FlatProfileBuilder fpb = Lookup.getDefault().lookup(FlatProfileBuilder.class);
fpb.setContext(null, null, null);
}
}
private ProfilingPointsProcessor getProfilingPointsManager() {
return Lookup.getDefault().lookup(ProfilingPointsProcessor.class);
}
private boolean waitForDeleteAgentFile(File agentFile) {
if (agentFile.delete()) {
return true;
}
for (int i = 0; i < 5; i++) {
if (agentFile.delete()) {
return true;
}
try {
Thread.sleep(50);
} catch (InterruptedException ex) {
}
}
return false;
}
private static void logActionConfig(String actionTitle, ProfilingSettings ps, SessionSettings ss, AttachSettings as, GenericFilter f) {
assert actionTitle != null;
assert ps != null;
assert f != null;
LOGGER.log(Level.CONFIG,
"*** Profiler Action = {0}\n" + //NOI18N
">>> Profiling Settings = \n" + // NOI18N
"{1}\n" +// NOI18N
">>> {2} Settings = \n" + // NOI18N
"{3}\n" + // NOI18N
">>> Instrumentation Filter = \n" + //NOI18N
"{4}", // NOI18N
new Object[]{
actionTitle,
ps.debug(),
(ss != null ? "Session" : (as != null ? "Attach" : null)), // NOI18N
(ss != null ? ss.debug() : (as != null ? as.debug() : null)),
f.toString()
}
);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy