1 /*******************************************************************************
2 * Copyright (c) 2016 EfficiOS Inc., Alexandre Montplaisir
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 *******************************************************************************/
10 package org
.lttng
.scope
.tmf2
.views
.core
.timegraph
.model
.provider
.statesystem
;
12 import java
.util
.Collections
;
13 import java
.util
.LinkedList
;
14 import java
.util
.List
;
16 import java
.util
.concurrent
.FutureTask
;
17 import java
.util
.function
.Function
;
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
;
35 import com
.google
.common
.collect
.Iterables
;
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
;
43 * Basic implementation of a {@link TimeGraphModelStateProvider} backed by a state
46 * @author Alexandre Montplaisir
48 public class StateSystemModelStateProvider
extends TimeGraphModelStateProvider
{
51 * The context of a single state interval. Should contain all the
52 * information required to generate the state interval in the render (name,
55 protected static final class StateIntervalContext
{
58 public final ITmfStateSystem ss
;
59 /** Base tree element */
60 public final StateSystemTimeGraphTreeElement baseTreeElement
;
61 /** Source interval */
62 public final ITmfStateInterval sourceInterval
;
65 * Full state system query at the start of the interval
69 public final List
<ITmfStateInterval
> fullQueryAtIntervalStart
;
76 * @param baseTreeElement
77 * Tree element for which the data should be fetched. It may
78 * not correspond directly to the state's tree element, a
79 * relative path may be used, for example for additional data
80 * stored in a separate attribute.
81 * @param sourceInterval
82 * The state system interval which will be represented by the
83 * model state interval
84 * @param fullQueryAtIntervalStart
85 * Full query at the start of the interval. FIXME Remove
86 * this! This should only be queried on-demand, not for every
89 public StateIntervalContext(ITmfStateSystem ss
,
90 StateSystemTimeGraphTreeElement baseTreeElement
,
91 ITmfStateInterval sourceInterval
,
92 List
<ITmfStateInterval
> fullQueryAtIntervalStart
) {
94 this.baseTreeElement
= baseTreeElement
;
95 this.sourceInterval
= sourceInterval
;
96 this.fullQueryAtIntervalStart
= fullQueryAtIntervalStart
;
100 private final String fStateSystemModuleId
;
101 private final Function
<StateIntervalContext
, TimeGraphStateInterval
> fIntervalMappingFunction
;
104 * This state system here is not necessarily the same as the one in the
105 * {@link StateSystemModelProvider}!
107 private transient @Nullable ITmfStateSystem fStateSystem
= null;
112 * TODO Maybe merge the various Functions into a single class?
114 * @param stateDefinitions
115 * The state definitions used in this provider
116 * @param stateSystemModuleId
117 * The ID of the state system from which to fetch the information
118 * @param stateNameMappingFunction
119 * Mapping function from state interval context to state name
120 * @param labelMappingFunction
121 * Mapping function from state interval context to state label
122 * @param colorMappingFunction
123 * Mapping function from state interval context to state color
124 * @param lineThicknessMappingFunction
125 * Mapping function from state interval context to line thickness
126 * @param propertiesMappingFunction
127 * Mapping function from state interval context to properties
129 public StateSystemModelStateProvider(
130 List
<StateDefinition
> stateDefinitions
,
131 String stateSystemModuleId
,
132 Function
<StateIntervalContext
, String
> stateNameMappingFunction
,
133 Function
<StateIntervalContext
, @Nullable String
> labelMappingFunction
,
134 Function
<StateIntervalContext
, ConfigOption
<ColorDefinition
>> colorMappingFunction
,
135 Function
<StateIntervalContext
, ConfigOption
<LineThickness
>> lineThicknessMappingFunction
,
136 Function
<StateIntervalContext
, Map
<String
, String
>> propertiesMappingFunction
) {
138 super(stateDefinitions
);
140 fStateSystemModuleId
= stateSystemModuleId
;
142 fIntervalMappingFunction
= ssCtx
-> {
143 return new BasicTimeGraphStateInterval(
144 ssCtx
.sourceInterval
.getStartTime(),
145 ssCtx
.sourceInterval
.getEndTime(),
146 ssCtx
.baseTreeElement
,
147 stateNameMappingFunction
.apply(ssCtx
),
148 labelMappingFunction
.apply(ssCtx
),
149 colorMappingFunction
.apply(ssCtx
),
150 lineThicknessMappingFunction
.apply(ssCtx
),
151 propertiesMappingFunction
.apply(ssCtx
));
155 * Change listener which will take care of keeping the target state
158 traceProperty().addListener((obs
, oldValue
, newValue
) -> {
159 ITmfTrace trace
= newValue
;
165 // FIXME Remove the extra thread once we move to Jabberwocky
166 Thread thread
= new Thread(() -> {
167 fStateSystem
= TmfStateSystemAnalysisModule
.getStateSystem(trace
, fStateSystemModuleId
);
174 // ------------------------------------------------------------------------
175 // Render generation methods
176 // ------------------------------------------------------------------------
179 public TimeGraphStateRender
getStateRender(TimeGraphTreeElement treeElement
,
180 TimeRange timeRange
, long resolution
, @Nullable FutureTask
<?
> task
) {
182 ITmfStateSystem ss
= fStateSystem
;
184 /* Has been called with an invalid trace/treeElement */
185 throw new IllegalArgumentException();
188 if (task
!= null && task
.isCancelled()) {
189 return TimeGraphStateRender
.EMPTY_RENDER
;
192 // FIXME Add generic type?
193 StateSystemTimeGraphTreeElement treeElem
= (StateSystemTimeGraphTreeElement
) treeElement
;
195 /* Prepare the state intervals */
196 List
<TimeGraphStateInterval
> intervals
;
198 intervals
= queryHistoryRange(ss
, treeElem
,
199 timeRange
.getStart(), timeRange
.getEnd(), resolution
, task
);
200 } catch (AttributeNotFoundException
| StateSystemDisposedException e
) {
201 intervals
= Collections
.emptyList();
204 return new TimeGraphStateRender(timeRange
, treeElement
, intervals
);
207 private List
<TimeGraphStateInterval
> queryHistoryRange(ITmfStateSystem ss
,
208 StateSystemTimeGraphTreeElement treeElem
,
209 final long t1
, final long t2
, final long resolution
,
210 @Nullable FutureTask
<?
> task
)
211 throws AttributeNotFoundException
, StateSystemDisposedException
{
213 /* Validate the parameters. */
214 if (t2
< t1
|| resolution
<= 0) {
215 throw new IllegalArgumentException(ss
.getSSID() + " Start:" + t1
+ ", End:" + t2
+ ", Resolution:" + resolution
); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
218 final List
<TimeGraphStateInterval
> modelIntervals
= new LinkedList
<>();
219 final int attributeQuark
= treeElem
.getSourceQuark();
220 ITmfStateInterval lastAddedInterval
= null;
222 /* Actual valid start/end time of the range query. */
223 long tStart
= Math
.max(t1
, ss
.getStartTime());
224 long tEnd
= Math
.min(t2
, ss
.getCurrentEndTime());
227 * First, iterate over the "resolution points" and keep all matching
230 for (long ts
= tStart
; ts
<= tEnd
- resolution
; ts
+= resolution
) {
232 * Skip queries if the corresponding interval was already included
234 if (lastAddedInterval
!= null && lastAddedInterval
.getEndTime() >= ts
) {
235 long nextTOffset
= MathUtils
.roundToClosestHigherMultiple(lastAddedInterval
.getEndTime() - tStart
, resolution
);
236 long nextTs
= tStart
+ nextTOffset
;
239 * The end time of the last interval happened to be exactly
240 * equal to the next resolution point. We will go to the
241 * resolution point after that then.
245 /* 'ts' will get incremented at next loop */
246 ts
= nextTs
- resolution
;
251 ITmfStateInterval stateSystemInterval
= ss
.querySingleState(ts
, attributeQuark
);
254 * Only pick the interval if it fills the current resolution range,
255 * from 'ts' to 'ts + resolution' (or 'ts2').
257 long ts2
= ts
+ resolution
;
258 if (stateSystemInterval
.getStartTime() <= ts
&& stateSystemInterval
.getEndTime() >= ts2
) {
259 TimeGraphStateInterval interval
= ssIntervalToModelInterval(ss
, treeElem
, stateSystemInterval
);
260 modelIntervals
.add(interval
);
261 lastAddedInterval
= stateSystemInterval
;
266 * For the very last interval, we'll use ['tEnd - resolution', 'tEnd']
267 * as a range condition instead.
269 long ts
= Math
.max(tStart
, tEnd
- resolution
);
271 if (lastAddedInterval
!= null && lastAddedInterval
.getEndTime() >= ts
) {
272 /* Interval already included */
274 ITmfStateInterval stateSystemInterval
= ss
.querySingleState(ts
, attributeQuark
);
275 if (stateSystemInterval
.getStartTime() <= ts
&& stateSystemInterval
.getEndTime() >= ts2
) {
276 TimeGraphStateInterval interval
= ssIntervalToModelInterval(ss
, treeElem
, stateSystemInterval
);
277 modelIntervals
.add(interval
);
282 * 'modelIntervals' now contains all the "real" intervals we will want
283 * to display in the view. Poly-filla the holes in between each using
284 * multi-state intervals.
286 if (modelIntervals
.size() < 2) {
287 return modelIntervals
;
290 List
<TimeGraphStateInterval
> filledIntervals
= new LinkedList
<>();
292 * Add the first real interval. There might be a multi-state at the
295 long firstRealIntervalStartTime
= modelIntervals
.get(0).getStartTime();
296 if (firstRealIntervalStartTime
> tStart
) {
297 filledIntervals
.add(new MultiStateInterval(tStart
, firstRealIntervalStartTime
- 1, treeElem
));
299 filledIntervals
.add(modelIntervals
.get(0));
301 for (int i
= 1; i
< modelIntervals
.size(); i
++) {
302 TimeGraphStateInterval interval1
= modelIntervals
.get(i
- 1);
303 TimeGraphStateInterval interval2
= modelIntervals
.get(i
);
304 long bound1
= interval1
.getEndTime();
305 long bound2
= interval2
.getStartTime();
307 /* (we've already inserted 'interval1' on the previous loop.) */
308 if (bound1
+ 1 != bound2
) {
309 TimeGraphStateInterval multiStateInterval
= new MultiStateInterval(bound1
+ 1, bound2
- 1, treeElem
);
310 filledIntervals
.add(multiStateInterval
);
312 filledIntervals
.add(interval2
);
315 /* Add a multi-state at the end too, if needed */
316 long lastRealIntervalEndTime
= Iterables
.getLast(modelIntervals
).getEndTime();
317 if (lastRealIntervalEndTime
< t2
) {
318 filledIntervals
.add(new MultiStateInterval(lastRealIntervalEndTime
+ 1, t2
, treeElem
));
321 return filledIntervals
;
324 private TimeGraphStateInterval
ssIntervalToModelInterval(ITmfStateSystem ss
,
325 StateSystemTimeGraphTreeElement treeElem
, ITmfStateInterval interval
) {
326 List
<ITmfStateInterval
> fullState
;
328 // TODO Big performance improvement low-hanging fruit here
329 fullState
= ss
.queryFullState(interval
.getStartTime());
330 } catch (StateSystemDisposedException e
) {
331 fullState
= Collections
.emptyList();
334 StateIntervalContext siCtx
= new StateIntervalContext(ss
, treeElem
, interval
, fullState
);
335 return fIntervalMappingFunction
.apply(siCtx
);