--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 EfficiOS Inc., Alexandre Montplaisir
+ *
+ * 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
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.analysis.os.linux.core.kernelanalysis;
+
+/**
+ * Definitions of values used in the Linux kernel code.
+ *
+ * Instead of using "magic numbers" in state providers, the definitions should
+ * be added here first.
+ *
+ * @author Alexandre Montplaisir
+ * @since 2.0
+ */
+public interface LinuxValues {
+
+ /**
+ * Process states found in scheduler events.
+ *
+ * From include/linux/sched.h
+ *
+ * <pre>
+ * #define TASK_RUNNING 0
+ * #define TASK_INTERRUPTIBLE 1
+ * #define TASK_UNINTERRUPTIBLE 2
+ * #define __TASK_STOPPED 4
+ * #define __TASK_TRACED 8
+ * #define EXIT_DEAD 16
+ * #define EXIT_ZOMBIE 32
+ * #define EXIT_TRACE (EXIT_ZOMBIE | EXIT_DEAD)
+ * #define TASK_DEAD 64
+ * #define TASK_WAKEKILL 128
+ * #define TASK_WAKING 256
+ * #define TASK_PARKED 512
+ * #define TASK_STATE_MAX 1024
+ * </pre>
+ */
+ /**
+ * The task is running normally, can be interrupted, in a syscall or user
+ * mode.
+ */
+ int TASK_STATE_RUNNING = 0;
+
+ /**
+ * The process is in an interruptible sleep, (waiting for an event to
+ * complete)
+ */
+ int TASK_INTERRUPTIBLE = 1;
+
+ /**
+ * The process is in an uninteruptible sleep, (usually waiting on IO)
+ */
+ int TASK_UNINTERRUPTIBLE = 2;
+
+ /**
+ * The process is stopped, it is waiting for a SIGCONT
+ */
+ int TASK_STOPPED__ = 4;
+
+ /**
+ * The process is being monitored by other processes like a debugger
+ */
+ int TASK_TRACED__ = 8;
+
+ /**
+ * The task is terminated. It is lingering waiting for a parent to reap it.
+ */
+ int EXIT_ZOMBIE = 16;
+
+ /**
+ * The final state, the process reaches this state when being reaped. This
+ * state should not be seen.
+ */
+ int EXIT_DEAD = 32;
+
+ /**
+ * The task is dead, that means the PID can be re-used.
+ */
+ int TASK_DEAD = 64;
+
+ /**
+ * The task will wake up only on kill signals
+ */
+ int TASK_WAKEKILL = 128;
+
+ /**
+ * A task is being woken up, should not appear in sched switch, but if we
+ * poll.
+ */
+ int TASK_WAKING = 256;
+
+ /**
+ * A very deep sleep that can only be woken by an unpark wakeup
+ */
+ int TASK_PARK = 512;
+
+ /**
+ * This is the maximum value + 1 that the task state can be. TASK_STATE_MAX
+ * - 1 is useful to mask the task state.
+ */
+ int TASK_STATE_MAX = 1024;
+
+ /**
+ * Process statuses, used in LTTng statedump events.
+ *
+ * This is LTTng-specific, but the statedump are handled at this level, so
+ * it makes sense to add those definitions here.
+ *
+ * Taken from lttng-module's lttng-statedump-impl.c:
+ *
+ * <pre>
+ * enum lttng_process_status {
+ * LTTNG_UNNAMED = 0,
+ * LTTNG_WAIT_FORK = 1,
+ * LTTNG_WAIT_CPU = 2,
+ * LTTNG_EXIT = 3,
+ * LTTNG_ZOMBIE = 4,
+ * LTTNG_WAIT = 5,
+ * LTTNG_RUN = 6,
+ * LTTNG_DEAD = 7,
+ * };
+ * </pre>
+ */
+
+ /** Task is initially preempted */
+ int STATEDUMP_PROCESS_STATUS_WAIT_CPU = 2;
+
+ /** Task is initially blocked */
+ int STATEDUMP_PROCESS_STATUS_WAIT = 5;
+
+ /**
+ * SoftIRQ definitions
+ *
+ * From linux/interrupt.h
+ *
+ * <pre>
+ * enum
+ * {
+ * HI_SOFTIRQ=0,
+ * TIMER_SOFTIRQ,
+ * NET_TX_SOFTIRQ,
+ * NET_RX_SOFTIRQ,
+ * BLOCK_SOFTIRQ,
+ * BLOCK_IOPOLL_SOFTIRQ,
+ * TASKLET_SOFTIRQ,
+ * SCHED_SOFTIRQ,
+ * HRTIMER_SOFTIRQ,
+ * RCU_SOFTIRQ,
+ * NR_SOFTIRQS // not used as this is the NUMBER of softirqs
+ * };
+ * </pre>
+ */
+
+ /** High-priority tasklet */
+ int SOFTIRQ_HI = 0;
+
+ /** Interrupted because of timer */
+ int SOFTIRQ_TIMER = 1;
+
+ /** Interrupted because of network transmission */
+ int SOFTIRQ_NET_TX = 2;
+
+ /** Interrupted because of network reception */
+ int SOFTIRQ_NET_RX = 3;
+
+ /** Interrupted because of block operation */
+ int SOFTIRQ_BLOCK = 4;
+
+ /** Interrupted because of block IO */
+ int SOFTIRQ_BLOCK_IOPOLL = 5;
+
+ /** Tasklet (differed device interrupt) */
+ int SOFTIRQ_TASKLET = 6;
+
+ /** Interrupted because of the scheduler */
+ int SOFTIRQ_SCHED = 7;
+
+ /** Interrupted because of HR timer */
+ int SOFTIRQ_HRTIMER = 8;
+
+ /** Interrupted because of RCU */
+ int SOFTIRQ_RCU = 9;
+}
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.tracecompass.analysis.os.linux.core.kernelanalysis.Attributes;
+import org.eclipse.tracecompass.analysis.os.linux.core.kernelanalysis.LinuxValues;
import org.eclipse.tracecompass.analysis.os.linux.core.kernelanalysis.StateValues;
import org.eclipse.tracecompass.analysis.os.linux.core.trace.IKernelAnalysisEventLayout;
-import org.eclipse.tracecompass.internal.analysis.os.linux.core.kernelanalysis.LinuxValues;
import org.eclipse.tracecompass.statesystem.core.ITmfStateSystemBuilder;
import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException;
import org.eclipse.tracecompass.statesystem.core.exceptions.StateValueTypeException;
+++ /dev/null
-/*******************************************************************************
- * Copyright (c) 2015 EfficiOS Inc., Alexandre Montplaisir
- *
- * 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
- *******************************************************************************/
-
-package org.eclipse.tracecompass.internal.analysis.os.linux.core.kernelanalysis;
-
-/**
- * Definitions of values used in the Linux kernel code.
- *
- * Instead of using "magic numbers" in state providers, the definitions should
- * be added here first.
- *
- * @author Alexandre Montplaisir
- */
-public interface LinuxValues {
-
- /**
- * Process states found in scheduler events.
- *
- * From include/linux/sched.h
- *
- * <pre>
- * #define TASK_RUNNING 0
- * #define TASK_INTERRUPTIBLE 1
- * #define TASK_UNINTERRUPTIBLE 2
- * #define __TASK_STOPPED 4
- * #define __TASK_TRACED 8
- * #define EXIT_DEAD 16
- * #define EXIT_ZOMBIE 32
- * #define EXIT_TRACE (EXIT_ZOMBIE | EXIT_DEAD)
- * #define TASK_DEAD 64
- * #define TASK_WAKEKILL 128
- * #define TASK_WAKING 256
- * #define TASK_PARKED 512
- * #define TASK_STATE_MAX 1024
- * </pre>
- */
- /**
- * The task is running normally, can be interrupted, in a syscall or user
- * mode.
- */
- int TASK_STATE_RUNNING = 0;
-
- /**
- * The process is in an interruptible sleep, (waiting for an event to
- * complete)
- */
- int TASK_INTERRUPTIBLE = 1;
-
- /**
- * The process is in an uninteruptible sleep, (usually waiting on IO)
- */
- int TASK_UNINTERRUPTIBLE = 2;
-
- /**
- * The process is stopped, it is waiting for a SIGCONT
- */
- int TASK_STOPPED__ = 4;
-
- /**
- * The process is being monitored by other processes like a debugger
- */
- int TASK_TRACED__ = 8;
-
- /**
- * The task is terminated. It is lingering waiting for a parent to reap it.
- */
- int EXIT_ZOMBIE = 16;
-
- /**
- * The final state, the process reaches this state when being reaped. This
- * state should not be seen.
- */
- int EXIT_DEAD = 32;
-
- /**
- * The task is dead, that means the PID can be re-used.
- */
- int TASK_DEAD = 64;
-
- /**
- * The task will wake up only on kill signals
- */
- int TASK_WAKEKILL = 128;
-
- /**
- * A task is being woken up, should not appear in sched switch, but if we
- * poll.
- */
- int TASK_WAKING = 256;
-
- /**
- * A very deep sleep that can only be woken by an unpark wakeup
- */
- int TASK_PARK = 512;
-
- /**
- * This is the maximum value + 1 that the task state can be. TASK_STATE_MAX
- * - 1 is useful to mask the task state.
- */
- int TASK_STATE_MAX = 1024;
-
- /**
- * Process statuses, used in LTTng statedump events.
- *
- * This is LTTng-specific, but the statedump are handled at this level, so
- * it makes sense to add those definitions here.
- *
- * Taken from lttng-module's lttng-statedump-impl.c:
- *
- * <pre>
- * enum lttng_process_status {
- * LTTNG_UNNAMED = 0,
- * LTTNG_WAIT_FORK = 1,
- * LTTNG_WAIT_CPU = 2,
- * LTTNG_EXIT = 3,
- * LTTNG_ZOMBIE = 4,
- * LTTNG_WAIT = 5,
- * LTTNG_RUN = 6,
- * LTTNG_DEAD = 7,
- * };
- * </pre>
- */
-
- /** Task is initially preempted */
- int STATEDUMP_PROCESS_STATUS_WAIT_CPU = 2;
-
- /** Task is initially blocked */
- int STATEDUMP_PROCESS_STATUS_WAIT = 5;
-
- /**
- * SoftIRQ definitions
- *
- * From linux/interrupt.h
- *
- * <pre>
- * enum
- * {
- * HI_SOFTIRQ=0,
- * TIMER_SOFTIRQ,
- * NET_TX_SOFTIRQ,
- * NET_RX_SOFTIRQ,
- * BLOCK_SOFTIRQ,
- * BLOCK_IOPOLL_SOFTIRQ,
- * TASKLET_SOFTIRQ,
- * SCHED_SOFTIRQ,
- * HRTIMER_SOFTIRQ,
- * RCU_SOFTIRQ,
- * NR_SOFTIRQS // not used as this is the NUMBER of softirqs
- * };
- * </pre>
- */
-
- /** High-priority tasklet */
- int SOFTIRQ_HI = 0;
-
- /** Interrupted because of timer */
- int SOFTIRQ_TIMER = 1;
-
- /** Interrupted because of network transmission */
- int SOFTIRQ_NET_TX = 2;
-
- /** Interrupted because of network reception */
- int SOFTIRQ_NET_RX = 3;
-
- /** Interrupted because of block operation */
- int SOFTIRQ_BLOCK = 4;
-
- /** Interrupted because of block IO */
- int SOFTIRQ_BLOCK_IOPOLL = 5;
-
- /** Tasklet (differed device interrupt) */
- int SOFTIRQ_TASKLET = 6;
-
- /** Interrupted because of the scheduler */
- int SOFTIRQ_SCHED = 7;
-
- /** Interrupted because of HR timer */
- int SOFTIRQ_HRTIMER = 8;
-
- /** Interrupted because of RCU */
- int SOFTIRQ_RCU = 9;
-}
org.eclipse.tracecompass.tmf.core,
org.eclipse.tracecompass.tmf.ctf.core,
org.eclipse.tracecompass.lttng2.control.core,
- org.eclipse.tracecompass.analysis.os.linux.core
+ org.eclipse.tracecompass.analysis.os.linux.core,
+ org.eclipse.tracecompass.analysis.graph.core
Export-Package: org.eclipse.tracecompass.internal.lttng2.kernel.core;x-friends:="org.eclipse.tracecompass.lttng2.kernel.ui,org.eclipse.tracecompass.lttng2.kernel.core.tests",
+ org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.graph.building;x-friends:="org.eclipse.tracecompass.lttng2.kernel.ui,org.eclipse.tracecompass.lttng2.kernel.core.tests",
+ org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.graph.handlers;x-friends:="org.eclipse.tracecompass.lttng2.kernel.ui,org.eclipse.tracecompass.lttng2.kernel.core.tests",
+ org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.graph.model;x-friends:="org.eclipse.tracecompass.lttng2.kernel.ui,org.eclipse.tracecompass.lttng2.kernel.core.tests",
org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.vm;x-friends:="org.eclipse.tracecompass.lttng2.kernel.core.tests,org.eclipse.tracecompass.lttng2.kernel.ui",
org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.vm.model;x-friends:="org.eclipse.tracecompass.lttng2.kernel.core.tests,org.eclipse.tracecompass.lttng2.kernel.ui",
org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.vm.model.qemukvm;x-friends:="org.eclipse.tracecompass.lttng2.kernel.core.tests,org.eclipse.tracecompass.lttng2.kernel.ui",
class="org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.vm.trace.VirtualMachineExperiment">
</tracetype>
</module>
+ <module
+ analysis_module="org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.graph.building.LttngKernelExecutionGraph"
+ applies_experiment="true"
+ id="org.eclipse.tracecompass.lttng2.kernel.core.execgraph"
+ name="LTTng Kernel Exec Graph">
+ <tracetype
+ class="org.eclipse.tracecompass.lttng2.kernel.core.trace.LttngKernelTrace">
+ </tracetype>
+ </module>
</extension>
</plugin>
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 École Polytechnique de Montréal
+ *
+ * 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
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.graph.building;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.tracecompass.analysis.graph.core.base.IGraphWorker;
+import org.eclipse.tracecompass.analysis.graph.core.base.TmfEdge;
+import org.eclipse.tracecompass.analysis.graph.core.base.TmfGraph;
+import org.eclipse.tracecompass.analysis.graph.core.base.TmfVertex;
+import org.eclipse.tracecompass.analysis.graph.core.base.TmfVertex.EdgeDirection;
+import org.eclipse.tracecompass.analysis.graph.core.building.AbstractTmfGraphProvider;
+import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.graph.handlers.EventContextHandler;
+import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.graph.handlers.TraceEventHandlerExecutionGraph;
+import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.graph.handlers.TraceEventHandlerSched;
+import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.graph.handlers.TraceEventHandlerStatedump;
+import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.graph.model.LttngSystemModel;
+import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.graph.model.LttngWorker;
+import org.eclipse.tracecompass.internal.lttng2.kernel.core.trace.layout.LttngEventLayout;
+import org.eclipse.tracecompass.lttng2.kernel.core.trace.LttngKernelTrace;
+import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
+
+/**
+ * The graph provider builds an execution graph from a kernel trace. The
+ * execution graph is a 2d-mesh model of the system, where vertices represent
+ * events, horizontal edges represent states of tasks, and where vertical edges
+ * represent relations between tasks (currently local wake-up and pairs of
+ * network packets).
+ *
+ * Event handling is split into smaller sub-handlers. One event request is done,
+ * and each event is passed to the handlers in the order in the list, such as
+ * this pseudo code:
+ *
+ * <pre>
+ * for each event:
+ * for each handler:
+ * handler.handleEvent(event)
+ * </pre>
+ *
+ * @author Geneviève Bastien
+ * @author Francis Giraldeau
+ */
+public class LttngKernelExecGraphProvider extends AbstractTmfGraphProvider {
+
+ private final LttngEventLayout fEventLayout;
+ private final LttngSystemModel fSystem;
+
+ /**
+ * Represents an interrupt context
+ */
+ public enum Context {
+ /** Not in an interrupt */
+ NONE,
+ /** The interrupt is a soft IRQ */
+ SOFTIRQ,
+ /** The interrupt is an IRQ */
+ IRQ,
+ /** The interrupt is a timer */
+ HRTIMER
+ }
+
+ /**
+ * A list of status a thread can be in
+ */
+ public enum ProcessStatus {
+ /** Unknown process status */
+ UNKNOWN(0),
+ /** Waiting for a fork */
+ WAIT_FORK(1),
+ /** Waiting for the CPU */
+ WAIT_CPU(2),
+ /** The thread has exited, but is not dead yet */
+ EXIT(3),
+ /** The thread is a zombie thread */
+ ZOMBIE(4),
+ /** The thread is blocked */
+ WAIT_BLOCKED(5),
+ /** The thread is running */
+ RUN(6),
+ /** The thread is dead */
+ DEAD(7);
+ private final int fValue;
+
+ private ProcessStatus(int value) {
+ fValue = value;
+ }
+
+ private int value() {
+ return fValue;
+ }
+
+ /**
+ * Get the ProcessStatus associated with a long value
+ *
+ * @param val
+ * The long value corresponding to a status
+ * @return The {@link ProcessStatus} enum value
+ */
+ static public ProcessStatus getStatus(long val) {
+ for (ProcessStatus e : ProcessStatus.values()) {
+ if (e.value() == val) {
+ return e;
+ }
+ }
+ return UNKNOWN;
+ }
+ }
+
+ /**
+ * Constructor
+ *
+ * @param trace
+ * The trace on which to build graph
+ */
+ public LttngKernelExecGraphProvider(ITmfTrace trace) {
+ super(trace, "LTTng Kernel"); //$NON-NLS-1$
+ fSystem = new LttngSystemModel();
+
+ /*
+ * TODO: factorize this code because it is duplicated everywhere to
+ * access layout
+ */
+ if (trace instanceof LttngKernelTrace) {
+
+ fEventLayout = (LttngEventLayout) ((LttngKernelTrace) trace).getKernelEventLayout();
+ } else {
+ /* Fall-back to the base LttngEventLayout */
+ fEventLayout = (LttngEventLayout) LttngEventLayout.getInstance();
+ }
+
+ registerHandler(new TraceEventHandlerStatedump(this));
+ registerHandler(new TraceEventHandlerSched(this));
+ registerHandler(new EventContextHandler(this));
+ registerHandler(new TraceEventHandlerExecutionGraph(this));
+ }
+
+ /**
+ * Simplify graph after construction
+ */
+ @Override
+ public void done() {
+ TmfGraph graph = getAssignedGraph();
+ if (graph == null) {
+ throw new NullPointerException();
+ }
+ Set<IGraphWorker> keys = graph.getWorkers();
+ List<LttngWorker> kernelWorker = new ArrayList<>();
+ /* build the set of worker to eliminate */
+ for (Object k : keys) {
+ if (k instanceof LttngWorker) {
+ LttngWorker w = (LttngWorker) k;
+ if (w.getHostThread().getTid() == -1) {
+ kernelWorker.add(w);
+ }
+ }
+ }
+ for (LttngWorker k : kernelWorker) {
+ if (k == null) {
+ throw new NullPointerException();
+ }
+ List<TmfVertex> nodes = graph.getNodesOf(k);
+ for (TmfVertex node : nodes) {
+ /*
+ * send -> recv, it removes the vertex between the real source
+ * and destination
+ */
+ TmfEdge nextH = node.getEdge(EdgeDirection.OUTGOING_HORIZONTAL_EDGE);
+ TmfEdge inV = node.getEdge(EdgeDirection.INCOMING_VERTICAL_EDGE);
+ if (inV != null && nextH != null) {
+
+ TmfVertex next = nextH.getVertexTo();
+ TmfEdge nextV = next.getEdge(EdgeDirection.OUTGOING_VERTICAL_EDGE);
+ if (nextV != null) {
+ TmfVertex src = inV.getVertexFrom();
+ TmfVertex dst = nextV.getVertexTo();
+
+ /* unlink */
+ node.removeEdge(EdgeDirection.INCOMING_VERTICAL_EDGE);
+ next.removeEdge(EdgeDirection.OUTGOING_VERTICAL_EDGE);
+
+ /* simplified link */
+ src.linkVertical(dst).setType(inV.getType());
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns the event layout for the current trace
+ *
+ * @return the eventLayout
+ */
+ public LttngEventLayout getEventLayout() {
+ return fEventLayout;
+ }
+
+ /**
+ * Returns the system model
+ *
+ * @return the system
+ */
+ public LttngSystemModel getSystem() {
+ return fSystem;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 École Polytechnique de Montréal
+ *
+ * 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
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.graph.building;
+
+import org.eclipse.tracecompass.analysis.graph.core.building.ITmfGraphProvider;
+import org.eclipse.tracecompass.analysis.graph.core.building.TmfGraphBuilderModule;
+import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
+
+/**
+ * Graph building module for the lttng kernel execution graph
+ *
+ * @author Francis Giraldeau
+ * @author Geneviève Bastien
+ */
+public class LttngKernelExecutionGraph extends TmfGraphBuilderModule {
+
+ /**
+ * Analysis id of this module
+ */
+ public static final String ANALYSIS_ID = "org.eclipse.tracecompass.lttng2.kernel.core.execgraph"; //$NON-NLS-1$
+
+ @Override
+ public boolean canExecute(ITmfTrace trace) {
+ /**
+ * TODO: Trace must have at least sched_switches and sched_wakeups
+ * enabled
+ */
+ return true;
+ }
+
+ @Override
+ protected ITmfGraphProvider getGraphProvider() {
+ ITmfTrace trace = getTrace();
+ if (trace == null) {
+ throw new NullPointerException();
+ }
+ return new LttngKernelExecGraphProvider(trace);
+ }
+
+ @Override
+ protected String getFullHelpText() {
+ return super.getFullHelpText();
+ }
+
+ @Override
+ protected String getShortHelpText(ITmfTrace trace) {
+ return super.getShortHelpText(trace);
+ }
+
+ @Override
+ protected String getTraceCannotExecuteHelpText(ITmfTrace trace) {
+ return "The trace must have events 'sched_switch' and 'sched_wakeup' enabled"; //$NON-NLS-1$
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 École Polytechnique de Montréal
+ *
+ * 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
+ *******************************************************************************/
+
+@org.eclipse.jdt.annotation.NonNullByDefault
+package org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.graph.building;
\ No newline at end of file
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 École Polytechnique de Montréal
+ *
+ * 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
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.graph.handlers;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.tracecompass.analysis.graph.core.building.AbstractTraceEventHandler;
+import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.graph.building.LttngKernelExecGraphProvider;
+import org.eclipse.tracecompass.internal.lttng2.kernel.core.trace.layout.LttngEventLayout;
+import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
+import org.eclipse.tracecompass.tmf.core.event.ITmfEventType;
+import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
+import org.eclipse.tracecompass.tmf.core.trace.ITmfTraceWithPreDefinedEvents;
+import org.eclipse.tracecompass.tmf.core.trace.TmfEventTypeCollectionHelper;
+import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager;
+
+/**
+ * Holds the fields commons to all handler classes.
+ *
+ * @author Francis Giraldeau <francis.giraldeau@gmail.com>
+ *
+ */
+public class BaseHandler extends AbstractTraceEventHandler {
+
+ private final LttngKernelExecGraphProvider fProvider;
+ private Map<ITmfTrace, Boolean> fHasEventSchedTTWU;
+
+ BaseHandler(LttngKernelExecGraphProvider provider) {
+ fProvider = provider;
+ fHasEventSchedTTWU = new HashMap<>();
+ ITmfTrace trace = getProvider().getTrace();
+ LttngEventLayout layout = getProvider().getEventLayout();
+ Collection<ITmfTrace> traceSet = TmfTraceManager.getTraceSet(trace);
+ for (ITmfTrace traceItem : traceSet) {
+ if (traceItem instanceof ITmfTraceWithPreDefinedEvents) {
+ Set<? extends ITmfEventType> content = ((ITmfTraceWithPreDefinedEvents) traceItem).getContainedEventTypes();
+ Set<String> traceEvents = TmfEventTypeCollectionHelper.getEventNames(content);
+ boolean hasEvent = traceEvents.contains(layout.eventSchedProcessTTWU());
+ fHasEventSchedTTWU.put(traceItem, hasEvent);
+ }
+ }
+ }
+
+ /**
+ * Returns the parent graph provider
+ *
+ * @return the graph provider
+ */
+ public LttngKernelExecGraphProvider getProvider() {
+ return fProvider;
+ }
+
+ /**
+ * Return if the trace has the try to wake-up event
+ *
+ * @param trace
+ * the trace to check
+ * @return if the trace has the try to wake-up event
+ */
+ public boolean traceHasEventSchedTTWU(ITmfTrace trace) {
+ Boolean ret = fHasEventSchedTTWU.get(trace);
+ if (ret == null) {
+ return false;
+ }
+ return ret;
+ }
+
+ @Override
+ public void handleEvent(ITmfEvent event) {
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 École Polytechnique de Montréal
+ *
+ * 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
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.graph.handlers;
+
+import org.eclipse.tracecompass.analysis.os.linux.core.trace.IKernelAnalysisEventLayout;
+import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.graph.building.LttngKernelExecGraphProvider;
+import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.graph.building.LttngKernelExecGraphProvider.Context;
+import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.graph.model.LttngInterruptContext;
+import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.graph.model.LttngSystemModel;
+import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
+import org.eclipse.tracecompass.tmf.core.event.aspect.TmfCpuAspect;
+import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils;
+
+/**
+ * Event Handler to handle the interrupt context stack of the model
+ *
+ * @author Francis Giraldeau
+ * @author Geneviève Bastien
+ */
+public class EventContextHandler extends BaseHandler {
+
+ /**
+ * Constructor
+ *
+ * @param provider
+ * The parent graph provider
+ */
+ public EventContextHandler(LttngKernelExecGraphProvider provider) {
+ super(provider);
+ }
+
+ @Override
+ public void handleEvent(ITmfEvent event) {
+ String eventName = event.getName();
+ IKernelAnalysisEventLayout eventLayout = getProvider().getEventLayout();
+ if (eventName.equals(eventLayout.eventSoftIrqEntry())) {
+ handleSoftirqEntry(event);
+ } else if (eventName.equals(eventLayout.eventSoftIrqExit())) {
+ handleSoftirqExit(event);
+ } else if (eventName.equals(eventLayout.eventHRTimerExpireEntry())) {
+ handleHrtimerExpireEntry(event);
+ } else if (eventName.equals(eventLayout.eventHRTimerExpireExit())) {
+ handleHrtimerExpireExit(event);
+ } else if (eventName.equals(eventLayout.eventIrqHandlerEntry())) {
+ handleIrqHandlerEntry(event);
+ } else if (eventName.equals(eventLayout.eventIrqHandlerExit())) {
+ handleIrqHandlerExit(event);
+ }
+ }
+
+ private void pushInterruptContext(ITmfEvent event, Context ctx) {
+ Object cpuObj = TmfTraceUtils.resolveEventAspectOfClassForEvent(event.getTrace(), TmfCpuAspect.class, event);
+ if (cpuObj == null) {
+ throw new NullPointerException();
+ }
+ Integer cpu = (Integer) cpuObj;
+ LttngSystemModel system = getProvider().getSystem();
+
+ LttngInterruptContext interruptCtx = new LttngInterruptContext(event, ctx);
+
+ system.pushContextStack(event.getTrace().getHostId(), cpu, interruptCtx);
+ }
+
+ private void popInterruptContext(ITmfEvent event, Context ctx) {
+ Object cpuObj = TmfTraceUtils.resolveEventAspectOfClassForEvent(event.getTrace(), TmfCpuAspect.class, event);
+ if (cpuObj == null) {
+ throw new NullPointerException();
+ }
+ Integer cpu = (Integer) cpuObj;
+ LttngSystemModel system = getProvider().getSystem();
+
+ /* TODO: add a warning bookmark if the interrupt context is not coherent */
+ LttngInterruptContext interruptCtx = system.peekContextStack(event.getTrace().getHostId(), cpu);
+ if (interruptCtx.getContext() == ctx) {
+ system.popContextStack(event.getTrace().getHostId(), cpu);
+ }
+ }
+
+ private void handleSoftirqEntry(ITmfEvent event) {
+ pushInterruptContext(event, Context.SOFTIRQ);
+ }
+
+ private void handleSoftirqExit(ITmfEvent event) {
+ popInterruptContext(event, Context.SOFTIRQ);
+ }
+
+ private void handleIrqHandlerEntry(ITmfEvent event) {
+ pushInterruptContext(event, Context.IRQ);
+ }
+
+ private void handleIrqHandlerExit(ITmfEvent event) {
+ popInterruptContext(event, Context.IRQ);
+ }
+
+ private void handleHrtimerExpireEntry(ITmfEvent event) {
+ pushInterruptContext(event, Context.HRTIMER);
+ }
+
+ private void handleHrtimerExpireExit(ITmfEvent event) {
+ popInterruptContext(event, Context.HRTIMER);
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 École Polytechnique de Montréal
+ *
+ * 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
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.graph.handlers;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * Messages for lttng graph handlers
+ *
+ * @author Francis Giraldeau <francis.giraldeau@gmail.com>
+ *
+ */
+@NonNullByDefault(false)
+public class Messages extends NLS {
+ private static final String BUNDLE_NAME = "org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.graph.handlers.messages"; //$NON-NLS-1$
+
+ /**
+ * Default thread name
+ */
+ public static String TraceEventHandlerSched_UnknownThreadName;
+
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
+
+ private Messages() {
+ }
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 École Polytechnique de Montréal
+ *
+ * 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
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.graph.handlers;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.analysis.graph.core.base.TmfEdge;
+import org.eclipse.tracecompass.analysis.graph.core.base.TmfEdge.EdgeType;
+import org.eclipse.tracecompass.analysis.graph.core.base.TmfGraph;
+import org.eclipse.tracecompass.analysis.graph.core.base.TmfVertex;
+import org.eclipse.tracecompass.analysis.graph.core.base.TmfVertex.EdgeDirection;
+import org.eclipse.tracecompass.analysis.os.linux.core.kernelanalysis.LinuxValues;
+import org.eclipse.tracecompass.analysis.os.linux.core.model.HostThread;
+import org.eclipse.tracecompass.common.core.NonNullUtils;
+import org.eclipse.tracecompass.internal.lttng2.kernel.core.TcpEventStrings;
+import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.graph.building.LttngKernelExecGraphProvider;
+import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.graph.building.LttngKernelExecGraphProvider.Context;
+import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.graph.building.LttngKernelExecGraphProvider.ProcessStatus;
+import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.graph.model.EventField;
+import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.graph.model.LttngInterruptContext;
+import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.graph.model.LttngSystemModel;
+import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.graph.model.LttngWorker;
+import org.eclipse.tracecompass.internal.lttng2.kernel.core.trace.layout.LttngEventLayout;
+import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
+import org.eclipse.tracecompass.tmf.core.event.aspect.TmfCpuAspect;
+import org.eclipse.tracecompass.tmf.core.event.matching.IMatchProcessingUnit;
+import org.eclipse.tracecompass.tmf.core.event.matching.TmfEventDependency;
+import org.eclipse.tracecompass.tmf.core.event.matching.TmfEventMatching;
+import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
+import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils;
+
+import com.google.common.collect.HashBasedTable;
+import com.google.common.collect.Table;
+
+/**
+ * Event handler that actually builds the execution graph from the events
+ *
+ * @author Francis Giraldeau
+ * @author Geneviève Bastien
+ */
+public class TraceEventHandlerExecutionGraph extends BaseHandler {
+
+ /*
+ * The following IRQ constants was found empirically.
+ *
+ * TODO: other IRQ values should be determined from the lttng_statedump_interrupt events.
+ */
+ private static final int IRQ_TIMER = 0;
+
+ private static final NullProgressMonitor DEFAULT_PROGRESS_MONITOR = new NullProgressMonitor();
+
+ private final Table<String, Integer, LttngWorker> fKernel;
+ private final IMatchProcessingUnit fMatchProcessing;
+ private HashMap<ITmfEvent, TmfVertex> fTcpNodes;
+ private TmfEventMatching fTcpMatching;
+
+ /**
+ * Constructor
+ *
+ * @param provider
+ * The parent graph provider
+ */
+ public TraceEventHandlerExecutionGraph(LttngKernelExecGraphProvider provider) {
+ super(provider);
+ fKernel = NonNullUtils.checkNotNull(HashBasedTable.<String, Integer, LttngWorker> create());
+
+ fTcpNodes = new HashMap<>();
+ fMatchProcessing = new IMatchProcessingUnit() {
+
+ @Override
+ public void matchingEnded() {
+ }
+
+ @Override
+ public int countMatches() {
+ return 0;
+ }
+
+ @Override
+ public void addMatch(@Nullable TmfEventDependency match) {
+ if (match == null) {
+ return;
+ }
+ TmfVertex output = fTcpNodes.remove(match.getSourceEvent());
+ TmfVertex input = fTcpNodes.remove(match.getDestinationEvent());
+ if (output != null && input != null) {
+ output.linkVertical(input).setType(EdgeType.NETWORK);
+ }
+ }
+
+ @Override
+ public void init(@Nullable Collection<ITmfTrace> fTraces) {
+
+ }
+
+ };
+
+ ITmfTrace trace = provider.getTrace();
+ fTcpMatching = new TmfEventMatching(Collections.singleton(trace), fMatchProcessing);
+ fTcpMatching.initMatching();
+ }
+
+ private LttngWorker getOrCreateKernelWorker(ITmfEvent event, Integer cpu) {
+ String host = event.getTrace().getHostId();
+ LttngWorker worker = fKernel.get(host, cpu);
+ if (worker == null) {
+ HostThread ht = new HostThread(host, -1);
+ worker = new LttngWorker(ht, "kernel/" + cpu, event.getTimestamp().getValue()); //$NON-NLS-1$
+ worker.setStatus(ProcessStatus.RUN);
+
+ fKernel.put(host, cpu, worker);
+ }
+ return worker;
+ }
+
+ @Override
+ public void handleEvent(ITmfEvent ev) {
+ String eventName = ev.getName();
+ LttngEventLayout eventLayout = getProvider().getEventLayout();
+
+ if (eventName.equals(eventLayout.eventSchedSwitch())) {
+ handleSchedSwitch(ev);
+ } else if (eventName.equals(eventLayout.eventSchedProcessTTWU())) {
+ if (traceHasEventSchedTTWU(ev.getTrace())) {
+ handleSchedWakeup(ev);
+ }
+ } else if (eventName.equals(eventLayout.eventSchedProcessWakeup())) {
+ if (!traceHasEventSchedTTWU(ev.getTrace())) {
+ handleSchedWakeup(ev);
+ }
+ } else if (eventName.equals(eventLayout.eventSchedProcessWakeupNew())) {
+ if (!traceHasEventSchedTTWU(ev.getTrace())) {
+ handleSchedWakeup(ev);
+ }
+ } else if (eventName.equals(eventLayout.eventSoftIrqEntry())) {
+ handleSoftirqEntry(ev);
+ } else if (eventName.equals(TcpEventStrings.INET_SOCK_LOCAL_IN) ||
+ eventName.equals(TcpEventStrings.NETIF_RECEIVE_SKB)) {
+ handleInetSockLocalIn(ev);
+ } else if (eventName.equals(TcpEventStrings.INET_SOCK_LOCAL_OUT) ||
+ eventName.equals(TcpEventStrings.NET_DEV_QUEUE)) {
+ handleInetSockLocalOut(ev);
+ }
+ }
+
+ private TmfVertex stateExtend(LttngWorker task, long ts) {
+ TmfGraph graph = NonNullUtils.checkNotNull(getProvider().getAssignedGraph());
+ TmfVertex node = new TmfVertex(ts);
+ ProcessStatus status = task.getStatus();
+ graph.append(task, node, resolveProcessStatus(status));
+ return node;
+ }
+
+ private TmfVertex stateChange(LttngWorker task, long ts) {
+ TmfGraph graph = NonNullUtils.checkNotNull(getProvider().getAssignedGraph());
+ TmfVertex node = new TmfVertex(ts);
+ ProcessStatus status = task.getOldStatus();
+ graph.append(task, node, resolveProcessStatus(status));
+ return node;
+ }
+
+ private static EdgeType resolveProcessStatus(ProcessStatus status) {
+ EdgeType ret = EdgeType.UNKNOWN;
+ switch (status) {
+ case DEAD:
+ break;
+ case EXIT:
+ case RUN:
+ ret = EdgeType.RUNNING;
+ break;
+ case UNKNOWN:
+ ret = EdgeType.UNKNOWN;
+ break;
+ case WAIT_BLOCKED:
+ ret = EdgeType.BLOCKED;
+ break;
+ case WAIT_CPU:
+ case WAIT_FORK:
+ ret = EdgeType.PREEMPTED;
+ break;
+ case ZOMBIE:
+ ret = EdgeType.UNKNOWN;
+ break;
+ default:
+ break;
+ }
+ return ret;
+ }
+
+ private void handleSchedSwitch(ITmfEvent event) {
+ String host = event.getTrace().getHostId();
+ long ts = event.getTimestamp().getValue();
+ LttngEventLayout eventLayout = getProvider().getEventLayout();
+ LttngSystemModel system = getProvider().getSystem();
+
+ Integer next = EventField.getInt(event, eventLayout.fieldNextTid());
+ Integer prev = EventField.getInt(event, eventLayout.fieldPrevTid());
+
+ LttngWorker nextTask = system.findWorker(new HostThread(host, next));
+ LttngWorker prevTask = system.findWorker(new HostThread(host, prev));
+
+ if (prevTask == null || nextTask == null) {
+ return;
+ }
+ stateChange(prevTask, ts);
+ stateChange(nextTask, ts);
+ }
+
+ private void handleSchedWakeup(ITmfEvent event) {
+ TmfGraph graph = NonNullUtils.checkNotNull(getProvider().getAssignedGraph());
+ String host = event.getTrace().getHostId();
+ Object cpuObj = TmfTraceUtils.resolveEventAspectOfClassForEvent(event.getTrace(), TmfCpuAspect.class, event);
+ if (cpuObj == null) {
+ throw new NullPointerException();
+ }
+ Integer cpu = (Integer) cpuObj;
+ LttngEventLayout eventLayout = getProvider().getEventLayout();
+ LttngSystemModel system = getProvider().getSystem();
+
+ long ts = event.getTimestamp().getValue();
+ Integer tid = EventField.getInt(event, eventLayout.fieldTid());
+
+ LttngWorker target = system.findWorker(new HostThread(host, tid));
+ LttngWorker current = system.getWorkerOnCpu(host, cpu);
+ if (target == null) {
+ return;
+ }
+
+ ProcessStatus status = target.getOldStatus();
+ switch (status) {
+ case WAIT_FORK:
+ waitFork(graph, ts, target, current);
+ break;
+ case WAIT_BLOCKED:
+ waitBlocked(event, graph, host, cpu, eventLayout, system, ts, target, current);
+ break;
+ case DEAD:
+ case EXIT:
+ case RUN:
+ case UNKNOWN:
+ case WAIT_CPU:
+ case ZOMBIE:
+ break;
+ default:
+ break;
+ }
+ }
+
+ private void waitBlocked(ITmfEvent event, TmfGraph graph, String host, Integer cpu, LttngEventLayout eventLayout, LttngSystemModel system, long ts, LttngWorker target, @Nullable LttngWorker current) {
+ LttngInterruptContext context = system.peekContextStack(host, cpu);
+ switch (context.getContext()) {
+ case HRTIMER:
+ // shortcut of appendTaskNode: resolve blocking source in situ
+ graph.append(target, new TmfVertex(ts), EdgeType.TIMER);
+ break;
+ case IRQ:
+ irq(graph, eventLayout, ts, target, context);
+ break;
+ case SOFTIRQ:
+ softIrq(event, graph, cpu, eventLayout, ts, target, context);
+ break;
+ case NONE:
+ none(ts, target, current);
+ break;
+ default:
+ break;
+ }
+ }
+
+ private void softIrq(ITmfEvent event, TmfGraph graph, Integer cpu, LttngEventLayout eventLayout, long ts, LttngWorker target, LttngInterruptContext context) {
+ TmfVertex wup = new TmfVertex(ts);
+ TmfEdge l2 = graph.append(target, wup);
+ if (l2 != null) {
+ int vec = EventField.getLong(context.getEvent(), eventLayout.fieldVec()).intValue();
+ l2.setType(resolveSoftirq(vec));
+ }
+ // special case for network related softirq
+ Long vec = EventField.getLong(context.getEvent(), eventLayout.fieldVec());
+ if (vec == LinuxValues.SOFTIRQ_NET_RX || vec == LinuxValues.SOFTIRQ_NET_TX) {
+ // create edge if wake up is caused by incoming packet
+ LttngWorker k = getOrCreateKernelWorker(event, cpu);
+ TmfVertex tail = graph.getTail(k);
+ if (tail != null && tail.getEdge(EdgeDirection.INCOMING_VERTICAL_EDGE) != null) {
+ TmfVertex kwup = stateExtend(k, event.getTimestamp().getValue());
+ kwup.linkVertical(wup);
+ }
+ }
+ }
+
+ private void none(long ts, LttngWorker target, @Nullable LttngWorker current) {
+ // task context wakeup
+ if (current != null) {
+ TmfVertex n0 = stateExtend(current, ts);
+ TmfVertex n1 = stateChange(target, ts);
+ n0.linkVertical(n1);
+ } else {
+ stateChange(target, ts);
+ }
+ }
+
+ private static void irq(TmfGraph graph, LttngEventLayout eventLayout, long ts, LttngWorker target, LttngInterruptContext context) {
+ TmfEdge link = graph.append(target, new TmfVertex(ts));
+ if (link != null) {
+ int vec = EventField.getLong(context.getEvent(), eventLayout.fieldIrq()).intValue();
+ link.setType(resolveIRQ(vec));
+ }
+ }
+
+ private void waitFork(TmfGraph graph, long ts, LttngWorker target, @Nullable LttngWorker current) {
+ if (current != null) {
+ TmfVertex n0 = stateExtend(current, ts);
+ TmfVertex n1 = stateChange(target, ts);
+ graph.link(n0, n1);
+ } else {
+ stateChange(target, ts);
+ }
+ }
+
+ private static EdgeType resolveIRQ(int vec) {
+ EdgeType ret = EdgeType.UNKNOWN;
+ switch (vec) {
+ case IRQ_TIMER:
+ ret = EdgeType.INTERRUPTED;
+ break;
+ default:
+ ret = EdgeType.UNKNOWN;
+ break;
+ }
+ return ret;
+ }
+
+ private static EdgeType resolveSoftirq(int vec) {
+ EdgeType ret = EdgeType.UNKNOWN;
+ switch (vec) {
+ case LinuxValues.SOFTIRQ_HRTIMER:
+ case LinuxValues.SOFTIRQ_TIMER:
+ ret = EdgeType.TIMER;
+ break;
+ case LinuxValues.SOFTIRQ_BLOCK:
+ case LinuxValues.SOFTIRQ_BLOCK_IOPOLL:
+ ret = EdgeType.BLOCK_DEVICE;
+ break;
+ case LinuxValues.SOFTIRQ_NET_RX:
+ case LinuxValues.SOFTIRQ_NET_TX:
+ ret = EdgeType.NETWORK;
+ break;
+ case LinuxValues.SOFTIRQ_SCHED:
+ ret = EdgeType.INTERRUPTED;
+ break;
+ default:
+ ret = EdgeType.UNKNOWN;
+ break;
+ }
+ return ret;
+ }
+
+ private void handleInetSockLocalIn(ITmfEvent event) {
+ Object cpuObj = TmfTraceUtils.resolveEventAspectOfClassForEvent(event.getTrace(), TmfCpuAspect.class, event);
+ if (cpuObj == null) {
+ throw new NullPointerException();
+ }
+ Integer cpu = (Integer) cpuObj;
+ String host = event.getTrace().getHostId();
+ LttngSystemModel system = getProvider().getSystem();
+
+ LttngInterruptContext intCtx = system.peekContextStack(host, cpu);
+ Context context = intCtx.getContext();
+ if (context == Context.SOFTIRQ) {
+ LttngWorker k = getOrCreateKernelWorker(event, cpu);
+ TmfVertex endpoint = stateExtend(k, event.getTimestamp().getValue());
+ fTcpNodes.put(event, endpoint);
+ // TODO add actual progress monitor
+ fTcpMatching.matchEvent(event, event.getTrace(), DEFAULT_PROGRESS_MONITOR);
+ }
+ }
+
+ private void handleInetSockLocalOut(ITmfEvent event) {
+ Object cpuObj = NonNullUtils.checkNotNull(TmfTraceUtils.resolveEventAspectOfClassForEvent(event.getTrace(), TmfCpuAspect.class, event));
+ Integer cpu = (Integer) cpuObj;
+ String host = event.getTrace().getHostId();
+ LttngSystemModel system = getProvider().getSystem();
+
+ LttngInterruptContext intCtx = system.peekContextStack(host, cpu);
+ Context context = intCtx.getContext();
+
+ LttngWorker sender = null;
+ if (context == Context.NONE) {
+ sender = system.getWorkerOnCpu(event.getTrace().getHostId(), cpu);
+ } else if (context == Context.SOFTIRQ) {
+ sender = getOrCreateKernelWorker(event, cpu);
+ }
+ if (sender == null) {
+ return;
+ }
+ TmfVertex endpoint = stateExtend(sender, event.getTimestamp().getValue());
+ fTcpNodes.put(event, endpoint);
+ // TODO, add actual progress monitor
+ fTcpMatching.matchEvent(event, event.getTrace(), new NullProgressMonitor());
+ }
+
+ private void handleSoftirqEntry(ITmfEvent event) {
+ LttngEventLayout eventLayout = getProvider().getEventLayout();
+ TmfGraph graph = NonNullUtils.checkNotNull(getProvider().getAssignedGraph());
+ Long vec = EventField.getLong(event, eventLayout.fieldVec());
+ if (vec == LinuxValues.SOFTIRQ_NET_RX || vec == LinuxValues.SOFTIRQ_NET_TX) {
+ Object cpuObj = NonNullUtils.checkNotNull(TmfTraceUtils.resolveEventAspectOfClassForEvent(event.getTrace(), TmfCpuAspect.class, event));
+ Integer cpu = (Integer) cpuObj;
+ LttngWorker k = getOrCreateKernelWorker(event, cpu);
+ graph.add(k, new TmfVertex(event.getTimestamp().getValue()));
+ }
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 École Polytechnique de Montréal
+ *
+ * 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
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.graph.handlers;
+
+import org.eclipse.tracecompass.analysis.os.linux.core.kernelanalysis.LinuxValues;
+import org.eclipse.tracecompass.analysis.os.linux.core.model.HostThread;
+import org.eclipse.tracecompass.common.core.NonNullUtils;
+import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.graph.building.LttngKernelExecGraphProvider;
+import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.graph.building.LttngKernelExecGraphProvider.ProcessStatus;
+import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.graph.model.EventField;
+import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.graph.model.LttngSystemModel;
+import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.graph.model.LttngWorker;
+import org.eclipse.tracecompass.internal.lttng2.kernel.core.trace.layout.LttngEventLayout;
+import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
+import org.eclipse.tracecompass.tmf.core.event.aspect.TmfCpuAspect;
+import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils;
+
+/**
+ * Provides the current task running on a CPU according to scheduling events
+ *
+ * @author Francis Giraldeau
+ * @author Geneviève Bastien
+ */
+public class TraceEventHandlerSched extends BaseHandler {
+
+ /**
+ * Constructor
+ *
+ * @param provider
+ * The parent graph provider
+ */
+ public TraceEventHandlerSched(LttngKernelExecGraphProvider provider) {
+ super(provider);
+ }
+
+ @Override
+ public void handleEvent(ITmfEvent ev) {
+ String eventName = ev.getName();
+ LttngEventLayout eventLayout = getProvider().getEventLayout();
+
+ if (eventName.equals(eventLayout.eventSchedSwitch())) {
+ handleSchedSwitch(ev);
+ } else if (eventName.equals(eventLayout.eventSchedProcessTTWU())) {
+ if (traceHasEventSchedTTWU(ev.getTrace())) {
+ handleSchedWakeup(ev);
+ }
+ } else if (eventName.equals(eventLayout.eventSchedProcessWakeup())) {
+ if (!traceHasEventSchedTTWU(ev.getTrace())) {
+ handleSchedWakeup(ev);
+ }
+ } else if (eventName.equals(eventLayout.eventSchedProcessWakeupNew())) {
+ if (!traceHasEventSchedTTWU(ev.getTrace())) {
+ handleSchedWakeup(ev);
+ }
+ } else if (eventName.equals(eventLayout.eventSchedProcessFork())) {
+ handleSchedProcessFork(ev);
+ } else if (eventName.equals(eventLayout.eventSchedProcessExit())) {
+ handleSchedProcessExit(ev);
+ } else if (eventName.equals(eventLayout.eventSchedProcessExec())) {
+ handleSchedProcessExec(ev);
+ }
+ }
+
+ private void handleSchedSwitch(ITmfEvent event) {
+ Object cpuObj = TmfTraceUtils.resolveEventAspectOfClassForEvent(event.getTrace(), TmfCpuAspect.class, event);
+ if (cpuObj == null) {
+ throw new NullPointerException();
+ }
+ Integer cpu = (Integer) cpuObj;
+ LttngEventLayout eventLayout = getProvider().getEventLayout();
+ LttngSystemModel system = getProvider().getSystem();
+
+ Integer next = EventField.getInt(event, eventLayout.fieldNextTid());
+ Integer prev = EventField.getInt(event, eventLayout.fieldPrevTid());
+ long ts = event.getTimestamp().getValue();
+ long prev_state = EventField.getLong(event, eventLayout.fieldPrevState());
+ prev_state = (long) ((int) prev_state) & (LinuxValues.TASK_STATE_RUNNING | LinuxValues.TASK_INTERRUPTIBLE | LinuxValues.TASK_UNINTERRUPTIBLE);
+ String host = event.getTrace().getHostId();
+
+ system.cacheTidOnCpu(cpu, new HostThread(event.getTrace().getHostId(), next));
+
+ HostThread nextHt = new HostThread(host, next);
+ LttngWorker nextTask = system.findWorker(nextHt);
+ if (nextTask == null) {
+ String name = EventField.getOrDefault(event, eventLayout.fieldNextComm(), NonNullUtils.checkNotNull(Messages.TraceEventHandlerSched_UnknownThreadName));
+ nextTask = new LttngWorker(nextHt, name, ts);
+ system.addWorker(nextTask);
+ }
+ nextTask.setStatus(ProcessStatus.RUN);
+
+ HostThread prevHt = new HostThread(host, prev);
+ LttngWorker prevTask = system.findWorker(prevHt);
+ if (prevTask == null) {
+ String name = EventField.getOrDefault(event, eventLayout.fieldPrevComm(), NonNullUtils.checkNotNull(Messages.TraceEventHandlerSched_UnknownThreadName));
+ prevTask = new LttngWorker(prevHt, name, ts);
+ system.addWorker(prevTask);
+ }
+ /* prev_state == 0 means runnable, thus waits for cpu */
+ if (prev_state == 0) {
+ prevTask.setStatus(ProcessStatus.WAIT_CPU);
+ } else {
+ prevTask.setStatus(ProcessStatus.WAIT_BLOCKED);
+ }
+ }
+
+ private void handleSchedProcessFork(ITmfEvent event) {
+ String host = event.getTrace().getHostId();
+ LttngEventLayout eventLayout = getProvider().getEventLayout();
+ LttngSystemModel system = getProvider().getSystem();
+
+ Integer childTid = EventField.getInt(event, eventLayout.fieldChildTid());
+ String name = EventField.getString(event, eventLayout.fieldChildComm());
+ long ts = event.getTimestamp().getValue();
+
+ HostThread childHt = new HostThread(host, childTid);
+
+ LttngWorker childTask = system.findWorker(childHt);
+ if (childTask == null) {
+ childTask = new LttngWorker(childHt, name, ts);
+ system.addWorker(childTask);
+ }
+
+ childTask.setStatus(ProcessStatus.WAIT_FORK);
+ }
+
+ private void handleSchedWakeup(ITmfEvent event) {
+ String host = event.getTrace().getHostId();
+ Object cpuObj = TmfTraceUtils.resolveEventAspectOfClassForEvent(event.getTrace(), TmfCpuAspect.class, event);
+ if (cpuObj == null) {
+ throw new NullPointerException();
+ }
+ Integer cpu = (Integer) cpuObj;
+ LttngEventLayout eventLayout = getProvider().getEventLayout();
+ LttngSystemModel system = getProvider().getSystem();
+
+ Integer tid = EventField.getInt(event, eventLayout.fieldTid());
+ HostThread targetHt = new HostThread(host, tid);
+
+ LttngWorker target = system.findWorker(targetHt);
+ LttngWorker current = system.getWorkerOnCpu(host, cpu);
+ if (target == null) {
+ String name = EventField.getOrDefault(event, eventLayout.fieldComm(), NonNullUtils.checkNotNull(Messages.TraceEventHandlerSched_UnknownThreadName));
+ target = new LttngWorker(targetHt, name, event.getTimestamp().getValue());
+ system.addWorker(target);
+ target.setStatus(ProcessStatus.WAIT_BLOCKED);
+ }
+ // spurious wakeup
+ ProcessStatus status = target.getStatus();
+ if ((current != null && target.getHostThread().equals(current.getHostThread())) ||
+ status == ProcessStatus.WAIT_CPU) {
+ return;
+ }
+ if (status == ProcessStatus.WAIT_BLOCKED ||
+ status == ProcessStatus.WAIT_FORK ||
+ status == ProcessStatus.UNKNOWN) {
+ target.setStatus(ProcessStatus.WAIT_CPU);
+ return;
+ }
+ }
+
+ private void handleSchedProcessExit(ITmfEvent event) {
+ String host = event.getTrace().getHostId();
+ LttngEventLayout eventLayout = getProvider().getEventLayout();
+ LttngSystemModel system = getProvider().getSystem();
+
+ Integer tid = EventField.getInt(event, eventLayout.fieldTid());
+ LttngWorker task = system.findWorker(new HostThread(host, tid));
+ if (task == null) {
+ return;
+ }
+ task.setStatus(ProcessStatus.EXIT);
+ }
+
+ private void handleSchedProcessExec(ITmfEvent event) {
+ String host = event.getTrace().getHostId();
+ Object cpuObj = TmfTraceUtils.resolveEventAspectOfClassForEvent(event.getTrace(), TmfCpuAspect.class, event);
+ if (cpuObj == null) {
+ throw new NullPointerException();
+ }
+ Integer cpu = (Integer) cpuObj;
+ LttngEventLayout eventLayout = getProvider().getEventLayout();
+ LttngSystemModel system = getProvider().getSystem();
+
+ String filename = EventField.getString(event, eventLayout.fieldFilename());
+ LttngWorker task = system.getWorkerOnCpu(host, cpu);
+ if (task == null) {
+ return;
+ }
+ task.setName(filename);
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 École Polytechnique de Montréal
+ *
+ * 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
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.graph.handlers;
+
+import org.eclipse.tracecompass.analysis.os.linux.core.model.HostThread;
+import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.graph.building.LttngKernelExecGraphProvider;
+import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.graph.building.LttngKernelExecGraphProvider.ProcessStatus;
+import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.graph.model.EventField;
+import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.graph.model.LttngSystemModel;
+import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.graph.model.LttngWorker;
+import org.eclipse.tracecompass.internal.lttng2.kernel.core.trace.layout.LttngEventLayout;
+import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
+
+/**
+ * Handles the LTTng statedump events necessary for the initialization of the
+ * system model
+ *
+ * @author Francis Giraldeau
+ */
+public class TraceEventHandlerStatedump extends BaseHandler {
+
+ /**
+ * Constructor
+ *
+ * @param provider
+ * The parent graph provider
+ */
+ public TraceEventHandlerStatedump(LttngKernelExecGraphProvider provider) {
+ super(provider);
+ }
+
+ @Override
+ public void handleEvent(ITmfEvent event) {
+ LttngEventLayout eventLayout = getProvider().getEventLayout();
+ LttngSystemModel system = getProvider().getSystem();
+ String eventName = event.getName();
+ if (!eventName.equals(eventLayout.eventStatedumpProcessState())) {
+ return;
+ }
+
+ Integer tid = EventField.getInt(event, eventLayout.fieldTid());
+ String name = EventField.getOrDefault(event, eventLayout.fieldName(), Messages.TraceEventHandlerSched_UnknownThreadName);
+ Integer status = EventField.getInt(event, eventLayout.fieldStatus());
+
+ String host = event.getTrace().getHostId();
+ long ts = event.getTimestamp().getValue();
+
+ HostThread ht = new HostThread(host, tid);
+ LttngWorker task = system.findWorker(ht);
+ if (task == null) {
+ task = new LttngWorker(ht, name, ts);
+ system.addWorker(task);
+ } else {
+ task.setName(name);
+ }
+
+ task.setStatus(ProcessStatus.getStatus(status));
+ }
+
+}
--- /dev/null
+###############################################################################
+# Copyright (c) 2015 Ecole Polytechnique de Montreal
+#
+# 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
+###############################################################################
+
+TraceEventHandlerSched_UnknownThreadName=unknown
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 École Polytechnique de Montréal
+ *
+ * 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
+ *******************************************************************************/
+
+@org.eclipse.jdt.annotation.NonNullByDefault
+package org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.graph.handlers;
\ No newline at end of file
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 École Polytechnique de Montréal
+ *
+ * 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
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.graph.model;
+
+import org.eclipse.tracecompass.common.core.NonNullUtils;
+import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
+import org.eclipse.tracecompass.tmf.core.event.ITmfEventField;
+
+/**
+ * Type casting for getting field values
+ *
+ * @author Francis Giraldeau
+ * @author Geneviève Bastien
+ */
+public class EventField {
+
+ /**
+ * Get int field
+ *
+ * @param event
+ * the event
+ * @param name
+ * the field name
+ * @return the long value
+ */
+ public static Integer getInt(ITmfEvent event, String name) {
+ ITmfEventField field = NonNullUtils.checkNotNull(event.getContent().getField(name));
+ Object value = field.getValue();
+ if (value instanceof Long) {
+ return NonNullUtils.checkNotNull(((Long) value).intValue());
+ }
+ return NonNullUtils.checkNotNull((Integer) value);
+ }
+
+ /**
+ * Get long field
+ *
+ * @param event
+ * the event
+ * @param name
+ * the field name
+ * @return the long value
+ */
+ public static Long getLong(ITmfEvent event, String name) {
+ ITmfEventField field = NonNullUtils.checkNotNull(event.getContent().getField(name));
+ return NonNullUtils.checkNotNull((Long) field.getValue());
+ }
+
+ /**
+ * Get string field
+ *
+ * @param event
+ * the event
+ * @param name
+ * the field name
+ * @return the string value
+ */
+ public static String getString(ITmfEvent event, String name) {
+ ITmfEventField field = NonNullUtils.checkNotNull(event.getContent().getField(name));
+ return NonNullUtils.checkNotNull((String) field.getValue());
+ }
+
+ /**
+ * Get float field
+ *
+ * @param event
+ * the event
+ * @param name
+ * the field name
+ * @return the float value
+ */
+ public static double getFloat(ITmfEvent event, String name) {
+ ITmfEventField field = NonNullUtils.checkNotNull(event.getContent().getField(name));
+ return NonNullUtils.checkNotNull((Double) field.getValue());
+ }
+
+ /**
+ * Get string field with default value
+ *
+ * @param event
+ * the event
+ * @param name
+ * the field name
+ * @param def
+ * the default value to return if the field does not exists
+ * @return the long value
+ */
+ public static String getOrDefault(ITmfEvent event, String name, String def) {
+ ITmfEventField field = event.getContent().getField(name);
+ if (field == null) {
+ return def;
+ }
+ return NonNullUtils.checkNotNull((String) field.getValue());
+ }
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 École Polytechnique de Montréal
+ *
+ * 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
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.graph.model;
+
+import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.graph.building.LttngKernelExecGraphProvider.Context;
+import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
+import org.eclipse.tracecompass.tmf.core.event.TmfEvent;
+import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestamp;
+import org.eclipse.tracecompass.tmf.core.trace.ITmfContext;
+
+/**
+ * A class representing an interrupt context in the kernel. It associates the
+ * reason of the context with an event.
+ *
+ * @author Francis Giraldeau
+ * @author Geneviève Bastien
+ */
+public class LttngInterruptContext {
+
+ /**
+ * The default context when none is defined
+ */
+ public static final LttngInterruptContext DEFAULT_CONTEXT = new LttngInterruptContext(new TmfEvent(null, ITmfContext.UNKNOWN_RANK, TmfTimestamp.BIG_BANG, null, null), Context.NONE);
+
+ private final ITmfEvent fEvent;
+ private final Context fContext;
+
+ /**
+ * Constructor
+ *
+ * @param event
+ * The event representing the start of this interrupt context
+ * @param ctx
+ * The context type
+ */
+ public LttngInterruptContext(ITmfEvent event, Context ctx) {
+ fEvent = event;
+ fContext = ctx;
+ }
+
+ /**
+ * The event associated with this interrupt context
+ *
+ * @return The event marking the entry in this interrupt context
+ */
+ public ITmfEvent getEvent() {
+ return fEvent;
+ }
+
+ /**
+ * Get the type of interrupt context this context represents
+ *
+ * @return The type of interrupt context
+ */
+ public Context getContext() {
+ return fContext;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 École Polytechnique de Montréal
+ *
+ * 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
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.graph.model;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Stack;
+
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.analysis.os.linux.core.model.HostThread;
+import org.eclipse.tracecompass.common.core.NonNullUtils;
+
+import com.google.common.collect.HashBasedTable;
+import com.google.common.collect.Table;
+
+/**
+ * This class contains the model of a Linux system
+ *
+ * TODO: This model is custom made for the LTTng dependency analysis for ease of
+ * development of the feature, but most of it and the classes it uses also apply
+ * to any Linux OS trace, so the classes in this package should be moved to
+ * analysis.os.linux
+ *
+ * @author Francis Giraldeau
+ * @author Geneviève Bastien
+ */
+public class LttngSystemModel {
+
+ private final Table<String, Integer, HostThread> fCurrentTids = NonNullUtils.checkNotNull(HashBasedTable.<String, Integer, HostThread> create());
+ private final Table<String, Integer, Stack<LttngInterruptContext>> fIntCtxStacks = NonNullUtils.checkNotNull(HashBasedTable.<String, Integer, Stack<LttngInterruptContext>> create());
+ private final Map<HostThread, LttngWorker> fWorkerMap = new HashMap<>();
+
+ /**
+ * Cache the TID currently on the CPU of a host, for easier access later on
+ *
+ * @param cpu
+ * The CPU ID
+ * @param ht
+ * The {@link HostThread} object that is running on this CPU
+ */
+ public void cacheTidOnCpu(Integer cpu, HostThread ht) {
+ fCurrentTids.put(ht.getHost(), cpu, ht);
+ }
+
+ /**
+ * Get the {@link LttngWorker} object that is currently running on the CPU
+ * of a host
+ *
+ * @param host
+ * The identifier of the trace/machine of the CPU
+ * @param cpu
+ * The CPU ID on which the worker is running
+ * @return The {@link LttngWorker} running on the CPU
+ */
+ public @Nullable LttngWorker getWorkerOnCpu(String host, Integer cpu) {
+ HostThread ht = fCurrentTids.get(host, cpu);
+ if (ht == null) {
+ return null;
+ }
+ return findWorker(ht);
+ }
+
+ /**
+ * Return the worker associated with this host TID
+ *
+ * @param ht
+ * The host thread associated with a worker
+ * @return The {@link LttngWorker} associated with a host thread
+ */
+ public @Nullable LttngWorker findWorker(HostThread ht) {
+ return fWorkerMap.get(ht);
+ }
+
+ /**
+ * Add a new worker to the system
+ *
+ * @param worker
+ * The worker to add
+ */
+ public void addWorker(LttngWorker worker) {
+ fWorkerMap.put(worker.getHostThread(), worker);
+ }
+
+ /**
+ * Get the list of workers on this system
+ *
+ * @return The list of workers on the system
+ */
+ public Collection<LttngWorker> getWorkers() {
+ return NonNullUtils.checkNotNull(fWorkerMap.values());
+ }
+
+ /**
+ * Pushes an interrupt context on the stack for a CPU on a host
+ *
+ * @param hostId
+ * The host ID of the trace/machine the interrupt context belongs
+ * to
+ * @param cpu
+ * The CPU this interrupt happened on
+ * @param interruptCtx
+ * The interrupt context to push on the stack
+ */
+ public void pushContextStack(String hostId, Integer cpu, LttngInterruptContext interruptCtx) {
+ Stack<LttngInterruptContext> stack = fIntCtxStacks.get(hostId, cpu);
+ if (stack == null) {
+ stack = new Stack<>();
+ fIntCtxStacks.put(hostId, cpu, stack);
+ }
+ stack.push(interruptCtx);
+ }
+
+ /**
+ * Peeks the top of the interrupt context stack for a CPU on a host, to see
+ * what is the latest context.
+ *
+ * @param hostId
+ * The host ID of the trace/machine the interrupt context belongs
+ * to
+ * @param cpu
+ * The CPU this interrupt happened on
+ * @return The latest interrupt context on the CPU of the host
+ */
+ public LttngInterruptContext peekContextStack(String hostId, Integer cpu) {
+ Stack<LttngInterruptContext> stack = fIntCtxStacks.get(hostId, cpu);
+ if (stack == null) {
+ return LttngInterruptContext.DEFAULT_CONTEXT;
+ }
+ if (stack.empty()) {
+ return LttngInterruptContext.DEFAULT_CONTEXT;
+ }
+ LttngInterruptContext peek = stack.peek();
+ if (peek == null) {
+ peek = LttngInterruptContext.DEFAULT_CONTEXT;
+ }
+ return peek;
+ }
+
+ /**
+ * Removes the top of the interrupt context stack for a CPU on a host and
+ * returns the result
+ *
+ * @param hostId
+ * The host ID of the trace/machine the interrupt context belongs
+ * to
+ * @param cpu
+ * The CPU this interrupt happened on
+ * @return The latest interrupt context on the CPU of the host
+ */
+ public @Nullable LttngInterruptContext popContextStack(String hostId, Integer cpu) {
+ Stack<LttngInterruptContext> stack = fIntCtxStacks.get(hostId, cpu);
+ if (stack == null) {
+ return null;
+ }
+ if (stack.empty()) {
+ return null;
+ }
+ return stack.pop();
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 École Polytechnique de Montréal
+ *
+ * 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
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.graph.model;
+
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.analysis.graph.core.base.IGraphWorker;
+import org.eclipse.tracecompass.analysis.os.linux.core.model.HostThread;
+import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.graph.building.LttngKernelExecGraphProvider.ProcessStatus;
+
+/**
+ * This class represents the worker unit from the execution graph
+ *
+ * TODO: See if this class could be integrated inside HostThread instead.
+ *
+ * @author Geneviève Bastien
+ */
+public class LttngWorker implements IGraphWorker {
+
+ private final HostThread fHostTid;
+ private final long fStart;
+
+ private String fThreadName;
+ private ProcessStatus fStatus = ProcessStatus.UNKNOWN;
+ private ProcessStatus fOldStatus = ProcessStatus.UNKNOWN;
+
+ /**
+ * Constructor
+ *
+ * @param ht
+ * The host thread represented by this worker
+ * @param name
+ * The name of this thread
+ * @param ts
+ * The timestamp
+ */
+ public LttngWorker(HostThread ht, String name, long ts) {
+ fHostTid = ht;
+ fThreadName = name;
+ fStart = ts;
+ }
+
+ @Override
+ public String getHostId() {
+ return fHostTid.getHost();
+ }
+
+ /**
+ * Set the name of this worker
+ *
+ * @param name The name of this worker
+ */
+ public void setName(String name) {
+ fThreadName = name;
+ }
+
+ /**
+ * Get the name of this worker
+ *
+ * @return The name of the worker
+ */
+ public String getName() {
+ return fThreadName;
+ }
+
+ /**
+ * Set the status, saving the old value that can still be accessed using {@link LttngWorker#getOldStatus()}
+ *
+ * @param status The new status of this
+ */
+ public void setStatus(ProcessStatus status) {
+ fOldStatus = fStatus;
+ fStatus = status;
+ }
+
+ /**
+ * Get the status of this thread
+ *
+ * @return The thread status
+ */
+ public ProcessStatus getStatus() {
+ return fStatus;
+ }
+
+ /**
+ * Return the previous status this worker was in
+ *
+ * @return The previous status of this worker
+ */
+ public ProcessStatus getOldStatus() {
+ return fOldStatus;
+ }
+
+ /**
+ * Get the host thread associated with this worker
+ *
+ * @return The {@link HostThread} associated with this worker
+ */
+ public HostThread getHostThread() {
+ return fHostTid;
+ }
+
+ /**
+ * Get the start time of this worker
+ *
+ * @return The start time in nanoseconds
+ */
+ public long getStart() {
+ return fStart;
+ }
+
+ @Override
+ public boolean equals(@Nullable Object obj) {
+ if (obj instanceof LttngWorker) {
+ return getHostThread().equals(((LttngWorker) obj).getHostThread());
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return fHostTid.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return '[' + fThreadName + ',' + fHostTid.getTid() + ']';
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 École Polytechnique de Montréal
+ *
+ * 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
+ *******************************************************************************/
+
+@org.eclipse.jdt.annotation.NonNullByDefault
+package org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.graph.model;
\ No newline at end of file
version="0.0.0"
unpack="false"/>
+ <plugin
+ id="org.eclipse.tracecompass.analysis.graph.core"
+ download-size="0"
+ install-size="0"
+ version="0.0.0"
+ unpack="false"/>
+
</feature>