1 /*******************************************************************************
2 * Copyright (c) 2011-2012 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
.MappedByteBuffer
;
16 import java
.nio
.channels
.FileChannel
.MapMode
;
17 import java
.util
.Collection
;
18 import java
.util
.HashMap
;
20 import org
.eclipse
.linuxtools
.ctf
.core
.event
.EventDeclaration
;
21 import org
.eclipse
.linuxtools
.ctf
.core
.event
.EventDefinition
;
22 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.Definition
;
23 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.IDefinitionScope
;
24 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.IntegerDefinition
;
25 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.SimpleDatatypeDefinition
;
26 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.StructDeclaration
;
27 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.StructDefinition
;
28 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.VariantDefinition
;
29 import org
.eclipse
.linuxtools
.internal
.ctf
.core
.event
.io
.BitBuffer
;
30 import org
.eclipse
.linuxtools
.internal
.ctf
.core
.trace
.Stream
;
31 import org
.eclipse
.linuxtools
.internal
.ctf
.core
.trace
.StreamInputPacketIndexEntry
;
34 * CTF trace packet reader. Reads the events of a packet of a trace file.
37 * @author Matthew Khouzam
38 * @author Simon Marchi
40 public class StreamInputPacketReader
implements IDefinitionScope
{
42 // ------------------------------------------------------------------------
44 // ------------------------------------------------------------------------
46 /** BitBuffer used to read the trace file. */
47 private final BitBuffer bitBuffer
;
49 /** StreamInputReader that uses this StreamInputPacketReader. */
50 private final StreamInputReader streamInputReader
;
52 /** Trace packet header. */
53 private final StructDefinition tracePacketHeaderDef
;
55 /** Stream packet context definition. */
56 private final StructDefinition streamPacketContextDef
;
58 /** Stream event header definition. */
59 private final StructDefinition streamEventHeaderDef
;
61 /** Stream event context definition.*/
62 private final StructDefinition streamEventContextDef
;
64 /** Maps event ID to event definitions. */
65 private final HashMap
<Long
, EventDefinition
> events
;
67 /** Reference to the index entry of the current packet. */
68 private StreamInputPacketIndexEntry currentPacket
= null;
71 * Last timestamp recorded.
73 * Needed to calculate the complete timestamp values for the events with
76 private long lastTimestamp
= 0;
78 /** CPU id of current packet. */
79 private int currentCpu
= 0;
81 /** number of lost events in this packet */
82 private int lostSoFar
;
84 private int lostEventsInThisPacket
;
86 // ------------------------------------------------------------------------
88 // ------------------------------------------------------------------------
91 * Constructs a StreamInputPacketReader.
93 * @param streamInputReader
94 * The StreamInputReader to which this packet reader belongs to.
96 public StreamInputPacketReader(StreamInputReader streamInputReader
) {
97 this.streamInputReader
= streamInputReader
;
99 /* Set the BitBuffer's byte order. */
100 bitBuffer
= new BitBuffer();
101 bitBuffer
.setByteOrder(streamInputReader
.getByteOrder());
103 events
= streamInputReader
.getStreamInput().getStream().getTrace().getEventDefs(streamInputReader
.getStreamInput());
106 /* Create trace packet header definition. */
107 final Stream currentStream
= streamInputReader
.getStreamInput().getStream();
108 StructDeclaration tracePacketHeaderDecl
= currentStream
.getTrace().getPacketHeader();
109 if (tracePacketHeaderDecl
!= null) {
110 tracePacketHeaderDef
= tracePacketHeaderDecl
.createDefinition(this, "trace.packet.header"); //$NON-NLS-1$
112 tracePacketHeaderDef
= null;
115 /* Create stream packet context definition. */
116 StructDeclaration streamPacketContextDecl
= currentStream
.getPacketContextDecl();
117 if (streamPacketContextDecl
!= null) {
118 streamPacketContextDef
= streamPacketContextDecl
.createDefinition(this, "stream.packet.context"); //$NON-NLS-1$
120 streamPacketContextDef
= null;
123 /* Create stream event header definition. */
124 StructDeclaration streamEventHeaderDecl
= currentStream
.getEventHeaderDecl();
125 if (streamEventHeaderDecl
!= null) {
126 streamEventHeaderDef
= streamEventHeaderDecl
.createDefinition(this, "stream.event.header"); //$NON-NLS-1$
128 streamEventHeaderDef
= null;
131 /* Create stream event context definition. */
132 StructDeclaration streamEventContextDecl
= currentStream
.getEventContextDecl();
133 if (streamEventContextDecl
!= null) {
134 streamEventContextDef
= streamEventContextDecl
.createDefinition(this, "stream.event.context"); //$NON-NLS-1$
136 streamEventContextDef
= null;
139 /* Create event definitions */
140 Collection
<EventDeclaration
> eventDecls
= streamInputReader
.getStreamInput().getStream().getEvents().values();
142 for (EventDeclaration event
: eventDecls
) {
143 if (!events
.containsKey(event
.getId())) {
144 EventDefinition eventDef
= event
.createDefinition(streamInputReader
);
145 events
.put(event
.getId(), eventDef
);
150 // ------------------------------------------------------------------------
151 // Getters/Setters/Predicates
152 // ------------------------------------------------------------------------
155 * Gets the current packet
157 * @return the current packet
159 public StreamInputPacketIndexEntry
getCurrentPacket() {
160 return this.currentPacket
;
164 * Gets the steamPacketContext Definition
166 * @return steamPacketContext Definition
168 public StructDefinition
getStreamPacketContextDef() {
169 return this.streamPacketContextDef
;
173 * Gets the CPU (core) number
175 * @return the CPU (core) number
177 public int getCPU() {
178 return this.currentCpu
;
182 public String
getPath() {
183 return ""; //$NON-NLS-1$
186 // ------------------------------------------------------------------------
188 // ------------------------------------------------------------------------
191 * Changes the current packet to the given one.
193 * @param currentPacket
194 * The index entry of the packet to switch to.
196 public void setCurrentPacket(StreamInputPacketIndexEntry currentPacket
) {
197 this.currentPacket
= currentPacket
;
199 if (this.currentPacket
!= null) {
201 * Change the map of the BitBuffer.
203 MappedByteBuffer bb
= null;
205 bb
= streamInputReader
.getStreamInput().getFileChannel()
206 .map(MapMode
.READ_ONLY
,
207 this.currentPacket
.getOffsetBytes(),
208 (this.currentPacket
.getPacketSizeBits() + 7) / 8);
209 } catch (IOException e
) {
211 * The streamInputReader object is already allocated, so this
212 * shouldn't fail bar some very bad kernel or RAM errors...
217 bitBuffer
.setByteBuffer(bb
);
220 * Read trace packet header.
222 if (tracePacketHeaderDef
!= null) {
223 tracePacketHeaderDef
.read(bitBuffer
);
227 * Read stream packet context.
229 if (getStreamPacketContextDef() != null) {
230 getStreamPacketContextDef().read(bitBuffer
);
233 if (this.getCurrentPacket().getTarget() != null) {
234 this.currentCpu
= (int) this.getCurrentPacket().getTargetId();
237 /* Read number of lost events */
238 lostEventsInThisPacket
= (int) this.getCurrentPacket().getLostEvents();
244 * Use the timestamp begin of the packet as the reference for the
245 * timestamp reconstitution.
247 lastTimestamp
= currentPacket
.getTimestampBegin();
249 bitBuffer
.setByteBuffer(null);
256 * Returns whether it is possible to read any more events from this packet.
258 * @return True if it is possible to read any more events from this packet.
260 public boolean hasMoreEvents() {
261 if (currentPacket
!= null) {
262 return bitBuffer
.position() < currentPacket
.getContentSizeBits();
268 * Reads the next event of the packet into the right event definition.
270 * @return The event definition containing the event data that was just
272 * @throws CTFReaderException
273 * If there was a problem reading the trace
275 public EventDefinition
readNextEvent() throws CTFReaderException
{
276 /* Default values for those fields */
280 if (lostEventsInThisPacket
> lostSoFar
) {
281 EventDefinition eventDef
= EventDeclaration
.getLostEventDeclaration().createDefinition(streamInputReader
);
282 eventDef
.setTimestamp(this.lastTimestamp
);
287 final StructDefinition sehd
= streamEventHeaderDef
;
288 final BitBuffer currentBitBuffer
= bitBuffer
;
290 /* Read the stream event header. */
292 sehd
.read(currentBitBuffer
);
294 /* Check for the event id. */
295 Definition idDef
= sehd
.lookupDefinition("id"); //$NON-NLS-1$
296 if (idDef
instanceof SimpleDatatypeDefinition
) {
297 eventID
= ((SimpleDatatypeDefinition
) idDef
).getIntegerValue();
298 } // else, eventID remains 0
300 /* Get the timestamp from the event header (may be overridden later on) */
301 Definition timestampDef
= sehd
.lookupInteger("timestamp"); //$NON-NLS-1$
302 if (timestampDef
instanceof IntegerDefinition
) {
303 timestamp
= calculateTimestamp((IntegerDefinition
) timestampDef
);
304 } // else timestamp remains 0
306 /* Check for the variant v. */
307 Definition variantDef
= sehd
.lookupDefinition("v"); //$NON-NLS-1$
308 if (variantDef
instanceof VariantDefinition
) {
310 /* Get the variant current field */
311 StructDefinition variantCurrentField
= (StructDefinition
) ((VariantDefinition
) variantDef
).getCurrentField();
314 * Try to get the id field in the current field of the variant.
315 * If it is present, it overrides the previously read event id.
317 Definition idIntegerDef
= variantCurrentField
.lookupDefinition("id"); //$NON-NLS-1$
318 if (idIntegerDef
instanceof IntegerDefinition
) {
319 eventID
= ((IntegerDefinition
) idIntegerDef
).getValue();
322 /* Get the timestamp. This would overwrite any previous timestamp definition */
323 timestampDef
= variantCurrentField
.lookupDefinition("timestamp"); //$NON-NLS-1$
324 if (timestampDef
instanceof IntegerDefinition
) {
325 timestamp
= calculateTimestamp((IntegerDefinition
) timestampDef
);
330 /* Read the stream event context. */
331 if (streamEventContextDef
!= null) {
332 streamEventContextDef
.read(currentBitBuffer
);
335 /* Get the right event definition using the event id. */
336 EventDefinition eventDef
= events
.get(eventID
);
337 if (eventDef
== null) {
338 throw new CTFReaderException("Incorrect event id : " + eventID
); //$NON-NLS-1$
341 /* Read the event context. */
342 if (eventDef
.getContext() != null) {
343 eventDef
.getContext().read(currentBitBuffer
);
346 /* Read the event fields. */
347 if (eventDef
.getFields() != null) {
348 eventDef
.getFields().read(currentBitBuffer
);
352 * Set the event timestamp using the timestamp calculated by
355 eventDef
.setTimestamp(timestamp
);
361 * Calculates the timestamp value of the event, possibly using the timestamp
362 * from the last event.
364 * @param timestampDef
365 * Integer definition of the timestamp.
366 * @return The calculated timestamp value.
368 private long calculateTimestamp(IntegerDefinition timestampDef
) {
371 int len
= timestampDef
.getDeclaration().getLength();
374 * If the timestamp length is 64 bits, it is a full timestamp.
376 if (timestampDef
.getDeclaration().getLength() == 64) {
377 lastTimestamp
= timestampDef
.getValue();
378 return lastTimestamp
;
382 * Bit mask to keep / remove all old / new bits.
384 majorasbitmask
= (1L << len
) - 1;
387 * If the new value is smaller than the corresponding bits of the last
388 * timestamp, we assume an overflow of the compact representation.
390 newval
= timestampDef
.getValue();
391 if (newval
< (lastTimestamp
& majorasbitmask
)) {
392 newval
= newval
+ (1L << len
);
395 /* Keep only the high bits of the old value */
396 lastTimestamp
= lastTimestamp
& ~majorasbitmask
;
398 /* Then add the low bits of the new value */
399 lastTimestamp
= lastTimestamp
+ newval
;
401 return lastTimestamp
;
405 public Definition
lookupDefinition(String lookupPath
) {
406 // TODO Auto-generated method stub