tmf: Split the state system in a separate plugin
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.ui / src / org / eclipse / linuxtools / tmf / ui / views / callstack / CallStackView.java
index 8c0acf345ee2449404d53003f2cef81418dc99e7..1c7cc98ee477dbd3a4c8f2c661d9c019c12b6fed 100644 (file)
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2013 Ericsson
+ * Copyright (c) 2013, 2014 Ericsson
  *
  * All rights reserved. This program and the accompanying materials are
  * made available under the terms of the Eclipse Public License v1.0 which
@@ -13,6 +13,7 @@
 
 package org.eclipse.linuxtools.tmf.ui.views.callstack;
 
+import java.io.File;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -20,7 +21,11 @@ import java.util.List;
 import java.util.Map;
 
 import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.jdt.annotation.Nullable;
 import org.eclipse.jface.action.Action;
 import org.eclipse.jface.action.IAction;
 import org.eclipse.jface.action.IStatusLineManager;
@@ -39,28 +44,28 @@ import org.eclipse.jface.viewers.Viewer;
 import org.eclipse.linuxtools.internal.tmf.ui.Activator;
 import org.eclipse.linuxtools.internal.tmf.ui.ITmfImageConstants;
 import org.eclipse.linuxtools.internal.tmf.ui.Messages;
+import org.eclipse.linuxtools.statesystem.core.ITmfStateSystem;
+import org.eclipse.linuxtools.statesystem.core.exceptions.AttributeNotFoundException;
+import org.eclipse.linuxtools.statesystem.core.exceptions.StateSystemDisposedException;
+import org.eclipse.linuxtools.statesystem.core.exceptions.StateValueTypeException;
+import org.eclipse.linuxtools.statesystem.core.exceptions.TimeRangeException;
+import org.eclipse.linuxtools.statesystem.core.interval.ITmfStateInterval;
+import org.eclipse.linuxtools.statesystem.core.statevalue.ITmfStateValue;
+import org.eclipse.linuxtools.statesystem.core.statevalue.ITmfStateValue.Type;
 import org.eclipse.linuxtools.tmf.core.callstack.CallStackStateProvider;
-import org.eclipse.linuxtools.tmf.core.exceptions.AttributeNotFoundException;
-import org.eclipse.linuxtools.tmf.core.exceptions.StateSystemDisposedException;
-import org.eclipse.linuxtools.tmf.core.exceptions.StateValueTypeException;
-import org.eclipse.linuxtools.tmf.core.exceptions.TimeRangeException;
-import org.eclipse.linuxtools.tmf.core.interval.ITmfStateInterval;
 import org.eclipse.linuxtools.tmf.core.signal.TmfRangeSynchSignal;
 import org.eclipse.linuxtools.tmf.core.signal.TmfSignalHandler;
 import org.eclipse.linuxtools.tmf.core.signal.TmfTimeSynchSignal;
 import org.eclipse.linuxtools.tmf.core.signal.TmfTraceClosedSignal;
 import org.eclipse.linuxtools.tmf.core.signal.TmfTraceOpenedSignal;
 import org.eclipse.linuxtools.tmf.core.signal.TmfTraceSelectedSignal;
-import org.eclipse.linuxtools.tmf.core.statesystem.ITmfStateSystem;
-import org.eclipse.linuxtools.tmf.core.statevalue.ITmfStateValue;
-import org.eclipse.linuxtools.tmf.core.statevalue.ITmfStateValue.Type;
 import org.eclipse.linuxtools.tmf.core.timestamp.ITmfTimestamp;
 import org.eclipse.linuxtools.tmf.core.timestamp.TmfNanoTimestamp;
 import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimeRange;
 import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimestamp;
 import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimestampDelta;
 import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace;
