tmf: Introduce the notion of PID to the Callstack analysis
authorAlexandre Montplaisir <alexmonthy@efficios.com>
Tue, 19 Apr 2016 23:43:27 +0000 (19:43 -0400)
committerAlexandre Montplaisir <alexmonthy@efficios.com>
Wed, 27 Apr 2016 22:15:13 +0000 (18:15 -0400)
The current Callstack View/Analysis does not handle PIDs (process IDs)
only TIDs (thread IDs).

This works fine with the basic use case of a trace with only one,
single-threaded process. But since callstacks are per thread, but
symbol resolution is per-process, the callstack analysis should be
augmented to know about both concepts.

Change-Id: I6a6ad5f92e18c3c161390237b8dea513dc9ce8cf
Signed-off-by: Alexandre Montplaisir <alexmonthy@efficios.com>
Reviewed-on: https://git.eclipse.org/r/69870
Reviewed-by: Hudson CI
Reviewed-by: Patrick Tasse <patrick.tasse@gmail.com>
Tested-by: Patrick Tasse <patrick.tasse@gmail.com>
lttng/org.eclipse.tracecompass.lttng2.ust.core.tests/src/org/eclipse/tracecompass/lttng2/ust/core/tests/callstack/AbstractProviderTest.java
lttng/org.eclipse.tracecompass.lttng2.ust.core.tests/src/org/eclipse/tracecompass/lttng2/ust/core/tests/callstack/LttngUstCallStackProviderFastTest.java
lttng/org.eclipse.tracecompass.lttng2.ust.core.tests/src/org/eclipse/tracecompass/lttng2/ust/core/tests/callstack/LttngUstCallStackProviderTest.java
lttng/org.eclipse.tracecompass.lttng2.ust.core/src/org/eclipse/tracecompass/internal/lttng2/ust/core/callstack/LttngUstCallStackProvider.java
lttng/org.eclipse.tracecompass.lttng2.ust.ui.swtbot.tests/src/org/eclipse/tracecompass/lttng2/ust/ui/swtbot/tests/CallStackViewTest.java
tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/callstack/CallStackStateProvider.java
tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/callstack/AbstractCallStackAnalysis.java
tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/callstack/CallStackView.java

