/******************************************************************************* * Copyright (c) 2009, 2013 STMicroelectronics. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Xavier Raynaud <xavier.raynaud@st.com> - initial API and implementation * Red Hat Inc. - fix for bug 418264 *******************************************************************************/ package org.eclipse.linuxtools.internal.gprof.view; import java.io.IOException; import org.eclipse.cdt.core.IBinaryParser.IBinaryObject; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Status; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.IAction; import org.eclipse.jface.action.IToolBarManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.resource.ColorRegistry; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.linuxtools.binutils.utils.STSymbolManager; import org.eclipse.linuxtools.dataviewers.abstractview.AbstractSTDataView; import org.eclipse.linuxtools.dataviewers.abstractviewers.AbstractSTViewer; import org.eclipse.linuxtools.dataviewers.abstractviewers.TreeColumnViewerFilter; import org.eclipse.linuxtools.dataviewers.actions.STExportToCSVAction; import org.eclipse.linuxtools.dataviewers.charts.actions.ChartAction; import org.eclipse.linuxtools.internal.gprof.Activator; import org.eclipse.linuxtools.internal.gprof.Messages; import org.eclipse.linuxtools.internal.gprof.action.SwitchContentProviderAction; import org.eclipse.linuxtools.internal.gprof.action.SwitchSampleTimeAction; import org.eclipse.linuxtools.internal.gprof.parser.GmonDecoder; import org.eclipse.linuxtools.internal.gprof.parser.HistogramDecoder; import org.eclipse.linuxtools.internal.gprof.utils.PPC64ElfBinaryObjectWrapper; import org.eclipse.linuxtools.internal.gprof.view.fields.SampleProfField; import org.eclipse.linuxtools.internal.gprof.view.histogram.CGArc; import org.eclipse.linuxtools.internal.gprof.view.histogram.CGCategory; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Text; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.PlatformUI; /** * The view where gmon file is displayed * * @author Xavier Raynaud <xavier.raynaud@st.com> */ public class GmonView extends AbstractSTDataView { public static final String ID = "org.eclipse.linuxtools.gprof.view"; //$NON-NLS-1$ /** WHITE color */ public static final Color DEFAULT_BG = PlatformUI.getWorkbench().getDisplay().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND); /** GREEN1 color : for children category */ public static final Color GREEN1 = new Color(PlatformUI.getWorkbench().getDisplay(), 207, 255, 207); /** GREEN2 color : for children */ public static final Color GREEN2 = new Color(PlatformUI.getWorkbench().getDisplay(), 175, 255, 175); /** BLUE1 color : for parent category */ public static final Color BLUE1 = new Color(PlatformUI.getWorkbench().getDisplay(), 207, 207, 255); /** BLUE2 color : for parents */ public static final Color BLUE2 = new Color(PlatformUI.getWorkbench().getDisplay(), 175, 175, 255); public static final int CALL_GRAPH_MODE = 0; public static final int SAMPLE_MODE = 1; private Label label; private Text fFilterText; private TreeColumnViewerFilter fViewerFilter; private Action action1; private Action action2; private Action action3; private Action action4; private Action switchSampleTime; @Override public void createPartControl(Composite parent) { super.createPartControl(parent); GridLayout l = (GridLayout) parent.getLayout(); l.horizontalSpacing = 0; l.verticalSpacing = 0; l.marginHeight = 0; l.marginWidth = 0; fViewerFilter = new TreeColumnViewerFilter((TreeViewer) getSTViewer().getViewer(), getSTViewer().getAllFields()[0], true); getSTViewer().getViewer().addFilter(fViewerFilter); } @Override protected void createTitle(Composite parent) { ColorRegistry colorRegistry = JFaceResources.getColorRegistry(); Color background = colorRegistry.get("org.eclipse.ui.workbench.INACTIVE_TAB_BG_START"); //$NON-NLS-1$ label = new Label(parent, SWT.WRAP); if (background != null) { label.setBackground(background); } GridData data = new GridData(SWT.FILL, SWT.BEGINNING, true, false, 1, 1); label.setLayoutData(data); fFilterText = new Text(parent, SWT.BORDER | SWT.SINGLE | SWT.SEARCH | SWT.ICON_SEARCH | SWT.ICON_CANCEL); fFilterText.setMessage(Messages.GmonView_type_filter_text); fFilterText.setToolTipText(Messages.GmonView_filter_by_name); fFilterText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); fFilterText.addModifyListener(e -> { String text = fFilterText.getText(); fViewerFilter.setMatchingText(text); }); } @Override protected void contributeToToolbar(IToolBarManager manager) { manager.add(new Separator()); manager.add(action2); action2.setChecked(true); manager.add(action3); manager.add(action4); manager.add(action1); manager.add(new Separator()); manager.add(switchSampleTime); manager.add(new Separator()); manager.add(new ChartAction(getViewSite().getShell(), getSTViewer())); } @Override protected void createActions() { super.createActions(); action1 = new SwitchContentProviderAction( "Display function call graph", "icons/ch_callees.png", getSTViewer().getViewer(), CallGraphContentProvider.sharedInstance); //$NON-NLS-1$ //$NON-NLS-2$ action2 = new SwitchContentProviderAction( "Sort samples per file", "icons/c_file_obj.gif", getSTViewer().getViewer(), FileHistogramContentProvider.sharedInstance); //$NON-NLS-1$ //$NON-NLS-2$ action3 = new SwitchContentProviderAction( "Sort samples per function", "icons/function_obj.gif", getSTViewer().getViewer(), FunctionHistogramContentProvider.sharedInstance); //$NON-NLS-1$ //$NON-NLS-2$ action4 = new SwitchContentProviderAction( "Sort samples per line", "icons/line_obj.gif", getSTViewer().getViewer(), FlatHistogramContentProvider.sharedInstance); //$NON-NLS-1$ //$NON-NLS-2$ switchSampleTime = new SwitchSampleTimeAction(this); } /* * I do not know where to put this static method. It is used by all ProfFields */ public static Color getBackground(Object element) { ColorRegistry colorRegistry = JFaceResources.getColorRegistry(); // FIXME: Not sure if color1-color4 are ever used...picked colors found in JFacesResources ColorRegistry // not tied to any particular language (e.g. didn't choose CDT or Java colors) // Color5 seems to work ok as bg in the one dark theme I tried (Nissl-Adwaita-dark-4) and as well // in default light adwaita, but it is much simpler to just return null and let the table color default // appropriately. Color color1 = colorRegistry.get("org.eclipse.ui.editors.currentLineColor"); //$NON-NLS-1$ Color color2 = colorRegistry.get("org.eclipse.ui.workbench.INACTIVE_TAB_BG_START"); //$NON-NLS-1$ Color color3 = colorRegistry.get("org.eclipse.ui.workbench.ACTIVE_NOFOCUS_TAB_BG_END"); //$NON-NLS-1$ Color color4 = colorRegistry.get("org.eclipse.ui.workbench.ACTIVE_TAB_BG_END"); //$NON-NLS-1$ // Color color5 = colorRegistry.get("org.eclipse.ui.workbench.INACTIVE_TAB_BG_START"); //$NON-NLS-1$ if (element instanceof CGCategory) { CGCategory cat = (CGCategory) element; if (CGCategory.CHILDREN.equals(cat.category)) { return color1 == null ? BLUE1 : color1; } else { return color2 == null ? GREEN1 : color2; } } else if (element instanceof CGArc) { CGArc arc = (CGArc) element; CGCategory cat = (CGCategory) arc.getParent(); if (CGCategory.CHILDREN.equals(cat.category)) { return color3 == null ? BLUE2 : color3; } else { return color4 == null ? GREEN2 : color4; } } return null; // default background // return color5 == null ? DEFAULT_BG : color5; } @Override protected AbstractSTViewer createAbstractSTViewer(Composite parent) { return new GmonViewer(parent); } /** * set the gprof view title * * @param decoder * the gmon decoder * @param titleLabel * the title label */ private static void setHistTitle(GmonDecoder decoder, Label titleLabel) { String title = " gmon file: " //$NON-NLS-1$ + decoder.getGmonFile() + "\n program file: " //$NON-NLS-1$ + decoder.getProgram().getPath() + "\n" //$NON-NLS-1$ + " timestamp: " + decoder.getGmonFileTimeStamp(); //$NON-NLS-1$ HistogramDecoder histo = decoder.getHistogramDecoder(); if (histo.hasValues()) { double prof_rate = histo.getProfRate(); String period = ""; //$NON-NLS-1$ if (prof_rate != 0) { char tUnit = histo.getTimeDimension(); switch (tUnit) { case 's': prof_rate /= 1000000000; break; case 'm': prof_rate /= 1000000; break; case 'u': prof_rate /= 1000; break; } period = ", each sample counts as " + SampleProfField.getValue(1, prof_rate); //$NON-NLS-1$ } title += "\n " + histo.getBucketSize() //$NON-NLS-1$ + " bytes per bucket" + period; //$NON-NLS-1$ } titleLabel.setText(title); titleLabel.getParent().layout(true); } /** * Display gmon results in the GProf View. NOTE: this method has to be called from within the UI thread. * * @param binaryPath * @param gmonPath * @param instanceName */ public static GmonView displayGprofView(String binaryPath, String gmonPath, IProject project) { IBinaryObject binary = STSymbolManager.sharedInstance.getBinaryObject(new Path(binaryPath)); if (binary == null) { MessageDialog.openError(PlatformUI.getWorkbench().getDisplay().getActiveShell(), "Invalid binary file", //$NON-NLS-1$ binaryPath + " is not a valid binary file."); //$NON-NLS-1$ return null; } else if (binary.getCPU().equals("ppc64") && !binary.isLittleEndian()) { //$NON-NLS-1$ binary = new PPC64ElfBinaryObjectWrapper(binary.getBinaryParser(), binary.getPath(), binary.getType()); } GmonDecoder decoder = new GmonDecoder(binary, project); try { decoder.read(gmonPath); } catch (IOException e) { Status status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, IStatus.ERROR, e.getMessage(), e); Activator.getDefault().getLog().log(status); } return displayGprofView(decoder, gmonPath); } /** * Display gmon results in the GProf View. NOTE: this method has to be called from within the UI thread. * * @param decoder * @param id Secondary id, usually path to gmon file. */ public static GmonView displayGprofView(GmonDecoder decoder, String id) { GmonView gmonview = null; try { IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); IWorkbenchPage page = window.getActivePage(); if (id != null) { id = id.replace('.', '_'); id = id.replace(':', '_'); } gmonview = (GmonView) page.showView(ID, id, IWorkbenchPage.VIEW_ACTIVATE); if (decoder.getHistogramDecoder().getProfRate() == 0) { gmonview.switchSampleTime.setToolTipText("Unable to display time, because profiling rate is null"); //$NON-NLS-1$ gmonview.switchSampleTime.setEnabled(false); } gmonview.setInput(decoder); GmonView.setHistTitle(decoder, gmonview.label); if (!decoder.getHistogramDecoder().hasValues()) { gmonview.action1.setChecked(true); gmonview.action2.setChecked(false); gmonview.action1.run(); } } catch (CoreException e) { Status status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, IStatus.ERROR, e.getMessage(), e); Activator.getDefault().getLog().log(status); } return gmonview; } @Override protected IAction createExportToCSVAction() { IAction action = new STExportToCSVAction(this.getSTViewer()) { @Override public void run() { Object o = getSTViewer().getInput(); if (o instanceof GmonDecoder) { GmonDecoder gd = (GmonDecoder) o; getExporter().setFilePath(gd.getGmonFile() + ".csv"); //$NON-NLS-1$ } super.run(); } }; return action; } }