1 /*******************************************************************************
2 * Copyright (c) 2011-2012 Ericsson, Ecole Polytechnique de Montreal and others
4 * All rights reserved. This program and the accompanying materials are made
5 * 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
9 * Contributors: Matthew Khouzam - Initial API and implementation
10 * Contributors: Alexandre Montplaisir - Initial API and implementation
11 *******************************************************************************/
13 package org
.eclipse
.linuxtools
.ctf
.core
.trace
;
15 import java
.util
.Collection
;
16 import java
.util
.PriorityQueue
;
18 import java
.util
.Vector
;
20 import org
.eclipse
.linuxtools
.ctf
.core
.event
.EventDefinition
;
21 import org
.eclipse
.linuxtools
.internal
.ctf
.core
.Activator
;
22 import org
.eclipse
.linuxtools
.internal
.ctf
.core
.trace
.StreamInputPacketIndexEntry
;
25 * Reads the events of a trace.
28 public class CTFTraceReader
{
30 // ------------------------------------------------------------------------
32 // ------------------------------------------------------------------------
35 * The trace to read from.
37 private final CTFTrace trace
;
40 * Vector of all the trace file readers.
42 private final Vector
<StreamInputReader
> streamInputReaders
= new Vector
<StreamInputReader
>();
45 * Priority queue to order the trace file readers by timestamp.
47 protected PriorityQueue
<StreamInputReader
> prio
;
50 * Array to count the number of event per trace file.
52 private int[] eventCountPerTraceFile
;
55 * Timestamp of the first event in the trace
57 private long startTime
;
60 * Timestamp of the last event read so far
69 private final long startIndex
[];
71 // ------------------------------------------------------------------------
73 // ------------------------------------------------------------------------
76 * Constructs a TraceReader to read a trace.
79 * The trace to read from.
80 * @throws CTFReaderException
82 public CTFTraceReader(CTFTrace trace
) {
86 * Create the trace file readers.
88 createStreamInputReaders();
91 * Populate the timestamp-based priority queue.
93 populateStreamInputReaderHeap();
96 * Get the start Time of this trace
98 this.startTime
= prio
.peek().getCurrentEvent().timestamp
;
99 this.endTime
= this.startTime
;
101 startIndex
= new long[prio
.size()];
102 for (int i
= 0; i
< prio
.size(); i
++) {
110 public CTFTraceReader
copyFrom() {
111 CTFTraceReader newReader
= null;
113 newReader
= new CTFTraceReader(this.trace
);
114 newReader
.startTime
= this.startTime
;
115 newReader
.endTime
= this.endTime
;
119 // ------------------------------------------------------------------------
120 // Getters/Setters/Predicates
121 // ------------------------------------------------------------------------
124 * Return the start time of this trace (== timestamp of the first event)
126 * @return the trace start time
128 public long getStartTime() {
129 return this.startTime
;
135 public long getIndex() {
139 // ------------------------------------------------------------------------
141 // ------------------------------------------------------------------------
144 * Creates one trace file reader per trace file contained in the trace.
146 private void createStreamInputReaders() {
147 Collection
<Stream
> streams
= this.trace
.getStreams().values();
152 for (Stream stream
: streams
) {
153 Set
<StreamInput
> streamInputs
= stream
.getStreamInputs();
156 * For each trace file of the stream.
158 for (StreamInput streamInput
: streamInputs
) {
162 StreamInputReader streamInputReader
= new StreamInputReader(
166 * Add it to the group.
168 this.streamInputReaders
.add(streamInputReader
);
173 * Create the array to count the number of event per trace file.
175 this.eventCountPerTraceFile
= new int[this.streamInputReaders
.size()];
179 * Initializes the priority queue used to choose the trace file with the
180 * lower next event timestamp.
182 private void populateStreamInputReaderHeap() {
184 * Create the priority queue with a size twice as bigger as the number
185 * of reader in order to avoid constant resizing.
187 this.prio
= new PriorityQueue
<StreamInputReader
>(
188 this.streamInputReaders
.size() * 2,
189 new StreamInputReaderTimestampComparator());
193 for (StreamInputReader reader
: this.streamInputReaders
) {
195 * Add each trace file reader in the priority queue, if we are able
196 * to read an event from it.
198 if (reader
.readNextEvent()) {
199 this.prio
.add(reader
);
201 this.eventCountPerTraceFile
[pos
] = 0;
210 * Get the current event, which is the current event of the trace file
211 * reader with the lowest timestamp.
213 * @return An event definition, or null of the trace reader reached the end
216 public EventDefinition
getCurrentEventDef() {
217 StreamInputReader top
= getTopStream();
219 return (top
!= null) ? top
.getCurrentEvent() : null;
223 * Go to the next event.
225 * @return True if an event was read.
227 public boolean advance() {
232 * Remove the reader from the top of the priority queue.
234 StreamInputReader top
= this.prio
.poll();
237 * If the queue was empty.
245 if (hasMoreEvents()) {
246 StreamInputPacketReader packetReader
= top
.getPacketReader();
247 boolean packetHasMoreEvents
= packetReader
.hasMoreEvents();
248 StreamInputPacketIndexEntry currentPacket
= packetReader
250 if (!packetHasMoreEvents
) {
251 int n
= this.streamInputReaders
.indexOf(top
);
252 currentPacket
.setIndexBegin(startIndex
[n
]);
253 currentPacket
.setIndexEnd(index
);
254 startIndex
[n
] = index
+ 1;
258 * Read the next event of this reader.
260 if (top
.readNextEvent()) {
262 * Add it back in the queue.
265 final long topEnd
= top
.getCurrentEvent().timestamp
;
266 this.endTime
= Math
.max(topEnd
, this.endTime
);
267 this.eventCountPerTraceFile
[top
.getName()]++;
269 * increment the index
273 boolean hasMoreEvents
= hasMoreEvents();
276 * If there is no reader in the queue, it means the trace reader reached
277 * the end of the trace.
279 return hasMoreEvents
;
283 * Go to the last event in the trace.
285 * @throws CTFReaderException
287 public void goToLastEvent() throws CTFReaderException
{
290 for (StreamInputReader streamInputReader
: this.streamInputReaders
) {
292 * Seek the trace reader.
294 streamInputReader
.goToLastEvent();
296 int count
= prio
.size();
297 for (int i
= 0; i
< (count
); i
++) {
303 * Seeks to a given timestamp It will go to the event just after the
304 * timestamp or the timestamp itself. if a if a trace is 10 20 30 40 and
305 * you're looking for 19, it'll give you 20, it you want 20, you'll get 20,
306 * if you want 21, you'll get 30. You want -inf, you'll get the first
307 * element, you want +inf, you'll get the end of the file with no events.
310 * the timestamp to seek to
311 * @return true if the trace has more events following the timestamp
313 public boolean seek(long timestamp
) {
315 * Remove all the trace readers from the priority queue
320 for (StreamInputReader streamInputReader
: this.streamInputReaders
) {
322 * Seek the trace reader.
324 offset
+= streamInputReader
.seek(timestamp
);
327 * Add it to the priority queue if there is a current event.
331 for (StreamInputReader streamInputReader
: this.streamInputReaders
) {
332 if (streamInputReader
.getCurrentEvent() != null) {
333 this.prio
.add(streamInputReader
);
334 index
= Math
.max(index
, streamInputReader
.getPacketReader()
335 .getCurrentPacket().getIndexBegin()
339 return hasMoreEvents();
342 public boolean seekIndex(long index
) {
345 long tempIndex
= Long
.MIN_VALUE
;
346 long tempTimestamp
= Long
.MIN_VALUE
;
348 for (StreamInputReader streamInputReader
: this.streamInputReaders
) {
350 * Seek the trace reader.
352 final long streamIndex
= streamInputReader
.seekIndex(index
);
353 tempIndex
= Math
.max(tempIndex
, streamIndex
);
354 tempTimestamp
= Math
.max(tempTimestamp
,
355 streamInputReader
.getCurrentEvent().timestamp
);
358 } catch (CTFReaderException e
) {
360 * Important, if it failed, it's because it's not yet indexed, so we
361 * have to manually advance to the right value.
363 for (StreamInputReader streamInputReader
: this.streamInputReaders
) {
365 * Seek the trace reader.
367 streamInputReader
.seek(0);
371 for (StreamInputReader streamInputReader
: this.streamInputReaders
) {
373 * Add it to the priority queue if there is a current event.
376 if (streamInputReader
.getCurrentEvent() != null) {
377 this.prio
.add(streamInputReader
);
380 if (tempIndex
== Long
.MAX_VALUE
) {
383 long pos
= tempIndex
;
384 if (index
> tempIndex
) {
388 while ((prio
.peek().getCurrentEvent().timestamp
< tempTimestamp
)
389 && hasMoreEvents()) {
393 for (pos
= tempIndex
; (pos
< index
) && hasMoreEvents(); pos
++) {
398 return hasMoreEvents();
401 public StreamInputReader
getTopStream() {
402 return this.prio
.peek();
406 * Does the trace have more events?
408 * @return true if yes.
410 public boolean hasMoreEvents() {
411 return this.prio
.size() > 0;
415 * Prints the event count stats.
417 public void printStats() {
422 * Prints the event count stats.
425 * Width of the display.
427 public void printStats(int width
) {
433 for (int i
: this.eventCountPerTraceFile
) {
437 for (int j
= 0; j
< this.eventCountPerTraceFile
.length
; j
++) {
438 StreamInputReader se
= this.streamInputReaders
.get(j
);
440 int len
= (width
* this.eventCountPerTraceFile
[se
.getName()])
443 StringBuilder sb
= new StringBuilder(se
.getStreamInput()
444 .getFilename() + "\t["); //$NON-NLS-1$
446 for (int i
= 0; i
< len
; i
++) {
450 for (int i
= len
; i
< width
; i
++) {
454 sb
.append("]\t" + this.eventCountPerTraceFile
[se
.getName()] + " Events"); //$NON-NLS-1$//$NON-NLS-2$
455 Activator
.getDefault().log(sb
.toString());
459 public long getEndTime() {
464 public int hashCode() {
465 final int prime
= 31;
467 result
= (prime
* result
) + (int) (endTime ^
(endTime
>>> 32));
468 result
= (prime
* result
) + (int) (startTime ^
(startTime
>>> 32));
469 result
= (prime
* result
)
470 + ((streamInputReaders
== null) ?
0 : streamInputReaders
472 result
= (prime
* result
) + ((trace
== null) ?
0 : trace
.hashCode());
477 public boolean equals(Object obj
) {
484 if (getClass() != obj
.getClass()) {
487 CTFTraceReader other
= (CTFTraceReader
) obj
;
488 if (endTime
!= other
.endTime
) {
491 if (startTime
!= other
.startTime
) {
494 if (streamInputReaders
== null) {
495 if (other
.streamInputReaders
!= null) {
498 } else if (!streamInputReaders
.equals(other
.streamInputReaders
)) {
502 if (other
.trace
!= null) {
505 } else if (!trace
.equals(other
.trace
)) {
514 * @see java.lang.Object#toString()
517 public String
toString() {
518 /* Only for debugging, shouldn't be externalized */
519 return "CTFTraceReader [trace=" + trace
+ ']'; //$NON-NLS-1$
522 public CTFTrace
getTrace() {