Temporary fix to make the architecture change transparent for now (bug id 302987)
[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
15import java.util.Collections;
16import java.util.Vector;
17
8c8bf09f
ASL
18import org.eclipse.linuxtools.tmf.component.TmfEventProvider;
19import org.eclipse.linuxtools.tmf.event.TmfEvent;
20import org.eclipse.linuxtools.tmf.event.TmfTimeRange;
21import org.eclipse.linuxtools.tmf.event.TmfTimestamp;
22import org.eclipse.linuxtools.tmf.request.ITmfDataRequest;
23import org.eclipse.linuxtools.tmf.request.ITmfEventRequest;
9aae0442
ASL
24import org.eclipse.linuxtools.tmf.request.TmfDataRequest;
25import org.eclipse.linuxtools.tmf.request.TmfEventRequest;
8c8bf09f
ASL
26import org.eclipse.linuxtools.tmf.signal.TmfExperimentSelectedSignal;
27import org.eclipse.linuxtools.tmf.signal.TmfExperimentUpdatedSignal;
8c8bf09f 28import org.eclipse.linuxtools.tmf.signal.TmfSignalHandler;
9aae0442 29import org.eclipse.linuxtools.tmf.signal.TmfSignalManager;
8c8bf09f
ASL
30import org.eclipse.linuxtools.tmf.signal.TmfTraceUpdatedSignal;
31import org.eclipse.linuxtools.tmf.trace.ITmfContext;
32import org.eclipse.linuxtools.tmf.trace.ITmfLocation;
33import org.eclipse.linuxtools.tmf.trace.ITmfTrace;
34import org.eclipse.linuxtools.tmf.trace.TmfCheckpoint;
35import org.eclipse.linuxtools.tmf.trace.TmfContext;
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 */
44public class TmfExperiment<T extends TmfEvent> extends TmfEventProvider<T> implements ITmfTrace {
45
46 // ------------------------------------------------------------------------
47 // Attributes
48 // ------------------------------------------------------------------------
49
50 // The currently selected experiment
51 private static TmfExperiment<?> fCurrentExperiment = null;
52
9aae0442 53 // The set of traces that constitute the experiment
8c8bf09f
ASL
54 private ITmfTrace[] fTraces;
55
56 // The total number of events
57 private long fNbEvents;
58
59 // The experiment time range
60 private TmfTimeRange fTimeRange;
61
62 // The experiment reference timestamp (default: BigBang)
63 private TmfTimestamp fEpoch;
64
65 // The experiment index
66 private Vector<TmfCheckpoint> fCheckpoints = new Vector<TmfCheckpoint>();
67
68 // ------------------------------------------------------------------------
69 // Constructors
70 // ------------------------------------------------------------------------
71
72 /**
73 * @param type
74 * @param id
75 * @param traces
76 * @param epoch
77 * @param indexPageSize
78 */
79 public TmfExperiment(Class<T> type, String id, ITmfTrace[] traces, TmfTimestamp epoch, int indexPageSize) {
80 super(id, type);
81
82 fTraces = traces;
83 fEpoch = epoch;
84 fIndexPageSize = indexPageSize;
9aae0442 85 fClone = createTraceCopy();
8c8bf09f
ASL
86
87 updateNbEvents();
88 updateTimeRange();
9aae0442 89 }
8c8bf09f
ASL
90
91 /**
92 * @param type
93 * @param id
94 * @param traces
95 */
96 public TmfExperiment(Class<T> type, String id, ITmfTrace[] traces) {
97 this(type, id, traces, TmfTimestamp.Zero, DEFAULT_INDEX_PAGE_SIZE);
98 }
99
100 /**
101 * @param type
102 * @param id
103 * @param traces
104 * @param indexPageSize
105 */
106 public TmfExperiment(Class<T> type, String id, ITmfTrace[] traces, int indexPageSize) {
107 this(type, id, traces, TmfTimestamp.Zero, indexPageSize);
108 }
109
8c8bf09f 110 public TmfExperiment(TmfExperiment<T> other) {
9aae0442 111 super(other.getName() + "(clone)", other.fType);
8c8bf09f
ASL
112
113 fEpoch = other.fEpoch;
114 fIndexPageSize = other.fIndexPageSize;
115
116 fTraces = new ITmfTrace[other.fTraces.length];
117 for (int trace = 0; trace < other.fTraces.length; trace++) {
118 fTraces[trace] = other.fTraces[trace].createTraceCopy();
119 }
120
121 fNbEvents = other.fNbEvents;
122 fTimeRange = other.fTimeRange;
9aae0442 123 fClone = null;
8c8bf09f
ASL
124 }
125
126 public TmfExperiment<T> createTraceCopy() {
9aae0442
ASL
127 TmfExperiment<T> experiment = new TmfExperiment<T>(this);
128 TmfSignalManager.deregister(experiment);
129 return experiment;
8c8bf09f
ASL
130 }
131
132 /**
133 * Clears the experiment
134 */
135 @Override
136 public void dispose() {
9aae0442
ASL
137 for (ITmfTrace trace : fTraces) {
138 trace.dispose();
139 }
140 fTraces = null;
8c8bf09f
ASL
141 fCheckpoints.clear();
142 super.dispose();
143 }
144
145 private static void setCurrentExperiment(TmfExperiment<?> experiment) {
146 fCurrentExperiment = experiment;
147 }
148
149 // ------------------------------------------------------------------------
150 // ITmfTrace
151 // ------------------------------------------------------------------------
152
153 public String getPath() {
154 return null;
155 }
156
157 public long getNbEvents() {
158 return fNbEvents;
159 }
160
161 public int getCacheSize() {
162 return fIndexPageSize;
163 }
164
165 public TmfTimeRange getTimeRange() {
166 return fTimeRange;
167 }
168
169 public TmfTimestamp getStartTime() {
170 return fTimeRange.getStartTime();
171 }
172
173 public TmfTimestamp getEndTime() {
174 return fTimeRange.getEndTime();
175 }
176
177 public Vector<TmfCheckpoint> getCheckpoints() {
178 return fCheckpoints;
179 }
180
181 // ------------------------------------------------------------------------
182 // Accessors
183 // ------------------------------------------------------------------------
184
185 public static TmfExperiment<?> getCurrentExperiment() {
186 return fCurrentExperiment;
187 }
188
189 public TmfTimestamp getEpoch() {
190 return fEpoch;
191 }
192
193 public ITmfTrace[] getTraces() {
194 return fTraces;
195 }
196
197 /**
198 * Returns the rank of the first event with the requested timestamp.
199 * If none, returns the index of the next event (if any).
200 *
201 * @param timestamp
202 * @return
203 */
204 public long getRank(TmfTimestamp timestamp) {
205 TmfExperimentContext context = seekEvent(timestamp);
206 return context.getRank();
207 }
208
209 /**
210 * Returns the timestamp of the event at the requested index.
211 * If none, returns null.
212 *
213 * @param index
214 * @return
215 */
216 public TmfTimestamp getTimestamp(int index) {
217 TmfExperimentContext context = seekEvent(index);
218 TmfEvent event = getNextEvent(context);
219 return (event != null) ? event.getTimestamp() : null;
220 }
221
222 // ------------------------------------------------------------------------
223 // Operators
224 // ------------------------------------------------------------------------
225
226 /**
227 * Update the total number of events
228 */
229 private void updateNbEvents() {
230 int nbEvents = 0;
231 for (ITmfTrace trace : fTraces) {
232 nbEvents += trace.getNbEvents();
233 }
234 fNbEvents = nbEvents;
235 }
236
237 /**
238 * Update the global time range
239 */
240 private void updateTimeRange() {
241 TmfTimestamp startTime = fTimeRange != null ? fTimeRange.getStartTime() : TmfTimestamp.BigCrunch;
242 TmfTimestamp endTime = fTimeRange != null ? fTimeRange.getEndTime() : TmfTimestamp.BigBang;
243
244 for (ITmfTrace trace : fTraces) {
245 if (trace.getNbEvents() > 0) {
246 TmfTimestamp traceStartTime = trace.getStartTime();
247 if (traceStartTime.compareTo(startTime, true) < 0)
248 startTime = traceStartTime;
249
250 TmfTimestamp traceEndTime = trace.getEndTime();
251 if (traceEndTime.compareTo(endTime, true) > 0)
252 endTime = traceEndTime;
253 }
254 }
255 fTimeRange = new TmfTimeRange(startTime, endTime);
256 }
257
258 // ------------------------------------------------------------------------
259 // TmfProvider
260 // ------------------------------------------------------------------------
261
262 @Override
263 public ITmfContext armRequest(ITmfDataRequest<T> request) {
264 TmfTimestamp timestamp = (request instanceof ITmfEventRequest<?>) ?
265 ((ITmfEventRequest<T>) request).getRange().getStartTime() : null;
266 TmfExperimentContext context = (timestamp != null) ?
267 seekEvent(timestamp) : seekEvent(request.getIndex());
268 return context;
269 }
270
271 @SuppressWarnings("unchecked")
272 @Override
273 public T getNext(ITmfContext context) {
274 if (context instanceof TmfExperimentContext) {
275 return (T) getNextEvent((TmfExperimentContext) context);
276 }
277 return null;
278 }
279
9aae0442 280 // ------------------------------------------------------------------------
8c8bf09f
ASL
281 // ITmfTrace trace positioning
282 // ------------------------------------------------------------------------
283
284 // Returns a brand new context based on the location provided
285 // and initializes the event queues
286 public TmfExperimentContext seekLocation(ITmfLocation<?> location) {
287
288 // Validate the location
289 if (location != null && !(location instanceof TmfExperimentLocation)) {
290 return null; // Throw an exception?
291 }
292
293 // Instantiate the location
294 TmfExperimentLocation expLocation = (location == null)
295 ? new TmfExperimentLocation(new ITmfLocation<?>[fTraces.length], new long[fTraces.length])
296 : (TmfExperimentLocation) location.clone();
297
298 // Create and populate the context's traces contexts
299 TmfExperimentContext context = new TmfExperimentContext(fTraces, new TmfContext[fTraces.length]);
300 long rank = 0;
301 for (int i = 0; i < fTraces.length; i++) {
302 // Get the relevant trace attributes
303 ITmfLocation<?> traceLocation = expLocation.getLocation()[i];
304 long traceRank = expLocation.getRanks()[i];
305
306 // Set the corresponding sub-context
307 context.getContexts()[i] = fTraces[i].seekLocation(traceLocation);
308 context.getContexts()[i].setRank(traceRank);
309 rank += traceRank;
310
311 // Set the trace location and read the corresponding event
312 expLocation.getLocation()[i] = context.getContexts()[i].getLocation();
313 context.getEvents()[i] = fTraces[i].getNextEvent(context.getContexts()[i]);
314 }
315
316 // Finalize context
317 context.setLocation(expLocation);
318 context.setRank(rank);
319 context.setLastTrace(TmfExperimentContext.NO_TRACE);
320 return context;
321 }
322
323 /* (non-Javadoc)
324 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#seekEvent(org.eclipse.linuxtools.tmf.event.TmfTimestamp)
325 */
326 public TmfExperimentContext seekEvent(TmfTimestamp timestamp) {
327
328 if (timestamp == null) {
329 timestamp = TmfTimestamp.BigBang;
330 }
331
332 // First, find the right checkpoint
333 int index = Collections.binarySearch(fCheckpoints, new TmfCheckpoint(timestamp, null));
334
335 // In the very likely case that the checkpoint was not found, bsearch
336 // returns its negated would-be location (not an offset...). From that
337 // index, we can then position the stream and get the event.
338 if (index < 0) {
339 index = Math.max(0, -(index + 2));
340 }
341
342 // Position the experiment at the checkpoint
343 ITmfLocation<?> location;
344 synchronized (fCheckpoints) {
345 if (fCheckpoints.size() > 0) {
346 if (index >= fCheckpoints.size()) {
347 index = fCheckpoints.size() - 1;
348 }
349 location = fCheckpoints.elementAt(index).getLocation();
350 }
351 else {
352 location = null;
353 }
354 }
355
356 TmfExperimentContext context = seekLocation(location);
357 context.setRank((long) index * fIndexPageSize);
358
359 // And locate the event
360 TmfExperimentContext nextEventContext = new TmfExperimentContext(context);
361 TmfEvent event = getNextEvent(nextEventContext);
362 while (event != null && event.getTimestamp().compareTo(timestamp, false) < 0) {
363 context = new TmfExperimentContext(nextEventContext);
364 event = getNextEvent(nextEventContext);
365 }
366 context.setLastTrace(TmfExperimentContext.NO_TRACE);
367
368 return context;
369 }
370
371 /* (non-Javadoc)
372 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#seekEvent(long)
373 */
374 public TmfExperimentContext seekEvent(long rank) {
375
376 // Position the stream at the previous checkpoint
377 int index = (int) rank / fIndexPageSize;
378 ITmfLocation<?> location;
379 synchronized (fCheckpoints) {
380 if (fCheckpoints.size() == 0) {
381 location = null;
382 }
383 else {
384 if (index >= fCheckpoints.size()) {
385 index = fCheckpoints.size() - 1;
386 }
387 location = fCheckpoints.elementAt(index).getLocation();
388 }
389 }
390
391 TmfExperimentContext context = seekLocation(location);
392 long pos = (long) index * fIndexPageSize;
393 context.setRank(pos);
394
395 // And locate the event
396 TmfExperimentContext nextEventContext = new TmfExperimentContext(context);
397 TmfEvent event = getNextEvent(nextEventContext);
398 while (event != null && pos++ < rank) {
399 event = getNextEvent(nextEventContext);
400 context = new TmfExperimentContext(nextEventContext);
401 if (event != null) context.updateRank(-1);
402 }
403 context.setLastTrace(TmfExperimentContext.NO_TRACE);
404
405 return context;
406 }
407
408 /**
409 * Scan the next events from all traces and return the next one
410 * in chronological order.
411 *
412 * @param context
413 * @return
414 */
415 public synchronized TmfEvent getNextEvent(TmfContext context) {
416
417 // Validate the context
418 if (!(context instanceof TmfExperimentContext)) {
419 return null; // Throw an exception?
420 }
421
422 TmfExperimentContext expContext = (TmfExperimentContext) context;
423
424 // If an event was consumed previously, get the next one from that trace
425 int lastTrace = expContext.getLastTrace();
426 if (lastTrace != TmfExperimentContext.NO_TRACE) {
427 TmfContext traceContext = expContext.getContexts()[lastTrace];
428 expContext.getEvents()[lastTrace] = expContext.getTraces()[lastTrace].getNextEvent(traceContext);
429 }
430
431 // Scan the candidate events and identify the "next" trace to read from
432 int trace = TmfExperimentContext.NO_TRACE;
433 TmfTimestamp timestamp = TmfTimestamp.BigCrunch;
434 for (int i = 0; i < expContext.getTraces().length; i++) {
435 TmfEvent event = expContext.getEvents()[i];
436 if (event != null && event.getTimestamp() != null) {
437 TmfTimestamp otherTS = event.getTimestamp();
438 if (otherTS.compareTo(timestamp, true) < 0) {
439 trace = i;
440 timestamp = otherTS;
441 }
442 }
443 }
444
445 // Update the experiment context and set the "next" event
446 TmfEvent event = null;
447 if (trace >= 0) {
9aae0442 448 long savedRank = expContext.getRank();
8c8bf09f
ASL
449 expContext.setLastTrace(trace);
450 expContext.updateRank(1);
451 TmfExperimentLocation expLocation = (TmfExperimentLocation) expContext.getLocation();
452 TmfContext traceContext = expContext.getContexts()[trace];
453 expLocation.getLocation()[trace] = traceContext.getLocation().clone();
454 expLocation.getRanks()[trace] = traceContext.getRank();
455 event = expContext.getEvents()[trace];
9aae0442 456 updateIndex(expContext, savedRank, timestamp);
8c8bf09f
ASL
457 }
458
459 return event;
460 }
461
9aae0442
ASL
462 public synchronized void updateIndex(ITmfContext context, long rank, TmfTimestamp timestamp) {
463 // Build the index as we go along
464 if (context.isValidRank() && (rank % fIndexPageSize) == 0) {
465 // Determine the table position
466 long position = context.getRank() / fIndexPageSize;
467 // Add new entry at proper location (if empty)
468 if (fCheckpoints.size() == position) {
469 ITmfLocation<?> location = context.getLocation().clone();
470 fCheckpoints.add(new TmfCheckpoint(timestamp, location));
471// System.out.println(this + "[" + (fCheckpoints.size() - 1) + "] " + timestamp + ", " + location.toString());
472 }
473 }
474 }
475
8c8bf09f
ASL
476 /* (non-Javadoc)
477 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#parseEvent(org.eclipse.linuxtools.tmf.trace.TmfContext)
478 */
479 public TmfEvent parseEvent(TmfContext context) {
480
481 if (context instanceof TmfExperimentContext) {
482 TmfExperimentContext expContext = (TmfExperimentContext) context;
483 int lastTrace = expContext.getLastTrace();
484 if (lastTrace != -1) {
485 TmfContext traceContext = expContext.getContexts()[lastTrace];
486 expContext.getEvents()[lastTrace] = expContext.getTraces()[lastTrace].getNextEvent(traceContext);
487 expContext.updateRank(1);
488 TmfExperimentLocation expLocation = (TmfExperimentLocation) expContext.getLocation();
489 expLocation.getLocation()[lastTrace] = traceContext.getLocation().clone();
490 }
491
492 int trace = -1;
493 TmfTimestamp timestamp = TmfTimestamp.BigCrunch;
494 for (int i = 0; i < expContext.getTraces().length; i++) {
495 if (expContext.getEvents()[i] != null) {
496 if (expContext.getEvents()[i].getTimestamp() != null) {
497 TmfTimestamp otherTS = expContext.getEvents()[i].getTimestamp();
498 if (otherTS.compareTo(timestamp, true) < 0) {
499 trace = i;
500 timestamp = otherTS;
501 }
502 }
503 }
504 }
505 if (trace >= 0) {
506 expContext.setLastTrace(TmfExperimentContext.NO_TRACE);
507 return expContext.getEvents()[trace];
508 }
509 }
510
511 return null;
512 }
513
514 /* (non-Javadoc)
515 * @see java.lang.Object#toString()
516 */
517 @Override
518 public String toString() {
519 return "[TmfExperiment (" + getName() + ")]";
520 }
521
522 // ------------------------------------------------------------------------
523 // Indexing
524 // ------------------------------------------------------------------------
525
526 /*
527 * The experiment holds the globally ordered events of its set of traces.
528 * It is expected to provide access to each individual event by index i.e.
529 * it must be possible to request the Nth event of the experiment.
530 *
531 * The purpose of the index is to keep the information needed to rapidly
532 * restore the traces contexts at regular intervals (every INDEX_PAGE_SIZE
533 * event).
534 */
535
536 // The index page size
537 private static final int DEFAULT_INDEX_PAGE_SIZE = 1000;
9aae0442 538 private final int fIndexPageSize;
8c8bf09f 539
9aae0442
ASL
540 @SuppressWarnings("unchecked")
541 public void indexExperiment() {
542
543 final TmfExperiment<?> experiment = getCurrentExperiment();
544 fCheckpoints.clear();
545
546 ITmfEventRequest<TmfEvent> request = new TmfEventRequest<TmfEvent>(TmfEvent.class, TmfTimeRange.Eternity, TmfDataRequest.ALL_DATA, 1) {
547
548 long indexingStart = System.nanoTime();
549
550 TmfTimestamp startTime = null;
551 TmfTimestamp lastTime = null;
552 int nbEvents = 0;
553
554 @Override
555 public void handleData() {
556 TmfEvent[] events = getData();
557 if (events.length > 0) {
558 nbEvents++;
559 TmfTimestamp ts = events[0].getTimestamp();
560 if (startTime == null)
561 startTime = new TmfTimestamp(ts);
562 lastTime = new TmfTimestamp(ts);
563
564 if ((nbEvents % DEFAULT_INDEX_PAGE_SIZE) == 0) {
565 updateExperiment();
566 }
567 }
8c8bf09f 568 }
8c8bf09f 569
9aae0442
ASL
570 @Override
571 public void handleSuccess() {
572 long indexingEnd = System.nanoTime();
573
574 updateExperiment();
575// experiment.fCheckpoints = new Vector<TmfCheckpoint>();
576// for (int i = 0; i < fCheckpoints.size(); i++) {
577// TmfCheckpoint checkpoint = fCheckpoints.get(i).clone();
578// experiment.fCheckpoints.add(checkpoint);
579// System.out.println("fCheckpoints[" + i + "] " + checkpoint.getTimestamp() + ", " + checkpoint.getLocation().toString());
580// }
581
582// clone.dispose();
583// if (Tracer.INTERNALS) Tracer.trace(getName() + ": nbEvents=" + nbEvents + " (" + ((indexingEnd-indexingStart)/nbEvents)+ " ns/evt), start=" + startTime + ", end=" + lastTime);
584
585 System.out.println(getName() + ": start=" + startTime + ", end=" + lastTime + ", elapsed=" + (indexingEnd*1.0 - indexingStart) / 1000000000);
586 System.out.println(getName() + ": nbEvents=" + fNbEvents + " (" + ((indexingEnd-indexingStart)/nbEvents)+ " ns/evt)");
587// for (int i = 0; i < experiment.fCheckpoints.size(); i++) {
588// TmfCheckpoint checkpoint = experiment.fCheckpoints.get(i);
589// System.out.println("fCheckpoints[" + i + "] " + checkpoint.getTimestamp() + ", " + checkpoint.getLocation().toString());
590// }
8c8bf09f
ASL
591 }
592
9aae0442
ASL
593 private void updateExperiment() {
594 if (experiment == fCurrentExperiment)
595 experiment.fTimeRange = new TmfTimeRange(startTime, new TmfTimestamp(lastTime));
596 experiment.fNbEvents = nbEvents;
597 experiment.fCheckpoints = ((TmfExperiment<T>) fClone).fCheckpoints;
598 notifyListeners();
599 }
600 };
8c8bf09f 601
9aae0442
ASL
602 sendRequest((ITmfDataRequest<T>) request, ExecutionType.LONG);
603 }
604
605 protected void notifyListeners() {
606 broadcast(new TmfExperimentUpdatedSignal(this, this, null));
8c8bf09f
ASL
607 }
608
609 // ------------------------------------------------------------------------
610 // Signal handlers
611 // ------------------------------------------------------------------------
612
613 @TmfSignalHandler
614 public void experimentSelected(TmfExperimentSelectedSignal<T> signal) {
615 TmfExperiment<?> experiment = signal.getExperiment();
616 if (experiment == this) {
617 setCurrentExperiment(experiment);
9aae0442 618 indexExperiment();
8c8bf09f
ASL
619 }
620 else {
621 dispose();
622 }
8c8bf09f
ASL
623 }
624
625 @TmfSignalHandler
626 public void experimentUpdated(TmfExperimentUpdatedSignal signal) {
8c8bf09f
ASL
627 }
628
629 @TmfSignalHandler
630 public void traceUpdated(TmfTraceUpdatedSignal signal) {
631 // TODO: Incremental index update
632 synchronized(this) {
633 updateNbEvents();
634 updateTimeRange();
635 }
636 broadcast(new TmfExperimentUpdatedSignal(this, this, signal.getTrace()));
637 }
638
639}
This page took 0.076988 seconds and 5 git commands to generate.