Merge branch 'master' into TmfTrace-new
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.core / src / org / eclipse / linuxtools / tmf / core / trace / TmfExperiment.java
1 /*******************************************************************************
2 * Copyright (c) 2009, 2010, 2012 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 * Francois Chouinard - Initial API and implementation
11 * Francois Chouinard - Updated as per TMF Trace Model 1.0
12 *******************************************************************************/
13
14 package org.eclipse.linuxtools.tmf.core.trace;
15
16 import org.eclipse.core.resources.IFile;
17 import org.eclipse.core.resources.IProject;
18 import org.eclipse.core.resources.IResource;
19 import org.eclipse.linuxtools.internal.tmf.core.trace.TmfExperimentContext;
20 import org.eclipse.linuxtools.internal.tmf.core.trace.TmfExperimentLocation;
21 import org.eclipse.linuxtools.internal.tmf.core.trace.TmfLocationArray;
22 import org.eclipse.linuxtools.tmf.core.event.ITmfEvent;
23 import org.eclipse.linuxtools.tmf.core.event.ITmfTimestamp;
24 import org.eclipse.linuxtools.tmf.core.event.TmfTimeRange;
25 import org.eclipse.linuxtools.tmf.core.event.TmfTimestamp;
26 import org.eclipse.linuxtools.tmf.core.exceptions.TmfTraceException;
27 import org.eclipse.linuxtools.tmf.core.signal.TmfEndSynchSignal;
28 import org.eclipse.linuxtools.tmf.core.signal.TmfExperimentDisposedSignal;
29 import org.eclipse.linuxtools.tmf.core.signal.TmfExperimentRangeUpdatedSignal;
30 import org.eclipse.linuxtools.tmf.core.signal.TmfExperimentSelectedSignal;
31 import org.eclipse.linuxtools.tmf.core.signal.TmfExperimentUpdatedSignal;
32 import org.eclipse.linuxtools.tmf.core.signal.TmfSignalHandler;
33 import org.eclipse.linuxtools.tmf.core.signal.TmfTraceUpdatedSignal;
34
35 /**
36 * TmfExperiment presents a time-ordered, unified view of a set of ITmfTrace:s
37 * that are part of a tracing experiment.
38 */
39 public class TmfExperiment<T extends ITmfEvent> extends TmfTrace<T> implements ITmfEventParser<T> {
40
41 // ------------------------------------------------------------------------
42 // Constants
43 // ------------------------------------------------------------------------
44
45 /**
46 * The default index page size
47 */
48 public static final int DEFAULT_INDEX_PAGE_SIZE = 5000;
49
50 // ------------------------------------------------------------------------
51 // Attributes
52 // ------------------------------------------------------------------------
53
54 /**
55 * The currently selected experiment (null if none)
56 */
57 protected static TmfExperiment<?> fCurrentExperiment = null;
58
59 /**
60 * The set of traces that constitute the experiment
61 */
62 protected ITmfTrace<T>[] fTraces;
63
64 /**
65 * The set of traces that constitute the experiment
66 */
67 private boolean fInitialized = false;
68
69 /**
70 * The experiment bookmarks file
71 */
72 private IFile fBookmarksFile;
73
74 // ------------------------------------------------------------------------
75 // Construction
76 // ------------------------------------------------------------------------
77
78 /**
79 * @param type
80 * @param id
81 * @param traces
82 * @throws TmfTraceException
83 */
84 public TmfExperiment(final Class<T> type, final String id, final ITmfTrace<T>[] traces) {
85 this(type, id, traces, DEFAULT_INDEX_PAGE_SIZE);
86 }
87
88 /**
89 * @param type
90 * @param id
91 * @param traces
92 * @param indexPageSize
93 * @throws TmfTraceException
94 */
95 @SuppressWarnings({ "unchecked", "rawtypes" })
96 public TmfExperiment(final Class<T> type, final String path, final ITmfTrace<T>[] traces, final int indexPageSize) {
97 setCacheSize(indexPageSize);
98 setStreamingInterval(0);
99 setIndexer(new TmfCheckpointIndexer(this, indexPageSize));
100 setParser(this);
101 try {
102 super.initialize(null, path, type);
103 } catch (TmfTraceException e) {
104 e.printStackTrace();
105 }
106
107 fTraces = traces;
108 setTimeRange(TmfTimeRange.NULL_RANGE);
109 }
110
111 /**
112 * Clears the experiment
113 */
114 @Override
115 @SuppressWarnings("rawtypes")
116 public synchronized void dispose() {
117
118 final TmfExperimentDisposedSignal<T> signal = new TmfExperimentDisposedSignal<T>(this, this);
119 broadcast(signal);
120
121 if (fCurrentExperiment == this) {
122 fCurrentExperiment = null;
123 }
124
125 if (fTraces != null) {
126 for (final ITmfTrace trace : fTraces)
127 trace.dispose();
128 fTraces = null;
129 }
130 super.dispose();
131 }
132
133 // ------------------------------------------------------------------------
134 // ITmfTrace - Initializers
135 // ------------------------------------------------------------------------
136
137 /* (non-Javadoc)
138 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#validate(org.eclipse.core.resources.IProject, java.lang.String)
139 */
140 @Override
141 public boolean validate(final IProject project, final String path) {
142 return true;
143 }
144
145 /* (non-Javadoc)
146 * @see org.eclipse.linuxtools.tmf.core.trace.TmfTrace#initTrace(org.eclipse.core.resources.IResource, java.lang.String, java.lang.Class)
147 */
148 @Override
149 public void initTrace(final IResource resource, final String path, final Class<T> type) {
150 }
151
152 // ------------------------------------------------------------------------
153 // Accessors
154 // ------------------------------------------------------------------------
155
156 /**
157 * Selects the current, framework-wide, experiment
158 *
159 * @param experiment das experiment
160 */
161 public static void setCurrentExperiment(final TmfExperiment<?> experiment) {
162 if (fCurrentExperiment != null && fCurrentExperiment != experiment) {
163 fCurrentExperiment.dispose();
164 }
165 fCurrentExperiment = experiment;
166 }
167
168 /**
169 * @return das experiment
170 */
171 public static TmfExperiment<?> getCurrentExperiment() {
172 return fCurrentExperiment;
173 }
174
175 /**
176 * Get the list of traces. Handle with care...
177 *
178 * @return the experiment traces
179 */
180 public ITmfTrace<T>[] getTraces() {
181 return fTraces;
182 }
183
184 /**
185 * Returns the timestamp of the event at the requested index. If none,
186 * returns null.
187 *
188 * @param index the event index (rank)
189 * @return the corresponding event timestamp
190 */
191 public ITmfTimestamp getTimestamp(final int index) {
192 final ITmfContext context = seekEvent(index);
193 final ITmfEvent event = getNext(context);
194 return (event != null) ? event.getTimestamp() : null;
195 }
196
197 /**
198 * Set the file to be used for bookmarks on this experiment
199 *
200 * @param file the bookmarks file
201 */
202 public void setBookmarksFile(final IFile file) {
203 fBookmarksFile = file;
204 }
205
206 /**
207 * Get the file used for bookmarks on this experiment
208 *
209 * @return the bookmarks file or null if none is set
210 */
211 public IFile getBookmarksFile() {
212 return fBookmarksFile;
213 }
214
215 // ------------------------------------------------------------------------
216 // ITmfTrace trace positioning
217 // ------------------------------------------------------------------------
218
219 /* (non-Javadoc)
220 *
221 * Returns a brand new context based on the location provided and
222 * initializes the event queues
223 *
224 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#seekEvent(org.eclipse.linuxtools.tmf.core.trace.ITmfLocation)
225 */
226 @Override
227 public synchronized ITmfContext seekEvent(final ITmfLocation<?> location) {
228 // Validate the location
229 if (location != null && !(location instanceof TmfExperimentLocation)) {
230 return null; // Throw an exception?
231 }
232 // Make sure we have something to read from
233 if (fTraces == null) {
234 return null;
235 }
236
237 // Instantiate the location
238 final TmfExperimentLocation expLocation = (location == null)
239 ? new TmfExperimentLocation(new TmfLocationArray(new ITmfLocation<?>[fTraces.length]))
240 : (TmfExperimentLocation) location.clone();
241
242 // Create and populate the context's traces contexts
243 final TmfExperimentContext context = new TmfExperimentContext(new ITmfContext[fTraces.length]);
244
245 for (int i = 0; i < fTraces.length; i++) {
246 // Get the relevant trace attributes
247 final ITmfLocation<?> traceLocation = expLocation.getLocation().getLocations()[i];
248 context.getContexts()[i] = fTraces[i].seekEvent(traceLocation);
249 expLocation.getLocation().getLocations()[i] = context.getContexts()[i].getLocation().clone();
250 context.getEvents()[i] = fTraces[i].getNext(context.getContexts()[i]);
251 }
252
253 // Finalize context
254 context.setLocation(expLocation);
255 context.setLastTrace(TmfExperimentContext.NO_TRACE);
256 context.setRank(ITmfContext.UNKNOWN_RANK);
257 return (ITmfContext) context;
258 }
259
260 /* (non-Javadoc)
261 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#seekEvent(double)
262 */
263 @Override
264 public ITmfContext seekEvent(final double ratio) {
265 final ITmfContext context = seekEvent((long) (ratio * getNbEvents()));
266 return context;
267 }
268
269 /* (non-Javadoc)
270 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#getLocationRatio(org.eclipse.linuxtools.tmf.core.trace.ITmfLocation)
271 */
272 @Override
273 public double getLocationRatio(final ITmfLocation<?> location) {
274 if (location instanceof TmfExperimentLocation) {
275 return (double) seekEvent(location).getRank() / getNbEvents();
276 }
277 return 0.0;
278 }
279
280 /* (non-Javadoc)
281 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#getCurrentLocation()
282 */
283 @Override
284 public ITmfLocation<?> getCurrentLocation() {
285 ITmfLocation<?>[] locations = new ITmfLocation<?>[fTraces.length];
286 for (int i = 0; i < fTraces.length; i++) {
287 locations[i] = fTraces[i].getCurrentLocation();
288 }
289 return new TmfExperimentLocation(new TmfLocationArray(locations));
290 }
291
292 // ------------------------------------------------------------------------
293 // ITmfTrace trace positioning
294 // ------------------------------------------------------------------------
295
296 /* (non-Javadoc)
297 * @see org.eclipse.linuxtools.tmf.core.trace.TmfTrace#getNext(org.eclipse.linuxtools.tmf.core.trace.ITmfContext)
298 */
299 @Override
300 public synchronized T getNext(final ITmfContext context) {
301 final ITmfContext previousContext = (TmfExperimentContext) context.clone();
302 final T event = parseEvent(context);
303 if (event != null) {
304 updateAttributes(previousContext, event.getTimestamp());
305
306 TmfExperimentContext expContext = (TmfExperimentContext) context;
307 int trace = expContext.getLastTrace();
308 if (trace != TmfExperimentContext.NO_TRACE) {
309 TmfExperimentLocation location = (TmfExperimentLocation) expContext.getLocation();
310 location.getLocation().getLocations()[trace] = expContext.getContexts()[trace].getLocation();
311 }
312
313 context.increaseRank();
314 processEvent(event);
315 }
316 return event;
317 }
318
319 /* (non-Javadoc)
320 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfEventParser#parseEvent(org.eclipse.linuxtools.tmf.core.trace.ITmfContext)
321 */
322 @SuppressWarnings("unchecked")
323 @Override
324 public T parseEvent(ITmfContext context) {
325
326 // Validate the context
327 if (!(context instanceof TmfExperimentContext)) {
328 return null; // Throw an exception?
329 }
330
331 TmfExperimentContext expContext = (TmfExperimentContext) context;
332
333 // If an event was consumed previously, first get the next one from that trace
334 final int lastTrace = expContext.getLastTrace();
335 if (lastTrace != TmfExperimentContext.NO_TRACE) {
336 final ITmfContext traceContext = expContext.getContexts()[lastTrace];
337 expContext.getEvents()[lastTrace] = fTraces[lastTrace].getNext(traceContext);
338 expContext.setLastTrace(TmfExperimentContext.NO_TRACE);
339 }
340
341 // Scan the candidate events and identify the "next" trace to read from
342 int trace = TmfExperimentContext.NO_TRACE;
343 ITmfTimestamp timestamp = TmfTimestamp.BIG_CRUNCH;
344 for (int i = 0; i < fTraces.length; i++) {
345 final ITmfEvent event = expContext.getEvents()[i];
346 if (event != null && event.getTimestamp() != null) {
347 final ITmfTimestamp otherTS = event.getTimestamp();
348 if (otherTS.compareTo(timestamp, true) < 0) {
349 trace = i;
350 timestamp = otherTS;
351 }
352 }
353 }
354
355 T event = null;
356 if (trace != TmfExperimentContext.NO_TRACE) {
357 event = (T) expContext.getEvents()[trace];
358 }
359
360 expContext.setLastTrace(trace);
361 return event;
362 }
363
364 /* (non-Javadoc)
365 * @see java.lang.Object#toString()
366 */
367 @Override
368 @SuppressWarnings("nls")
369 public String toString() {
370 return "[TmfExperiment (" + getName() + ")]";
371 }
372
373 // ------------------------------------------------------------------------
374 // Streaming support
375 // ------------------------------------------------------------------------
376
377 private synchronized void initializeStreamingMonitor() {
378
379 if (fInitialized) {
380 return;
381 }
382 fInitialized = true;
383
384 if (getStreamingInterval() == 0) {
385 final ITmfContext context = seekEvent(0);
386 final ITmfEvent event = getNext(context);
387 if (event == null)
388 return;
389 final TmfTimeRange timeRange = new TmfTimeRange(event.getTimestamp().clone(), TmfTimestamp.BIG_CRUNCH);
390 final TmfExperimentRangeUpdatedSignal signal = new TmfExperimentRangeUpdatedSignal(this, this, timeRange);
391
392 // Broadcast in separate thread to prevent deadlock
393 new Thread() {
394 @Override
395 public void run() {
396 broadcast(signal);
397 }
398 }.start();
399 return;
400 }
401
402 final Thread thread = new Thread("Streaming Monitor for experiment " + getName()) { //$NON-NLS-1$
403 private ITmfTimestamp safeTimestamp = null;
404 private TmfTimeRange timeRange = null;
405
406 @Override
407 public void run() {
408 while (!fExecutor.isShutdown()) {
409 if (!getIndexer().isIndexing()) {
410 ITmfTimestamp startTimestamp = TmfTimestamp.BIG_CRUNCH;
411 ITmfTimestamp endTimestamp = TmfTimestamp.BIG_BANG;
412 for (final ITmfTrace<T> trace : fTraces) {
413 if (trace.getStartTime().compareTo(startTimestamp) < 0)
414 startTimestamp = trace.getStartTime();
415 if (trace.getStreamingInterval() != 0 && trace.getEndTime().compareTo(endTimestamp) > 0)
416 endTimestamp = trace.getEndTime();
417 }
418 if (safeTimestamp != null && safeTimestamp.compareTo(getTimeRange().getEndTime(), false) > 0)
419 timeRange = new TmfTimeRange(startTimestamp, safeTimestamp);
420 else
421 timeRange = null;
422 safeTimestamp = endTimestamp;
423 if (timeRange != null) {
424 final TmfExperimentRangeUpdatedSignal signal =
425 new TmfExperimentRangeUpdatedSignal(TmfExperiment.this, TmfExperiment.this, timeRange);
426 broadcast(signal);
427 }
428 }
429 try {
430 Thread.sleep(getStreamingInterval());
431 } catch (final InterruptedException e) {
432 e.printStackTrace();
433 }
434 }
435 }
436 };
437 thread.start();
438 }
439
440 /* (non-Javadoc)
441 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getStreamingInterval()
442 */
443 @Override
444 public long getStreamingInterval() {
445 long interval = 0;
446 for (final ITmfTrace<T> trace : fTraces)
447 interval = Math.max(interval, trace.getStreamingInterval());
448 return interval;
449 }
450
451 // ------------------------------------------------------------------------
452 // Signal handlers
453 // ------------------------------------------------------------------------
454
455 private Integer fEndSynchReference;
456
457 /**
458 * Signal handler for the TmfExperimentSelectedSignal signal
459 *
460 * @param signal
461 */
462 @TmfSignalHandler
463 public void experimentSelected(final TmfExperimentSelectedSignal<T> signal) {
464 final TmfExperiment<?> experiment = signal.getExperiment();
465 if (experiment == this) {
466 setCurrentExperiment(experiment);
467 fEndSynchReference = Integer.valueOf(signal.getReference());
468 }
469 }
470
471 /**
472 * Signal handler for the TmfEndSynchSignal signal
473 *
474 * @param signal
475 */
476 @TmfSignalHandler
477 public void endSync(final TmfEndSynchSignal signal) {
478 if (fEndSynchReference != null && fEndSynchReference.intValue() == signal.getReference()) {
479 fEndSynchReference = null;
480 initializeStreamingMonitor();
481 }
482 }
483
484 /**
485 * Signal handler for the TmfTraceUpdatedSignal signal
486 *
487 * @param signal
488 */
489 @TmfSignalHandler
490 public void traceUpdated(final TmfTraceUpdatedSignal signal) {
491 if (signal.getTrace() == this) {
492 broadcast(new TmfExperimentUpdatedSignal(this, this));
493 }
494 }
495
496 /**
497 * Signal handler for the TmfExperimentRangeUpdatedSignal signal
498 *
499 * @param signal
500 */
501 @TmfSignalHandler
502 public void experimentRangeUpdated(final TmfExperimentRangeUpdatedSignal signal) {
503 if (signal.getExperiment() == this) {
504 getIndexer().buildIndex(getNbEvents(), signal.getRange(), false);
505 }
506 }
507
508 }
This page took 0.052659 seconds and 6 git commands to generate.