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