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.EnumDefinition;
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.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 lostEvents;
104
private int lostSoFar;
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.
135
// ------------------------------------------------------------------------
137
// ------------------------------------------------------------------------
139
// ------------------------------------------------------------------------
140
// Getters/Setters/Predicates
141
// ------------------------------------------------------------------------
144
* Gets the current packet
146
* @return the current packet
148
public StreamInputPacketIndexEntry getCurrentPacket() {
149
return this.currentPacket;
153
* Gets the steamPacketContext Definition
155
* @return steamPacketContext Definition
157
public StructDefinition getStreamPacketContextDef() {
158
return this.streamPacketContextDef;
162
* Gets the CPU (core) number
164
* @return the CPU (core) number
166
public int getCPU() {
167
return this.currentCpu;
171
public String getPath() {
172
return ""; //$NON-NLS-1$
175
// ------------------------------------------------------------------------
177
// ------------------------------------------------------------------------
180
* Creates definitions needed to read events (stream-defined and
183
private void createDefinitions() {
185
* Create trace packet header definition.
187
final Stream currentStream = getStreamInputReader().getStreamInput()
189
StructDeclaration tracePacketHeaderDecl = currentStream.getTrace()
191
if (tracePacketHeaderDecl != null) {
192
setTracePacketHeaderDef(tracePacketHeaderDecl.createDefinition(
193
this, "trace.packet.header")); //$NON-NLS-1$
197
* Create stream packet context definition.
199
StructDeclaration streamPacketContextDecl = currentStream
200
.getPacketContextDecl();
201
if (streamPacketContextDecl != null) {
202
setStreamPacketContextDef(streamPacketContextDecl.createDefinition(
203
this, "stream.packet.context")); //$NON-NLS-1$
207
* Create stream event header definition.
209
StructDeclaration streamEventHeaderDecl = currentStream
210
.getEventHeaderDecl();
211
if (streamEventHeaderDecl != null) {
212
setStreamEventHeaderDef(streamEventHeaderDecl.createDefinition(
213
this, "stream.event.header")); //$NON-NLS-1$
217
* Create stream event context definition.
219
StructDeclaration streamEventContextDecl = currentStream
220
.getEventContextDecl();
221
if (streamEventContextDecl != null) {
222
setStreamEventContextDef(streamEventContextDecl.createDefinition(
223
this, "stream.event.context")); //$NON-NLS-1$
226
createEventDefinitions();
230
* Creates definitions needed to read the event. (event-defined).
232
private void createEventDefinitions() {
233
Collection<EventDeclaration> eventDecls = getStreamInputReader()
234
.getStreamInput().getStream().getEvents().values();
237
* Create definitions for each event.
239
for (EventDeclaration event : eventDecls) {
240
if (!events.containsKey(event.getId())) {
241
EventDefinition eventDef = event
242
.createDefinition(getStreamInputReader());
243
events.put(event.getId(), eventDef);
249
* Changes the current packet to the given one.
251
* @param currentPacket
252
* The index entry of the packet to switch to.
254
public void setCurrentPacket(StreamInputPacketIndexEntry currentPacket) {
255
this.currentPacket = currentPacket;
257
if (this.currentPacket != null) {
259
* Change the map of the BitBuffer.
261
MappedByteBuffer bb = null;
263
bb = getStreamInputReader()
266
.map(MapMode.READ_ONLY,
267
this.currentPacket.getOffsetBytes(),
268
(this.currentPacket.getPacketSizeBits() + 7) / 8);
269
} catch (IOException e) {
271
* The streamInputReader object is already allocated, so this
272
* shouldn't fail bar some very bad kernel or RAM errors...
277
getBitBuffer().setByteBuffer(bb);
280
* Read trace packet header.
282
if (getTracePacketHeaderDef() != null) {
283
getTracePacketHeaderDef().read(getBitBuffer());
287
* Read stream packet context.
289
if (getStreamPacketContextDef() != null) {
290
getStreamPacketContextDef().read(getBitBuffer());
295
Definition cpuiddef = getStreamPacketContextDef()
296
.lookupDefinition("cpu_id"); //$NON-NLS-1$
297
if (cpuiddef instanceof IntegerDefinition) {
298
currentCpu = (int) ((IntegerDefinition) cpuiddef)
302
* Read number of lost events
304
Definition lostEventsdef = getStreamPacketContextDef()
305
.lookupDefinition("events_discarded"); //$NON-NLS-1$
306
if (cpuiddef instanceof IntegerDefinition) {
307
lostEvents = (int) ((IntegerDefinition) lostEventsdef)
314
* Use the timestamp begin of the packet as the reference for the
315
* timestamp reconstitution.
317
lastTimestamp = currentPacket.getTimestampBegin();
319
getBitBuffer().setByteBuffer(null);
326
* Returns whether it is possible to read any more events from this packet.
328
* @return True if it is possible to read any more events from this packet.
330
public boolean hasMoreEvents() {
331
if (currentPacket != null) {
332
return getBitBuffer().position() < currentPacket
333
.getContentSizeBits();
339
* Reads the next event of the packet into the right event definition.
341
* @return The event definition containing the event data that was just
343
* @throws CTFReaderException
344
* If there was a problem reading the trace
346
public EventDefinition readNextEvent() throws CTFReaderException {
347
/* WARNING: This is very LTTng-specific. */
351
if (lostEvents > lostSoFar) {
352
EventDefinition eventDef = EventDeclaration
353
.getLostEventDeclaration().createDefinition(
355
eventDef.setTimestamp(this.lastTimestamp);
359
StructDefinition sehd = getStreamEventHeaderDef(); // acronym for a long
361
BitBuffer currentBitBuffer = getBitBuffer();
363
* Read the stream event header.
367
sehd.read(currentBitBuffer);
370
* Check for an event id.
372
EnumDefinition idEnumDef = (EnumDefinition) sehd
373
.lookupDefinition("id"); //$NON-NLS-1$
374
assert (idEnumDef != null);
376
eventID = idEnumDef.getIntegerValue();
379
* Check for the variant v.
381
VariantDefinition variantDef = (VariantDefinition) sehd
382
.lookupDefinition("v"); //$NON-NLS-1$
383
assert (variantDef != null);
386
* Get the variant current field
388
StructDefinition variantCurrentField = (StructDefinition) variantDef
390
assert (variantCurrentField != null);
393
* Try to get the id field in the current field of the variant. If
394
* it is present, it overrides the previously read event id.
396
IntegerDefinition idIntegerDef = (IntegerDefinition) variantCurrentField
397
.lookupDefinition("id"); //$NON-NLS-1$
398
if (idIntegerDef != null) {
399
eventID = idIntegerDef.getValue();
405
IntegerDefinition timestampDef = (IntegerDefinition) variantCurrentField
406
.lookupDefinition("timestamp"); //$NON-NLS-1$
407
assert (timestampDef != null);
410
* Calculate the event timestamp.
412
timestamp = calculateTimestamp(timestampDef);
416
* Read the stream event context.
418
if (getStreamEventContextDef() != null) {
419
getStreamEventContextDef().read(currentBitBuffer);
423
* Get the right event definition using the event id.
425
EventDefinition eventDef = events.get(eventID);
426
if (eventDef == null) {
427
throw new CTFReaderException("Incorrect event id : " + eventID); //$NON-NLS-1$
431
* Read the event context.
433
if (eventDef.getContext() != null) {
434
eventDef.getContext().read(currentBitBuffer);
438
* Read the event fields.
440
if (eventDef.getFields() != null) {
441
eventDef.getFields().read(currentBitBuffer);
445
* Set the event timestamp using the timestamp calculated by
448
eventDef.setTimestamp(timestamp);
454
* Calculates the timestamp value of the event, possibly using the timestamp
455
* from the last event.
457
* @param timestampDef
458
* Integer definition of the timestamp.
459
* @return The calculated timestamp value.
461
private long calculateTimestamp(IntegerDefinition timestampDef) {
464
int len = timestampDef.getDeclaration().getLength();
467
* If the timestamp length is 64 bits, it is a full timestamp.
469
if (timestampDef.getDeclaration().getLength() == 64) {
470
lastTimestamp = timestampDef.getValue();
471
return lastTimestamp;
475
* Bit mask to keep / remove all old / new bits.
477
majorasbitmask = (1L << len) - 1;
480
* If the new value is smaller than the corresponding bits of the last
481
* timestamp, we assume an overflow of the compact representation.
483
newval = timestampDef.getValue();
484
if (newval < (lastTimestamp & majorasbitmask)) {
485
newval = newval + (1L << len);
488
/* Keep only the high bits of the old value */
489
lastTimestamp = lastTimestamp & ~majorasbitmask;
491
/* Then add the low bits of the new value */
492
lastTimestamp = lastTimestamp + newval;
494
return lastTimestamp;
498
public Definition lookupDefinition(String lookupPath) {
499
// TODO Auto-generated method stub
504
* Gets the stream event context definition (see CTF specs)
506
* @return the definition of the stream event context (the form not the
509
public StructDefinition getStreamEventContextDef() {
510
return this.streamEventContextDef;
514
* Sets the stream event context definition
516
* @param streamEventContextDef
517
* The stream event context definition
519
public void setStreamEventContextDef(StructDefinition streamEventContextDef) {
520
this.streamEventContextDef = streamEventContextDef;
524
* Gets the stream event header definition
526
* @return the stream event header definition
528
public StructDefinition getStreamEventHeaderDef() {
529
return this.streamEventHeaderDef;
533
* Sets the stream event header definition
535
* @param streamEventHeaderDef
536
* the stream event header definition
538
public void setStreamEventHeaderDef(StructDefinition streamEventHeaderDef) {
539
this.streamEventHeaderDef = streamEventHeaderDef;
543
* Sets the stream packet context definition
545
* @param streamPacketContextDef
546
* the stream packet context definition
548
public void setStreamPacketContextDef(
549
StructDefinition streamPacketContextDef) {
550
this.streamPacketContextDef = streamPacketContextDef;
554
* Gets the trace packet header definition
556
* @return the trace packet header definition
558
public StructDefinition getTracePacketHeaderDef() {
559
return this.tracePacketHeaderDef;
563
* Sets the trace packet header definition
565
* @param tracePacketHeaderDef
566
* the trace packet header definition
568
public void setTracePacketHeaderDef(StructDefinition tracePacketHeaderDef) {
569
this.tracePacketHeaderDef = tracePacketHeaderDef;
573
* @return the parent stream input reader
575
public StreamInputReader getStreamInputReader() {
576
return this.streamInputReader;
581
* @return THe bit buffer that reads the file.
583
public BitBuffer getBitBuffer() {