tmf: Add an abstract state system time graph view
[deliverable/tracecompass.git] / tmf / org.eclipse.tracecompass.tmf.ui / src / org / eclipse / tracecompass / tmf / ui / views / timegraph / AbstractStateSystemTimeGraphView.java
CommitLineData
6ae6c5bd
PT
1/*******************************************************************************
2 * Copyright (c) 2015 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
13package org.eclipse.tracecompass.tmf.ui.views.timegraph;
14
15import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
16
17import java.util.ArrayList;
18import java.util.HashMap;
19import java.util.List;
20import java.util.Map;
21import java.util.concurrent.CopyOnWriteArrayList;
22
23import org.eclipse.core.runtime.IProgressMonitor;
24import org.eclipse.jdt.annotation.NonNull;
25import org.eclipse.jdt.annotation.Nullable;
26import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem;
27import org.eclipse.tracecompass.statesystem.core.exceptions.StateSystemDisposedException;
28import org.eclipse.tracecompass.statesystem.core.interval.ITmfStateInterval;
29import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler;
30import org.eclipse.tracecompass.tmf.core.signal.TmfTraceClosedSignal;
31import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
32import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphPresentationProvider;
33import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ILinkEvent;
34import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeEvent;
35import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeGraphEntry;
36import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.TimeGraphEntry;
37
38import com.google.common.collect.HashMultimap;
39import 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 */
49public 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<TimeGraphEntry>> fSSEntryListMap = new HashMap<>();
63
64 /** The trace to state system multi map */
65 private final Multimap<ITmfTrace, ITmfStateSystem> fTraceSSMap = HashMultimap.create();
66
67 // ------------------------------------------------------------------------
68 // Classes
69 // ------------------------------------------------------------------------
70
71 /**
72 * Handler for state system queries
73 */
74 public interface IQueryHandler {
75 /**
76 * Handle a full or partial list of full states. This can be called many
77 * times for the same query if the query result is split, in which case
78 * the previous full state is null only the first time it is called, and
79 * set to the last full state of the previous call from then on.
80 *
81 * @param fullStates
82 * the list of full states
83 * @param prevFullState
84 * the previous full state, or null
85 */
86 void handle(@NonNull List<List<ITmfStateInterval>> fullStates, @Nullable List<ITmfStateInterval> prevFullState);
87 }
88
89 private class ZoomThreadByTime extends ZoomThread {
90 private final @NonNull List<ITmfStateSystem> fZoomSSList;
91 private boolean fClearZoomedLists;
92
93 public ZoomThreadByTime(@NonNull List<ITmfStateSystem> ssList, long startTime, long endTime, long resolution, boolean restart) {
94 super(startTime, endTime, resolution);
95 fZoomSSList = ssList;
96 fClearZoomedLists = !restart;
97 }
98
99 @Override
100 public void run() {
101 final List<ILinkEvent> links = new ArrayList<>();
102 if (fClearZoomedLists) {
103 clearZoomedLists();
104 }
105 for (ITmfStateSystem ss : fZoomSSList) {
106 List<TimeGraphEntry> entryList = null;
107 synchronized (fSSEntryListMap) {
108 entryList = fSSEntryListMap.get(ss);
109 }
110 if (entryList != null) {
111 zoomByTime(ss, entryList, links, getZoomStartTime(), getZoomEndTime(), getResolution(), getMonitor());
112 }
113 }
114 if (!getMonitor().isCanceled()) {
115 getTimeGraphViewer().setLinks(links);
116 }
117 }
118
119 @Override
120 public void cancel() {
121 super.cancel();
122 if (fClearZoomedLists) {
123 clearZoomedLists();
124 }
125 }
126
127 private void zoomByTime(final ITmfStateSystem ss, final List<TimeGraphEntry> entryList, final List<ILinkEvent> links,
128 long startTime, long endTime, long resolution, final @NonNull IProgressMonitor monitor) {
129 final long start = Math.max(startTime, ss.getStartTime());
130 final long end = Math.min(endTime, ss.getCurrentEndTime());
131 final boolean fullRange = getZoomStartTime() <= getStartTime() && getZoomEndTime() >= getEndTime();
132 if (end < start) {
133 return;
134 }
135 if (fullRange) {
136 redraw();
137 }
138 queryFullStates(ss, start, end, resolution, monitor, new IQueryHandler() {
139 @Override
140 public void handle(@NonNull List<List<ITmfStateInterval>> fullStates, @Nullable List<ITmfStateInterval> prevFullState) {
141 if (!fullRange) {
142 for (TimeGraphEntry entry : entryList) {
143 zoom(checkNotNull(entry), ss, fullStates, prevFullState, monitor);
144 }
145 }
146 /* Refresh the arrows when zooming */
147 links.addAll(getLinkList(ss, fullStates, monitor));
148 }
149 });
150 refresh();
151 }
152
153 private void zoom(@NonNull TimeGraphEntry entry, ITmfStateSystem ss, @NonNull List<List<ITmfStateInterval>> fullStates, @Nullable List<ITmfStateInterval> prevFullState, @NonNull IProgressMonitor monitor) {
154 List<ITimeEvent> eventList = getEventList(entry, ss, fullStates, prevFullState, monitor);
155 if (eventList != null) {
156 for (ITimeEvent event : eventList) {
157 entry.addZoomedEvent(event);
158 }
159 }
160 for (ITimeGraphEntry child : entry.getChildren()) {
161 if (monitor.isCanceled()) {
162 return;
163 }
164 if (child instanceof TimeGraphEntry) {
165 zoom((TimeGraphEntry) child, ss, fullStates, prevFullState, monitor);
166 }
167 }
168 }
169
170 private void clearZoomedLists() {
171 for (ITmfStateSystem ss : fZoomSSList) {
172 List<TimeGraphEntry> entryList = null;
173 synchronized (fSSEntryListMap) {
174 entryList = fSSEntryListMap.get(ss);
175 }
176 if (entryList != null) {
177 for (TimeGraphEntry entry : entryList) {
178 clearZoomedList(entry);
179 }
180 }
181 }
182 fClearZoomedLists = false;
183 }
184
185 private void clearZoomedList(TimeGraphEntry entry) {
186 entry.setZoomedEventList(null);
187 for (ITimeGraphEntry child : entry.getChildren()) {
188 if (child instanceof TimeGraphEntry) {
189 clearZoomedList((TimeGraphEntry) child);
190 }
191 }
192 }
193 }
194
195 // ------------------------------------------------------------------------
196 // Constructors
197 // ------------------------------------------------------------------------
198
199 /**
200 * Constructs a time graph view that contains either a time graph viewer or
201 * a time graph combo.
202 *
203 * By default, the view uses a time graph viewer. To use a time graph combo,
204 * the subclass constructor must call {@link #setTreeColumns(String[])} and
205 * {@link #setTreeLabelProvider(TreeLabelProvider)}.
206 *
207 * @param id
208 * The id of the view
209 * @param pres
210 * The presentation provider
211 */
212 public AbstractStateSystemTimeGraphView(String id, TimeGraphPresentationProvider pres) {
213 super(id, pres);
214 }
215
216 // ------------------------------------------------------------------------
217 // Internal
218 // ------------------------------------------------------------------------
219
220 /**
221 * Gets the entry list for a state system
222 *
223 * @param ss
224 * the state system
225 *
226 * @return the entry list map
227 */
228 protected List<TimeGraphEntry> getEntryList(ITmfStateSystem ss) {
229 synchronized (fSSEntryListMap) {
230 return fSSEntryListMap.get(ss);
231 }
232 }
233
234 /**
235 * Adds a trace entry list to the entry list map
236 *
237 * @param trace
238 * the trace
239 * @param ss
240 * the state system
241 * @param list
242 * the list of time graph entries
243 */
244 protected void putEntryList(ITmfTrace trace, ITmfStateSystem ss, List<TimeGraphEntry> list) {
245 super.putEntryList(trace, list);
246 synchronized (fSSEntryListMap) {
247 fSSEntryListMap.put(ss, new CopyOnWriteArrayList<>(list));
248 fTraceSSMap.put(trace, ss);
249 }
250 }
251
252 /**
253 * Adds a list of entries to a trace's entry list
254 *
255 * @param trace
256 * the trace
257 * @param ss
258 * the state system
259 * @param list
260 * the list of time graph entries to add
261 */
262 protected void addToEntryList(ITmfTrace trace, ITmfStateSystem ss, List<TimeGraphEntry> list) {
263 super.addToEntryList(trace, list);
264 synchronized (fSSEntryListMap) {
265 List<TimeGraphEntry> entryList = fSSEntryListMap.get(ss);
266 if (entryList == null) {
267 fSSEntryListMap.put(ss, new CopyOnWriteArrayList<>(list));
268 } else {
269 entryList.addAll(list);
270 }
271 fTraceSSMap.put(trace, ss);
272 }
273 }
274
275 /**
276 * Removes a list of entries from a trace's entry list
277 *
278 * @param trace
279 * the trace
280 * @param ss
281 * the state system
282 * @param list
283 * the list of time graph entries to remove
284 */
285 protected void removeFromEntryList(ITmfTrace trace, ITmfStateSystem ss, List<TimeGraphEntry> list) {
286 super.removeFromEntryList(trace, list);
287 synchronized (fSSEntryListMap) {
288 List<TimeGraphEntry> entryList = fSSEntryListMap.get(ss);
289 if (entryList != null) {
290 entryList.removeAll(list);
291 if (entryList.isEmpty()) {
292 fTraceSSMap.remove(trace, ss);
293 }
294 }
295 }
296 }
297
298 @Override
299 protected @Nullable ZoomThread createZoomThread(long startTime, long endTime, long resolution, boolean restart) {
300 List<ITmfStateSystem> ssList = null;
301 synchronized (fSSEntryListMap) {
302 ssList = new ArrayList<>(fTraceSSMap.get(getTrace()));
303 }
304 if (ssList.isEmpty()) {
305 return null;
306 }
307 return new ZoomThreadByTime(ssList, startTime, endTime, resolution, restart);
308 }
309
310 /**
311 * Query the state system full state for the given time range.
312 *
313 * @param ss
314 * The state system
315 * @param start
316 * The start time
317 * @param end
318 * The end time
319 * @param resolution
320 * The resolution
321 * @param monitor
322 * The progress monitor
323 * @param handler
324 * The query handler
325 */
326 protected void queryFullStates(ITmfStateSystem ss, long start, long end, long resolution,
327 @NonNull IProgressMonitor monitor, @NonNull IQueryHandler handler) {
328 List<List<ITmfStateInterval>> fullStates = new ArrayList<>();
329 List<ITmfStateInterval> prevFullState = null;
330 try {
331 long time = start;
332 while (true) {
333 if (monitor.isCanceled()) {
334 break;
335 }
336 List<ITmfStateInterval> fullState = ss.queryFullState(time);
337 fullStates.add(fullState);
338 if (fullStates.size() * fullState.size() > MAX_INTERVALS) {
339 handler.handle(fullStates, prevFullState);
340 prevFullState = fullStates.get(fullStates.size() - 1);
341 fullStates.clear();
342 }
343 if (time >= end) {
344 break;
345 }
346 time = Math.min(end, time + resolution);
347 }
348 if (fullStates.size() > 0) {
349 handler.handle(fullStates, prevFullState);
350 }
351 } catch (StateSystemDisposedException e) {
352 /* Ignored */
353 }
354 }
355
356 /**
357 * Gets the list of events for an entry for a given list of full states.
358 *
359 * @param tgentry
360 * The time graph entry
361 * @param ss
362 * The state system
363 * @param fullStates
364 * A list of full states
365 * @param prevFullState
366 * The previous full state, or null
367 * @param monitor
368 * A progress monitor
369 * @return The list of time graph events
370 * @since 1.1
371 */
372 protected abstract @Nullable List<ITimeEvent> getEventList(@NonNull TimeGraphEntry tgentry, ITmfStateSystem ss,
373 @NonNull List<List<ITmfStateInterval>> fullStates, @Nullable List<ITmfStateInterval> prevFullState, @NonNull IProgressMonitor monitor);
374
375 /**
376 * Gets the list of links (displayed as arrows) for a given list of full
377 * states. The default implementation returns an empty list.
378 *
379 * @param ss
380 * The state system
381 * @param fullStates
382 * A list of full states
383 * @param monitor
384 * A progress monitor
385 * @return The list of link events
386 */
387 protected @NonNull List<ILinkEvent> getLinkList(ITmfStateSystem ss,
388 @NonNull List<List<ITmfStateInterval>> fullStates, @NonNull IProgressMonitor monitor) {
389 return new ArrayList<>();
390 }
391
392 /**
393 * @deprecated The subclass should call {@link #getEntryList(ITmfStateSystem)} instead.
394 */
395 @Deprecated
396 @Override
397 protected final List<TimeGraphEntry> getEntryList(ITmfTrace trace) {
398 throw new UnsupportedOperationException();
399 }
400
401 /**
402 * @deprecated The subclass should call {@link #addToEntryList(ITmfTrace, ITmfStateSystem, List)} instead.
403 */
404 @Deprecated
405 @Override
406 protected final void addToEntryList(ITmfTrace trace, List<TimeGraphEntry> list) {
407 throw new UnsupportedOperationException();
408 }
409
410 /**
411 * @deprecated The subclass should call {@link #putEntryList(ITmfTrace, ITmfStateSystem, List)} instead.
412 */
413 @Deprecated
414 @Override
415 protected final void putEntryList(ITmfTrace trace, List<TimeGraphEntry> list) {
416 throw new UnsupportedOperationException();
417 }
418
419 /**
420 * @deprecated The subclass should call {@link #removeFromEntryList(ITmfTrace, ITmfStateSystem, List)} instead.
421 */
422 @Deprecated
423 @Override
424 protected final void removeFromEntryList(ITmfTrace trace, List<TimeGraphEntry> list) {
425 throw new UnsupportedOperationException();
426 }
427
428 /**
429 * @deprecated The subclass should implement {@link #getEventList(TimeGraphEntry, ITmfStateSystem, List, List, IProgressMonitor)} instead.
430 */
431 @Deprecated
432 @Override
433 protected final List<ITimeEvent> getEventList(TimeGraphEntry entry, long startTime, long endTime, long resolution, IProgressMonitor monitor) {
434 throw new UnsupportedOperationException();
435 }
436
437 /**
438 * @deprecated The subclass should implement {@link #getLinkList(ITmfStateSystem, List, IProgressMonitor)} instead.
439 */
440 @Deprecated
441 @Override
442 protected final List<ILinkEvent> getLinkList(long startTime, long endTime, long resolution, IProgressMonitor monitor) {
443 throw new UnsupportedOperationException();
444 }
445
446 // ------------------------------------------------------------------------
447 // Signal handlers
448 // ------------------------------------------------------------------------
449
450 @TmfSignalHandler
451 @Override
452 public void traceClosed(final TmfTraceClosedSignal signal) {
453 super.traceClosed(signal);
454 synchronized (fSSEntryListMap) {
455 for (ITmfStateSystem ss : fTraceSSMap.removeAll(signal.getTrace())) {
456 fSSEntryListMap.remove(ss);
457 }
458 }
459 }
460}
This page took 0.041808 seconds and 5 git commands to generate.