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
.IDefinition
;
27 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.IntegerDeclaration
;
28 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.IntegerDefinition
;
29 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.SimpleDatatypeDefinition
;
30 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.StructDeclaration
;
31 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.StructDefinition
;
32 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.VariantDefinition
;
33 import org
.eclipse
.linuxtools
.internal
.ctf
.core
.event
.EventDeclaration
;
34 import org
.eclipse
.linuxtools
.internal
.ctf
.core
.trace
.StreamInputPacketIndexEntry
;
36 import com
.google
.common
.collect
.ImmutableList
;
39 * CTF trace packet reader. Reads the events of a packet of a trace file.
41 * @author Matthew Khouzam
42 * @author Simon Marchi
45 public class CTFStreamInputPacketReader
implements IDefinitionScope
, AutoCloseable
{
47 // ------------------------------------------------------------------------
49 // ------------------------------------------------------------------------
51 /** BitBuffer used to read the trace file. */
53 private BitBuffer fBitBuffer
;
55 /** StreamInputReader that uses this StreamInputPacketReader. */
56 private final CTFStreamInputReader fStreamInputReader
;
58 /** Trace packet header. */
59 private final StructDeclaration fTracePacketHeaderDecl
;
61 /** Stream packet context definition. */
62 private final StructDeclaration fStreamPacketContextDecl
;
64 /** Stream event header definition. */
65 private final StructDeclaration fStreamEventHeaderDecl
;
67 /** Stream event context definition. */
68 private final StructDeclaration fStreamEventContextDecl
;
70 private StructDefinition fCurrentTracePacketHeaderDef
;
71 private StructDefinition fCurrentStreamEventHeaderDef
;
72 private Definition fCurrentStreamPacketContextDef
;
73 /** Reference to the index entry of the current packet. */
74 private StreamInputPacketIndexEntry fCurrentPacket
= null;
77 * Last timestamp recorded.
79 * Needed to calculate the complete timestamp values for the events with
82 private long fLastTimestamp
= 0;
84 /** CPU id of current packet. */
85 private int fCurrentCpu
= 0;
87 private int fLostEventsInThisPacket
;
89 private long fLostEventsDuration
;
91 private boolean fHasLost
= false;
93 // ------------------------------------------------------------------------
95 // ------------------------------------------------------------------------
98 * Constructs a StreamInputPacketReader.
100 * @param streamInputReader
101 * The StreamInputReader to which this packet reader belongs to.
103 public CTFStreamInputPacketReader(CTFStreamInputReader streamInputReader
) {
104 fStreamInputReader
= streamInputReader
;
106 /* Set the BitBuffer's byte order. */
107 fBitBuffer
= new BitBuffer();
108 fBitBuffer
.setByteOrder(streamInputReader
.getByteOrder());
110 final CTFStream currentStream
= streamInputReader
.getStreamInput().getStream();
111 fTracePacketHeaderDecl
= currentStream
.getTrace().getPacketHeader();
112 fStreamPacketContextDecl
= currentStream
.getPacketContextDecl();
113 fStreamEventHeaderDecl
= currentStream
.getEventHeaderDecl();
114 fStreamEventContextDecl
= currentStream
.getEventContextDecl();
118 * Get the event context defintiion
121 * the bitbuffer to read from
122 * @return an context definition, can be null
123 * @throws CTFReaderException
124 * out of bounds exception or such
126 public StructDefinition
getEventContextDefinition(@NonNull BitBuffer input
) throws CTFReaderException
{
127 return fStreamEventContextDecl
.createDefinition(fStreamInputReader
.getStreamInput(), LexicalScope
.STREAM_EVENT_CONTEXT
, input
);
131 * Get the stream context defintiion
134 * the bitbuffer to read from
135 * @return an context definition, can be null
136 * @throws CTFReaderException
137 * out of bounds exception or such
139 public StructDefinition
getStreamEventHeaderDefinition(@NonNull BitBuffer input
) throws CTFReaderException
{
140 return fStreamEventHeaderDecl
.createDefinition(this, LexicalScope
.EVENT_HEADER
, input
);
144 * Get the packet context defintiion
147 * the bitbuffer to read from
148 * @return an context definition, can be null
149 * @throws CTFReaderException
150 * out of bounds exception or such
152 public StructDefinition
getStreamPacketContextDefinition(@NonNull BitBuffer input
) throws CTFReaderException
{
153 return fStreamPacketContextDecl
.createDefinition(fStreamInputReader
.getStreamInput(), LexicalScope
.STREAM_PACKET_CONTEXT
, input
);
157 * Get the event header defintiion
160 * the bitbuffer to read from
161 * @return an header definition, can be null
162 * @throws CTFReaderException
163 * out of bounds exception or such
165 public StructDefinition
getTracePacketHeaderDefinition(@NonNull BitBuffer input
) throws CTFReaderException
{
166 return fTracePacketHeaderDecl
.createDefinition(fStreamInputReader
.getStreamInput().getStream().getTrace(), LexicalScope
.TRACE_PACKET_HEADER
, input
);
170 * Dispose the StreamInputPacketReader
173 public void close() {
177 // ------------------------------------------------------------------------
178 // Getters/Setters/Predicates
179 // ------------------------------------------------------------------------
182 * Gets the current packet
184 * @return the current packet
186 StreamInputPacketIndexEntry
getCurrentPacket() {
187 return fCurrentPacket
;
191 * Gets the CPU (core) number
193 * @return the CPU (core) number
195 public int getCPU() {
200 public LexicalScope
getScopePath() {
201 return LexicalScope
.PACKET
;
204 // ------------------------------------------------------------------------
206 // ------------------------------------------------------------------------
209 * Changes the current packet to the given one.
211 * @param currentPacket
212 * The index entry of the packet to switch to.
213 * @throws CTFReaderException
214 * If we get an error reading the packet
216 void setCurrentPacket(StreamInputPacketIndexEntry currentPacket
) throws CTFReaderException
{
217 StreamInputPacketIndexEntry prevPacket
= null;
218 fCurrentPacket
= currentPacket
;
220 if (fCurrentPacket
!= null) {
222 * Change the map of the BitBuffer.
224 ByteBuffer bb
= null;
226 bb
= fStreamInputReader
.getStreamInput().getByteBufferAt(
227 fCurrentPacket
.getOffsetBytes(),
228 (fCurrentPacket
.getPacketSizeBits() + 7) / 8);
229 } catch (IOException e
) {
230 throw new CTFReaderException(e
.getMessage(), e
);
233 BitBuffer bitBuffer
= new BitBuffer(bb
);
234 fBitBuffer
= bitBuffer
;
236 * Read trace packet header.
238 if (fTracePacketHeaderDecl
!= null) {
239 fCurrentTracePacketHeaderDef
= getTracePacketHeaderDefinition(bitBuffer
);
243 * Read stream packet context.
245 if (fStreamPacketContextDecl
!= null) {
246 fCurrentStreamPacketContextDef
= getStreamPacketContextDefinition(bitBuffer
);
249 if (getCurrentPacket().getTarget() != null) {
250 fCurrentCpu
= (int) getCurrentPacket().getTargetId();
253 /* Read number of lost events */
254 fLostEventsInThisPacket
= (int) getCurrentPacket().getLostEvents();
255 if (fLostEventsInThisPacket
!= 0) {
258 * Compute the duration of the lost event time range. If the
259 * current packet is the first packet, duration will be set
262 long lostEventsStartTime
;
263 int index
= fStreamInputReader
.getStreamInput().getIndex().getEntries().indexOf(currentPacket
);
265 lostEventsStartTime
= currentPacket
.getTimestampBegin() + 1;
267 prevPacket
= fStreamInputReader
.getStreamInput().getIndex().getEntries().get(index
- 1);
268 lostEventsStartTime
= prevPacket
.getTimestampEnd();
270 fLostEventsDuration
= Math
.abs(lostEventsStartTime
- currentPacket
.getTimestampBegin());
275 * Use the timestamp begin of the packet as the reference for the
276 * timestamp reconstitution.
278 fLastTimestamp
= currentPacket
.getTimestampBegin();
286 * Returns whether it is possible to read any more events from this packet.
288 * @return True if it is possible to read any more events from this packet.
290 public boolean hasMoreEvents() {
291 BitBuffer bitBuffer
= fBitBuffer
;
292 StreamInputPacketIndexEntry currentPacket
= fCurrentPacket
;
293 if (currentPacket
!= null && bitBuffer
!= null) {
294 return fHasLost
|| (bitBuffer
.position() < currentPacket
.getContentSizeBits());
300 * Reads the next event of the packet into the right event definition.
302 * @return The event definition containing the event data that was just
304 * @throws CTFReaderException
305 * If there was a problem reading the trace
307 public EventDefinition
readNextEvent() throws CTFReaderException
{
308 /* Default values for those fields */
309 long eventID
= EventDeclaration
.UNSET_EVENT_ID
;
313 EventDeclaration lostEventDeclaration
= EventDeclaration
.getLostEventDeclaration();
314 StructDeclaration lostFields
= lostEventDeclaration
.getFields();
315 // this is a hard coded map, we know it's not null
316 IntegerDeclaration lostFieldsDecl
= (IntegerDeclaration
) lostFields
.getField(CTFStrings
.LOST_EVENTS_FIELD
);
317 if (lostFieldsDecl
== null)
319 throw new IllegalStateException("Lost events count not declared!"); //$NON-NLS-1$
321 IntegerDeclaration lostEventsDurationDecl
= (IntegerDeclaration
) lostFields
.getField(CTFStrings
.LOST_EVENTS_DURATION
);
322 if (lostEventsDurationDecl
== null) {
323 throw new IllegalStateException("Lost events duration not declared!"); //$NON-NLS-1$
325 IntegerDefinition lostDurationDef
= new IntegerDefinition(lostFieldsDecl
, null, CTFStrings
.LOST_EVENTS_DURATION
, fLostEventsDuration
);
326 IntegerDefinition lostCountDef
= new IntegerDefinition(lostEventsDurationDecl
, null, CTFStrings
.LOST_EVENTS_FIELD
, fLostEventsInThisPacket
);
327 IntegerDefinition
[] fields
= new IntegerDefinition
[] { lostCountDef
, lostDurationDef
};
328 /* this is weird notation, but it's the java notation */
329 final ImmutableList
<String
> fieldNameList
= ImmutableList
.<String
> builder().add(CTFStrings
.LOST_EVENTS_FIELD
).add(CTFStrings
.LOST_EVENTS_DURATION
).build();
330 return new EventDefinition(
331 lostEventDeclaration
,
337 new StructDefinition(
339 this, "fields", //$NON-NLS-1$
346 final BitBuffer currentBitBuffer
= fBitBuffer
;
347 if( currentBitBuffer
== null ) {
350 final long posStart
= currentBitBuffer
.position();
351 /* Read the stream event header. */
352 if (fStreamEventHeaderDecl
!= null) {
353 fCurrentStreamEventHeaderDef
= getStreamEventHeaderDefinition(currentBitBuffer
);
355 /* Check for the event id. */
356 IDefinition idDef
= fCurrentStreamEventHeaderDef
.lookupDefinition("id"); //$NON-NLS-1$
357 if (idDef
instanceof SimpleDatatypeDefinition
) {
358 eventID
= ((SimpleDatatypeDefinition
) idDef
).getIntegerValue();
359 } else if (idDef
!= null) {
360 throw new CTFReaderException("Incorrect event id : " + eventID
); //$NON-NLS-1$
364 * Get the timestamp from the event header (may be overridden later
367 IntegerDefinition timestampDef
= fCurrentStreamEventHeaderDef
.lookupInteger("timestamp"); //$NON-NLS-1$
368 if (timestampDef
!= null) {
369 timestamp
= calculateTimestamp(timestampDef
);
370 } // else timestamp remains 0
372 /* Check for the variant v. */
373 IDefinition variantDef
= fCurrentStreamEventHeaderDef
.lookupDefinition("v"); //$NON-NLS-1$
374 if (variantDef
instanceof VariantDefinition
) {
376 /* Get the variant current field */
377 StructDefinition variantCurrentField
= (StructDefinition
) ((VariantDefinition
) variantDef
).getCurrentField();
380 * Try to get the id field in the current field of the variant.
381 * If it is present, it overrides the previously read event id.
383 IDefinition idIntegerDef
= variantCurrentField
.lookupDefinition("id"); //$NON-NLS-1$
384 if (idIntegerDef
instanceof IntegerDefinition
) {
385 eventID
= ((IntegerDefinition
) idIntegerDef
).getValue();
389 * Get the timestamp. This would overwrite any previous
390 * timestamp definition
392 IDefinition def
= variantCurrentField
.lookupDefinition("timestamp"); //$NON-NLS-1$
393 if (def
instanceof IntegerDefinition
) {
394 timestamp
= calculateTimestamp((IntegerDefinition
) def
);
399 /* Get the right event definition using the event id. */
400 IEventDeclaration eventDeclaration
= fStreamInputReader
.getStreamInput().getStream().getEvents().get(eventID
);
401 if (eventDeclaration
== null) {
402 throw new CTFReaderException("Incorrect event id : " + eventID
); //$NON-NLS-1$
404 EventDefinition eventDef
= eventDeclaration
.createDefinition(fStreamInputReader
, currentBitBuffer
, timestamp
);
407 * Set the event timestamp using the timestamp calculated by
411 if (posStart
== currentBitBuffer
.position()) {
412 throw new CTFReaderException("Empty event not allowed, event: " + eventDef
.getDeclaration().getName()); //$NON-NLS-1$
419 * Calculates the timestamp value of the event, possibly using the timestamp
420 * from the last event.
422 * @param timestampDef
423 * Integer definition of the timestamp.
424 * @return The calculated timestamp value.
426 private long calculateTimestamp(IntegerDefinition timestampDef
) {
429 int len
= timestampDef
.getDeclaration().getLength();
432 * If the timestamp length is 64 bits, it is a full timestamp.
434 if (timestampDef
.getDeclaration().getLength() == 64) {
435 fLastTimestamp
= timestampDef
.getValue();
436 return fLastTimestamp
;
440 * Bit mask to keep / remove all old / new bits.
442 majorasbitmask
= (1L << len
) - 1;
445 * If the new value is smaller than the corresponding bits of the last
446 * timestamp, we assume an overflow of the compact representation.
448 newval
= timestampDef
.getValue();
449 if (newval
< (fLastTimestamp
& majorasbitmask
)) {
450 newval
= newval
+ (1L << len
);
453 /* Keep only the high bits of the old value */
454 fLastTimestamp
= fLastTimestamp
& ~majorasbitmask
;
456 /* Then add the low bits of the new value */
457 fLastTimestamp
= fLastTimestamp
+ newval
;
459 return fLastTimestamp
;
463 public Definition
lookupDefinition(String lookupPath
) {
464 if (lookupPath
.equals(LexicalScope
.STREAM_PACKET_CONTEXT
.toString())) {
465 return fCurrentStreamPacketContextDef
;
467 if (lookupPath
.equals(LexicalScope
.TRACE_PACKET_HEADER
.toString())) {
468 return fCurrentTracePacketHeaderDef
;
474 * Get stream event header
476 * @return the stream event header
478 public StructDefinition
getCurrentStreamEventHeader() {
479 return fCurrentStreamEventHeaderDef
;
483 * Get the current packet event header
485 * @return the current packet event header
487 public StructDefinition
getCurrentPacketEventHeader() {
488 return fCurrentTracePacketHeaderDef
;