[WIP] CFV Refactor
[deliverable/tracecompass.git] / analysis / org.eclipse.tracecompass.analysis.os.linux.core / src / org / eclipse / tracecompass / internal / analysis / os / linux / core / views / controlflow2 / ControlFlowRenderProvider.java
diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/internal/analysis/os/linux/core/views/controlflow2/ControlFlowRenderProvider.java b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/internal/analysis/os/linux/core/views/controlflow2/ControlFlowRenderProvider.java
new file mode 100644 (file)
index 0000000..c8447ec
--- /dev/null
@@ -0,0 +1,264 @@
+/*******************************************************************************
+ * Copyright (c) 2016 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.views.controlflow2;
+
+import static org.eclipse.tracecompass.common.core.NonNullUtils.nullToEmptyString;
+
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.analysis.os.linux.core.kernel.KernelAnalysisModule;
+import org.eclipse.tracecompass.analysis.os.linux.core.kernel.StateValues;
+import org.eclipse.tracecompass.internal.analysis.os.linux.core.kernel.Attributes;
+import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.ColorDefinition;
+import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.TimeGraphTreeElement;
+import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.TimeGraphTreeRender;
+import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.TimeGraphStateInterval.LineThickness;
+import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.statesystem.StateSystemModelRenderProvider;
+import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem;
+import org.eclipse.tracecompass.statesystem.core.StateSystemUtils;
+import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException;
+import org.eclipse.tracecompass.statesystem.core.exceptions.StateValueTypeException;
+import org.eclipse.tracecompass.statesystem.core.interval.ITmfStateInterval;
+import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue;
+import org.eclipse.tracecompass.statesystem.core.statevalue.TmfStateValue;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+
+public class ControlFlowRenderProvider extends StateSystemModelRenderProvider {
+
+    private static final List<SortingMode> SORTING_MODES = ImmutableList.of(
+            ControlFlowConfigModes.SORTING_BY_TID,
+            ControlFlowConfigModes.SORTING_BY_THREAD_NAME);
+
+    private static final List<FilterMode> FILTER_MODES = ImmutableList.of(
+            ControlFlowConfigModes.FILTERING_INACTIVE_ENTRIES);
+
+    /**
+     * State values that are considered inactive, for purposes of filtering out
+     * when the "filter inactive entries" mode is enabled.
+     */
+    private static final Set<ITmfStateValue> INACTIVE_STATE_VALUES = ImmutableSet.of(
+            TmfStateValue.nullValue(),
+            StateValues.PROCESS_STATUS_UNKNOWN_VALUE,
+            StateValues.PROCESS_STATUS_WAIT_UNKNOWN_VALUE,
+            StateValues.PROCESS_STATUS_WAIT_BLOCKED_VALUE
+            );
+
+    /**
+     * Each "Thread" attribute has the following children:
+     *
+     * <ul>
+     * <li>Prio</li>
+     * <li>System_call</li>
+     * <li>Exec_name</li>
+     * <li>PPID</li>
+     * </ul>
+     *
+     * The "Thread" is considered the base quark.
+     */
+    private static final String[] BASE_QUARK_PATTERN = { Attributes.THREADS, "*" }; //$NON-NLS-1$
+
+    /**
+     * Get the tree element name for every thread. It consists of the TID
+     * followed by the first available exec_name for this thread.
+     *
+     * FIXME This implies a static tree definition for every TID, which does not
+     * handle TID re-use correctly. The state system structure should be updated
+     * accordingly.
+     */
+    @VisibleForTesting
+    public static final Function<TreeRenderContext, TimeGraphTreeRender> SS_TO_TREE_RENDER_FUNCTION = (treeContext) -> {
+        ITmfStateSystem ss = treeContext.ss;
+        List<ITmfStateInterval> fullState = treeContext.fullQueryAtRangeStart;
+
+        Stream<ControlFlowTreeElement> treeElems = ss.getQuarks(BASE_QUARK_PATTERN).stream()
+                .map(baseQuark -> {
+                    String tid = ss.getAttributeName(baseQuark);
+
+                    String threadName;
+                    try {
+                        int execNameQuark = ss.getQuarkRelative(baseQuark, Attributes.EXEC_NAME);
+                        // TODO We should look starting at treeContext.renderTimeRangeStart
+                        // first, and if we don't find anything use ss.getStartTime(), so that
+                        // we catch subsequent process name changes
+                        ITmfStateInterval firstInterval = StateSystemUtils.queryUntilNonNullValue(ss,
+                                execNameQuark, ss.getStartTime(), Long.MAX_VALUE);
+                        if (firstInterval == null) {
+                            threadName = null;
+                        } else {
+                            threadName = firstInterval.getStateValue().unboxStr();
+                        }
+                    } catch (AttributeNotFoundException | StateValueTypeException e) {
+                        threadName = null;
+                    }
+
+                    return new ControlFlowTreeElement(tid, threadName, Collections.emptyList(), baseQuark);
+                });
+
+        /* Run the entries through the active filter modes */
+        Set<FilterMode> filterModes = treeContext.filterModes;
+        if (filterModes.contains(ControlFlowConfigModes.FILTERING_INACTIVE_ENTRIES)) {
+            /*
+             * Filter out the tree elements whose state is considered inactive
+             * for the whole duration of the configured time range.
+             */
+            treeElems = treeElems.filter(elem -> {
+                ITmfStateInterval interval = fullState.get(elem.getSourceQuark());
+                if (interval.getEndTime() > treeContext.renderTimeRangeEnd &&
+                        INACTIVE_STATE_VALUES.contains(interval.getStateValue())) {
+                    return false;
+                }
+                return true;
+            });
+        }
+
+        /* Sort entries according to the active sorting mode */
+        SortingMode sortingMode = treeContext.sortingMode;
+        if (sortingMode == ControlFlowConfigModes.SORTING_BY_TID) {
+            treeElems = treeElems.sorted(Comparator.comparingInt(ControlFlowTreeElement::getTid));
+        } else if (sortingMode == ControlFlowConfigModes.SORTING_BY_THREAD_NAME) {
+            treeElems = treeElems.sorted((elem1, elem2) -> {
+                return elem1.getThreadName().compareToIgnoreCase(elem2.getThreadName());
+            });
+        }
+
+        List<TimeGraphTreeElement> treeElemsList = treeElems.collect(Collectors.toList());
+        return new TimeGraphTreeRender(treeElemsList);
+    };
+
+
+
+    /**
+     * Function mapping state names
+     *
+     * @param value
+     *            State value representing the state
+     * @return The state name to display, should be localized
+     */
+    @VisibleForTesting
+    public static String mapStateValueToStateName(int value) {
+        try {
+            switch (value) {
+            case StateValues.PROCESS_STATUS_WAIT_UNKNOWN:
+                return nullToEmptyString(Messages.ControlFlowRenderProvider_State_WaitUnknown);
+            case StateValues.PROCESS_STATUS_WAIT_BLOCKED:
+                return nullToEmptyString(Messages.ControlFlowRenderProvider_State_WaitBlocked);
+            case StateValues.PROCESS_STATUS_WAIT_FOR_CPU:
+                return nullToEmptyString(Messages.ControlFlowRenderProvider_State_WaitForCpu);
+            case StateValues.PROCESS_STATUS_RUN_USERMODE:
+                return nullToEmptyString(Messages.ControlFlowRenderProvider_State_UserMode);
+            case StateValues.PROCESS_STATUS_RUN_SYSCALL:
+                return nullToEmptyString(Messages.ControlFlowRenderProvider_State_Syscall);
+            case StateValues.PROCESS_STATUS_INTERRUPTED:
+                return nullToEmptyString(Messages.ControlFlowRenderProvider_State_Interrupted);
+            default:
+                return nullToEmptyString(Messages.ControlFlowRenderProvider_State_Unknown);
+            }
+
+        } catch (StateValueTypeException e) {
+            return nullToEmptyString(Messages.ControlFlowRenderProvider_State_Unknown);
+        }
+    }
+
+    private static final Function<StateIntervalContext, String> STATE_NAME_MAPPING_FUNCTION = ssCtx -> {
+        int statusQuark = ssCtx.baseTreeElement.getSourceQuark();
+        ITmfStateValue val = ssCtx.fullQueryAtIntervalStart.get(statusQuark).getStateValue();
+        int status = val.unboxInt();
+        return mapStateValueToStateName(status);
+    };
+
+
+    private static final ColorDefinition NO_COLOR           = new ColorDefinition(  0,   0,   0,  0);
+    private static final ColorDefinition COLOR_UNKNOWN      = new ColorDefinition(100, 100, 100);
+    private static final ColorDefinition COLOR_WAIT_UNKNOWN = new ColorDefinition(200, 200, 200);
+    private static final ColorDefinition COLOR_WAIT_BLOCKED = new ColorDefinition(200, 200,   0);
+    private static final ColorDefinition COLOR_WAIT_FOR_CPU = new ColorDefinition(200, 100,   0);
+    private static final ColorDefinition COLOR_USERMODE     = new ColorDefinition(  0, 200,   0);
+    private static final ColorDefinition COLOR_SYSCALL      = new ColorDefinition(  0,   0, 200);
+    private static final ColorDefinition COLOR_INTERRUPTED  = new ColorDefinition(200,   0, 100);
+
+    private static final Function<StateIntervalContext, ColorDefinition> COLOR_MAPPING_FUNCTION = ssCtx -> {
+        try {
+            int statusQuark = ssCtx.baseTreeElement.getSourceQuark();
+            ITmfStateValue val = ssCtx.fullQueryAtIntervalStart.get(statusQuark).getStateValue();
+
+            if (val.isNull()) {
+                return NO_COLOR;
+            }
+
+            int status = val.unboxInt();
+            switch (status) {
+            case StateValues.PROCESS_STATUS_WAIT_UNKNOWN:
+                return COLOR_WAIT_UNKNOWN;
+            case StateValues.PROCESS_STATUS_WAIT_BLOCKED:
+                return COLOR_WAIT_BLOCKED;
+            case StateValues.PROCESS_STATUS_WAIT_FOR_CPU:
+                return COLOR_WAIT_FOR_CPU;
+            case StateValues.PROCESS_STATUS_RUN_USERMODE:
+                return COLOR_USERMODE;
+            case StateValues.PROCESS_STATUS_RUN_SYSCALL:
+                return COLOR_SYSCALL;
+            case StateValues.PROCESS_STATUS_INTERRUPTED:
+                return COLOR_INTERRUPTED;
+            default:
+                return COLOR_UNKNOWN;
+            }
+
+        } catch (StateValueTypeException e) {
+            return COLOR_UNKNOWN;
+        }
+    };
+
+    /* No variation for now */
+    private static final Function<StateIntervalContext, LineThickness> LINE_THICKNESS_MAPPING_FUNCTION = ssCtx -> {
+//        int statusQuark = ssCtx.baseTreeElement.getSourceQuark();
+//        ITmfStateValue val = ssCtx.fullQueryAtIntervalStart.get(statusQuark).getStateValue();
+//
+//        // For demo purposes only!
+//        if (val.equals(StateValues.PROCESS_STATUS_RUN_SYSCALL_VALUE)) {
+//            return LineThickness.SMALL;
+//        }
+
+        return LineThickness.NORMAL;
+    };
+
+    // TODO
+    private static final Function<StateIntervalContext, @Nullable Supplier<Map<String, String>>> PROPERTY_MAPPING_FUNCTION = ssCtx -> {
+        return null;
+    };
+
+    /**
+     * Constructor
+     */
+    public ControlFlowRenderProvider() {
+        super(SORTING_MODES,
+                FILTER_MODES,
+                /* Parameters specific to state system render providers */
+                KernelAnalysisModule.ID,
+                SS_TO_TREE_RENDER_FUNCTION,
+                STATE_NAME_MAPPING_FUNCTION,
+                COLOR_MAPPING_FUNCTION,
+                LINE_THICKNESS_MAPPING_FUNCTION,
+                PROPERTY_MAPPING_FUNCTION);
+
+        enableFilterMode(0);
+    }
+}
This page took 0.026397 seconds and 5 git commands to generate.