1 /*******************************************************************************
2 * Copyright (c) 2015, 2016 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
;
22 import java
.util
.logging
.Logger
;
24 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
25 import org
.eclipse
.jdt
.annotation
.NonNull
;
26 import org
.eclipse
.jdt
.annotation
.Nullable
;
27 import org
.eclipse
.tracecompass
.common
.core
.log
.TraceCompassLog
;
28 import org
.eclipse
.tracecompass
.statesystem
.core
.ITmfStateSystem
;
29 import org
.eclipse
.tracecompass
.statesystem
.core
.exceptions
.StateSystemDisposedException
;
30 import org
.eclipse
.tracecompass
.statesystem
.core
.interval
.ITmfStateInterval
;
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
.TimeGraphEntry
;
38 import com
.google
.common
.collect
.HashMultimap
;
39 import com
.google
.common
.collect
.Multimap
;
42 * An abstract time graph view where each entry's time event list is populated
43 * from a state system. The state system full state is queried in chronological
44 * order before creating the time event lists as this is optimal for state
49 public abstract class AbstractStateSystemTimeGraphView
extends AbstractTimeGraphView
{
51 // ------------------------------------------------------------------------
53 // ------------------------------------------------------------------------
55 private static final long MAX_INTERVALS
= 1000000;
57 // ------------------------------------------------------------------------
59 // ------------------------------------------------------------------------
61 /** The state system to entry list hash map */
62 private final Map
<ITmfStateSystem
, List
<@NonNull TimeGraphEntry
>> fSSEntryListMap
= new HashMap
<>();
64 /** The trace to state system multi map */
65 private final Multimap
<ITmfTrace
, ITmfStateSystem
> fTraceSSMap
= HashMultimap
.create();
67 private static final Logger LOGGER
= TraceCompassLog
.getLogger(AbstractStateSystemTimeGraphView
.class);
69 // ------------------------------------------------------------------------
71 // ------------------------------------------------------------------------
74 * Handler for state system queries
76 public interface IQueryHandler
{
78 * Handle a full or partial list of full states. This can be called many
79 * times for the same query if the query result is split, in which case
80 * the previous full state is null only the first time it is called, and
81 * set to the last full state of the previous call from then on.
84 * the list of full states
85 * @param prevFullState
86 * the previous full state, or null
88 void handle(@NonNull List
<List
<ITmfStateInterval
>> fullStates
, @Nullable List
<ITmfStateInterval
> prevFullState
);
91 private class ZoomThreadByTime
extends ZoomThread
{
92 private final @NonNull List
<ITmfStateSystem
> fZoomSSList
;
93 private boolean fClearZoomedLists
;
95 public ZoomThreadByTime(@NonNull List
<ITmfStateSystem
> ssList
, long startTime
, long endTime
, long resolution
, boolean restart
) {
96 super(startTime
, endTime
, resolution
);
98 fClearZoomedLists
= !restart
;
102 public void doRun() {
103 final List
<ILinkEvent
> links
= new ArrayList
<>();
104 final List
<IMarkerEvent
> markers
= new ArrayList
<>();
105 if (fClearZoomedLists
) {
108 for (ITmfStateSystem ss
: fZoomSSList
) {
109 List
<TimeGraphEntry
> entryList
= null;
110 synchronized (fSSEntryListMap
) {
111 entryList
= fSSEntryListMap
.get(ss
);
113 if (entryList
!= null) {
114 zoomByTime(ss
, entryList
, links
, markers
, getZoomStartTime(), getZoomEndTime(), getResolution(), getMonitor());
117 if (!getMonitor().isCanceled()) {
118 /* Refresh the trace-specific markers when zooming */
119 markers
.addAll(getTraceMarkerList(getZoomStartTime(), getZoomEndTime(), getResolution(), getMonitor()));
121 getTimeGraphViewer().setLinks(links
);
122 getTimeGraphViewer().setMarkers(markers
);
125 LOGGER
.info(() -> "[TimeGraphView:ZoomThreadCanceled]"); //$NON-NLS-1$
130 public void cancel() {
132 if (fClearZoomedLists
) {
137 private void zoomByTime(final ITmfStateSystem ss
, final List
<TimeGraphEntry
> entryList
, final List
<ILinkEvent
> links
, final List
<IMarkerEvent
> markers
,
138 long startTime
, long endTime
, long resolution
, final @NonNull IProgressMonitor monitor
) {
139 final long start
= Math
.max(startTime
, ss
.getStartTime());
140 final long end
= Math
.min(endTime
, ss
.getCurrentEndTime());
141 final boolean fullRange
= getZoomStartTime() <= getStartTime() && getZoomEndTime() >= getEndTime();
148 queryFullStates(ss
, start
, end
, resolution
, monitor
, new IQueryHandler() {
150 public void handle(@NonNull List
<List
<ITmfStateInterval
>> fullStates
, @Nullable List
<ITmfStateInterval
> prevFullState
) {
151 LOGGER
.config(() -> "[TimeGraphView:ZoomThreadGettingStates]"); //$NON-NLS-1$
153 for (TimeGraphEntry entry
: entryList
) {
154 zoom(checkNotNull(entry
), ss
, fullStates
, prevFullState
, monitor
);
157 /* Refresh the arrows when zooming */
158 LOGGER
.config(() -> "[TimeGraphView:ZoomThreadGettingLinks]"); //$NON-NLS-1$
159 links
.addAll(getLinkList(ss
, fullStates
, prevFullState
, monitor
));
160 /* Refresh the view-specific markers when zooming */
161 LOGGER
.config(() -> "[TimeGraphView:ZoomThreadGettingMarkers]"); //$NON-NLS-1$
162 markers
.addAll(getViewMarkerList(ss
, fullStates
, prevFullState
, monitor
));
163 LOGGER
.config(() -> "[TimeGraphView:ZoomThreadDone]"); //$NON-NLS-1$
169 private void zoom(@NonNull TimeGraphEntry entry
, ITmfStateSystem ss
, @NonNull List
<List
<ITmfStateInterval
>> fullStates
, @Nullable List
<ITmfStateInterval
> prevFullState
, @NonNull IProgressMonitor monitor
) {
170 List
<ITimeEvent
> eventList
= getEventList(entry
, ss
, fullStates
, prevFullState
, monitor
);
171 if (eventList
!= null) {
173 for (ITimeEvent event
: eventList
) {
174 if (monitor
.isCanceled()) {
177 entry
.addZoomedEvent(event
);
181 for (TimeGraphEntry child
: entry
.getChildren()) {
182 if (monitor
.isCanceled()) {
183 LOGGER
.info(() -> "[TimeGraphView:ZoomThreadCanceled]"); //$NON-NLS-1$
186 zoom(child
, ss
, fullStates
, prevFullState
, monitor
);
190 private void clearZoomedLists() {
191 for (ITmfStateSystem ss
: fZoomSSList
) {
192 List
<TimeGraphEntry
> entryList
= null;
193 synchronized (fSSEntryListMap
) {
194 entryList
= fSSEntryListMap
.get(ss
);
196 if (entryList
!= null) {
197 for (TimeGraphEntry entry
: entryList
) {
198 clearZoomedList(entry
);
202 fClearZoomedLists
= false;
205 private void clearZoomedList(TimeGraphEntry entry
) {
206 entry
.setZoomedEventList(null);
207 for (TimeGraphEntry child
: entry
.getChildren()) {
208 clearZoomedList(child
);
213 // ------------------------------------------------------------------------
215 // ------------------------------------------------------------------------
218 * Constructs a time graph view that contains either a time graph viewer or
219 * a time graph combo.
221 * By default, the view uses a time graph viewer. To use a time graph combo,
222 * the subclass constructor must call {@link #setTreeColumns(String[])} and
223 * {@link #setTreeLabelProvider(TreeLabelProvider)}.
228 * The presentation provider
230 public AbstractStateSystemTimeGraphView(String id
, TimeGraphPresentationProvider pres
) {
234 // ------------------------------------------------------------------------
236 // ------------------------------------------------------------------------
239 * Gets the entry list for a state system
244 * @return the entry list map
246 protected List
<@NonNull TimeGraphEntry
> getEntryList(ITmfStateSystem ss
) {
247 synchronized (fSSEntryListMap
) {
248 return fSSEntryListMap
.get(ss
);
253 * Adds a trace entry list to the entry list map
260 * the list of time graph entries
262 protected void putEntryList(ITmfTrace trace
, ITmfStateSystem ss
, List
<@NonNull TimeGraphEntry
> list
) {
263 super.putEntryList(trace
, list
);
264 synchronized (fSSEntryListMap
) {
265 fSSEntryListMap
.put(ss
, new CopyOnWriteArrayList
<>(list
));
266 fTraceSSMap
.put(trace
, ss
);
271 * Adds a list of entries to a trace's entry list
278 * the list of time graph entries to add
280 protected void addToEntryList(ITmfTrace trace
, ITmfStateSystem ss
, List
<@NonNull TimeGraphEntry
> list
) {
281 super.addToEntryList(trace
, list
);
282 synchronized (fSSEntryListMap
) {
283 List
<@NonNull TimeGraphEntry
> entryList
= fSSEntryListMap
.get(ss
);
284 if (entryList
== null) {
285 fSSEntryListMap
.put(ss
, new CopyOnWriteArrayList
<>(list
));
287 entryList
.addAll(list
);
289 fTraceSSMap
.put(trace
, ss
);
294 * Removes a list of entries from a trace's entry list
301 * the list of time graph entries to remove
303 protected void removeFromEntryList(ITmfTrace trace
, ITmfStateSystem ss
, List
<TimeGraphEntry
> list
) {
304 super.removeFromEntryList(trace
, list
);
305 synchronized (fSSEntryListMap
) {
306 List
<TimeGraphEntry
> entryList
= fSSEntryListMap
.get(ss
);
307 if (entryList
!= null) {
308 entryList
.removeAll(list
);
309 if (entryList
.isEmpty()) {
310 fTraceSSMap
.remove(trace
, ss
);
317 protected @Nullable ZoomThread
createZoomThread(long startTime
, long endTime
, long resolution
, boolean restart
) {
318 List
<ITmfStateSystem
> ssList
= null;
319 synchronized (fSSEntryListMap
) {
320 ssList
= new ArrayList
<>(fTraceSSMap
.get(getTrace()));
322 if (ssList
.isEmpty()) {
325 return new ZoomThreadByTime(ssList
, startTime
, endTime
, resolution
, restart
);
329 * Query the state system full state for the given time range.
340 * The progress monitor
344 protected void queryFullStates(ITmfStateSystem ss
, long start
, long end
, long resolution
,
345 @NonNull IProgressMonitor monitor
, @NonNull IQueryHandler handler
) {
346 List
<List
<ITmfStateInterval
>> fullStates
= new ArrayList
<>();
347 List
<ITmfStateInterval
> prevFullState
= null;
351 if (monitor
.isCanceled()) {
354 List
<ITmfStateInterval
> fullState
= ss
.queryFullState(time
);
355 fullStates
.add(fullState
);
356 if (fullStates
.size() * fullState
.size() > MAX_INTERVALS
) {
357 handler
.handle(fullStates
, prevFullState
);
358 prevFullState
= fullStates
.get(fullStates
.size() - 1);
364 time
= Math
.min(end
, time
+ resolution
);
366 if (fullStates
.size() > 0) {
367 handler
.handle(fullStates
, prevFullState
);
369 } catch (StateSystemDisposedException e
) {
375 * Gets the list of events for an entry for a given list of full states.
377 * Called from the ZoomThread for every entry to update the zoomed event
378 * list. Can be an empty implementation if the view does not support zoomed
379 * event lists. Can also be used to compute the full event list.
382 * The time graph entry
386 * A list of full states
387 * @param prevFullState
388 * The previous full state, or null
391 * @return The list of time graph events
393 protected abstract @Nullable List
<ITimeEvent
> getEventList(@NonNull TimeGraphEntry tgentry
, ITmfStateSystem ss
,
394 @NonNull List
<List
<ITmfStateInterval
>> fullStates
, @Nullable List
<ITmfStateInterval
> prevFullState
, @NonNull IProgressMonitor monitor
);
397 * Gets the list of links (displayed as arrows) for a given list of full
398 * states. The default implementation returns an empty list.
403 * A list of full states
404 * @param prevFullState
405 * The previous full state, or null
408 * @return The list of link events
411 protected @NonNull List
<ILinkEvent
> getLinkList(ITmfStateSystem ss
,
412 @NonNull List
<List
<ITmfStateInterval
>> fullStates
, @Nullable List
<ITmfStateInterval
> prevFullState
, @NonNull IProgressMonitor monitor
) {
413 return new ArrayList
<>();
417 * Gets the list of markers for a given list of full
418 * states. The default implementation returns an empty list.
423 * A list of full states
424 * @param prevFullState
425 * The previous full state, or null
428 * @return The list of marker events
431 protected @NonNull List
<IMarkerEvent
> getViewMarkerList(ITmfStateSystem ss
,
432 @NonNull List
<List
<ITmfStateInterval
>> fullStates
, @Nullable List
<ITmfStateInterval
> prevFullState
, @NonNull IProgressMonitor monitor
) {
433 return new ArrayList
<>();
437 * @deprecated The subclass should call {@link #getEntryList(ITmfStateSystem)} instead.
441 protected final List
<TimeGraphEntry
> getEntryList(ITmfTrace trace
) {
442 throw new UnsupportedOperationException();
446 * @deprecated The subclass should call {@link #addToEntryList(ITmfTrace, ITmfStateSystem, List)} instead.
450 protected final void addToEntryList(ITmfTrace trace
, List
<TimeGraphEntry
> list
) {
451 throw new UnsupportedOperationException();
455 * @deprecated The subclass should call {@link #putEntryList(ITmfTrace, ITmfStateSystem, List)} instead.
459 protected final void putEntryList(ITmfTrace trace
, List
<TimeGraphEntry
> list
) {
460 throw new UnsupportedOperationException();
464 * @deprecated The subclass should call {@link #removeFromEntryList(ITmfTrace, ITmfStateSystem, List)} instead.
468 protected final void removeFromEntryList(ITmfTrace trace
, List
<TimeGraphEntry
> list
) {
469 throw new UnsupportedOperationException();
473 * @deprecated The subclass should implement {@link #getEventList(TimeGraphEntry, ITmfStateSystem, List, List, IProgressMonitor)} instead.
477 protected final List
<ITimeEvent
> getEventList(TimeGraphEntry entry
, long startTime
, long endTime
, long resolution
, IProgressMonitor monitor
) {
478 throw new UnsupportedOperationException();
482 * @deprecated The subclass should implement {@link #getLinkList(ITmfStateSystem, List, List, IProgressMonitor)} instead.
486 protected final List
<ILinkEvent
> getLinkList(long startTime
, long endTime
, long resolution
, IProgressMonitor monitor
) {
487 throw new UnsupportedOperationException();
491 * @deprecated The subclass should implement {@link #getViewMarkerList(ITmfStateSystem, List, List, IProgressMonitor)} instead.
495 protected final List
<IMarkerEvent
> getViewMarkerList(long startTime
, long endTime
, long resolution
, IProgressMonitor monitor
) {
496 throw new UnsupportedOperationException();
500 protected void resetView(ITmfTrace viewTrace
) {
501 // Don't remove super call
502 super.resetView(viewTrace
);
503 synchronized (fSSEntryListMap
) {
504 for (ITmfStateSystem ss
: fTraceSSMap
.removeAll(viewTrace
)) {
505 fSSEntryListMap
.remove(ss
);