| /******************************************************************************* |
| * (C) Copyright 2010, 2018 IBM Corp. and others. |
| * |
| * This program and the accompanying materials are made |
| * available under the terms of the Eclipse Public License 2.0 |
| * which is available at https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Thavidu Ranatunga (IBM) - Initial implementation. |
| *******************************************************************************/ |
| package org.eclipse.linuxtools.internal.perf; |
| |
| import java.io.BufferedReader; |
| import java.io.IOException; |
| import java.io.InputStreamReader; |
| import java.io.PrintStream; |
| import java.net.URI; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.regex.Matcher; |
| import java.util.regex.Pattern; |
| |
| import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants; |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.core.resources.ResourcesPlugin; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Path; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.debug.core.ILaunchConfiguration; |
| import org.eclipse.linuxtools.internal.perf.model.PMCommand; |
| import org.eclipse.linuxtools.internal.perf.model.PMDso; |
| import org.eclipse.linuxtools.internal.perf.model.PMEvent; |
| import org.eclipse.linuxtools.internal.perf.model.PMFile; |
| import org.eclipse.linuxtools.internal.perf.model.PMSymbol; |
| import org.eclipse.linuxtools.internal.perf.model.TreeParent; |
| import org.eclipse.linuxtools.internal.perf.ui.PerfProfileView; |
| import org.eclipse.linuxtools.profiling.launch.ConfigUtils; |
| import org.eclipse.linuxtools.tools.launch.core.factory.RuntimeProcessFactory; |
| import org.eclipse.osgi.util.NLS; |
| import org.eclipse.swt.widgets.Display; |
| import org.eclipse.ui.PartInitException; |
| import org.eclipse.ui.PlatformUI; |
| |
| public class PerfCore { |
| |
| private static String spitStream(BufferedReader br, String blockTitle, PrintStream print) { |
| |
| StringBuffer strBuf = new StringBuffer(); |
| String line = null; |
| try { |
| while (( line = br.readLine()) != null){ |
| strBuf.append(line); |
| strBuf.append("\n"); //$NON-NLS-1$ |
| } |
| } catch (IOException e) { |
| logException(e); |
| } |
| String str = strBuf.toString(); |
| if (!str.trim().isEmpty() && print != null) { |
| print.println(blockTitle + ": \n" +str + "\n END OF " + blockTitle); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| return str; |
| } |
| // Maps event lists to host names for caching |
| private static Map<String,Map<String, List<String>>> eventsHostMap = null; |
| private static Map<String,List<String>> eventList = null; |
| |
| /** |
| * Gets the list of events for a given launch configuration. Uses a cache for each host |
| * @param config |
| * @return |
| */ |
| public static Map<String,List<String>> getEventList(ILaunchConfiguration config) { |
| String projectHost = getHostName(config); |
| |
| if(eventsHostMap == null){ |
| eventsHostMap = new HashMap<>(); |
| } |
| |
| // local projects have null hosts |
| if(projectHost == null){ |
| projectHost = "local"; //$NON-NLS-1$ |
| } |
| |
| eventList = eventsHostMap.get(projectHost); |
| |
| if(eventList == null){ |
| eventList = loadEventList(config); |
| eventsHostMap.put(projectHost, eventList); |
| } |
| return eventList; |
| } |
| |
| |
| /** |
| * |
| * @param config |
| * @return the name of the host in which the config's project is stored |
| */ |
| private static String getHostName(ILaunchConfiguration config){ |
| String projectName = null; |
| try { |
| projectName = config.getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROJECT_NAME, ""); //$NON-NLS-1$ |
| } catch (CoreException e) { |
| return null; |
| } |
| if (projectName.isEmpty()) { |
| return null; |
| } |
| IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName); |
| if(project == null){ |
| return null; |
| } |
| |
| URI projectURI = project.getLocationURI(); |
| if (projectURI == null) { |
| Status status = new Status(IStatus.WARNING, PerfPlugin.PLUGIN_ID, |
| NLS.bind(Messages.MsgNoProjectError, projectName)); |
| PerfPlugin.getDefault().getLog().log(status); |
| return null; |
| } |
| return project.getLocationURI().getHost(); |
| |
| } |
| |
| public static IProject getProject(ILaunchConfiguration config){ |
| if(config == null){ |
| return null; |
| } else { |
| try { |
| String projectName = ConfigUtils.getProjectName(config); |
| // an empty string is not a legal path to file argument for ConfigUtils.getProject |
| if (projectName != null && !projectName.isEmpty()) { |
| return ConfigUtils.getProject(projectName); |
| } |
| } catch (CoreException e1) { |
| logException(e1); |
| } |
| } |
| |
| return null; |
| } |
| |
| private static Map<String,List<String>> loadEventList(ILaunchConfiguration config){ |
| Map<String,List<String>> events = new HashMap<>(); |
| IProject project = getProject(config); |
| |
| if (!PerfCore.checkPerfInPath(project)) { |
| return events; |
| } |
| |
| Process p = null; |
| BufferedReader input = null; |
| try { |
| // Execute "perf list" to get list of all symbolic event types. |
| // Alternatively can try with -i flag. |
| p = RuntimeProcessFactory.getFactory().exec(new String[] {PerfPlugin.PERF_COMMAND, "list"}, project); //(char 1 as -t is a custom field seperator //$NON-NLS-1$ |
| |
| /* |
| * Old versions of Perf will send events list to stderr instead of stdout |
| * Checking if stdout is empty then read from stderr |
| */ |
| input = new BufferedReader(new InputStreamReader(p.getInputStream())); |
| |
| } catch( IOException e ) { |
| logException(e); |
| } |
| return parseEventList(input); |
| } |
| |
| public static Map<String,List<String>> parseEventList (BufferedReader input){ |
| Map<String,List<String>> events = new HashMap<>(); |
| String line; |
| try { |
| // Process list of events. Each line is of the form <event>\s+<category>. |
| while (( line = input.readLine()) != null){ |
| if (line.contains("[")) { //$NON-NLS-1$ |
| String event; |
| String category; |
| if (line.contains(PerfPlugin.STRINGS_HWBREAKPOINTS)) { |
| category = PerfPlugin.STRINGS_HWBREAKPOINTS; |
| event = line.substring(1,line.indexOf('[', 0)).trim(); |
| } else if (line.contains(PerfPlugin.STRINGS_RAWHWEvents)) { |
| category = PerfPlugin.STRINGS_RAWHWEvents; |
| event = line.substring(1,line.indexOf('[', 0)).trim(); |
| } else { |
| event = line.substring(1,line.indexOf('[', 0)).trim(); |
| if (event.contains("OR")) { //$NON-NLS-1$ |
| event = event.split("OR")[0]; //filter out the abbreviations. //$NON-NLS-1$ |
| } |
| category = line.replaceFirst(".*\\[(.+)\\]", "$1").trim(); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| List<String> categoryEvents = events.get(category); |
| if (categoryEvents == null) { |
| categoryEvents = new ArrayList<>(); |
| events.put(category, categoryEvents); |
| } |
| categoryEvents.add(event.trim()); |
| } |
| } |
| } catch (IOException e) { |
| logException(e); |
| } finally { |
| if (null != input) { |
| try { |
| input.close(); |
| } catch (IOException e) { |
| } |
| } |
| } |
| return events; |
| } |
| |
| //Gets the current version of perf |
| public static PerfVersion getPerfVersion(ILaunchConfiguration config) { |
| IProject project = getProject(config); |
| Process p = null; |
| |
| try { |
| p = RuntimeProcessFactory.getFactory().exec(new String [] {PerfPlugin.PERF_COMMAND, "--version"}, project); //$NON-NLS-1$ |
| } catch (IOException e) { |
| // Issue warning to avoid AERI reports whenever user is missing perf |
| Status status = new Status(IStatus.WARNING, PerfPlugin.PLUGIN_ID, |
| e.getMessage()); |
| PerfPlugin.getDefault().getLog().log(status); |
| } |
| |
| if (p == null) { |
| return null; |
| } |
| |
| BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream())); |
| |
| String perfVersion = spitStream(input, "Perf --version", null); //$NON-NLS-1$ |
| int index = perfVersion.indexOf('-'); |
| if (index > 0) { |
| perfVersion = perfVersion.substring(0, index); |
| } |
| Pattern pattern = Pattern.compile("\\D*((\\d|\\.)+)"); //$NON-NLS-1$ |
| Matcher matcher = pattern.matcher(perfVersion); |
| if (matcher.matches()) { |
| return new PerfVersion(matcher.group(1)); |
| } |
| return null; |
| } |
| |
| |
| public static boolean checkPerfInPath(IProject project) { |
| try { |
| Process p = RuntimeProcessFactory.getFactory().exec(new String [] {PerfPlugin.PERF_COMMAND, "--version"}, project); //$NON-NLS-1$ |
| return (p != null); |
| } catch (IOException e) { |
| return false; |
| } |
| } |
| |
| //Generates a perf record command string with the options set in the given config. (If null uses default). |
| public static String [] getRecordString(ILaunchConfiguration config) { |
| String [] base = new String [] {PerfPlugin.PERF_COMMAND, "record"}; //$NON-NLS-1$ |
| if (config == null) { |
| return base; |
| } else { |
| ArrayList<String> newCommand = new ArrayList<>(); |
| newCommand.addAll(Arrays.asList(base)); |
| try { |
| if (config.getAttribute(PerfPlugin.ATTR_Record_Realtime, PerfPlugin.ATTR_Record_Realtime_default)) { |
| newCommand.add("-r"); //$NON-NLS-1$ |
| int priority = config.getAttribute(PerfPlugin.ATTR_Record_Realtime_Priority, PerfPlugin.ATTR_Record_Realtime_Priority_default); |
| newCommand.add(Integer.toString(priority)); |
| } |
| if (config.getAttribute(PerfPlugin.ATTR_Record_Verbose, PerfPlugin.ATTR_Record_Verbose_default)) |
| newCommand.add("-v"); //$NON-NLS-1$ |
| if (config.getAttribute(PerfPlugin.ATTR_Multiplex, PerfPlugin.ATTR_Multiplex_default)) |
| newCommand.add("-M"); //$NON-NLS-1$ |
| List<?> selE = config.getAttribute(PerfPlugin.ATTR_SelectedEvents, PerfPlugin.ATTR_SelectedEvents_default); |
| if (!config.getAttribute(PerfPlugin.ATTR_DefaultEvent, PerfPlugin.ATTR_DefaultEvent_default) |
| && selE != null) { |
| for(Object e : selE) { |
| newCommand.add("-e"); //$NON-NLS-1$ |
| newCommand.add((String)e); |
| } |
| } |
| } catch (CoreException e) { } |
| return newCommand.toArray(new String[] {}); |
| } |
| } |
| |
| public static String[] getReportString(ILaunchConfiguration config, String perfDataLoc) { |
| ArrayList<String> base = new ArrayList<>(); |
| base.addAll(Arrays.asList(new String [] {PerfPlugin.PERF_COMMAND, "report", "--sort", "comm,dso,sym", "-n", "-t", "" + (char)1 }));//(char 1 as -t is a custom field seperator) //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ |
| if (config != null) { |
| try { |
| String kernelLoc = config.getAttribute(PerfPlugin.ATTR_Kernel_Location, PerfPlugin.ATTR_Kernel_Location_default); |
| if (!kernelLoc.equals(PerfPlugin.ATTR_Kernel_Location_default)) { |
| base.add("--vmlinux"); //$NON-NLS-1$ |
| base.add(kernelLoc); |
| } |
| if (config.getAttribute(PerfPlugin.ATTR_ModuleSymbols, PerfPlugin.ATTR_ModuleSymbols_default)) { |
| base.add("-m"); //$NON-NLS-1$ |
| } |
| |
| /* |
| * danielhb, 12/14/2011 - some systems, like ubuntu and sles, does not have |
| * the -U option. The binary fails to execute in those systems when this |
| * option is enabled. |
| * I'm disabling it to make the plug-in runnable for them. This |
| * will probably need to be revisited in the future, probably when this |
| * flag is implemented by the Perf binary of those systems. |
| */ |
| /* |
| if (config.getAttribute(PerfPlugin.ATTR_HideUnresolvedSymbols, PerfPlugin.ATTR_HideUnresolvedSymbols_default)) |
| base.add("-U"); |
| */ |
| if (perfDataLoc != null) { |
| base.add("-i"); //$NON-NLS-1$ |
| base.add(perfDataLoc); |
| } |
| } catch (CoreException e) { } |
| } |
| return base.toArray( new String[base.size()] ); |
| } |
| |
| public static String[] getAnnotateString(ILaunchConfiguration config, String dso, String symbol, String perfDataLoc, boolean oldPerfVersion) { |
| ArrayList<String> base = new ArrayList<>(); |
| if (oldPerfVersion) { |
| base.addAll( Arrays.asList( new String[]{PerfPlugin.PERF_COMMAND, "annotate", "-s", symbol, "-l", "-P"} ) ); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ |
| } else { |
| base.addAll( Arrays.asList( new String[]{PerfPlugin.PERF_COMMAND, "annotate", "--stdio", "-d", dso, "-s", symbol, "-l", "-P"} ) ); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ |
| } |
| if (config != null) { |
| try { |
| String kernelLoc = config.getAttribute(PerfPlugin.ATTR_Kernel_Location, PerfPlugin.ATTR_Kernel_Location_default); |
| if (!kernelLoc.equals(PerfPlugin.ATTR_Kernel_Location_default)) { |
| base.add("--vmlinux"); //$NON-NLS-1$ |
| base.add(kernelLoc); |
| } |
| if (config.getAttribute(PerfPlugin.ATTR_ModuleSymbols, PerfPlugin.ATTR_ModuleSymbols_default)) { |
| base.add("-m"); //$NON-NLS-1$ |
| } |
| if (perfDataLoc != null) { |
| base.add("-i"); //$NON-NLS-1$ |
| base.add(perfDataLoc); |
| } |
| } catch (CoreException e) { } |
| } |
| /* |
| * Some versions of perf annotate hangs while waiting for an input. |
| * Redirect input from an empty file (or /dev/null) to avoid that behavior. |
| */ |
| base.add("<"); //$NON-NLS-1$ |
| base.add("/dev/null"); //$NON-NLS-1$ |
| |
| //(Annotate string per symbol) |
| return base.toArray( new String[base.size()] ); |
| } |
| |
| // Runs assuming perf.data has already been recorded, environ and workingDir can be set to null to use default |
| //perfDataLoc is optional - it is used to provide a pre-existing data file instead of something recorded from |
| //whatever project is being profiled. It is only used for junit tests atm. |
| public static void report(ILaunchConfiguration config, IPath workingDir, IProgressMonitor monitor, String perfDataLoc, PrintStream print) { |
| IProject project = getProject(config); |
| |
| TreeParent invisibleRoot = PerfPlugin.getDefault().clearModelRoot(); |
| |
| PerfVersion perfVersion = getPerfVersion(config); |
| boolean oldPerfVersion = false; |
| |
| if (perfVersion == null) { |
| if (print != null) { |
| print.println("ERROR: Unable to find Perf version, please verify it is installed and on the run path"); //$NON-NLS-1$ |
| return; |
| } |
| } else if (!perfVersion.isNewer(new PerfVersion(0, 0, 2))) { |
| oldPerfVersion = true; |
| if (print != null) { print.println("WARNING: You are running an older version of Perf, please update if you can. The plugin may produce unpredictable results."); } //$NON-NLS-1$ |
| } |
| |
| |
| BufferedReader input = null; |
| BufferedReader error = null; |
| Process p = null; |
| |
| if (monitor != null && monitor.isCanceled()) { |
| return; |
| } |
| |
| try { |
| if (workingDir==null) { |
| p = RuntimeProcessFactory.getFactory().exec(getReportString(config, perfDataLoc), project); |
| PerfPlugin.getDefault().setPerfProfileData(new Path(perfDataLoc)); |
| PerfPlugin.getDefault().setWorkingDir(project.getLocation()); |
| } else { |
| String defaultPerfDataLoc = workingDir.toOSString() + PerfPlugin.PERF_DEFAULT_DATA; |
| p = RuntimeProcessFactory.getFactory().exec(getReportString(config, defaultPerfDataLoc), project); |
| PerfPlugin.getDefault().setPerfProfileData(new Path(defaultPerfDataLoc)); |
| PerfPlugin.getDefault().setWorkingDir(workingDir); |
| } |
| |
| input = new BufferedReader(new InputStreamReader(p.getInputStream())); |
| error = new BufferedReader(new InputStreamReader(p.getErrorStream())); |
| //spitting error stream moved to end of while loop, due to commenting of p.waitFor() |
| } catch( IOException e ) { |
| logException(e); |
| } |
| |
| PerfCore.parseRemoteReport(config, workingDir, monitor, perfDataLoc, print, |
| invisibleRoot, oldPerfVersion, input, error, project); |
| } |
| |
| /** |
| * Parse and build a tree model from the report of a perf data file |
| * @param config launch configuration |
| * @param workingDir working directory configuration |
| * @param monitor monitor |
| * @param perfDataLoc location of perf data file |
| * @param print print stream |
| * @param invisibleRoot root of the model |
| * @param oldPerfVersion boolean old perf version flag |
| * @param input input stream from perf data file report |
| * @param error output stream to where all standard error is written to |
| */ |
| public static void parseReport(ILaunchConfiguration config, |
| IPath workingDir, IProgressMonitor monitor, String perfDataLoc, |
| PrintStream print, TreeParent invisibleRoot, |
| boolean oldPerfVersion, BufferedReader input, BufferedReader error) { |
| PerfCore.parseRemoteReport(config, workingDir, monitor, perfDataLoc, print, |
| invisibleRoot, oldPerfVersion, input, error, null); |
| } |
| |
| private static void parseRemoteReport(ILaunchConfiguration config, |
| IPath workingDir, IProgressMonitor monitor, String perfDataLoc, |
| PrintStream print, TreeParent invisibleRoot, |
| boolean oldPerfVersion, BufferedReader input, BufferedReader error, IProject project) { |
| |
| if (monitor != null && monitor.isCanceled()) { |
| return; |
| } |
| String line = null; |
| String items[]; |
| float percent; |
| |
| Process p = null; |
| double samples; |
| String comm,dso,symbol; |
| boolean kernelFlag; |
| PMEvent currentEvent = null; |
| PMCommand currentCommand = null; |
| PMDso currentDso = null; |
| PMFile currentFile = null; |
| PMSymbol currentSym = null; |
| try { |
| while (( line = input.readLine()) != null){ |
| if (monitor != null && monitor.isCanceled()) { |
| return; |
| } |
| // line containing report information |
| if ((line.startsWith("#"))) { //$NON-NLS-1$ |
| if (line.contains("Events:") || line.contains("Samples:")) { //$NON-NLS-1$ //$NON-NLS-2$ |
| // ignore lost samples as the plugin has no logic for handling them |
| if (line.startsWith("# Total Lost Samples:")) { //$NON-NLS-1$ |
| continue; |
| } |
| String[] tmp = line.trim().split(" "); //$NON-NLS-1$ |
| String event = tmp[tmp.length - 1]; |
| // In this case, the event name is single quoted |
| if (line.contains("Samples:")){ //$NON-NLS-1$ |
| event = event.substring(1, event.length() -1); |
| } |
| currentEvent = new PMEvent(event); |
| invisibleRoot.addChild(currentEvent); |
| currentCommand = null; |
| currentDso = null; |
| } else if (line.contains("Samples:")) { //"samples" was used instead of events in an older version, some incompatibilities may arise. //$NON-NLS-1$ |
| if (print != null) { print.println("WARNING: You are running an older version of Perf, please update if you can. The plugin may produce unpredictable results."); } //$NON-NLS-1$ |
| invisibleRoot.addChild(new PMEvent("WARNING: You are running an older version of Perf, the plugin may produce unpredictable results.")); //$NON-NLS-1$ |
| } |
| // contains profiled information |
| } else { |
| items = line.trim().split(""+(char)1); // using custom field separator. for default whitespace use " +" //$NON-NLS-1$ |
| if (items.length != 5) { |
| continue; |
| } |
| percent = Float.parseFloat(items[0].replace("%", "")); //$NON-NLS-1$ //$NON-NLS-2$ |
| samples = Double.parseDouble(items[1].trim()); //samples column |
| comm = items[2].trim(); //command column |
| dso = items[3].trim(); //dso column |
| symbol = items[4].trim(); //symbol column |
| kernelFlag = (""+symbol.charAt(1)).equals("k"); //$NON-NLS-1$ //$NON-NLS-2$ |
| |
| // initialize current command if it doesn't exist |
| if ((currentCommand == null) || (!currentCommand.getName().equals(comm))) { |
| currentCommand = (PMCommand) currentEvent.getChild(comm); |
| if(currentCommand == null) { |
| currentCommand = new PMCommand(comm); |
| currentEvent.addChild(currentCommand); |
| } |
| } |
| |
| // initialize current dso if it doesn't exist |
| if ((currentDso == null) || (!currentDso.getName().equals(dso))) { |
| currentDso = (PMDso) currentCommand.getChild(dso); |
| if (currentDso == null) { |
| currentDso = new PMDso(dso,kernelFlag); |
| currentCommand.addChild(currentDso); |
| } |
| } |
| |
| /* |
| * Initialize the current file, and symbol |
| * |
| * We won't know the name of the file containing the symbol |
| * until we run 'perf annotate' to resolve it, so for now we |
| * attach all symbols as children of 'Unfiled Symbols'. |
| */ |
| currentFile = currentDso.getFile(PerfPlugin.STRINGS_UnfiledSymbols); |
| currentSym = new PMSymbol(symbol, percent, samples); |
| currentFile.addChild(currentSym); |
| } |
| } |
| } catch (IOException e) { |
| logException(e); |
| } |
| spitStream(error,"Perf Report", print); //$NON-NLS-1$ |
| |
| boolean SourceLineNumbers = PerfPlugin.ATTR_SourceLineNumbers_default; |
| boolean Kernel_SourceLineNumbers = PerfPlugin.ATTR_Kernel_SourceLineNumbers_default; |
| try { |
| // Check if resolving source file/line numbers is selected |
| SourceLineNumbers = config.getAttribute(PerfPlugin.ATTR_SourceLineNumbers, PerfPlugin.ATTR_SourceLineNumbers_default); |
| Kernel_SourceLineNumbers = config.getAttribute(PerfPlugin.ATTR_Kernel_SourceLineNumbers, PerfPlugin.ATTR_Kernel_SourceLineNumbers_default); |
| } catch (CoreException e2) { |
| SourceLineNumbers = false; |
| } |
| |
| if (monitor != null && monitor.isCanceled()) { |
| return; |
| } |
| |
| boolean hasProfileData = invisibleRoot.getChildren().length != 0; |
| |
| if (SourceLineNumbers) { |
| for (TreeParent ev : invisibleRoot.getChildren()) { |
| if (!(ev instanceof PMEvent)) continue; |
| for (TreeParent cmd : ev.getChildren()) { |
| if (!(cmd instanceof PMCommand)) continue; |
| for (TreeParent d : cmd.getChildren()) { |
| if (!(d instanceof PMDso)) continue; |
| currentDso = (PMDso)d; |
| if ((!Kernel_SourceLineNumbers) && currentDso.isKernelDso()) continue; |
| for (TreeParent s : currentDso.getFile(PerfPlugin.STRINGS_UnfiledSymbols).getChildren()) { |
| if (!(s instanceof PMSymbol)) continue; |
| |
| if (monitor != null && monitor.isCanceled()) { |
| return; |
| } |
| currentSym = (PMSymbol)s; |
| String[] annotateCmd; |
| if (workingDir == null) { |
| annotateCmd = getAnnotateString(config, currentDso.getName(), currentSym.getName().substring(4), perfDataLoc, oldPerfVersion); |
| } else { |
| String perfDefaultDataLoc = workingDir + "/" + PerfPlugin.PERF_DEFAULT_DATA; //$NON-NLS-1$ |
| annotateCmd = getAnnotateString(config, currentDso.getName(), currentSym.getName().substring(4), perfDefaultDataLoc, oldPerfVersion); |
| } |
| |
| try { |
| if(project==null) { |
| p = Runtime.getRuntime().exec(annotateCmd); |
| } else { |
| StringBuffer sb = new StringBuffer(); |
| ArrayList<String> al = new ArrayList<>(); |
| /* |
| * Wrap the whole Perf annotate line as a single argument of sh command |
| * so that any IO redirection will take effect. Change to working directory before run perf annotate. |
| * It results on a command string as 'sh', '-c', 'cd <workindir> && perf annotate <args> < /dev/null' |
| */ |
| al.add("sh"); //$NON-NLS-1$ |
| al.add("-c"); //$NON-NLS-1$ |
| if(workingDir != null) { |
| sb.append("cd " + workingDir.toOSString() + " && "); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| for(int i=0; i<annotateCmd.length; i++) { |
| sb.append(annotateCmd[i]); |
| sb.append(" "); //$NON-NLS-1$ |
| } |
| al.add(sb.toString()); |
| p = RuntimeProcessFactory.getFactory().exec(al.toArray(new String[]{}), project); |
| } |
| input = new BufferedReader(new InputStreamReader(p.getInputStream())); |
| error = new BufferedReader(new InputStreamReader(p.getErrorStream())); |
| } catch (IOException e) { |
| logException(e); |
| } |
| |
| PerfCore.parseAnnotation(monitor, input, workingDir, currentDso, currentSym); |
| } |
| |
| if (currentDso.getFile(PerfPlugin.STRINGS_UnfiledSymbols).getChildren().length == 0) { |
| currentDso.removeChild(currentDso.getFile(PerfPlugin.STRINGS_UnfiledSymbols)); |
| } |
| spitStream(error,"Perf Annotate", print); //$NON-NLS-1$ |
| } |
| } |
| } |
| } |
| |
| if (print != null) { |
| if (hasProfileData) { |
| print.println("Profile data loaded into Perf Profile View."); //$NON-NLS-1$ |
| } else { |
| print.println("No profile data generated to be displayed."); //$NON-NLS-1$ |
| } |
| } |
| } |
| |
| /** |
| * Parse annotation file for a dso given a symbol |
| * @param monitor monitor |
| * @param input annotation file input stream |
| * @param workingDir working directory configuration |
| * @param currentDso dso |
| * @param currentSym symbol |
| */ |
| public static void parseAnnotation(IProgressMonitor monitor, |
| BufferedReader input, IPath workingDir, PMDso currentDso, |
| PMSymbol currentSym) { |
| |
| if (monitor != null && monitor.isCanceled()) { |
| return; |
| } |
| |
| boolean grabBlock = false; |
| boolean blockStarted = false; |
| String dsoName,lineRef; |
| String line = null; |
| String items[]; |
| float percent; |
| |
| try { |
| while (( line = input.readLine()) != null){ |
| if (line.startsWith("Sorted summary for file")) { //$NON-NLS-1$ |
| grabBlock = true; |
| dsoName = line.replace("Sorted summary for file ",""); //$NON-NLS-1$ //$NON-NLS-2$ |
| blockStarted = false; |
| if ((workingDir != null) && (dsoName.startsWith("./"))) { //$NON-NLS-1$ |
| if (workingDir.toOSString().endsWith("/")) { //$NON-NLS-1$ |
| dsoName = workingDir.toOSString() + dsoName.substring(2); // path already ends with '/', so trim './' |
| } else { |
| dsoName = workingDir.toOSString() + dsoName.substring(1); // path doesn't have '/', so trim just the '.' |
| } |
| } |
| currentDso.setPath(dsoName); |
| } else if (line.startsWith("---")) { //$NON-NLS-1$ |
| if (blockStarted) { |
| blockStarted = false; |
| grabBlock = false; |
| } else { |
| blockStarted = true; |
| } |
| } else if (grabBlock && blockStarted) { |
| //process the line. |
| items = line.trim().split(" +"); //$NON-NLS-1$ |
| if (items.length != 2) { |
| continue; |
| } |
| percent = Float.parseFloat(items[0]); |
| lineRef = items[1]; |
| items = lineRef.split(":"); //$NON-NLS-1$ |
| if (currentDso == null) { |
| //if (PerfPlugin.DEBUG_ON) System.err.println("Parsed line ref without being in valid block, shouldn't happen."); |
| break; |
| } else { |
| int lineNum = -1; |
| try { |
| /* |
| * May not have line number when parsing a line like "100.00 [vdso][7ffce9fdbda0]" |
| */ |
| if( items.length > 1) { |
| lineNum = Integer.parseInt(items[1]); |
| } |
| } catch (NumberFormatException e) { |
| // leave line number as -1 |
| } |
| currentSym.addPercent(lineNum, percent); |
| // Symbol currently in 'Unfiled Symbols' but we now know the actual parent |
| if (currentSym.getParent().getName().equals(PerfPlugin.STRINGS_UnfiledSymbols)) { |
| currentSym.getParent().removeChild(currentSym); |
| currentDso.getFile(items[0]).addChild(currentSym); |
| // Symbol has 2 (or more) parents |
| } else if (!((PMFile)currentSym.getParent()).getPath().equals(items[0])) { |
| currentSym.markConflict(); |
| currentSym.getParent().removeChild(currentSym); |
| currentDso.getFile(PerfPlugin.STRINGS_MultipleFilesForSymbol).addChild(currentSym); |
| } |
| } |
| } |
| } |
| } catch (IOException e) { |
| logException(e); |
| } |
| } |
| |
| public static void refreshView (final String title) { |
| Display.getDefault().syncExec(() -> { |
| try { |
| PerfProfileView view = (PerfProfileView) PlatformUI |
| .getWorkbench().getActiveWorkbenchWindow() |
| .getActivePage().showView(PerfPlugin.VIEW_ID); |
| view.setContentDescription(title); |
| view.refreshModel(); |
| } catch (PartInitException e) { |
| logException(e); |
| } |
| }); |
| } |
| |
| /** |
| * Log specified exception. |
| * @param e Exception to log. |
| */ |
| public static void logException(Exception e) { |
| Status status = new Status(IStatus.ERROR, PerfPlugin.PLUGIN_ID, |
| e.getMessage()); |
| PerfPlugin.getDefault().getLog().log(status); |
| } |
| } |