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
.ICompositeDefinition
;
27 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.IDeclaration
;
28 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.IDefinition
;
29 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.IEventHeaderDeclaration
;
30 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.IntegerDeclaration
;
31 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.IntegerDefinition
;
32 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.SimpleDatatypeDefinition
;
33 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.StructDeclaration
;
34 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.StructDefinition
;
35 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.VariantDefinition
;
36 import org
.eclipse
.linuxtools
.internal
.ctf
.core
.event
.EventDeclaration
;
37 import org
.eclipse
.linuxtools
.internal
.ctf
.core
.event
.types
.composite
.EventHeaderDefinition
;
38 import org
.eclipse
.linuxtools
.internal
.ctf
.core
.trace
.StreamInputPacketIndexEntry
;
40 import com
.google
.common
.collect
.ImmutableList
;
43 * CTF trace packet reader. Reads the events of a packet of a trace file.
45 * @author Matthew Khouzam
46 * @author Simon Marchi
49 public class CTFStreamInputPacketReader
implements IDefinitionScope
, AutoCloseable
{
51 // ------------------------------------------------------------------------
53 // ------------------------------------------------------------------------
55 /** BitBuffer used to read the trace file. */
57 private BitBuffer fBitBuffer
;
59 /** StreamInputReader that uses this StreamInputPacketReader. */
60 private final CTFStreamInputReader fStreamInputReader
;
62 /** Trace packet header. */
63 private final StructDeclaration fTracePacketHeaderDecl
;
65 /** Stream packet context definition. */
66 private final StructDeclaration fStreamPacketContextDecl
;
68 /** Stream event header definition. */
69 private final IDeclaration fStreamEventHeaderDecl
;
71 /** Stream event context definition. */
72 private final StructDeclaration fStreamEventContextDecl
;
74 private ICompositeDefinition fCurrentTracePacketHeaderDef
;
75 private ICompositeDefinition fCurrentStreamEventHeaderDef
;
76 private ICompositeDefinition fCurrentStreamPacketContextDef
;
77 /** Reference to the index entry of the current packet. */
78 private StreamInputPacketIndexEntry fCurrentPacket
= null;
81 * Last timestamp recorded.
83 * Needed to calculate the complete timestamp values for the events with
86 private long fLastTimestamp
= 0;
88 /** CPU id of current packet. */
89 private int fCurrentCpu
= 0;
91 private int fLostEventsInThisPacket
;
93 private long fLostEventsDuration
;
95 private boolean fHasLost
= false;
97 // ------------------------------------------------------------------------
99 // ------------------------------------------------------------------------
102 * Constructs a StreamInputPacketReader.
104 * @param streamInputReader
105 * The StreamInputReader to which this packet reader belongs to.
107 public CTFStreamInputPacketReader(CTFStreamInputReader streamInputReader
) {
108 fStreamInputReader
= streamInputReader
;
110 /* Set the BitBuffer's byte order. */
111 ByteBuffer allocateDirect
= ByteBuffer
.allocateDirect(0);
112 if (allocateDirect
== null) {
113 throw new IllegalStateException("Unable to allocate 0 bytes!"); //$NON-NLS-1$
115 fBitBuffer
= new BitBuffer(allocateDirect
);
117 final CTFStream currentStream
= streamInputReader
.getStreamInput().getStream();
118 fTracePacketHeaderDecl
= currentStream
.getTrace().getPacketHeader();
119 fStreamPacketContextDecl
= currentStream
.getPacketContextDecl();
120 fStreamEventHeaderDecl
= currentStream
.getEventHeaderDeclaration();
121 fStreamEventContextDecl
= currentStream
.getEventContextDecl();
125 * Get the event context defintiion
128 * the bitbuffer to read from
129 * @return an context definition, can be null
130 * @throws CTFReaderException
131 * out of bounds exception or such
133 public StructDefinition
getEventContextDefinition(@NonNull BitBuffer input
) throws CTFReaderException
{
134 return fStreamEventContextDecl
.createDefinition(fStreamInputReader
.getStreamInput(), LexicalScope
.STREAM_EVENT_CONTEXT
, input
);
138 * Get the stream context defintiion
141 * the bitbuffer to read from
142 * @return an context definition, can be null
143 * @throws CTFReaderException
144 * out of bounds exception or such
145 * @deprecated it was not used
148 public StructDefinition
getStreamEventHeaderDefinition(@NonNull BitBuffer input
) throws CTFReaderException
{
149 if (!(fStreamEventHeaderDecl
instanceof StructDeclaration
)) {
150 throw new IllegalStateException("Definition is not a struct definition, this is a deprecated method that doesn't work so well, stop using it."); //$NON-NLS-1$
152 return ((StructDeclaration
) fStreamEventHeaderDecl
).createDefinition(this, LexicalScope
.STREAM_EVENT_HEADER
, input
);
156 * Get the packet context defintiion
159 * the bitbuffer to read from
160 * @return an context definition, can be null
161 * @throws CTFReaderException
162 * out of bounds exception or such
164 public StructDefinition
getStreamPacketContextDefinition(@NonNull BitBuffer input
) throws CTFReaderException
{
165 return fStreamPacketContextDecl
.createDefinition(fStreamInputReader
.getStreamInput(), LexicalScope
.STREAM_PACKET_CONTEXT
, input
);
169 * Get the event header defintiion
172 * the bitbuffer to read from
173 * @return an header definition, can be null
174 * @throws CTFReaderException
175 * out of bounds exception or such
177 public StructDefinition
getTracePacketHeaderDefinition(@NonNull BitBuffer input
) throws CTFReaderException
{
178 return fTracePacketHeaderDecl
.createDefinition(fStreamInputReader
.getStreamInput().getStream().getTrace(), LexicalScope
.TRACE_PACKET_HEADER
, input
);
182 * Dispose the StreamInputPacketReader
185 public void close() {
189 // ------------------------------------------------------------------------
190 // Getters/Setters/Predicates
191 // ------------------------------------------------------------------------
194 * Gets the current packet
196 * @return the current packet
198 StreamInputPacketIndexEntry
getCurrentPacket() {
199 return fCurrentPacket
;
203 * Gets the CPU (core) number
205 * @return the CPU (core) number
207 public int getCPU() {
212 public LexicalScope
getScopePath() {
213 return LexicalScope
.PACKET
;
216 // ------------------------------------------------------------------------
218 // ------------------------------------------------------------------------
221 * Changes the current packet to the given one.
223 * @param currentPacket
224 * The index entry of the packet to switch to.
225 * @throws CTFReaderException
226 * If we get an error reading the packet
228 void setCurrentPacket(StreamInputPacketIndexEntry currentPacket
) throws CTFReaderException
{
229 StreamInputPacketIndexEntry prevPacket
= null;
230 fCurrentPacket
= currentPacket
;
232 if (fCurrentPacket
!= null) {
234 * Change the map of the BitBuffer.
236 ByteBuffer bb
= null;
238 bb
= fStreamInputReader
.getStreamInput().getByteBufferAt(
239 fCurrentPacket
.getOffsetBytes(),
240 (fCurrentPacket
.getPacketSizeBits() + 7) / 8);
241 } catch (IOException e
) {
242 throw new CTFReaderException(e
.getMessage(), e
);
245 BitBuffer bitBuffer
= new BitBuffer(bb
);
246 fBitBuffer
= bitBuffer
;
248 * Read trace packet header.
250 if (fTracePacketHeaderDecl
!= null) {
251 fCurrentTracePacketHeaderDef
= getTracePacketHeaderDefinition(bitBuffer
);
255 * Read stream packet context.
257 if (fStreamPacketContextDecl
!= null) {
258 fCurrentStreamPacketContextDef
= getStreamPacketContextDefinition(bitBuffer
);
261 if (getCurrentPacket().getTarget() != null) {
262 fCurrentCpu
= (int) getCurrentPacket().getTargetId();
265 /* Read number of lost events */
266 fLostEventsInThisPacket
= (int) getCurrentPacket().getLostEvents();
267 if (fLostEventsInThisPacket
!= 0) {
270 * Compute the duration of the lost event time range. If the
271 * current packet is the first packet, duration will be set
274 long lostEventsStartTime
;
275 int index
= fStreamInputReader
.getStreamInput().getIndex().getEntries().indexOf(currentPacket
);
277 lostEventsStartTime
= currentPacket
.getTimestampBegin() + 1;
279 prevPacket
= fStreamInputReader
.getStreamInput().getIndex().getEntries().get(index
- 1);
280 lostEventsStartTime
= prevPacket
.getTimestampEnd();
282 fLostEventsDuration
= Math
.abs(lostEventsStartTime
- currentPacket
.getTimestampBegin());
287 * Use the timestamp begin of the packet as the reference for the
288 * timestamp reconstitution.
290 fLastTimestamp
= currentPacket
.getTimestampBegin();
298 * Returns whether it is possible to read any more events from this packet.
300 * @return True if it is possible to read any more events from this packet.
302 public boolean hasMoreEvents() {
303 BitBuffer bitBuffer
= fBitBuffer
;
304 StreamInputPacketIndexEntry currentPacket
= fCurrentPacket
;
305 if (currentPacket
!= null && bitBuffer
!= null) {
306 return fHasLost
|| (bitBuffer
.position() < currentPacket
.getContentSizeBits());
312 * Reads the next event of the packet into the right event definition.
314 * @return The event definition containing the event data that was just
316 * @throws CTFReaderException
317 * If there was a problem reading the trace
319 public EventDefinition
readNextEvent() throws CTFReaderException
{
320 /* Default values for those fields */
321 long eventID
= EventDeclaration
.UNSET_EVENT_ID
;
325 EventDeclaration lostEventDeclaration
= EventDeclaration
.getLostEventDeclaration();
326 StructDeclaration lostFields
= lostEventDeclaration
.getFields();
327 // this is a hard coded map, we know it's not null
328 IntegerDeclaration lostFieldsDecl
= (IntegerDeclaration
) lostFields
.getField(CTFStrings
.LOST_EVENTS_FIELD
);
329 if (lostFieldsDecl
== null)
331 throw new IllegalStateException("Lost events count not declared!"); //$NON-NLS-1$
333 IntegerDeclaration lostEventsDurationDecl
= (IntegerDeclaration
) lostFields
.getField(CTFStrings
.LOST_EVENTS_DURATION
);
334 if (lostEventsDurationDecl
== null) {
335 throw new IllegalStateException("Lost events duration not declared!"); //$NON-NLS-1$
337 IntegerDefinition lostDurationDef
= new IntegerDefinition(lostFieldsDecl
, null, CTFStrings
.LOST_EVENTS_DURATION
, fLostEventsDuration
);
338 IntegerDefinition lostCountDef
= new IntegerDefinition(lostEventsDurationDecl
, null, CTFStrings
.LOST_EVENTS_FIELD
, fLostEventsInThisPacket
);
339 IntegerDefinition
[] fields
= new IntegerDefinition
[] { lostCountDef
, lostDurationDef
};
340 /* this is weird notation, but it's the java notation */
341 final ImmutableList
<String
> fieldNameList
= ImmutableList
.<String
> builder().add(CTFStrings
.LOST_EVENTS_FIELD
).add(CTFStrings
.LOST_EVENTS_DURATION
).build();
342 return new EventDefinition(
343 lostEventDeclaration
,
349 new StructDefinition(
351 this, "fields", //$NON-NLS-1$
358 final BitBuffer currentBitBuffer
= fBitBuffer
;
359 if (currentBitBuffer
== null) {
362 final long posStart
= currentBitBuffer
.position();
363 /* Read the stream event header. */
364 if (fStreamEventHeaderDecl
!= null) {
365 if (fStreamEventHeaderDecl
instanceof IEventHeaderDeclaration
) {
366 fCurrentStreamEventHeaderDef
= (ICompositeDefinition
) fStreamEventHeaderDecl
.createDefinition(null, "", currentBitBuffer
); //$NON-NLS-1$
367 EventHeaderDefinition ehd
= (EventHeaderDefinition
) fCurrentStreamEventHeaderDef
;
368 eventID
= ehd
.getId();
369 timestamp
= calculateTimestamp(ehd
.getTimestamp(), ehd
.getTimestampLength());
371 fCurrentStreamEventHeaderDef
= ((StructDeclaration
) fStreamEventHeaderDecl
).createDefinition(null, LexicalScope
.EVENT_HEADER
, currentBitBuffer
);
372 StructDefinition StructEventHeaderDef
= (StructDefinition
) fCurrentStreamEventHeaderDef
;
373 /* Check for the event id. */
374 IDefinition idDef
= StructEventHeaderDef
.lookupDefinition("id"); //$NON-NLS-1$
375 SimpleDatatypeDefinition simpleIdDef
= null;
376 if (idDef
instanceof SimpleDatatypeDefinition
) {
377 simpleIdDef
= ((SimpleDatatypeDefinition
) idDef
);
378 } else if (idDef
!= null) {
379 throw new CTFReaderException("Id defintion not an integer, enum or float definiton in event header."); //$NON-NLS-1$
383 * Get the timestamp from the event header (may be overridden
386 IntegerDefinition timestampDef
= StructEventHeaderDef
.lookupInteger("timestamp"); //$NON-NLS-1$
388 /* Check for the variant v. */
389 IDefinition variantDef
= StructEventHeaderDef
.lookupDefinition("v"); //$NON-NLS-1$
390 if (variantDef
instanceof VariantDefinition
) {
392 /* Get the variant current field */
393 StructDefinition variantCurrentField
= (StructDefinition
) ((VariantDefinition
) variantDef
).getCurrentField();
396 * Try to get the id field in the current field of the
397 * variant. If it is present, it overrides the previously
400 IDefinition vIdDef
= variantCurrentField
.lookupDefinition("id"); //$NON-NLS-1$
401 if (vIdDef
instanceof IntegerDefinition
) {
402 simpleIdDef
= (SimpleDatatypeDefinition
) vIdDef
;
406 * Get the timestamp. This would overwrite any previous
407 * timestamp definition
409 timestampDef
= variantCurrentField
.lookupInteger("timestamp"); //$NON-NLS-1$
411 if (simpleIdDef
!= null) {
412 eventID
= simpleIdDef
.getIntegerValue();
414 if (timestampDef
!= null) {
415 timestamp
= calculateTimestamp(timestampDef
);
416 } // else timestamp remains 0
419 /* Get the right event definition using the event id. */
420 IEventDeclaration eventDeclaration
= fStreamInputReader
.getStreamInput().getStream().getEvents().get(eventID
);
421 if (eventDeclaration
== null) {
422 throw new CTFReaderException("Incorrect event id : " + eventID
); //$NON-NLS-1$
424 EventDefinition eventDef
= eventDeclaration
.createDefinition(fStreamInputReader
, currentBitBuffer
, timestamp
);
427 * Set the event timestamp using the timestamp calculated by
431 if (posStart
== currentBitBuffer
.position()) {
432 throw new CTFReaderException("Empty event not allowed, event: " + eventDef
.getDeclaration().getName()); //$NON-NLS-1$
439 * Calculates the timestamp value of the event, possibly using the timestamp
440 * from the last event.
442 * @param timestampDef
443 * Integer definition of the timestamp.
444 * @return The calculated timestamp value.
446 private long calculateTimestamp(IntegerDefinition timestampDef
) {
447 int len
= timestampDef
.getDeclaration().getLength();
448 final long value
= timestampDef
.getValue();
450 return calculateTimestamp(value
, len
);
453 private long calculateTimestamp(final long value
, int len
) {
457 * If the timestamp length is 64 bits, it is a full timestamp.
460 fLastTimestamp
= value
;
461 return fLastTimestamp
;
465 * Bit mask to keep / remove all old / new bits.
467 majorasbitmask
= (1L << len
) - 1;
470 * If the new value is smaller than the corresponding bits of the last
471 * timestamp, we assume an overflow of the compact representation.
474 if (newval
< (fLastTimestamp
& majorasbitmask
)) {
475 newval
= newval
+ (1L << len
);
478 /* Keep only the high bits of the old value */
479 fLastTimestamp
= fLastTimestamp
& ~majorasbitmask
;
481 /* Then add the low bits of the new value */
482 fLastTimestamp
= fLastTimestamp
+ newval
;
484 return fLastTimestamp
;
488 public Definition
lookupDefinition(String lookupPath
) {
489 if (lookupPath
.equals(LexicalScope
.STREAM_PACKET_CONTEXT
.toString())) {
490 return (Definition
) fCurrentStreamPacketContextDef
;
492 if (lookupPath
.equals(LexicalScope
.TRACE_PACKET_HEADER
.toString())) {
493 return (Definition
) fCurrentTracePacketHeaderDef
;
499 * Get stream event header
501 * @return the stream event header
503 * {@link CTFStreamInputPacketReader#getStreamEventHeaderDefinition()}
506 public StructDefinition
getCurrentStreamEventHeader() {
507 return (StructDefinition
) ((fCurrentStreamEventHeaderDef
instanceof StructDefinition
) ? fCurrentStreamEventHeaderDef
: null);
511 * Get stream event header
513 * @return the stream event header
516 public ICompositeDefinition
getStreamEventHeaderDefinition() {
517 return fCurrentStreamEventHeaderDef
;
521 * Get the current packet event header
523 * @return the current packet event header
525 public StructDefinition
getCurrentPacketEventHeader() {
526 if (fCurrentTracePacketHeaderDef
instanceof StructDefinition
) {
527 return (StructDefinition
) fCurrentTracePacketHeaderDef
;