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 *******************************************************************************/
12 package org
.eclipse
.linuxtools
.ctf
.core
.trace
;
14 import java
.io
.IOException
;
15 import java
.nio
.ByteBuffer
;
17 import org
.eclipse
.jdt
.annotation
.NonNull
;
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
.scope
.IDefinitionScope
;
23 import org
.eclipse
.linuxtools
.ctf
.core
.event
.scope
.LexicalScope
;
24 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.Definition
;
25 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.IntegerDeclaration
;
26 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.IntegerDefinition
;
27 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.SimpleDatatypeDefinition
;
28 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.StructDeclaration
;
29 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.StructDefinition
;
30 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.VariantDefinition
;
31 import org
.eclipse
.linuxtools
.internal
.ctf
.core
.event
.EventDeclaration
;
32 import org
.eclipse
.linuxtools
.internal
.ctf
.core
.trace
.StreamInputPacketIndexEntry
;
34 import com
.google
.common
.collect
.ImmutableList
;
37 * CTF trace packet reader. Reads the events of a packet of a trace file.
39 * @author Matthew Khouzam
40 * @author Simon Marchi
43 public class CTFStreamInputPacketReader
implements IDefinitionScope
, AutoCloseable
{
45 // ------------------------------------------------------------------------
47 // ------------------------------------------------------------------------
49 /** BitBuffer used to read the trace file. */
51 private final BitBuffer fBitBuffer
;
53 /** StreamInputReader that uses this StreamInputPacketReader. */
54 private final CTFStreamInputReader fStreamInputReader
;
56 /** Trace packet header. */
57 private final StructDeclaration fTracePacketHeaderDecl
;
59 /** Stream packet context definition. */
60 private final StructDeclaration fStreamPacketContextDecl
;
62 /** Stream event header definition. */
63 private final StructDeclaration fStreamEventHeaderDecl
;
65 /** Stream event context definition. */
66 private final StructDeclaration fStreamEventContextDecl
;
68 private StructDefinition fCurrentTracePacketHeaderDef
;
69 private StructDefinition fCurrentStreamEventHeaderDef
;
70 private Definition fCurrentStreamPacketContextDef
;
71 /** Reference to the index entry of the current packet. */
72 private StreamInputPacketIndexEntry fCurrentPacket
= null;
75 * Last timestamp recorded.
77 * Needed to calculate the complete timestamp values for the events with
80 private long fLastTimestamp
= 0;
82 /** CPU id of current packet. */
83 private int fCurrentCpu
= 0;
85 private int fLostEventsInThisPacket
;
87 private long fLostEventsDuration
;
89 private boolean fHasLost
= false;
91 // ------------------------------------------------------------------------
93 // ------------------------------------------------------------------------
96 * Constructs a StreamInputPacketReader.
98 * @param streamInputReader
99 * The StreamInputReader to which this packet reader belongs to.
101 public CTFStreamInputPacketReader(CTFStreamInputReader streamInputReader
) {
102 fStreamInputReader
= streamInputReader
;
104 /* Set the BitBuffer's byte order. */
105 fBitBuffer
= new BitBuffer();
106 fBitBuffer
.setByteOrder(streamInputReader
.getByteOrder());
108 final CTFStream currentStream
= streamInputReader
.getStreamInput().getStream();
109 fTracePacketHeaderDecl
= currentStream
.getTrace().getPacketHeader();
110 fStreamPacketContextDecl
= currentStream
.getPacketContextDecl();
111 fStreamEventHeaderDecl
= currentStream
.getEventHeaderDecl();
112 fStreamEventContextDecl
= currentStream
.getEventContextDecl();
116 * Get the event context defintiion
119 * the bitbuffer to read from
120 * @return an context definition, can be null
121 * @throws CTFReaderException
122 * out of bounds exception or such
124 public StructDefinition
getEventContextDefinition(@NonNull BitBuffer input
) throws CTFReaderException
{
125 return fStreamEventContextDecl
.createDefinition(this, LexicalScope
.STREAM_EVENT_CONTEXT
.getName(), input
);
129 * Get the stream context defintiion
132 * the bitbuffer to read from
133 * @return an context definition, can be null
134 * @throws CTFReaderException
135 * out of bounds exception or such
137 public StructDefinition
getStreamEventHeaderDefinition(@NonNull BitBuffer input
) throws CTFReaderException
{
138 return fStreamEventHeaderDecl
.createDefinition(this, LexicalScope
.STREAM_EVENT_HEADER
.getName(), input
);
142 * Get the packet context defintiion
145 * the bitbuffer to read from
146 * @return an context definition, can be null
147 * @throws CTFReaderException
148 * out of bounds exception or such
150 public StructDefinition
getStreamPacketContextDefinition(@NonNull BitBuffer input
) throws CTFReaderException
{
151 return fStreamPacketContextDecl
.createDefinition(this, LexicalScope
.STREAM_PACKET_CONTEXT
.getName(), input
);
155 * Get the event header defintiion
158 * the bitbuffer to read from
159 * @return an header definition, can be null
160 * @throws CTFReaderException
161 * out of bounds exception or such
163 public StructDefinition
getTracePacketHeaderDefinition(@NonNull BitBuffer input
) throws CTFReaderException
{
164 return fTracePacketHeaderDecl
.createDefinition(this, LexicalScope
.TRACE_PACKET_HEADER
.getName(), input
);
168 * Dispose the StreamInputPacketReader
171 public void close() {
172 fBitBuffer
.setByteBuffer(null);
175 // ------------------------------------------------------------------------
176 // Getters/Setters/Predicates
177 // ------------------------------------------------------------------------
180 * Gets the current packet
182 * @return the current packet
184 StreamInputPacketIndexEntry
getCurrentPacket() {
185 return fCurrentPacket
;
189 * Gets the CPU (core) number
191 * @return the CPU (core) number
193 public int getCPU() {
198 public LexicalScope
getScopePath() {
199 return LexicalScope
.PACKET
;
202 // ------------------------------------------------------------------------
204 // ------------------------------------------------------------------------
207 * Changes the current packet to the given one.
209 * @param currentPacket
210 * The index entry of the packet to switch to.
211 * @throws CTFReaderException
212 * If we get an error reading the packet
214 void setCurrentPacket(StreamInputPacketIndexEntry currentPacket
) throws CTFReaderException
{
215 StreamInputPacketIndexEntry prevPacket
= null;
216 fCurrentPacket
= currentPacket
;
218 if (fCurrentPacket
!= null) {
220 * Change the map of the BitBuffer.
222 ByteBuffer bb
= null;
224 bb
= fStreamInputReader
.getStreamInput().getByteBufferAt(
225 fCurrentPacket
.getOffsetBytes(),
226 (fCurrentPacket
.getPacketSizeBits() + 7) / 8);
227 } catch (IOException e
) {
228 throw new CTFReaderException(e
.getMessage(), e
);
231 fBitBuffer
.setByteBuffer(bb
);
234 * Read trace packet header.
236 if (fTracePacketHeaderDecl
!= null) {
237 fCurrentTracePacketHeaderDef
= getTracePacketHeaderDefinition(fBitBuffer
);
241 * Read stream packet context.
243 if (fStreamPacketContextDecl
!= null) {
244 fCurrentStreamPacketContextDef
= getStreamPacketContextDefinition(fBitBuffer
);
247 if (getCurrentPacket().getTarget() != null) {
248 fCurrentCpu
= (int) getCurrentPacket().getTargetId();
251 /* Read number of lost events */
252 fLostEventsInThisPacket
= (int) getCurrentPacket().getLostEvents();
253 if (fLostEventsInThisPacket
!= 0) {
256 * Compute the duration of the lost event time range. If the
257 * current packet is the first packet, duration will be set
260 long lostEventsStartTime
;
261 int index
= fStreamInputReader
.getStreamInput().getIndex().getEntries().indexOf(currentPacket
);
263 lostEventsStartTime
= currentPacket
.getTimestampBegin() + 1;
265 prevPacket
= fStreamInputReader
.getStreamInput().getIndex().getEntries().get(index
- 1);
266 lostEventsStartTime
= prevPacket
.getTimestampEnd();
268 fLostEventsDuration
= Math
.abs(lostEventsStartTime
- currentPacket
.getTimestampBegin());
273 * Use the timestamp begin of the packet as the reference for the
274 * timestamp reconstitution.
276 fLastTimestamp
= currentPacket
.getTimestampBegin();
278 fBitBuffer
.setByteBuffer(null);
285 * Returns whether it is possible to read any more events from this packet.
287 * @return True if it is possible to read any more events from this packet.
289 public boolean hasMoreEvents() {
290 if (fCurrentPacket
!= null) {
291 return fHasLost
|| (fBitBuffer
.position() < fCurrentPacket
.getContentSizeBits());
297 * Reads the next event of the packet into the right event definition.
299 * @return The event definition containing the event data that was just
301 * @throws CTFReaderException
302 * If there was a problem reading the trace
304 public EventDefinition
readNextEvent() throws CTFReaderException
{
305 /* Default values for those fields */
306 long eventID
= EventDeclaration
.UNSET_EVENT_ID
;
310 EventDeclaration lostEventDeclaration
= EventDeclaration
.getLostEventDeclaration();
311 StructDeclaration lostFields
= lostEventDeclaration
.getFields();
312 // this is a hard coded map, we know it's not null
313 IntegerDeclaration lostFieldsDecl
= (IntegerDeclaration
) lostFields
.getFields().get(CTFStrings
.LOST_EVENTS_FIELD
);
314 if (lostFieldsDecl
== null)
316 throw new IllegalStateException("Lost events count not declared!"); //$NON-NLS-1$
318 IntegerDeclaration lostEventsDurationDecl
= (IntegerDeclaration
) lostFields
.getFields().get(CTFStrings
.LOST_EVENTS_DURATION
);
319 if (lostEventsDurationDecl
== null) {
320 throw new IllegalStateException("Lost events duration not declared!"); //$NON-NLS-1$
322 IntegerDefinition lostDurationDef
= new IntegerDefinition(lostFieldsDecl
, null, CTFStrings
.LOST_EVENTS_DURATION
, fLostEventsDuration
);
323 IntegerDefinition lostCountDef
= new IntegerDefinition(lostEventsDurationDecl
, null, CTFStrings
.LOST_EVENTS_FIELD
, fLostEventsInThisPacket
);
324 IntegerDefinition
[] fields
= new IntegerDefinition
[] { lostCountDef
, lostDurationDef
};
325 /* this is weird notation, but it's the java notation */
326 final ImmutableList
<String
> fieldNameList
= ImmutableList
.<String
> builder().add(CTFStrings
.LOST_EVENTS_FIELD
).add(CTFStrings
.LOST_EVENTS_DURATION
).build();
327 return new EventDefinition(
328 lostEventDeclaration
,
334 new StructDefinition(
336 this, "fields", //$NON-NLS-1$
343 final BitBuffer currentBitBuffer
= fBitBuffer
;
344 final long posStart
= currentBitBuffer
.position();
345 /* Read the stream event header. */
346 if (fStreamEventHeaderDecl
!= null) {
347 fCurrentStreamEventHeaderDef
= getStreamEventHeaderDefinition(currentBitBuffer
);
349 /* Check for the event id. */
350 Definition idDef
= fCurrentStreamEventHeaderDef
.lookupDefinition("id"); //$NON-NLS-1$
351 if (idDef
instanceof SimpleDatatypeDefinition
) {
352 eventID
= ((SimpleDatatypeDefinition
) idDef
).getIntegerValue();
353 } else if (idDef
!= null) {
354 throw new CTFReaderException("Incorrect event id : " + eventID
); //$NON-NLS-1$
358 * Get the timestamp from the event header (may be overridden later
361 IntegerDefinition timestampDef
= fCurrentStreamEventHeaderDef
.lookupInteger("timestamp"); //$NON-NLS-1$
362 if (timestampDef
!= null) {
363 timestamp
= calculateTimestamp(timestampDef
);
364 } // else timestamp remains 0
366 /* Check for the variant v. */
367 Definition variantDef
= fCurrentStreamEventHeaderDef
.lookupDefinition("v"); //$NON-NLS-1$
368 if (variantDef
instanceof VariantDefinition
) {
370 /* Get the variant current field */
371 StructDefinition variantCurrentField
= (StructDefinition
) ((VariantDefinition
) variantDef
).getCurrentField();
374 * Try to get the id field in the current field of the variant.
375 * If it is present, it overrides the previously read event id.
377 Definition idIntegerDef
= variantCurrentField
.lookupDefinition("id"); //$NON-NLS-1$
378 if (idIntegerDef
instanceof IntegerDefinition
) {
379 eventID
= ((IntegerDefinition
) idIntegerDef
).getValue();
383 * Get the timestamp. This would overwrite any previous
384 * timestamp definition
386 Definition def
= variantCurrentField
.lookupDefinition("timestamp"); //$NON-NLS-1$
387 if (def
instanceof IntegerDefinition
) {
388 timestamp
= calculateTimestamp((IntegerDefinition
) def
);
393 /* Get the right event definition using the event id. */
394 IEventDeclaration eventDeclaration
= fStreamInputReader
.getStreamInput().getStream().getEvents().get(eventID
);
395 if (eventDeclaration
== null) {
396 throw new CTFReaderException("Incorrect event id : " + eventID
); //$NON-NLS-1$
398 EventDefinition eventDef
= eventDeclaration
.createDefinition(fStreamInputReader
, fBitBuffer
, timestamp
);
401 * Set the event timestamp using the timestamp calculated by
405 if (posStart
== currentBitBuffer
.position()) {
406 throw new CTFReaderException("Empty event not allowed, event: " + eventDef
.getDeclaration().getName()); //$NON-NLS-1$
413 * Calculates the timestamp value of the event, possibly using the timestamp
414 * from the last event.
416 * @param timestampDef
417 * Integer definition of the timestamp.
418 * @return The calculated timestamp value.
420 private long calculateTimestamp(IntegerDefinition timestampDef
) {
423 int len
= timestampDef
.getDeclaration().getLength();
426 * If the timestamp length is 64 bits, it is a full timestamp.
428 if (timestampDef
.getDeclaration().getLength() == 64) {
429 fLastTimestamp
= timestampDef
.getValue();
430 return fLastTimestamp
;
434 * Bit mask to keep / remove all old / new bits.
436 majorasbitmask
= (1L << len
) - 1;
439 * If the new value is smaller than the corresponding bits of the last
440 * timestamp, we assume an overflow of the compact representation.
442 newval
= timestampDef
.getValue();
443 if (newval
< (fLastTimestamp
& majorasbitmask
)) {
444 newval
= newval
+ (1L << len
);
447 /* Keep only the high bits of the old value */
448 fLastTimestamp
= fLastTimestamp
& ~majorasbitmask
;
450 /* Then add the low bits of the new value */
451 fLastTimestamp
= fLastTimestamp
+ newval
;
453 return fLastTimestamp
;
457 public Definition
lookupDefinition(String lookupPath
) {
458 if (lookupPath
.equals(LexicalScope
.STREAM_PACKET_CONTEXT
)) {
459 return fCurrentStreamPacketContextDef
;
461 if (lookupPath
.equals(LexicalScope
.TRACE_PACKET_HEADER
)) {
462 return fCurrentTracePacketHeaderDef
;
468 * Get stream event header
470 * @return the stream event header
472 public StructDefinition
getCurrentStreamEventHeader() {
473 return fCurrentStreamEventHeaderDef
;
477 * Get the current packet event header
479 * @return the current packet event header
481 public StructDefinition
getCurrentPacketEventHeader() {
482 return fCurrentTracePacketHeaderDef
;