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 // ------------------------------------------------------------------------
47 * Reference to the index entry of the current packet.
49 private StreamInputPacketIndexEntry currentPacket
= null;
52 * BitBuffer used to read the trace file.
54 private final BitBuffer bitBuffer
= new BitBuffer();
57 * StreamInputReader that uses this StreamInputPacketReader.
59 private final StreamInputReader streamInputReader
;
62 * Last timestamp recorded.
64 * Needed to calculate the complete timestamp values for the events with
67 private long lastTimestamp
= 0;
70 * Trace packet header.
72 private StructDefinition tracePacketHeaderDef
= null;
75 * Stream packet context definition.
77 private StructDefinition streamPacketContextDef
= null;
80 * Stream event header definition.
82 private StructDefinition streamEventHeaderDef
= null;
85 * Stream event context definition.
87 private StructDefinition streamEventContextDef
= null;
90 * Maps event ID to event definitions.
92 private final HashMap
<Long
, EventDefinition
> events
;
95 * CPU id of current packet.
97 private int currentCpu
= 0;
100 * number of lost events in this packet
102 private int lostSoFar
;
104 private int lostEventsInThisPacket
;
106 // ------------------------------------------------------------------------
108 // ------------------------------------------------------------------------
111 * Constructs a StreamInputPacketReader.
113 * @param streamInputReader
114 * The StreamInputReader to which this packet reader belongs to.
116 public StreamInputPacketReader(StreamInputReader streamInputReader
) {
117 this.streamInputReader
= streamInputReader
;
120 * Set the BitBuffer's byte order.
122 getBitBuffer().setByteOrder(streamInputReader
.getByteOrder());
124 events
= streamInputReader
.getStreamInput().getStream().getTrace()
125 .getEventDefs(streamInputReader
.getStreamInput());
127 * Create definitions needed to read the events.
134 // ------------------------------------------------------------------------
136 // ------------------------------------------------------------------------
138 // ------------------------------------------------------------------------
139 // Getters/Setters/Predicates
140 // ------------------------------------------------------------------------
143 * Gets the current packet
145 * @return the current packet
147 public StreamInputPacketIndexEntry
getCurrentPacket() {
148 return this.currentPacket
;
152 * Gets the steamPacketContext Definition
154 * @return steamPacketContext Definition
156 public StructDefinition
getStreamPacketContextDef() {
157 return this.streamPacketContextDef
;
161 * Gets the CPU (core) number
163 * @return the CPU (core) number
165 public int getCPU() {
166 return this.currentCpu
;
170 public String
getPath() {
171 return ""; //$NON-NLS-1$
174 // ------------------------------------------------------------------------
176 // ------------------------------------------------------------------------
179 * Creates definitions needed to read events (stream-defined and
182 private void createDefinitions() {
184 * Create trace packet header definition.
186 final Stream currentStream
= getStreamInputReader().getStreamInput()
188 StructDeclaration tracePacketHeaderDecl
= currentStream
.getTrace()
190 if (tracePacketHeaderDecl
!= null) {
191 setTracePacketHeaderDef(tracePacketHeaderDecl
.createDefinition(
192 this, "trace.packet.header")); //$NON-NLS-1$
196 * Create stream packet context definition.
198 StructDeclaration streamPacketContextDecl
= currentStream
199 .getPacketContextDecl();
200 if (streamPacketContextDecl
!= null) {
201 setStreamPacketContextDef(streamPacketContextDecl
.createDefinition(
202 this, "stream.packet.context")); //$NON-NLS-1$
206 * Create stream event header definition.
208 StructDeclaration streamEventHeaderDecl
= currentStream
209 .getEventHeaderDecl();
210 if (streamEventHeaderDecl
!= null) {
211 setStreamEventHeaderDef(streamEventHeaderDecl
.createDefinition(
212 this, "stream.event.header")); //$NON-NLS-1$
216 * Create stream event context definition.
218 StructDeclaration streamEventContextDecl
= currentStream
219 .getEventContextDecl();
220 if (streamEventContextDecl
!= null) {
221 setStreamEventContextDef(streamEventContextDecl
.createDefinition(
222 this, "stream.event.context")); //$NON-NLS-1$
225 createEventDefinitions();
229 * Creates definitions needed to read the event. (event-defined).
231 private void createEventDefinitions() {
232 Collection
<EventDeclaration
> eventDecls
= getStreamInputReader()
233 .getStreamInput().getStream().getEvents().values();
236 * Create definitions for each event.
238 for (EventDeclaration event
: eventDecls
) {
239 if (!events
.containsKey(event
.getId())) {
240 EventDefinition eventDef
= event
241 .createDefinition(getStreamInputReader());
242 events
.put(event
.getId(), eventDef
);
248 * Changes the current packet to the given one.
250 * @param currentPacket
251 * The index entry of the packet to switch to.
253 public void setCurrentPacket(StreamInputPacketIndexEntry currentPacket
) {
254 this.currentPacket
= currentPacket
;
256 if (this.currentPacket
!= null) {
258 * Change the map of the BitBuffer.
260 MappedByteBuffer bb
= null;
262 bb
= getStreamInputReader()
265 .map(MapMode
.READ_ONLY
,
266 this.currentPacket
.getOffsetBytes(),
267 (this.currentPacket
.getPacketSizeBits() + 7) / 8);
268 } catch (IOException e
) {
270 * The streamInputReader object is already allocated, so this
271 * shouldn't fail bar some very bad kernel or RAM errors...
276 getBitBuffer().setByteBuffer(bb
);
279 * Read trace packet header.
281 if (getTracePacketHeaderDef() != null) {
282 getTracePacketHeaderDef().read(getBitBuffer());
286 * Read stream packet context.
288 if (getStreamPacketContextDef() != null) {
289 getStreamPacketContextDef().read(getBitBuffer());
292 if (this.getCurrentPacket().getTarget() != null) {
293 this.currentCpu
= (int) this.getCurrentPacket().getTargetId();
296 /* Read number of lost events */
297 lostEventsInThisPacket
= (int) this.getCurrentPacket().getLostEvents();
303 * Use the timestamp begin of the packet as the reference for the
304 * timestamp reconstitution.
306 lastTimestamp
= currentPacket
.getTimestampBegin();
308 getBitBuffer().setByteBuffer(null);
315 * Returns whether it is possible to read any more events from this packet.
317 * @return True if it is possible to read any more events from this packet.
319 public boolean hasMoreEvents() {
320 if (currentPacket
!= null) {
321 return getBitBuffer().position() < currentPacket
322 .getContentSizeBits();
328 * Reads the next event of the packet into the right event definition.
330 * @return The event definition containing the event data that was just
332 * @throws CTFReaderException
333 * If there was a problem reading the trace
335 public EventDefinition
readNextEvent() throws CTFReaderException
{
336 /* WARNING: This is still LTTng-specific. */
340 if (lostEventsInThisPacket
> lostSoFar
) {
341 EventDefinition eventDef
= EventDeclaration
342 .getLostEventDeclaration().createDefinition(
344 eventDef
.setTimestamp(this.lastTimestamp
);
349 StructDefinition sehd
= getStreamEventHeaderDef(); // acronym for a long
351 BitBuffer currentBitBuffer
= getBitBuffer();
353 * Read the stream event header.
357 sehd
.read(currentBitBuffer
);
360 * Check for an event id.
362 SimpleDatatypeDefinition idDef
= (SimpleDatatypeDefinition
) sehd
363 .lookupDefinition("id"); //$NON-NLS-1$
364 IntegerDefinition timestampDef
= sehd
.lookupInteger("timestamp"); //$NON-NLS-1$
365 eventID
= idDef
.getIntegerValue();
368 * Check for the variant v.
370 VariantDefinition variantDef
= (VariantDefinition
) sehd
371 .lookupDefinition("v"); //$NON-NLS-1$
372 if (variantDef
!= null) {
375 * Get the variant current field
377 StructDefinition variantCurrentField
= (StructDefinition
) variantDef
381 * Try to get the id field in the current field of the variant.
382 * If it is present, it overrides the previously read event id.
384 IntegerDefinition idIntegerDef
= (IntegerDefinition
) variantCurrentField
385 .lookupDefinition("id"); //$NON-NLS-1$
386 if (idIntegerDef
!= null) {
387 eventID
= idIntegerDef
.getValue();
392 timestampDef
= (IntegerDefinition
) variantCurrentField
393 .lookupDefinition("timestamp"); //$NON-NLS-1$
398 * Calculate the event timestamp.
400 timestamp
= calculateTimestamp(timestampDef
);
404 * Read the stream event context.
406 if (getStreamEventContextDef() != null) {
407 getStreamEventContextDef().read(currentBitBuffer
);
411 * Get the right event definition using the event id.
413 EventDefinition eventDef
= events
.get(eventID
);
414 if (eventDef
== null) {
415 throw new CTFReaderException("Incorrect event id : " + eventID
); //$NON-NLS-1$
419 * Read the event context.
421 if (eventDef
.getContext() != null) {
422 eventDef
.getContext().read(currentBitBuffer
);
426 * Read the event fields.
428 if (eventDef
.getFields() != null) {
429 eventDef
.getFields().read(currentBitBuffer
);
433 * Set the event timestamp using the timestamp calculated by
436 eventDef
.setTimestamp(timestamp
);
442 * Calculates the timestamp value of the event, possibly using the timestamp
443 * from the last event.
445 * @param timestampDef
446 * Integer definition of the timestamp.
447 * @return The calculated timestamp value.
449 private long calculateTimestamp(IntegerDefinition timestampDef
) {
452 int len
= timestampDef
.getDeclaration().getLength();
455 * If the timestamp length is 64 bits, it is a full timestamp.
457 if (timestampDef
.getDeclaration().getLength() == 64) {
458 lastTimestamp
= timestampDef
.getValue();
459 return lastTimestamp
;
463 * Bit mask to keep / remove all old / new bits.
465 majorasbitmask
= (1L << len
) - 1;
468 * If the new value is smaller than the corresponding bits of the last
469 * timestamp, we assume an overflow of the compact representation.
471 newval
= timestampDef
.getValue();
472 if (newval
< (lastTimestamp
& majorasbitmask
)) {
473 newval
= newval
+ (1L << len
);
476 /* Keep only the high bits of the old value */
477 lastTimestamp
= lastTimestamp
& ~majorasbitmask
;
479 /* Then add the low bits of the new value */
480 lastTimestamp
= lastTimestamp
+ newval
;
482 return lastTimestamp
;
486 public Definition
lookupDefinition(String lookupPath
) {
487 // TODO Auto-generated method stub
492 * Gets the stream event context definition (see CTF specs)
494 * @return the definition of the stream event context (the form not the
497 public StructDefinition
getStreamEventContextDef() {
498 return this.streamEventContextDef
;
502 * Sets the stream event context definition
504 * @param streamEventContextDef
505 * The stream event context definition
507 public void setStreamEventContextDef(StructDefinition streamEventContextDef
) {
508 this.streamEventContextDef
= streamEventContextDef
;
512 * Gets the stream event header definition
514 * @return the stream event header definition
516 public StructDefinition
getStreamEventHeaderDef() {
517 return this.streamEventHeaderDef
;
521 * Sets the stream event header definition
523 * @param streamEventHeaderDef
524 * the stream event header definition
526 public void setStreamEventHeaderDef(StructDefinition streamEventHeaderDef
) {
527 this.streamEventHeaderDef
= streamEventHeaderDef
;
531 * Sets the stream packet context definition
533 * @param streamPacketContextDef
534 * the stream packet context definition
536 public void setStreamPacketContextDef(
537 StructDefinition streamPacketContextDef
) {
538 this.streamPacketContextDef
= streamPacketContextDef
;
542 * Gets the trace packet header definition
544 * @return the trace packet header definition
546 public StructDefinition
getTracePacketHeaderDef() {
547 return this.tracePacketHeaderDef
;
551 * Sets the trace packet header definition
553 * @param tracePacketHeaderDef
554 * the trace packet header definition
556 public void setTracePacketHeaderDef(StructDefinition tracePacketHeaderDef
) {
557 this.tracePacketHeaderDef
= tracePacketHeaderDef
;
561 * @return the parent stream input reader
563 public StreamInputReader
getStreamInputReader() {
564 return this.streamInputReader
;
569 * @return THe bit buffer that reads the file.
571 public BitBuffer
getBitBuffer() {