1 /*******************************************************************************
2 * Copyright (c) 2011-2013 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
;
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
.types
.Definition
;
24 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.IDefinitionScope
;
25 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.IntegerDefinition
;
26 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.SimpleDatatypeDefinition
;
27 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.StructDeclaration
;
28 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.StructDefinition
;
29 import org
.eclipse
.linuxtools
.ctf
.core
.event
.types
.VariantDefinition
;
30 import org
.eclipse
.linuxtools
.internal
.ctf
.core
.event
.EventDeclaration
;
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 /** Reference to the index entry of the current packet. */
65 private StreamInputPacketIndexEntry currentPacket
= null;
68 * Last timestamp recorded.
70 * Needed to calculate the complete timestamp values for the events with
73 private long lastTimestamp
= 0;
75 /** CPU id of current packet. */
76 private int currentCpu
= 0;
78 private int lostEventsInThisPacket
;
80 private long lostEventsDuration
;
82 private boolean hasLost
= false;
84 // ------------------------------------------------------------------------
86 // ------------------------------------------------------------------------
89 * Constructs a StreamInputPacketReader.
91 * @param streamInputReader
92 * The StreamInputReader to which this packet reader belongs to.
94 public StreamInputPacketReader(StreamInputReader streamInputReader
) {
95 this.streamInputReader
= streamInputReader
;
97 /* Set the BitBuffer's byte order. */
98 bitBuffer
= new BitBuffer();
99 bitBuffer
.setByteOrder(streamInputReader
.getByteOrder());
101 /* Create trace packet header definition. */
102 final Stream currentStream
= streamInputReader
.getStreamInput().getStream();
103 StructDeclaration tracePacketHeaderDecl
= currentStream
.getTrace().getPacketHeader();
104 if (tracePacketHeaderDecl
!= null) {
105 tracePacketHeaderDef
= tracePacketHeaderDecl
.createDefinition(this, "trace.packet.header"); //$NON-NLS-1$
107 tracePacketHeaderDef
= null;
110 /* Create stream packet context definition. */
111 StructDeclaration streamPacketContextDecl
= currentStream
.getPacketContextDecl();
112 if (streamPacketContextDecl
!= null) {
113 streamPacketContextDef
= streamPacketContextDecl
.createDefinition(this, "stream.packet.context"); //$NON-NLS-1$
115 streamPacketContextDef
= null;
118 /* Create stream event header definition. */
119 StructDeclaration streamEventHeaderDecl
= currentStream
.getEventHeaderDecl();
120 if (streamEventHeaderDecl
!= null) {
121 streamEventHeaderDef
= streamEventHeaderDecl
.createDefinition(this, "stream.event.header"); //$NON-NLS-1$
123 streamEventHeaderDef
= null;
126 /* Create stream event context definition. */
127 StructDeclaration streamEventContextDecl
= currentStream
.getEventContextDecl();
128 if (streamEventContextDecl
!= null) {
129 streamEventContextDef
= streamEventContextDecl
.createDefinition(this, "stream.event.context"); //$NON-NLS-1$
131 streamEventContextDef
= null;
134 /* Create event definitions */
135 Collection
<IEventDeclaration
> eventDecls
= streamInputReader
.getStreamInput().getStream().getEvents().values();
137 for (IEventDeclaration event
: eventDecls
) {
138 if (!streamInputReader
.getEventDefinitions().containsKey(event
.getId())) {
139 EventDefinition eventDef
= event
.createDefinition(streamInputReader
);
140 streamInputReader
.addEventDefinition(event
.getId(), eventDef
);
146 * Dispose the StreamInputPacketReader
150 public void dispose() {
151 bitBuffer
.setByteBuffer(null);
154 // ------------------------------------------------------------------------
155 // Getters/Setters/Predicates
156 // ------------------------------------------------------------------------
159 * Gets the current packet
161 * @return the current packet
163 StreamInputPacketIndexEntry
getCurrentPacket() {
164 return this.currentPacket
;
168 * Gets the steamPacketContext Definition
170 * @return steamPacketContext Definition
172 public StructDefinition
getStreamPacketContextDef() {
173 return this.streamPacketContextDef
;
177 * Gets the stream's event context definition.
179 * @return The streamEventContext definition
181 public StructDefinition
getStreamEventContextDef() {
182 return streamEventContextDef
;
186 * Gets the CPU (core) number
188 * @return the CPU (core) number
190 public int getCPU() {
191 return this.currentCpu
;
195 public String
getPath() {
196 return ""; //$NON-NLS-1$
199 // ------------------------------------------------------------------------
201 // ------------------------------------------------------------------------
204 * Changes the current packet to the given one.
206 * @param currentPacket
207 * The index entry of the packet to switch to.
208 * @throws CTFReaderException
209 * If we get an error reading the packet
211 void setCurrentPacket(StreamInputPacketIndexEntry currentPacket
) throws CTFReaderException
{
212 StreamInputPacketIndexEntry prevPacket
= null;
213 this.currentPacket
= currentPacket
;
215 if (this.currentPacket
!= null) {
217 * Change the map of the BitBuffer.
219 MappedByteBuffer bb
= null;
221 bb
= streamInputReader
.getStreamInput().getFileChannel()
222 .map(MapMode
.READ_ONLY
,
223 this.currentPacket
.getOffsetBytes(),
224 (this.currentPacket
.getPacketSizeBits() + 7) / 8);
225 } catch (IOException e
) {
227 * The streamInputReader object is already allocated, so this
228 * shouldn't fail bar some very bad kernel or RAM errors...
233 bitBuffer
.setByteBuffer(bb
);
236 * Read trace packet header.
238 if (tracePacketHeaderDef
!= null) {
239 tracePacketHeaderDef
.read(bitBuffer
);
243 * Read stream packet context.
245 if (getStreamPacketContextDef() != null) {
246 getStreamPacketContextDef().read(bitBuffer
);
249 if (this.getCurrentPacket().getTarget() != null) {
250 this.currentCpu
= (int) this.getCurrentPacket().getTargetId();
253 /* Read number of lost events */
254 lostEventsInThisPacket
= (int) this.getCurrentPacket().getLostEvents();
255 if (lostEventsInThisPacket
!= 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
= this.streamInputReader
.getStreamInput().getIndex().getEntries().indexOf(currentPacket
);
265 lostEventsStartTime
= currentPacket
.getTimestampBegin() + 1;
267 prevPacket
= this.streamInputReader
.getStreamInput().getIndex().getEntries().get(index
- 1);
268 lostEventsStartTime
= prevPacket
.getTimestampEnd();
270 lostEventsDuration
= Math
.abs(lostEventsStartTime
- currentPacket
.getTimestampBegin());
275 * Use the timestamp begin of the packet as the reference for the
276 * timestamp reconstitution.
278 lastTimestamp
= currentPacket
.getTimestampBegin();
280 bitBuffer
.setByteBuffer(null);
287 * Returns whether it is possible to read any more events from this packet.
289 * @return True if it is possible to read any more events from this packet.
291 public boolean hasMoreEvents() {
292 if (currentPacket
!= null) {
293 return hasLost
|| (bitBuffer
.position() < currentPacket
.getContentSizeBits());
299 * Reads the next event of the packet into the right event definition.
301 * @return The event definition containing the event data that was just
303 * @throws CTFReaderException
304 * If there was a problem reading the trace
306 public EventDefinition
readNextEvent() throws CTFReaderException
{
307 /* Default values for those fields */
308 long eventID
= EventDeclaration
.UNSET_EVENT_ID
;
312 EventDefinition eventDef
= EventDeclaration
.getLostEventDeclaration().createDefinition(streamInputReader
);
313 ((IntegerDefinition
) eventDef
.getFields().getDefinitions().get(CTFStrings
.LOST_EVENTS_FIELD
)).setValue(lostEventsInThisPacket
);
314 ((IntegerDefinition
) eventDef
.getFields().getDefinitions().get(CTFStrings
.LOST_EVENTS_DURATION
)).setValue(lostEventsDuration
);
315 eventDef
.setTimestamp(this.lastTimestamp
);
319 final StructDefinition sehd
= streamEventHeaderDef
;
320 final BitBuffer currentBitBuffer
= bitBuffer
;
322 /* Read the stream event header. */
324 sehd
.read(currentBitBuffer
);
326 /* Check for the event id. */
327 Definition idDef
= sehd
.lookupDefinition("id"); //$NON-NLS-1$
328 if (idDef
instanceof SimpleDatatypeDefinition
) {
329 eventID
= ((SimpleDatatypeDefinition
) idDef
).getIntegerValue();
330 } // else, eventID remains 0
333 * Get the timestamp from the event header (may be overridden later
336 IntegerDefinition timestampDef
= sehd
.lookupInteger("timestamp"); //$NON-NLS-1$
337 if (timestampDef
!= null) {
338 timestamp
= calculateTimestamp(timestampDef
);
339 } // else timestamp remains 0
341 /* Check for the variant v. */
342 Definition variantDef
= sehd
.lookupDefinition("v"); //$NON-NLS-1$
343 if (variantDef
instanceof VariantDefinition
) {
345 /* Get the variant current field */
346 StructDefinition variantCurrentField
= (StructDefinition
) ((VariantDefinition
) variantDef
).getCurrentField();
349 * Try to get the id field in the current field of the variant.
350 * If it is present, it overrides the previously read event id.
352 Definition idIntegerDef
= variantCurrentField
.lookupDefinition("id"); //$NON-NLS-1$
353 if (idIntegerDef
instanceof IntegerDefinition
) {
354 eventID
= ((IntegerDefinition
) idIntegerDef
).getValue();
358 * Get the timestamp. This would overwrite any previous
359 * timestamp definition
361 Definition def
= variantCurrentField
.lookupDefinition("timestamp"); //$NON-NLS-1$
362 if (def
instanceof IntegerDefinition
) {
363 timestamp
= calculateTimestamp((IntegerDefinition
) def
);
368 /* Read the stream event context. */
369 if (streamEventContextDef
!= null) {
370 streamEventContextDef
.read(currentBitBuffer
);
373 /* Get the right event definition using the event id. */
374 EventDefinition eventDef
= streamInputReader
.getEventDefinitions().get(eventID
);
375 if (eventDef
== null) {
376 throw new CTFReaderException("Incorrect event id : " + eventID
); //$NON-NLS-1$
379 /* Read the event context. */
380 if (eventDef
.getEventContext() != null) {
381 eventDef
.getEventContext().read(currentBitBuffer
);
384 /* Read the event fields. */
385 if (eventDef
.getFields() != null) {
386 eventDef
.getFields().read(currentBitBuffer
);
390 * Set the event timestamp using the timestamp calculated by
393 eventDef
.setTimestamp(timestamp
);
399 * Calculates the timestamp value of the event, possibly using the timestamp
400 * from the last event.
402 * @param timestampDef
403 * Integer definition of the timestamp.
404 * @return The calculated timestamp value.
406 private long calculateTimestamp(IntegerDefinition timestampDef
) {
409 int len
= timestampDef
.getDeclaration().getLength();
412 * If the timestamp length is 64 bits, it is a full timestamp.
414 if (timestampDef
.getDeclaration().getLength() == 64) {
415 lastTimestamp
= timestampDef
.getValue();
416 return lastTimestamp
;
420 * Bit mask to keep / remove all old / new bits.
422 majorasbitmask
= (1L << len
) - 1;
425 * If the new value is smaller than the corresponding bits of the last
426 * timestamp, we assume an overflow of the compact representation.
428 newval
= timestampDef
.getValue();
429 if (newval
< (lastTimestamp
& majorasbitmask
)) {
430 newval
= newval
+ (1L << len
);
433 /* Keep only the high bits of the old value */
434 lastTimestamp
= lastTimestamp
& ~majorasbitmask
;
436 /* Then add the low bits of the new value */
437 lastTimestamp
= lastTimestamp
+ newval
;
439 return lastTimestamp
;
443 public Definition
lookupDefinition(String lookupPath
) {