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
9 * Contributors: Matthew Khouzam - Initial API and implementation
10 * Contributors: Simon Marchi - Initial API and implementation
11 *******************************************************************************/
13 package org
.eclipse
.linuxtools
.ctf
.core
.trace
;
15 import java
.nio
.ByteOrder
;
16 import java
.util
.Collections
;
17 import java
.util
.HashMap
;
20 import org
.eclipse
.linuxtools
.ctf
.core
.event
.EventDefinition
;
21 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.StructDefinition
;
22 import org
.eclipse
.linuxtools
.internal
.ctf
.core
.trace
.StreamInputPacketIndexEntry
;
25 * A CTF trace event reader. Reads the events of a trace file.
28 * @author Matthew Khouzam
29 * @author Simon Marchi
31 public class StreamInputReader
implements AutoCloseable
{
33 // ------------------------------------------------------------------------
35 // ------------------------------------------------------------------------
38 * The StreamInput we are reading.
40 private final StreamInput fStreamInput
;
43 * The packet reader used to read packets from this trace file.
45 private final StreamInputPacketReader fPacketReader
;
48 * Iterator on the packet index
50 private int fPacketIndex
;
53 * Reference to the current event of this trace file (iow, the last on that
54 * was read, the next one to be returned)
56 private EventDefinition fCurrentEvent
= null;
60 private CTFTraceReader fParent
;
62 /** Map of all the event types */
63 private final Map
<Long
, EventDefinition
> fEventDefs
= new HashMap
<>();
68 private boolean fLive
= false;
70 // ------------------------------------------------------------------------
72 // ------------------------------------------------------------------------
75 * Constructs a StreamInputReader that reads a StreamInput.
78 * The StreamInput to read.
79 * @throws CTFReaderException
83 public StreamInputReader(StreamInput streamInput
) throws CTFReaderException
{
84 fStreamInput
= streamInput
;
85 fPacketReader
= new StreamInputPacketReader(this);
87 * Get the iterator on the packet index.
91 * Make first packet the current one.
97 * Dispose the StreamInputReader
102 public void close() {
103 fPacketReader
.close();
106 // ------------------------------------------------------------------------
107 // Getters/Setters/Predicates
108 // ------------------------------------------------------------------------
111 * Gets the current event in this stream
113 * @return the current event in the stream, null if the stream is
114 * finished/empty/malformed
116 public EventDefinition
getCurrentEvent() {
117 return fCurrentEvent
;
121 * Gets the current packet context
123 * @return the current packet context (size, lost events and such)
125 public StructDefinition
getCurrentPacketContext() {
126 return fPacketReader
.getStreamPacketContextDef();
130 * Gets the byte order for a trace
132 * @return the trace byte order
134 public ByteOrder
getByteOrder() {
135 return fStreamInput
.getStream().getTrace().getByteOrder();
139 * Gets the name of the stream (it's an id and a number)
141 * @return gets the stream name (it's a number)
143 public int getName() {
148 * Sets the name of the stream
151 * the name of the stream, (it's a number)
153 public void setName(int name
) {
158 * Gets the CPU of a stream. It's the same as the one in /proc or running
159 * the asm CPUID instruction
161 * @return The CPU id (a number)
163 public int getCPU() {
164 return fPacketReader
.getCPU();
168 * Gets the filename of the stream being read
170 * @return The filename of the stream being read
172 public String
getFilename() {
173 return fStreamInput
.getFilename();
177 * for internal use only
179 StreamInput
getStreamInput() {
184 * Gets the event definition hashmap for this StreamInput
186 * @return Unmodifiable map with the event definitions
189 public Map
<Long
, EventDefinition
> getEventDefinitions() {
190 return Collections
.unmodifiableMap(fEventDefs
);
194 * Add an event definition to this stream input reader.
197 * The id of the event definition. This will overwrite any
198 * existing definition with the same id.
200 * The matching event definition
203 public void addEventDefinition(Long id
, EventDefinition def
) {
204 fEventDefs
.put(id
, def
);
208 * Set the trace to live mode
211 * whether the trace is read live or not
214 public void setLive(boolean live
) {
219 * Get if the trace is to read live or not
221 * @return whether the trace is live or not
224 public boolean isLive() {
228 // ------------------------------------------------------------------------
230 // ------------------------------------------------------------------------
232 * Reads the next event in the current event variable.
234 * @return If an event has been successfully read.
235 * @throws CTFReaderException
239 public CTFResponse
readNextEvent() throws CTFReaderException
{
242 * Change packet if needed
244 if (!fPacketReader
.hasMoreEvents()) {
245 final StreamInputPacketIndexEntry prevPacket
= fPacketReader
247 if (prevPacket
!= null || fLive
) {
254 * If an event is available, read it.
256 if (fPacketReader
.hasMoreEvents()) {
257 setCurrentEvent(fPacketReader
.readNextEvent());
258 return CTFResponse
.OK
;
260 this.setCurrentEvent(null);
261 return fLive ? CTFResponse
.WAIT
: CTFResponse
.FINISH
;
265 * Change the current packet of the packet reader to the next one.
267 * @throws CTFReaderException
270 private void goToNextPacket() throws CTFReaderException
{
272 // did we already index the packet?
273 if (getPacketSize() >= (fPacketIndex
+ 1)) {
274 fPacketReader
.setCurrentPacket(getPacket());
276 // go to the next packet if there is one, index it at the same time
277 if (fStreamInput
.addPacketHeaderIndex()) {
278 fPacketIndex
= getPacketSize() - 1;
279 fPacketReader
.setCurrentPacket(getPacket());
282 fPacketReader
.setCurrentPacket(null);
290 private int getPacketSize() {
291 return fStreamInput
.getIndex().getEntries().size();
295 * Changes the location of the trace file reader so that the current event
296 * is the first event with a timestamp greater or equal the given timestamp.
299 * The timestamp to seek to.
300 * @return The offset compared to the current position
301 * @throws CTFReaderException
304 public long seek(long timestamp
) throws CTFReaderException
{
307 gotoPacket(timestamp
);
310 * index up to the desired timestamp.
312 while ((fPacketReader
.getCurrentPacket() != null)
313 && (fPacketReader
.getCurrentPacket().getTimestampEnd() < timestamp
)) {
315 fStreamInput
.addPacketHeaderIndex();
317 } catch (CTFReaderException e
) {
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 boolean done
= (this.getCurrentEvent() == null);
336 while (!done
&& (this.getCurrentEvent().getTimestamp() < timestamp
)) {
338 done
= (this.getCurrentEvent() == null);
347 * @throws CTFReaderException
350 private void gotoPacket(long timestamp
) throws CTFReaderException
{
351 fPacketIndex
= fStreamInput
.getIndex().search(timestamp
)
354 * Switch to this packet.
360 * Seeks the last event of a stream and returns it.
362 * @throws CTFReaderException
365 public void goToLastEvent() throws CTFReaderException
{
367 * Search in the index for the packet to search in.
369 final int len
= fStreamInput
.getIndex().getEntries().size();
372 * Go to beginning of trace.
376 * if the trace is empty.
378 if ((len
== 0) || (fPacketReader
.hasMoreEvents() == false)) {
380 * This means the trace is empty. abort.
385 * Go to the last packet that contains events.
387 for (int pos
= len
- 1; pos
> 0; pos
--) {
389 fPacketReader
.setCurrentPacket(getPacket());
390 if (fPacketReader
.hasMoreEvents()) {
396 * Go until the end of that packet
398 EventDefinition prevEvent
= null;
399 while (fCurrentEvent
!= null) {
400 prevEvent
= fCurrentEvent
;
401 this.readNextEvent();
404 * Go back to the previous event
406 this.setCurrentEvent(prevEvent
);
412 public CTFTraceReader
getParent() {
420 public void setParent(CTFTraceReader parent
) {
425 * Sets the current event in a stream input reader
427 * @param currentEvent
430 public void setCurrentEvent(EventDefinition currentEvent
) {
431 fCurrentEvent
= currentEvent
;
435 * @return the packetIndexIt
437 private int getPacketIndex() {
441 private StreamInputPacketIndexEntry
getPacket() {
442 return fStreamInput
.getIndex().getEntries().get(getPacketIndex());
446 * @return the packetReader
448 public StreamInputPacketReader
getPacketReader() {
449 return fPacketReader
;
453 public int hashCode() {
454 final int prime
= 31;
456 result
= (prime
* result
) + fId
;
457 result
= (prime
* result
)
458 + ((fStreamInput
== null) ?
0 : fStreamInput
.hashCode());
463 public boolean equals(Object obj
) {
470 if (!(obj
instanceof StreamInputReader
)) {
473 StreamInputReader other
= (StreamInputReader
) obj
;
474 if (fId
!= other
.fId
) {
477 if (fStreamInput
== null) {
478 if (other
.fStreamInput
!= null) {
481 } else if (!fStreamInput
.equals(other
.fStreamInput
)) {
488 public String
toString() {
489 // this helps debugging
490 return fId
+ ' ' + fCurrentEvent
.toString();