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
{
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
129 public void dispose() {
130 for (StreamInputReader reader
: fStreamInputReaders
) {
131 if (reader
!= null) {
135 fStreamInputReaders
.clear();
138 // ------------------------------------------------------------------------
139 // Getters/Setters/Predicates
140 // ------------------------------------------------------------------------
143 * Return the start time of this trace (== timestamp of the first event)
145 * @return the trace start time
147 public long getStartTime() {
152 * Set the trace's end time
155 * The end time to use
157 protected final void setEndTime(long endTime
) {
162 * Get the priority queue of this trace reader.
164 * @return The priority queue of input readers
167 protected PriorityQueue
<StreamInputReader
> getPrio() {
171 // ------------------------------------------------------------------------
173 // ------------------------------------------------------------------------
176 * Creates one trace file reader per trace file contained in the trace.
178 * @throws CTFReaderException
181 private void createStreamInputReaders() throws CTFReaderException
{
185 for (Stream stream
: fTrace
.getStreams()) {
186 Set
<StreamInput
> streamInputs
= stream
.getStreamInputs();
189 * For each trace file of the stream.
191 for (StreamInput streamInput
: streamInputs
) {
195 StreamInputReader streamInputReader
= new StreamInputReader(
199 * Add it to the group.
201 fStreamInputReaders
.add(streamInputReader
);
206 * Create the array to count the number of event per trace file.
208 fEventCountPerTraceFile
= new long[fStreamInputReaders
.size()];
212 * Update the priority queue to make it match the parent trace
214 * @throws CTFReaderException
219 public void update() throws CTFReaderException
{
220 Set
<StreamInputReader
> readers
= new HashSet
<>();
221 for (Stream stream
: fTrace
.getStreams()) {
222 Set
<StreamInput
> streamInputs
= stream
.getStreamInputs();
223 for (StreamInput streamInput
: streamInputs
) {
227 StreamInputReader streamInputReader
= new StreamInputReader(
231 * Add it to the group.
233 if (!fStreamInputReaders
.contains(streamInputReader
)) {
234 streamInputReader
.readNextEvent();
235 fStreamInputReaders
.add(streamInputReader
);
236 readers
.add(streamInputReader
);
240 long[] temp
= fEventCountPerTraceFile
;
241 fEventCountPerTraceFile
= new long[readers
.size() + temp
.length
];
242 for (StreamInputReader reader
: readers
) {
245 for (int i
= 0; i
< temp
.length
; i
++) {
246 fEventCountPerTraceFile
[i
] = temp
[i
];
251 * Initializes the priority queue used to choose the trace file with the
252 * lower next event timestamp.
254 * @throws CTFReaderException
257 private void populateStreamInputReaderHeap() throws CTFReaderException
{
258 if (fStreamInputReaders
.isEmpty()) {
259 fPrio
= new PriorityQueue
<>(MIN_PRIO_SIZE
,
260 new StreamInputReaderTimestampComparator());
265 * Create the priority queue with a size twice as bigger as the number
266 * of reader in order to avoid constant resizing.
268 fPrio
= new PriorityQueue
<>(
269 Math
.max(fStreamInputReaders
.size() * 2, MIN_PRIO_SIZE
),
270 new StreamInputReaderTimestampComparator());
274 for (StreamInputReader reader
: fStreamInputReaders
) {
276 * Add each trace file reader in the priority queue, if we are able
277 * to read an event from it.
279 reader
.setParent(this);
280 CTFResponse readNextEvent
= reader
.readNextEvent();
281 if (readNextEvent
== CTFResponse
.OK
|| readNextEvent
== CTFResponse
.WAIT
) {
284 fEventCountPerTraceFile
[pos
] = 0;
293 * Get the current event, which is the current event of the trace file
294 * reader with the lowest timestamp.
296 * @return An event definition, or null of the trace reader reached the end
299 public EventDefinition
getCurrentEventDef() {
300 StreamInputReader top
= getTopStream();
302 return (top
!= null) ? top
.getCurrentEvent() : null;
306 * Go to the next event.
308 * @return True if an event was read.
309 * @throws CTFReaderException
312 public boolean advance() throws CTFReaderException
{
314 * Remove the reader from the top of the priority queue.
316 StreamInputReader top
= fPrio
.poll();
319 * If the queue was empty.
325 * Read the next event of this reader.
327 switch (top
.readNextEvent()) {
330 * Add it back in the queue.
333 final long topEnd
= fTrace
.timestampCyclesToNanos(top
.getCurrentEvent().getTimestamp());
334 setEndTime(Math
.max(topEnd
, getEndTime()));
335 fEventCountPerTraceFile
[top
.getName()]++;
337 if (top
.getCurrentEvent() != null) {
338 fEndTime
= Math
.max(top
.getCurrentEvent().getTimestamp(),
351 // something bad happend
354 * If there is no reader in the queue, it means the trace reader reached
355 * the end of the trace.
357 return hasMoreEvents();
361 * Go to the last event in the trace.
363 * @throws CTFReaderException
366 public void goToLastEvent() throws CTFReaderException
{
368 while (fPrio
.size() > 1) {
374 * Seeks to a given timestamp. It will seek to the nearest event greater or
375 * equal to timestamp. If a trace is [10 20 30 40] and you are looking for
376 * 19, it will give you 20. If you want 20, you will get 20, if you want 21,
377 * you will get 30. The value -inf will seek to the first element and the
378 * value +inf will seek to the end of the file (past the last event).
381 * the timestamp to seek to
382 * @return true if there are events above or equal the seek timestamp, false
383 * if seek at the end of the trace (no valid event).
384 * @throws CTFReaderException
387 public boolean seek(long timestamp
) throws CTFReaderException
{
389 * Remove all the trace readers from the priority queue
392 for (StreamInputReader streamInputReader
: fStreamInputReaders
) {
394 * Seek the trace reader.
396 streamInputReader
.seek(timestamp
);
399 * Add it to the priority queue if there is a current event.
401 if (streamInputReader
.getCurrentEvent() != null) {
402 fPrio
.add(streamInputReader
);
405 return hasMoreEvents();
409 * Gets the stream with the oldest event
411 * @return the stream with the oldest event
413 public StreamInputReader
getTopStream() {
418 * Does the trace have more events?
420 * @return true if yes.
422 public final boolean hasMoreEvents() {
423 return fPrio
.size() > 0;
427 * Prints the event count stats.
429 public void printStats() {
434 * Prints the event count stats.
437 * Width of the display.
439 public void printStats(int width
) {
445 for (long i
: fEventCountPerTraceFile
) {
449 for (int j
= 0; j
< fEventCountPerTraceFile
.length
; j
++) {
450 StreamInputReader se
= fStreamInputReaders
.get(j
);
452 long len
= (width
* fEventCountPerTraceFile
[se
.getName()])
455 StringBuilder sb
= new StringBuilder(se
.getFilename());
456 sb
.append("\t["); //$NON-NLS-1$
458 for (int i
= 0; i
< len
; i
++) {
462 for (long i
= len
; i
< width
; i
++) {
466 sb
.append("]\t" + fEventCountPerTraceFile
[se
.getName()] + " Events"); //$NON-NLS-1$//$NON-NLS-2$
467 Activator
.log(sb
.toString());
472 * Gets the last event timestamp that was read. This is NOT necessarily the
473 * last event in a trace, just the last one read so far.
475 * @return the last event
477 public long getEndTime() {
482 * Sets a trace to be live or not
485 * whether the trace is live
488 public void setLive(boolean live
) {
489 for (StreamInputReader s
: fPrio
) {
495 * Get if the trace is to read live or not
497 * @return whether the trace is live or not
501 public boolean isLive() {
502 return fPrio
.peek().isLive();
506 public int hashCode() {
507 final int prime
= 31;
509 result
= (prime
* result
) + (int) (fStartTime ^
(fStartTime
>>> 32));
510 result
= (prime
* result
) + fStreamInputReaders
.hashCode();
511 result
= (prime
* result
) + ((fTrace
== null) ?
0 : fTrace
.hashCode());
516 public boolean equals(Object obj
) {
523 if (!(obj
instanceof CTFTraceReader
)) {
526 CTFTraceReader other
= (CTFTraceReader
) obj
;
527 if (!fStreamInputReaders
.equals(other
.fStreamInputReaders
)) {
530 if (fTrace
== null) {
531 if (other
.fTrace
!= null) {
534 } else if (!fTrace
.equals(other
.fTrace
)) {
541 public String
toString() {
542 /* Only for debugging, shouldn't be externalized */
543 return "CTFTraceReader [trace=" + fTrace
+ ']'; //$NON-NLS-1$
547 * Gets the parent trace
549 * @return the parent trace
551 public CTFTrace
getTrace() {