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
;
16 import java
.nio
.MappedByteBuffer
;
17 import java
.nio
.channels
.FileChannel
.MapMode
;
19 import org
.eclipse
.jdt
.annotation
.NonNull
;
20 import org
.eclipse
.jdt
.annotation
.Nullable
;
21 import org
.eclipse
.linuxtools
.ctf
.core
.CTFStrings
;
22 import org
.eclipse
.linuxtools
.ctf
.core
.event
.EventDefinition
;
23 import org
.eclipse
.linuxtools
.ctf
.core
.event
.IEventDeclaration
;
24 import org
.eclipse
.linuxtools
.ctf
.core
.event
.io
.BitBuffer
;
25 import org
.eclipse
.linuxtools
.ctf
.core
.event
.scope
.IDefinitionScope
;
26 import org
.eclipse
.linuxtools
.ctf
.core
.event
.scope
.LexicalScope
;
27 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.Definition
;
28 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.ICompositeDefinition
;
29 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.IDeclaration
;
30 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.IDefinition
;
31 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.IEventHeaderDeclaration
;
32 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.IntegerDeclaration
;
33 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.IntegerDefinition
;
34 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.SimpleDatatypeDefinition
;
35 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.StructDeclaration
;
36 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.StructDefinition
;
37 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.VariantDefinition
;
38 import org
.eclipse
.linuxtools
.internal
.ctf
.core
.event
.EventDeclaration
;
39 import org
.eclipse
.linuxtools
.internal
.ctf
.core
.event
.types
.composite
.EventHeaderDefinition
;
40 import org
.eclipse
.linuxtools
.internal
.ctf
.core
.trace
.StreamInputPacketIndexEntry
;
42 import com
.google
.common
.collect
.ImmutableList
;
45 * CTF trace packet reader. Reads the events of a packet of a trace file.
47 * @author Matthew Khouzam
48 * @author Simon Marchi
51 public class CTFStreamInputPacketReader
implements IDefinitionScope
, AutoCloseable
{
53 // ------------------------------------------------------------------------
55 // ------------------------------------------------------------------------
57 /** BitBuffer used to read the trace file. */
59 private BitBuffer fBitBuffer
;
61 /** StreamInputReader that uses this StreamInputPacketReader. */
62 private final CTFStreamInputReader fStreamInputReader
;
64 /** Trace packet header. */
65 private final StructDeclaration fTracePacketHeaderDecl
;
67 /** Stream packet context definition. */
68 private final StructDeclaration fStreamPacketContextDecl
;
70 /** Stream event header definition. */
71 private final IDeclaration fStreamEventHeaderDecl
;
73 /** Stream event context definition. */
74 private final StructDeclaration fStreamEventContextDecl
;
76 private ICompositeDefinition fCurrentTracePacketHeaderDef
;
77 private ICompositeDefinition fCurrentStreamEventHeaderDef
;
78 private ICompositeDefinition fCurrentStreamPacketContextDef
;
79 /** Reference to the index entry of the current packet. */
80 private StreamInputPacketIndexEntry fCurrentPacket
= null;
83 * Last timestamp recorded.
85 * Needed to calculate the complete timestamp values for the events with
88 private long fLastTimestamp
= 0;
90 /** CPU id of current packet. */
91 private int fCurrentCpu
= 0;
93 private int fLostEventsInThisPacket
;
95 private long fLostEventsDuration
;
97 private boolean fHasLost
= false;
99 // ------------------------------------------------------------------------
101 // ------------------------------------------------------------------------
104 * Constructs a StreamInputPacketReader.
106 * @param streamInputReader
107 * The StreamInputReader to which this packet reader belongs to.
109 public CTFStreamInputPacketReader(CTFStreamInputReader streamInputReader
) {
110 fStreamInputReader
= streamInputReader
;
112 /* Set the BitBuffer's byte order. */
113 ByteBuffer allocateDirect
= ByteBuffer
.allocateDirect(0);
114 if (allocateDirect
== null) {
115 throw new IllegalStateException("Unable to allocate 0 bytes!"); //$NON-NLS-1$
117 fBitBuffer
= new BitBuffer(allocateDirect
);
119 final CTFStream currentStream
= streamInputReader
.getStreamInput().getStream();
120 fTracePacketHeaderDecl
= currentStream
.getTrace().getPacketHeader();
121 fStreamPacketContextDecl
= currentStream
.getPacketContextDecl();
122 fStreamEventHeaderDecl
= currentStream
.getEventHeaderDeclaration();
123 fStreamEventContextDecl
= currentStream
.getEventContextDecl();
127 * Get the event context defintiion
130 * the bitbuffer to read from
131 * @return an context definition, can be null
132 * @throws CTFReaderException
133 * out of bounds exception or such
135 public StructDefinition
getEventContextDefinition(@NonNull BitBuffer input
) throws CTFReaderException
{
136 return fStreamEventContextDecl
.createDefinition(fStreamInputReader
.getStreamInput(), LexicalScope
.STREAM_EVENT_CONTEXT
, input
);
140 * Get the stream context defintiion
143 * the bitbuffer to read from
144 * @return an context definition, can be null
145 * @throws CTFReaderException
146 * out of bounds exception or such
147 * @deprecated it was not used
150 public StructDefinition
getStreamEventHeaderDefinition(@NonNull BitBuffer input
) throws CTFReaderException
{
151 if (!(fStreamEventHeaderDecl
instanceof StructDeclaration
)) {
152 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$
154 return ((StructDeclaration
) fStreamEventHeaderDecl
).createDefinition(this, LexicalScope
.STREAM_EVENT_HEADER
, input
);
158 * Get the packet context defintiion
161 * the bitbuffer to read from
162 * @return an context definition, can be null
163 * @throws CTFReaderException
164 * out of bounds exception or such
166 public StructDefinition
getStreamPacketContextDefinition(@NonNull BitBuffer input
) throws CTFReaderException
{
167 return fStreamPacketContextDecl
.createDefinition(fStreamInputReader
.getStreamInput(), LexicalScope
.STREAM_PACKET_CONTEXT
, input
);
171 * Get the event header defintiion
174 * the bitbuffer to read from
175 * @return an header definition, can be null
176 * @throws CTFReaderException
177 * out of bounds exception or such
179 public StructDefinition
getTracePacketHeaderDefinition(@NonNull BitBuffer input
) throws CTFReaderException
{
180 return fTracePacketHeaderDecl
.createDefinition(fStreamInputReader
.getStreamInput().getStream().getTrace(), LexicalScope
.TRACE_PACKET_HEADER
, input
);
184 * Dispose the StreamInputPacketReader
187 public void close() {
191 // ------------------------------------------------------------------------
192 // Getters/Setters/Predicates
193 // ------------------------------------------------------------------------
196 * Gets the current packet
198 * @return the current packet
200 StreamInputPacketIndexEntry
getCurrentPacket() {
201 return fCurrentPacket
;
205 * Gets the CPU (core) number
207 * @return the CPU (core) number
209 public int getCPU() {
214 public LexicalScope
getScopePath() {
215 return LexicalScope
.PACKET
;
218 // ------------------------------------------------------------------------
220 // ------------------------------------------------------------------------
223 private ByteBuffer
getByteBufferAt(long position
, long size
) throws CTFReaderException
, IOException
{
224 MappedByteBuffer map
= fStreamInputReader
.getFc().map(MapMode
.READ_ONLY
, position
, size
);
226 throw new CTFReaderException("Failed to allocate mapped byte buffer"); //$NON-NLS-1$
231 * Changes the current packet to the given one.
233 * @param currentPacket
234 * The index entry of the packet to switch to.
235 * @throws CTFReaderException
236 * If we get an error reading the packet
238 void setCurrentPacket(StreamInputPacketIndexEntry currentPacket
) throws CTFReaderException
{
239 StreamInputPacketIndexEntry prevPacket
= null;
240 fCurrentPacket
= currentPacket
;
242 if (fCurrentPacket
!= null) {
244 * Change the map of the BitBuffer.
246 ByteBuffer bb
= null;
248 bb
= getByteBufferAt(
249 fCurrentPacket
.getOffsetBytes(),
250 (fCurrentPacket
.getPacketSizeBits() + 7) / 8);
251 } catch (IOException e
) {
252 throw new CTFReaderException(e
.getMessage(), e
);
255 BitBuffer bitBuffer
= new BitBuffer(bb
);
256 fBitBuffer
= bitBuffer
;
258 * Read trace packet header.
260 if (fTracePacketHeaderDecl
!= null) {
261 fCurrentTracePacketHeaderDef
= getTracePacketHeaderDefinition(bitBuffer
);
265 * Read stream packet context.
267 if (fStreamPacketContextDecl
!= null) {
268 fCurrentStreamPacketContextDef
= getStreamPacketContextDefinition(bitBuffer
);
271 if (getCurrentPacket().getTarget() != null) {
272 fCurrentCpu
= (int) getCurrentPacket().getTargetId();
275 /* Read number of lost events */
276 fLostEventsInThisPacket
= (int) getCurrentPacket().getLostEvents();
277 if (fLostEventsInThisPacket
!= 0) {
280 * Compute the duration of the lost event time range. If the
281 * current packet is the first packet, duration will be set
284 long lostEventsStartTime
;
285 int index
= fStreamInputReader
.getStreamInput().getIndex().getEntries().indexOf(currentPacket
);
287 lostEventsStartTime
= currentPacket
.getTimestampBegin() + 1;
289 prevPacket
= fStreamInputReader
.getStreamInput().getIndex().getEntries().get(index
- 1);
290 lostEventsStartTime
= prevPacket
.getTimestampEnd();
292 fLostEventsDuration
= Math
.abs(lostEventsStartTime
- currentPacket
.getTimestampBegin());
297 * Use the timestamp begin of the packet as the reference for the
298 * timestamp reconstitution.
300 fLastTimestamp
= currentPacket
.getTimestampBegin();
308 * Returns whether it is possible to read any more events from this packet.
310 * @return True if it is possible to read any more events from this packet.
312 public boolean hasMoreEvents() {
313 BitBuffer bitBuffer
= fBitBuffer
;
314 StreamInputPacketIndexEntry currentPacket
= fCurrentPacket
;
315 if (currentPacket
!= null && bitBuffer
!= null) {
316 return fHasLost
|| (bitBuffer
.position() < currentPacket
.getContentSizeBits());
322 * Reads the next event of the packet into the right event definition.
324 * @return The event definition containing the event data that was just
326 * @throws CTFReaderException
327 * If there was a problem reading the trace
329 public EventDefinition
readNextEvent() throws CTFReaderException
{
330 /* Default values for those fields */
331 // compromise since we cannot have 64 bit addressing of arrays yet.
332 int eventID
= (int) EventDeclaration
.UNSET_EVENT_ID
;
336 EventDeclaration lostEventDeclaration
= EventDeclaration
.getLostEventDeclaration();
337 StructDeclaration lostFields
= lostEventDeclaration
.getFields();
338 // this is a hard coded map, we know it's not null
339 IntegerDeclaration lostFieldsDecl
= (IntegerDeclaration
) lostFields
.getField(CTFStrings
.LOST_EVENTS_FIELD
);
340 if (lostFieldsDecl
== null)
342 throw new IllegalStateException("Lost events count not declared!"); //$NON-NLS-1$
344 IntegerDeclaration lostEventsDurationDecl
= (IntegerDeclaration
) lostFields
.getField(CTFStrings
.LOST_EVENTS_DURATION
);
345 if (lostEventsDurationDecl
== null) {
346 throw new IllegalStateException("Lost events duration not declared!"); //$NON-NLS-1$
348 IntegerDefinition lostDurationDef
= new IntegerDefinition(lostFieldsDecl
, null, CTFStrings
.LOST_EVENTS_DURATION
, fLostEventsDuration
);
349 IntegerDefinition lostCountDef
= new IntegerDefinition(lostEventsDurationDecl
, null, CTFStrings
.LOST_EVENTS_FIELD
, fLostEventsInThisPacket
);
350 IntegerDefinition
[] fields
= new IntegerDefinition
[] { lostCountDef
, lostDurationDef
};
351 /* this is weird notation, but it's the java notation */
352 final ImmutableList
<String
> fieldNameList
= ImmutableList
.<String
> builder().add(CTFStrings
.LOST_EVENTS_FIELD
).add(CTFStrings
.LOST_EVENTS_DURATION
).build();
353 return new EventDefinition(
354 lostEventDeclaration
,
360 new StructDefinition(
362 this, "fields", //$NON-NLS-1$
369 final BitBuffer currentBitBuffer
= fBitBuffer
;
370 if (currentBitBuffer
== null) {
373 final long posStart
= currentBitBuffer
.position();
374 /* Read the stream event header. */
375 if (fStreamEventHeaderDecl
!= null) {
376 if (fStreamEventHeaderDecl
instanceof IEventHeaderDeclaration
) {
377 fCurrentStreamEventHeaderDef
= (ICompositeDefinition
) fStreamEventHeaderDecl
.createDefinition(null, "", currentBitBuffer
); //$NON-NLS-1$
378 EventHeaderDefinition ehd
= (EventHeaderDefinition
) fCurrentStreamEventHeaderDef
;
379 eventID
= ehd
.getId();
380 timestamp
= calculateTimestamp(ehd
.getTimestamp(), ehd
.getTimestampLength());
382 fCurrentStreamEventHeaderDef
= ((StructDeclaration
) fStreamEventHeaderDecl
).createDefinition(null, LexicalScope
.EVENT_HEADER
, currentBitBuffer
);
383 StructDefinition StructEventHeaderDef
= (StructDefinition
) fCurrentStreamEventHeaderDef
;
384 /* Check for the event id. */
385 IDefinition idDef
= StructEventHeaderDef
.lookupDefinition("id"); //$NON-NLS-1$
386 SimpleDatatypeDefinition simpleIdDef
= null;
387 if (idDef
instanceof SimpleDatatypeDefinition
) {
388 simpleIdDef
= ((SimpleDatatypeDefinition
) idDef
);
389 } else if (idDef
!= null) {
390 throw new CTFReaderException("Id defintion not an integer, enum or float definiton in event header."); //$NON-NLS-1$
394 * Get the timestamp from the event header (may be overridden
397 IntegerDefinition timestampDef
= StructEventHeaderDef
.lookupInteger("timestamp"); //$NON-NLS-1$
399 /* Check for the variant v. */
400 IDefinition variantDef
= StructEventHeaderDef
.lookupDefinition("v"); //$NON-NLS-1$
401 if (variantDef
instanceof VariantDefinition
) {
403 /* Get the variant current field */
404 StructDefinition variantCurrentField
= (StructDefinition
) ((VariantDefinition
) variantDef
).getCurrentField();
407 * Try to get the id field in the current field of the
408 * variant. If it is present, it overrides the previously
411 IDefinition vIdDef
= variantCurrentField
.lookupDefinition("id"); //$NON-NLS-1$
412 if (vIdDef
instanceof IntegerDefinition
) {
413 simpleIdDef
= (SimpleDatatypeDefinition
) vIdDef
;
417 * Get the timestamp. This would overwrite any previous
418 * timestamp definition
420 timestampDef
= variantCurrentField
.lookupInteger("timestamp"); //$NON-NLS-1$
422 if (simpleIdDef
!= null) {
423 eventID
= simpleIdDef
.getIntegerValue().intValue();
425 if (timestampDef
!= null) {
426 timestamp
= calculateTimestamp(timestampDef
);
427 } // else timestamp remains 0
430 /* Get the right event definition using the event id. */
431 IEventDeclaration eventDeclaration
= fStreamInputReader
.getStreamInput().getStream().getEventDeclaration(eventID
);
432 if (eventDeclaration
== null) {
433 throw new CTFReaderException("Incorrect event id : " + eventID
); //$NON-NLS-1$
435 EventDefinition eventDef
= eventDeclaration
.createDefinition(fStreamInputReader
, currentBitBuffer
, timestamp
);
438 * Set the event timestamp using the timestamp calculated by
442 if (posStart
== currentBitBuffer
.position()) {
443 throw new CTFReaderException("Empty event not allowed, event: " + eventDef
.getDeclaration().getName()); //$NON-NLS-1$
450 * Calculates the timestamp value of the event, possibly using the timestamp
451 * from the last event.
453 * @param timestampDef
454 * Integer definition of the timestamp.
455 * @return The calculated timestamp value.
457 private long calculateTimestamp(IntegerDefinition timestampDef
) {
458 int len
= timestampDef
.getDeclaration().getLength();
459 final long value
= timestampDef
.getValue();
461 return calculateTimestamp(value
, len
);
464 private long calculateTimestamp(final long value
, int len
) {
468 * If the timestamp length is 64 bits, it is a full timestamp.
471 fLastTimestamp
= value
;
472 return fLastTimestamp
;
476 * Bit mask to keep / remove all old / new bits.
478 majorasbitmask
= (1L << len
) - 1;
481 * If the new value is smaller than the corresponding bits of the last
482 * timestamp, we assume an overflow of the compact representation.
485 if (newval
< (fLastTimestamp
& majorasbitmask
)) {
486 newval
= newval
+ (1L << len
);
489 /* Keep only the high bits of the old value */
490 fLastTimestamp
= fLastTimestamp
& ~majorasbitmask
;
492 /* Then add the low bits of the new value */
493 fLastTimestamp
= fLastTimestamp
+ newval
;
495 return fLastTimestamp
;
499 public Definition
lookupDefinition(String lookupPath
) {
500 if (lookupPath
.equals(LexicalScope
.STREAM_PACKET_CONTEXT
.toString())) {
501 return (Definition
) fCurrentStreamPacketContextDef
;
503 if (lookupPath
.equals(LexicalScope
.TRACE_PACKET_HEADER
.toString())) {
504 return (Definition
) fCurrentTracePacketHeaderDef
;
510 * Get stream event header
512 * @return the stream event header
514 * {@link CTFStreamInputPacketReader#getStreamEventHeaderDefinition()}
517 public StructDefinition
getCurrentStreamEventHeader() {
518 return (StructDefinition
) ((fCurrentStreamEventHeaderDef
instanceof StructDefinition
) ? fCurrentStreamEventHeaderDef
: null);
522 * Get stream event header
524 * @return the stream event header
527 public ICompositeDefinition
getStreamEventHeaderDefinition() {
528 return fCurrentStreamEventHeaderDef
;
532 * Get the current packet event header
534 * @return the current packet event header
536 public StructDefinition
getCurrentPacketEventHeader() {
537 if (fCurrentTracePacketHeaderDef
instanceof StructDefinition
) {
538 return (StructDefinition
) fCurrentTracePacketHeaderDef
;