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
.jdt
.annotation
.Nullable
;
19 import org
.eclipse
.linuxtools
.ctf
.core
.CTFStrings
;
20 import org
.eclipse
.linuxtools
.ctf
.core
.event
.EventDefinition
;
21 import org
.eclipse
.linuxtools
.ctf
.core
.event
.IEventDeclaration
;
22 import org
.eclipse
.linuxtools
.ctf
.core
.event
.io
.BitBuffer
;
23 import org
.eclipse
.linuxtools
.ctf
.core
.event
.scope
.IDefinitionScope
;
24 import org
.eclipse
.linuxtools
.ctf
.core
.event
.scope
.LexicalScope
;
25 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.Definition
;
26 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.IntegerDeclaration
;
27 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.IntegerDefinition
;
28 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.SimpleDatatypeDefinition
;
29 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.StructDeclaration
;
30 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.StructDefinition
;
31 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.VariantDefinition
;
32 import org
.eclipse
.linuxtools
.internal
.ctf
.core
.event
.EventDeclaration
;
33 import org
.eclipse
.linuxtools
.internal
.ctf
.core
.trace
.StreamInputPacketIndexEntry
;
35 import com
.google
.common
.collect
.ImmutableList
;
38 * CTF trace packet reader. Reads the events of a packet of a trace file.
40 * @author Matthew Khouzam
41 * @author Simon Marchi
44 public class CTFStreamInputPacketReader
implements IDefinitionScope
, AutoCloseable
{
46 // ------------------------------------------------------------------------
48 // ------------------------------------------------------------------------
50 /** BitBuffer used to read the trace file. */
52 private BitBuffer fBitBuffer
;
54 /** StreamInputReader that uses this StreamInputPacketReader. */
55 private final CTFStreamInputReader fStreamInputReader
;
57 /** Trace packet header. */
58 private final StructDeclaration fTracePacketHeaderDecl
;
60 /** Stream packet context definition. */
61 private final StructDeclaration fStreamPacketContextDecl
;
63 /** Stream event header definition. */
64 private final StructDeclaration fStreamEventHeaderDecl
;
66 /** Stream event context definition. */
67 private final StructDeclaration fStreamEventContextDecl
;
69 private StructDefinition fCurrentTracePacketHeaderDef
;
70 private StructDefinition fCurrentStreamEventHeaderDef
;
71 private Definition fCurrentStreamPacketContextDef
;
72 /** Reference to the index entry of the current packet. */
73 private StreamInputPacketIndexEntry fCurrentPacket
= null;
76 * Last timestamp recorded.
78 * Needed to calculate the complete timestamp values for the events with
81 private long fLastTimestamp
= 0;
83 /** CPU id of current packet. */
84 private int fCurrentCpu
= 0;
86 private int fLostEventsInThisPacket
;
88 private long fLostEventsDuration
;
90 private boolean fHasLost
= false;
92 // ------------------------------------------------------------------------
94 // ------------------------------------------------------------------------
97 * Constructs a StreamInputPacketReader.
99 * @param streamInputReader
100 * The StreamInputReader to which this packet reader belongs to.
102 public CTFStreamInputPacketReader(CTFStreamInputReader streamInputReader
) {
103 fStreamInputReader
= streamInputReader
;
105 /* Set the BitBuffer's byte order. */
106 fBitBuffer
= new BitBuffer();
107 fBitBuffer
.setByteOrder(streamInputReader
.getByteOrder());
109 final CTFStream currentStream
= streamInputReader
.getStreamInput().getStream();
110 fTracePacketHeaderDecl
= currentStream
.getTrace().getPacketHeader();
111 fStreamPacketContextDecl
= currentStream
.getPacketContextDecl();
112 fStreamEventHeaderDecl
= currentStream
.getEventHeaderDecl();
113 fStreamEventContextDecl
= currentStream
.getEventContextDecl();
117 * Get the event context defintiion
120 * the bitbuffer to read from
121 * @return an context definition, can be null
122 * @throws CTFReaderException
123 * out of bounds exception or such
125 public StructDefinition
getEventContextDefinition(@NonNull BitBuffer input
) throws CTFReaderException
{
126 return fStreamEventContextDecl
.createDefinition(fStreamInputReader
.getStreamInput(), LexicalScope
.STREAM_EVENT_CONTEXT
, input
);
130 * Get the stream context defintiion
133 * the bitbuffer to read from
134 * @return an context definition, can be null
135 * @throws CTFReaderException
136 * out of bounds exception or such
138 public StructDefinition
getStreamEventHeaderDefinition(@NonNull BitBuffer input
) throws CTFReaderException
{
139 return fStreamEventHeaderDecl
.createDefinition(this, LexicalScope
.EVENT_HEADER
, input
);
143 * Get the packet context defintiion
146 * the bitbuffer to read from
147 * @return an context definition, can be null
148 * @throws CTFReaderException
149 * out of bounds exception or such
151 public StructDefinition
getStreamPacketContextDefinition(@NonNull BitBuffer input
) throws CTFReaderException
{
152 return fStreamPacketContextDecl
.createDefinition(fStreamInputReader
.getStreamInput(), LexicalScope
.STREAM_PACKET_CONTEXT
, input
);
156 * Get the event header defintiion
159 * the bitbuffer to read from
160 * @return an header definition, can be null
161 * @throws CTFReaderException
162 * out of bounds exception or such
164 public StructDefinition
getTracePacketHeaderDefinition(@NonNull BitBuffer input
) throws CTFReaderException
{
165 return fTracePacketHeaderDecl
.createDefinition(fStreamInputReader
.getStreamInput().getStream().getTrace(), LexicalScope
.TRACE_PACKET_HEADER
, input
);
169 * Dispose the StreamInputPacketReader
172 public void close() {
176 // ------------------------------------------------------------------------
177 // Getters/Setters/Predicates
178 // ------------------------------------------------------------------------
181 * Gets the current packet
183 * @return the current packet
185 StreamInputPacketIndexEntry
getCurrentPacket() {
186 return fCurrentPacket
;
190 * Gets the CPU (core) number
192 * @return the CPU (core) number
194 public int getCPU() {
199 public LexicalScope
getScopePath() {
200 return LexicalScope
.PACKET
;
203 // ------------------------------------------------------------------------
205 // ------------------------------------------------------------------------
208 * Changes the current packet to the given one.
210 * @param currentPacket
211 * The index entry of the packet to switch to.
212 * @throws CTFReaderException
213 * If we get an error reading the packet
215 void setCurrentPacket(StreamInputPacketIndexEntry currentPacket
) throws CTFReaderException
{
216 StreamInputPacketIndexEntry prevPacket
= null;
217 fCurrentPacket
= currentPacket
;
219 if (fCurrentPacket
!= null) {
221 * Change the map of the BitBuffer.
223 ByteBuffer bb
= null;
225 bb
= fStreamInputReader
.getStreamInput().getByteBufferAt(
226 fCurrentPacket
.getOffsetBytes(),
227 (fCurrentPacket
.getPacketSizeBits() + 7) / 8);
228 } catch (IOException e
) {
229 throw new CTFReaderException(e
.getMessage(), e
);
232 BitBuffer bitBuffer
= new BitBuffer(bb
);
233 fBitBuffer
= bitBuffer
;
235 * Read trace packet header.
237 if (fTracePacketHeaderDecl
!= null) {
238 fCurrentTracePacketHeaderDef
= getTracePacketHeaderDefinition(bitBuffer
);
242 * Read stream packet context.
244 if (fStreamPacketContextDecl
!= null) {
245 fCurrentStreamPacketContextDef
= getStreamPacketContextDefinition(bitBuffer
);
248 if (getCurrentPacket().getTarget() != null) {
249 fCurrentCpu
= (int) getCurrentPacket().getTargetId();
252 /* Read number of lost events */
253 fLostEventsInThisPacket
= (int) getCurrentPacket().getLostEvents();
254 if (fLostEventsInThisPacket
!= 0) {
257 * Compute the duration of the lost event time range. If the
258 * current packet is the first packet, duration will be set
261 long lostEventsStartTime
;
262 int index
= fStreamInputReader
.getStreamInput().getIndex().getEntries().indexOf(currentPacket
);
264 lostEventsStartTime
= currentPacket
.getTimestampBegin() + 1;
266 prevPacket
= fStreamInputReader
.getStreamInput().getIndex().getEntries().get(index
- 1);
267 lostEventsStartTime
= prevPacket
.getTimestampEnd();
269 fLostEventsDuration
= Math
.abs(lostEventsStartTime
- currentPacket
.getTimestampBegin());
274 * Use the timestamp begin of the packet as the reference for the
275 * timestamp reconstitution.
277 fLastTimestamp
= currentPacket
.getTimestampBegin();
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 BitBuffer bitBuffer
= fBitBuffer
;
291 StreamInputPacketIndexEntry currentPacket
= fCurrentPacket
;
292 if (currentPacket
!= null && bitBuffer
!= null) {
293 return fHasLost
|| (bitBuffer
.position() < currentPacket
.getContentSizeBits());
299 * Reads the next event of the packet into the right event definition.
301 * @return The event definition containing the event data that was just
303 * @throws CTFReaderException
304 * If there was a problem reading the trace
306 public EventDefinition
readNextEvent() throws CTFReaderException
{
307 /* Default values for those fields */
308 long eventID
= EventDeclaration
.UNSET_EVENT_ID
;
312 EventDeclaration lostEventDeclaration
= EventDeclaration
.getLostEventDeclaration();
313 StructDeclaration lostFields
= lostEventDeclaration
.getFields();
314 // this is a hard coded map, we know it's not null
315 IntegerDeclaration lostFieldsDecl
= (IntegerDeclaration
) lostFields
.getField(CTFStrings
.LOST_EVENTS_FIELD
);
316 if (lostFieldsDecl
== null)
318 throw new IllegalStateException("Lost events count not declared!"); //$NON-NLS-1$
320 IntegerDeclaration lostEventsDurationDecl
= (IntegerDeclaration
) lostFields
.getField(CTFStrings
.LOST_EVENTS_DURATION
);
321 if (lostEventsDurationDecl
== null) {
322 throw new IllegalStateException("Lost events duration not declared!"); //$NON-NLS-1$
324 IntegerDefinition lostDurationDef
= new IntegerDefinition(lostFieldsDecl
, null, CTFStrings
.LOST_EVENTS_DURATION
, fLostEventsDuration
);
325 IntegerDefinition lostCountDef
= new IntegerDefinition(lostEventsDurationDecl
, null, CTFStrings
.LOST_EVENTS_FIELD
, fLostEventsInThisPacket
);
326 IntegerDefinition
[] fields
= new IntegerDefinition
[] { lostCountDef
, lostDurationDef
};
327 /* this is weird notation, but it's the java notation */
328 final ImmutableList
<String
> fieldNameList
= ImmutableList
.<String
> builder().add(CTFStrings
.LOST_EVENTS_FIELD
).add(CTFStrings
.LOST_EVENTS_DURATION
).build();
329 return new EventDefinition(
330 lostEventDeclaration
,
336 new StructDefinition(
338 this, "fields", //$NON-NLS-1$
345 final BitBuffer currentBitBuffer
= fBitBuffer
;
346 if( currentBitBuffer
== null ) {
349 final long posStart
= currentBitBuffer
.position();
350 /* Read the stream event header. */
351 if (fStreamEventHeaderDecl
!= null) {
352 fCurrentStreamEventHeaderDef
= getStreamEventHeaderDefinition(currentBitBuffer
);
354 /* Check for the event id. */
355 Definition idDef
= fCurrentStreamEventHeaderDef
.lookupDefinition("id"); //$NON-NLS-1$
356 if (idDef
instanceof SimpleDatatypeDefinition
) {
357 eventID
= ((SimpleDatatypeDefinition
) idDef
).getIntegerValue();
358 } else if (idDef
!= null) {
359 throw new CTFReaderException("Incorrect event id : " + eventID
); //$NON-NLS-1$
363 * Get the timestamp from the event header (may be overridden later
366 IntegerDefinition timestampDef
= fCurrentStreamEventHeaderDef
.lookupInteger("timestamp"); //$NON-NLS-1$
367 if (timestampDef
!= null) {
368 timestamp
= calculateTimestamp(timestampDef
);
369 } // else timestamp remains 0
371 /* Check for the variant v. */
372 Definition variantDef
= fCurrentStreamEventHeaderDef
.lookupDefinition("v"); //$NON-NLS-1$
373 if (variantDef
instanceof VariantDefinition
) {
375 /* Get the variant current field */
376 StructDefinition variantCurrentField
= (StructDefinition
) ((VariantDefinition
) variantDef
).getCurrentField();
379 * Try to get the id field in the current field of the variant.
380 * If it is present, it overrides the previously read event id.
382 Definition idIntegerDef
= variantCurrentField
.lookupDefinition("id"); //$NON-NLS-1$
383 if (idIntegerDef
instanceof IntegerDefinition
) {
384 eventID
= ((IntegerDefinition
) idIntegerDef
).getValue();
388 * Get the timestamp. This would overwrite any previous
389 * timestamp definition
391 Definition def
= variantCurrentField
.lookupDefinition("timestamp"); //$NON-NLS-1$
392 if (def
instanceof IntegerDefinition
) {
393 timestamp
= calculateTimestamp((IntegerDefinition
) def
);
398 /* Get the right event definition using the event id. */
399 IEventDeclaration eventDeclaration
= fStreamInputReader
.getStreamInput().getStream().getEvents().get(eventID
);
400 if (eventDeclaration
== null) {
401 throw new CTFReaderException("Incorrect event id : " + eventID
); //$NON-NLS-1$
403 EventDefinition eventDef
= eventDeclaration
.createDefinition(fStreamInputReader
, currentBitBuffer
, timestamp
);
406 * Set the event timestamp using the timestamp calculated by
410 if (posStart
== currentBitBuffer
.position()) {
411 throw new CTFReaderException("Empty event not allowed, event: " + eventDef
.getDeclaration().getName()); //$NON-NLS-1$
418 * Calculates the timestamp value of the event, possibly using the timestamp
419 * from the last event.
421 * @param timestampDef
422 * Integer definition of the timestamp.
423 * @return The calculated timestamp value.
425 private long calculateTimestamp(IntegerDefinition timestampDef
) {
428 int len
= timestampDef
.getDeclaration().getLength();
431 * If the timestamp length is 64 bits, it is a full timestamp.
433 if (timestampDef
.getDeclaration().getLength() == 64) {
434 fLastTimestamp
= timestampDef
.getValue();
435 return fLastTimestamp
;
439 * Bit mask to keep / remove all old / new bits.
441 majorasbitmask
= (1L << len
) - 1;
444 * If the new value is smaller than the corresponding bits of the last
445 * timestamp, we assume an overflow of the compact representation.
447 newval
= timestampDef
.getValue();
448 if (newval
< (fLastTimestamp
& majorasbitmask
)) {
449 newval
= newval
+ (1L << len
);
452 /* Keep only the high bits of the old value */
453 fLastTimestamp
= fLastTimestamp
& ~majorasbitmask
;
455 /* Then add the low bits of the new value */
456 fLastTimestamp
= fLastTimestamp
+ newval
;
458 return fLastTimestamp
;
462 public Definition
lookupDefinition(String lookupPath
) {
463 if (lookupPath
.equals(LexicalScope
.STREAM_PACKET_CONTEXT
)) {
464 return fCurrentStreamPacketContextDef
;
466 if (lookupPath
.equals(LexicalScope
.TRACE_PACKET_HEADER
)) {
467 return fCurrentTracePacketHeaderDef
;
473 * Get stream event header
475 * @return the stream event header
477 public StructDefinition
getCurrentStreamEventHeader() {
478 return fCurrentStreamEventHeaderDef
;
482 * Get the current packet event header
484 * @return the current packet event header
486 public StructDefinition
getCurrentPacketEventHeader() {
487 return fCurrentTracePacketHeaderDef
;