1 /*******************************************************************************
2 * Copyright (c) 2011, 2013 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
10 * Matthew Khouzam - Initial API and implementation
11 * Alexandre Montplaisir - Initial API and implementation
12 *******************************************************************************/
14 package org
.eclipse
.linuxtools
.ctf
.core
.trace
;
16 import java
.util
.ArrayList
;
17 import java
.util
.List
;
18 import java
.util
.PriorityQueue
;
21 import org
.eclipse
.linuxtools
.ctf
.core
.event
.EventDefinition
;
22 import org
.eclipse
.linuxtools
.internal
.ctf
.core
.Activator
;
23 import org
.eclipse
.linuxtools
.internal
.ctf
.core
.trace
.StreamInputReaderTimestampComparator
;
26 * A CTF trace reader. Reads the events of a trace.
29 * @author Matthew Khouzam
30 * @author Alexandre Montplaisir
32 public class CTFTraceReader
{
34 // ------------------------------------------------------------------------
36 // ------------------------------------------------------------------------
39 * The trace to read from.
41 private final CTFTrace trace
;
44 * Vector of all the trace file readers.
46 private final List
<StreamInputReader
> streamInputReaders
= new ArrayList
<StreamInputReader
>();
49 * Priority queue to order the trace file readers by timestamp.
51 private PriorityQueue
<StreamInputReader
> prio
;
54 * Array to count the number of event per trace file.
56 private long[] eventCountPerTraceFile
;
59 * Timestamp of the first event in the trace
61 private long startTime
;
64 * Timestamp of the last event read so far
68 // ------------------------------------------------------------------------
70 // ------------------------------------------------------------------------
73 * Constructs a TraceReader to read a trace.
76 * The trace to read from.
77 * @throws CTFReaderException
80 public CTFTraceReader(CTFTrace trace
) throws CTFReaderException
{
82 streamInputReaders
.clear();
85 * Create the trace file readers.
87 createStreamInputReaders();
90 * Populate the timestamp-based priority queue.
92 populateStreamInputReaderHeap();
95 * Get the start Time of this trace bear in mind that the trace could be
99 if (hasMoreEvents()) {
100 this.startTime
= prio
.peek().getCurrentEvent().getTimestamp();
101 this.setEndTime(this.startTime
);
108 * @return The new CTFTraceReader
109 * @throws CTFReaderException if an error occurs
111 public CTFTraceReader
copyFrom() throws CTFReaderException
{
112 CTFTraceReader newReader
= null;
114 newReader
= new CTFTraceReader(this.trace
);
115 newReader
.startTime
= this.startTime
;
116 newReader
.setEndTime(this.endTime
);
121 * Dispose the CTFTraceReader
125 public void dispose() {
126 for (StreamInputReader reader
: streamInputReaders
) {
127 if (reader
!= null) {
131 streamInputReaders
.clear();
134 // ------------------------------------------------------------------------
135 // Getters/Setters/Predicates
136 // ------------------------------------------------------------------------
139 * Return the start time of this trace (== timestamp of the first event)
141 * @return the trace start time
143 public long getStartTime() {
144 return this.startTime
;
148 * Set the trace's end time
151 * The end time to use
153 protected final void setEndTime(long endTime
) {
154 this.endTime
= endTime
;
158 * Get the priority queue of this trace reader.
160 * @return The priority queue of input readers
163 protected PriorityQueue
<StreamInputReader
> getPrio() {
167 // ------------------------------------------------------------------------
169 // ------------------------------------------------------------------------
172 * Creates one trace file reader per trace file contained in the trace.
174 * @throws CTFReaderException
177 private void createStreamInputReaders() throws CTFReaderException
{
181 for (Stream stream
: this.trace
.getStreams()) {
182 Set
<StreamInput
> streamInputs
= stream
.getStreamInputs();
185 * For each trace file of the stream.
187 for (StreamInput streamInput
: streamInputs
) {
191 StreamInputReader streamInputReader
= new StreamInputReader(
195 * Add it to the group.
197 this.streamInputReaders
.add(streamInputReader
);
202 * Create the array to count the number of event per trace file.
204 this.eventCountPerTraceFile
= new long[this.streamInputReaders
.size()];
208 * Initializes the priority queue used to choose the trace file with the
209 * lower next event timestamp.
211 * @throws CTFReaderException
214 private void populateStreamInputReaderHeap() throws CTFReaderException
{
215 if (this.streamInputReaders
.isEmpty()) {
216 this.prio
= new PriorityQueue
<StreamInputReader
>();
221 * Create the priority queue with a size twice as bigger as the number
222 * of reader in order to avoid constant resizing.
224 this.prio
= new PriorityQueue
<StreamInputReader
>(
225 this.streamInputReaders
.size() * 2,
226 new StreamInputReaderTimestampComparator());
230 for (StreamInputReader reader
: this.streamInputReaders
) {
232 * Add each trace file reader in the priority queue, if we are able
233 * to read an event from it.
235 reader
.setParent(this);
236 if (reader
.readNextEvent()) {
237 this.prio
.add(reader
);
239 this.eventCountPerTraceFile
[pos
] = 0;
248 * Get the current event, which is the current event of the trace file
249 * reader with the lowest timestamp.
251 * @return An event definition, or null of the trace reader reached the end
254 public EventDefinition
getCurrentEventDef() {
255 StreamInputReader top
= getTopStream();
257 return (top
!= null) ? top
.getCurrentEvent() : null;
261 * Go to the next event.
263 * @return True if an event was read.
264 * @throws CTFReaderException
267 public boolean advance() throws CTFReaderException
{
269 * Remove the reader from the top of the priority queue.
271 StreamInputReader top
= this.prio
.poll();
274 * If the queue was empty.
280 * Read the next event of this reader.
282 if (top
.readNextEvent()) {
284 * Add it back in the queue.
287 final long topEnd
= this.trace
.timestampCyclesToNanos(top
.getCurrentEvent().getTimestamp());
288 this.setEndTime(Math
.max(topEnd
, this.getEndTime()));
289 this.eventCountPerTraceFile
[top
.getName()]++;
291 if (top
.getCurrentEvent() != null) {
292 this.endTime
= Math
.max(top
.getCurrentEvent().getTimestamp(),
297 * If there is no reader in the queue, it means the trace reader reached
298 * the end of the trace.
300 return hasMoreEvents();
304 * Go to the last event in the trace.
306 * @throws CTFReaderException
309 public void goToLastEvent() throws CTFReaderException
{
310 seek(this.getEndTime());
311 while (this.prio
.size() > 1) {
317 * Seeks to a given timestamp. It will seek to the nearest event greater or
318 * equal to timestamp. If a trace is [10 20 30 40] and you are looking for
319 * 19, it will give you 20. If you want 20, you will get 20, if you want 21,
320 * you will get 30. The value -inf will seek to the first element and the
321 * value +inf will seek to the end of the file (past the last event).
324 * the timestamp to seek to
325 * @return true if there are events above or equal the seek timestamp,
326 * false if seek at the end of the trace (no valid event).
327 * @throws CTFReaderException
330 public boolean seek(long timestamp
) throws CTFReaderException
{
332 * Remove all the trace readers from the priority queue
335 for (StreamInputReader streamInputReader
: this.streamInputReaders
) {
337 * Seek the trace reader.
339 streamInputReader
.seek(timestamp
);
342 * Add it to the priority queue if there is a current event.
344 if (streamInputReader
.getCurrentEvent() != null) {
345 this.prio
.add(streamInputReader
);
348 return hasMoreEvents();
352 * Gets the stream with the oldest event
354 * @return the stream with the oldest event
356 public StreamInputReader
getTopStream() {
357 return this.prio
.peek();
361 * Does the trace have more events?
363 * @return true if yes.
365 public final boolean hasMoreEvents() {
366 return this.prio
.size() > 0;
370 * Prints the event count stats.
372 public void printStats() {
377 * Prints the event count stats.
380 * Width of the display.
382 public void printStats(int width
) {
388 for (long i
: this.eventCountPerTraceFile
) {
392 for (int j
= 0; j
< this.eventCountPerTraceFile
.length
; j
++) {
393 StreamInputReader se
= this.streamInputReaders
.get(j
);
395 long len
= (width
* this.eventCountPerTraceFile
[se
.getName()])
398 StringBuilder sb
= new StringBuilder(se
.getFilename());
399 sb
.append("\t["); //$NON-NLS-1$
401 for (int i
= 0; i
< len
; i
++) {
405 for (long i
= len
; i
< width
; i
++) {
409 sb
.append("]\t" + this.eventCountPerTraceFile
[se
.getName()] + " Events"); //$NON-NLS-1$//$NON-NLS-2$
410 Activator
.log(sb
.toString());
415 * Gets the last event timestamp that was read. This is NOT necessarily the
416 * last event in a trace, just the last one read so far.
418 * @return the last event
420 public long getEndTime() {
425 public int hashCode() {
426 final int prime
= 31;
428 result
= (prime
* result
) + (int) (startTime ^
(startTime
>>> 32));
429 result
= (prime
* result
) + streamInputReaders
.hashCode();
430 result
= (prime
* result
) + ((trace
== null) ?
0 : trace
.hashCode());
435 public boolean equals(Object obj
) {
442 if (!(obj
instanceof CTFTraceReader
)) {
445 CTFTraceReader other
= (CTFTraceReader
) obj
;
446 if (!streamInputReaders
.equals(other
.streamInputReaders
)) {
450 if (other
.trace
!= null) {
453 } else if (!trace
.equals(other
.trace
)) {
460 public String
toString() {
461 /* Only for debugging, shouldn't be externalized */
462 return "CTFTraceReader [trace=" + trace
+ ']'; //$NON-NLS-1$
466 * Gets the parent trace
468 * @return the parent trace
470 public CTFTrace
getTrace() {