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
.Stream
;
23 import org
.eclipse
.linuxtools
.internal
.ctf
.core
.trace
.StreamInput
;
24 import org
.eclipse
.linuxtools
.internal
.ctf
.core
.trace
.StreamInputReaderTimestampComparator
;
27 * Reads the events of a trace.
30 public class CTFTraceReader
{
32 // ------------------------------------------------------------------------
34 // ------------------------------------------------------------------------
37 * The trace to read from.
39 private final CTFTrace trace
;
42 * Vector of all the trace file readers.
44 private final Vector
<StreamInputReader
> streamInputReaders
= new Vector
<StreamInputReader
>();
47 * Priority queue to order the trace file readers by timestamp.
49 protected PriorityQueue
<StreamInputReader
> prio
;
52 * Array to count the number of event per trace file.
54 private long[] eventCountPerTraceFile
;
57 * Timestamp of the first event in the trace
59 private long startTime
;
62 * Timestamp of the last event read so far
67 protected void setEndTime(long endTime
) {
68 this.endTime
= endTime
;
71 // ------------------------------------------------------------------------
73 // ------------------------------------------------------------------------
76 * Constructs a TraceReader to read a trace.
79 * The trace to read from.
80 * @throws CTFReaderException
82 public CTFTraceReader(CTFTrace trace
) {
84 streamInputReaders
.clear();
87 * Create the trace file readers.
89 createStreamInputReaders();
92 * Populate the timestamp-based priority queue.
94 populateStreamInputReaderHeap();
97 * Get the start Time of this trace bear in mind that the trace could be
100 this.startTime
= 0;// prio.peek().getPacketReader().getCurrentPacket().getTimestampBegin();
101 if (hasMoreEvents()) {
102 this.startTime
= prio
.peek().getCurrentEvent().getTimestamp();
103 this.setEndTime(this.startTime
);
110 public CTFTraceReader
copyFrom() {
111 CTFTraceReader newReader
= null;
113 newReader
= new CTFTraceReader(this.trace
);
114 newReader
.startTime
= this.startTime
;
115 newReader
.setEndTime(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
;
132 // ------------------------------------------------------------------------
134 // ------------------------------------------------------------------------
137 * Creates one trace file reader per trace file contained in the trace.
139 private void createStreamInputReaders() {
140 Collection
<Stream
> streams
= this.trace
.getStreams().values();
145 for (Stream stream
: streams
) {
146 Set
<StreamInput
> streamInputs
= stream
.getStreamInputs();
149 * For each trace file of the stream.
151 for (StreamInput streamInput
: streamInputs
) {
152 streamInput
.getIndex().getEntries().clear();
156 StreamInputReader streamInputReader
= new StreamInputReader(
160 * Add it to the group.
162 this.streamInputReaders
.add(streamInputReader
);
167 * Create the array to count the number of event per trace file.
169 this.eventCountPerTraceFile
= new long[this.streamInputReaders
.size()];
173 * Initializes the priority queue used to choose the trace file with the
174 * lower next event timestamp.
176 private void populateStreamInputReaderHeap() {
178 * Create the priority queue with a size twice as bigger as the number
179 * of reader in order to avoid constant resizing.
181 this.prio
= new PriorityQueue
<StreamInputReader
>(
182 this.streamInputReaders
.size() * 2,
183 new StreamInputReaderTimestampComparator());
187 for (StreamInputReader reader
: this.streamInputReaders
) {
189 * Add each trace file reader in the priority queue, if we are able
190 * to read an event from it.
192 reader
.setParent(this);
193 if (reader
.readNextEvent()) {
194 this.prio
.add(reader
);
196 this.eventCountPerTraceFile
[pos
] = 0;
205 * Get the current event, which is the current event of the trace file
206 * reader with the lowest timestamp.
208 * @return An event definition, or null of the trace reader reached the end
211 public EventDefinition
getCurrentEventDef() {
212 StreamInputReader top
= getTopStream();
214 return (top
!= null) ? top
.getCurrentEvent() : null;
218 * Go to the next event.
220 * @return True if an event was read.
222 public boolean advance() {
227 * Remove the reader from the top of the priority queue.
229 StreamInputReader top
= this.prio
.poll();
232 * If the queue was empty.
238 * Read the next event of this reader.
240 if (top
.readNextEvent()) {
242 * Add it back in the queue.
245 final long topEnd
= top
.getCurrentEvent().getTimestamp() + this.getTrace().getOffset();
246 this.setEndTime( Math
.max(topEnd
, this.getEndTime()));
247 this.eventCountPerTraceFile
[top
.getName()]++;
249 * increment the index
252 if (top
.getCurrentEvent() != null) {
253 this.endTime
= Math
.max(top
.getCurrentEvent().getTimestamp(),
258 * If there is no reader in the queue, it means the trace reader reached
259 * the end of the trace.
261 return hasMoreEvents();
265 * Go to the last event in the trace.
267 * @throws CTFReaderException
269 public void goToLastEvent() {
270 seek(this.getEndTime());
271 while (this.prio
.size() > 1) {
277 * Seeks to a given timestamp It will go to the event just after the
278 * timestamp or the timestamp itself. if a if a trace is 10 20 30 40 and
279 * you're looking for 19, it'll give you 20, it you want 20, you'll get 20,
280 * if you want 21, you'll get 30. You want -inf, you'll get the first
281 * element, you want +inf, you'll get the end of the file with no events.
284 * the timestamp to seek to
285 * @return true if the trace has more events following the timestamp
287 public boolean seek(long timestamp
) {
289 * Remove all the trace readers from the priority queue
292 for (StreamInputReader streamInputReader
: this.streamInputReaders
) {
294 * Seek the trace reader.
296 streamInputReader
.seek(timestamp
);
299 * Add it to the priority queue if there is a current event.
303 for (StreamInputReader streamInputReader
: this.streamInputReaders
) {
304 if (streamInputReader
.getCurrentEvent() != null) {
305 this.prio
.add(streamInputReader
);
309 return hasMoreEvents();
313 * Go to the first entry of a trace
315 * @return 0, the first index.
317 private long goToZero() {
319 for (StreamInputReader streamInputReader
: this.streamInputReaders
) {
321 * Seek the trace reader.
323 streamInputReader
.seek(0);
329 public StreamInputReader
getTopStream() {
330 return this.prio
.peek();
334 * Does the trace have more events?
336 * @return true if yes.
338 public boolean hasMoreEvents() {
339 return this.prio
.size() > 0;
343 * Prints the event count stats.
345 public void printStats() {
350 * Prints the event count stats.
353 * Width of the display.
355 public void printStats(int width
) {
361 for (long i
: this.eventCountPerTraceFile
) {
365 for (int j
= 0; j
< this.eventCountPerTraceFile
.length
; j
++) {
366 StreamInputReader se
= this.streamInputReaders
.get(j
);
368 long len
= (width
* this.eventCountPerTraceFile
[se
.getName()])
371 StringBuilder sb
= new StringBuilder(se
.getFilename() + "\t["); //$NON-NLS-1$
373 for (int i
= 0; i
< len
; i
++) {
377 for (long i
= len
; i
< width
; i
++) {
381 sb
.append("]\t" + this.eventCountPerTraceFile
[se
.getName()] + " Events"); //$NON-NLS-1$//$NON-NLS-2$
382 Activator
.getDefault().log(sb
.toString());
386 public long getEndTime() {
391 public int hashCode() {
392 final int prime
= 31;
394 result
= (prime
* result
) + (int) (startTime ^
(startTime
>>> 32));
395 result
= (prime
* result
)
396 + ((streamInputReaders
== null) ?
0 : streamInputReaders
398 result
= (prime
* result
) + ((trace
== null) ?
0 : trace
.hashCode());
403 public boolean equals(Object obj
) {
410 if (!(obj
instanceof CTFTraceReader
)) {
413 CTFTraceReader other
= (CTFTraceReader
) obj
;
414 if (streamInputReaders
== null) {
415 if (other
.streamInputReaders
!= null) {
418 } else if (!streamInputReaders
.equals(other
.streamInputReaders
)) {
422 if (other
.trace
!= null) {
425 } else if (!trace
.equals(other
.trace
)) {
434 * @see java.lang.Object#toString()
437 public String
toString() {
438 /* Only for debugging, shouldn't be externalized */
439 return "CTFTraceReader [trace=" + trace
+ ']'; //$NON-NLS-1$
442 public CTFTrace
getTrace() {