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().setMarkerCategories(getMarkerCategories());
123 getTimeGraphViewer().setMarkers(markers
);
126 LOGGER
.info(() -> "[TimeGraphView:ZoomThreadCanceled]"); //$NON-NLS-1$
131 public void cancel() {
133 if (fClearZoomedLists
) {
138 private void zoomByTime(final ITmfStateSystem ss
, final List
<TimeGraphEntry
> entryList
, final List
<ILinkEvent
> links
, final List
<IMarkerEvent
> markers
,
139 long startTime
, long endTime
, long resolution
, final @NonNull IProgressMonitor monitor
) {
140 final long start
= Math
.max(startTime
, ss
.getStartTime());
141 final long end
= Math
.min(endTime
, ss
.getCurrentEndTime());
142 final boolean fullRange
= getZoomStartTime() <= getStartTime() && getZoomEndTime() >= getEndTime();
149 queryFullStates(ss
, start
, end
, resolution
, monitor
, new IQueryHandler() {
151 public void handle(@NonNull List
<List
<ITmfStateInterval
>> fullStates
, @Nullable List
<ITmfStateInterval
> prevFullState
) {
152 LOGGER
.config(() -> "[TimeGraphView:ZoomThreadGettingStates]"); //$NON-NLS-1$
154 for (TimeGraphEntry entry
: entryList
) {
155 zoom(checkNotNull(entry
), ss
, fullStates
, prevFullState
, monitor
);
158 /* Refresh the arrows when zooming */
159 LOGGER
.config(() -> "[TimeGraphView:ZoomThreadGettingLinks]"); //$NON-NLS-1$
160 links
.addAll(getLinkList(ss
, fullStates
, prevFullState
, monitor
));
161 /* Refresh the view-specific markers when zooming */
162 LOGGER
.config(() -> "[TimeGraphView:ZoomThreadGettingMarkers]"); //$NON-NLS-1$
163 markers
.addAll(getViewMarkerList(ss
, fullStates
, prevFullState
, monitor
));
164 LOGGER
.config(() -> "[TimeGraphView:ZoomThreadDone]"); //$NON-NLS-1$
170 private void zoom(@NonNull TimeGraphEntry entry
, ITmfStateSystem ss
, @NonNull List
<List
<ITmfStateInterval
>> fullStates
, @Nullable List
<ITmfStateInterval
> prevFullState
, @NonNull IProgressMonitor monitor
) {
171 List
<ITimeEvent
> eventList
= getEventList(entry
, ss
, fullStates
, prevFullState
, monitor
);
172 if (eventList
!= null) {
174 for (ITimeEvent event
: eventList
) {
175 if (monitor
.isCanceled()) {
178 entry
.addZoomedEvent(event
);
182 for (TimeGraphEntry child
: entry
.getChildren()) {
183 if (monitor
.isCanceled()) {
184 LOGGER
.info(() -> "[TimeGraphView:ZoomThreadCanceled]"); //$NON-NLS-1$
187 zoom(child
, ss
, fullStates
, prevFullState
, monitor
);
191 private void clearZoomedLists() {
192 for (ITmfStateSystem ss
: fZoomSSList
) {
193 List
<TimeGraphEntry
> entryList
= null;
194 synchronized (fSSEntryListMap
) {
195 entryList
= fSSEntryListMap
.get(ss
);
197 if (entryList
!= null) {
198 for (TimeGraphEntry entry
: entryList
) {
199 clearZoomedList(entry
);
203 fClearZoomedLists
= false;
206 private void clearZoomedList(TimeGraphEntry entry
) {
207 entry
.setZoomedEventList(null);
208 for (TimeGraphEntry child
: entry
.getChildren()) {
209 clearZoomedList(child
);
214 // ------------------------------------------------------------------------
216 // ------------------------------------------------------------------------
219 * Constructs a time graph view that contains either a time graph viewer or
220 * a time graph combo.
222 * By default, the view uses a time graph viewer. To use a time graph combo,
223 * the subclass constructor must call {@link #setTreeColumns(String[])} and
224 * {@link #setTreeLabelProvider(TreeLabelProvider)}.
229 * The presentation provider
231 public AbstractStateSystemTimeGraphView(String id
, TimeGraphPresentationProvider pres
) {
235 // ------------------------------------------------------------------------
237 // ------------------------------------------------------------------------
240 * Gets the entry list for a state system
245 * @return the entry list map
247 protected List
<@NonNull TimeGraphEntry
> getEntryList(ITmfStateSystem ss
) {
248 synchronized (fSSEntryListMap
) {
249 return fSSEntryListMap
.get(ss
);
254 * Adds a trace entry list to the entry list map
261 * the list of time graph entries
263 protected void putEntryList(ITmfTrace trace
, ITmfStateSystem ss
, List
<@NonNull TimeGraphEntry
> list
) {
264 super.putEntryList(trace
, list
);
265 synchronized (fSSEntryListMap
) {
266 fSSEntryListMap
.put(ss
, new CopyOnWriteArrayList
<>(list
));
267 fTraceSSMap
.put(trace
, ss
);
272 * Adds a list of entries to a trace's entry list
279 * the list of time graph entries to add
281 protected void addToEntryList(ITmfTrace trace
, ITmfStateSystem ss
, List
<@NonNull TimeGraphEntry
> list
) {
282 super.addToEntryList(trace
, list
);
283 synchronized (fSSEntryListMap
) {
284 List
<@NonNull TimeGraphEntry
> entryList
= fSSEntryListMap
.get(ss
);
285 if (entryList
== null) {
286 fSSEntryListMap
.put(ss
, new CopyOnWriteArrayList
<>(list
));
288 entryList
.addAll(list
);
290 fTraceSSMap
.put(trace
, ss
);
295 * Removes a list of entries from a trace's entry list
302 * the list of time graph entries to remove
304 protected void removeFromEntryList(ITmfTrace trace
, ITmfStateSystem ss
, List
<TimeGraphEntry
> list
) {
305 super.removeFromEntryList(trace
, list
);
306 synchronized (fSSEntryListMap
) {
307 List
<TimeGraphEntry
> entryList
= fSSEntryListMap
.get(ss
);
308 if (entryList
!= null) {
309 entryList
.removeAll(list
);
310 if (entryList
.isEmpty()) {
311 fTraceSSMap
.remove(trace
, ss
);
318 protected @Nullable ZoomThread
createZoomThread(long startTime
, long endTime
, long resolution
, boolean restart
) {
319 List
<ITmfStateSystem
> ssList
= null;
320 synchronized (fSSEntryListMap
) {
321 ssList
= new ArrayList
<>(fTraceSSMap
.get(getTrace()));
323 if (ssList
.isEmpty()) {
326 return new ZoomThreadByTime(ssList
, startTime
, endTime
, resolution
, restart
);
330 * Query the state system full state for the given time range.
341 * The progress monitor
345 protected void queryFullStates(ITmfStateSystem ss
, long start
, long end
, long resolution
,
346 @NonNull IProgressMonitor monitor
, @NonNull IQueryHandler handler
) {
347 List
<List
<ITmfStateInterval
>> fullStates
= new ArrayList
<>();
348 List
<ITmfStateInterval
> prevFullState
= null;
352 if (monitor
.isCanceled()) {
355 List
<ITmfStateInterval
> fullState
= ss
.queryFullState(time
);
356 fullStates
.add(fullState
);
357 if (fullStates
.size() * fullState
.size() > MAX_INTERVALS
) {
358 handler
.handle(fullStates
, prevFullState
);
359 prevFullState
= fullStates
.get(fullStates
.size() - 1);
365 time
= Math
.min(end
, time
+ resolution
);
367 if (fullStates
.size() > 0) {
368 handler
.handle(fullStates
, prevFullState
);
370 } catch (StateSystemDisposedException e
) {
376 * Gets the list of events for an entry for a given list of full states.
378 * Called from the ZoomThread for every entry to update the zoomed event
379 * list. Can be an empty implementation if the view does not support zoomed
380 * event lists. Can also be used to compute the full event list.
383 * The time graph entry
387 * A list of full states
388 * @param prevFullState
389 * The previous full state, or null
392 * @return The list of time graph events
394 protected abstract @Nullable List
<ITimeEvent
> getEventList(@NonNull TimeGraphEntry tgentry
, ITmfStateSystem ss
,
395 @NonNull List
<List
<ITmfStateInterval
>> fullStates
, @Nullable List
<ITmfStateInterval
> prevFullState
, @NonNull IProgressMonitor monitor
);
398 * Gets the list of links (displayed as arrows) for a given list of full
399 * states. The default implementation returns an empty list.
404 * A list of full states
405 * @param prevFullState
406 * The previous full state, or null
409 * @return The list of link events
412 protected @NonNull List
<ILinkEvent
> getLinkList(ITmfStateSystem ss
,
413 @NonNull List
<List
<ITmfStateInterval
>> fullStates
, @Nullable List
<ITmfStateInterval
> prevFullState
, @NonNull IProgressMonitor monitor
) {
414 return new ArrayList
<>();
418 * Gets the list of markers for a given list of full
419 * states. The default implementation returns an empty list.
424 * A list of full states
425 * @param prevFullState
426 * The previous full state, or null
429 * @return The list of marker events
432 protected @NonNull List
<IMarkerEvent
> getViewMarkerList(ITmfStateSystem ss
,
433 @NonNull List
<List
<ITmfStateInterval
>> fullStates
, @Nullable List
<ITmfStateInterval
> prevFullState
, @NonNull IProgressMonitor monitor
) {
434 return new ArrayList
<>();
438 * @deprecated The subclass should call {@link #getEntryList(ITmfStateSystem)} instead.
442 protected final List
<TimeGraphEntry
> getEntryList(ITmfTrace trace
) {
443 throw new UnsupportedOperationException();
447 * @deprecated The subclass should call {@link #addToEntryList(ITmfTrace, ITmfStateSystem, List)} instead.
451 protected final void addToEntryList(ITmfTrace trace
, List
<TimeGraphEntry
> list
) {
452 throw new UnsupportedOperationException();
456 * @deprecated The subclass should call {@link #putEntryList(ITmfTrace, ITmfStateSystem, List)} instead.
460 protected final void putEntryList(ITmfTrace trace
, List
<TimeGraphEntry
> list
) {
461 throw new UnsupportedOperationException();
465 * @deprecated The subclass should call {@link #removeFromEntryList(ITmfTrace, ITmfStateSystem, List)} instead.
469 protected final void removeFromEntryList(ITmfTrace trace
, List
<TimeGraphEntry
> list
) {
470 throw new UnsupportedOperationException();
474 * @deprecated The subclass should implement {@link #getEventList(TimeGraphEntry, ITmfStateSystem, List, List, IProgressMonitor)} instead.
478 protected final List
<ITimeEvent
> getEventList(TimeGraphEntry entry
, long startTime
, long endTime
, long resolution
, IProgressMonitor monitor
) {
479 throw new UnsupportedOperationException();
483 * @deprecated The subclass should implement {@link #getLinkList(ITmfStateSystem, List, List, IProgressMonitor)} instead.
487 protected final List
<ILinkEvent
> getLinkList(long startTime
, long endTime
, long resolution
, IProgressMonitor monitor
) {
488 throw new UnsupportedOperationException();
492 * @deprecated The subclass should implement {@link #getViewMarkerList(ITmfStateSystem, List, List, IProgressMonitor)} instead.
496 protected final List
<IMarkerEvent
> getViewMarkerList(long startTime
, long endTime
, long resolution
, IProgressMonitor monitor
) {
497 throw new UnsupportedOperationException();
501 protected void resetView(ITmfTrace viewTrace
) {
502 // Don't remove super call
503 super.resetView(viewTrace
);
504 synchronized (fSSEntryListMap
) {
505 for (ITmfStateSystem ss
: fTraceSSMap
.removeAll(viewTrace
)) {
506 fSSEntryListMap
.remove(ss
);