Import views plugins
[deliverable/tracecompass.git] / tmf / org.lttng.scope.tmf2.views.core / src / org / lttng / scope / tmf2 / views / core / timegraph / model / provider / statesystem / StateSystemModelStateProvider.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.lttng.scope.tmf2.views.core.timegraph.model.provider.statesystem;
11
12 import java.util.Collections;
13 import java.util.LinkedList;
14 import java.util.List;
15 import java.util.Map;
16 import java.util.concurrent.FutureTask;
17 import java.util.function.Function;
18
19 import org.eclipse.jdt.annotation.Nullable;
20 import org.eclipse.tracecompass.tmf.core.statesystem.TmfStateSystemAnalysisModule;
21 import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
22 import org.lttng.scope.tmf2.views.core.MathUtils;
23 import org.lttng.scope.tmf2.views.core.TimeRange;
24 import org.lttng.scope.tmf2.views.core.config.ConfigOption;
25 import org.lttng.scope.tmf2.views.core.timegraph.model.provider.states.TimeGraphModelStateProvider;
26 import org.lttng.scope.tmf2.views.core.timegraph.model.render.ColorDefinition;
27 import org.lttng.scope.tmf2.views.core.timegraph.model.render.LineThickness;
28 import org.lttng.scope.tmf2.views.core.timegraph.model.render.StateDefinition;
29 import org.lttng.scope.tmf2.views.core.timegraph.model.render.states.BasicTimeGraphStateInterval;
30 import org.lttng.scope.tmf2.views.core.timegraph.model.render.states.MultiStateInterval;
31 import org.lttng.scope.tmf2.views.core.timegraph.model.render.states.TimeGraphStateInterval;
32 import org.lttng.scope.tmf2.views.core.timegraph.model.render.states.TimeGraphStateRender;
33 import org.lttng.scope.tmf2.views.core.timegraph.model.render.tree.TimeGraphTreeElement;
34
35 import com.google.common.collect.Iterables;
36
37 import ca.polymtl.dorsal.libdelorean.ITmfStateSystem;
38 import ca.polymtl.dorsal.libdelorean.exceptions.AttributeNotFoundException;
39 import ca.polymtl.dorsal.libdelorean.exceptions.StateSystemDisposedException;
40 import ca.polymtl.dorsal.libdelorean.interval.ITmfStateInterval;
41
42 /**
43 * Basic implementation of a {@link TimeGraphModelStateProvider} backed by a state
44 * system.
45 *
46 * @author Alexandre Montplaisir
47 */
48 public class StateSystemModelStateProvider extends TimeGraphModelStateProvider {
49
50 /**
51 * The context of a single state interval. Should contain all the
52 * information required to generate the state interval in the render (name,
53 * color, etc.)
54 */
55 protected static final class StateIntervalContext {
56
57 /** State system */
58 public final ITmfStateSystem ss;
59 /** Base tree element */
60 public final StateSystemTimeGraphTreeElement baseTreeElement;
61 /** Source interval */
62 public final ITmfStateInterval sourceInterval;
63
64 /**
65 * Constructor
66 *
67 * @param ss
68 * State system
69 * @param baseTreeElement
70 * Tree element for which the data should be fetched. It may
71 * not correspond directly to the state's tree element, a
72 * relative path may be used, for example for additional data
73 * stored in a separate attribute.
74 * @param sourceInterval
75 * The state system interval which will be represented by the
76 * model state interval
77 */
78 public StateIntervalContext(ITmfStateSystem ss,
79 StateSystemTimeGraphTreeElement baseTreeElement,
80 ITmfStateInterval sourceInterval) {
81 this.ss = ss;
82 this.baseTreeElement = baseTreeElement;
83 this.sourceInterval = sourceInterval;
84 }
85 }
86
87 private final String fStateSystemModuleId;
88 private final Function<StateIntervalContext, TimeGraphStateInterval> fIntervalMappingFunction;
89
90 /**
91 * This state system here is not necessarily the same as the one in the
92 * {@link StateSystemModelProvider}!
93 */
94 private transient @Nullable ITmfStateSystem fStateSystem = null;
95
96 /**
97 * Constructor
98 *
99 * TODO Maybe merge the various Functions into a single class?
100 *
101 * @param stateDefinitions
102 * The state definitions used in this provider
103 * @param stateSystemModuleId
104 * The ID of the state system from which to fetch the information
105 * @param stateNameMappingFunction
106 * Mapping function from state interval context to state name
107 * @param labelMappingFunction
108 * Mapping function from state interval context to state label
109 * @param colorMappingFunction
110 * Mapping function from state interval context to state color
111 * @param lineThicknessMappingFunction
112 * Mapping function from state interval context to line thickness
113 * @param propertiesMappingFunction
114 * Mapping function from state interval context to properties
115 */
116 public StateSystemModelStateProvider(
117 List<StateDefinition> stateDefinitions,
118 String stateSystemModuleId,
119 Function<StateIntervalContext, String> stateNameMappingFunction,
120 Function<StateIntervalContext, @Nullable String> labelMappingFunction,
121 Function<StateIntervalContext, ConfigOption<ColorDefinition>> colorMappingFunction,
122 Function<StateIntervalContext, ConfigOption<LineThickness>> lineThicknessMappingFunction,
123 Function<StateIntervalContext, Map<String, String>> propertiesMappingFunction) {
124
125 super(stateDefinitions);
126
127 fStateSystemModuleId = stateSystemModuleId;
128
129 fIntervalMappingFunction = ssCtx -> {
130 return new BasicTimeGraphStateInterval(
131 ssCtx.sourceInterval.getStartTime(),
132 ssCtx.sourceInterval.getEndTime(),
133 ssCtx.baseTreeElement,
134 stateNameMappingFunction.apply(ssCtx),
135 labelMappingFunction.apply(ssCtx),
136 colorMappingFunction.apply(ssCtx),
137 lineThicknessMappingFunction.apply(ssCtx),
138 propertiesMappingFunction.apply(ssCtx));
139 };
140
141 /*
142 * Change listener which will take care of keeping the target state
143 * system up to date.
144 */
145 traceProperty().addListener((obs, oldValue, newValue) -> {
146 ITmfTrace trace = newValue;
147 if (trace == null) {
148 fStateSystem = null;
149 return;
150 }
151
152 // FIXME Remove the extra thread once we move to Jabberwocky
153 Thread thread = new Thread(() -> {
154 fStateSystem = TmfStateSystemAnalysisModule.getStateSystem(trace, fStateSystemModuleId);
155 });
156 thread.start();
157 });
158
159 }
160
161 // ------------------------------------------------------------------------
162 // Render generation methods
163 // ------------------------------------------------------------------------
164
165 @Override
166 public TimeGraphStateRender getStateRender(TimeGraphTreeElement treeElement,
167 TimeRange timeRange, long resolution, @Nullable FutureTask<?> task) {
168
169 ITmfStateSystem ss = fStateSystem;
170 /*
171 * Sometimes ss is null with uninitialized or empty views, just keep the model
172 * empty.
173 */
174 if (ss == null
175 || (task != null && task.isCancelled())
176 /* "Title" entries should be ignored */
177 || !(treeElement instanceof StateSystemTimeGraphTreeElement)) {
178
179 return TimeGraphStateRender.EMPTY_RENDER;
180 }
181 StateSystemTimeGraphTreeElement treeElem = (StateSystemTimeGraphTreeElement) treeElement;
182
183 /* Prepare the state intervals */
184 List<TimeGraphStateInterval> intervals;
185 try {
186 intervals = queryHistoryRange(ss, treeElem,
187 timeRange.getStart(), timeRange.getEnd(), resolution, task);
188 } catch (AttributeNotFoundException | StateSystemDisposedException e) {
189 intervals = Collections.emptyList();
190 }
191
192 return new TimeGraphStateRender(timeRange, treeElement, intervals);
193 }
194
195 private List<TimeGraphStateInterval> queryHistoryRange(ITmfStateSystem ss,
196 StateSystemTimeGraphTreeElement treeElem,
197 final long t1, final long t2, final long resolution,
198 @Nullable FutureTask<?> task)
199 throws AttributeNotFoundException, StateSystemDisposedException {
200
201 /* Validate the parameters. */
202 if (t2 < t1 || resolution <= 0) {
203 throw new IllegalArgumentException(ss.getSSID() + " Start:" + t1 + ", End:" + t2 + ", Resolution:" + resolution); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
204 }
205
206 final List<TimeGraphStateInterval> modelIntervals = new LinkedList<>();
207 final int attributeQuark = treeElem.getSourceQuark();
208 ITmfStateInterval lastAddedInterval = null;
209
210 /* Actual valid start/end time of the range query. */
211 long tStart = Math.max(t1, ss.getStartTime());
212 long tEnd = Math.min(t2, ss.getCurrentEndTime());
213
214 /*
215 * First, iterate over the "resolution points" and keep all matching
216 * state intervals.
217 */
218 for (long ts = tStart; ts <= tEnd - resolution; ts += resolution) {
219 /*
220 * Skip queries if the corresponding interval was already included
221 */
222 if (lastAddedInterval != null && lastAddedInterval.getEndTime() >= ts) {
223 long nextTOffset = MathUtils.roundToClosestHigherMultiple(lastAddedInterval.getEndTime() - tStart, resolution);
224 long nextTs = tStart + nextTOffset;
225 if (nextTs == ts) {
226 /*
227 * The end time of the last interval happened to be exactly
228 * equal to the next resolution point. We will go to the
229 * resolution point after that then.
230 */
231 ts = nextTs;
232 } else {
233 /* 'ts' will get incremented at next loop */
234 ts = nextTs - resolution;
235 }
236 continue;
237 }
238
239 ITmfStateInterval stateSystemInterval = ss.querySingleState(ts, attributeQuark);
240
241 /*
242 * Only pick the interval if it fills the current resolution range,
243 * from 'ts' to 'ts + resolution' (or 'ts2').
244 */
245 long ts2 = ts + resolution;
246 if (stateSystemInterval.getStartTime() <= ts && stateSystemInterval.getEndTime() >= ts2) {
247 TimeGraphStateInterval interval = ssIntervalToModelInterval(ss, treeElem, stateSystemInterval);
248 modelIntervals.add(interval);
249 lastAddedInterval = stateSystemInterval;
250 }
251 }
252
253 /*
254 * For the very last interval, we'll use ['tEnd - resolution', 'tEnd']
255 * as a range condition instead.
256 */
257 long ts = Math.max(tStart, tEnd - resolution);
258 long ts2 = tEnd;
259 if (lastAddedInterval != null && lastAddedInterval.getEndTime() >= ts) {
260 /* Interval already included */
261 } else {
262 ITmfStateInterval stateSystemInterval = ss.querySingleState(ts, attributeQuark);
263 if (stateSystemInterval.getStartTime() <= ts && stateSystemInterval.getEndTime() >= ts2) {
264 TimeGraphStateInterval interval = ssIntervalToModelInterval(ss, treeElem, stateSystemInterval);
265 modelIntervals.add(interval);
266 }
267 }
268
269 /*
270 * 'modelIntervals' now contains all the "real" intervals we will want
271 * to display in the view. Poly-filla the holes in between each using
272 * multi-state intervals.
273 */
274 if (modelIntervals.size() < 2) {
275 return modelIntervals;
276 }
277
278 List<TimeGraphStateInterval> filledIntervals = new LinkedList<>();
279 /*
280 * Add the first real interval. There might be a multi-state at the
281 * beginning.
282 */
283 long firstRealIntervalStartTime = modelIntervals.get(0).getStartTime();
284 if (firstRealIntervalStartTime > tStart) {
285 filledIntervals.add(new MultiStateInterval(tStart, firstRealIntervalStartTime - 1, treeElem));
286 }
287 filledIntervals.add(modelIntervals.get(0));
288
289 for (int i = 1; i < modelIntervals.size(); i++) {
290 TimeGraphStateInterval interval1 = modelIntervals.get(i - 1);
291 TimeGraphStateInterval interval2 = modelIntervals.get(i);
292 long bound1 = interval1.getEndTime();
293 long bound2 = interval2.getStartTime();
294
295 /* (we've already inserted 'interval1' on the previous loop.) */
296 if (bound1 + 1 != bound2) {
297 TimeGraphStateInterval multiStateInterval = new MultiStateInterval(bound1 + 1, bound2 - 1, treeElem);
298 filledIntervals.add(multiStateInterval);
299 }
300 filledIntervals.add(interval2);
301 }
302
303 /* Add a multi-state at the end too, if needed */
304 long lastRealIntervalEndTime = Iterables.getLast(modelIntervals).getEndTime();
305 if (lastRealIntervalEndTime < t2) {
306 filledIntervals.add(new MultiStateInterval(lastRealIntervalEndTime + 1, t2, treeElem));
307 }
308
309 return filledIntervals;
310 }
311
312 private TimeGraphStateInterval ssIntervalToModelInterval(ITmfStateSystem ss,
313 StateSystemTimeGraphTreeElement treeElem, ITmfStateInterval interval) {
314 StateIntervalContext siCtx = new StateIntervalContext(ss, treeElem, interval);
315 return fIntervalMappingFunction.apply(siCtx);
316 }
317
318 }
This page took 0.038526 seconds and 5 git commands to generate.