1 /*******************************************************************************
2 * Copyright (c) 2015 Ericsson
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
10 * Patrick Tasse - Initial API and implementation
11 *******************************************************************************/
13 package org
.eclipse
.tracecompass
.tmf
.ui
.views
.timegraph
;
15 import static org
.eclipse
.tracecompass
.common
.core
.NonNullUtils
.checkNotNull
;
17 import java
.util
.ArrayList
;
18 import java
.util
.HashMap
;
19 import java
.util
.List
;
21 import java
.util
.concurrent
.CopyOnWriteArrayList
;
23 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
24 import org
.eclipse
.jdt
.annotation
.NonNull
;
25 import org
.eclipse
.jdt
.annotation
.Nullable
;
26 import org
.eclipse
.tracecompass
.statesystem
.core
.ITmfStateSystem
;
27 import org
.eclipse
.tracecompass
.statesystem
.core
.exceptions
.StateSystemDisposedException
;
28 import org
.eclipse
.tracecompass
.statesystem
.core
.interval
.ITmfStateInterval
;
29 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfSignalHandler
;
30 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfTraceClosedSignal
;
31 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.ITmfTrace
;
32 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.TimeGraphPresentationProvider
;
33 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.model
.ILinkEvent
;
34 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.model
.IMarkerEvent
;
35 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.model
.ITimeEvent
;
36 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.model
.ITimeGraphEntry
;
37 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.model
.TimeGraphEntry
;
39 import com
.google
.common
.collect
.HashMultimap
;
40 import com
.google
.common
.collect
.Multimap
;
43 * An abstract time graph view where each entry's time event list is populated
44 * from a state system. The state system full state is queried in chronological
45 * order before creating the time event lists as this is optimal for state
50 public abstract class AbstractStateSystemTimeGraphView
extends AbstractTimeGraphView
{
52 // ------------------------------------------------------------------------
54 // ------------------------------------------------------------------------
56 private static final long MAX_INTERVALS
= 1000000;
58 // ------------------------------------------------------------------------
60 // ------------------------------------------------------------------------
62 /** The state system to entry list hash map */
63 private final Map
<ITmfStateSystem
, List
<TimeGraphEntry
>> fSSEntryListMap
= new HashMap
<>();
65 /** The trace to state system multi map */
66 private final Multimap
<ITmfTrace
, ITmfStateSystem
> fTraceSSMap
= HashMultimap
.create();
68 // ------------------------------------------------------------------------
70 // ------------------------------------------------------------------------
73 * Handler for state system queries
75 public interface IQueryHandler
{
77 * Handle a full or partial list of full states. This can be called many
78 * times for the same query if the query result is split, in which case
79 * the previous full state is null only the first time it is called, and
80 * set to the last full state of the previous call from then on.
83 * the list of full states
84 * @param prevFullState
85 * the previous full state, or null
87 void handle(@NonNull List
<List
<ITmfStateInterval
>> fullStates
, @Nullable List
<ITmfStateInterval
> prevFullState
);
90 private class ZoomThreadByTime
extends ZoomThread
{
91 private final @NonNull List
<ITmfStateSystem
> fZoomSSList
;
92 private boolean fClearZoomedLists
;
94 public ZoomThreadByTime(@NonNull List
<ITmfStateSystem
> ssList
, long startTime
, long endTime
, long resolution
, boolean restart
) {
95 super(startTime
, endTime
, resolution
);
97 fClearZoomedLists
= !restart
;
102 final List
<ILinkEvent
> links
= new ArrayList
<>();
103 final List
<IMarkerEvent
> markers
= new ArrayList
<>();
104 if (fClearZoomedLists
) {
107 for (ITmfStateSystem ss
: fZoomSSList
) {
108 List
<TimeGraphEntry
> entryList
= null;
109 synchronized (fSSEntryListMap
) {
110 entryList
= fSSEntryListMap
.get(ss
);
112 if (entryList
!= null) {
113 zoomByTime(ss
, entryList
, links
, markers
, getZoomStartTime(), getZoomEndTime(), getResolution(), getMonitor());
116 if (!getMonitor().isCanceled()) {
117 getTimeGraphViewer().setLinks(links
);
118 getTimeGraphViewer().getTimeGraphControl().setMarkers(markers
);
123 public void cancel() {
125 if (fClearZoomedLists
) {
130 private void zoomByTime(final ITmfStateSystem ss
, final List
<TimeGraphEntry
> entryList
, final List
<ILinkEvent
> links
, final List
<IMarkerEvent
> markers
,
131 long startTime
, long endTime
, long resolution
, final @NonNull IProgressMonitor monitor
) {
132 final long start
= Math
.max(startTime
, ss
.getStartTime());
133 final long end
= Math
.min(endTime
, ss
.getCurrentEndTime());
134 final boolean fullRange
= getZoomStartTime() <= getStartTime() && getZoomEndTime() >= getEndTime();
141 queryFullStates(ss
, start
, end
, resolution
, monitor
, new IQueryHandler() {
143 public void handle(@NonNull List
<List
<ITmfStateInterval
>> fullStates
, @Nullable List
<ITmfStateInterval
> prevFullState
) {
145 for (TimeGraphEntry entry
: entryList
) {
146 zoom(checkNotNull(entry
), ss
, fullStates
, prevFullState
, monitor
);
149 /* Refresh the arrows when zooming */
150 links
.addAll(getLinkList(ss
, fullStates
, monitor
));
151 /* Refresh the markers when zooming */
152 markers
.addAll(getMarkerList(ss
, fullStates
, monitor
));
158 private void zoom(@NonNull TimeGraphEntry entry
, ITmfStateSystem ss
, @NonNull List
<List
<ITmfStateInterval
>> fullStates
, @Nullable List
<ITmfStateInterval
> prevFullState
, @NonNull IProgressMonitor monitor
) {
159 List
<ITimeEvent
> eventList
= getEventList(entry
, ss
, fullStates
, prevFullState
, monitor
);
160 if (eventList
!= null) {
161 for (ITimeEvent event
: eventList
) {
162 entry
.addZoomedEvent(event
);
165 for (ITimeGraphEntry child
: entry
.getChildren()) {
166 if (monitor
.isCanceled()) {
169 if (child
instanceof TimeGraphEntry
) {
170 zoom((TimeGraphEntry
) child
, ss
, fullStates
, prevFullState
, monitor
);
175 private void clearZoomedLists() {
176 for (ITmfStateSystem ss
: fZoomSSList
) {
177 List
<TimeGraphEntry
> entryList
= null;
178 synchronized (fSSEntryListMap
) {
179 entryList
= fSSEntryListMap
.get(ss
);
181 if (entryList
!= null) {
182 for (TimeGraphEntry entry
: entryList
) {
183 clearZoomedList(entry
);
187 fClearZoomedLists
= false;
190 private void clearZoomedList(TimeGraphEntry entry
) {
191 entry
.setZoomedEventList(null);
192 for (ITimeGraphEntry child
: entry
.getChildren()) {
193 if (child
instanceof TimeGraphEntry
) {
194 clearZoomedList((TimeGraphEntry
) child
);
200 // ------------------------------------------------------------------------
202 // ------------------------------------------------------------------------
205 * Constructs a time graph view that contains either a time graph viewer or
206 * a time graph combo.
208 * By default, the view uses a time graph viewer. To use a time graph combo,
209 * the subclass constructor must call {@link #setTreeColumns(String[])} and
210 * {@link #setTreeLabelProvider(TreeLabelProvider)}.
215 * The presentation provider
217 public AbstractStateSystemTimeGraphView(String id
, TimeGraphPresentationProvider pres
) {
221 // ------------------------------------------------------------------------
223 // ------------------------------------------------------------------------
226 * Gets the entry list for a state system
231 * @return the entry list map
233 protected List
<TimeGraphEntry
> getEntryList(ITmfStateSystem ss
) {
234 synchronized (fSSEntryListMap
) {
235 return fSSEntryListMap
.get(ss
);
240 * Adds a trace entry list to the entry list map
247 * the list of time graph entries
249 protected void putEntryList(ITmfTrace trace
, ITmfStateSystem ss
, List
<TimeGraphEntry
> list
) {
250 super.putEntryList(trace
, list
);
251 synchronized (fSSEntryListMap
) {
252 fSSEntryListMap
.put(ss
, new CopyOnWriteArrayList
<>(list
));
253 fTraceSSMap
.put(trace
, ss
);
258 * Adds a list of entries to a trace's entry list
265 * the list of time graph entries to add
267 protected void addToEntryList(ITmfTrace trace
, ITmfStateSystem ss
, List
<TimeGraphEntry
> list
) {
268 super.addToEntryList(trace
, list
);
269 synchronized (fSSEntryListMap
) {
270 List
<TimeGraphEntry
> entryList
= fSSEntryListMap
.get(ss
);
271 if (entryList
== null) {
272 fSSEntryListMap
.put(ss
, new CopyOnWriteArrayList
<>(list
));
274 entryList
.addAll(list
);
276 fTraceSSMap
.put(trace
, ss
);
281 * Removes a list of entries from a trace's entry list
288 * the list of time graph entries to remove
290 protected void removeFromEntryList(ITmfTrace trace
, ITmfStateSystem ss
, List
<TimeGraphEntry
> list
) {
291 super.removeFromEntryList(trace
, list
);
292 synchronized (fSSEntryListMap
) {
293 List
<TimeGraphEntry
> entryList
= fSSEntryListMap
.get(ss
);
294 if (entryList
!= null) {
295 entryList
.removeAll(list
);
296 if (entryList
.isEmpty()) {
297 fTraceSSMap
.remove(trace
, ss
);
304 protected @Nullable ZoomThread
createZoomThread(long startTime
, long endTime
, long resolution
, boolean restart
) {
305 List
<ITmfStateSystem
> ssList
= null;
306 synchronized (fSSEntryListMap
) {
307 ssList
= new ArrayList
<>(fTraceSSMap
.get(getTrace()));
309 if (ssList
.isEmpty()) {
312 return new ZoomThreadByTime(ssList
, startTime
, endTime
, resolution
, restart
);
316 * Query the state system full state for the given time range.
327 * The progress monitor
331 protected void queryFullStates(ITmfStateSystem ss
, long start
, long end
, long resolution
,
332 @NonNull IProgressMonitor monitor
, @NonNull IQueryHandler handler
) {
333 List
<List
<ITmfStateInterval
>> fullStates
= new ArrayList
<>();
334 List
<ITmfStateInterval
> prevFullState
= null;
338 if (monitor
.isCanceled()) {
341 List
<ITmfStateInterval
> fullState
= ss
.queryFullState(time
);
342 fullStates
.add(fullState
);
343 if (fullStates
.size() * fullState
.size() > MAX_INTERVALS
) {
344 handler
.handle(fullStates
, prevFullState
);
345 prevFullState
= fullStates
.get(fullStates
.size() - 1);
351 time
= Math
.min(end
, time
+ resolution
);
353 if (fullStates
.size() > 0) {
354 handler
.handle(fullStates
, prevFullState
);
356 } catch (StateSystemDisposedException e
) {
362 * Gets the list of events for an entry for a given list of full states.
365 * The time graph entry
369 * A list of full states
370 * @param prevFullState
371 * The previous full state, or null
374 * @return The list of time graph events
376 protected abstract @Nullable List
<ITimeEvent
> getEventList(@NonNull TimeGraphEntry tgentry
, ITmfStateSystem ss
,
377 @NonNull List
<List
<ITmfStateInterval
>> fullStates
, @Nullable List
<ITmfStateInterval
> prevFullState
, @NonNull IProgressMonitor monitor
);
380 * Gets the list of links (displayed as arrows) for a given list of full
381 * states. The default implementation returns an empty list.
386 * A list of full states
389 * @return The list of link events
391 protected @NonNull List
<ILinkEvent
> getLinkList(ITmfStateSystem ss
,
392 @NonNull List
<List
<ITmfStateInterval
>> fullStates
, @NonNull IProgressMonitor monitor
) {
393 return new ArrayList
<>();
397 * Gets the list of markers for a given list of full
398 * states. The default implementation returns an empty list.
403 * A list of full states
406 * @return The list of marker events
409 protected @NonNull List
<IMarkerEvent
> getMarkerList(ITmfStateSystem ss
,
410 @NonNull List
<List
<ITmfStateInterval
>> fullStates
, @NonNull IProgressMonitor monitor
) {
411 return new ArrayList
<>();
415 * @deprecated The subclass should call {@link #getEntryList(ITmfStateSystem)} instead.
419 protected final List
<TimeGraphEntry
> getEntryList(ITmfTrace trace
) {
420 throw new UnsupportedOperationException();
424 * @deprecated The subclass should call {@link #addToEntryList(ITmfTrace, ITmfStateSystem, List)} instead.
428 protected final void addToEntryList(ITmfTrace trace
, List
<TimeGraphEntry
> list
) {
429 throw new UnsupportedOperationException();
433 * @deprecated The subclass should call {@link #putEntryList(ITmfTrace, ITmfStateSystem, List)} instead.
437 protected final void putEntryList(ITmfTrace trace
, List
<TimeGraphEntry
> list
) {
438 throw new UnsupportedOperationException();
442 * @deprecated The subclass should call {@link #removeFromEntryList(ITmfTrace, ITmfStateSystem, List)} instead.
446 protected final void removeFromEntryList(ITmfTrace trace
, List
<TimeGraphEntry
> list
) {
447 throw new UnsupportedOperationException();
451 * @deprecated The subclass should implement {@link #getEventList(TimeGraphEntry, ITmfStateSystem, List, List, IProgressMonitor)} instead.
455 protected final List
<ITimeEvent
> getEventList(TimeGraphEntry entry
, long startTime
, long endTime
, long resolution
, IProgressMonitor monitor
) {
456 throw new UnsupportedOperationException();
460 * @deprecated The subclass should implement {@link #getLinkList(ITmfStateSystem, List, IProgressMonitor)} instead.
464 protected final List
<ILinkEvent
> getLinkList(long startTime
, long endTime
, long resolution
, IProgressMonitor monitor
) {
465 throw new UnsupportedOperationException();
469 * @deprecated The subclass should implement {@link #getMarkerList(ITmfStateSystem, List, IProgressMonitor)} instead.
473 protected final List
<IMarkerEvent
> getMarkerList(long startTime
, long endTime
, long resolution
, IProgressMonitor monitor
) {
474 throw new UnsupportedOperationException();
477 // ------------------------------------------------------------------------
479 // ------------------------------------------------------------------------
483 public void traceClosed(final TmfTraceClosedSignal signal
) {
484 super.traceClosed(signal
);
485 synchronized (fSSEntryListMap
) {
486 for (ITmfStateSystem ss
: fTraceSSMap
.removeAll(signal
.getTrace())) {
487 fSSEntryListMap
.remove(ss
);