tmf: Support dynamic marker event sources
[deliverable/tracecompass.git] / tmf / org.eclipse.tracecompass.tmf.ui / src / org / eclipse / tracecompass / tmf / ui / views / timegraph / AbstractStateSystemTimeGraphView.java
1 /*******************************************************************************
2 * Copyright (c) 2015, 2016 Ericsson
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 * Contributors:
10 * Patrick Tasse - Initial API and implementation
11 *******************************************************************************/
12
13 package org.eclipse.tracecompass.tmf.ui.views.timegraph;
14
15 import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
16
17 import java.util.ArrayList;
18 import java.util.HashMap;
19 import java.util.List;
20 import java.util.Map;
21 import java.util.concurrent.CopyOnWriteArrayList;
22 import java.util.logging.Logger;
23
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;
37
38 import com.google.common.collect.HashMultimap;
39 import com.google.common.collect.Multimap;
40
41 /**
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
45 * system queries.
46 *
47 * @since 1.1
48 */
49 public abstract class AbstractStateSystemTimeGraphView extends AbstractTimeGraphView {
50
51 // ------------------------------------------------------------------------
52 // Constants
53 // ------------------------------------------------------------------------
54
55 private static final long MAX_INTERVALS = 1000000;
56
57 // ------------------------------------------------------------------------
58 // Fields
59 // ------------------------------------------------------------------------
60
61 /** The state system to entry list hash map */
62 private final Map<ITmfStateSystem, List<@NonNull TimeGraphEntry>> fSSEntryListMap = new HashMap<>();
63
64 /** The trace to state system multi map */
65 private final Multimap<ITmfTrace, ITmfStateSystem> fTraceSSMap = HashMultimap.create();
66
67 private static final Logger LOGGER = TraceCompassLog.getLogger(AbstractStateSystemTimeGraphView.class);
68
69 // ------------------------------------------------------------------------
70 // Classes
71 // ------------------------------------------------------------------------
72
73 /**
74 * Handler for state system queries
75 */
76 public interface IQueryHandler {
77 /**
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.
82 *
83 * @param fullStates
84 * the list of full states
85 * @param prevFullState
86 * the previous full state, or null
87 */
88 void handle(@NonNull List<List<ITmfStateInterval>> fullStates, @Nullable List<ITmfStateInterval> prevFullState);
89 }
90
91 private class ZoomThreadByTime extends ZoomThread {
92 private final @NonNull List<ITmfStateSystem> fZoomSSList;
93 private boolean fClearZoomedLists;
94
95 public ZoomThreadByTime(@NonNull List<ITmfStateSystem> ssList, long startTime, long endTime, long resolution, boolean restart) {
96 super(startTime, endTime, resolution);
97 fZoomSSList = ssList;
98 fClearZoomedLists = !restart;
99 }
100
101 @Override
102 public void doRun() {
103 final List<ILinkEvent> links = new ArrayList<>();
104 final List<IMarkerEvent> markers = new ArrayList<>();
105 if (fClearZoomedLists) {
106 clearZoomedLists();
107 }
108 for (ITmfStateSystem ss : fZoomSSList) {
109 List<TimeGraphEntry> entryList = null;
110 synchronized (fSSEntryListMap) {
111 entryList = fSSEntryListMap.get(ss);
112 }
113 if (entryList != null) {
114 zoomByTime(ss, entryList, links, markers, getZoomStartTime(), getZoomEndTime(), getResolution(), getMonitor());
115 }
116 }
117 if (!getMonitor().isCanceled()) {
118 /* Refresh the trace-specific markers when zooming */
119 markers.addAll(getTraceMarkerList(getZoomStartTime(), getZoomEndTime(), getResolution(), getMonitor()));
120 applyResults(() -> {
121 getTimeGraphViewer().setLinks(links);
122 getTimeGraphViewer().setMarkerCategories(getMarkerCategories());
123 getTimeGraphViewer().setMarkers(markers);
124 });
125 } else {
126 LOGGER.info(() -> "[TimeGraphView:ZoomThreadCanceled]"); //$NON-NLS-1$
127 }
128 }
129
130 @Override
131 public void cancel() {
132 super.cancel();
133 if (fClearZoomedLists) {
134 clearZoomedLists();
135 }
136 }
137
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();
143 if (end < start) {
144 return;
145 }
146 if (fullRange) {
147 redraw();
148 }
149 queryFullStates(ss, start, end, resolution, monitor, new IQueryHandler() {
150 @Override
151 public void handle(@NonNull List<List<ITmfStateInterval>> fullStates, @Nullable List<ITmfStateInterval> prevFullState) {
152 LOGGER.config(() -> "[TimeGraphView:ZoomThreadGettingStates]"); //$NON-NLS-1$
153 if (!fullRange) {
154 for (TimeGraphEntry entry : entryList) {
155 zoom(checkNotNull(entry), ss, fullStates, prevFullState, monitor);
156 }
157 }
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$
165 }
166 });
167 refresh();
168 }
169
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) {
173 applyResults(() -> {
174 for (ITimeEvent event : eventList) {
175 if (monitor.isCanceled()) {
176 return;
177 }
178 entry.addZoomedEvent(event);
179 }
180 });
181 }
182 for (TimeGraphEntry child : entry.getChildren()) {
183 if (monitor.isCanceled()) {
184 LOGGER.info(() -> "[TimeGraphView:ZoomThreadCanceled]"); //$NON-NLS-1$
185 return;
186 }
187 zoom(child, ss, fullStates, prevFullState, monitor);
188 }
189 }
190
191 private void clearZoomedLists() {
192 for (ITmfStateSystem ss : fZoomSSList) {
193 List<TimeGraphEntry> entryList = null;
194 synchronized (fSSEntryListMap) {
195 entryList = fSSEntryListMap.get(ss);
196 }
197 if (entryList != null) {
198 for (TimeGraphEntry entry : entryList) {
199 clearZoomedList(entry);
200 }
201 }
202 }
203 fClearZoomedLists = false;
204 }
205
206 private void clearZoomedList(TimeGraphEntry entry) {
207 entry.setZoomedEventList(null);
208 for (TimeGraphEntry child : entry.getChildren()) {
209 clearZoomedList(child);
210 }
211 }
212 }
213
214 // ------------------------------------------------------------------------
215 // Constructors
216 // ------------------------------------------------------------------------
217
218 /**
219 * Constructs a time graph view that contains either a time graph viewer or
220 * a time graph combo.
221 *
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)}.
225 *
226 * @param id
227 * The id of the view
228 * @param pres
229 * The presentation provider
230 */
231 public AbstractStateSystemTimeGraphView(String id, TimeGraphPresentationProvider pres) {
232 super(id, pres);
233 }
234
235 // ------------------------------------------------------------------------
236 // Internal
237 // ------------------------------------------------------------------------
238
239 /**
240 * Gets the entry list for a state system
241 *
242 * @param ss
243 * the state system
244 *
245 * @return the entry list map
246 */
247 protected List<@NonNull TimeGraphEntry> getEntryList(ITmfStateSystem ss) {
248 synchronized (fSSEntryListMap) {
249 return fSSEntryListMap.get(ss);
250 }
251 }
252
253 /**
254 * Adds a trace entry list to the entry list map
255 *
256 * @param trace
257 * the trace
258 * @param ss
259 * the state system
260 * @param list
261 * the list of time graph entries
262 */
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);
268 }
269 }
270
271 /**
272 * Adds a list of entries to a trace's entry list
273 *
274 * @param trace
275 * the trace
276 * @param ss
277 * the state system
278 * @param list
279 * the list of time graph entries to add
280 */
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));
287 } else {
288 entryList.addAll(list);
289 }
290 fTraceSSMap.put(trace, ss);
291 }
292 }
293
294 /**
295 * Removes a list of entries from a trace's entry list
296 *
297 * @param trace
298 * the trace
299 * @param ss
300 * the state system
301 * @param list
302 * the list of time graph entries to remove
303 */
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);
312 }
313 }
314 }
315 }
316
317 @Override
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()));
322 }
323 if (ssList.isEmpty()) {
324 return null;
325 }
326 return new ZoomThreadByTime(ssList, startTime, endTime, resolution, restart);
327 }
328
329 /**
330 * Query the state system full state for the given time range.
331 *
332 * @param ss
333 * The state system
334 * @param start
335 * The start time
336 * @param end
337 * The end time
338 * @param resolution
339 * The resolution
340 * @param monitor
341 * The progress monitor
342 * @param handler
343 * The query handler
344 */
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;
349 try {
350 long time = start;
351 while (true) {
352 if (monitor.isCanceled()) {
353 break;
354 }
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);
360 fullStates.clear();
361 }
362 if (time >= end) {
363 break;
364 }
365 time = Math.min(end, time + resolution);
366 }
367 if (fullStates.size() > 0) {
368 handler.handle(fullStates, prevFullState);
369 }
370 } catch (StateSystemDisposedException e) {
371 /* Ignored */
372 }
373 }
374
375 /**
376 * Gets the list of events for an entry for a given list of full states.
377 * <p>
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.
381 *
382 * @param tgentry
383 * The time graph entry
384 * @param ss
385 * The state system
386 * @param fullStates
387 * A list of full states
388 * @param prevFullState
389 * The previous full state, or null
390 * @param monitor
391 * A progress monitor
392 * @return The list of time graph events
393 */
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);
396
397 /**
398 * Gets the list of links (displayed as arrows) for a given list of full
399 * states. The default implementation returns an empty list.
400 *
401 * @param ss
402 * The state system
403 * @param fullStates
404 * A list of full states
405 * @param prevFullState
406 * The previous full state, or null
407 * @param monitor
408 * A progress monitor
409 * @return The list of link events
410 * @since 2.0
411 */
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<>();
415 }
416
417 /**
418 * Gets the list of markers for a given list of full
419 * states. The default implementation returns an empty list.
420 *
421 * @param ss
422 * The state system
423 * @param fullStates
424 * A list of full states
425 * @param prevFullState
426 * The previous full state, or null
427 * @param monitor
428 * A progress monitor
429 * @return The list of marker events
430 * @since 2.0
431 */
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<>();
435 }
436
437 /**
438 * @deprecated The subclass should call {@link #getEntryList(ITmfStateSystem)} instead.
439 */
440 @Deprecated
441 @Override
442 protected final List<TimeGraphEntry> getEntryList(ITmfTrace trace) {
443 throw new UnsupportedOperationException();
444 }
445
446 /**
447 * @deprecated The subclass should call {@link #addToEntryList(ITmfTrace, ITmfStateSystem, List)} instead.
448 */
449 @Deprecated
450 @Override
451 protected final void addToEntryList(ITmfTrace trace, List<TimeGraphEntry> list) {
452 throw new UnsupportedOperationException();
453 }
454
455 /**
456 * @deprecated The subclass should call {@link #putEntryList(ITmfTrace, ITmfStateSystem, List)} instead.
457 */
458 @Deprecated
459 @Override
460 protected final void putEntryList(ITmfTrace trace, List<TimeGraphEntry> list) {
461 throw new UnsupportedOperationException();
462 }
463
464 /**
465 * @deprecated The subclass should call {@link #removeFromEntryList(ITmfTrace, ITmfStateSystem, List)} instead.
466 */
467 @Deprecated
468 @Override
469 protected final void removeFromEntryList(ITmfTrace trace, List<TimeGraphEntry> list) {
470 throw new UnsupportedOperationException();
471 }
472
473 /**
474 * @deprecated The subclass should implement {@link #getEventList(TimeGraphEntry, ITmfStateSystem, List, List, IProgressMonitor)} instead.
475 */
476 @Deprecated
477 @Override
478 protected final List<ITimeEvent> getEventList(TimeGraphEntry entry, long startTime, long endTime, long resolution, IProgressMonitor monitor) {
479 throw new UnsupportedOperationException();
480 }
481
482 /**
483 * @deprecated The subclass should implement {@link #getLinkList(ITmfStateSystem, List, List, IProgressMonitor)} instead.
484 */
485 @Deprecated
486 @Override
487 protected final List<ILinkEvent> getLinkList(long startTime, long endTime, long resolution, IProgressMonitor monitor) {
488 throw new UnsupportedOperationException();
489 }
490
491 /**
492 * @deprecated The subclass should implement {@link #getViewMarkerList(ITmfStateSystem, List, List, IProgressMonitor)} instead.
493 */
494 @Deprecated
495 @Override
496 protected final List<IMarkerEvent> getViewMarkerList(long startTime, long endTime, long resolution, IProgressMonitor monitor) {
497 throw new UnsupportedOperationException();
498 }
499
500 @Override
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);
507 }
508 }
509 }
510 }
This page took 0.056689 seconds and 5 git commands to generate.