1 /*******************************************************************************
2 * Copyright (c) 2011, 2015 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: Simon Marchi - Initial API and implementation
11 *******************************************************************************/
13 package org
.eclipse
.tracecompass
.ctf
.core
.trace
;
15 import static org
.eclipse
.tracecompass
.common
.core
.NonNullUtils
.checkNotNull
;
18 import java
.io
.IOException
;
19 import java
.nio
.channels
.FileChannel
;
20 import java
.nio
.file
.StandardOpenOption
;
22 import org
.eclipse
.jdt
.annotation
.NonNullByDefault
;
23 import org
.eclipse
.jdt
.annotation
.Nullable
;
24 import org
.eclipse
.tracecompass
.common
.core
.NonNullUtils
;
25 import org
.eclipse
.tracecompass
.ctf
.core
.CTFException
;
26 import org
.eclipse
.tracecompass
.ctf
.core
.event
.EventDefinition
;
27 import org
.eclipse
.tracecompass
.ctf
.core
.event
.IEventDeclaration
;
28 import org
.eclipse
.tracecompass
.ctf
.core
.event
.types
.StructDeclaration
;
29 import org
.eclipse
.tracecompass
.internal
.ctf
.core
.Activator
;
31 import com
.google
.common
.collect
.ImmutableList
;
34 * A CTF trace event reader. Reads the events of a trace file.
36 * @author Matthew Khouzam
37 * @author Simon Marchi
41 public class CTFStreamInputReader
implements AutoCloseable
{
43 // ------------------------------------------------------------------------
45 // ------------------------------------------------------------------------
48 * The StreamInput we are reading.
50 private final File fFile
;
52 private final CTFStreamInput fStreamInput
;
54 private final @Nullable FileChannel fFileChannel
;
57 * The packet reader used to read packets from this trace file.
59 private final CTFStreamInputPacketReader fPacketReader
;
62 * Iterator on the packet index
64 private int fPacketIndex
;
67 * Reference to the current event of this trace file (iow, the last on that
68 * was read, the next one to be returned)
70 private @Nullable EventDefinition fCurrentEvent
= null;
77 private boolean fLive
= false;
79 // ------------------------------------------------------------------------
81 // ------------------------------------------------------------------------
83 * Constructs a StreamInputReader that reads a StreamInput.
86 * The StreamInput to read.
87 * @throws CTFException
88 * If the file cannot be opened
90 public CTFStreamInputReader(CTFStreamInput streamInput
) throws CTFException
{
91 fStreamInput
= streamInput
;
92 fFile
= fStreamInput
.getFile();
94 fFileChannel
= FileChannel
.open(fFile
.toPath(), StandardOpenOption
.READ
);
95 } catch (IOException e
) {
96 throw new CTFIOException(e
);
99 fPacketReader
= new CTFStreamInputPacketReader(this);
101 * Get the iterator on the packet index.
105 * Make first packet the current one.
108 } catch (Exception e
) {
111 } catch (IOException e1
) {
119 * Dispose the StreamInputReader, closes the file channel and its packet
122 * @throws IOException
123 * If an I/O error occurs
126 public void close() throws IOException
{
127 if (fFileChannel
!= null) {
128 fFileChannel
.close();
130 fPacketReader
.close();
133 // ------------------------------------------------------------------------
134 // Getters/Setters/Predicates
135 // ------------------------------------------------------------------------
138 * Gets the current event in this stream
140 * @return the current event in the stream, null if the stream is
141 * finished/empty/malformed
143 public @Nullable EventDefinition
getCurrentEvent() {
144 return fCurrentEvent
;
148 * Gets the name of the stream (it's an id and a number)
150 * @return gets the stream name (it's a number)
152 public int getName() {
157 * Sets the name of the stream
160 * the name of the stream, (it's a number)
162 public void setName(int name
) {
167 * Gets the CPU of a stream. It's the same as the one in /proc or running
168 * the asm CPUID instruction
170 * @return The CPU id (a number)
172 public int getCPU() {
173 return fPacketReader
.getCPU();
177 * Gets the filename of the stream being read
179 * @return The filename of the stream being read
181 public String
getFilename() {
182 return fStreamInput
.getFilename();
186 * for internal use only
188 CTFStreamInput
getStreamInput() {
193 * Gets the event definition set for this StreamInput
195 * @return Unmodifiable set with the event definitions
197 public Iterable
<IEventDeclaration
> getEventDeclarations() {
198 return checkNotNull(ImmutableList
.copyOf(fStreamInput
.getStream().getEventDeclarations()));
202 * Set the trace to live mode
205 * whether the trace is read live or not
207 public void setLive(boolean live
) {
212 * Get if the trace is to read live or not
214 * @return whether the trace is live or not
216 public boolean isLive() {
221 * Get the event context of the stream
223 * @return the event context declaration of the stream
225 public @Nullable StructDeclaration
getStreamEventContextDecl() {
226 return getStreamInput().getStream().getEventContextDecl();
229 // ------------------------------------------------------------------------
231 // ------------------------------------------------------------------------
233 * Reads the next event in the current event variable.
235 * @return If an event has been successfully read.
236 * @throws CTFException
239 public CTFResponse
readNextEvent() throws CTFException
{
242 * Change packet if needed
244 if (!fPacketReader
.hasMoreEvents()) {
245 final ICTFPacketDescriptor prevPacket
= fPacketReader
.getCurrentPacket();
246 if (prevPacket
!= null || fLive
) {
253 * If an event is available, read it.
255 if (fPacketReader
.hasMoreEvents()) {
256 setCurrentEvent(fPacketReader
.readNextEvent());
257 return CTFResponse
.OK
;
259 this.setCurrentEvent(null);
260 return fLive ? CTFResponse
.WAIT
: CTFResponse
.FINISH
;
264 * Change the current packet of the packet reader to the next one.
266 * @throws CTFException
269 private void goToNextPacket() throws CTFException
{
271 // did we already index the packet?
272 if (getPacketSize() >= (fPacketIndex
+ 1)) {
273 fPacketReader
.setCurrentPacket(getPacket());
275 // go to the next packet if there is one, index it at the same time
276 if (fStreamInput
.addPacketHeaderIndex()) {
277 fPacketIndex
= getPacketSize() - 1;
278 fPacketReader
.setCurrentPacket(getPacket());
281 fPacketReader
.setCurrentPacket(null);
289 private int getPacketSize() {
290 return fStreamInput
.getIndex().size();
294 * Changes the location of the trace file reader so that the current event
295 * is the first event with a timestamp greater or equal the given timestamp.
298 * The timestamp to seek to.
299 * @return The offset compared to the current position
300 * @throws CTFException
303 public long seek(long timestamp
) throws CTFException
{
306 gotoPacket(timestamp
);
309 * index up to the desired timestamp.
311 while ((fPacketReader
.getCurrentPacket() != null)
312 && (fPacketReader
.getCurrentPacket().getTimestampEnd() < timestamp
)) {
314 fStreamInput
.addPacketHeaderIndex();
316 } catch (CTFException e
) {
318 Activator
.log(e
.getMessage());
321 if (fPacketReader
.getCurrentPacket() == null) {
322 gotoPacket(timestamp
);
326 * Advance until either of these conditions are met:
328 * - reached the end of the trace file (the given timestamp is after the
331 * - found the first event with a timestamp greater or equal the given
335 EventDefinition currentEvent
= getCurrentEvent();
336 while (currentEvent
!= null && (currentEvent
.getTimestamp() < timestamp
)) {
338 currentEvent
= getCurrentEvent();
347 * @throws CTFException
350 private void gotoPacket(long timestamp
) throws CTFException
{
351 fPacketIndex
= fStreamInput
.getIndex().search(timestamp
) - 1;
353 * Switch to this packet.
359 * Seeks the last event of a stream and returns it.
361 * @throws CTFException
364 public void goToLastEvent() throws CTFException
{
367 * Go to the beginning of the trace
372 * Check that there is at least one event
374 if ((fStreamInput
.getIndex().isEmpty()) || (!fPacketReader
.hasMoreEvents())) {
376 * This means the trace is empty. abort.
381 fPacketIndex
= fStreamInput
.getIndex().size() - 1;
383 * Go to last indexed packet
385 fPacketReader
.setCurrentPacket(getPacket());
388 * Keep going until you cannot
390 while (fPacketReader
.getCurrentPacket() != null) {
394 final int lastPacketIndex
= fStreamInput
.getIndex().size() - 1;
396 * Go to the last packet that contains events.
398 for (int pos
= lastPacketIndex
; pos
> 0; pos
--) {
400 fPacketReader
.setCurrentPacket(getPacket());
402 if (fPacketReader
.hasMoreEvents()) {
408 * Go until the end of that packet
410 EventDefinition prevEvent
= null;
411 while (fCurrentEvent
!= null) {
412 prevEvent
= fCurrentEvent
;
413 this.readNextEvent();
416 * Go back to the previous event
418 this.setCurrentEvent(prevEvent
);
422 * Sets the current event in a stream input reader
424 * @param currentEvent
427 public void setCurrentEvent(@Nullable EventDefinition currentEvent
) {
428 fCurrentEvent
= currentEvent
;
432 * @return the packetIndexIt
434 private int getPacketIndex() {
438 private @Nullable ICTFPacketDescriptor
getPacket() {
439 if (getPacketIndex() >= fStreamInput
.getIndex().size()) {
442 return fStreamInput
.getIndex().getElement(getPacketIndex());
446 * Get the file channel wrapped by this reader
448 * @return the file channel
451 FileChannel
getFc() {
456 * @return the packetReader
458 public CTFStreamInputPacketReader
getPacketReader() {
459 return fPacketReader
;
463 public int hashCode() {
464 final int prime
= 31;
466 result
= (prime
* result
) + fId
;
467 result
= (prime
* result
)
473 public boolean equals(@Nullable Object obj
) {
480 if (!(obj
instanceof CTFStreamInputReader
)) {
483 CTFStreamInputReader other
= (CTFStreamInputReader
) obj
;
484 if (fId
!= other
.fId
) {
487 return fFile
.equals(other
.fFile
);
491 public String
toString() {
492 // this helps debugging
493 return fId
+ ' ' + NonNullUtils
.nullToEmptyString(fCurrentEvent
);