blob: 8ae9e14b63cd85216966821b85ca30840d02803d [file] [log] [blame]
/*
* 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 java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import org.netbeans.lib.profiler.TargetAppRunner;
import org.netbeans.lib.profiler.client.MonitoredData;
import org.netbeans.lib.profiler.common.Profiler;
import org.netbeans.lib.profiler.global.CommonConstants;
import org.netbeans.lib.profiler.results.monitor.VMTelemetryDataManager;
import org.netbeans.lib.profiler.results.threads.ThreadsDataManager;
import javax.swing.*;
import org.netbeans.modules.profiler.api.ProfilerDialogs;
import org.openide.util.NbBundle;
/**
* This class provides thread for periodically processing monitoring data from profiled application (feeding them to
* telemetry and threads data managers) as well as I/O redirection.
*
* @author Tomas Hurka
* @author Ian Formanek
*/
public final class ProfilingMonitor {
@NbBundle.Messages({
"ProfilingMonitor_OomeMsg=<html><b>Not enough memory to store profiling data.</b><br><br>To avoid this error, increase the -Xmx value<br>in the etc/netbeans.conf file in NetBeans IDE installation.</html>"
})
//~ Inner Classes ------------------------------------------------------------------------------------------------------------
final class UpdateThread extends Thread {
//~ Static fields/initializers -------------------------------------------------------------------------------------------
private static final int UPDATE_INTERVAL = 1200;
//~ Instance fields ------------------------------------------------------------------------------------------------------
private TargetAppRunner runner;
private ThreadsDataManager threadsDataManager;
private VMTelemetryDataManager vmTelemetryManager;
// private boolean doUpdateLiveResults;
private boolean keepRunning = true;
private volatile boolean oomeNotified;
//~ Constructors ---------------------------------------------------------------------------------------------------------
UpdateThread() {
super("Profiler Monitor"); // NOI18N
}
//~ Methods --------------------------------------------------------------------------------------------------------------
public void monitor(final TargetAppRunner runner) {
oomeNotified = false;
this.runner = runner;
this.threadsDataManager = Profiler.getDefault().getThreadsManager();
this.vmTelemetryManager = Profiler.getDefault().getVMTelemetryManager();
if (runner != null) {
this.vmTelemetryManager.maxHeapSize = runner.getProfilingSessionStatus().maxHeapSize;
}
}
public void run() {
while (keepRunning) { // Main loop
try {
if (runner != null) {
// ProfilerControlPanel2.getDefault().updateStatus(); // TODO: move elsewhere
final MonitoredData md = runner.getProfilerClient().getMonitoredData();
if (md != null) {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
try {
setServerState(md.getServerState());
setServerProgress(md.getServerProgress());
threadsDataManager.processData(md);
vmTelemetryManager.processData(md);
// ---------------------------------------------------------
// Temporary workaround to refresh profiling points when LiveResultsWindow is not refreshing
// TODO: move this code to a separate class performing the update if necessary
// final Profiler profiler = Profiler.getDefault();
// final ProfilerClient client = profiler.getTargetAppRunner().getProfilerClient();
// final int instrType = client.getCurrentInstrType();
// if ((NetBeansProfiler.getDefaultNB().processesProfilingPoints())
// && (!doUpdateLiveResults /*|| !LiveResultsWindow.hasDefault()*/)) {
// ProfilerUtils.runInProfilerRequestProcessor(new Runnable() {
// public void run() {
// try {
// if (instrType != ProfilerEngineSettings.INSTR_CODE_REGION) {
// client.forceObtainedResultsDump(true);
// }
// } catch (Exception e /*ClientUtils.TargetAppOrVMTerminated targetAppOrVMTerminated*/) {
// }
// }
// });
//
// }
//
// // ---------------------------------------------------------
//
// // Let results updating happen every other cycle (i.e. every ~2.5 sec) to allow the user to understand something before it disappears :-)
//// if (doUpdateLiveResults && LiveResultsWindow.hasDefault()) {
//// LiveResultsWindow.getDefault().refreshLiveResults();
//// }
//
// doUpdateLiveResults = !doUpdateLiveResults;
} catch (Exception e) {
Profiler.getDefault().notifyException(Profiler.EXCEPTION, e);
} catch (OutOfMemoryError e) {
if (!oomeNotified) {
oomeNotified = true;
ProfilerDialogs.displayError(Bundle.ProfilingMonitor_OomeMsg());
}
}
}
});
} else {
NetBeansProfiler.getDefaultNB().checkAndUpdateState();
runner = null; // stop monitoring, the TA must have terminated
}
}
} catch (Throwable t) {
// prevent thread from dying on exceptions from JFluid engine
if (t instanceof ThreadDeath) {
throw (ThreadDeath) t;
}
}
try {
sleep(UPDATE_INTERVAL);
} catch (InterruptedException e) {
break;
}
}
}
private void stopThread() {
keepRunning = false;
}
}
//~ Static fields/initializers -----------------------------------------------------------------------------------------------
static final String PROPERTY_SERVER_STATE = "serverState";
static final String PROPERTY_SERVER_PROGRESS = "serverProgress";
//~ Instance fields ----------------------------------------------------------------------------------------------------------
private UpdateThread monitorThread;
private boolean updateThreadStarted = false;
private int serverState = CommonConstants.SERVER_RUNNING;
private int serverProgress = CommonConstants.SERVER_PROGRESS_INDETERMINATE;
private PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);
//~ Constructors -------------------------------------------------------------------------------------------------------------
/**
* Initializes the Form
*/
public ProfilingMonitor() {
monitorThread = new UpdateThread();
}
//~ Methods ------------------------------------------------------------------------------------------------------------------
public void monitorVM(final TargetAppRunner runner) {
//set server state before first MONITORED_NUMBERS response arrives
setServerState(CommonConstants.SERVER_INITIALIZING);
setServerProgress(CommonConstants.SERVER_PROGRESS_INDETERMINATE);
if (!updateThreadStarted) {
updateThreadStarted = true;
monitorThread.start();
}
monitorThread.monitor(runner);
}
public void stopDisplayingVM() {
if (monitorThread != null) {
monitorThread.monitor(null);
}
}
public void stopUpdateThread() {
if (monitorThread != null) {
monitorThread.stopThread();
monitorThread = null;
}
}
private void setServerState(int serverState) {
if(this.serverState != serverState) {
int oldValue = this.serverState;
this.serverState = serverState;
propertyChangeSupport.firePropertyChange(PROPERTY_SERVER_STATE, oldValue, serverState);
}
}
int getServerState() {
return serverState;
}
private void setServerProgress(int serverProgress) {
if(this.serverProgress != serverProgress)
{
int oldValue = this.serverProgress;
this.serverProgress = serverProgress;
propertyChangeSupport.firePropertyChange(PROPERTY_SERVER_PROGRESS, oldValue, serverProgress);
}
}
int getServerProgress() {
return serverProgress;
}
void addPropertyChangeListener(PropertyChangeListener listener) {
propertyChangeSupport.addPropertyChangeListener(listener);
}
void removePropertyChangeListener(PropertyChangeListener listener) {
propertyChangeSupport.addPropertyChangeListener(listener);
}
}