1 /*******************************************************************************
2 * Copyright (c) 2011, 2015 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
10 * Matthew Khouzam - Initial API and implementation
11 * Simon Marchi - Initial API and implementation
12 * Patrick Tasse - Bug 470754 - Incorrect time range in CTF Lost Event
13 *******************************************************************************/
14 package org
.eclipse
.tracecompass
.ctf
.core
.trace
;
16 import java
.io
.IOException
;
17 import java
.nio
.ByteBuffer
;
18 import java
.nio
.channels
.FileChannel
.MapMode
;
20 import org
.eclipse
.jdt
.annotation
.NonNull
;
21 import org
.eclipse
.jdt
.annotation
.Nullable
;
22 import org
.eclipse
.tracecompass
.ctf
.core
.CTFException
;
23 import org
.eclipse
.tracecompass
.ctf
.core
.CTFStrings
;
24 import org
.eclipse
.tracecompass
.ctf
.core
.event
.EventDefinition
;
25 import org
.eclipse
.tracecompass
.ctf
.core
.event
.IEventDeclaration
;
26 import org
.eclipse
.tracecompass
.ctf
.core
.event
.LostEventDeclaration
;
27 import org
.eclipse
.tracecompass
.ctf
.core
.event
.io
.BitBuffer
;
28 import org
.eclipse
.tracecompass
.ctf
.core
.event
.scope
.IDefinitionScope
;
29 import org
.eclipse
.tracecompass
.ctf
.core
.event
.scope
.ILexicalScope
;
30 import org
.eclipse
.tracecompass
.ctf
.core
.event
.scope
.LexicalScope
;
31 import org
.eclipse
.tracecompass
.ctf
.core
.event
.types
.Definition
;
32 import org
.eclipse
.tracecompass
.ctf
.core
.event
.types
.ICompositeDefinition
;
33 import org
.eclipse
.tracecompass
.ctf
.core
.event
.types
.IDeclaration
;
34 import org
.eclipse
.tracecompass
.ctf
.core
.event
.types
.IDefinition
;
35 import org
.eclipse
.tracecompass
.ctf
.core
.event
.types
.IEventHeaderDeclaration
;
36 import org
.eclipse
.tracecompass
.ctf
.core
.event
.types
.IntegerDeclaration
;
37 import org
.eclipse
.tracecompass
.ctf
.core
.event
.types
.IntegerDefinition
;
38 import org
.eclipse
.tracecompass
.ctf
.core
.event
.types
.SimpleDatatypeDefinition
;
39 import org
.eclipse
.tracecompass
.ctf
.core
.event
.types
.StructDeclaration
;
40 import org
.eclipse
.tracecompass
.ctf
.core
.event
.types
.StructDefinition
;
41 import org
.eclipse
.tracecompass
.ctf
.core
.event
.types
.VariantDefinition
;
42 import org
.eclipse
.tracecompass
.internal
.ctf
.core
.SafeMappedByteBuffer
;
43 import org
.eclipse
.tracecompass
.internal
.ctf
.core
.event
.EventDeclaration
;
44 import org
.eclipse
.tracecompass
.internal
.ctf
.core
.event
.types
.composite
.EventHeaderDefinition
;
47 * CTF trace packet reader. Reads the events of a packet of a trace file.
49 * @author Matthew Khouzam
50 * @author Simon Marchi
52 public class CTFStreamInputPacketReader
implements IDefinitionScope
, AutoCloseable
{
54 // ------------------------------------------------------------------------
56 // ------------------------------------------------------------------------
58 private static final int BITS_PER_BYTE
= Byte
.SIZE
;
60 private static final IDefinitionScope EVENT_HEADER_SCOPE
= new IDefinitionScope() {
63 public IDefinition
lookupDefinition(String lookupPath
) {
68 public ILexicalScope
getScopePath() {
73 /** BitBuffer used to read the trace file. */
75 private BitBuffer fBitBuffer
;
77 /** StreamInputReader that uses this StreamInputPacketReader. */
78 private final CTFStreamInputReader fStreamInputReader
;
80 /** Trace packet header. */
81 private final StructDeclaration fTracePacketHeaderDecl
;
83 /** Stream packet context definition. */
84 private final StructDeclaration fStreamPacketContextDecl
;
86 /** Stream event header definition. */
87 private final IDeclaration fStreamEventHeaderDecl
;
89 /** Stream event context definition. */
90 private final StructDeclaration fStreamEventContextDecl
;
92 private ICompositeDefinition fCurrentTracePacketHeaderDef
;
93 private ICompositeDefinition fCurrentStreamEventHeaderDef
;
94 private ICompositeDefinition fCurrentStreamPacketContextDef
;
95 /** Reference to the index entry of the current packet. */
96 private ICTFPacketDescriptor fCurrentPacket
= null;
99 * Last timestamp recorded.
101 * Needed to calculate the complete timestamp values for the events with
104 private long fLastTimestamp
= 0;
106 /** CPU id of current packet. */
107 private int fCurrentCpu
= 0;
109 private int fLostEventsInThisPacket
;
111 private boolean fHasLost
= false;
113 // ------------------------------------------------------------------------
115 // ------------------------------------------------------------------------
118 * Constructs a StreamInputPacketReader.
120 * @param streamInputReader
121 * The StreamInputReader to which this packet reader belongs to.
123 public CTFStreamInputPacketReader(CTFStreamInputReader streamInputReader
) {
124 fStreamInputReader
= streamInputReader
;
126 /* Set the BitBuffer's byte order. */
127 ByteBuffer allocateDirect
= ByteBuffer
.allocateDirect(0);
128 if (allocateDirect
== null) {
129 throw new IllegalStateException("Unable to allocate 0 bytes!"); //$NON-NLS-1$
131 fBitBuffer
= new BitBuffer(allocateDirect
);
133 final CTFStream currentStream
= streamInputReader
.getStreamInput().getStream();
134 fTracePacketHeaderDecl
= currentStream
.getTrace().getPacketHeader();
135 fStreamPacketContextDecl
= currentStream
.getPacketContextDecl();
136 fStreamEventHeaderDecl
= currentStream
.getEventHeaderDeclaration();
137 fStreamEventContextDecl
= currentStream
.getEventContextDecl();
141 * Get the event context defintiion
144 * the bitbuffer to read from
145 * @return an context definition, can be null
146 * @throws CTFException
147 * out of bounds exception or such
149 public StructDefinition
getEventContextDefinition(@NonNull BitBuffer input
) throws CTFException
{
150 return fStreamEventContextDecl
.createDefinition(fStreamInputReader
.getStreamInput(), ILexicalScope
.STREAM_EVENT_CONTEXT
, input
);
154 * Get the packet context defintiion
157 * the bitbuffer to read from
158 * @return an context definition, can be null
159 * @throws CTFException
160 * out of bounds exception or such
162 public StructDefinition
getStreamPacketContextDefinition(@NonNull BitBuffer input
) throws CTFException
{
163 return fStreamPacketContextDecl
.createDefinition(fStreamInputReader
.getStreamInput(), ILexicalScope
.STREAM_PACKET_CONTEXT
, input
);
167 * Get the event header defintiion
170 * the bitbuffer to read from
171 * @return an header definition, can be null
172 * @throws CTFException
173 * out of bounds exception or such
175 public StructDefinition
getTracePacketHeaderDefinition(@NonNull BitBuffer input
) throws CTFException
{
176 return fTracePacketHeaderDecl
.createDefinition(fStreamInputReader
.getStreamInput().getStream().getTrace(), ILexicalScope
.TRACE_PACKET_HEADER
, input
);
180 * Dispose the StreamInputPacketReader
183 public void close() {
187 // ------------------------------------------------------------------------
188 // Getters/Setters/Predicates
189 // ------------------------------------------------------------------------
192 * Gets the current packet
194 * @return the current packet
196 ICTFPacketDescriptor
getCurrentPacket() {
197 return fCurrentPacket
;
201 * Gets the CPU (core) number
203 * @return the CPU (core) number
205 public int getCPU() {
210 public LexicalScope
getScopePath() {
211 return ILexicalScope
.PACKET
;
214 // ------------------------------------------------------------------------
216 // ------------------------------------------------------------------------
219 private ByteBuffer
getByteBufferAt(long position
, long size
) throws CTFException
, IOException
{
220 ByteBuffer map
= SafeMappedByteBuffer
.map(fStreamInputReader
.getFc(), MapMode
.READ_ONLY
, position
, size
);
222 throw new CTFIOException("Failed to allocate mapped byte buffer"); //$NON-NLS-1$
228 * Changes the current packet to the given one.
230 * @param currentPacket
231 * The index entry of the packet to switch to.
232 * @throws CTFException
233 * If we get an error reading the packet
236 public void setCurrentPacket(ICTFPacketDescriptor currentPacket
) throws CTFException
{
237 fCurrentPacket
= currentPacket
;
239 if (fCurrentPacket
!= null) {
241 * Change the map of the BitBuffer.
243 ByteBuffer bb
= null;
245 bb
= getByteBufferAt(fCurrentPacket
.getOffsetBytes(), (fCurrentPacket
.getPacketSizeBits() + BITS_PER_BYTE
- 1) / BITS_PER_BYTE
);
246 } catch (IOException e
) {
247 throw new CTFIOException(e
.getMessage(), e
);
250 BitBuffer bitBuffer
= new BitBuffer(bb
);
251 fBitBuffer
= bitBuffer
;
253 * Read trace packet header.
255 if (fTracePacketHeaderDecl
!= null) {
256 fCurrentTracePacketHeaderDef
= getTracePacketHeaderDefinition(bitBuffer
);
260 * Read stream packet context.
262 if (fStreamPacketContextDecl
!= null) {
263 fCurrentStreamPacketContextDef
= getStreamPacketContextDefinition(bitBuffer
);
266 if (getCurrentPacket().getTarget() != null) {
267 fCurrentCpu
= (int) getCurrentPacket().getTargetId();
270 /* Read number of lost events */
271 fLostEventsInThisPacket
= (int) getCurrentPacket().getLostEvents();
272 if (fLostEventsInThisPacket
!= 0) {
278 * Use the timestamp begin of the packet as the reference for the
279 * timestamp reconstitution.
281 fLastTimestamp
= Math
.max(currentPacket
.getTimestampBegin(), 0);
289 * Returns whether it is possible to read any more events from this packet.
291 * @return True if it is possible to read any more events from this packet.
293 public boolean hasMoreEvents() {
294 BitBuffer bitBuffer
= fBitBuffer
;
295 ICTFPacketDescriptor currentPacket
= fCurrentPacket
;
296 if (currentPacket
!= null && bitBuffer
!= null) {
297 return fHasLost
|| (bitBuffer
.position() < currentPacket
.getContentSizeBits());
303 * Reads the next event of the packet into the right event definition.
305 * @return The event definition containing the event data that was just
307 * @throws CTFException
308 * If there was a problem reading the trace
310 public EventDefinition
readNextEvent() throws CTFException
{
311 /* Default values for those fields */
312 // compromise since we cannot have 64 bit addressing of arrays yet.
313 int eventID
= (int) IEventDeclaration
.UNSET_EVENT_ID
;
314 final BitBuffer currentBitBuffer
= fBitBuffer
;
315 final ICTFPacketDescriptor currentPacket
= fCurrentPacket
;
316 if (currentBitBuffer
== null || currentPacket
== null) {
319 final long posStart
= currentBitBuffer
.position();
321 * Return the Lost Event after all other events in this packet.
323 if (fHasLost
&& posStart
>= currentPacket
.getContentSizeBits()) {
325 IEventDeclaration lostEventDeclaration
= LostEventDeclaration
.INSTANCE
;
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 long lostEventsTimestamp
= fLastTimestamp
;
338 long lostEventsDuration
= currentPacket
.getTimestampEnd() - lostEventsTimestamp
;
339 IntegerDefinition lostDurationDef
= new IntegerDefinition(lostFieldsDecl
, null, CTFStrings
.LOST_EVENTS_DURATION
, lostEventsDuration
);
340 IntegerDefinition lostCountDef
= new IntegerDefinition(lostEventsDurationDecl
, null, CTFStrings
.LOST_EVENTS_FIELD
, fLostEventsInThisPacket
);
341 IntegerDefinition
[] fields
= new IntegerDefinition
[] { lostCountDef
, lostDurationDef
};
342 return new EventDefinition(
343 lostEventDeclaration
,
349 new StructDefinition(
351 this, "fields", //$NON-NLS-1$
357 /* Read the stream event header. */
358 if (fStreamEventHeaderDecl
!= null) {
359 if (fStreamEventHeaderDecl
instanceof IEventHeaderDeclaration
) {
360 fCurrentStreamEventHeaderDef
= (ICompositeDefinition
) fStreamEventHeaderDecl
.createDefinition(EVENT_HEADER_SCOPE
, "", currentBitBuffer
); //$NON-NLS-1$
361 EventHeaderDefinition ehd
= (EventHeaderDefinition
) fCurrentStreamEventHeaderDef
;
362 eventID
= ehd
.getId();
364 fCurrentStreamEventHeaderDef
= ((StructDeclaration
) fStreamEventHeaderDecl
).createDefinition(EVENT_HEADER_SCOPE
, ILexicalScope
.EVENT_HEADER
, currentBitBuffer
);
365 StructDefinition StructEventHeaderDef
= (StructDefinition
) fCurrentStreamEventHeaderDef
;
366 /* Check for the event id. */
367 IDefinition idDef
= StructEventHeaderDef
.lookupDefinition("id"); //$NON-NLS-1$
368 SimpleDatatypeDefinition simpleIdDef
= null;
369 if (idDef
instanceof SimpleDatatypeDefinition
) {
370 simpleIdDef
= ((SimpleDatatypeDefinition
) idDef
);
371 } else if (idDef
!= null) {
372 throw new CTFIOException("Id defintion not an integer, enum or float definiton in event header."); //$NON-NLS-1$
374 /* Check for the variant v. */
375 IDefinition variantDef
= StructEventHeaderDef
.lookupDefinition("v"); //$NON-NLS-1$
376 if (variantDef
instanceof VariantDefinition
) {
378 /* Get the variant current field */
379 StructDefinition variantCurrentField
= (StructDefinition
) ((VariantDefinition
) variantDef
).getCurrentField();
382 * Try to get the id field in the current field of the
383 * variant. If it is present, it overrides the previously
386 IDefinition vIdDef
= variantCurrentField
.lookupDefinition("id"); //$NON-NLS-1$
387 if (vIdDef
instanceof IntegerDefinition
) {
388 simpleIdDef
= (SimpleDatatypeDefinition
) vIdDef
;
392 if (simpleIdDef
!= null) {
393 eventID
= simpleIdDef
.getIntegerValue().intValue();
397 /* Get the right event definition using the event id. */
398 EventDeclaration eventDeclaration
= (EventDeclaration
) fStreamInputReader
.getStreamInput().getStream().getEventDeclaration(eventID
);
399 if (eventDeclaration
== null) {
400 throw new CTFIOException("Incorrect event id : " + eventID
); //$NON-NLS-1$
402 EventDefinition eventDef
= eventDeclaration
.createDefinition(fStreamInputReader
, fCurrentStreamEventHeaderDef
, currentBitBuffer
, fLastTimestamp
);
403 fLastTimestamp
= eventDef
.getTimestamp();
405 * Set the event timestamp using the timestamp calculated by
409 if (posStart
== currentBitBuffer
.position()) {
410 throw new CTFIOException("Empty event not allowed, event: " + eventDef
.getDeclaration().getName()); //$NON-NLS-1$
417 public Definition
lookupDefinition(String lookupPath
) {
418 if (lookupPath
.equals(ILexicalScope
.STREAM_PACKET_CONTEXT
.getPath())) {
419 return (Definition
) fCurrentStreamPacketContextDef
;
421 if (lookupPath
.equals(ILexicalScope
.TRACE_PACKET_HEADER
.getPath())) {
422 return (Definition
) fCurrentTracePacketHeaderDef
;
429 * Get stream event header
431 * @return the stream event header
433 public ICompositeDefinition
getStreamEventHeaderDefinition() {
434 return fCurrentStreamEventHeaderDef
;
438 * Get the current packet event header
440 * @return the current packet event header
442 public StructDefinition
getCurrentPacketEventHeader() {
443 if (fCurrentTracePacketHeaderDef
instanceof StructDefinition
) {
444 return (StructDefinition
) fCurrentTracePacketHeaderDef
;