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
.io
.IOException
;
17 import java
.util
.ArrayList
;
18 import java
.util
.HashSet
;
19 import java
.util
.List
;
20 import java
.util
.PriorityQueue
;
23 import org
.eclipse
.linuxtools
.ctf
.core
.event
.EventDefinition
;
24 import org
.eclipse
.linuxtools
.ctf
.core
.event
.IEventDeclaration
;
25 import org
.eclipse
.linuxtools
.internal
.ctf
.core
.Activator
;
26 import org
.eclipse
.linuxtools
.internal
.ctf
.core
.trace
.StreamInputReaderTimestampComparator
;
28 import com
.google
.common
.collect
.ImmutableSet
;
29 import com
.google
.common
.collect
.ImmutableSet
.Builder
;
32 * A CTF trace reader. Reads the events of a trace.
35 * @author Matthew Khouzam
36 * @author Alexandre Montplaisir
38 public class CTFTraceReader
implements AutoCloseable
{
40 private static final int MIN_PRIO_SIZE
= 16;
42 // ------------------------------------------------------------------------
44 // ------------------------------------------------------------------------
47 * The trace to read from.
49 private final CTFTrace fTrace
;
52 * Vector of all the trace file readers.
54 private final List
<CTFStreamInputReader
> fStreamInputReaders
= new ArrayList
<>();
57 * Priority queue to order the trace file readers by timestamp.
59 private PriorityQueue
<CTFStreamInputReader
> fPrio
;
62 * Array to count the number of event per trace file.
64 private long[] fEventCountPerTraceFile
;
67 * Timestamp of the first event in the trace
69 private long fStartTime
;
72 * Timestamp of the last event read so far
74 private long fEndTime
;
76 // ------------------------------------------------------------------------
78 // ------------------------------------------------------------------------
81 * Constructs a TraceReader to read a trace.
84 * The trace to read from.
85 * @throws CTFReaderException
88 public CTFTraceReader(CTFTrace trace
) throws CTFReaderException
{
90 fStreamInputReaders
.clear();
93 * Create the trace file readers.
95 createStreamInputReaders();
98 * Populate the timestamp-based priority queue.
100 populateStreamInputReaderHeap();
103 * Get the start Time of this trace bear in mind that the trace could be
107 if (hasMoreEvents()) {
108 fStartTime
= getTopStream().getCurrentEvent().getTimestamp();
109 setEndTime(fStartTime
);
116 * @return The new CTFTraceReader
117 * @throws CTFReaderException
120 public CTFTraceReader
copyFrom() throws CTFReaderException
{
121 CTFTraceReader newReader
= null;
123 newReader
= new CTFTraceReader(fTrace
);
124 newReader
.fStartTime
= fStartTime
;
125 newReader
.setEndTime(fEndTime
);
130 * Dispose the CTFTraceReader
135 public void close() {
136 for (CTFStreamInputReader reader
: fStreamInputReaders
) {
137 if (reader
!= null) {
140 } catch (IOException e
) {
141 Activator
.logError(e
.getMessage(), e
);
145 fStreamInputReaders
.clear();
148 // ------------------------------------------------------------------------
149 // Getters/Setters/Predicates
150 // ------------------------------------------------------------------------
153 * Return the start time of this trace (== timestamp of the first event)
155 * @return the trace start time
157 public long getStartTime() {
162 * Set the trace's end time
165 * The end time to use
167 protected final void setEndTime(long endTime
) {
172 * Get the priority queue of this trace reader.
174 * @return The priority queue of input readers
177 protected PriorityQueue
<CTFStreamInputReader
> getPrio() {
181 // ------------------------------------------------------------------------
183 // ------------------------------------------------------------------------
186 * Creates one trace file reader per trace file contained in the trace.
188 * @throws CTFReaderException
191 private void createStreamInputReaders() throws CTFReaderException
{
195 for (CTFStream stream
: fTrace
.getStreams()) {
196 Set
<CTFStreamInput
> streamInputs
= stream
.getStreamInputs();
199 * For each trace file of the stream.
201 for (CTFStreamInput streamInput
: streamInputs
) {
204 * Create a reader and add it to the group.
206 fStreamInputReaders
.add(new CTFStreamInputReader(streamInput
));
211 * Create the array to count the number of event per trace file.
213 fEventCountPerTraceFile
= new long[fStreamInputReaders
.size()];
217 * Update the priority queue to make it match the parent trace
219 * @throws CTFReaderException
224 public void update() throws CTFReaderException
{
225 Set
<CTFStreamInputReader
> readers
= new HashSet
<>();
226 for (CTFStream stream
: fTrace
.getStreams()) {
227 Set
<CTFStreamInput
> streamInputs
= stream
.getStreamInputs();
228 for (CTFStreamInput streamInput
: streamInputs
) {
232 CTFStreamInputReader streamInputReader
= new CTFStreamInputReader(
236 * Add it to the group.
238 if (!fStreamInputReaders
.contains(streamInputReader
)) {
239 streamInputReader
.readNextEvent();
240 fStreamInputReaders
.add(streamInputReader
);
241 readers
.add(streamInputReader
);
245 long[] temp
= fEventCountPerTraceFile
;
246 fEventCountPerTraceFile
= new long[readers
.size() + temp
.length
];
247 for (CTFStreamInputReader reader
: readers
) {
250 for (int i
= 0; i
< temp
.length
; i
++) {
251 fEventCountPerTraceFile
[i
] = temp
[i
];
256 * Gets an iterable of the stream input readers, useful for foreaches
258 * @return the iterable of the stream input readers
261 public Iterable
<IEventDeclaration
> getEventDeclarations() {
262 ImmutableSet
.Builder
<IEventDeclaration
> builder
= new Builder
<>();
263 for (CTFStreamInputReader sir
: fStreamInputReaders
) {
264 builder
.addAll(sir
.getEventDeclarations());
266 return builder
.build();
270 * Initializes the priority queue used to choose the trace file with the
271 * lower next event timestamp.
273 * @throws CTFReaderException
276 private void populateStreamInputReaderHeap() throws CTFReaderException
{
277 if (fStreamInputReaders
.isEmpty()) {
278 fPrio
= new PriorityQueue
<>(MIN_PRIO_SIZE
,
279 new StreamInputReaderTimestampComparator());
284 * Create the priority queue with a size twice as bigger as the number
285 * of reader in order to avoid constant resizing.
287 fPrio
= new PriorityQueue
<>(
288 Math
.max(fStreamInputReaders
.size() * 2, MIN_PRIO_SIZE
),
289 new StreamInputReaderTimestampComparator());
293 for (CTFStreamInputReader reader
: fStreamInputReaders
) {
295 * Add each trace file reader in the priority queue, if we are able
296 * to read an event from it.
298 reader
.setParent(this);
299 CTFResponse readNextEvent
= reader
.readNextEvent();
300 if (readNextEvent
== CTFResponse
.OK
|| readNextEvent
== CTFResponse
.WAIT
) {
303 fEventCountPerTraceFile
[pos
] = 0;
312 * Get the current event, which is the current event of the trace file
313 * reader with the lowest timestamp.
315 * @return An event definition, or null of the trace reader reached the end
318 public EventDefinition
getCurrentEventDef() {
319 CTFStreamInputReader top
= getTopStream();
320 return (top
!= null) ? top
.getCurrentEvent() : null;
324 * Go to the next event.
326 * @return True if an event was read.
327 * @throws CTFReaderException
330 public boolean advance() throws CTFReaderException
{
332 * Remove the reader from the top of the priority queue.
334 CTFStreamInputReader top
= fPrio
.poll();
337 * If the queue was empty.
343 * Read the next event of this reader.
345 switch (top
.readNextEvent()) {
348 * Add it back in the queue.
351 final long topEnd
= fTrace
.timestampCyclesToNanos(top
.getCurrentEvent().getTimestamp());
352 setEndTime(Math
.max(topEnd
, getEndTime()));
353 fEventCountPerTraceFile
[top
.getName()]++;
355 if (top
.getCurrentEvent() != null) {
356 fEndTime
= Math
.max(top
.getCurrentEvent().getTimestamp(),
369 // something bad happend
372 * If there is no reader in the queue, it means the trace reader reached
373 * the end of the trace.
375 return hasMoreEvents();
379 * Go to the last event in the trace.
381 * @throws CTFReaderException
384 public void goToLastEvent() throws CTFReaderException
{
386 while (fPrio
.size() > 1) {
392 * Seeks to a given timestamp. It will seek to the nearest event greater or
393 * equal to timestamp. If a trace is [10 20 30 40] and you are looking for
394 * 19, it will give you 20. If you want 20, you will get 20, if you want 21,
395 * you will get 30. The value -inf will seek to the first element and the
396 * value +inf will seek to the end of the file (past the last event).
399 * the timestamp to seek to
400 * @return true if there are events above or equal the seek timestamp, false
401 * if seek at the end of the trace (no valid event).
402 * @throws CTFReaderException
405 public boolean seek(long timestamp
) throws CTFReaderException
{
407 * Remove all the trace readers from the priority queue
410 for (CTFStreamInputReader streamInputReader
: fStreamInputReaders
) {
412 * Seek the trace reader.
414 streamInputReader
.seek(timestamp
);
417 * Add it to the priority queue if there is a current event.
419 if (streamInputReader
.getCurrentEvent() != null) {
420 fPrio
.add(streamInputReader
);
423 return hasMoreEvents();
427 * Gets the stream with the oldest event
429 * @return the stream with the oldest event
432 public CTFStreamInputReader
getTopStream() {
437 * Does the trace have more events?
439 * @return true if yes.
441 public final boolean hasMoreEvents() {
442 return fPrio
.size() > 0;
446 * Prints the event count stats.
448 public void printStats() {
453 * Prints the event count stats.
456 * Width of the display.
458 public void printStats(int width
) {
464 for (long i
: fEventCountPerTraceFile
) {
468 for (int j
= 0; j
< fEventCountPerTraceFile
.length
; j
++) {
469 CTFStreamInputReader se
= fStreamInputReaders
.get(j
);
471 long len
= (width
* fEventCountPerTraceFile
[se
.getName()])
474 StringBuilder sb
= new StringBuilder(se
.getFilename());
475 sb
.append("\t["); //$NON-NLS-1$
477 for (int i
= 0; i
< len
; i
++) {
481 for (long i
= len
; i
< width
; i
++) {
485 sb
.append("]\t" + fEventCountPerTraceFile
[se
.getName()] + " Events"); //$NON-NLS-1$//$NON-NLS-2$
486 Activator
.log(sb
.toString());
491 * Gets the last event timestamp that was read. This is NOT necessarily the
492 * last event in a trace, just the last one read so far.
494 * @return the last event
496 public long getEndTime() {
501 * Sets a trace to be live or not
504 * whether the trace is live
507 public void setLive(boolean live
) {
508 for (CTFStreamInputReader s
: fPrio
) {
514 * Get if the trace is to read live or not
516 * @return whether the trace is live or not
520 public boolean isLive() {
521 return getTopStream().isLive();
525 public int hashCode() {
526 final int prime
= 31;
528 result
= (prime
* result
) + (int) (fStartTime ^
(fStartTime
>>> 32));
529 result
= (prime
* result
) + fStreamInputReaders
.hashCode();
530 result
= (prime
* result
) + ((fTrace
== null) ?
0 : fTrace
.hashCode());
535 public boolean equals(Object obj
) {
542 if (!(obj
instanceof CTFTraceReader
)) {
545 CTFTraceReader other
= (CTFTraceReader
) obj
;
546 if (!fStreamInputReaders
.equals(other
.fStreamInputReaders
)) {
549 if (fTrace
== null) {
550 if (other
.fTrace
!= null) {
553 } else if (!fTrace
.equals(other
.fTrace
)) {
560 public String
toString() {
561 /* Only for debugging, shouldn't be externalized */
562 return "CTFTraceReader [trace=" + fTrace
+ ']'; //$NON-NLS-1$
566 * Gets the parent trace
568 * @return the parent trace
570 public CTFTrace
getTrace() {