index dab697e75bf9e6359e7051c94c248f18ea451a05..e4bec226c91f44388280145ec12608dd29d1f98f 100644 (file)
@@ -76,10 +76,15 @@ public abstract class AbstractProviderTest {
      */
     protected abstract @NonNull CtfTestTrace getTestTrace();
 
+    /**
+     * @return The ID of the process the desired thread belongs to
+     */
+    protected abstract int getProcessId();
+
     /**
      * @return The name of the executable process in that particular trace
      */
-    protected abstract String getProcName();
+    protected abstract String getThreadName();
 
     /**
      * Get the list of timestamps to query in that trace.
@@ -185,7 +190,7 @@ public abstract class AbstractProviderTest {
     @Test
     public void testCallStackBegin() {
         long start = fSS.getStartTime();
-        String[] cs = getCallStack(fSS, getProcName(), start);
+        String[] cs = getCallStack(fSS, getProcessId(), getThreadName(), start);
         assertEquals(1, cs.length);
 
         assertEquals("40472b", cs[0]);
@@ -196,7 +201,7 @@ public abstract class AbstractProviderTest {
      */
     @Test
     public void testCallStack1() {
-        String[] cs = getCallStack(fSS, getProcName(), getTestTimestamp(0));
+        String[] cs = getCallStack(fSS, getProcessId(), getThreadName(), getTestTimestamp(0));
         assertEquals(2, cs.length);
 
         assertEquals("40472b", cs[0]);
@@ -208,7 +213,7 @@ public abstract class AbstractProviderTest {
      */
     @Test
     public void testCallStack2() {
-        String[] cs = getCallStack(fSS, getProcName(), getTestTimestamp(1));
+        String[] cs = getCallStack(fSS, getProcessId(), getThreadName(), getTestTimestamp(1));
         assertEquals(3, cs.length);
 
         assertEquals("40472b", cs[0]);
@@ -221,7 +226,7 @@ public abstract class AbstractProviderTest {
      */
     @Test
     public void testCallStack3() {
-        String[] cs = getCallStack(fSS, getProcName(), getTestTimestamp(2));
+        String[] cs = getCallStack(fSS, getProcessId(), getThreadName(), getTestTimestamp(2));
         assertEquals(4, cs.length);
 
         assertEquals("40472b", cs[0]);
@@ -236,7 +241,7 @@ public abstract class AbstractProviderTest {
     @Test
     public void testCallStackEnd() {
         long end = fSS.getCurrentEndTime();
-        String[] cs = getCallStack(fSS, getProcName(), end);
+        String[] cs = getCallStack(fSS, getProcessId(), getThreadName(), end);
         assertEquals(3, cs.length);
 
         assertEquals("40472b", cs[0]);
@@ -258,9 +263,9 @@ public abstract class AbstractProviderTest {
     }
 
     /** Get the callstack for the given timestamp, for this particular trace */
-    private static String[] getCallStack(ITmfStateSystem ss, String processName, long timestamp) {
+    private static String[] getCallStack(ITmfStateSystem ss, int pid, String threadName, long timestamp) {
         try {
-            int stackAttribute = ss.getQuarkAbsolute("Threads", processName, "CallStack");
+            int stackAttribute = ss.getQuarkAbsolute("Processes", Integer.toString(pid), threadName, "CallStack");
             List<ITmfStateInterval> state = ss.queryFullState(timestamp);
             int depth = state.get(stackAttribute).getStateValue().unboxInt();
 
index c873e8c854abd626429efb4650d4dbd7fd820d70..ba2dc88f357a39b89fe2331bb59cfa1bdd736462 100644 (file)
@@ -33,7 +33,13 @@ public class LttngUstCallStackProviderFastTest extends AbstractProviderTest {
     }
 
     @Override
-    protected String getProcName() {
+    protected int getProcessId() {
+        /* This particular trace does not have PID contexts. */
+        return -1;
+    }
+
+    @Override
+    protected String getThreadName() {
         return "glxgears-29822";
     }
 
index c8ce1610e75aeb98a4a3f595dedf47c29a484efb..5556ea26a458d8e16666c813591f2edeeb3ec1bc 100644 (file)
@@ -32,7 +32,13 @@ public class LttngUstCallStackProviderTest extends AbstractProviderTest {
     }
 
     @Override
-    protected String getProcName() {
+    protected int getProcessId() {
+        /* This particular trace does not have PID contexts. */
+        return -1;
+    }
+
+    @Override
+    protected String getThreadName() {
         return "glxgears-16073";
     }
 
index cd89b401143b6d8926850d78dc98984837b5dd75..2729e6e0a47436c7b5b90ff30c95629a024ded97 100644 (file)
@@ -16,6 +16,8 @@ package org.eclipse.tracecompass.internal.lttng2.ust.core.callstack;
 import java.util.Set;
 
 import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
 import org.eclipse.tracecompass.internal.lttng2.ust.core.trace.layout.LttngUst20EventLayout;
 import org.eclipse.tracecompass.lttng2.ust.core.trace.LttngUstTrace;
 import org.eclipse.tracecompass.lttng2.ust.core.trace.layout.ILttngUstEventLayout;
@@ -40,21 +42,22 @@ import com.google.common.collect.ImmutableSet;
  *
  * @author Alexandre Montplaisir
  */
+@NonNullByDefault
 public class LttngUstCallStackProvider extends CallStackStateProvider {
 
     /**
      * Version number of this state provider. Please bump this if you modify
      * the contents of the generated state history in some way.
      */
-    private static final int VERSION = 2;
+    private static final int VERSION = 3;
 
     /** Event names indicating function entry */
-    private final @NonNull Set<String> funcEntryEvents;
+    private final Set<String> funcEntryEvents;
 
     /** Event names indicating function exit */
-    private final @NonNull Set<String> funcExitEvents;
+    private final Set<String> funcExitEvents;
 
-    private final @NonNull ILttngUstEventLayout fLayout;
+    private final ILttngUstEventLayout fLayout;
 
     // ------------------------------------------------------------------------
     // Constructor
@@ -66,7 +69,7 @@ public class LttngUstCallStackProvider extends CallStackStateProvider {
      * @param trace
      *            The UST trace
      */
-    public LttngUstCallStackProvider(@NonNull ITmfTrace trace) {
+    public LttngUstCallStackProvider(ITmfTrace trace) {
         super(trace);
 
         if (trace instanceof LttngUstTrace) {
@@ -107,6 +110,8 @@ public class LttngUstCallStackProvider extends CallStackStateProvider {
      * Check that this event contains the required information we need to be
      * used in the call stack view. We need at least the "procname" and "vtid"
      * contexts.
+     *
+     * The "vpid" is useful too, but optional.
      */
     @Override
     protected boolean considerEvent(ITmfEvent event) {
@@ -122,7 +127,7 @@ public class LttngUstCallStackProvider extends CallStackStateProvider {
     }
 
     @Override
-    public String functionEntry(ITmfEvent event) {
+    public @Nullable String functionEntry(ITmfEvent event) {
         String eventName = event.getName();
         if (!funcEntryEvents.contains(eventName)) {
             return null;
@@ -132,7 +137,7 @@ public class LttngUstCallStackProvider extends CallStackStateProvider {
     }
 
     @Override
-    public String functionExit(ITmfEvent event) {
+    public @Nullable String functionExit(ITmfEvent event) {
         String eventName = event.getName();
         if (!funcExitEvents.contains(eventName)) {
             return null;
@@ -150,22 +155,29 @@ public class LttngUstCallStackProvider extends CallStackStateProvider {
     }
 
     @Override
-    public String getThreadName(ITmfEvent event) {
-        /* Class type and content was already checked if we get called here */
-        ITmfEventField content = ((CtfTmfEvent) event).getContent();
-        String procName = (String) content.getField(fLayout.contextProcname()).getValue();
-        Long vtid = (Long) content.getField(fLayout.contextVtid()).getValue();
-
-        if (procName == null || vtid == null) {
-            throw new IllegalStateException();
+    protected int getProcessId(@NonNull ITmfEvent event) {
+        /* The "vpid" context may not be present! We need to check */
+        ITmfEventField content = event.getContent();
+        ITmfEventField vpidContextField = content.getField(fLayout.contextVpid());
+        if (vpidContextField == null) {
+            return UNDEFINED_PID;
         }
+        return ((Long) vpidContextField.getValue()).intValue();
+    }
 
-        return procName + '-' + vtid.toString();
+    @Override
+    protected long getThreadId(ITmfEvent event) {
+        /* We checked earlier that the "vtid" context is present */
+        ITmfEventField content = event.getContent();
+        return ((Long) content.getField(fLayout.contextVtid()).getValue()).longValue();
     }
 
     @Override
-    protected Long getThreadId(ITmfEvent event) {
-        ITmfEventField content = ((CtfTmfEvent) event).getContent();
-        return (Long) content.getField(fLayout.contextVtid()).getValue();
+    public String getThreadName(ITmfEvent event) {
+        /* We checked earlier that the "procname" context is present */
+        ITmfEventField content = event.getContent();
+        String procName = (String) content.getField(fLayout.contextProcname()).getValue();
+        long vtid = getThreadId(event);
+        return (procName + '-' + Long.toString(vtid));
     }
 }
index 50fe209b932262e989f83af50878e3eb4da11ab9..4524729641bf1ee5c205734a4642e482adb924eb 100644 (file)
@@ -18,7 +18,9 @@ import static org.junit.Assert.assertNotNull;
 
 import java.io.File;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
+import java.util.stream.Collectors;
 
 import org.apache.log4j.ConsoleAppender;
 import org.apache.log4j.Logger;
@@ -187,6 +189,7 @@ public class CallStackViewTest {
     @Test
     public void testOpenCallstack() {
         String node = "glxgears-cyg-profile";
+        String pid = "-1";
         String childName = "glxgears-16073";
         List<String> expected = ImmutableList.of("40472b", "", "", "", "");
 
@@ -194,7 +197,7 @@ public class CallStackViewTest {
         viewBot.setFocus();
         final SWTBotView viewBot1 = viewBot;
         SWTBotTree tree = viewBot1.bot().tree();
-        SWTBotTreeItem treeItem = tree.getTreeItem(node);
+        SWTBotTreeItem treeItem = tree.getTreeItem(node).getNode(pid);
         assertEquals(childName, treeItem.getNodes().get(0));
         List<String> names = treeItem.getNode(childName).getNodes();
         assertEquals(expected, names);
@@ -273,15 +276,15 @@ public class CallStackViewTest {
 
     private static List<String> getVisibleStackFrames(final SWTBotView viewBot) {
         SWTBotTree tree = viewBot.bot().tree();
-        List<String> names = new ArrayList<>();
-        for (SWTBotTreeItem swtBotTreeItem : tree.getAllItems()) {
-            for (SWTBotTreeItem items : swtBotTreeItem.getItems()) {
-                for (SWTBotTreeItem item : items.getItems()) {
-                    names.add(item.cell(0));
-                }
-            }
-        }
-        return names;
+        return Arrays.stream(tree.getAllItems())
+                // Process entries
+                .flatMap(item -> Arrays.stream(item.getItems()))
+                // Thread entries
+                .flatMap(item -> Arrays.stream(item.getItems()))
+                // Callstack entries
+                .flatMap(item -> Arrays.stream(item.getItems()))
+                .map(item -> item.cell(0))
+                .collect(Collectors.toList());
     }
 
     private static void goToTime(long timestamp) {
index 825f98d1a1eadd596ad72a60810d26b15580444c..1eed618d9290ee701409c459085282878ed38368 100644 (file)
@@ -14,68 +14,84 @@ package org.eclipse.tracecompass.tmf.core.callstack;
 
 import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
 
-import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
 import org.eclipse.osgi.util.NLS;
 import org.eclipse.tracecompass.internal.tmf.core.Activator;
 import org.eclipse.tracecompass.statesystem.core.ITmfStateSystemBuilder;
 import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException;
-import org.eclipse.tracecompass.statesystem.core.exceptions.StateValueTypeException;
-import org.eclipse.tracecompass.statesystem.core.exceptions.TimeRangeException;
 import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue;
 import org.eclipse.tracecompass.statesystem.core.statevalue.TmfStateValue;
 import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
 import org.eclipse.tracecompass.tmf.core.statesystem.AbstractTmfStateProvider;
+import org.eclipse.tracecompass.tmf.core.statesystem.ITmfStateProvider;
 import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
 
 /**
  * The state provider for traces that support the Call Stack view.
  *
  * The attribute tree should have the following structure:
- *<pre>
+ *
+ * <pre>
  * (root)
- *   \-- Threads
- *        |-- (Thread 1)
- *        |    \-- CallStack (stack-attribute)
- *        |         |-- 1
- *        |         |-- 2
- *        |        ...
- *        |         \-- n
- *        |-- (Thread 2)
- *        |    \-- CallStack (stack-attribute)
- *        |         |-- 1
- *        |         |-- 2
- *        |        ...
- *        |         \-- n
- *       ...
- *        \-- (Thread n)
- *             \-- CallStack (stack-attribute)
- *                  |-- 1
- *                  |-- 2
- *                 ...
- *                  \-- n
- *</pre>
+ *   +-- Processes
+ *       +-- (PID 1000)
+ *       |    +-- (TID 1000)
+ *       |    |    +-- CallStack (stack-attribute)
+ *       |    |         +-- 1
+ *       |    |         +-- 2
+ *       |    |        ...
+ *       |    |         +-- n
+ *       |    +-- (TID 1001)
+ *       |         +-- CallStack (stack-attribute)
+ *       |              +-- 1
+ *       |              +-- 2
+ *       |             ...
+ *       |              +-- n
+ *       |
+ *       +-- (PID 2000)
+ *            +-- (TID 2000)
+ *                 +-- CallStack (stack-attribute)
+ *                      +-- 1
+ *                      +-- 2
+ *                     ...
+ *                      +-- n
+ * </pre>
+ *
  * where:
- * <br>
- * (Thread n) is an attribute whose name is the display name of the thread.
+ * <ul>
+ * <li>(PID n) is an attribute name representing a unique process identifier.
+ * </li>
+ * <li>(TID n) is an attribute whose name is the display name of the thread.
  * Optionally, its value is a long representing the thread id, used for sorting.
- * <br>
- * CallStack is a stack-attribute whose pushed values are either a string,
- * int or long representing the function name or address in the call stack.
- * The type of value used must be constant for a particular CallStack.
+ * </li>
+ * <li>"CallStack" is a stack-attribute whose pushed values are either a string,
+ * int or long representing the function name or address in the call stack. The
+ * type of value used must be constant for a particular CallStack.</li>
+ * </ul>
  *
  * @author Patrick Tasse
  */
+@NonNullByDefault
 public abstract class CallStackStateProvider extends AbstractTmfStateProvider {
 
-    /** Thread attribute */
-    public static final String THREADS = "Threads"; //$NON-NLS-1$
+    /** Thread attribute
+     * @since 2.0 */
+    public static final String PROCESSES = "Processes"; //$NON-NLS-1$
+
     /** CallStack stack-attribute */
     public static final String CALL_STACK = "CallStack"; //$NON-NLS-1$
+
+    /** Undefined process ID
+     * @since 2.0 */
+    protected static final int UNDEFINED_PID = -1;
+
     /** Undefined function exit name */
-    public static final String UNDEFINED = "UNDEFINED"; //$NON-NLS-1$
+    protected static final String UNDEFINED = "UNDEFINED"; //$NON-NLS-1$
 
     /** CallStack state system ID */
-    private static final @NonNull String ID = "org.eclipse.linuxtools.tmf.callstack"; //$NON-NLS-1$
+    private static final String ID = "org.eclipse.linuxtools.tmf.callstack"; //$NON-NLS-1$
+
     /** Dummy function name for when no function is expected */
     private static final String NO_FUNCTION = "no function"; //$NON-NLS-1$
 
@@ -85,7 +101,7 @@ public abstract class CallStackStateProvider extends AbstractTmfStateProvider {
      * @param trace
      *            The trace for which we build this state system
      */
-    public CallStackStateProvider(@NonNull ITmfTrace trace) {
+    public CallStackStateProvider(ITmfTrace trace) {
         super(trace, ID);
     }
 
@@ -102,12 +118,13 @@ public abstract class CallStackStateProvider extends AbstractTmfStateProvider {
             String functionEntryName = functionEntry(event);
             if (functionEntryName != null) {
                 long timestamp = event.getTimestamp().toNanos();
-                String thread = getThreadName(event);
-                int threadQuark = ss.getQuarkAbsoluteAndAdd(THREADS, thread);
-                Long threadId = getThreadId(event);
-                if (threadId != null) {
-                    ss.updateOngoingState(TmfStateValue.newValueLong(threadId), threadQuark);
-                }
+                int pid = getProcessId(event);
+                String threadName = getThreadName(event);
+                int threadQuark = ss.getQuarkAbsoluteAndAdd(PROCESSES, Integer.toString(pid), threadName);
+
+                long threadId = getThreadId(event);
+                ss.updateOngoingState(TmfStateValue.newValueLong(threadId), threadQuark);
+
                 int callStackQuark = ss.getQuarkRelativeAndAdd(threadQuark, CALL_STACK);
                 ITmfStateValue value = TmfStateValue.newValueString(functionEntryName);
                 ss.pushAttribute(timestamp, value, callStackQuark);
@@ -118,8 +135,9 @@ public abstract class CallStackStateProvider extends AbstractTmfStateProvider {
             String functionExitName = functionExit(event);
             if (functionExitName != null) {
                 long timestamp = event.getTimestamp().toNanos();
+                int pid = getProcessId(event);
                 String thread = getThreadName(event);
-                int quark = ss.getQuarkAbsoluteAndAdd(THREADS, thread, CALL_STACK);
+                int quark = ss.getQuarkAbsoluteAndAdd(PROCESSES, Integer.toString(pid), thread, CALL_STACK);
                 ITmfStateValue poppedValue = ss.popAttribute(timestamp, quark);
                 String poppedName = (poppedValue == null ? NO_FUNCTION : poppedValue.unboxStr());
 
@@ -136,15 +154,19 @@ public abstract class CallStackStateProvider extends AbstractTmfStateProvider {
                 }
             }
 
-        } catch (TimeRangeException e) {
-            e.printStackTrace();
         } catch (AttributeNotFoundException e) {
             e.printStackTrace();
-        } catch (StateValueTypeException e) {
-            e.printStackTrace();
         }
     }
 
+    /**
+     * Restrict the return type for {@link ITmfStateProvider#getNewInstance}.
+     *
+     * @since 2.0
+     */
+    @Override
+    public abstract CallStackStateProvider getNewInstance();
+
     /**
      * Check if this event should be considered at all for function entry/exit
      * analysis. This check is only run once per event, before
@@ -166,7 +188,7 @@ public abstract class CallStackStateProvider extends AbstractTmfStateProvider {
      * @return The function name of the function entry, or null if not a
      *         function entry.
      */
-    protected abstract String functionEntry(ITmfEvent event);
+    protected abstract @Nullable String functionEntry(ITmfEvent event);
 
     /**
      * Check an event if it indicates a function exit.
@@ -176,25 +198,36 @@ public abstract class CallStackStateProvider extends AbstractTmfStateProvider {
      * @return The function name, or UNDEFINED, for a function exit, or null if
      *         not a function exit.
      */
-    protected abstract String functionExit(ITmfEvent event);
+    protected abstract @Nullable String functionExit(ITmfEvent event);
 
     /**
-     * Return the thread name of a function entry or exit event.
+     * Return the process ID of a function entry event.
+     *
+     * Use {@link #UNDEFINED_PID} if it is not known.
      *
      * @param event
      *            The event
-     * @return The thread name (as will be shown in the view)
+     * @return The process ID
+     * @since 2.0
      */
-    protected abstract String getThreadName(ITmfEvent event);
+    protected abstract int getProcessId(ITmfEvent event);
 
     /**
      * Return the thread id of a function entry event.
      *
      * @param event
      *            The event
-     * @return The thread id, or null if undefined
+     * @return The thread id
+     * @since 2.0
      */
-    protected Long getThreadId(ITmfEvent event) {
-        return null;
-    }
+    protected abstract long getThreadId(ITmfEvent event);
+
+    /**
+     * Return the thread name of a function entry or exit event.
+     *
+     * @param event
+     *            The event
+     * @return The thread name (as will be shown in the view)
+     */
+    protected abstract String getThreadName(ITmfEvent event);
 }
index f09701736399b5b03a34b7b219916dacda1488d4..480bd375db4845c30d3bda88983ec03277c3c133 100644 (file)
@@ -13,6 +13,7 @@
 
 package org.eclipse.tracecompass.tmf.ui.views.callstack;
 
+import org.eclipse.jdt.annotation.NonNullByDefault;
 import org.eclipse.tracecompass.tmf.core.callstack.CallStackStateProvider;
 import org.eclipse.tracecompass.tmf.core.statesystem.TmfStateSystemAnalysisModule;
 import org.eclipse.tracecompass.tmf.ui.analysis.TmfAnalysisViewOutput;
@@ -22,10 +23,13 @@ import org.eclipse.tracecompass.tmf.ui.analysis.TmfAnalysisViewOutput;
  *
  * @author Alexandre Montplaisir
  */
+@NonNullByDefault
 public abstract class AbstractCallStackAnalysis extends TmfStateSystemAnalysisModule {
 
-    private static final String[] DEFAULT_THREADS_PATTERN =
-            new String[] { CallStackStateProvider.THREADS, "*" }; //$NON-NLS-1$;
+    private static final String[] DEFAULT_PROCESSES_PATTERN =
+            new String[] { CallStackStateProvider.PROCESSES, "*" }; //$NON-NLS-1$
+
+    private static final String DEFAULT_THREADS_PATTERN = ".*"; //$NON-NLS-1$
 
     private static final String[] DEFAULT_CALL_STACK_PATH =
             new String[] { CallStackStateProvider.CALL_STACK };
@@ -34,31 +38,49 @@ public abstract class AbstractCallStackAnalysis extends TmfStateSystemAnalysisMo
      * Abstract constructor (should only be called via the sub-classes'
      * constructors.
      */
-    public AbstractCallStackAnalysis() {
+    protected AbstractCallStackAnalysis() {
         super();
         registerOutput(new TmfAnalysisViewOutput(CallStackView.ID));
     }
 
     /**
-     * Get the pattern of thread attributes. Override this method if the state
-     * system attributes do not match the default pattern defined by
-     * {@link CallStackStateProvider}.
+     * The quark pattern to get the list of attributes representing the
+     * different processes.
+     *
+     * It is passed as-is to
+     * {@link org.eclipse.tracecompass.statesystem.core.ITmfStateSystem#getQuarks}
+     * .
+     * @return The quark pattern to find the processes attribute
+     * @since 2.0
+     */
+    public String[] getProcessesPattern() {
+        return DEFAULT_PROCESSES_PATTERN;
+    }
+
+    /**
+     * The regex to match sub-attributes of each Process attributes representing
+     * the threads of this process.
      *
-     * @return the absolute pattern of the thread attributes
+     * This will be passed as-is to
+     * {@link org.eclipse.tracecompass.statesystem.core.ITmfStateSystem#getSubAttributes(int, boolean, String)}
+     *
+     * @return The regex to pass
+     * @since 2.0
      */
-    public String[] getThreadsPattern() {
+    public String getThreadsForProcessPattern() {
         return DEFAULT_THREADS_PATTERN;
     }
 
     /**
      * Get the call stack attribute path relative to a thread attribute found by
-     * {@link #getThreadsPattern()}. Override this method if the state system
-     * attributes do not match the default pattern defined by
+     * {@link #getThreadsForProcessPattern()}. Override this method if the state
+     * system attributes do not match the default pattern defined by
      * {@link CallStackStateProvider}.
      *
      * @return the relative path of the call stack attribute
+     * @since 2.0
      */
-    public String[] getCallStackPath() {
+    public String[] getCallStackPathForThread() {
         return DEFAULT_CALL_STACK_PATH;
     }
 }
index fe480fdb3e912be619eb63a8b751ab58bb37a435..229f8746d8aa4ced72e9afaa537336c907ece74f 100644 (file)
@@ -187,6 +187,18 @@ public class CallStackView extends AbstractTimeGraphView {
         }
     }
 
+    private static class ProcessEntry extends TimeGraphEntry {
+
+        public ProcessEntry(String name, long startTime, long endTime) {
+            super(name, startTime, endTime);
+        }
+
+        @Override
+        public boolean hasTimeEvents() {
+            return false;
+        }
+    }
+
     private static class ThreadEntry extends TimeGraphEntry {
         // The call stack quark
         private final int fCallStackQuark;
@@ -459,35 +471,38 @@ public class CallStackView extends AbstractTimeGraphView {
                 }
                 synchingToTime(beginTime);
                 startZoomThread(getTimeGraphViewer().getTime0(), getTimeGraphViewer().getTime1());
-                List<TimeGraphEntry> entryList = getEntryList(getTrace());
-                if (entryList == null) {
+                List<TimeGraphEntry> traceEntries = getEntryList(getTrace());
+                if (traceEntries == null) {
                     return;
                 }
                 TimeGraphViewer viewer = getTimeGraphViewer();
-                for (TimeGraphEntry traceEntry : entryList) {
-                    for (ITimeGraphEntry child : traceEntry.getChildren()) {
-                        ThreadEntry threadEntry = (ThreadEntry) child;
-                        ITmfStateSystem ss = threadEntry.getStateSystem();
-                        if (ss == null || beginTime < ss.getStartTime() || beginTime > ss.getCurrentEndTime()) {
-                            continue;
-                        }
-                        try {
-                            int quark = threadEntry.getCallStackQuark();
-                            ITmfStateInterval stackInterval = ss.querySingleState(beginTime, quark);
-                            if (beginTime == stackInterval.getStartTime()) {
-                                int stackLevel = stackInterval.getStateValue().unboxInt();
-                                ITimeGraphEntry selectedEntry = threadEntry.getChildren().get(Math.max(0, stackLevel - 1));
-                                getTimeGraphCombo().setSelection(selectedEntry);
-                                viewer.getTimeGraphControl().fireSelectionChanged();
-                                break;
+                for (TimeGraphEntry traceEntry : traceEntries) {
+                    for (ITimeGraphEntry processEntry : traceEntry.getChildren()) {
+                        for (ITimeGraphEntry aThreadEntry : processEntry.getChildren()) {
+                            ThreadEntry threadEntry = (ThreadEntry) aThreadEntry;
+                            ITmfStateSystem ss = threadEntry.getStateSystem();
+                            if (ss == null || beginTime < ss.getStartTime() || beginTime > ss.getCurrentEndTime()) {
+                                continue;
+                            }
+                            try {
+                                int quark = threadEntry.getCallStackQuark();
+                                ITmfStateInterval stackInterval = ss.querySingleState(beginTime, quark);
+                                if (beginTime == stackInterval.getStartTime()) {
+                                    int stackLevel = stackInterval.getStateValue().unboxInt();
+                                    ITimeGraphEntry selectedEntry = threadEntry.getChildren().get(Math.max(0, stackLevel - 1));
+                                    getTimeGraphCombo().setSelection(selectedEntry);
+                                    viewer.getTimeGraphControl().fireSelectionChanged();
+                                    break;
+                                }
+                            } catch (AttributeNotFoundException | TimeRangeException | StateSystemDisposedException | StateValueTypeException e) {
+                                Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
                             }
-                        } catch (AttributeNotFoundException | TimeRangeException | StateSystemDisposedException | StateValueTypeException e) {
-                            Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
                         }
                     }
                 }
             }
         });
+
     }
 
     /**
@@ -549,8 +564,8 @@ public class CallStackView extends AbstractTimeGraphView {
         }
 
         Map<ITmfTrace, TraceEntry> traceEntryMap = new HashMap<>();
+        Map<Integer, ProcessEntry> processEntryMap = new HashMap<>();
         Map<Integer, ThreadEntry> threadEntryMap = new HashMap<>();
-        String[] threadPaths = module.getThreadsPattern();
 
         long start = ss.getStartTime();
 
@@ -577,7 +592,7 @@ public class CallStackView extends AbstractTimeGraphView {
 
             getConfigureSymbolsAction().setEnabled(true);
 
-            List<Integer> threadQuarks = ss.getQuarks(threadPaths);
+
             TraceEntry traceEntry = traceEntryMap.get(trace);
             if (traceEntry == null) {
                 traceEntry = new TraceEntry(trace.getName(), start, end + 1);
@@ -588,54 +603,76 @@ public class CallStackView extends AbstractTimeGraphView {
                 traceEntry.updateEndTime(end);
             }
 
-            try {
-                /* Only query startStates if necessary (threadEntry == null)*/
-                List<ITmfStateInterval> startStates = null;
-                List<ITmfStateInterval> endStates = ss.queryFullState(ss.getCurrentEndTime());
-                for (int i = 0; i < threadQuarks.size(); i++) {
-                    if (monitor.isCanceled()) {
-                        return;
-                    }
-                    int threadQuark = threadQuarks.get(i);
-                    String[] callStackPath = module.getCallStackPath();
-                    int callStackQuark = ss.getQuarkRelative(threadQuark, callStackPath);
-                    String threadName = ss.getAttributeName(threadQuark);
-                    long threadEnd = end + 1;
-                    ITmfStateInterval endInterval = endStates.get(callStackQuark);
-                    if (endInterval.getStateValue().isNull() && endInterval.getStartTime() != ss.getStartTime()) {
-                        threadEnd = endInterval.getStartTime();
-                    }
-                    ThreadEntry threadEntry = threadEntryMap.get(threadQuark);
-                    if (threadEntry == null) {
-                        if (startStates == null) {
-                            startStates = ss.queryFullState(ss.getStartTime());
+            List<Integer> processQuarks = ss.getQuarks(module.getProcessesPattern());
+            for (Integer processQuark : processQuarks) {
+
+                /* Create the entry for the process */
+                ProcessEntry processEntry = processEntryMap.get(processQuark);
+                if (processEntry == null) {
+                    String name = ss.getAttributeName(processQuark.intValue());
+                    processEntry = new ProcessEntry(name, start, end);
+                    processEntryMap.put(processQuark, processEntry);
+                    traceEntry.addChild(processEntry);
+                } else {
+                    processEntry.updateEndTime(end);
+                  }
+
+                /* Create the threads under the process */
+                try {
+                    List<Integer> threadQuarks = ss.getSubAttributes(processQuark, false, module.getThreadsForProcessPattern());
+
+                    /*
+                     * Only query startStates if necessary (threadEntry == null)
+                     */
+                    List<ITmfStateInterval> startStates = null;
+                    List<ITmfStateInterval> endStates = ss.queryFullState(ss.getCurrentEndTime());
+                    for (int i = 0; i < threadQuarks.size(); i++) {
+                        if (monitor.isCanceled()) {
+                            return;
                         }
-                        long threadId = endInterval.getStateValue().unboxLong();
-                        long threadStart = start;
-                        ITmfStateInterval startInterval = startStates.get(callStackQuark);
-                        if (startInterval.getStateValue().isNull()) {
-                            threadStart = Math.min(startInterval.getEndTime() + 1, end + 1);
+                        int threadQuark = threadQuarks.get(i);
+
+                        String[] callStackPath = module.getCallStackPathForThread();
+                        int callStackQuark = ss.getQuarkRelative(threadQuark, callStackPath);
+                        String threadName = ss.getAttributeName(threadQuark);
+                        long threadEnd = end + 1;
+                        ITmfStateInterval endInterval = endStates.get(callStackQuark);
+                        if (endInterval.getStateValue().isNull() && endInterval.getStartTime() != ss.getStartTime()) {
+                            threadEnd = endInterval.getStartTime();
                         }
-                        threadEntry = new ThreadEntry(ss, threadName, threadId, callStackQuark, threadStart, threadEnd);
-                        threadEntryMap.put(threadQuark, threadEntry);
-                        traceEntry.addChild(threadEntry);
-                    } else {
-                        threadEntry.updateEndTime(threadEnd);
-                    }
-                    int level = 1;
-                    for (int stackLevelQuark : ss.getSubAttributes(callStackQuark, false)) {
-                        if (level > threadEntry.getChildren().size()) {
-                            CallStackEntry callStackEntry = new CallStackEntry(threadName, stackLevelQuark, level, trace, ss);
-                            threadEntry.addChild(callStackEntry);
+                        ThreadEntry threadEntry = threadEntryMap.get(threadQuark);
+                        if (threadEntry == null) {
+                            if (startStates == null) {
+                                startStates = ss.queryFullState(ss.getStartTime());
+                            }
+                            long threadId = endInterval.getStateValue().unboxLong();
+                            long threadStart = start;
+                            ITmfStateInterval startInterval = startStates.get(callStackQuark);
+                            if (startInterval.getStateValue().isNull()) {
+                                threadStart = Math.min(startInterval.getEndTime() + 1, end + 1);
+                            }
+                            threadEntry = new ThreadEntry(ss, threadName, threadId, callStackQuark, threadStart, threadEnd);
+                            threadEntryMap.put(threadQuark, threadEntry);
+                            processEntry.addChild(threadEntry);
+                        } else {
+                            threadEntry.updateEndTime(threadEnd);
+                        }
+                        int level = 1;
+                        for (int stackLevelQuark : ss.getSubAttributes(callStackQuark, false)) {
+                            if (level > threadEntry.getChildren().size()) {
+                                CallStackEntry callStackEntry = new CallStackEntry(threadName, stackLevelQuark, level, trace, ss);
+                                threadEntry.addChild(callStackEntry);
+                            }
+                            level++;
                         }
-                        level++;
                     }
+                } catch (AttributeNotFoundException e) {
+                    Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
+                } catch (StateSystemDisposedException e) {
+                    /* Ignored */
                 }
-            } catch (AttributeNotFoundException e) {
-                Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
-            } catch (StateSystemDisposedException e) {
-                /* Ignored */
             }
+
             if (parentTrace == getTrace()) {
                 synchronized (this) {
                     setStartTime(getStartTime() == SWT.DEFAULT ? start : Math.min(getStartTime(), start));
@@ -644,12 +681,15 @@ public class CallStackView extends AbstractTimeGraphView {
                 synchingToTime(getTimeGraphViewer().getSelectionBegin());
                 refresh();
             }
-            for (ITimeGraphEntry threadEntry : traceEntry.getChildren()) {
-                for (ITimeGraphEntry callStackEntry : threadEntry.getChildren()) {
-                    if (monitor.isCanceled()) {
-                        return;
+
+            for (ITimeGraphEntry processEntry : traceEntry.getChildren()) {
+                for (ITimeGraphEntry threadEntry : processEntry.getChildren()) {
+                    for (ITimeGraphEntry callStackEntry : threadEntry.getChildren()) {
+                        if (monitor.isCanceled()) {
+                            return;
+                        }
+                        buildStatusEvents(parentTrace, (CallStackEntry) callStackEntry, monitor, ss.getStartTime(), end);
                     }
-                    buildStatusEvents(parentTrace, (CallStackEntry) callStackEntry, monitor, ss.getStartTime(), end);
                 }
             }
             start = end;
@@ -748,33 +788,35 @@ public class CallStackView extends AbstractTimeGraphView {
             return;
         }
         for (TimeGraphEntry traceEntry : entryList) {
-            for (ITimeGraphEntry threadEntry : traceEntry.getChildren()) {
-                ITmfStateSystem ss = ((ThreadEntry) threadEntry).getStateSystem();
-                if (ss == null) {
-                    continue;
-                }
-                if (ss.isCancelled()) {
-                    continue;
-                }
-                if (time < ss.getStartTime() || time > ss.getCurrentEndTime()) {
-                    continue;
-                }
-                for (ITimeGraphEntry child : threadEntry.getChildren()) {
-                    CallStackEntry callStackEntry = (CallStackEntry) child;
-                    ITmfTrace trace = callStackEntry.getTrace();
-                    try {
-                        ITmfStateInterval stackLevelInterval = ss.querySingleState(time, callStackEntry.getQuark());
-                        ITmfStateValue nameValue = stackLevelInterval.getStateValue();
-                        String name = getFunctionName(trace, nameValue);
-                        callStackEntry.setFunctionName(name);
-                        if (name.length() > 0) {
-                            callStackEntry.setFunctionEntryTime(stackLevelInterval.getStartTime());
-                            callStackEntry.setFunctionExitTime(stackLevelInterval.getEndTime() + 1);
+            for (ITimeGraphEntry processEntry : traceEntry.getChildren()) {
+                for (ITimeGraphEntry threadEntry : processEntry.getChildren()) {
+                    ITmfStateSystem ss = ((ThreadEntry) threadEntry).getStateSystem();
+                    if (ss == null) {
+                        continue;
+                    }
+                    if (ss.isCancelled()) {
+                        continue;
+                    }
+                    if (time < ss.getStartTime() || time > ss.getCurrentEndTime()) {
+                        continue;
+                    }
+                    for (ITimeGraphEntry child : threadEntry.getChildren()) {
+                        CallStackEntry callStackEntry = (CallStackEntry) child;
+                        ITmfTrace trace = callStackEntry.getTrace();
+                        try {
+                            ITmfStateInterval stackLevelInterval = ss.querySingleState(time, callStackEntry.getQuark());
+                            ITmfStateValue nameValue = stackLevelInterval.getStateValue();
+                            String name = getFunctionName(trace, nameValue);
+                            callStackEntry.setFunctionName(name);
+                            if (name.length() > 0) {
+                                callStackEntry.setFunctionEntryTime(stackLevelInterval.getStartTime());
+                                callStackEntry.setFunctionExitTime(stackLevelInterval.getEndTime() + 1);
+                            }
+                        } catch (AttributeNotFoundException e) {
+                            Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
+                        } catch (StateSystemDisposedException e) {
+                            /* Ignored */
                         }
-                    } catch (AttributeNotFoundException e) {
-                        Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
-                    } catch (StateSystemDisposedException e) {
-                        /* Ignored */
                     }
                 }
             }
This page took 0.03709 seconds and 5 git commands to generate.