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
;
240 if (fCurrentPacket
!= null) {
242 * Change the map of the BitBuffer.
244 ByteBuffer bb
= null;
246 bb
= getByteBufferAt(fCurrentPacket
.getOffsetBytes(), (fCurrentPacket
.getPacketSizeBits() + BITS_PER_BYTE
- 1) / BITS_PER_BYTE
);
247 } catch (IOException e
) {
248 throw new CTFIOException(e
.getMessage(), e
);
251 BitBuffer bitBuffer
= new BitBuffer(bb
);
252 fBitBuffer
= bitBuffer
;
254 * Read trace packet header.
256 if (fTracePacketHeaderDecl
!= null) {
257 fCurrentTracePacketHeaderDef
= getTracePacketHeaderDefinition(bitBuffer
);
261 * Read stream packet context.
263 if (fStreamPacketContextDecl
!= null) {
264 fCurrentStreamPacketContextDef
= getStreamPacketContextDefinition(bitBuffer
);
267 if (getCurrentPacket().getTarget() != null) {
268 fCurrentCpu
= (int) getCurrentPacket().getTargetId();
271 /* Read number of lost events */
272 fLostEventsInThisPacket
= (int) getCurrentPacket().getLostEvents();
273 if (fLostEventsInThisPacket
!= 0) {
279 * Use the timestamp begin of the packet as the reference for the
280 * timestamp reconstitution.
282 fLastTimestamp
= Math
.max(currentPacket
.getTimestampBegin(), 0);
290 * Returns whether it is possible to read any more events from this packet.
292 * @return True if it is possible to read any more events from this packet.
294 public boolean hasMoreEvents() {
295 BitBuffer bitBuffer
= fBitBuffer
;
296 ICTFPacketDescriptor currentPacket
= fCurrentPacket
;
297 if (currentPacket
!= null && bitBuffer
!= null) {
298 return fHasLost
|| (bitBuffer
.position() < currentPacket
.getContentSizeBits());
304 * Reads the next event of the packet into the right event definition.
306 * @return The event definition containing the event data that was just
308 * @throws CTFException
309 * If there was a problem reading the trace
311 public EventDefinition
readNextEvent() throws CTFException
{
312 /* Default values for those fields */
313 // compromise since we cannot have 64 bit addressing of arrays yet.
314 int eventID
= (int) IEventDeclaration
.UNSET_EVENT_ID
;
315 final BitBuffer currentBitBuffer
= fBitBuffer
;
316 final ICTFPacketDescriptor currentPacket
= fCurrentPacket
;
317 if (currentBitBuffer
== null || currentPacket
== null) {
320 final long posStart
= currentBitBuffer
.position();
322 * Return the Lost Event after all other events in this packet.
324 if (fHasLost
&& posStart
>= currentPacket
.getContentSizeBits()) {
326 IEventDeclaration lostEventDeclaration
= LostEventDeclaration
.INSTANCE
;
327 StructDeclaration lostFields
= lostEventDeclaration
.getFields();
328 // this is a hard coded map, we know it's not null
329 IntegerDeclaration lostFieldsDecl
= (IntegerDeclaration
) lostFields
.getField(CTFStrings
.LOST_EVENTS_FIELD
);
330 if (lostFieldsDecl
== null)
332 throw new IllegalStateException("Lost events count not declared!"); //$NON-NLS-1$
334 IntegerDeclaration lostEventsDurationDecl
= (IntegerDeclaration
) lostFields
.getField(CTFStrings
.LOST_EVENTS_DURATION
);
335 if (lostEventsDurationDecl
== null) {
336 throw new IllegalStateException("Lost events duration not declared!"); //$NON-NLS-1$
338 long lostEventsTimestamp
= fLastTimestamp
;
339 long lostEventsDuration
= currentPacket
.getTimestampEnd() - lostEventsTimestamp
;
340 IntegerDefinition lostDurationDef
= new IntegerDefinition(lostFieldsDecl
, null, CTFStrings
.LOST_EVENTS_DURATION
, lostEventsDuration
);
341 IntegerDefinition lostCountDef
= new IntegerDefinition(lostEventsDurationDecl
, null, CTFStrings
.LOST_EVENTS_FIELD
, fLostEventsInThisPacket
);
342 IntegerDefinition
[] fields
= new IntegerDefinition
[] { lostCountDef
, lostDurationDef
};
343 return new EventDefinition(
344 lostEventDeclaration
,
350 new StructDefinition(
352 this, "fields", //$NON-NLS-1$
358 /* Read the stream event header. */
359 if (fStreamEventHeaderDecl
!= null) {
360 if (fStreamEventHeaderDecl
instanceof IEventHeaderDeclaration
) {
361 fCurrentStreamEventHeaderDef
= (ICompositeDefinition
) fStreamEventHeaderDecl
.createDefinition(EVENT_HEADER_SCOPE
, "", currentBitBuffer
); //$NON-NLS-1$
362 EventHeaderDefinition ehd
= (EventHeaderDefinition
) fCurrentStreamEventHeaderDef
;
363 eventID
= ehd
.getId();
365 fCurrentStreamEventHeaderDef
= ((StructDeclaration
) fStreamEventHeaderDecl
).createDefinition(EVENT_HEADER_SCOPE
, ILexicalScope
.EVENT_HEADER
, currentBitBuffer
);
366 StructDefinition StructEventHeaderDef
= (StructDefinition
) fCurrentStreamEventHeaderDef
;
367 /* Check for the event id. */
368 IDefinition idDef
= StructEventHeaderDef
.lookupDefinition("id"); //$NON-NLS-1$
369 SimpleDatatypeDefinition simpleIdDef
= null;
370 if (idDef
instanceof SimpleDatatypeDefinition
) {
371 simpleIdDef
= ((SimpleDatatypeDefinition
) idDef
);
372 } else if (idDef
!= null) {
373 throw new CTFIOException("Id defintion not an integer, enum or float definiton in event header."); //$NON-NLS-1$
375 /* Check for the variant v. */
376 IDefinition variantDef
= StructEventHeaderDef
.lookupDefinition("v"); //$NON-NLS-1$
377 if (variantDef
instanceof VariantDefinition
) {
379 /* Get the variant current field */
380 StructDefinition variantCurrentField
= (StructDefinition
) ((VariantDefinition
) variantDef
).getCurrentField();
383 * Try to get the id field in the current field of the
384 * variant. If it is present, it overrides the previously
387 IDefinition vIdDef
= variantCurrentField
.lookupDefinition("id"); //$NON-NLS-1$
388 if (vIdDef
instanceof IntegerDefinition
) {
389 simpleIdDef
= (SimpleDatatypeDefinition
) vIdDef
;
393 if (simpleIdDef
!= null) {
394 eventID
= simpleIdDef
.getIntegerValue().intValue();
398 /* Get the right event definition using the event id. */
399 EventDeclaration eventDeclaration
= (EventDeclaration
) fStreamInputReader
.getStreamInput().getStream().getEventDeclaration(eventID
);
400 if (eventDeclaration
== null) {
401 throw new CTFIOException("Incorrect event id : " + eventID
); //$NON-NLS-1$
403 EventDefinition eventDef
= eventDeclaration
.createDefinition(fStreamInputReader
, fCurrentStreamEventHeaderDef
, currentBitBuffer
, fLastTimestamp
);
404 fLastTimestamp
= eventDef
.getTimestamp();
406 * Set the event timestamp using the timestamp calculated by
410 if (posStart
== currentBitBuffer
.position()) {
411 throw new CTFIOException("Empty event not allowed, event: " + eventDef
.getDeclaration().getName()); //$NON-NLS-1$
418 public Definition
lookupDefinition(String lookupPath
) {
419 if (lookupPath
.equals(ILexicalScope
.STREAM_PACKET_CONTEXT
.getPath())) {
420 return (Definition
) fCurrentStreamPacketContextDef
;
422 if (lookupPath
.equals(ILexicalScope
.TRACE_PACKET_HEADER
.getPath())) {
423 return (Definition
) fCurrentTracePacketHeaderDef
;
430 * Get stream event header
432 * @return the stream event header
434 public ICompositeDefinition
getStreamEventHeaderDefinition() {
435 return fCurrentStreamEventHeaderDef
;
439 * Get the current packet event header
441 * @return the current packet event header
443 public StructDefinition
getCurrentPacketEventHeader() {
444 if (fCurrentTracePacketHeaderDef
instanceof StructDefinition
) {
445 return (StructDefinition
) fCurrentTracePacketHeaderDef
;