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