1 /*******************************************************************************
2 * Copyright (c) 2009, 2010 Ericsson
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
10 * Francois Chouinard - Initial API and implementation
11 *******************************************************************************/
13 package org
.eclipse
.linuxtools
.tmf
.experiment
;
15 import java
.util
.Collections
;
16 import java
.util
.Vector
;
18 import org
.eclipse
.linuxtools
.tmf
.component
.TmfEventProvider
;
19 import org
.eclipse
.linuxtools
.tmf
.event
.TmfEvent
;
20 import org
.eclipse
.linuxtools
.tmf
.event
.TmfTimeRange
;
21 import org
.eclipse
.linuxtools
.tmf
.event
.TmfTimestamp
;
22 import org
.eclipse
.linuxtools
.tmf
.request
.ITmfDataRequest
;
23 import org
.eclipse
.linuxtools
.tmf
.request
.ITmfEventRequest
;
24 import org
.eclipse
.linuxtools
.tmf
.request
.TmfDataRequest
;
25 import org
.eclipse
.linuxtools
.tmf
.request
.TmfEventRequest
;
26 import org
.eclipse
.linuxtools
.tmf
.signal
.TmfExperimentSelectedSignal
;
27 import org
.eclipse
.linuxtools
.tmf
.signal
.TmfExperimentUpdatedSignal
;
28 import org
.eclipse
.linuxtools
.tmf
.signal
.TmfSignalHandler
;
29 import org
.eclipse
.linuxtools
.tmf
.signal
.TmfSignalManager
;
30 import org
.eclipse
.linuxtools
.tmf
.signal
.TmfTraceUpdatedSignal
;
31 import org
.eclipse
.linuxtools
.tmf
.trace
.ITmfContext
;
32 import org
.eclipse
.linuxtools
.tmf
.trace
.ITmfLocation
;
33 import org
.eclipse
.linuxtools
.tmf
.trace
.ITmfTrace
;
34 import org
.eclipse
.linuxtools
.tmf
.trace
.TmfCheckpoint
;
35 import org
.eclipse
.linuxtools
.tmf
.trace
.TmfContext
;
38 * <b><u>TmfExperiment</u></b>
40 * TmfExperiment presents a time-ordered, unified view of a set of TmfTraces
41 * that are part of a tracing experiment.
44 public class TmfExperiment
<T
extends TmfEvent
> extends TmfEventProvider
<T
> implements ITmfTrace
{
46 // ------------------------------------------------------------------------
48 // ------------------------------------------------------------------------
50 // The currently selected experiment
51 private static TmfExperiment
<?
> fCurrentExperiment
= null;
53 // The set of traces that constitute the experiment
54 private ITmfTrace
[] fTraces
;
56 // The total number of events
57 private long fNbEvents
;
59 // The experiment time range
60 private TmfTimeRange fTimeRange
;
62 // The experiment reference timestamp (default: BigBang)
63 private TmfTimestamp fEpoch
;
65 // The experiment index
66 private Vector
<TmfCheckpoint
> fCheckpoints
= new Vector
<TmfCheckpoint
>();
68 // ------------------------------------------------------------------------
70 // ------------------------------------------------------------------------
77 * @param indexPageSize
79 public TmfExperiment(Class
<T
> type
, String id
, ITmfTrace
[] traces
, TmfTimestamp epoch
, int indexPageSize
) {
84 fIndexPageSize
= indexPageSize
;
85 fClone
= createTraceCopy();
96 public TmfExperiment(Class
<T
> type
, String id
, ITmfTrace
[] traces
) {
97 this(type
, id
, traces
, TmfTimestamp
.Zero
, DEFAULT_INDEX_PAGE_SIZE
);
104 * @param indexPageSize
106 public TmfExperiment(Class
<T
> type
, String id
, ITmfTrace
[] traces
, int indexPageSize
) {
107 this(type
, id
, traces
, TmfTimestamp
.Zero
, indexPageSize
);
110 public TmfExperiment(TmfExperiment
<T
> other
) {
111 super(other
.getName() + "(clone)", other
.fType
);
113 fEpoch
= other
.fEpoch
;
114 fIndexPageSize
= other
.fIndexPageSize
;
116 fTraces
= new ITmfTrace
[other
.fTraces
.length
];
117 for (int trace
= 0; trace
< other
.fTraces
.length
; trace
++) {
118 fTraces
[trace
] = other
.fTraces
[trace
].createTraceCopy();
121 fNbEvents
= other
.fNbEvents
;
122 fTimeRange
= other
.fTimeRange
;
126 public TmfExperiment
<T
> createTraceCopy() {
127 TmfExperiment
<T
> experiment
= new TmfExperiment
<T
>(this);
128 TmfSignalManager
.deregister(experiment
);
133 * Clears the experiment
136 public void dispose() {
137 for (ITmfTrace trace
: fTraces
) {
141 fCheckpoints
.clear();
145 private static void setCurrentExperiment(TmfExperiment
<?
> experiment
) {
146 fCurrentExperiment
= experiment
;
149 // ------------------------------------------------------------------------
151 // ------------------------------------------------------------------------
153 public String
getPath() {
157 public long getNbEvents() {
161 public int getCacheSize() {
162 return fIndexPageSize
;
165 public TmfTimeRange
getTimeRange() {
169 public TmfTimestamp
getStartTime() {
170 return fTimeRange
.getStartTime();
173 public TmfTimestamp
getEndTime() {
174 return fTimeRange
.getEndTime();
177 public Vector
<TmfCheckpoint
> getCheckpoints() {
181 // ------------------------------------------------------------------------
183 // ------------------------------------------------------------------------
185 public static TmfExperiment
<?
> getCurrentExperiment() {
186 return fCurrentExperiment
;
189 public TmfTimestamp
getEpoch() {
193 public ITmfTrace
[] getTraces() {
198 * Returns the rank of the first event with the requested timestamp.
199 * If none, returns the index of the next event (if any).
204 public long getRank(TmfTimestamp timestamp
) {
205 TmfExperimentContext context
= seekEvent(timestamp
);
206 return context
.getRank();
210 * Returns the timestamp of the event at the requested index.
211 * If none, returns null.
216 public TmfTimestamp
getTimestamp(int index
) {
217 TmfExperimentContext context
= seekEvent(index
);
218 TmfEvent event
= getNextEvent(context
);
219 return (event
!= null) ? event
.getTimestamp() : null;
222 // ------------------------------------------------------------------------
224 // ------------------------------------------------------------------------
227 * Update the total number of events
229 private void updateNbEvents() {
231 for (ITmfTrace trace
: fTraces
) {
232 nbEvents
+= trace
.getNbEvents();
234 fNbEvents
= nbEvents
;
238 * Update the global time range
240 private void updateTimeRange() {
241 TmfTimestamp startTime
= fTimeRange
!= null ? fTimeRange
.getStartTime() : TmfTimestamp
.BigCrunch
;
242 TmfTimestamp endTime
= fTimeRange
!= null ? fTimeRange
.getEndTime() : TmfTimestamp
.BigBang
;
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
;
250 TmfTimestamp traceEndTime
= trace
.getEndTime();
251 if (traceEndTime
.compareTo(endTime
, true) > 0)
252 endTime
= traceEndTime
;
255 fTimeRange
= new TmfTimeRange(startTime
, endTime
);
258 // ------------------------------------------------------------------------
260 // ------------------------------------------------------------------------
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());
271 @SuppressWarnings("unchecked")
273 public T
getNext(ITmfContext context
) {
274 if (context
instanceof TmfExperimentContext
) {
275 return (T
) getNextEvent((TmfExperimentContext
) context
);
280 // ------------------------------------------------------------------------
281 // ITmfTrace trace positioning
282 // ------------------------------------------------------------------------
284 // Returns a brand new context based on the location provided
285 // and initializes the event queues
286 public TmfExperimentContext
seekLocation(ITmfLocation
<?
> location
) {
288 // Validate the location
289 if (location
!= null && !(location
instanceof TmfExperimentLocation
)) {
290 return null; // Throw an exception?
293 // Instantiate the location
294 TmfExperimentLocation expLocation
= (location
== null)
295 ?
new TmfExperimentLocation(new ITmfLocation
<?
>[fTraces
.length
], new long[fTraces
.length
])
296 : (TmfExperimentLocation
) location
.clone();
298 // Create and populate the context's traces contexts
299 TmfExperimentContext context
= new TmfExperimentContext(fTraces
, new TmfContext
[fTraces
.length
]);
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
];
306 // Set the corresponding sub-context
307 context
.getContexts()[i
] = fTraces
[i
].seekLocation(traceLocation
);
308 context
.getContexts()[i
].setRank(traceRank
);
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
]);
317 context
.setLocation(expLocation
);
318 context
.setRank(rank
);
319 context
.setLastTrace(TmfExperimentContext
.NO_TRACE
);
324 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#seekEvent(org.eclipse.linuxtools.tmf.event.TmfTimestamp)
326 public TmfExperimentContext
seekEvent(TmfTimestamp timestamp
) {
328 if (timestamp
== null) {
329 timestamp
= TmfTimestamp
.BigBang
;
332 // First, find the right checkpoint
333 int index
= Collections
.binarySearch(fCheckpoints
, new TmfCheckpoint(timestamp
, null));
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.
339 index
= Math
.max(0, -(index
+ 2));
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;
349 location
= fCheckpoints
.elementAt(index
).getLocation();
356 TmfExperimentContext context
= seekLocation(location
);
357 context
.setRank((long) index
* fIndexPageSize
);
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
);
366 context
.setLastTrace(TmfExperimentContext
.NO_TRACE
);
372 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#seekEvent(long)
374 public TmfExperimentContext
seekEvent(long rank
) {
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) {
384 if (index
>= fCheckpoints
.size()) {
385 index
= fCheckpoints
.size() - 1;
387 location
= fCheckpoints
.elementAt(index
).getLocation();
391 TmfExperimentContext context
= seekLocation(location
);
392 long pos
= (long) index
* fIndexPageSize
;
393 context
.setRank(pos
);
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);
403 context
.setLastTrace(TmfExperimentContext
.NO_TRACE
);
409 * Scan the next events from all traces and return the next one
410 * in chronological order.
415 public synchronized TmfEvent
getNextEvent(TmfContext context
) {
417 // Validate the context
418 if (!(context
instanceof TmfExperimentContext
)) {
419 return null; // Throw an exception?
422 TmfExperimentContext expContext
= (TmfExperimentContext
) context
;
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
);
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) {
445 // Update the experiment context and set the "next" event
446 TmfEvent event
= null;
448 long savedRank
= expContext
.getRank();
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
];
456 updateIndex(expContext
, savedRank
, timestamp
);
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());
477 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#parseEvent(org.eclipse.linuxtools.tmf.trace.TmfContext)
479 public TmfEvent
parseEvent(TmfContext context
) {
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();
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) {
506 expContext
.setLastTrace(TmfExperimentContext
.NO_TRACE
);
507 return expContext
.getEvents()[trace
];
515 * @see java.lang.Object#toString()
518 public String
toString() {
519 return "[TmfExperiment (" + getName() + ")]";
522 // ------------------------------------------------------------------------
524 // ------------------------------------------------------------------------
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.
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
536 // The index page size
537 private static final int DEFAULT_INDEX_PAGE_SIZE
= 1000;
538 private final int fIndexPageSize
;
540 @SuppressWarnings("unchecked")
541 public void indexExperiment() {
543 final TmfExperiment
<?
> experiment
= getCurrentExperiment();
544 fCheckpoints
.clear();
546 ITmfEventRequest
<TmfEvent
> request
= new TmfEventRequest
<TmfEvent
>(TmfEvent
.class, TmfTimeRange
.Eternity
, TmfDataRequest
.ALL_DATA
, 1) {
548 long indexingStart
= System
.nanoTime();
550 TmfTimestamp startTime
= null;
551 TmfTimestamp lastTime
= null;
555 public void handleData() {
556 TmfEvent
[] events
= getData();
557 if (events
.length
> 0) {
559 TmfTimestamp ts
= events
[0].getTimestamp();
560 if (startTime
== null)
561 startTime
= new TmfTimestamp(ts
);
562 lastTime
= new TmfTimestamp(ts
);
564 if ((nbEvents
% DEFAULT_INDEX_PAGE_SIZE
) == 0) {
571 public void handleSuccess() {
572 long indexingEnd
= System
.nanoTime();
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());
583 // if (Tracer.INTERNALS) Tracer.trace(getName() + ": nbEvents=" + nbEvents + " (" + ((indexingEnd-indexingStart)/nbEvents)+ " ns/evt), start=" + startTime + ", end=" + lastTime);
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());
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
;
602 sendRequest((ITmfDataRequest
<T
>) request
, ExecutionType
.LONG
);
605 protected void notifyListeners() {
606 broadcast(new TmfExperimentUpdatedSignal(this, this, null));
609 // ------------------------------------------------------------------------
611 // ------------------------------------------------------------------------
614 public void experimentSelected(TmfExperimentSelectedSignal
<T
> signal
) {
615 TmfExperiment
<?
> experiment
= signal
.getExperiment();
616 if (experiment
== this) {
617 setCurrentExperiment(experiment
);
626 public void experimentUpdated(TmfExperimentUpdatedSignal signal
) {
630 public void traceUpdated(TmfTraceUpdatedSignal signal
) {
631 // TODO: Incremental index update
636 broadcast(new TmfExperimentUpdatedSignal(this, this, signal
.getTrace()));