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.
209
void setCurrentPacket(StreamInputPacketIndexEntry currentPacket) {
210
StreamInputPacketIndexEntry prevPacket = null;
211
this.currentPacket = currentPacket;
213
if (this.currentPacket != null) {
215
* Change the map of the BitBuffer.
217
MappedByteBuffer bb = null;
219
bb = streamInputReader.getStreamInput().getFileChannel()
220
.map(MapMode.READ_ONLY,
221
this.currentPacket.getOffsetBytes(),
222
(this.currentPacket.getPacketSizeBits() + 7) / 8);
223
} catch (IOException e) {
225
* The streamInputReader object is already allocated, so this
226
* shouldn't fail bar some very bad kernel or RAM errors...
231
bitBuffer.setByteBuffer(bb);
234
* Read trace packet header.
236
if (tracePacketHeaderDef != null) {
237
tracePacketHeaderDef.read(bitBuffer);
241
* Read stream packet context.
243
if (getStreamPacketContextDef() != null) {
244
getStreamPacketContextDef().read(bitBuffer);
247
if (this.getCurrentPacket().getTarget() != null) {
248
this.currentCpu = (int) this.getCurrentPacket().getTargetId();
251
/* Read number of lost events */
252
lostEventsInThisPacket = (int) this.getCurrentPacket().getLostEvents();
253
if (lostEventsInThisPacket != 0) {
256
* Compute the duration of the lost event time range. If the
257
* current packet is the first packet, duration will be set
260
long lostEventsStartTime;
261
int index = this.streamInputReader.getStreamInput().getIndex().getEntries().indexOf(currentPacket);
263
lostEventsStartTime = currentPacket.getTimestampBegin() + 1;
265
prevPacket = this.streamInputReader.getStreamInput().getIndex().getEntries().get(index - 1);
266
lostEventsStartTime = prevPacket.getTimestampEnd();
268
lostEventsDuration = Math.abs(lostEventsStartTime - currentPacket.getTimestampBegin());
273
* Use the timestamp begin of the packet as the reference for the
274
* timestamp reconstitution.
276
lastTimestamp = currentPacket.getTimestampBegin();
278
bitBuffer.setByteBuffer(null);
285
* Returns whether it is possible to read any more events from this packet.
287
* @return True if it is possible to read any more events from this packet.
289
public boolean hasMoreEvents() {
290
if (currentPacket != null) {
291
return hasLost || (bitBuffer.position() < currentPacket.getContentSizeBits());
297
* Reads the next event of the packet into the right event definition.
299
* @return The event definition containing the event data that was just
301
* @throws CTFReaderException
302
* If there was a problem reading the trace
304
public EventDefinition readNextEvent() throws CTFReaderException {
305
/* Default values for those fields */
306
long eventID = EventDeclaration.UNSET_EVENT_ID;
310
EventDefinition eventDef = EventDeclaration.getLostEventDeclaration().createDefinition(streamInputReader);
311
((IntegerDefinition) eventDef.getFields().getDefinitions().get(CTFStrings.LOST_EVENTS_FIELD)).setValue(lostEventsInThisPacket);
312
((IntegerDefinition) eventDef.getFields().getDefinitions().get(CTFStrings.LOST_EVENTS_DURATION)).setValue(lostEventsDuration);
313
eventDef.setTimestamp(this.lastTimestamp);
317
final StructDefinition sehd = streamEventHeaderDef;
318
final BitBuffer currentBitBuffer = bitBuffer;
320
/* Read the stream event header. */
322
sehd.read(currentBitBuffer);
324
/* Check for the event id. */
325
Definition idDef = sehd.lookupDefinition("id"); //$NON-NLS-1$
326
if (idDef instanceof SimpleDatatypeDefinition) {
327
eventID = ((SimpleDatatypeDefinition) idDef).getIntegerValue();
328
} // else, eventID remains 0
331
* Get the timestamp from the event header (may be overridden later
334
IntegerDefinition timestampDef = sehd.lookupInteger("timestamp"); //$NON-NLS-1$
335
if (timestampDef != null) {
336
timestamp = calculateTimestamp(timestampDef);
337
} // else timestamp remains 0
339
/* Check for the variant v. */
340
Definition variantDef = sehd.lookupDefinition("v"); //$NON-NLS-1$
341
if (variantDef instanceof VariantDefinition) {
343
/* Get the variant current field */
344
StructDefinition variantCurrentField = (StructDefinition) ((VariantDefinition) variantDef).getCurrentField();
347
* Try to get the id field in the current field of the variant.
348
* If it is present, it overrides the previously read event id.
350
Definition idIntegerDef = variantCurrentField.lookupDefinition("id"); //$NON-NLS-1$
351
if (idIntegerDef instanceof IntegerDefinition) {
352
eventID = ((IntegerDefinition) idIntegerDef).getValue();
356
* Get the timestamp. This would overwrite any previous
357
* timestamp definition
359
Definition def = variantCurrentField.lookupDefinition("timestamp"); //$NON-NLS-1$
360
if (def instanceof IntegerDefinition) {
361
timestamp = calculateTimestamp((IntegerDefinition) def);
366
/* Read the stream event context. */
367
if (streamEventContextDef != null) {
368
streamEventContextDef.read(currentBitBuffer);
371
/* Get the right event definition using the event id. */
372
EventDefinition eventDef = streamInputReader.getEventDefinitions().get(eventID);
373
if (eventDef == null) {
374
throw new CTFReaderException("Incorrect event id : " + eventID); //$NON-NLS-1$
377
/* Read the event context. */
378
if (eventDef.getEventContext() != null) {
379
eventDef.getEventContext().read(currentBitBuffer);
382
/* Read the event fields. */
383
if (eventDef.getFields() != null) {
384
eventDef.getFields().read(currentBitBuffer);
388
* Set the event timestamp using the timestamp calculated by
391
eventDef.setTimestamp(timestamp);
397
* Calculates the timestamp value of the event, possibly using the timestamp
398
* from the last event.
400
* @param timestampDef
401
* Integer definition of the timestamp.
402
* @return The calculated timestamp value.
404
private long calculateTimestamp(IntegerDefinition timestampDef) {
407
int len = timestampDef.getDeclaration().getLength();
410
* If the timestamp length is 64 bits, it is a full timestamp.
412
if (timestampDef.getDeclaration().getLength() == 64) {
413
lastTimestamp = timestampDef.getValue();
414
return lastTimestamp;
418
* Bit mask to keep / remove all old / new bits.
420
majorasbitmask = (1L << len) - 1;
423
* If the new value is smaller than the corresponding bits of the last
424
* timestamp, we assume an overflow of the compact representation.
426
newval = timestampDef.getValue();
427
if (newval < (lastTimestamp & majorasbitmask)) {
428
newval = newval + (1L << len);
431
/* Keep only the high bits of the old value */
432
lastTimestamp = lastTimestamp & ~majorasbitmask;
434
/* Then add the low bits of the new value */
435
lastTimestamp = lastTimestamp + newval;
437
return lastTimestamp;
441
public Definition lookupDefinition(String lookupPath) {