| /* |
| * 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.awt.Cursor; |
| import java.awt.Window; |
| import java.io.*; |
| import java.nio.file.Files; |
| import java.nio.file.StandardCopyOption; |
| import java.util.*; |
| import java.util.logging.Level; |
| import java.util.logging.Logger; |
| import javax.swing.JFileChooser; |
| 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.TargetAppRunner; |
| import org.netbeans.lib.profiler.client.ClientUtils; |
| import org.netbeans.lib.profiler.common.CommonUtils; |
| import org.netbeans.lib.profiler.common.Profiler; |
| import org.netbeans.lib.profiler.common.ProfilingSettings; |
| import org.netbeans.lib.profiler.global.CommonConstants; |
| import org.netbeans.lib.profiler.results.ProfilingResultsDispatcher; |
| import org.netbeans.lib.profiler.results.ResultsSnapshot; |
| import org.netbeans.lib.profiler.results.RuntimeCCTNode; |
| import org.netbeans.lib.profiler.results.cpu.CPUCCTProvider; |
| import org.netbeans.lib.profiler.results.cpu.CPUResultsDiff; |
| import org.netbeans.lib.profiler.results.cpu.CPUResultsSnapshot; |
| import org.netbeans.lib.profiler.results.jdbc.JdbcResultsDiff; |
| import org.netbeans.lib.profiler.results.jdbc.JdbcResultsSnapshot; |
| import org.netbeans.lib.profiler.results.memory.AllocMemoryResultsDiff; |
| import org.netbeans.lib.profiler.results.memory.AllocMemoryResultsSnapshot; |
| import org.netbeans.lib.profiler.results.memory.LivenessMemoryResultsDiff; |
| import org.netbeans.lib.profiler.results.memory.LivenessMemoryResultsSnapshot; |
| import org.netbeans.lib.profiler.results.memory.MemoryCCTProvider; |
| import org.netbeans.lib.profiler.results.memory.SampledMemoryResultsDiff; |
| import org.netbeans.lib.profiler.results.memory.SampledMemoryResultsSnapshot; |
| import org.netbeans.lib.profiler.ui.swing.ExportUtils; |
| import org.netbeans.lib.profiler.utils.StringUtils; |
| import org.netbeans.modules.profiler.api.ProfilerDialogs; |
| import org.netbeans.modules.profiler.api.ProfilerStorage; |
| import org.netbeans.modules.profiler.utilities.ProfilerUtils; |
| import org.openide.cookies.OpenCookie; |
| import org.openide.filesystems.FileLock; |
| import org.openide.filesystems.FileObject; |
| import org.openide.filesystems.FileUtil; |
| import org.openide.loaders.DataObject; |
| import org.openide.loaders.DataObjectNotFoundException; |
| import org.openide.util.Exceptions; |
| import org.openide.util.Lookup; |
| import org.openide.util.NbBundle; |
| import org.openide.util.lookup.ServiceProvider; |
| import org.openide.util.lookup.ServiceProviders; |
| import org.openide.windows.WindowManager; |
| |
| |
| /** An manager for management/notifications about obtainer profiling results. |
| * |
| * @author Tomas Hurka |
| * @author Ian Formanek |
| */ |
| @NbBundle.Messages({ |
| "ResultsManager_SnapshotSaveFailedMsg=Failed to save snapshot: {0}", |
| "ResultsManager_SnapshotCreateFailedMsg=Failed to create snapshot file: {0}", |
| "ResultsManager_ProfiledAppTerminatedMsg=Failed to obtain results snapshot. The profiled application terminated.", |
| "ResultsManager_DataNotAvailableMsg=Failed to obtain results snapshot. Data is not available yet.", |
| "ResultsManager_OutOfMemoryMsg=Too much data collected - the profiler ran out of memory.\n\nCollected profiling data has been deleted and profiling resumed.\nTo avoid this error, increase the -Xmx value\nin the etc/netbeans.conf file in NetBeans IDE installation\nor decrease the amount of detail in profiling settings.", |
| "ResultsManager_SnapshotDeleteFailedMsg=Failed to delete the snapshot file: {0}", |
| "ResultsManager_CantFindSnapshotLocationMsg=Cannot find default location for snapshot in project: {0}", |
| "ResultsManager_SnapshotCreateInProjectFailedMsg=Failed to create snapshot file in project: {0}", |
| "ResultsManager_SnapshotLoadFailed=Error while loading snapshot: {0}", |
| "ResultsManager_SnapshotsLoadFailedMsg=Loading snapshots failed.", |
| "ResultsManager_ObtainSavedSnapshotsFailedMsg=Failed to obtain list of saved snaphshots for project: {0}", |
| "ResultsManager_SelectDirDialogCaption=Select Target Directory", |
| "ResultsManager_SaveButtonName=Save", |
| "ResultsManager_OverwriteFileDialogCaption=Overwrite Existing File?", |
| "ResultsManager_OverwriteFileDialogMsg=The target folder already contains file {0}\n Do you want to overwrite this file?", |
| "ResultsManager_FileDeleteFailedMsg=Cannot delete the existing file: {0}", |
| "ResultsManager_SnapshotExportFailedMsg=<html><b>Failed to export snapshot:</b><br><br>{0}</html>", |
| "ResultsManager_ExportSnapshotData=Export Snapshot Data", |
| "ResultsManager_SelectFileOrDirDialogCaption=Select File or Directory", |
| "ResultsManager_ProfilerSnapshotFileFilter=Profiler Snapshot File (*.{0})", |
| "ResultsManager_ProfilerHeapdumpFileFilter=Heap Dump File (*.{0})", |
| "ResultsManager_OutOfMemorySavingMsg=<html><b>Not enough memory to save the snapshot.</b><br><br>To avoid this error, increase the -Xmx value<br>in the etc/netbeans.conf file in NetBeans IDE installation.</html>", |
| "ResultsManager_CannotCompareSnapshotsMsg=<html><b>Cannot compare snapshots:</b><br><br> {0}<br> {1}<br><br>Make sure that both snaphots are the same type.</html>", |
| "ResultsManager_DirectoryDoesntExistCaption=Selected Directory Does Not Exist", |
| "ResultsManager_DirectoryDoesntExistMsg=The directory you have selected does not exist.\nDo you want to create the directory?", |
| "ResultsManager_SnapshotLoadFailedMsg=<html><b>Snapshot {0} failed to load.</b><br><br>{1}</html>", |
| "ResultsManager_CannotOpenSnapshotMsg=<html><b>Cannot open profiler snapshot.</b><br><br>Attempting to open null snapshot.<br>Check the logfile for details.</html>", |
| "ResultsManager_CpuSnapshotDisplayName=cpu: {0}", |
| "ResultsManager_MemorySnapshotDisplayName=mem: {0}", |
| "ResultsManager_HeapSnapshotDisplayName=heap: {0}", |
| "MSG_SavingSnapshots=Saving Snapshots", |
| "MSG_SavingSnapshot=Saving Snapshot", |
| "ResultsManager_CaptionWarning=Warning", |
| "ResultsManager_DifferentObjectSize=<html><b>Object sizes are different.</b><br><br>Size of the same objects differ for each snapshot and their comparison is invalid.<br>The snapshots have likely been taken on different architectures (32bit vs. 64bit).</html>" |
| }) |
| public final class ResultsManager { |
| private static final Logger LOGGER = Logger.getLogger(ResultsManager.class.getName()); |
| |
| //~ Inner Classes ------------------------------------------------------------------------------------------------------------ |
| |
| // /** |
| // * Resets collected results (either memory or CPU, depending on current mode). |
| // */ |
| // public void resetCollectors() { |
| // reset(); |
| // int instr = Profiler.getDefault().getTargetAppRunner().getProfilerClient().getCurrentInstrType(); |
| // ProfilingResultsDispatcher.getDefault().reset(); |
| // if (instr == CommonConstants.INSTR_RECURSIVE_FULL || instr == CommonConstants.INSTR_RECURSIVE_SAMPLED) { |
| // // TODO reset cpu profiling results collectors |
| //// CPUCallGraphBuilder.resetCollectors(); |
| // } else if (instr == CommonConstants.INSTR_OBJECT_ALLOCATIONS || instr == CommonConstants.INSTR_OBJECT_LIVENESS) { |
| // MemoryCallGraphBuilder mcgb = Profiler.getDefault().getTargetAppRunner().getProfilerClient().getMemoryCallGraphBuilder(); |
| // mcgb.resetCollectors(); |
| // } |
| // fireResultsReset(); |
| // } |
| static class SelectedFile { |
| //~ Instance fields ------------------------------------------------------------------------------------------------------ |
| |
| FileObject folder; |
| String fileExt; |
| String fileName; |
| |
| //~ Constructors --------------------------------------------------------------------------------------------------------- |
| |
| SelectedFile(FileObject folder, String fileName, String fileExt) { |
| this.folder = folder; |
| this.fileName = fileName; |
| this.fileExt = fileExt; |
| } |
| } |
| |
| //~ Static fields/initializers ----------------------------------------------------------------------------------------------- |
| public static final String SNAPSHOT_EXTENSION = "nps"; // NOI18N |
| public static final String HEAPDUMP_EXTENSION = "hprof"; // NOI18N |
| /* see org.netbeans.modules.sampler.SampleOutputStream.FILE_EXT */ |
| public static final String STACKTRACES_SNAPSHOT_EXTENSION = "npss"; // NOI18N |
| |
| static final String HEAPDUMP_PREFIX = "heapdump-"; // NOI18N // should differ from generated OOME heapdumps not to be detected as OOME |
| private static final String SNAPSHOT_PREFIX = "snapshot-"; // NOI18N |
| private static final long MINIMAL_TIMESTAMP = 946684800000L; // Sat, 01 Jan 2000 00:00:00 GMT in milliseconds since 01 Jan 1970 |
| |
| //~ Instance fields ---------------------------------------------------------------------------------------------------------- |
| |
| private ArrayList<LoadedSnapshot> loadedSnapshots = new ArrayList<LoadedSnapshot>(); |
| private File exportDir; |
| private HashMap<FileObject, ProfilingSettings> settingsCache = new HashMap<FileObject, ProfilingSettings>(); |
| private HashMap<FileObject, Integer> typeCache = new HashMap<FileObject, Integer>(); |
| private Window mainWindow; |
| private boolean resultsAvailable = false; |
| |
| private Lookup.Result<SnapshotsListener> snapshotListeners; |
| private Lookup.Result<ResultsListener> resultsListeners; |
| |
| //~ Constructors ------------------------------------------------------------------------------------------------------------- |
| private ResultsManager() { |
| Lookup l = Lookup.getDefault(); |
| snapshotListeners = l.lookupResult(SnapshotsListener.class); |
| resultsListeners = l.lookupResult(ResultsListener.class); |
| } |
| |
| private static class Singleton { |
| private static final ResultsManager INSTANCE = new ResultsManager(); |
| } |
| |
| //~ Methods ------------------------------------------------------------------------------------------------------------------ |
| |
| public static ResultsManager getDefault() { |
| return Singleton.INSTANCE; |
| } |
| |
| public String getDefaultSnapshotFileName(LoadedSnapshot ls) { |
| return SNAPSHOT_PREFIX + ls.getSnapshot().getTimeTaken(); |
| } |
| |
| public String getSnapshotDisplayName(LoadedSnapshot ls) { |
| String name = ls.getFile() == null ? null : ls.getFile().getName(); |
| if (name == null) { |
| name = getDefaultSnapshotFileName(ls); |
| } else { |
| int dotIndex = name.lastIndexOf('.'); // NOI18N |
| if (dotIndex > 0 && dotIndex <= name.length() - 2) |
| name = name.substring(0, dotIndex); |
| } |
| return getSnapshotDisplayName(name, ls.getType()); |
| } |
| |
| public String getSnapshotDisplayName(String fileName, int snapshotType) { |
| String displayName; |
| if (fileName.startsWith(SNAPSHOT_PREFIX)) { |
| String time = fileName.substring(SNAPSHOT_PREFIX.length(), fileName.length()); |
| try { |
| long timeStamp = Long.parseLong(time); |
| if (timeStamp > MINIMAL_TIMESTAMP) { |
| displayName = StringUtils.formatUserDate(new Date(timeStamp)); |
| } else { |
| // file name is probably customized |
| displayName = fileName; |
| } |
| } catch (NumberFormatException e) { |
| // file name is probably customized |
| displayName = fileName; |
| } |
| } else { |
| displayName = fileName; |
| } |
| // switch (snapshotType) { |
| // case LoadedSnapshot.SNAPSHOT_TYPE_CPU: |
| // return Bundle.ResultsManager_CpuSnapshotDisplayName(displayName); |
| // case LoadedSnapshot.SNAPSHOT_TYPE_MEMORY_ALLOCATIONS: |
| // case LoadedSnapshot.SNAPSHOT_TYPE_MEMORY_LIVENESS: |
| // case LoadedSnapshot.SNAPSHOT_TYPE_MEMORY_SAMPLED: |
| // return Bundle.ResultsManager_MemorySnapshotDisplayName(displayName); |
| // default: |
| // return displayName; |
| // } |
| return displayName; |
| } |
| |
| public String getDefaultHeapDumpFileName(long time) { |
| return HEAPDUMP_PREFIX + time; |
| } |
| |
| public String getHeapDumpDisplayName(String fileName) { |
| String displayName; |
| if (fileName.startsWith(HEAPDUMP_PREFIX)) { |
| String time = fileName.substring(HEAPDUMP_PREFIX.length(), fileName.length()); |
| try { |
| long timeStamp = Long.parseLong(time); |
| if (timeStamp > MINIMAL_TIMESTAMP) { |
| displayName = StringUtils.formatUserDate(new Date(timeStamp)); |
| } else { |
| // file name is probably customized |
| displayName = fileName; |
| } |
| } catch (NumberFormatException e) { |
| // file name is probably customized |
| displayName = fileName; |
| } |
| } else { |
| displayName = fileName; |
| } |
| |
| return displayName; |
| // return Bundle.ResultsManager_HeapSnapshotDisplayName(displayName); |
| } |
| |
| public LoadedSnapshot[] getLoadedSnapshots() { |
| return loadedSnapshots.toArray(new LoadedSnapshot[0]); |
| } |
| |
| public LoadedSnapshot getSnapshotFromFileObject(FileObject fo) { |
| LoadedSnapshot ls = findAlreadyLoadedSnapshot(fo); |
| |
| if (ls != null) { |
| return ls; |
| } |
| |
| try { |
| return loadSnapshotFromFileObject(fo); |
| } catch (IOException e) { |
| LOGGER.log(Level.SEVERE, null, e); |
| |
| return null; |
| } |
| } |
| |
| public ProfilingSettings getSnapshotSettings(FileObject fo) { |
| ProfilingSettings settings = settingsCache.get(fo); |
| |
| if ((settings == null) && !settingsCache.containsKey(fo)) { |
| settings = readSettingsFromFile(fo); |
| settingsCache.put(fo, settings); |
| } |
| |
| return settings; |
| } |
| |
| public int getSnapshotType(FileObject fo) { |
| Integer type = typeCache.get(fo); |
| |
| if (type == null) { |
| type = Integer.valueOf(readTypeFromFile(fo)); |
| typeCache.put(fo, type); |
| } |
| |
| return type.intValue(); |
| } |
| |
| @ServiceProviders({@ServiceProvider(service=CPUCCTProvider.Listener.class), @ServiceProvider(service=MemoryCCTProvider.Listener.class)}) |
| public static final class ResultsMonitor implements CPUCCTProvider.Listener, MemoryCCTProvider.Listener { |
| //~ Methods -------------------------------------------------------------------------------------------------------------- |
| |
| public void cctEstablished(RuntimeCCTNode runtimeCCTNode, boolean empty) { |
| if (!empty) { |
| ResultsManager rm = getDefault(); |
| if (!rm.resultsAvailable() && !isSomeResultsAvailable()) { |
| return; |
| } |
| rm.resultsBecameAvailable(); |
| } |
| } |
| |
| public void cctReset() { |
| getDefault().resultsReset(); |
| } |
| |
| private boolean isSomeResultsAvailable() { |
| // check that we have data for snapshot, CPU profiling can have non-empty |
| // batch, but this batch can contain only marker methods |
| Profiler profiler = Profiler.getDefault(); |
| ProfilerClient client = profiler.getTargetAppRunner().getProfilerClient(); |
| int profilingType = profiler.getLastProfilingSettings().getProfilingType(); |
| |
| if (profilingType == ProfilingSettings.PROFILE_CPU_ENTIRE || |
| profilingType == ProfilingSettings.PROFILE_CPU_PART) { |
| try { |
| // construct snapshot and check that it has some data |
| client.getCPUProfilingResultsSnapshot(false); |
| } catch (CPUResultsSnapshot.NoDataAvailableException ex) { |
| // we don't have data for snapshot |
| return false; |
| } catch (ClientUtils.TargetAppOrVMTerminated ex) { |
| // target VM is down |
| return false; |
| } |
| } |
| return true; |
| } |
| } |
| |
| public void closeSnapshot(LoadedSnapshot ls) { |
| if (ls != null) { |
| loadedSnapshots.remove(ls); |
| fireSnapshotRemoved(ls); |
| } |
| } |
| |
| public void compareSnapshots(FileObject snapshot1FO, FileObject snapshot2FO) { |
| LoadedSnapshot s1 = null; |
| LoadedSnapshot s2 = null; |
| |
| FileObject snapshotFO = snapshot1FO; |
| |
| try { |
| s1 = findAlreadyLoadedSnapshot(snapshot1FO); |
| |
| if (s1 == null) { |
| s1 = loadSnapshotImpl(snapshot1FO); |
| } |
| |
| snapshotFO = snapshot2FO; |
| |
| s2 = findAlreadyLoadedSnapshot(snapshot2FO); |
| |
| if (s2 == null) { |
| s2 = loadSnapshotFromFileObject(snapshot2FO); |
| } |
| } catch (Exception e) { |
| LOGGER.log(Level.INFO, Bundle.ResultsManager_SnapshotLoadFailed(snapshotFO.getPath()), e); |
| ProfilerDialogs.displayError(Bundle.ResultsManager_SnapshotLoadFailedMsg(snapshotFO.getNameExt(), e.getMessage())); |
| |
| return; |
| } |
| |
| if ((s1 != null) && (s2 != null)) { |
| compareSnapshots(s1, s2); |
| } else { |
| ProfilerDialogs.displayError(Bundle.ResultsManager_SnapshotsLoadFailedMsg()); |
| } |
| } |
| |
| public ResultsSnapshot createDiffSnapshot(LoadedSnapshot s1, LoadedSnapshot s2) { |
| ResultsSnapshot snap1 = s1.getSnapshot(); |
| ResultsSnapshot snap2 = s2.getSnapshot(); |
| ResultsSnapshot diff = null; |
| |
| if (snap1 instanceof SampledMemoryResultsSnapshot && snap2 instanceof SampledMemoryResultsSnapshot) { |
| SampledMemoryResultsSnapshot sn1 = (SampledMemoryResultsSnapshot)snap1; |
| SampledMemoryResultsSnapshot sn2 = (SampledMemoryResultsSnapshot)snap2; |
| checkObjectSizes(sn1.getClassNames(), sn1.getObjectsCounts(), sn1.getObjectsSizePerClass(), 1, |
| sn2.getClassNames(), sn2.getObjectsCounts(), sn2.getObjectsSizePerClass(), 1); |
| diff = new SampledMemoryResultsDiff((SampledMemoryResultsSnapshot)snap1, |
| (SampledMemoryResultsSnapshot)snap2); |
| } else if (snap1 instanceof AllocMemoryResultsSnapshot && snap2 instanceof AllocMemoryResultsSnapshot) { |
| AllocMemoryResultsSnapshot sn1 = (AllocMemoryResultsSnapshot)snap1; |
| AllocMemoryResultsSnapshot sn2 = (AllocMemoryResultsSnapshot)snap2; |
| // Note: instrumented allocations not compared because of #236363 |
| // ProfilingSettings sn1s = s1.getSettings(); |
| // ProfilingSettings sn2s = s2.getSettings(); |
| // checkObjectSizes(sn1.getClassNames(), sn1.getObjectsCounts(), sn1.getObjectsSizePerClass(), sn1s.getAllocTrackEvery(), |
| // sn2.getClassNames(), sn2.getObjectsCounts(), sn2.getObjectsSizePerClass(), sn2s.getAllocTrackEvery()); |
| checkObjectSizes(sn1.getClassNames(), sn1.getObjectsCounts(), sn1.getObjectsSizePerClass(), Integer.MAX_VALUE, |
| sn2.getClassNames(), sn2.getObjectsCounts(), sn2.getObjectsSizePerClass(), Integer.MAX_VALUE); |
| diff = new AllocMemoryResultsDiff((AllocMemoryResultsSnapshot)snap1, |
| (AllocMemoryResultsSnapshot)snap2); |
| } else if (snap1 instanceof LivenessMemoryResultsSnapshot && snap2 instanceof LivenessMemoryResultsSnapshot) { |
| LivenessMemoryResultsSnapshot sn1 = (LivenessMemoryResultsSnapshot)snap1; |
| LivenessMemoryResultsSnapshot sn2 = (LivenessMemoryResultsSnapshot)snap2; |
| // Note: using track each 1 object to prevent unnecessary division, the data are always correct for liveness results |
| // ProfilingSettings sn1s = s1.getSettings(); |
| // ProfilingSettings sn2s = s2.getSettings(); |
| // checkObjectSizes(sn1.getClassNames(), sn1.getNTrackedLiveObjects(), sn1.getTrackedLiveObjectsSize(), sn1s.getAllocTrackEvery(), |
| // sn2.getClassNames(), sn2.getNTrackedLiveObjects(), sn2.getTrackedLiveObjectsSize(), sn2s.getAllocTrackEvery()); |
| checkObjectSizes(sn1.getClassNames(), sn1.getNTrackedLiveObjects(), sn1.getTrackedLiveObjectsSize(), 1, |
| sn2.getClassNames(), sn2.getNTrackedLiveObjects(), sn2.getTrackedLiveObjectsSize(), 1); |
| diff = new LivenessMemoryResultsDiff((LivenessMemoryResultsSnapshot)snap1, |
| (LivenessMemoryResultsSnapshot)snap2); |
| } else if (snap1 instanceof CPUResultsSnapshot && snap2 instanceof CPUResultsSnapshot) { |
| diff = new CPUResultsDiff((CPUResultsSnapshot)snap1, (CPUResultsSnapshot)snap2); |
| } else if (snap1 instanceof JdbcResultsSnapshot && snap2 instanceof JdbcResultsSnapshot) { |
| diff = new JdbcResultsDiff((JdbcResultsSnapshot)snap1, (JdbcResultsSnapshot)snap2); |
| } |
| |
| return diff; |
| } |
| |
| public void compareSnapshots(final LoadedSnapshot s1, final LoadedSnapshot s2) { |
| CommonUtils.runInEventDispatchThread(new Runnable() { |
| public void run() { |
| SnapshotResultsWindow srw = SnapshotResultsWindow.get(s1, 0, false); |
| if (!srw.setRefSnapshot(s2)) { |
| ProfilerDialogs.displayError(Bundle.ResultsManager_CannotCompareSnapshotsMsg( |
| s1.getFile().getName(), s2.getFile().getName())); |
| } else { |
| srw.open(); |
| srw.requestActive(); |
| } |
| } |
| }); |
| } |
| |
| static void checkObjectSizes(String[] names1, int[] counts1, long[] sizes1, int n1, |
| String[] names2, int[] counts2, long[] sizes2, int n2) { |
| String obj1 = "java.lang.Object"; // NOI18N // Sampled snapshots |
| String obj2 = "java/lang/Object"; // NOI18N // Instrumented snapshots |
| |
| int idx1 = -1; |
| for (int i = 0; i < names1.length; i++) |
| if (obj1.equals(names1[i]) || obj2.equals(names1[i])) { |
| idx1 = i; |
| break; |
| } |
| if (idx1 == -1 || counts1[idx1] == 0) return; // Should not happen |
| |
| int idx2 = -1; |
| for (int i = 0; i < names2.length; i++) |
| if (obj1.equals(names2[i]) || obj2.equals(names2[i])) { |
| idx2 = i; |
| break; |
| } |
| if (idx2 == -1 || counts2[idx2] == 0) return; // Should not happen |
| |
| // Note: instrumented allocations not compared because of #236363 |
| long objsize1 = n1 == 1 ? sizes1[idx1] / counts1[idx1] : 0; |
| long objsize2 = n2 == 1 ? sizes2[idx2] / counts2[idx2] : 0; |
| |
| if (objsize1 != objsize2) |
| ProfilerDialogs.displayWarningDNSA(Bundle.ResultsManager_DifferentObjectSize(), |
| Bundle.ResultsManager_CaptionWarning(), null, |
| "ResultsManager.checkObjectSizes", false); // NOI18N |
| } |
| |
| public void deleteSnapshot(FileObject snapshotFile) { |
| LoadedSnapshot ls = findLoadedSnapshot(FileUtil.toFile(snapshotFile)); |
| |
| try { |
| snapshotFile.delete(); |
| } catch (IOException e) { |
| LOGGER.log(Level.SEVERE, Bundle.ResultsManager_SnapshotDeleteFailedMsg(e.getMessage()), e); |
| |
| return; // do not proceed with removing the snapshot from internal structures |
| } |
| |
| if (ls != null) { // if the snapshot has been loaded, remove the internal structures as well |
| loadedSnapshots.remove(ls); |
| fireSnapshotRemoved(ls); |
| } |
| } |
| |
| public void exportSnapshots(final FileObject[] selectedSnapshots) { |
| assert (selectedSnapshots != null); |
| assert (selectedSnapshots.length > 0); |
| |
| final String[] fileName = new String[1], fileExt = new String[1]; |
| final FileObject[] dir = new FileObject[1]; |
| if (selectedSnapshots.length == 1) { |
| SelectedFile sf = selectSnapshotTargetFile(selectedSnapshots[0].getName(), |
| selectedSnapshots[0].getExt().equals(HEAPDUMP_EXTENSION)); |
| |
| if ((sf != null) && checkFileExists(sf)) { |
| fileName[0] = sf.fileName; |
| fileExt[0] = sf.fileExt; |
| dir[0] = sf.folder; |
| } else { // dialog cancelled by the user |
| return; |
| } |
| } else { |
| JFileChooser chooser = new JFileChooser(); |
| |
| if (exportDir != null) { |
| chooser.setCurrentDirectory(exportDir); |
| } |
| |
| chooser.setDialogTitle(Bundle.ResultsManager_SelectDirDialogCaption()); |
| chooser.setApproveButtonText(Bundle.ResultsManager_SaveButtonName()); |
| chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); |
| chooser.setMultiSelectionEnabled(false); |
| |
| if (chooser.showSaveDialog(WindowManager.getDefault().getMainWindow()) == JFileChooser.APPROVE_OPTION) { |
| File file = chooser.getSelectedFile(); |
| |
| if (!file.exists()) { |
| if (!ProfilerDialogs.displayConfirmation( |
| Bundle.ResultsManager_DirectoryDoesntExistMsg(), |
| Bundle.ResultsManager_DirectoryDoesntExistCaption())) { |
| return; // cancelled by the user |
| } |
| |
| file.mkdir(); |
| } |
| |
| exportDir = file; |
| |
| dir[0] = FileUtil.toFileObject(FileUtil.normalizeFile(file)); |
| } else { // dialog cancelled |
| return; |
| } |
| } |
| final ProgressHandle ph = ProgressHandle.createHandle(Bundle.MSG_SavingSnapshots()); |
| ph.setInitialDelay(500); |
| ph.start(); |
| ProfilerUtils.runInProfilerRequestProcessor(new Runnable() { |
| @Override |
| public void run() { |
| try { |
| for (int i = 0; i < selectedSnapshots.length; i++) { |
| exportSnapshot(selectedSnapshots[i], dir[0], fileName[0] != null ? fileName[0] : selectedSnapshots[i].getName(), fileExt[0] != null ? fileExt[0] : selectedSnapshots[i].getExt()); |
| } |
| } finally { |
| ph.finish(); |
| } |
| } |
| }); |
| } |
| |
| public LoadedSnapshot findLoadedSnapshot(ResultsSnapshot snapshot) { |
| Iterator it = loadedSnapshots.iterator(); |
| |
| while (it.hasNext()) { |
| LoadedSnapshot ls = (LoadedSnapshot) it.next(); |
| |
| if (ls.getSnapshot() == snapshot) { |
| return ls; |
| } |
| } |
| |
| return null; |
| } |
| |
| public LoadedSnapshot findLoadedSnapshot(File snapshotFile) { |
| Iterator it = loadedSnapshots.iterator(); |
| |
| while (it.hasNext()) { |
| LoadedSnapshot ls = (LoadedSnapshot) it.next(); |
| |
| if ((ls.getFile() != null) && ls.getFile().equals(snapshotFile)) { |
| return ls; |
| } |
| } |
| |
| return null; |
| } |
| |
| private static final String HPROF_HEADER = "JAVA PROFILE 1.0"; // NOI18H |
| private static final long MIN_HPROF_SIZE = 1024*1024L; |
| public static boolean checkHprofFile(File file) { |
| try { |
| if (file.isFile() && file.canRead() && file.length()>MIN_HPROF_SIZE) { // heap dump must be 1M and bigger |
| byte[] prefix = new byte[HPROF_HEADER.length()+4]; |
| RandomAccessFile raf = new RandomAccessFile(file,"r"); // NOI18H |
| raf.readFully(prefix); |
| raf.close(); |
| if (new String(prefix).startsWith(HPROF_HEADER)) { |
| return true; |
| } |
| } |
| } catch (FileNotFoundException ex) { |
| return false; |
| } catch (IOException ex) { |
| return false; |
| } |
| return false; |
| } |
| |
| public FileObject[] listSavedHeapdumps(Lookup.Provider project, File directory) { |
| try { |
| FileObject snapshotsFolder = null; |
| |
| if (project == null && directory != null) { |
| snapshotsFolder = FileUtil.toFileObject(directory); |
| } else { |
| snapshotsFolder = ProfilerStorage.getProjectFolder(project, false); |
| } |
| |
| if (snapshotsFolder == null) { |
| return new FileObject[0]; |
| } |
| |
| snapshotsFolder.refresh(); |
| |
| FileObject[] children = snapshotsFolder.getChildren(); |
| |
| ArrayList /*<FileObject>*/ files = new ArrayList /*<FileObject>*/(); |
| |
| for (int i = 0; i < children.length; i++) { |
| FileObject child = children[i]; |
| if (checkHprofFile(FileUtil.toFile(children[i]))) |
| files.add(child); |
| } |
| |
| Collections.sort(files, |
| new Comparator() { |
| public int compare(Object o1, Object o2) { |
| FileObject f1 = (FileObject) o1; |
| FileObject f2 = (FileObject) o2; |
| |
| return f1.getName().compareTo(f2.getName()); |
| } |
| }); |
| |
| return (FileObject[])files.toArray(new FileObject[0]); |
| } catch (IOException e) { |
| LOGGER.log(Level.SEVERE, Bundle.ResultsManager_ObtainSavedSnapshotsFailedMsg(e.getMessage()), e); |
| |
| return new FileObject[0]; |
| } |
| } |
| |
| public FileObject[] listSavedSnapshots(Lookup.Provider project, File directory) { |
| try { |
| FileObject snapshotsFolder = null; |
| |
| if (project == null && directory != null) { |
| snapshotsFolder = FileUtil.toFileObject(directory); |
| } else { |
| snapshotsFolder = ProfilerStorage.getProjectFolder(project, false); |
| } |
| |
| if (snapshotsFolder == null) { |
| return new FileObject[0]; |
| } |
| |
| snapshotsFolder.refresh(); |
| |
| FileObject[] children = snapshotsFolder.getChildren(); |
| |
| ArrayList /*<FileObject>*/ files = new ArrayList /*<FileObject>*/(); |
| |
| for (int i = 0; i < children.length; i++) { |
| FileObject child = children[i]; |
| |
| if (child.getExt().equalsIgnoreCase(SNAPSHOT_EXTENSION)) { |
| files.add(child); |
| } |
| } |
| |
| Collections.sort(files, |
| new Comparator() { |
| public int compare(Object o1, Object o2) { |
| FileObject f1 = (FileObject) o1; |
| FileObject f2 = (FileObject) o2; |
| |
| return f1.getName().compareTo(f2.getName()); |
| } |
| }); |
| |
| return (FileObject[])files.toArray(new FileObject[0]); |
| } catch (IOException e) { |
| LOGGER.log(Level.SEVERE, Bundle.ResultsManager_ObtainSavedSnapshotsFailedMsg(e.getMessage()), e); |
| |
| return new FileObject[0]; |
| } |
| } |
| |
| public boolean hasSnapshotsFor(Lookup.Provider project) { |
| try { |
| FileObject snapshotsFolder = ProfilerStorage.getProjectFolder(project, false); |
| FileObject[] children; |
| |
| if (snapshotsFolder == null) { |
| return false; |
| } |
| snapshotsFolder.refresh(); |
| children = snapshotsFolder.getChildren(); |
| for (FileObject child : children) { |
| if (child.getExt().equalsIgnoreCase(SNAPSHOT_EXTENSION)) return true; |
| if (checkHprofFile(FileUtil.toFile(child))) return true; |
| } |
| } catch (IOException e) { |
| LOGGER.log(Level.SEVERE, Bundle.ResultsManager_ObtainSavedSnapshotsFailedMsg(e.getMessage()), e); |
| } |
| return false; |
| } |
| |
| public int getSnapshotsCountFor(Lookup.Provider project) { |
| int count = 0; |
| try { |
| FileObject snapshotsFolder = ProfilerStorage.getProjectFolder(project, false); |
| FileObject[] children; |
| |
| if (snapshotsFolder == null) { |
| return count; |
| } |
| snapshotsFolder.refresh(); |
| children = snapshotsFolder.getChildren(); |
| for (FileObject child : children) { |
| if (child.getExt().equalsIgnoreCase(SNAPSHOT_EXTENSION) || |
| checkHprofFile(FileUtil.toFile(child))) count++; |
| } |
| } catch (IOException e) { |
| LOGGER.log(Level.SEVERE, Bundle.ResultsManager_ObtainSavedSnapshotsFailedMsg(e.getMessage()), e); |
| } |
| return count; |
| } |
| |
| public LoadedSnapshot loadSnapshot(FileObject selectedFile) { |
| try { |
| return loadSnapshotImpl(selectedFile); |
| } catch (IOException e) { |
| LOGGER.log(Level.INFO, Bundle.ResultsManager_SnapshotLoadFailed(selectedFile.getPath()), e); |
| ProfilerDialogs.displayError(Bundle.ResultsManager_SnapshotLoadFailedMsg(selectedFile.getNameExt(), e.getMessage())); |
| |
| return null; |
| } |
| } |
| |
| public LoadedSnapshot[] loadSnapshots(FileObject[] selectedFiles) { |
| LoadedSnapshot[] ret = new LoadedSnapshot[selectedFiles.length]; |
| |
| for (int i = 0; i < selectedFiles.length; i++) { |
| try { |
| if (selectedFiles[i] != null) { |
| ret[i] = loadSnapshotImpl(selectedFiles[i]); |
| } |
| } catch (IOException e) { |
| LOGGER.log(Level.INFO, Bundle.ResultsManager_SnapshotLoadFailed(selectedFiles[i].getPath()), e); |
| ProfilerDialogs.displayError(Bundle.ResultsManager_SnapshotLoadFailedMsg(selectedFiles[i].getNameExt(), e.getMessage())); |
| } |
| } |
| |
| return ret; |
| } |
| |
| public void openSnapshot(File snapshot) { |
| File sf = FileUtil.normalizeFile(snapshot); |
| FileObject snapshotFo = FileUtil.toFileObject(sf); |
| openSnapshot(snapshotFo); |
| } |
| |
| public void openSnapshot(FileObject snapshotFo) { |
| try { |
| DataObject snapshotDo = DataObject.find(snapshotFo); |
| OpenCookie open = snapshotDo.getCookie(OpenCookie.class); |
| if (open != null) { |
| open.open(); |
| } |
| } catch (DataObjectNotFoundException ex) { |
| Exceptions.printStackTrace(ex); |
| } |
| } |
| |
| public void openSnapshot(LoadedSnapshot ls) { |
| openSnapshot(ls, CommonConstants.SORTING_COLUMN_DEFAULT, false); // target component decides which column will be used for sorting |
| } |
| |
| public void openSnapshot(final LoadedSnapshot ls, final int sortingColumn, final boolean sortingOrder) { |
| if (ls == null) ProfilerDialogs.displayError(Bundle.ResultsManager_CannotOpenSnapshotMsg()); |
| else CommonUtils.runInEventDispatchThread(new Runnable() { |
| public void run() { |
| SnapshotResultsWindow srw = SnapshotResultsWindow.get(ls, sortingColumn, sortingOrder); |
| srw.open(); |
| srw.requestActive(); |
| } |
| }); |
| } |
| |
| public void openSnapshots(LoadedSnapshot[] loaded) { |
| LoadedSnapshot loadedSnapshot = null; |
| |
| try { |
| SnapshotResultsWindow srw = null; |
| |
| for (int i = 0; i < loaded.length; i++) { |
| loadedSnapshot = loaded[i]; |
| |
| if (loaded[i] != null) { |
| srw = SnapshotResultsWindow.get(loadedSnapshot); |
| srw.open(); |
| } |
| } |
| |
| if (srw != null) { |
| srw.requestActive(); // activate the last one |
| } |
| } catch (Exception e) { |
| LOGGER.log(Level.INFO, Bundle.ResultsManager_SnapshotLoadFailed(loadedSnapshot.getFile().getAbsoluteFile()), e); |
| ProfilerDialogs.displayError(Bundle.ResultsManager_SnapshotLoadFailedMsg(loadedSnapshot.getFile().getName(), e.getMessage())); |
| } |
| } |
| |
| public LoadedSnapshot prepareSnapshot() { |
| return prepareSnapshot(true); |
| } |
| |
| public LoadedSnapshot prepareSnapshot(boolean reqeustData) { |
| ResultsSnapshot snapshot = null; |
| |
| if (!resultsAvailable()) { |
| return null; |
| } |
| |
| try { |
| final Profiler profiler = Profiler.getDefault(); |
| final TargetAppRunner runner = profiler.getTargetAppRunner(); |
| final ProfilerClient client = runner.getProfilerClient(); |
| final int currentProfilingType = profiler.getLastProfilingSettings().getProfilingType(); |
| |
| try { |
| switch (currentProfilingType) { |
| case ProfilingSettings.PROFILE_MEMORY_ALLOCATIONS: |
| case ProfilingSettings.PROFILE_MEMORY_LIVENESS: |
| case ProfilingSettings.PROFILE_MEMORY_SAMPLING: |
| snapshot = client.getMemoryProfilingResultsSnapshot(reqeustData); |
| |
| break; |
| case ProfilingSettings.PROFILE_CPU_ENTIRE: |
| case ProfilingSettings.PROFILE_CPU_PART: |
| case ProfilingSettings.PROFILE_CPU_SAMPLING: |
| snapshot = client.getCPUProfilingResultsSnapshot(reqeustData); |
| |
| break; |
| case ProfilingSettings.PROFILE_CPU_STOPWATCH: |
| snapshot = client.getCodeRegionProfilingResultsSnapshot(); |
| |
| break; |
| case ProfilingSettings.PROFILE_CPU_JDBC: |
| snapshot = client.getJdbcProfilingResultsSnapshot(reqeustData); |
| |
| break; |
| } |
| } catch (ClientUtils.TargetAppOrVMTerminated e1) { |
| ProfilerDialogs.displayWarning(Bundle.ResultsManager_ProfiledAppTerminatedMsg()); |
| ProfilerLogger.log(e1.getMessage()); |
| } catch (CPUResultsSnapshot.NoDataAvailableException e2) { |
| LOGGER.log(Level.SEVERE, Bundle.ResultsManager_DataNotAvailableMsg(), e2); |
| } catch (OutOfMemoryError e) { |
| try { |
| reset(); // reset the client data |
| runner.resetTimers(); // reset the server data |
| } catch (ClientUtils.TargetAppOrVMTerminated targetAppOrVMTerminated) { |
| // the target app has died; clean up all client data |
| client.resetClientData(); |
| } |
| |
| LOGGER.log(Level.SEVERE, Bundle.ResultsManager_OutOfMemoryMsg(), e); |
| } |
| } finally { |
| if (snapshot != null) { |
| ProfilingSettings settings = new ProfilingSettings(); |
| Profiler.getDefault().getLastProfilingSettings().copySettingsInto(settings); |
| settings.setSettingsName(Profiler.getDefault().getLastProfilingSettings().getSettingsName()); |
| |
| Lookup.Provider profiledProject = NetBeansProfiler.getDefaultNB().getProfiledProject(); |
| |
| return new LoadedSnapshot(snapshot, settings, null, profiledProject); |
| } |
| } |
| |
| return null; |
| } |
| |
| /** |
| * This should be called when the app is restarted or "Reset Collected Results" is invoked (because once this happened, |
| * there are all sorts of data that's going to be deleted/changed, and an attempt to do something with old results displayed |
| * here can cause big problems). It should also set the results panel invisible (or is it already happening?) etc. |
| */ |
| public void reset() { |
| ProfilingResultsDispatcher.getDefault().reset(); |
| resultsReset(); |
| } |
| |
| public boolean resultsAvailable() { |
| return resultsAvailable; |
| } |
| |
| |
| public static interface SnapshotHandle { |
| public LoadedSnapshot getSnapshot(); |
| } |
| |
| public ExportUtils.Exportable createSnapshotExporter(final LoadedSnapshot snapshot) { |
| return createSnapshotExporter(new SnapshotHandle() { |
| public LoadedSnapshot getSnapshot() { return snapshot; } |
| }); |
| } |
| |
| public ExportUtils.Exportable createSnapshotExporter(final SnapshotHandle handle) { |
| return new ExportUtils.Exportable() { |
| public String getName() { |
| return Bundle.ResultsManager_ExportSnapshotData(); |
| } |
| |
| public boolean isEnabled() { |
| return true; |
| } |
| |
| public ExportUtils.ExportProvider[] getProviders() { |
| final LoadedSnapshot snapshot = handle.getSnapshot(); |
| return new ExportUtils.ExportProvider[] { |
| new ExportUtils.AbstractNPSExportProvider(snapshot.getFile()) { |
| protected void doExport(File targetFile) { |
| exportSnapshot(snapshot, targetFile); |
| } |
| } |
| }; |
| } |
| }; |
| } |
| |
| private boolean exportSnapshot(LoadedSnapshot snapshot, File targetFile) { |
| File sourceFile = snapshot.getFile(); |
| if (sourceFile != null) { |
| try { |
| Files.copy(sourceFile.toPath(), targetFile.toPath(), StandardCopyOption.REPLACE_EXISTING, |
| StandardCopyOption.COPY_ATTRIBUTES); |
| return true; |
| } catch (Throwable t) { |
| LOGGER.log(Level.INFO, t.getMessage(), t); |
| String msg = t.getLocalizedMessage().replace("<", "<").replace(">", ">"); // NOI18N |
| ProfilerDialogs.displayError(Bundle.ResultsManager_SnapshotExportFailedMsg(msg)); |
| return false; |
| } |
| } else { |
| FileLock lock = null; |
| FileObject target = null; |
| DataOutputStream dos = null; |
| |
| try { |
| targetFile = FileUtil.normalizeFile(targetFile); |
| target = targetFile.isFile() ? FileUtil.toFileObject(targetFile) : |
| FileUtil.createData(targetFile); |
| |
| lock = target.lock(); |
| |
| OutputStream os = target.getOutputStream(lock); |
| BufferedOutputStream bos = new BufferedOutputStream(os); |
| dos = new DataOutputStream(bos); |
| // System.out.println("Saving snapshot [" + snapshot.getSnapshot().getTimeTaken() + "]"); |
| snapshot.save(dos); |
| dos.close(); |
| } catch (IOException e) { |
| try { |
| if (dos != null) dos.close(); |
| if (lock != null) target.delete(lock); |
| } catch (Exception e2) {} |
| |
| ProfilerDialogs.displayError(Bundle.ResultsManager_SnapshotSaveFailedMsg(e.getMessage())); |
| |
| return false; // failure => we wont continue with firing the event |
| } catch (OutOfMemoryError e) { |
| try { |
| if (dos != null) dos.close(); |
| if (lock != null) target.delete(lock); |
| } catch (Exception e2) {} |
| |
| ProfilerDialogs.displayError(Bundle.ResultsManager_OutOfMemorySavingMsg()); |
| |
| return false; // failure => we wont continue with firing the event |
| } finally { |
| if (lock != null) lock.releaseLock(); |
| } |
| |
| return true; |
| } |
| } |
| |
| public boolean saveSnapshot(LoadedSnapshot snapshot, FileObject profFile) { |
| FileLock lock = null; |
| DataOutputStream dos = null; |
| |
| boolean isSaved = snapshot.isSaved(); |
| snapshot.setSaved(true); // Set the file as saved in advance to prevent saving it again |
| try { |
| lock = profFile.lock(); |
| |
| OutputStream os = profFile.getOutputStream(lock); |
| BufferedOutputStream bos = new BufferedOutputStream(os); |
| dos = new DataOutputStream(bos); |
| // System.out.println("Saving snapshot [" + snapshot.getSnapshot().getTimeTaken() + "]"); |
| snapshot.save(dos); |
| dos.close(); |
| snapshot.setFile(FileUtil.toFile(profFile)); |
| snapshot.setSaved(true); |
| fireSnapshotSaved(snapshot); |
| } catch (IOException e) { |
| snapshot.setSaved(isSaved); |
| try { |
| if (dos != null) { |
| dos.close(); |
| } |
| |
| if (lock != null) { |
| profFile.delete(lock); |
| } |
| } catch (Exception e2) { |
| } |
| |
| ProfilerDialogs.displayError(Bundle.ResultsManager_SnapshotSaveFailedMsg(e.getMessage())); |
| |
| return false; // failure => we wont continue with firing the event |
| } catch (OutOfMemoryError e) { |
| snapshot.setSaved(isSaved); |
| try { |
| if (dos != null) { |
| dos.close(); |
| } |
| |
| if (lock != null) { |
| profFile.delete(lock); |
| } |
| } catch (Exception e2) { |
| } |
| |
| ProfilerDialogs.displayError(Bundle.ResultsManager_OutOfMemorySavingMsg()); |
| |
| return false; // failure => we wont continue with firing the event |
| } finally { |
| if (lock != null) { |
| lock.releaseLock(); |
| } |
| } |
| |
| return true; |
| } |
| |
| public boolean saveSnapshot(LoadedSnapshot ls) { |
| FileObject profFile = null; |
| |
| Lookup.Provider p = ls.getProject(); |
| FileObject saveDir = null; |
| |
| try { |
| saveDir = ProfilerStorage.getProjectFolder(p, true); |
| } catch (IOException e) { |
| LOGGER.log(Level.SEVERE, Bundle.ResultsManager_CantFindSnapshotLocationMsg(e.getMessage()), e); |
| |
| return false; |
| } |
| |
| try { |
| profFile = saveDir.createData(getDefaultSnapshotFileName(ls), SNAPSHOT_EXTENSION); |
| } catch (IOException e) { |
| LOGGER.log(Level.SEVERE, Bundle.ResultsManager_SnapshotCreateInProjectFailedMsg(e.getMessage()), e); |
| |
| return false; |
| } |
| |
| return saveSnapshot(ls, profFile); |
| } |
| |
| public LoadedSnapshot takeSnapshot() { |
| CommonUtils.runInEventDispatchThreadAndWait(new Runnable() { |
| public void run() { |
| mainWindow = WindowManager.getDefault().getMainWindow(); |
| } |
| }); |
| |
| final Cursor cursor = mainWindow.getCursor(); |
| mainWindow.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); |
| |
| try { |
| LoadedSnapshot snapshot = prepareSnapshot(); |
| |
| if (snapshot != null) { |
| loadedSnapshots.add(snapshot); |
| fireSnapshotTaken(snapshot); |
| |
| return snapshot; |
| } |
| } finally { |
| mainWindow.setCursor(cursor); |
| } |
| |
| return null; |
| } |
| |
| protected void fireResultsAvailable() { |
| if (LOGGER.isLoggable(Level.FINEST)) { |
| LOGGER.log(Level.FINEST, "fireResultsAvailable", new Exception()); |
| } |
| if (resultsListeners.allClasses().isEmpty()) { |
| return; |
| } |
| |
| CommonUtils.runInEventDispatchThread(new Runnable() { |
| public void run() { |
| for(ResultsListener rl : resultsListeners.allInstances()) { |
| rl.resultsAvailable(); |
| } |
| } |
| }); |
| } |
| |
| protected void fireResultsReset() { |
| if (LOGGER.isLoggable(Level.FINEST)) { |
| LOGGER.log(Level.FINEST, "fireResultsReset", new Exception()); |
| } |
| if (resultsListeners.allClasses().isEmpty()) { |
| return; |
| } |
| |
| CommonUtils.runInEventDispatchThread(new Runnable() { |
| public void run() { |
| for(ResultsListener rl : resultsListeners.allInstances()) { |
| rl.resultsReset(); |
| } |
| } |
| }); |
| } |
| |
| protected void fireSnapshotLoaded(final LoadedSnapshot snapshot) { |
| if (snapshotListeners.allClasses().isEmpty()) { |
| return; |
| } |
| |
| CommonUtils.runInEventDispatchThread(new Runnable() { |
| public void run() { |
| for(SnapshotsListener sl : snapshotListeners.allInstances()) { |
| sl.snapshotLoaded(snapshot); |
| } |
| } |
| }); |
| } |
| |
| protected void fireSnapshotRemoved(final LoadedSnapshot snapshot) { |
| if (snapshotListeners.allClasses().isEmpty()) { |
| return; |
| } |
| |
| CommonUtils.runInEventDispatchThread(new Runnable() { |
| public void run() { |
| for(SnapshotsListener sl : snapshotListeners.allInstances()) { |
| sl.snapshotRemoved(snapshot); |
| } |
| } |
| }); |
| } |
| |
| protected void fireSnapshotSaved(final LoadedSnapshot snapshot) { |
| if (snapshotListeners.allClasses().isEmpty()) { |
| return; |
| } |
| |
| CommonUtils.runInEventDispatchThread(new Runnable() { |
| public void run() { |
| for(SnapshotsListener sl : snapshotListeners.allInstances()) { |
| sl.snapshotSaved(snapshot); |
| } |
| } |
| }); |
| } |
| |
| protected void fireSnapshotTaken(final LoadedSnapshot snapshot) { |
| if (snapshotListeners.allClasses().isEmpty()) { |
| return; |
| } |
| |
| CommonUtils.runInEventDispatchThread(new Runnable() { |
| public void run() { |
| for(SnapshotsListener sl : snapshotListeners.allInstances()) { |
| sl.snapshotTaken(snapshot); |
| } |
| } |
| }); |
| } |
| |
| void resultsBecameAvailable() { |
| if (Profiler.getDefault().getProfilingState() == Profiler.PROFILING_INACTIVE) return; // Calibration, ignore |
| resultsAvailable = true; |
| fireResultsAvailable(); |
| } |
| |
| void resultsReset() { |
| // NOTE: originally left as true for memory profiling due to Issue 60432, now seems to work correctly |
| resultsAvailable = false; |
| fireResultsReset(); |
| } |
| |
| // heapdump == true means selecting heapdump (*.hprof) |
| SelectedFile selectSnapshotTargetFile(final String defaultName, final boolean heapdump) { |
| String targetName; |
| FileObject targetDir; |
| |
| // 1. let the user choose file or directory |
| JFileChooser chooser = new JFileChooser(); |
| |
| if (exportDir != null) { |
| chooser.setCurrentDirectory(exportDir); |
| } |
| |
| chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES); |
| chooser.setMultiSelectionEnabled(false); |
| chooser.setDialogTitle(Bundle.ResultsManager_SelectFileOrDirDialogCaption()); |
| chooser.setApproveButtonText(Bundle.ResultsManager_SaveButtonName()); |
| chooser.setAcceptAllFileFilterUsed(false); |
| chooser.setFileFilter(new javax.swing.filechooser.FileFilter() { |
| public boolean accept(File f) { |
| return f.isDirectory() || f.getName().endsWith("." + (heapdump ? HEAPDUMP_EXTENSION : SNAPSHOT_EXTENSION)); //NOI18N |
| } |
| |
| public String getDescription() { |
| if (heapdump) { |
| return Bundle.ResultsManager_ProfilerHeapdumpFileFilter(HEAPDUMP_EXTENSION); |
| } |
| return Bundle.ResultsManager_ProfilerSnapshotFileFilter(SNAPSHOT_EXTENSION); |
| } |
| }); |
| |
| if (chooser.showSaveDialog(WindowManager.getDefault().getMainWindow()) != JFileChooser.APPROVE_OPTION) { |
| return null; // cancelled by the user |
| } |
| |
| // 2. process both cases and extract file name and extension to use |
| File file = chooser.getSelectedFile(); |
| String targetExt = heapdump ? HEAPDUMP_EXTENSION : SNAPSHOT_EXTENSION; |
| |
| if (file.isDirectory()) { // save to selected directory under default name |
| exportDir = chooser.getCurrentDirectory(); |
| targetDir = FileUtil.toFileObject(FileUtil.normalizeFile(file)); |
| targetName = defaultName; |
| } else { // save to selected file |
| exportDir = chooser.getCurrentDirectory(); |
| |
| targetDir = FileUtil.toFileObject(FileUtil.normalizeFile(exportDir)); |
| |
| String fName = file.getName(); |
| |
| // divide the file name into name and extension |
| int idx = fName.lastIndexOf('.'); // NOI18N |
| |
| if (idx == -1) { // no extension |
| targetName = fName; |
| |
| // extension will be used from source file |
| } else { // extension exists |
| if (heapdump || fName.endsWith("." + targetExt)) { // NOI18N |
| targetName = fName.substring(0, idx); |
| targetExt = fName.substring(idx + 1); |
| } else { |
| targetName = fName; |
| } |
| } |
| } |
| |
| // 3. return a newly created FileObject |
| return new SelectedFile(targetDir, targetName, targetExt); |
| } |
| |
| private boolean checkFileExists(SelectedFile sf) { |
| // check if the file already exists and if so prompt the user |
| FileObject existingFile = sf.folder.getFileObject(sf.fileName, sf.fileExt); |
| |
| if (existingFile != null) { |
| if (!ProfilerDialogs.displayConfirmation(Bundle.ResultsManager_OverwriteFileDialogMsg( |
| sf.fileName + "." //NOI18N |
| + sf.fileExt), |
| Bundle.ResultsManager_OverwriteFileDialogCaption())) { |
| return false; // cancelled by the user |
| } |
| |
| try { |
| existingFile.delete(); |
| } catch (IOException e) { |
| LOGGER.log(Level.SEVERE, Bundle.ResultsManager_FileDeleteFailedMsg(e.getMessage()), e); |
| |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| private void exportSnapshot(FileObject selectedSnapshot, FileObject targetFolder, String fileName, String fileExt) { |
| if (checkFileExists(new SelectedFile(targetFolder, fileName, fileExt))) { |
| try { |
| FileUtil.copyFile(selectedSnapshot, targetFolder, fileName, fileExt); |
| } catch (Throwable t) { |
| LOGGER.log(Level.INFO, t.getMessage(), t); |
| String msg = t.getLocalizedMessage().replace("<", "<").replace(">", ">"); // NOI18N |
| ProfilerDialogs.displayError(Bundle.ResultsManager_SnapshotExportFailedMsg(msg)); |
| } |
| } |
| } |
| |
| private LoadedSnapshot findAlreadyLoadedSnapshot(FileObject selectedFile) { |
| Iterator it = loadedSnapshots.iterator(); |
| File f = FileUtil.toFile(selectedFile); |
| |
| if (f == null) { |
| return null; |
| } |
| |
| while (it.hasNext()) { |
| LoadedSnapshot ls = (LoadedSnapshot) it.next(); |
| |
| if ((ls.getFile() != null) && (ls.getFile().equals(f))) { |
| return ls; |
| } |
| } |
| |
| return null; |
| } |
| |
| private Lookup.Provider findProjectForSnapshot(FileObject selectedFile) { |
| return ProfilerStorage.getProjectFromFolder(selectedFile.getParent()); |
| } |
| |
| private LoadedSnapshot loadSnapshotFromFileObject(FileObject selectedFile) |
| throws IOException { |
| DataInputStream dis = null; |
| |
| try { |
| InputStream is = selectedFile.getInputStream(); |
| BufferedInputStream bis = new BufferedInputStream(is); |
| dis = new DataInputStream(bis); |
| |
| LoadedSnapshot ls = LoadedSnapshot.loadSnapshot(dis); |
| |
| if (ls != null) { |
| ls.setFile(FileUtil.toFile(selectedFile)); |
| ls.setProject(findProjectForSnapshot(selectedFile)); |
| } |
| |
| return ls; |
| } finally { |
| if (dis != null) { |
| dis.close(); |
| } |
| } |
| } |
| |
| private LoadedSnapshot loadSnapshotImpl(FileObject selectedFile) |
| throws IOException { |
| LoadedSnapshot ls = findAlreadyLoadedSnapshot(selectedFile); |
| |
| if (ls != null) { |
| return ls; |
| } |
| |
| ls = loadSnapshotFromFileObject(selectedFile); |
| |
| if (ls != null) { |
| loadedSnapshots.add(ls); |
| fireSnapshotLoaded(ls); |
| } |
| |
| return ls; |
| } |
| |
| private ProfilingSettings readSettingsFromFile(FileObject fo) { |
| LoadedSnapshot ls = findAlreadyLoadedSnapshot(fo); |
| |
| if (ls != null) { |
| return ls.getSettings(); |
| } |
| |
| DataInputStream dis = null; |
| |
| try { |
| InputStream is = fo.getInputStream(); |
| BufferedInputStream bis = new BufferedInputStream(is); |
| dis = new DataInputStream(bis); |
| |
| // data before settings |
| byte[] magicArray = new byte[LoadedSnapshot.PROFILER_FILE_MAGIC_STRING.length()]; |
| int len = dis.read(magicArray); |
| |
| if ((len != LoadedSnapshot.PROFILER_FILE_MAGIC_STRING.length()) |
| || !LoadedSnapshot.PROFILER_FILE_MAGIC_STRING.equals(new String(magicArray))) { |
| return null; |
| } |
| |
| byte majorVersion = dis.readByte(); |
| byte minorVersion = dis.readByte(); |
| int type = dis.readInt(); |
| int compressedDataLen = dis.readInt(); |
| int uncompressedDataLen = dis.readInt(); |
| |
| if (dis.skipBytes(compressedDataLen) != compressedDataLen) { |
| return null; |
| } |
| |
| // settings data |
| int settingsLen = dis.readInt(); |
| byte[] settingsBytes = new byte[settingsLen]; |
| |
| if (dis.read(settingsBytes) != settingsLen) { |
| return null; |
| } |
| |
| // create settings |
| Properties props = new Properties(); |
| ProfilingSettings settings = new ProfilingSettings(); |
| ByteArrayInputStream bais2 = new ByteArrayInputStream(settingsBytes); |
| BufferedInputStream bufBais2 = new BufferedInputStream(bais2); |
| DataInputStream settingsDis = new DataInputStream(bufBais2); |
| |
| try { |
| props.load(settingsDis); |
| } catch (IOException e) { |
| ProfilerLogger.log(e); |
| |
| return null; |
| } finally { |
| settingsDis.close(); |
| } |
| |
| settings.load(props); |
| |
| return settings; |
| } catch (Exception e) { |
| ProfilerLogger.log(e); |
| |
| return null; |
| } finally { |
| try { |
| if (dis != null) { |
| dis.close(); |
| } |
| } catch (IOException e) { |
| ProfilerLogger.log(e); |
| } |
| } |
| } |
| |
| private int readTypeFromFile(FileObject fo) { |
| LoadedSnapshot ls = findAlreadyLoadedSnapshot(fo); |
| |
| if (ls != null) { |
| return ls.getType(); |
| } |
| |
| DataInputStream dis = null; |
| |
| try { |
| InputStream is = fo.getInputStream(); |
| BufferedInputStream bis = new BufferedInputStream(is); |
| dis = new DataInputStream(bis); |
| |
| byte[] magicArray = new byte[LoadedSnapshot.PROFILER_FILE_MAGIC_STRING.length()]; |
| int len = dis.read(magicArray); |
| |
| if ((len != LoadedSnapshot.PROFILER_FILE_MAGIC_STRING.length()) |
| || !LoadedSnapshot.PROFILER_FILE_MAGIC_STRING.equals(new String(magicArray))) { |
| return LoadedSnapshot.SNAPSHOT_TYPE_UNKNOWN; |
| } |
| |
| byte majorVersion = dis.readByte(); |
| byte minorVersion = dis.readByte(); |
| int type = dis.readInt(); |
| |
| return type; |
| } catch (Exception e) { |
| return LoadedSnapshot.SNAPSHOT_TYPE_UNKNOWN; |
| } finally { |
| try { |
| if (dis != null) { |
| dis.close(); |
| } |
| } catch (IOException e) { |
| e.printStackTrace(System.err); |
| } |
| } |
| } |
| } |