1 /*******************************************************************************
2 * Copyright (c) 2013 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 * Alexandre Montplaisir - Initial API and implementation
11 *******************************************************************************/
13 package org
.eclipse
.linuxtools
.tmf
.core
.trace
;
15 import java
.util
.LinkedHashMap
;
18 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfRangeSynchSignal
;
19 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfSignalHandler
;
20 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfSignalManager
;
21 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTimeSynchSignal
;
22 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTraceClosedSignal
;
23 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTraceOpenedSignal
;
24 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTraceSelectedSignal
;
25 import org
.eclipse
.linuxtools
.tmf
.core
.timestamp
.ITmfTimestamp
;
26 import org
.eclipse
.linuxtools
.tmf
.core
.timestamp
.TmfTimeRange
;
27 import org
.eclipse
.linuxtools
.tmf
.core
.timestamp
.TmfTimestamp
;
30 * Central trace manager for TMF. It tracks the currently opened traces and
31 * experiment, as well as the currently-selected timestamps and time ranges for
34 * It's a singleton class, so only one instance should exist (available via
35 * {@link #getInstance()}).
37 * @author Alexandre Montplaisir
40 public final class TmfTraceManager
{
42 // ------------------------------------------------------------------------
44 // ------------------------------------------------------------------------
46 private final Map
<ITmfTrace
, TmfTraceContext
> fTraces
;
48 /** The currently-selected trace. Should always be part of the trace map */
49 private ITmfTrace fCurrentTrace
= null;
51 // ------------------------------------------------------------------------
53 // ------------------------------------------------------------------------
55 private TmfTraceManager() {
56 fTraces
= new LinkedHashMap
<ITmfTrace
, TmfTraceContext
>();
57 TmfSignalManager
.registerVIP(this);
60 /** Singleton instance */
61 private static TmfTraceManager tm
= null;
64 * Get an instance of the trace manager.
66 * @return The trace manager
68 public static synchronized TmfTraceManager
getInstance() {
70 tm
= new TmfTraceManager();
75 // ------------------------------------------------------------------------
77 // ------------------------------------------------------------------------
80 * Return the current selected time.
82 * @return the current time stamp
84 public synchronized ITmfTimestamp
getCurrentTime() {
85 return getCurrentTraceContext().getTimestamp();
89 * Return the current selected range.
91 * @return the current time range
93 public synchronized TmfTimeRange
getCurrentRange() {
94 return getCurrentTraceContext().getTimerange();
98 * Get the currently selected trace (normally, the focused editor).
100 * @return The active trace
102 public synchronized ITmfTrace
getActiveTrace() {
103 return fCurrentTrace
;
107 * Get the currently active trace set. For a 'normal' trace, this is simply
108 * an array with only that trace in it. For trace experiments, this will be
109 * an array containing the 'real' child traces in the experiment.
111 * @return The active trace set
113 public synchronized ITmfTrace
[] getActiveTraceSet() {
114 final ITmfTrace trace
= fCurrentTrace
;
115 if (trace
instanceof TmfExperiment
) {
116 final TmfExperiment exp
= (TmfExperiment
) trace
;
117 return exp
.getTraces();
119 return new ITmfTrace
[] { trace
};
122 private TmfTraceContext
getCurrentTraceContext() {
123 TmfTraceContext curCtx
= fTraces
.get(fCurrentTrace
);
124 if (curCtx
== null) {
125 /* There are no traces opened at the moment. */
126 return TmfTraceContext
.NULL_CONTEXT
;
131 // ------------------------------------------------------------------------
133 // ------------------------------------------------------------------------
136 * Signal handler for the traceOpened signal.
139 * The incoming signal
142 public synchronized void traceOpened(final TmfTraceOpenedSignal signal
) {
143 final ITmfTrace trace
= signal
.getTrace();
144 final ITmfTimestamp startTs
= trace
.getStartTime();
146 /* Calculate the initial time range */
147 final int SCALE
= ITmfTimestamp
.NANOSECOND_SCALE
;
148 long offset
= trace
.getInitialRangeOffset().normalize(0, SCALE
).getValue();
149 long endTime
= startTs
.normalize(0, SCALE
).getValue() + offset
;
150 final TmfTimeRange startTr
= new TmfTimeRange(startTs
, new TmfTimestamp(endTime
, SCALE
));
152 final TmfTraceContext startCtx
= new TmfTraceContext(startTs
, startTr
);
154 fTraces
.put(trace
, startCtx
);
156 /* We also want to set the newly-opened trace as the active trace */
157 fCurrentTrace
= trace
;
162 * Handler for the TmfTraceSelectedSignal.
165 * The incoming signal
168 public synchronized void traceSelected(final TmfTraceSelectedSignal signal
) {
169 final ITmfTrace newTrace
= signal
.getTrace();
170 if (!fTraces
.containsKey(newTrace
)) {
171 throw new RuntimeException();
173 fCurrentTrace
= newTrace
;
177 * Signal handler for the traceClosed signal.
180 * The incoming signal
183 public synchronized void traceClosed(final TmfTraceClosedSignal signal
) {
184 TmfTraceContext ret
= fTraces
.remove(signal
.getTrace());
186 throw new RuntimeException();
188 if (fTraces
.size() == 0) {
189 fCurrentTrace
= null;
191 * In other cases, we should receive a traceSelected signal that
192 * will indicate which trace is the new one.
198 * Signal handler for the TmfTimeSynchSignal signal.
200 * The current time of *all* traces whose range contains the requested new
201 * time will be updated.
204 * The incoming signal
207 public synchronized void timeUpdated(final TmfTimeSynchSignal signal
) {
208 final ITmfTimestamp ts
= signal
.getCurrentTime();
210 for (Map
.Entry
<ITmfTrace
, TmfTraceContext
> entry
: fTraces
.entrySet()) {
211 final ITmfTrace trace
= entry
.getKey();
212 if (ts
.intersects(getValidTimeRange(trace
))) {
213 TmfTraceContext prevCtx
= entry
.getValue();
214 TmfTraceContext newCtx
= new TmfTraceContext(prevCtx
, ts
);
215 entry
.setValue(newCtx
);
221 * Signal handler for the TmfRangeSynchSignal signal.
223 * The current timestamp and timerange of *all* valid traces will be updated
224 * to the new requested times.
227 * The incoming signal
230 public synchronized void timeRangeUpdated(final TmfRangeSynchSignal signal
) {
231 final ITmfTimestamp signalTs
= signal
.getCurrentTime();
233 for (Map
.Entry
<ITmfTrace
, TmfTraceContext
> entry
: fTraces
.entrySet()) {
234 final ITmfTrace trace
= entry
.getKey();
235 final TmfTraceContext curCtx
= entry
.getValue();
237 final TmfTimeRange validTr
= getValidTimeRange(trace
);
239 /* Determine the new time stamp */
241 if (signalTs
!= null && signalTs
.intersects(validTr
)) {
244 newTs
= curCtx
.getTimestamp();
247 /* Determine the new time range */
248 TmfTimeRange targetTr
= signal
.getCurrentRange().getIntersection(validTr
);
249 TmfTimeRange newTr
= (targetTr
== null ? curCtx
.getTimerange() : targetTr
);
251 /* Update the values */
252 TmfTraceContext newCtx
= new TmfTraceContext(newTs
, newTr
);
253 entry
.setValue(newCtx
);
257 // ------------------------------------------------------------------------
259 // ------------------------------------------------------------------------
262 * Return the valid time range of a trace (not the "current time range", but
263 * the range of all possible valid timestamps).
265 * For a real trace this is the whole range of the trace. For an experiment,
266 * it goes from the start time of the earliest trace to the end time of the
270 * The trace to check for
271 * @return The valid time span, or 'null' if the trace is not valid
273 private TmfTimeRange
getValidTimeRange(ITmfTrace trace
) {
274 if (!fTraces
.containsKey(trace
)) {
275 /* Trace is not part of the currently opened traces */
278 if (!(trace
instanceof TmfExperiment
)) {
279 /* "trace" is a single trace, return its time range directly */
280 return trace
.getTimeRange();
282 final ITmfTrace
[] traces
= ((TmfExperiment
) trace
).getTraces();
283 if (traces
.length
== 0) {
284 /* We are being trolled */
287 if (traces
.length
== 1) {
288 /* Trace is an experiment with only 1 trace */
289 return traces
[0].getTimeRange();
292 * Trace is an experiment with 2+ traces, so get the earliest start and
295 ITmfTimestamp start
= traces
[0].getStartTime();
296 ITmfTimestamp end
= traces
[0].getEndTime();
297 for (int i
= 1; i
< traces
.length
; i
++) {
298 ITmfTrace curTrace
= traces
[i
];
299 if (curTrace
.getStartTime().compareTo(start
) < 0) {
300 start
= curTrace
.getStartTime();
302 if (curTrace
.getEndTime().compareTo(end
) > 0) {
303 end
= curTrace
.getEndTime();
306 return new TmfTimeRange(start
, end
);