1 /*******************************************************************************
2 * Copyright (c) 2011, 2014 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
.HashSet
;
18 import java
.util
.List
;
19 import java
.util
.PriorityQueue
;
22 import org
.eclipse
.linuxtools
.ctf
.core
.event
.EventDefinition
;
23 import org
.eclipse
.linuxtools
.internal
.ctf
.core
.Activator
;
24 import org
.eclipse
.linuxtools
.internal
.ctf
.core
.trace
.StreamInputReaderTimestampComparator
;
27 * A CTF trace reader. Reads the events of a trace.
30 * @author Matthew Khouzam
31 * @author Alexandre Montplaisir
33 public class CTFTraceReader
implements AutoCloseable
{
35 private static final int MIN_PRIO_SIZE
= 16;
37 // ------------------------------------------------------------------------
39 // ------------------------------------------------------------------------
42 * The trace to read from.
44 private final CTFTrace fTrace
;
47 * Vector of all the trace file readers.
49 private final List
<StreamInputReader
> fStreamInputReaders
= new ArrayList
<>();
52 * Priority queue to order the trace file readers by timestamp.
54 private PriorityQueue
<StreamInputReader
> fPrio
;
57 * Array to count the number of event per trace file.
59 private long[] fEventCountPerTraceFile
;
62 * Timestamp of the first event in the trace
64 private long fStartTime
;
67 * Timestamp of the last event read so far
69 private long fEndTime
;
71 // ------------------------------------------------------------------------
73 // ------------------------------------------------------------------------
76 * Constructs a TraceReader to read a trace.
79 * The trace to read from.
80 * @throws CTFReaderException
83 public CTFTraceReader(CTFTrace trace
) throws CTFReaderException
{
85 fStreamInputReaders
.clear();
88 * Create the trace file readers.
90 createStreamInputReaders();
93 * Populate the timestamp-based priority queue.
95 populateStreamInputReaderHeap();
98 * Get the start Time of this trace bear in mind that the trace could be
102 if (hasMoreEvents()) {
103 fStartTime
= fPrio
.peek().getCurrentEvent().getTimestamp();
104 setEndTime(fStartTime
);
111 * @return The new CTFTraceReader
112 * @throws CTFReaderException
115 public CTFTraceReader
copyFrom() throws CTFReaderException
{
116 CTFTraceReader newReader
= null;
118 newReader
= new CTFTraceReader(fTrace
);
119 newReader
.fStartTime
= fStartTime
;
120 newReader
.setEndTime(fEndTime
);
125 * Dispose the CTFTraceReader
130 public void close() {
131 for (StreamInputReader reader
: fStreamInputReaders
) {
132 if (reader
!= null) {
136 fStreamInputReaders
.clear();
139 // ------------------------------------------------------------------------
140 // Getters/Setters/Predicates
141 // ------------------------------------------------------------------------
144 * Return the start time of this trace (== timestamp of the first event)
146 * @return the trace start time
148 public long getStartTime() {
153 * Set the trace's end time
156 * The end time to use
158 protected final void setEndTime(long endTime
) {
163 * Get the priority queue of this trace reader.
165 * @return The priority queue of input readers
168 protected PriorityQueue
<StreamInputReader
> getPrio() {
172 // ------------------------------------------------------------------------
174 // ------------------------------------------------------------------------
177 * Creates one trace file reader per trace file contained in the trace.
179 * @throws CTFReaderException
182 private void createStreamInputReaders() throws CTFReaderException
{
186 for (Stream stream
: fTrace
.getStreams()) {
187 Set
<StreamInput
> streamInputs
= stream
.getStreamInputs();
190 * For each trace file of the stream.
192 for (StreamInput streamInput
: streamInputs
) {
196 StreamInputReader streamInputReader
= new StreamInputReader(
200 * Add it to the group.
202 fStreamInputReaders
.add(streamInputReader
);
207 * Create the array to count the number of event per trace file.
209 fEventCountPerTraceFile
= new long[fStreamInputReaders
.size()];
213 * Update the priority queue to make it match the parent trace
215 * @throws CTFReaderException
220 public void update() throws CTFReaderException
{
221 Set
<StreamInputReader
> readers
= new HashSet
<>();
222 for (Stream stream
: fTrace
.getStreams()) {
223 Set
<StreamInput
> streamInputs
= stream
.getStreamInputs();
224 for (StreamInput streamInput
: streamInputs
) {
228 StreamInputReader streamInputReader
= new StreamInputReader(
232 * Add it to the group.
234 if (!fStreamInputReaders
.contains(streamInputReader
)) {
235 streamInputReader
.readNextEvent();
236 fStreamInputReaders
.add(streamInputReader
);
237 readers
.add(streamInputReader
);
241 long[] temp
= fEventCountPerTraceFile
;
242 fEventCountPerTraceFile
= new long[readers
.size() + temp
.length
];
243 for (StreamInputReader reader
: readers
) {
246 for (int i
= 0; i
< temp
.length
; i
++) {
247 fEventCountPerTraceFile
[i
] = temp
[i
];
252 * Initializes the priority queue used to choose the trace file with the
253 * lower next event timestamp.
255 * @throws CTFReaderException
258 private void populateStreamInputReaderHeap() throws CTFReaderException
{
259 if (fStreamInputReaders
.isEmpty()) {
260 fPrio
= new PriorityQueue
<>(MIN_PRIO_SIZE
,
261 new StreamInputReaderTimestampComparator());
266 * Create the priority queue with a size twice as bigger as the number
267 * of reader in order to avoid constant resizing.
269 fPrio
= new PriorityQueue
<>(
270 Math
.max(fStreamInputReaders
.size() * 2, MIN_PRIO_SIZE
),
271 new StreamInputReaderTimestampComparator());
275 for (StreamInputReader reader
: fStreamInputReaders
) {
277 * Add each trace file reader in the priority queue, if we are able
278 * to read an event from it.
280 reader
.setParent(this);
281 CTFResponse readNextEvent
= reader
.readNextEvent();
282 if (readNextEvent
== CTFResponse
.OK
|| readNextEvent
== CTFResponse
.WAIT
) {
285 fEventCountPerTraceFile
[pos
] = 0;
294 * Get the current event, which is the current event of the trace file
295 * reader with the lowest timestamp.
297 * @return An event definition, or null of the trace reader reached the end
300 public EventDefinition
getCurrentEventDef() {
301 StreamInputReader top
= getTopStream();
303 return (top
!= null) ? top
.getCurrentEvent() : null;
307 * Go to the next event.
309 * @return True if an event was read.
310 * @throws CTFReaderException
313 public boolean advance() throws CTFReaderException
{
315 * Remove the reader from the top of the priority queue.
317 StreamInputReader top
= fPrio
.poll();
320 * If the queue was empty.
326 * Read the next event of this reader.
328 switch (top
.readNextEvent()) {
331 * Add it back in the queue.
334 final long topEnd
= fTrace
.timestampCyclesToNanos(top
.getCurrentEvent().getTimestamp());
335 setEndTime(Math
.max(topEnd
, getEndTime()));
336 fEventCountPerTraceFile
[top
.getName()]++;
338 if (top
.getCurrentEvent() != null) {
339 fEndTime
= Math
.max(top
.getCurrentEvent().getTimestamp(),
352 // something bad happend
355 * If there is no reader in the queue, it means the trace reader reached
356 * the end of the trace.
358 return hasMoreEvents();
362 * Go to the last event in the trace.
364 * @throws CTFReaderException
367 public void goToLastEvent() throws CTFReaderException
{
369 while (fPrio
.size() > 1) {
375 * Seeks to a given timestamp. It will seek to the nearest event greater or
376 * equal to timestamp. If a trace is [10 20 30 40] and you are looking for
377 * 19, it will give you 20. If you want 20, you will get 20, if you want 21,
378 * you will get 30. The value -inf will seek to the first element and the
379 * value +inf will seek to the end of the file (past the last event).
382 * the timestamp to seek to
383 * @return true if there are events above or equal the seek timestamp, false
384 * if seek at the end of the trace (no valid event).
385 * @throws CTFReaderException
388 public boolean seek(long timestamp
) throws CTFReaderException
{
390 * Remove all the trace readers from the priority queue
393 for (StreamInputReader streamInputReader
: fStreamInputReaders
) {
395 * Seek the trace reader.
397 streamInputReader
.seek(timestamp
);
400 * Add it to the priority queue if there is a current event.
402 if (streamInputReader
.getCurrentEvent() != null) {
403 fPrio
.add(streamInputReader
);
406 return hasMoreEvents();
410 * Gets the stream with the oldest event
412 * @return the stream with the oldest event
414 public StreamInputReader
getTopStream() {
419 * Does the trace have more events?
421 * @return true if yes.
423 public final boolean hasMoreEvents() {
424 return fPrio
.size() > 0;
428 * Prints the event count stats.
430 public void printStats() {
435 * Prints the event count stats.
438 * Width of the display.
440 public void printStats(int width
) {
446 for (long i
: fEventCountPerTraceFile
) {
450 for (int j
= 0; j
< fEventCountPerTraceFile
.length
; j
++) {
451 StreamInputReader se
= fStreamInputReaders
.get(j
);
453 long len
= (width
* fEventCountPerTraceFile
[se
.getName()])
456 StringBuilder sb
= new StringBuilder(se
.getFilename());
457 sb
.append("\t["); //$NON-NLS-1$
459 for (int i
= 0; i
< len
; i
++) {
463 for (long i
= len
; i
< width
; i
++) {
467 sb
.append("]\t" + fEventCountPerTraceFile
[se
.getName()] + " Events"); //$NON-NLS-1$//$NON-NLS-2$
468 Activator
.log(sb
.toString());
473 * Gets the last event timestamp that was read. This is NOT necessarily the
474 * last event in a trace, just the last one read so far.
476 * @return the last event
478 public long getEndTime() {
483 * Sets a trace to be live or not
486 * whether the trace is live
489 public void setLive(boolean live
) {
490 for (StreamInputReader s
: fPrio
) {
496 * Get if the trace is to read live or not
498 * @return whether the trace is live or not
502 public boolean isLive() {
503 return fPrio
.peek().isLive();
507 public int hashCode() {
508 final int prime
= 31;
510 result
= (prime
* result
) + (int) (fStartTime ^
(fStartTime
>>> 32));
511 result
= (prime
* result
) + fStreamInputReaders
.hashCode();
512 result
= (prime
* result
) + ((fTrace
== null) ?
0 : fTrace
.hashCode());
517 public boolean equals(Object obj
) {
524 if (!(obj
instanceof CTFTraceReader
)) {
527 CTFTraceReader other
= (CTFTraceReader
) obj
;
528 if (!fStreamInputReaders
.equals(other
.fStreamInputReaders
)) {
531 if (fTrace
== null) {
532 if (other
.fTrace
!= null) {
535 } else if (!fTrace
.equals(other
.fTrace
)) {
542 public String
toString() {
543 /* Only for debugging, shouldn't be externalized */
544 return "CTFTraceReader [trace=" + fTrace
+ ']'; //$NON-NLS-1$
548 * Gets the parent trace
550 * @return the parent trace
552 public CTFTrace
getTrace() {