[Bug291070] Fix for multi-traces support at the framework level + unit tests
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf / src / org / eclipse / linuxtools / tmf / experiment / TmfExperiment.java
CommitLineData
8c8bf09f
ASL
1/*******************************************************************************
2 * Copyright (c) 2009, 2010 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 *******************************************************************************/
12
13package org.eclipse.linuxtools.tmf.experiment;
14
9f584e4c 15import java.util.Collections;
8c8bf09f
ASL
16import java.util.Vector;
17
e31e01e8
FC
18import org.eclipse.core.runtime.IProgressMonitor;
19import org.eclipse.core.runtime.IStatus;
20import org.eclipse.core.runtime.Status;
21import org.eclipse.core.runtime.jobs.Job;
fc6ccf6f 22import org.eclipse.linuxtools.tmf.component.TmfEventProvider;
8c8bf09f
ASL
23import org.eclipse.linuxtools.tmf.event.TmfEvent;
24import org.eclipse.linuxtools.tmf.event.TmfTimeRange;
25import org.eclipse.linuxtools.tmf.event.TmfTimestamp;
9aae0442
ASL
26import org.eclipse.linuxtools.tmf.request.TmfDataRequest;
27import org.eclipse.linuxtools.tmf.request.TmfEventRequest;
9f584e4c 28import org.eclipse.linuxtools.tmf.signal.TmfRangeSynchSignal;
8c8bf09f 29import org.eclipse.linuxtools.tmf.signal.TmfSignalHandler;
9f584e4c
FC
30import org.eclipse.linuxtools.tmf.trace.ITmfContext;
31import org.eclipse.linuxtools.tmf.trace.ITmfLocation;
8c8bf09f 32import org.eclipse.linuxtools.tmf.trace.ITmfTrace;
9f584e4c
FC
33import org.eclipse.linuxtools.tmf.trace.TmfCheckpoint;
34import org.eclipse.linuxtools.tmf.trace.TmfContext;
e31e01e8 35import org.eclipse.linuxtools.tmf.trace.TmfTraceUpdatedSignal;
8c8bf09f
ASL
36
37/**
38 * <b><u>TmfExperiment</u></b>
39 * <p>
40 * TmfExperiment presents a time-ordered, unified view of a set of TmfTraces
41 * that are part of a tracing experiment.
42 * <p>
43 */
fc6ccf6f 44public class TmfExperiment<T extends TmfEvent> extends TmfEventProvider<T> implements ITmfTrace {
8c8bf09f
ASL
45
46 // ------------------------------------------------------------------------
47 // Attributes
48 // ------------------------------------------------------------------------
49
50 // The currently selected experiment
e31e01e8
FC
51 private static TmfExperiment<?> fCurrentExperiment;
52
53 // The experiment ID
54 private String fExperimentId;
8c8bf09f 55
9f584e4c
FC
56 // The set of traces that constitute the experiment
57 private ITmfTrace[] fTraces;
8c8bf09f
ASL
58
59 // The total number of events
9f584e4c 60 private long fNbEvents;
8c8bf09f
ASL
61
62 // The experiment time range
63 private TmfTimeRange fTimeRange;
64
65 // The experiment reference timestamp (default: BigBang)
66 private TmfTimestamp fEpoch;
67
9f584e4c
FC
68 // The experiment index
69 private Vector<TmfCheckpoint> fCheckpoints = new Vector<TmfCheckpoint>();
70
8c8bf09f
ASL
71 // ------------------------------------------------------------------------
72 // Constructors
73 // ------------------------------------------------------------------------
74
75 /**
76 * @param type
77 * @param id
78 * @param traces
79 * @param epoch
80 * @param indexPageSize
81 */
82 public TmfExperiment(Class<T> type, String id, ITmfTrace[] traces, TmfTimestamp epoch, int indexPageSize) {
e31e01e8 83 super(type);
8c8bf09f 84
e31e01e8 85 fExperimentId = id;
9f584e4c 86 fTraces = traces;
8c8bf09f
ASL
87 fEpoch = epoch;
88 fIndexPageSize = indexPageSize;
89
90 updateNbEvents();
91 updateTimeRange();
e31e01e8 92 }
8c8bf09f
ASL
93
94 /**
95 * @param type
96 * @param id
97 * @param traces
98 */
99 public TmfExperiment(Class<T> type, String id, ITmfTrace[] traces) {
100 this(type, id, traces, TmfTimestamp.Zero, DEFAULT_INDEX_PAGE_SIZE);
101 }
102
103 /**
104 * @param type
105 * @param id
106 * @param traces
107 * @param indexPageSize
108 */
109 public TmfExperiment(Class<T> type, String id, ITmfTrace[] traces, int indexPageSize) {
110 this(type, id, traces, TmfTimestamp.Zero, indexPageSize);
111 }
e31e01e8 112
8c8bf09f 113 /**
e31e01e8 114 *
8c8bf09f
ASL
115 */
116 @Override
e31e01e8 117 public void deregister() {
9f584e4c
FC
118 fTraces = null;
119 fCheckpoints.clear();
e31e01e8
FC
120 fCurrentExperiment= null;
121 super.deregister();
8c8bf09f
ASL
122 }
123
9f584e4c
FC
124 // ------------------------------------------------------------------------
125 // ITmfTrace accessors
126 // ------------------------------------------------------------------------
127
128 public String getPath() {
129 return null;
130 }
131
fc6ccf6f 132 @Override
9f584e4c
FC
133 public String getName() {
134 return fExperimentId;
135 }
136
137 public long getNbEvents() {
138 return fNbEvents;
139 }
140
141 public TmfTimeRange getTimeRange() {
142 return fTimeRange;
143 }
144
145 public TmfTimestamp getStartTime() {
146 return fTimeRange.getStartTime();
147 }
148
149 public TmfTimestamp getEndTime() {
150 return fTimeRange.getEndTime();
151 }
152
8c8bf09f 153 // ------------------------------------------------------------------------
e31e01e8 154 // Accessors
8c8bf09f
ASL
155 // ------------------------------------------------------------------------
156
e31e01e8
FC
157 public static TmfExperiment<?> getCurrentExperiment() {
158 return fCurrentExperiment;
8c8bf09f
ASL
159 }
160
8c8bf09f
ASL
161 public TmfTimestamp getEpoch() {
162 return fEpoch;
163 }
164
9f584e4c
FC
165 public ITmfTrace[] getTraces() {
166 return fTraces;
8c8bf09f
ASL
167 }
168
169 /**
170 * Returns the rank of the first event with the requested timestamp.
171 * If none, returns the index of the next event (if any).
172 *
85fb0e54 173 * @param timestamp
8c8bf09f
ASL
174 * @return
175 */
85fb0e54
FC
176 public long getRank(TmfTimestamp timestamp) {
177 TmfExperimentContext context = seekEvent(timestamp);
8c8bf09f
ASL
178 return context.getRank();
179 }
180
181 /**
182 * Returns the timestamp of the event at the requested index.
183 * If none, returns null.
184 *
185 * @param index
186 * @return
187 */
188 public TmfTimestamp getTimestamp(int index) {
85fb0e54
FC
189 TmfExperimentContext context = seekEvent(index);
190 TmfEvent event = parseEvent(context);
191 return (event != null) ? event.getTimestamp() : null;
8c8bf09f
ASL
192 }
193
194 // ------------------------------------------------------------------------
195 // Operators
196 // ------------------------------------------------------------------------
197
9f584e4c
FC
198// /**
199// * Add a trace to the experiment trace set
200// *
201// * @param trace
202// */
203// public void addTrace(ITmfTrace trace) {
204// fTraces.add(trace);
205// synchronized(this) {
206// updateNbEvents();
207// updateTimeRange();
208// }
209// }
e31e01e8 210
8c8bf09f
ASL
211 /**
212 * Update the total number of events
213 */
214 private void updateNbEvents() {
215 int nbEvents = 0;
216 for (ITmfTrace trace : fTraces) {
217 nbEvents += trace.getNbEvents();
218 }
219 fNbEvents = nbEvents;
220 }
221
222 /**
223 * Update the global time range
224 */
225 private void updateTimeRange() {
226 TmfTimestamp startTime = fTimeRange != null ? fTimeRange.getStartTime() : TmfTimestamp.BigCrunch;
227 TmfTimestamp endTime = fTimeRange != null ? fTimeRange.getEndTime() : TmfTimestamp.BigBang;
228
229 for (ITmfTrace trace : fTraces) {
e31e01e8
FC
230 TmfTimestamp traceStartTime = trace.getStartTime();
231 if (traceStartTime.compareTo(startTime, true) < 0)
232 startTime = traceStartTime;
233
234 TmfTimestamp traceEndTime = trace.getEndTime();
235 if (traceEndTime.compareTo(endTime, true) > 0)
236 endTime = traceEndTime;
8c8bf09f
ASL
237 }
238 fTimeRange = new TmfTimeRange(startTime, endTime);
239 }
240
241 // ------------------------------------------------------------------------
242 // TmfProvider
243 // ------------------------------------------------------------------------
244
245 @Override
fc6ccf6f 246 public ITmfContext armRequest(TmfDataRequest<T> request) {
9f584e4c
FC
247 TmfTimestamp timestamp = (request instanceof TmfEventRequest<?>) ?
248 ((TmfEventRequest<T>) request).getRange().getStartTime() : null;
249
250 TmfExperimentContext context = (timestamp != null) ?
251 seekEvent(timestamp) : seekEvent(request.getIndex());
252
8c8bf09f
ASL
253 return context;
254 }
255
256 @SuppressWarnings("unchecked")
257 @Override
258 public T getNext(ITmfContext context) {
259 if (context instanceof TmfExperimentContext) {
260 return (T) getNextEvent((TmfExperimentContext) context);
261 }
262 return null;
263 }
264
9f584e4c
FC
265 // ------------------------------------------------------------------------
266 // ITmfTrace trace positioning
267 // ------------------------------------------------------------------------
268
269 // Returns a brand new context based on the location provided
270 // Arms the event queues
271 // NOTE: This is a fine example of pathological coupling...
452ad365 272 public TmfExperimentContext seekLocation(ITmfLocation<?> location) {
9f584e4c 273 if (location instanceof TmfExperimentLocation || location == null) {
85fb0e54 274 ITmfLocation<?>[] prvloc = (location != null) ? ((TmfExperimentLocation) location).getLocation() : new TmfExperimentLocation[fTraces.length];
452ad365 275 ITmfLocation<?>[] newloc = new ITmfLocation[fTraces.length];
9f584e4c
FC
276 TmfContext[] contexts = new TmfContext[fTraces.length];
277
278 TmfExperimentContext context = new TmfExperimentContext(fTraces, contexts);
279 TmfEvent[] events = context.getEvents();
280
281 long rank = 0;
282 for (int i = 0; i < fTraces.length; i++) {
85fb0e54 283 contexts[i] = fTraces[i].seekLocation(prvloc[i]);
9f584e4c
FC
284 newloc[i] = contexts[i].getLocation(); // No clone here
285 events[i] = fTraces[i].parseEvent(contexts[i]);
286 rank += contexts[i].getRank();
287 }
288 context.setLocation(new TmfExperimentLocation(newloc));
289 context.setRank(rank);
290 return context;
291 }
292 return null;
293 }
294
295 public TmfExperimentContext seekEvent(TmfTimestamp timestamp) {
8c8bf09f 296
9f584e4c
FC
297 if (timestamp == null) {
298 timestamp = TmfTimestamp.BigBang;
299 }
300
301 // First, find the right checkpoint
302 int index = Collections.binarySearch(fCheckpoints, new TmfCheckpoint(timestamp, null));
303
304 // In the very likely case that the checkpoint was not found, bsearch
305 // returns its negated would-be location (not an offset...). From that
306 // index, we can then position the stream and get the event.
307 if (index < 0) {
308 index = Math.max(0, -(index + 2));
309 }
310
311 // Position the experiment at the checkpoint
452ad365 312 ITmfLocation<?> location;
9f584e4c
FC
313 synchronized (fCheckpoints) {
314 if (fCheckpoints.size() > 0) {
315 if (index >= fCheckpoints.size()) {
316 index = fCheckpoints.size() - 1;
317 }
318 location = fCheckpoints.elementAt(index).getLocation();
319 }
320 else {
321 location = null;
322 }
323 }
324
85fb0e54
FC
325 TmfExperimentContext context = seekLocation(location);
326 context.setRank(index * fIndexPageSize);
9f584e4c
FC
327
328 // And get the event
85fb0e54 329 TmfEvent event = parseEvent(context);
9f584e4c 330 while (event != null && event.getTimestamp().compareTo(timestamp, false) < 0) {
85fb0e54
FC
331 getNextEvent(context);
332 event = parseEvent(context);
9f584e4c
FC
333 }
334
85fb0e54 335 return context;
9f584e4c 336 }
8c8bf09f 337
9f584e4c
FC
338 public TmfExperimentContext seekEvent(long rank) {
339
340 TmfExperimentContext context;
e31e01e8
FC
341 int page = 0; // The checkpoint page
342 int current = 0; // The current event index (rank)
9f584e4c 343
e31e01e8 344 // If there is no checkpoint created yet, start from the beginning
9f584e4c
FC
345 if (fCheckpoints.size() == 0) {
346 context = seekLocation(null);
e31e01e8
FC
347 }
348 else {
9f584e4c
FC
349 page = (int) rank / fIndexPageSize;
350 if (page >= fCheckpoints.size()) {
351 page = fCheckpoints.size() - 1;
e31e01e8 352 }
9f584e4c 353 context = seekLocation(fCheckpoints.elementAt(page).getLocation());
e31e01e8
FC
354 current = page * fIndexPageSize;
355 }
356
357 // Position the traces at the requested index
9f584e4c 358 while (current++ < rank) {
e31e01e8
FC
359 getNextEvent(context);
360 }
9f584e4c
FC
361
362 return context;
8c8bf09f
ASL
363 }
364
365 /**
366 * Scan the next events from all traces and return the next one
367 * in chronological order.
368 *
369 * @param context
370 * @return
371 */
9f584e4c
FC
372 public synchronized TmfEvent getNextEvent(TmfContext context) {
373 if (context instanceof TmfExperimentContext) {
374 TmfExperimentContext expContext = (TmfExperimentContext) context;
85fb0e54 375 int trace = -1;
9f584e4c 376 TmfTimestamp timestamp = TmfTimestamp.BigCrunch;
85fb0e54
FC
377 for (int i = 0; i < expContext.getTraces().length; i++) {
378 if (expContext.getEvents()[i] != null) {
379 if (expContext.getEvents()[i].getTimestamp() != null) {
380 TmfTimestamp otherTS = expContext.getEvents()[i].getTimestamp();
381 if (otherTS.compareTo(timestamp, true) < 0) {
382 trace = i;
383 timestamp = otherTS;
384 }
9f584e4c 385 }
8c8bf09f
ASL
386 }
387 }
85fb0e54
FC
388
389 if (trace >= 0) {
390 TmfContext trcloc = expContext.getContexts()[trace];
391 TmfEvent event = expContext.getTraces()[trace].getNextEvent(trcloc);
392 TmfExperimentLocation exploc = (TmfExperimentLocation) expContext.getLocation();
393 exploc.getLocation()[trace] = trcloc.getLocation().clone();
394 expContext.getEvents()[trace] = expContext.getTraces()[trace].parseEvent(trcloc);
395 expContext.updateRank(1);
396 return event;
397 }
8c8bf09f 398 }
9f584e4c 399 return null;
8c8bf09f
ASL
400 }
401
9f584e4c 402 public TmfEvent parseEvent(TmfContext context) {
85fb0e54
FC
403 if (context instanceof TmfExperimentContext) {
404 TmfExperimentContext expContext = (TmfExperimentContext) context;
405 int trace = -1;
406 TmfTimestamp timestamp = TmfTimestamp.BigCrunch;
407 for (int i = 0; i < expContext.getTraces().length; i++) {
408 if (expContext.getEvents()[i] != null) {
409 if (expContext.getEvents()[i].getTimestamp() != null) {
410 TmfTimestamp otherTS = expContext.getEvents()[i].getTimestamp();
411 if (otherTS.compareTo(timestamp, true) < 0) {
412 trace = i;
413 timestamp = otherTS;
414 }
415 }
416 }
417 }
418 if (trace >= 0) {
419 TmfContext trcloc = expContext.getContexts()[trace];
420 expContext.getEvents()[trace] = expContext.getTraces()[trace].parseEvent(trcloc);
421 return expContext.getEvents()[trace];
422 }
423 }
424 return null;
8c8bf09f
ASL
425 }
426
427 /* (non-Javadoc)
428 * @see java.lang.Object#toString()
429 */
430 @Override
431 public String toString() {
e31e01e8 432 return "[TmfExperiment (" + fExperimentId + ")]";
8c8bf09f
ASL
433 }
434
435 // ------------------------------------------------------------------------
436 // Indexing
437 // ------------------------------------------------------------------------
438
439 /*
440 * The experiment holds the globally ordered events of its set of traces.
441 * It is expected to provide access to each individual event by index i.e.
9f584e4c 442 * it must be possible to request the Nth event of the experiment.
8c8bf09f
ASL
443 *
444 * The purpose of the index is to keep the information needed to rapidly
445 * restore the traces contexts at regular intervals (every INDEX_PAGE_SIZE
446 * event).
447 */
448
449 // The index page size
450 private static final int DEFAULT_INDEX_PAGE_SIZE = 1000;
e31e01e8 451 private final int fIndexPageSize;
8c8bf09f 452
e31e01e8
FC
453 // Indicates that an indexing job is already running
454 private Boolean fIndexing = false;
455 private Boolean fIndexed = false;
8c8bf09f 456
e31e01e8
FC
457 // The indexing job
458 private IndexingJob job;
459
460 /**
461 * indexExperiment
462 *
463 * Creates the experiment index.
464 */
465 public void indexExperiment(boolean waitForCompletion) {
466
467 synchronized(fIndexing) {
468 if (fIndexed || fIndexing) {
469 // An indexing job is already running but a new request came
470 // in (probably due to a change in the trace set). The index
471 // being currently built is therefore already invalid.
472 // TODO: Cancel and restart the job
473 // TODO: Add support for dynamically adding/removing traces
474 return;
9aae0442 475 }
e31e01e8
FC
476 fIndexing = true;
477 }
8c8bf09f 478
e31e01e8
FC
479 job = new IndexingJob(fExperimentId);
480 job.schedule();
481
482 if (waitForCompletion) {
483 try {
484 job.join();
485 } catch (InterruptedException e) {
486 e.printStackTrace();
487 }
488 }
8c8bf09f 489 }
e31e01e8
FC
490
491 private class IndexingJob extends Job {
492
493 public IndexingJob(String name) {
494 super(name);
495 }
496
497 /* (non-Javadoc)
498 * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor)
499 */
500 @Override
501 protected IStatus run(IProgressMonitor monitor) {
502
503 // Minimal check
9f584e4c 504 if (fTraces.length == 0) {
e31e01e8
FC
505 fIndexing = false;
506 return Status.OK_STATUS;
507 }
508
509 monitor.beginTask("Indexing " + fExperimentId, IProgressMonitor.UNKNOWN);
510
511 int nbEvents = 0;
512 TmfTimestamp startTime = null;
513 TmfTimestamp lastTime = null;
514
9f584e4c
FC
515 // Reset the index
516 fCheckpoints = new Vector<TmfCheckpoint>();
e31e01e8
FC
517
518 try {
9f584e4c
FC
519 // Position the trace at the beginning
520 TmfExperimentContext context = seekLocation(null);
521 TmfExperimentLocation location = (TmfExperimentLocation) context.getLocation();
522
523 // Get the first event
85fb0e54 524 TmfEvent event = parseEvent(context);
9f584e4c
FC
525 if (event != null) {
526 startTime = new TmfTimestamp(event.getTimestamp());
527 }
528
529 // Index the experiment
530 while (event != null) {
531 lastTime = event.getTimestamp();
e31e01e8 532 if ((nbEvents++ % fIndexPageSize) == 0) {
9f584e4c 533 fCheckpoints.add(new TmfCheckpoint(lastTime, location.clone()));
e31e01e8
FC
534 fNbEvents = nbEvents;
535 fTimeRange = new TmfTimeRange(startTime, lastTime);
9f584e4c 536 notifyListeners(new TmfTimeRange(startTime, lastTime));
e31e01e8
FC
537
538 monitor.worked(1);
539
540 // Check monitor *after* fCheckpoints has been updated
541 if (monitor.isCanceled()) {
542 monitor.done();
543 return Status.CANCEL_STATUS;
544 }
545 }
546
547 // We will need the contexts at the next iteration
548 if ((nbEvents % fIndexPageSize) == 0) {
9f584e4c 549 location = (TmfExperimentLocation) context.getLocation();
e31e01e8
FC
550 }
551
85fb0e54
FC
552 getNextEvent(context);
553 event = parseEvent(context);
e31e01e8
FC
554 }
555
556 }
557 finally {
558 synchronized(this) {
559 fNbEvents = nbEvents;
560 fTimeRange = new TmfTimeRange(startTime, lastTime);
561 fIndexing = false;
562 fIndexed = true;
563 }
564 monitor.done();
565 }
566
9f584e4c 567// dumpCheckpoints();
e31e01e8
FC
568
569 return Status.OK_STATUS;
570 }
571 }
572
9f584e4c
FC
573 protected void notifyListeners(TmfTimeRange range) {
574 broadcast(new TmfRangeSynchSignal(this, range, null));
575 }
576
85fb0e54
FC
577// // ========================================================================
578// // Toubleshooting code
579// // ========================================================================
580//
9f584e4c 581// private void dumpCheckpoints() {
e31e01e8
FC
582// System.out.println("-----");
583// System.out.println("Checkpoints of " + fExperimentId);
9f584e4c 584// for (int i = 0; i < fCheckpoints.size(); i++) {
e31e01e8 585// System.out.println("Entry:" + i);
9f584e4c 586// TmfCheckpoint checkpoint = fCheckpoints.get(i);
85fb0e54 587//// long rank = 0;
9f584e4c
FC
588// for (int j = 0; j < fTraces.length; j++) {
589// ITmfTrace trace = fTraces[j];
590// TmfExperimentContext context = seekLocation(checkpoint.getLocation());
591// TmfContext[] traces = context.getContexts();
85fb0e54 592//// rank += context.getRank();
9f584e4c 593// TmfEvent event = fTraces[j].getNextEvent(new TmfContext(traces[j]));
e31e01e8
FC
594// System.out.println(" [" + trace.getName() + "] rank: " + context.getRank() + ", timestamp: " + event.getTimestamp());
595// assert (checkpoint.getTimestamp().compareTo(event.getTimestamp(), false) == 0);
596// }
85fb0e54 597//// System.out.println("Sum of ranks: " + rank + " (expected: " + i * fIndexPageSize + ")");
e31e01e8
FC
598// }
599// }
600
8c8bf09f
ASL
601 // ------------------------------------------------------------------------
602 // Signal handlers
603 // ------------------------------------------------------------------------
604
605 @TmfSignalHandler
951d134a 606 public void experimentSelected(TmfExperimentSelectedSignal<T> signal) {
e31e01e8
FC
607 fCurrentExperiment = signal.getExperiment();
608// if (signal.getExperiment() == this) {
609// indexExperiment(true);
610// }
8c8bf09f
ASL
611 }
612
613 @TmfSignalHandler
614 public void experimentUpdated(TmfExperimentUpdatedSignal signal) {
e31e01e8 615// indexExperiment(true);
8c8bf09f
ASL
616 }
617
618 @TmfSignalHandler
619 public void traceUpdated(TmfTraceUpdatedSignal signal) {
620 // TODO: Incremental index update
621 synchronized(this) {
622 updateNbEvents();
623 updateTimeRange();
624 }
625 broadcast(new TmfExperimentUpdatedSignal(this, this, signal.getTrace()));
626 }
627
628}
This page took 0.054267 seconds and 5 git commands to generate.