1 /*******************************************************************************
2 * Copyright (c) 2011-2013 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 *******************************************************************************/
12 package org
.eclipse
.linuxtools
.ctf
.core
.trace
;
14 import java
.io
.IOException
;
15 import java
.nio
.ByteBuffer
;
16 import java
.util
.Collection
;
18 import org
.eclipse
.linuxtools
.ctf
.core
.CTFStrings
;
19 import org
.eclipse
.linuxtools
.ctf
.core
.event
.EventDefinition
;
20 import org
.eclipse
.linuxtools
.ctf
.core
.event
.IEventDeclaration
;
21 import org
.eclipse
.linuxtools
.ctf
.core
.event
.io
.BitBuffer
;
22 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.Definition
;
23 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.IDefinitionScope
;
24 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.IntegerDefinition
;
25 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.SimpleDatatypeDefinition
;
26 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.StructDeclaration
;
27 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.StructDefinition
;
28 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.VariantDefinition
;
29 import org
.eclipse
.linuxtools
.internal
.ctf
.core
.event
.EventDeclaration
;
30 import org
.eclipse
.linuxtools
.internal
.ctf
.core
.trace
.StreamInputPacketIndexEntry
;
33 * CTF trace packet reader. Reads the events of a packet of a trace file.
36 * @author Matthew Khouzam
37 * @author Simon Marchi
39 public class StreamInputPacketReader
implements IDefinitionScope
{
41 // ------------------------------------------------------------------------
43 // ------------------------------------------------------------------------
45 /** BitBuffer used to read the trace file. */
46 private final BitBuffer fBitBuffer
;
48 /** StreamInputReader that uses this StreamInputPacketReader. */
49 private final StreamInputReader fStreamInputReader
;
51 /** Trace packet header. */
52 private final StructDefinition fTracePacketHeaderDef
;
54 /** Stream packet context definition. */
55 private final StructDefinition fStreamPacketContextDef
;
57 /** Stream event header definition. */
58 private final StructDefinition fStreamEventHeaderDef
;
60 /** Stream event context definition. */
61 private final StructDefinition fStreamEventContextDef
;
63 /** Reference to the index entry of the current packet. */
64 private StreamInputPacketIndexEntry fCurrentPacket
= null;
67 * Last timestamp recorded.
69 * Needed to calculate the complete timestamp values for the events with
72 private long fLastTimestamp
= 0;
74 /** CPU id of current packet. */
75 private int fCurrentCpu
= 0;
77 private int fLostEventsInThisPacket
;
79 private long fLostEventsDuration
;
81 private boolean fHasLost
= false;
83 // ------------------------------------------------------------------------
85 // ------------------------------------------------------------------------
88 * Constructs a StreamInputPacketReader.
90 * @param streamInputReader
91 * The StreamInputReader to which this packet reader belongs to.
93 public StreamInputPacketReader(StreamInputReader streamInputReader
) {
94 fStreamInputReader
= streamInputReader
;
96 /* Set the BitBuffer's byte order. */
97 fBitBuffer
= new BitBuffer();
98 fBitBuffer
.setByteOrder(streamInputReader
.getByteOrder());
100 /* Create trace packet header definition. */
101 final Stream currentStream
= streamInputReader
.getStreamInput().getStream();
102 StructDeclaration tracePacketHeaderDecl
= currentStream
.getTrace().getPacketHeader();
103 if (tracePacketHeaderDecl
!= null) {
104 fTracePacketHeaderDef
= tracePacketHeaderDecl
.createDefinition(this, "trace.packet.header"); //$NON-NLS-1$
106 fTracePacketHeaderDef
= null;
109 /* Create stream packet context definition. */
110 StructDeclaration streamPacketContextDecl
= currentStream
.getPacketContextDecl();
111 if (streamPacketContextDecl
!= null) {
112 fStreamPacketContextDef
= streamPacketContextDecl
.createDefinition(this, "stream.packet.context"); //$NON-NLS-1$
114 fStreamPacketContextDef
= null;
117 /* Create stream event header definition. */
118 StructDeclaration streamEventHeaderDecl
= currentStream
.getEventHeaderDecl();
119 if (streamEventHeaderDecl
!= null) {
120 fStreamEventHeaderDef
= streamEventHeaderDecl
.createDefinition(this, "stream.event.header"); //$NON-NLS-1$
122 fStreamEventHeaderDef
= null;
125 /* Create stream event context definition. */
126 StructDeclaration streamEventContextDecl
= currentStream
.getEventContextDecl();
127 if (streamEventContextDecl
!= null) {
128 fStreamEventContextDef
= streamEventContextDecl
.createDefinition(this, "stream.event.context"); //$NON-NLS-1$
130 fStreamEventContextDef
= null;
133 /* Create event definitions */
134 Collection
<IEventDeclaration
> eventDecls
= streamInputReader
.getStreamInput().getStream().getEvents().values();
136 for (IEventDeclaration event
: eventDecls
) {
137 if (!streamInputReader
.getEventDefinitions().containsKey(event
.getId())) {
138 EventDefinition eventDef
= event
.createDefinition(streamInputReader
);
139 streamInputReader
.addEventDefinition(event
.getId(), eventDef
);
145 * Dispose the StreamInputPacketReader
149 public void dispose() {
150 fBitBuffer
.setByteBuffer(null);
153 // ------------------------------------------------------------------------
154 // Getters/Setters/Predicates
155 // ------------------------------------------------------------------------
158 * Gets the current packet
160 * @return the current packet
162 StreamInputPacketIndexEntry
getCurrentPacket() {
163 return fCurrentPacket
;
167 * Gets the steamPacketContext Definition
169 * @return steamPacketContext Definition
171 public StructDefinition
getStreamPacketContextDef() {
172 return fStreamPacketContextDef
;
176 * Gets the stream's event context definition.
178 * @return The streamEventContext definition
180 public StructDefinition
getStreamEventContextDef() {
181 return fStreamEventContextDef
;
185 * Gets the CPU (core) number
187 * @return the CPU (core) number
189 public int getCPU() {
194 public String
getPath() {
195 return ""; //$NON-NLS-1$
198 // ------------------------------------------------------------------------
200 // ------------------------------------------------------------------------
203 * Changes the current packet to the given one.
205 * @param currentPacket
206 * The index entry of the packet to switch to.
207 * @throws CTFReaderException
208 * If we get an error reading the packet
210 void setCurrentPacket(StreamInputPacketIndexEntry currentPacket
) throws CTFReaderException
{
211 StreamInputPacketIndexEntry prevPacket
= null;
212 fCurrentPacket
= currentPacket
;
214 if (fCurrentPacket
!= null) {
216 * Change the map of the BitBuffer.
218 ByteBuffer bb
= null;
220 bb
= fStreamInputReader
.getStreamInput().getByteBufferAt(
221 fCurrentPacket
.getOffsetBytes(),
222 (fCurrentPacket
.getPacketSizeBits() + 7) / 8);
223 } catch (IOException e
) {
224 throw new CTFReaderException(e
.getMessage(), e
);
227 fBitBuffer
.setByteBuffer(bb
);
230 * Read trace packet header.
232 if (fTracePacketHeaderDef
!= null) {
233 fTracePacketHeaderDef
.read(fBitBuffer
);
237 * Read stream packet context.
239 if (getStreamPacketContextDef() != null) {
240 getStreamPacketContextDef().read(fBitBuffer
);
243 if (getCurrentPacket().getTarget() != null) {
244 fCurrentCpu
= (int) getCurrentPacket().getTargetId();
247 /* Read number of lost events */
248 fLostEventsInThisPacket
= (int) getCurrentPacket().getLostEvents();
249 if (fLostEventsInThisPacket
!= 0) {
252 * Compute the duration of the lost event time range. If the
253 * current packet is the first packet, duration will be set
256 long lostEventsStartTime
;
257 int index
= fStreamInputReader
.getStreamInput().getIndex().getEntries().indexOf(currentPacket
);
259 lostEventsStartTime
= currentPacket
.getTimestampBegin() + 1;
261 prevPacket
= fStreamInputReader
.getStreamInput().getIndex().getEntries().get(index
- 1);
262 lostEventsStartTime
= prevPacket
.getTimestampEnd();
264 fLostEventsDuration
= Math
.abs(lostEventsStartTime
- currentPacket
.getTimestampBegin());
269 * Use the timestamp begin of the packet as the reference for the
270 * timestamp reconstitution.
272 fLastTimestamp
= currentPacket
.getTimestampBegin();
274 fBitBuffer
.setByteBuffer(null);
281 * Returns whether it is possible to read any more events from this packet.
283 * @return True if it is possible to read any more events from this packet.
285 public boolean hasMoreEvents() {
286 if (fCurrentPacket
!= null) {
287 return fHasLost
|| (fBitBuffer
.position() < fCurrentPacket
.getContentSizeBits());
293 * Reads the next event of the packet into the right event definition.
295 * @return The event definition containing the event data that was just
297 * @throws CTFReaderException
298 * If there was a problem reading the trace
300 public EventDefinition
readNextEvent() throws CTFReaderException
{
301 /* Default values for those fields */
302 long eventID
= EventDeclaration
.UNSET_EVENT_ID
;
306 EventDefinition eventDef
= EventDeclaration
.getLostEventDeclaration().createDefinition(fStreamInputReader
);
307 ((IntegerDefinition
) eventDef
.getFields().getDefinitions().get(CTFStrings
.LOST_EVENTS_FIELD
)).setValue(fLostEventsInThisPacket
);
308 ((IntegerDefinition
) eventDef
.getFields().getDefinitions().get(CTFStrings
.LOST_EVENTS_DURATION
)).setValue(fLostEventsDuration
);
309 eventDef
.setTimestamp(fLastTimestamp
);
313 final StructDefinition sehd
= fStreamEventHeaderDef
;
314 final BitBuffer currentBitBuffer
= fBitBuffer
;
315 final long posStart
= currentBitBuffer
.position();
316 /* Read the stream event header. */
318 sehd
.read(currentBitBuffer
);
320 /* Check for the event id. */
321 Definition idDef
= sehd
.lookupDefinition("id"); //$NON-NLS-1$
322 if (idDef
instanceof SimpleDatatypeDefinition
) {
323 eventID
= ((SimpleDatatypeDefinition
) idDef
).getIntegerValue();
324 } else if (idDef
!= null) {
325 throw new CTFReaderException("Incorrect event id : " + eventID
); //$NON-NLS-1$
329 * Get the timestamp from the event header (may be overridden later
332 IntegerDefinition timestampDef
= sehd
.lookupInteger("timestamp"); //$NON-NLS-1$
333 if (timestampDef
!= null) {
334 timestamp
= calculateTimestamp(timestampDef
);
335 } // else timestamp remains 0
337 /* Check for the variant v. */
338 Definition variantDef
= sehd
.lookupDefinition("v"); //$NON-NLS-1$
339 if (variantDef
instanceof VariantDefinition
) {
341 /* Get the variant current field */
342 StructDefinition variantCurrentField
= (StructDefinition
) ((VariantDefinition
) variantDef
).getCurrentField();
345 * Try to get the id field in the current field of the variant.
346 * If it is present, it overrides the previously read event id.
348 Definition idIntegerDef
= variantCurrentField
.lookupDefinition("id"); //$NON-NLS-1$
349 if (idIntegerDef
instanceof IntegerDefinition
) {
350 eventID
= ((IntegerDefinition
) idIntegerDef
).getValue();
354 * Get the timestamp. This would overwrite any previous
355 * timestamp definition
357 Definition def
= variantCurrentField
.lookupDefinition("timestamp"); //$NON-NLS-1$
358 if (def
instanceof IntegerDefinition
) {
359 timestamp
= calculateTimestamp((IntegerDefinition
) def
);
364 /* Read the stream event context. */
365 if (fStreamEventContextDef
!= null) {
366 fStreamEventContextDef
.read(currentBitBuffer
);
369 /* Get the right event definition using the event id. */
370 EventDefinition eventDef
= fStreamInputReader
.getEventDefinitions().get(eventID
);
371 if (eventDef
== null) {
372 throw new CTFReaderException("Incorrect event id : " + eventID
); //$NON-NLS-1$
375 /* Read the event context. */
376 if (eventDef
.getEventContext() != null) {
377 eventDef
.getEventContext().read(currentBitBuffer
);
380 /* Read the event fields. */
381 if (eventDef
.getFields() != null) {
382 eventDef
.getFields().read(currentBitBuffer
);
386 * Set the event timestamp using the timestamp calculated by
389 eventDef
.setTimestamp(timestamp
);
391 if (posStart
== currentBitBuffer
.position()) {
392 throw new CTFReaderException("Empty event not allowed, event: " + eventDef
.getDeclaration().getName()); //$NON-NLS-1$
399 * Calculates the timestamp value of the event, possibly using the timestamp
400 * from the last event.
402 * @param timestampDef
403 * Integer definition of the timestamp.
404 * @return The calculated timestamp value.
406 private long calculateTimestamp(IntegerDefinition timestampDef
) {
409 int len
= timestampDef
.getDeclaration().getLength();
412 * If the timestamp length is 64 bits, it is a full timestamp.
414 if (timestampDef
.getDeclaration().getLength() == 64) {
415 fLastTimestamp
= timestampDef
.getValue();
416 return fLastTimestamp
;
420 * Bit mask to keep / remove all old / new bits.
422 majorasbitmask
= (1L << len
) - 1;
425 * If the new value is smaller than the corresponding bits of the last
426 * timestamp, we assume an overflow of the compact representation.
428 newval
= timestampDef
.getValue();
429 if (newval
< (fLastTimestamp
& majorasbitmask
)) {
430 newval
= newval
+ (1L << len
);
433 /* Keep only the high bits of the old value */
434 fLastTimestamp
= fLastTimestamp
& ~majorasbitmask
;
436 /* Then add the low bits of the new value */
437 fLastTimestamp
= fLastTimestamp
+ newval
;
439 return fLastTimestamp
;
443 public Definition
lookupDefinition(String lookupPath
) {