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
;
16 import java
.io
.IOException
;
17 import java
.nio
.ByteBuffer
;
18 import java
.nio
.channels
.FileChannel
;
19 import java
.nio
.channels
.FileChannel
.MapMode
;
20 import java
.nio
.file
.StandardOpenOption
;
21 import java
.util
.List
;
23 import org
.eclipse
.jdt
.annotation
.NonNullByDefault
;
24 import org
.eclipse
.jdt
.annotation
.Nullable
;
25 import org
.eclipse
.tracecompass
.common
.core
.NonNullUtils
;
26 import org
.eclipse
.tracecompass
.ctf
.core
.CTFException
;
27 import org
.eclipse
.tracecompass
.ctf
.core
.event
.EventDefinition
;
28 import org
.eclipse
.tracecompass
.ctf
.core
.event
.IEventDeclaration
;
29 import org
.eclipse
.tracecompass
.ctf
.core
.event
.io
.BitBuffer
;
30 import org
.eclipse
.tracecompass
.ctf
.core
.event
.types
.IDeclaration
;
31 import org
.eclipse
.tracecompass
.ctf
.core
.event
.types
.StructDeclaration
;
32 import org
.eclipse
.tracecompass
.internal
.ctf
.core
.Activator
;
33 import org
.eclipse
.tracecompass
.internal
.ctf
.core
.SafeMappedByteBuffer
;
34 import org
.eclipse
.tracecompass
.internal
.ctf
.core
.trace
.CTFPacketReader
;
35 import org
.eclipse
.tracecompass
.internal
.ctf
.core
.trace
.NullPacketReader
;
38 * A CTF trace event reader. Reads the events of a trace file.
40 * @author Matthew Khouzam
41 * @author Simon Marchi
45 public class CTFStreamInputReader
implements AutoCloseable
{
47 private static final int BITS_PER_BYTE
= Byte
.SIZE
;
49 // ------------------------------------------------------------------------
51 // ------------------------------------------------------------------------
54 * The StreamInput we are reading.
56 private final File fFile
;
58 private final CTFStreamInput fStreamInput
;
60 private final @Nullable FileChannel fFileChannel
;
63 * The packet reader used to read packets from this trace file.
65 private IPacketReader fPacketReader
;
68 * Iterator on the packet index
70 private int fPacketIndex
;
73 * Reference to the current event of this trace file (iow, the last on that
74 * was read, the next one to be returned)
76 private @Nullable EventDefinition fCurrentEvent
= null;
83 private boolean fLive
= false;
85 // ------------------------------------------------------------------------
87 // ------------------------------------------------------------------------
89 * Constructs a StreamInputReader that reads a StreamInput.
92 * The StreamInput to read.
93 * @throws CTFException
94 * If the file cannot be opened
96 public CTFStreamInputReader(CTFStreamInput streamInput
) throws CTFException
{
97 fStreamInput
= streamInput
;
98 fFile
= fStreamInput
.getFile();
100 fFileChannel
= FileChannel
.open(fFile
.toPath(), StandardOpenOption
.READ
);
101 } catch (IOException e
) {
102 throw new CTFIOException(e
);
106 * Get the iterator on the packet index.
110 * Make first packet the current one.
112 // did we already index the packet?
113 if (getPacketSize() < (fPacketIndex
+ 1)) {
114 // go to the next packet if there is one, index it at the same
116 if (fStreamInput
.addPacketHeaderIndex()) {
117 fPacketIndex
= getPacketSize() - 1;
120 ICTFPacketDescriptor packet
= getPacket();
121 fPacketReader
= getCurrentPacketReader(packet
);
122 } catch (Exception e
) {
125 } catch (IOException e1
) {
132 private IPacketReader
getCurrentPacketReader(@Nullable ICTFPacketDescriptor packet
) throws CTFException
{
133 IPacketReader ctfPacketReader
= NullPacketReader
.INSTANCE
;
134 if (packet
!= null) {
135 long size
= packet
.getContentSizeBits();
137 throw new CTFIOException("Cannot have negative sized buffers."); //$NON-NLS-1$
139 BitBuffer bitBuffer
= new BitBuffer(getByteBufferAt(packet
.getOffsetBits(), size
));
140 bitBuffer
.position(packet
.getPayloadStartBits());
141 IDeclaration eventHeaderDeclaration
= getStreamInput().getStream().getEventHeaderDeclaration();
142 CTFTrace trace
= getStreamInput().getStream().getTrace();
143 ctfPacketReader
= new CTFPacketReader(bitBuffer
, packet
, getEventDeclarations(), eventHeaderDeclaration
, getStreamEventContextDecl(), trace
.getPacketHeaderDef(), trace
);
145 return ctfPacketReader
;
149 * Get a bytebuffer map of the file
152 * start offset in bits
154 * size of the map in bits, use caution
155 * @return a byte buffer
156 * @throws CTFException
157 * if the map failed in its allocation
161 public ByteBuffer
getByteBufferAt(long position
, long size
) throws CTFException
{
164 map
= SafeMappedByteBuffer
.map(fFileChannel
, MapMode
.READ_ONLY
, position
/ BITS_PER_BYTE
, (size
+ BITS_PER_BYTE
- 1) / BITS_PER_BYTE
);
165 } catch (IOException e
) {
166 throw new CTFIOException(e
.getMessage(), e
);
169 throw new CTFIOException("Failed to allocate mapped byte buffer"); //$NON-NLS-1$
175 * Dispose the StreamInputReader, closes the file channel and its packet
178 * @throws IOException
179 * If an I/O error occurs
182 public void close() throws IOException
{
183 if (fFileChannel
!= null) {
184 fFileChannel
.close();
186 fPacketReader
= NullPacketReader
.INSTANCE
;
189 // ------------------------------------------------------------------------
190 // Getters/Setters/Predicates
191 // ------------------------------------------------------------------------
194 * Gets the current event in this stream
196 * @return the current event in the stream, null if the stream is
197 * finished/empty/malformed
199 public @Nullable EventDefinition
getCurrentEvent() {
200 return fCurrentEvent
;
204 * Gets the name of the stream (it's an id and a number)
206 * @return gets the stream name (it's a number)
208 public int getName() {
213 * Sets the name of the stream
216 * the name of the stream, (it's a number)
218 public void setName(int name
) {
223 * Gets the CPU of a stream. It's the same as the one in /proc or running
224 * the asm CPUID instruction
226 * @return The CPU id (a number)
228 public int getCPU() {
229 return fPacketReader
.getCPU();
233 * Gets the filename of the stream being read
235 * @return The filename of the stream being read
237 public String
getFilename() {
238 return fStreamInput
.getFilename();
242 * for internal use only
244 CTFStreamInput
getStreamInput() {
249 * Gets the event definition set for this StreamInput
251 * @return Unmodifiable set with the event definitions
254 public List
<@Nullable IEventDeclaration
> getEventDeclarations() {
255 return fStreamInput
.getStream().getEventDeclarations();
259 * Set the trace to live mode
262 * whether the trace is read live or not
264 public void setLive(boolean live
) {
269 * Get if the trace is to read live or not
271 * @return whether the trace is live or not
273 public boolean isLive() {
278 * Get the event context of the stream
280 * @return the event context declaration of the stream
282 public @Nullable StructDeclaration
getStreamEventContextDecl() {
283 return getStreamInput().getStream().getEventContextDecl();
286 // ------------------------------------------------------------------------
288 // ------------------------------------------------------------------------
290 * Reads the next event in the current event variable.
292 * @return If an event has been successfully read.
293 * @throws CTFException
296 public CTFResponse
readNextEvent() throws CTFException
{
299 * Change packet if needed
301 if (!fPacketReader
.hasMoreEvents()) {
302 final ICTFPacketDescriptor prevPacket
= fPacketReader
.getCurrentPacket();
303 if (prevPacket
!= null || fLive
) {
310 * If an event is available, read it.
312 if (fPacketReader
.hasMoreEvents()) {
313 setCurrentEvent(fPacketReader
.readNextEvent());
314 return CTFResponse
.OK
;
316 this.setCurrentEvent(null);
317 return fLive ? CTFResponse
.WAIT
: CTFResponse
.FINISH
;
321 * Change the current packet of the packet reader to the next one.
323 * @throws CTFException
326 private void goToNextPacket() throws CTFException
{
328 // did we already index the packet?
329 while (getPacketSize() < (fPacketIndex
+ 1)) {
330 // go to the next packet if there is one, index it at the same time
331 if (fStreamInput
.addPacketHeaderIndex()) {
332 fPacketIndex
= getPacketSize() - 1;
334 fPacketReader
= NullPacketReader
.INSTANCE
;
339 ICTFPacketDescriptor packet
= getPacket();
340 fPacketReader
= getCurrentPacketReader(packet
);
347 private int getPacketSize() {
348 return fStreamInput
.getIndex().size();
352 * Changes the location of the trace file reader so that the current event
353 * is the first event with a timestamp greater or equal the given timestamp.
356 * The timestamp to seek to.
357 * @return The offset compared to the current position
358 * @throws CTFException
361 public long seek(long timestamp
) throws CTFException
{
364 gotoPacket(timestamp
);
367 * index up to the desired timestamp.
369 while ((fPacketReader
.getCurrentPacket() != null)
370 && (fPacketReader
.getCurrentPacket().getTimestampEnd() < timestamp
)) {
372 fStreamInput
.addPacketHeaderIndex();
374 } catch (CTFException e
) {
376 Activator
.log(e
.getMessage());
379 if (fPacketReader
.getCurrentPacket() == null) {
380 gotoPacket(timestamp
);
384 * Advance until either of these conditions are met:
386 * - reached the end of the trace file (the given timestamp is after the
389 * - found the first event with a timestamp greater or equal the given
393 EventDefinition currentEvent
= getCurrentEvent();
394 while (currentEvent
!= null && (currentEvent
.getTimestamp() < timestamp
)) {
396 currentEvent
= getCurrentEvent();
405 * @throws CTFException
408 private void gotoPacket(long timestamp
) throws CTFException
{
409 fPacketIndex
= fStreamInput
.getIndex().search(timestamp
) - 1;
411 * Switch to this packet.
417 * Seeks the last event of a stream and returns it.
419 * @throws CTFException
422 public void goToLastEvent() throws CTFException
{
425 * Go to the beginning of the trace
430 * Check that there is at least one event
432 if ((fStreamInput
.getIndex().isEmpty()) || (!fPacketReader
.hasMoreEvents())) {
434 * This means the trace is empty. abort.
439 fPacketIndex
= fStreamInput
.getIndex().size() - 1;
441 * Go to last indexed packet
443 fPacketReader
= getCurrentPacketReader(getPacket());
446 * Keep going until you cannot
448 while (fPacketReader
.getCurrentPacket() != null) {
452 final int lastPacketIndex
= fStreamInput
.getIndex().size() - 1;
454 * Go to the last packet that contains events.
456 for (int pos
= lastPacketIndex
; pos
> 0; pos
--) {
458 fPacketReader
= getCurrentPacketReader(getPacket());
460 if (fPacketReader
.hasMoreEvents()) {
466 * Go until the end of that packet
468 EventDefinition prevEvent
= null;
469 while (fCurrentEvent
!= null) {
470 prevEvent
= fCurrentEvent
;
471 this.readNextEvent();
474 * Go back to the previous event
476 this.setCurrentEvent(prevEvent
);
480 * Sets the current event in a stream input reader
482 * @param currentEvent
485 public void setCurrentEvent(@Nullable EventDefinition currentEvent
) {
486 fCurrentEvent
= currentEvent
;
490 * @return the packetIndexIt
492 private int getPacketIndex() {
496 private @Nullable ICTFPacketDescriptor
getPacket() {
497 if (getPacketIndex() >= fStreamInput
.getIndex().size()) {
500 return fStreamInput
.getIndex().getElement(getPacketIndex());
504 * Get the current packet reader
506 * @return the packetReader
509 public IPacketReader
getCurrentPacketReader() {
510 return fPacketReader
;
514 public int hashCode() {
515 final int prime
= 31;
517 result
= (prime
* result
) + fId
;
518 result
= (prime
* result
)
524 public boolean equals(@Nullable Object obj
) {
531 if (!(obj
instanceof CTFStreamInputReader
)) {
534 CTFStreamInputReader other
= (CTFStreamInputReader
) obj
;
535 if (fId
!= other
.fId
) {
538 return fFile
.equals(other
.fFile
);
542 public String
toString() {
543 // this helps debugging
544 return fId
+ ' ' + NonNullUtils
.nullToEmptyString(fCurrentEvent
);