[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
1 /*******************************************************************************
2 * Copyright (c) 2016 EfficiOS Inc., Alexandre Montplaisir
3 *
4 * All rights reserved. This program and the accompanying materials are
5 * made available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
8 *******************************************************************************/
9
10 package org.eclipse.tracecompass.internal.analysis.os.linux.core.views.controlflow2;
11
12 import static org.eclipse.tracecompass.common.core.NonNullUtils.nullToEmptyString;
13
14 import java.util.Collections;
15 import java.util.Comparator;
16 import java.util.List;
17 import java.util.Map;
18 import java.util.Set;
19 import java.util.function.Function;
20 import java.util.function.Supplier;
21 import java.util.stream.Collectors;
22 import java.util.stream.Stream;
23
24 import org.eclipse.jdt.annotation.Nullable;
25 import org.eclipse.tracecompass.analysis.os.linux.core.kernel.KernelAnalysisModule;
26 import org.eclipse.tracecompass.analysis.os.linux.core.kernel.StateValues;
27 import org.eclipse.tracecompass.internal.analysis.os.linux.core.kernel.Attributes;
28 import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.ColorDefinition;
29 import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.TimeGraphTreeElement;
30 import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.TimeGraphTreeRender;
31 import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.TimeGraphStateInterval.LineThickness;
32 import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.statesystem.StateSystemModelRenderProvider;
33 import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem;
34 import org.eclipse.tracecompass.statesystem.core.StateSystemUtils;
35 import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException;
36 import org.eclipse.tracecompass.statesystem.core.exceptions.StateValueTypeException;
37 import org.eclipse.tracecompass.statesystem.core.interval.ITmfStateInterval;
38 import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue;
39 import org.eclipse.tracecompass.statesystem.core.statevalue.TmfStateValue;
40
41 import com.google.common.annotations.VisibleForTesting;
42 import com.google.common.collect.ImmutableList;
43 import com.google.common.collect.ImmutableSet;
44
45 public class ControlFlowRenderProvider extends StateSystemModelRenderProvider {
46
47 private static final List<SortingMode> SORTING_MODES = ImmutableList.of(
48 ControlFlowConfigModes.SORTING_BY_TID,
49 ControlFlowConfigModes.SORTING_BY_THREAD_NAME);
50
51 private static final List<FilterMode> FILTER_MODES = ImmutableList.of(
52 ControlFlowConfigModes.FILTERING_INACTIVE_ENTRIES);
53
54 /**
55 * State values that are considered inactive, for purposes of filtering out
56 * when the "filter inactive entries" mode is enabled.
57 */
58 private static final Set<ITmfStateValue> INACTIVE_STATE_VALUES = ImmutableSet.of(
59 TmfStateValue.nullValue(),
60 StateValues.PROCESS_STATUS_UNKNOWN_VALUE,
61 StateValues.PROCESS_STATUS_WAIT_UNKNOWN_VALUE,
62 StateValues.PROCESS_STATUS_WAIT_BLOCKED_VALUE
63 );
64
65 /**
66 * Each "Thread" attribute has the following children:
67 *
68 * <ul>
69 * <li>Prio</li>
70 * <li>System_call</li>
71 * <li>Exec_name</li>
72 * <li>PPID</li>
73 * </ul>
74 *
75 * The "Thread" is considered the base quark.
76 */
77 private static final String[] BASE_QUARK_PATTERN = { Attributes.THREADS, "*" }; //$NON-NLS-1$
78
79 /**
80 * Get the tree element name for every thread. It consists of the TID
81 * followed by the first available exec_name for this thread.
82 *
83 * FIXME This implies a static tree definition for every TID, which does not
84 * handle TID re-use correctly. The state system structure should be updated
85 * accordingly.
86 */
87 @VisibleForTesting
88 public static final Function<TreeRenderContext, TimeGraphTreeRender> SS_TO_TREE_RENDER_FUNCTION = (treeContext) -> {
89 ITmfStateSystem ss = treeContext.ss;
90 List<ITmfStateInterval> fullState = treeContext.fullQueryAtRangeStart;
91
92 Stream<ControlFlowTreeElement> treeElems = ss.getQuarks(BASE_QUARK_PATTERN).stream()
93 .map(baseQuark -> {
94 String tid = ss.getAttributeName(baseQuark);
95
96 String threadName;
97 try {
98 int execNameQuark = ss.getQuarkRelative(baseQuark, Attributes.EXEC_NAME);
99 // TODO We should look starting at treeContext.renderTimeRangeStart
100 // first, and if we don't find anything use ss.getStartTime(), so that
101 // we catch subsequent process name changes
102 ITmfStateInterval firstInterval = StateSystemUtils.queryUntilNonNullValue(ss,
103 execNameQuark, ss.getStartTime(), Long.MAX_VALUE);
104 if (firstInterval == null) {
105 threadName = null;
106 } else {
107 threadName = firstInterval.getStateValue().unboxStr();
108 }
109 } catch (AttributeNotFoundException | StateValueTypeException e) {
110 threadName = null;
111 }
112
113 return new ControlFlowTreeElement(tid, threadName, Collections.emptyList(), baseQuark);
114 });
115
116 /* Run the entries through the active filter modes */
117 Set<FilterMode> filterModes = treeContext.filterModes;
118 if (filterModes.contains(ControlFlowConfigModes.FILTERING_INACTIVE_ENTRIES)) {
119 /*
120 * Filter out the tree elements whose state is considered inactive
121 * for the whole duration of the configured time range.
122 */
123 treeElems = treeElems.filter(elem -> {
124 ITmfStateInterval interval = fullState.get(elem.getSourceQuark());
125 if (interval.getEndTime() > treeContext.renderTimeRangeEnd &&
126 INACTIVE_STATE_VALUES.contains(interval.getStateValue())) {
127 return false;
128 }
129 return true;
130 });
131 }
132
133 /* Sort entries according to the active sorting mode */
134 SortingMode sortingMode = treeContext.sortingMode;
135 if (sortingMode == ControlFlowConfigModes.SORTING_BY_TID) {
136 treeElems = treeElems.sorted(Comparator.comparingInt(ControlFlowTreeElement::getTid));
137 } else if (sortingMode == ControlFlowConfigModes.SORTING_BY_THREAD_NAME) {
138 treeElems = treeElems.sorted((elem1, elem2) -> {
139 return elem1.getThreadName().compareToIgnoreCase(elem2.getThreadName());
140 });
141 }
142
143 List<TimeGraphTreeElement> treeElemsList = treeElems.collect(Collectors.toList());
144 return new TimeGraphTreeRender(treeElemsList);
145 };
146
147
148
149 /**
150 * Function mapping state names
151 *
152 * @param value
153 * State value representing the state
154 * @return The state name to display, should be localized
155 */
156 @VisibleForTesting
157 public static String mapStateValueToStateName(int value) {
158 try {
159 switch (value) {
160 case StateValues.PROCESS_STATUS_WAIT_UNKNOWN:
161 return nullToEmptyString(Messages.ControlFlowRenderProvider_State_WaitUnknown);
162 case StateValues.PROCESS_STATUS_WAIT_BLOCKED:
163 return nullToEmptyString(Messages.ControlFlowRenderProvider_State_WaitBlocked);
164 case StateValues.PROCESS_STATUS_WAIT_FOR_CPU:
165 return nullToEmptyString(Messages.ControlFlowRenderProvider_State_WaitForCpu);
166 case StateValues.PROCESS_STATUS_RUN_USERMODE:
167 return nullToEmptyString(Messages.ControlFlowRenderProvider_State_UserMode);
168 case StateValues.PROCESS_STATUS_RUN_SYSCALL:
169 return nullToEmptyString(Messages.ControlFlowRenderProvider_State_Syscall);
170 case StateValues.PROCESS_STATUS_INTERRUPTED:
171 return nullToEmptyString(Messages.ControlFlowRenderProvider_State_Interrupted);
172 default:
173 return nullToEmptyString(Messages.ControlFlowRenderProvider_State_Unknown);
174 }
175
176 } catch (StateValueTypeException e) {
177 return nullToEmptyString(Messages.ControlFlowRenderProvider_State_Unknown);
178 }
179 }
180
181 private static final Function<StateIntervalContext, String> STATE_NAME_MAPPING_FUNCTION = ssCtx -> {
182 int statusQuark = ssCtx.baseTreeElement.getSourceQuark();
183 ITmfStateValue val = ssCtx.fullQueryAtIntervalStart.get(statusQuark).getStateValue();
184 int status = val.unboxInt();
185 return mapStateValueToStateName(status);
186 };
187
188
189 private static final ColorDefinition NO_COLOR = new ColorDefinition( 0, 0, 0, 0);
190 private static final ColorDefinition COLOR_UNKNOWN = new ColorDefinition(100, 100, 100);
191 private static final ColorDefinition COLOR_WAIT_UNKNOWN = new ColorDefinition(200, 200, 200);
192 private static final ColorDefinition COLOR_WAIT_BLOCKED = new ColorDefinition(200, 200, 0);
193 private static final ColorDefinition COLOR_WAIT_FOR_CPU = new ColorDefinition(200, 100, 0);
194 private static final ColorDefinition COLOR_USERMODE = new ColorDefinition( 0, 200, 0);
195 private static final ColorDefinition COLOR_SYSCALL = new ColorDefinition( 0, 0, 200);
196 private static final ColorDefinition COLOR_INTERRUPTED = new ColorDefinition(200, 0, 100);
197
198 private static final Function<StateIntervalContext, ColorDefinition> COLOR_MAPPING_FUNCTION = ssCtx -> {
199 try {
200 int statusQuark = ssCtx.baseTreeElement.getSourceQuark();
201 ITmfStateValue val = ssCtx.fullQueryAtIntervalStart.get(statusQuark).getStateValue();
202
203 if (val.isNull()) {
204 return NO_COLOR;
205 }
206
207 int status = val.unboxInt();
208 switch (status) {
209 case StateValues.PROCESS_STATUS_WAIT_UNKNOWN:
210 return COLOR_WAIT_UNKNOWN;
211 case StateValues.PROCESS_STATUS_WAIT_BLOCKED:
212 return COLOR_WAIT_BLOCKED;
213 case StateValues.PROCESS_STATUS_WAIT_FOR_CPU:
214 return COLOR_WAIT_FOR_CPU;
215 case StateValues.PROCESS_STATUS_RUN_USERMODE:
216 return COLOR_USERMODE;
217 case StateValues.PROCESS_STATUS_RUN_SYSCALL:
218 return COLOR_SYSCALL;
219 case StateValues.PROCESS_STATUS_INTERRUPTED:
220 return COLOR_INTERRUPTED;
221 default:
222 return COLOR_UNKNOWN;
223 }
224
225 } catch (StateValueTypeException e) {
226 return COLOR_UNKNOWN;
227 }
228 };
229
230 /* No variation for now */
231 private static final Function<StateIntervalContext, LineThickness> LINE_THICKNESS_MAPPING_FUNCTION = ssCtx -> {
232 // int statusQuark = ssCtx.baseTreeElement.getSourceQuark();
233 // ITmfStateValue val = ssCtx.fullQueryAtIntervalStart.get(statusQuark).getStateValue();
234 //
235 // // For demo purposes only!
236 // if (val.equals(StateValues.PROCESS_STATUS_RUN_SYSCALL_VALUE)) {
237 // return LineThickness.SMALL;
238 // }
239
240 return LineThickness.NORMAL;
241 };
242
243 // TODO
244 private static final Function<StateIntervalContext, @Nullable Supplier<Map<String, String>>> PROPERTY_MAPPING_FUNCTION = ssCtx -> {
245 return null;
246 };
247
248 /**
249 * Constructor
250 */
251 public ControlFlowRenderProvider() {
252 super(SORTING_MODES,
253 FILTER_MODES,
254 /* Parameters specific to state system render providers */
255 KernelAnalysisModule.ID,
256 SS_TO_TREE_RENDER_FUNCTION,
257 STATE_NAME_MAPPING_FUNCTION,
258 COLOR_MAPPING_FUNCTION,
259 LINE_THICKNESS_MAPPING_FUNCTION,
260 PROPERTY_MAPPING_FUNCTION);
261
262 enableFilterMode(0);
263 }
264 }
This page took 0.0371 seconds and 5 git commands to generate.