-import org.eclipse.linuxtools.tmf.core.trace.TmfExperiment;
+import org.eclipse.linuxtools.tmf.core.trace.TmfTraceManager;
 import org.eclipse.linuxtools.tmf.ui.editors.ITmfTraceEditor;
 import org.eclipse.linuxtools.tmf.ui.views.TmfView;
 import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.ITimeGraphRangeListener;
@@ -84,6 +89,7 @@ import org.eclipse.swt.events.MouseEvent;
 import org.eclipse.swt.graphics.Image;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.FileDialog;
 import org.eclipse.ui.IActionBars;
 import org.eclipse.ui.IEditorPart;
 
@@ -129,6 +135,8 @@ public class CallStackView extends TmfView {
     private static final Image THREAD_IMAGE = Activator.getDefault().getImageFromPath("icons/obj16/thread_obj.gif"); //$NON-NLS-1$
     private static final Image STACKFRAME_IMAGE = Activator.getDefault().getImageFromPath("icons/obj16/stckframe_obj.gif"); //$NON-NLS-1$
 
+    private static final String IMPORT_MAPPING_ICON_PATH = "icons/etool16/import.gif"; //$NON-NLS-1$
+
     // ------------------------------------------------------------------------
     // Fields
     // ------------------------------------------------------------------------
@@ -140,16 +148,19 @@ public class CallStackView extends TmfView {
     private ITmfTrace fTrace;
 
     // The selected thread map
-    private final Map<ITmfTrace, String> fSelectedThreadMap = new HashMap<ITmfTrace, String>();
+    private final Map<ITmfTrace, String> fSelectedThreadMap = new HashMap<>();
 
     // The time graph entry list
     private List<ThreadEntry> fEntryList;
 
     // The trace to entry list hash map
-    private final Map<ITmfTrace, ArrayList<ThreadEntry>> fEntryListMap = new HashMap<ITmfTrace, ArrayList<ThreadEntry>>();
+    private final Map<ITmfTrace, ArrayList<ThreadEntry>> fEntryListMap = new HashMap<>();
 
     // The trace to build thread hash map
-    private final Map<ITmfTrace, BuildThread> fBuildThreadMap = new HashMap<ITmfTrace, BuildThread>();
+    private final Map<ITmfTrace, BuildThread> fBuildThreadMap = new HashMap<>();
+
+    /** The map to map function addresses to function names */
+    private Map<String, String> fNameMapping;
 
     // The start time
     private long fStartTime;
@@ -172,6 +183,9 @@ public class CallStackView extends TmfView {
     // The previous item action
     private Action fPreviousItemAction;
 
+    /** The action to import a function-name mapping file */
+    private Action fImportMappingAction;
+
     // The zoom thread
     private ZoomThread fZoomThread;
 
@@ -192,8 +206,6 @@ public class CallStackView extends TmfView {
     // ------------------------------------------------------------------------
 
     private class ThreadEntry implements ITimeGraphEntry {
-        // The Trace
-        private final ITmfTrace fThreadTrace;
         // The start time
         private final long fTraceStartTime;
         // The end time
@@ -204,14 +216,17 @@ public class CallStackView extends TmfView {
         private final String fName;
         // The thread attribute quark
         private final int fThreadQuark;
+        // The state system from which this entry comes
+        private final ITmfStateSystem fSS;
 
         public ThreadEntry(ITmfTrace trace, String name, int threadQuark, long startTime, long endTime) {
-            fThreadTrace = trace;
-            fChildren = new ArrayList<CallStackEntry>();
+            fChildren = new ArrayList<>();
             fName = name;
             fTraceStartTime = startTime;
             fTraceEndTime = endTime;
             fThreadQuark = threadQuark;
+
+            fSS = getCallStackStateSystem(trace);
         }
 
         @Override
@@ -222,7 +237,10 @@ public class CallStackView extends TmfView {
         @Override
         public boolean hasChildren() {
             if (fChildren == null) {
-                ITmfStateSystem ss = fThreadTrace.getStateSystems().get(CallStackStateProvider.ID);
+                ITmfStateSystem ss = getStateSystem();
+                if (ss == null) {
+                    return false;
+                }
                 try {
                     int eventStackQuark = ss.getQuarkRelative(fThreadQuark, CallStackStateProvider.CALL_STACK);
                     ITmfStateInterval eventStackInterval = ss.querySingleState(ss.getStartTime(), eventStackQuark);
@@ -277,8 +295,9 @@ public class CallStackView extends TmfView {
             return fThreadQuark;
         }
 
-        public ITmfTrace getTrace() {
-            return fThreadTrace;
+        @Nullable
+        public ITmfStateSystem getStateSystem() {
+            return fSS;
         }
 
         public void addChild(CallStackEntry entry) {
@@ -429,8 +448,12 @@ public class CallStackView extends TmfView {
             }
             long resolution = Math.max(1, (fZoomEndTime - fZoomStartTime) / fDisplayWidth);
             for (ThreadEntry threadEntry : fZoomEntryList) {
-                ITmfStateSystem ss = threadEntry.fThreadTrace.getStateSystems().get(CallStackStateProvider.ID);
-                if (ss == null || !ss.waitUntilBuilt()) {
+                ITmfStateSystem ss = threadEntry.getStateSystem();
+                if (ss == null) {
+                    continue;
+                }
+                ss.waitUntilBuilt();
+                if (ss.isCancelled()) {
                     continue;
                 }
                 for (ITimeGraphEntry child : threadEntry.getChildren()) {
@@ -488,7 +511,7 @@ public class CallStackView extends TmfView {
         fTimeGraphCombo.getTreeViewer().getTree().getColumn(3).setWidth(COLUMN_WIDTHS[3]);
         fTimeGraphCombo.getTreeViewer().getTree().getColumn(4).setWidth(COLUMN_WIDTHS[4]);
 
-        fTimeGraphCombo.setTimeGraphProvider(new CallStackPresentationProvider());
+        fTimeGraphCombo.setTimeGraphProvider(new CallStackPresentationProvider(this));
         fTimeGraphCombo.getTimeGraphViewer().setTimeFormat(TimeFormat.CALENDAR);
 
         fTimeGraphCombo.getTimeGraphViewer().addRangeListener(new ITimeGraphRangeListener() {
@@ -676,7 +699,7 @@ public class CallStackView extends TmfView {
                 }
                 TimeGraphViewer viewer = fTimeGraphCombo.getTimeGraphViewer();
                 for (ThreadEntry threadEntry : fEntryList) {
-                    ITmfStateSystem ss = threadEntry.getTrace().getStateSystems().get(CallStackStateProvider.ID);
+                    ITmfStateSystem ss = threadEntry.getStateSystem();
                     if (ss == null || beginTime < ss.getStartTime() || beginTime > ss.getCurrentEndTime()) {
                         continue;
                     }
@@ -743,6 +766,7 @@ public class CallStackView extends TmfView {
     // ------------------------------------------------------------------------
     // Internal
     // ------------------------------------------------------------------------
+
     private void loadTrace() {
         synchronized (fEntryListMap) {
             fEntryList = fEntryListMap.get(fTrace);
@@ -763,23 +787,20 @@ public class CallStackView extends TmfView {
     private void buildThreadList(final ITmfTrace trace, IProgressMonitor monitor) {
         fStartTime = Long.MAX_VALUE;
         fEndTime = Long.MIN_VALUE;
-        ITmfTrace[] traces;
-        if (trace instanceof TmfExperiment) {
-            TmfExperiment experiment = (TmfExperiment) trace;
-            traces = experiment.getTraces();
-        } else {
-            traces = new ITmfTrace[] { trace };
-        }
-        ArrayList<ThreadEntry> entryList = new ArrayList<ThreadEntry>();
+        ITmfTrace[] traces = TmfTraceManager.getTraceSet(trace);
+        ArrayList<ThreadEntry> entryList = new ArrayList<>();
         for (ITmfTrace aTrace : traces) {
             if (monitor.isCanceled()) {
                 return;
             }
-            ITmfStateSystem ss = aTrace.getStateSystems().get(CallStackStateProvider.ID);
-            if (ss == null || !ss.waitUntilBuilt()) {
-                String threadName = Messages.CallStackView_StackInfoNotAvailable + ' ' + '(' + aTrace.getName() + ')';
-                ThreadEntry threadEntry = new ThreadEntry(aTrace, threadName, -1, 0, 0);
-                entryList.add(threadEntry);
+            ITmfStateSystem ss = getCallStackStateSystem(aTrace);
+            if (ss == null) {
+                addUnavailableEntry(aTrace, entryList);
+                continue;
+            }
+            ss.waitUntilBuilt();
+            if (ss.isCancelled()) {
+                addUnavailableEntry(aTrace, entryList);
                 continue;
             }
             long startTime = ss.getStartTime();
@@ -810,7 +831,7 @@ public class CallStackView extends TmfView {
             }
         }
         synchronized (fEntryListMap) {
-            fEntryListMap.put(trace, new ArrayList<ThreadEntry>(entryList));
+            fEntryListMap.put(trace, new ArrayList<>(entryList));
         }
         if (trace == fTrace) {
             refresh();
@@ -825,8 +846,17 @@ public class CallStackView extends TmfView {
         }
     }
 
+    private void addUnavailableEntry(ITmfTrace trace, List<ThreadEntry> list) {
+        String threadName = Messages.CallStackView_StackInfoNotAvailable + ' ' + '(' + trace.getName() + ')';
+        ThreadEntry threadEntry = new ThreadEntry(trace, threadName, -1, 0, 0);
+        list.add(threadEntry);
+    }
+
     private void buildStatusEvents(ITmfTrace trace, CallStackEntry entry, IProgressMonitor monitor) {
-        ITmfStateSystem ss = entry.getTrace().getStateSystems().get(CallStackStateProvider.ID);
+        ITmfStateSystem ss = getCallStackStateSystem(entry.getTrace());
+        if (ss == null) {
+            return;
+        }
         long start = ss.getStartTime();
         long end = ss.getCurrentEndTime() + 1;
         long resolution = Math.max(1, (end - start) / fDisplayWidth);
@@ -843,7 +873,10 @@ public class CallStackView extends TmfView {
     private static List<ITimeEvent> getEventList(CallStackEntry entry,
             long startTime, long endTime, long resolution,
             IProgressMonitor monitor) {
-        ITmfStateSystem ss = entry.getTrace().getStateSystems().get(CallStackStateProvider.ID);
+        ITmfStateSystem ss = getCallStackStateSystem(entry.getTrace());
+        if (ss == null) {
+            return null;
+        }
         long start = Math.max(startTime, ss.getStartTime());
         long end = Math.min(endTime, ss.getCurrentEndTime() + 1);
         if (end <= start) {
@@ -852,7 +885,7 @@ public class CallStackView extends TmfView {
         List<ITimeEvent> eventList = null;
         try {
             List<ITmfStateInterval> stackIntervals = ss.queryHistoryRange(entry.getQuark(), start, end - 1, resolution, monitor);
-            eventList = new ArrayList<ITimeEvent>(stackIntervals.size());
+            eventList = new ArrayList<>(stackIntervals.size());
             long lastEndTime = -1;
             boolean lastIsNull = true;
             for (ITmfStateInterval statusInterval : stackIntervals) {
@@ -899,8 +932,12 @@ public class CallStackView extends TmfView {
             return;
         }
         for (ThreadEntry threadEntry : fEntryList) {
-            ITmfStateSystem ss = threadEntry.fThreadTrace.getStateSystems().get(CallStackStateProvider.ID);
-            if (ss == null || !ss.waitUntilBuilt()) {
+            ITmfStateSystem ss = threadEntry.getStateSystem();
+            if (ss == null) {
+                continue;
+            }
+            ss.waitUntilBuilt();
+            if (ss.isCancelled()) {
                 continue;
             }
             long queryTime = Math.max(ss.getStartTime(), Math.min(ss.getCurrentEndTime(), time));
@@ -911,7 +948,8 @@ public class CallStackView extends TmfView {
                     String name = ""; //$NON-NLS-1$
                     try {
                         if (nameValue.getType() == Type.STRING) {
-                            name = nameValue.unboxStr();
+                            String address = nameValue.unboxStr();
+                            name = getFunctionName(address);
                         } else if (nameValue.getType() == Type.INTEGER) {
                             name = "0x" + Integer.toHexString(nameValue.unboxInt()); //$NON-NLS-1$
                         } else if (nameValue.getType() == Type.LONG) {
@@ -947,7 +985,7 @@ public class CallStackView extends TmfView {
                 synchronized (fEntryListMap) {
                     fEntryList = fEntryListMap.get(fTrace);
                     if (fEntryList == null) {
-                        fEntryList = new ArrayList<ThreadEntry>();
+                        fEntryList = new ArrayList<>();
                     }
                     entries = fEntryList.toArray(new ITimeGraphEntry[0]);
                 }
@@ -1039,6 +1077,7 @@ public class CallStackView extends TmfView {
     }
 
     private void fillLocalToolBar(IToolBarManager manager) {
+        manager.add(getImportMappingAction());
         manager.add(fTimeGraphCombo.getTimeGraphViewer().getResetScaleAction());
         manager.add(getPreviousEventAction());
         manager.add(getNextEventAction());
@@ -1065,7 +1104,10 @@ public class CallStackView extends TmfView {
                         try {
                             CallStackEntry callStackEntry = (CallStackEntry) entry;
                             ITmfTrace trace = callStackEntry.getTrace();
-                            ITmfStateSystem ss = trace.getStateSystems().get(CallStackStateProvider.ID);
+                            ITmfStateSystem ss = getCallStackStateSystem(trace);
+                            if (ss == null) {
+                                return;
+                            }
                             long time = Math.max(ss.getStartTime(), Math.min(ss.getCurrentEndTime(), viewer.getSelectionBegin()));
                             ThreadEntry threadEntry = (ThreadEntry) callStackEntry.getParent();
                             int quark = ss.getQuarkRelative(threadEntry.getThreadQuark(), CallStackStateProvider.CALL_STACK);
@@ -1078,6 +1120,7 @@ public class CallStackView extends TmfView {
                             fTimeGraphCombo.setSelection(selectedEntry);
                             viewer.getTimeGraphControl().fireSelectionChanged();
                             startZoomThread(viewer.getTime0(), viewer.getTime1());
+
                         } catch (AttributeNotFoundException e) {
                             Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
                         } catch (TimeRangeException e) {
@@ -1115,7 +1158,10 @@ public class CallStackView extends TmfView {
                         try {
                             CallStackEntry callStackEntry = (CallStackEntry) entry;
                             ITmfTrace trace = callStackEntry.getTrace();
-                            ITmfStateSystem ss = trace.getStateSystems().get(CallStackStateProvider.ID);
+                            ITmfStateSystem ss = getCallStackStateSystem(trace);
+                            if (ss == null) {
+                                return;
+                            }
                             long time = Math.max(ss.getStartTime(), Math.min(ss.getCurrentEndTime(), viewer.getSelectionBegin()));
                             ThreadEntry threadEntry = (ThreadEntry) callStackEntry.getParent();
                             int quark = ss.getQuarkRelative(threadEntry.getThreadQuark(), CallStackStateProvider.CALL_STACK);
@@ -1129,6 +1175,7 @@ public class CallStackView extends TmfView {
                             fTimeGraphCombo.setSelection(selectedEntry);
                             viewer.getTimeGraphControl().fireSelectionChanged();
                             startZoomThread(viewer.getTime0(), viewer.getTime1());
+
                         } catch (AttributeNotFoundException e) {
                             Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
                         } catch (TimeRangeException e) {
@@ -1150,4 +1197,106 @@ public class CallStackView extends TmfView {
         return fPrevEventAction;
     }
 
+    @Nullable
+    static ITmfStateSystem getCallStackStateSystem(ITmfTrace trace) {
+        /*
+         * Since we cannot know the exact analysis ID (in separate plugins), we
+         * will search using the analysis type.
+         */
+        Iterable<AbstractCallStackAnalysis> modules =
+                trace.getAnalysisModulesOfClass(AbstractCallStackAnalysis.class);
+        Iterator<AbstractCallStackAnalysis> it = modules.iterator();
+        if (!it.hasNext()) {
+            /* This trace does not provide a call-stack analysis */
+            return null;
+        }
+
+        /*
+         * We only look at the first module we find.
+         *
+         * TODO Handle the advanced case where one trace provides more than one
+         * call-stack analysis.
+         */
+        AbstractCallStackAnalysis module = it.next();
+        /* This analysis is not automatic, we need to schedule it on-demand */
+        module.schedule();
+        module.waitForInitialization();
+        ITmfStateSystem ss = module.getStateSystem();
+        if (ss == null) {
+            /* If we've waited for initialization, 'ss' should not be null */
+            throw new IllegalStateException();
+        }
+        return ss;
+    }
+
+    // ------------------------------------------------------------------------
+    // Methods related to function name mapping
+    // ------------------------------------------------------------------------
+
+    /**
+     * Toolbar icon to import the function address-to-name mapping file.
+     */
+    private Action getImportMappingAction() {
+        if (fImportMappingAction != null) {
+            return fImportMappingAction;
+        }
+        fImportMappingAction = new Action() {
+            @Override
+            public void run() {
+                FileDialog dialog = new FileDialog(getViewSite().getShell());
+                dialog.setText(Messages.CallStackView_ImportMappingDialogTitle);
+                String filePath = dialog.open();
+                if (filePath == null) {
+                    /* No file was selected, don't change anything */
+                    return;
+                }
+                /*
+                 * Start the mapping import in a separate thread (we do not want
+                 * to UI thread to do this).
+                 */
+                Job job = new ImportMappingJob(new File(filePath));
+                job.schedule();
+            }
+        };
+
+        fImportMappingAction.setText(Messages.CallStackView_ImportMappingButtonText);
+        fImportMappingAction.setToolTipText(Messages.CallStackView_ImportMappingButtonTooltip);
+        fImportMappingAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(IMPORT_MAPPING_ICON_PATH));
+
+        return fImportMappingAction;
+    }
+
+    private class ImportMappingJob extends Job {
+        private final File fMappingFile;
+
+        public ImportMappingJob(File mappingFile) {
+            super(Messages.CallStackView_ImportMappingJobName);
+            fMappingFile = mappingFile;
+        }
+
+        @Override
+        public IStatus run(IProgressMonitor monitor) {
+            fNameMapping = FunctionNameMapper.mapFromNmTextFile(fMappingFile);
+
+            /* Refresh the time graph and the list of entries */
+            buildThreadList(fTrace, new NullProgressMonitor());
+            redraw();
+
+            return Status.OK_STATUS;
+        }
+    }
+
+    String getFunctionName(String address) {
+        if (fNameMapping == null) {
+            /* No mapping available, just print the addresses */
+            return address;
+        }
+        String ret = fNameMapping.get(address);
+        if (ret == null) {
+            /* We didn't find this address in the mapping file, just use the address */
+            return address;
+        }
+        return ret;
+    }
+
 }
This page took 0.038342 seconds and 5 git commands to generate.