ctf: Throw CTFReaderException in the BitBuffer API
[deliverable/tracecompass.git] / org.eclipse.linuxtools.ctf.core / src / org / eclipse / linuxtools / ctf / core / trace / StreamInputPacketReader.java
CommitLineData
866e5b51 1/*******************************************************************************
8e964be1 2 * Copyright (c) 2011-2013 Ericsson, Ecole Polytechnique de Montreal and others
866e5b51
FC
3 *
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
8 *
9 * Contributors: Matthew Khouzam - Initial API and implementation
10 * Contributors: Simon Marchi - Initial API and implementation
11 *******************************************************************************/
12package org.eclipse.linuxtools.ctf.core.trace;
13
14import java.io.IOException;
15import java.nio.MappedByteBuffer;
16import java.nio.channels.FileChannel.MapMode;
17import java.util.Collection;
866e5b51 18
c26d0fe0 19import org.eclipse.linuxtools.ctf.core.CTFStrings;
866e5b51 20import org.eclipse.linuxtools.ctf.core.event.EventDefinition;
8e964be1 21import org.eclipse.linuxtools.ctf.core.event.IEventDeclaration;
486efb2e 22import org.eclipse.linuxtools.ctf.core.event.io.BitBuffer;
866e5b51 23import org.eclipse.linuxtools.ctf.core.event.types.Definition;
866e5b51
FC
24import org.eclipse.linuxtools.ctf.core.event.types.IDefinitionScope;
25import org.eclipse.linuxtools.ctf.core.event.types.IntegerDefinition;
21fb02fa 26import org.eclipse.linuxtools.ctf.core.event.types.SimpleDatatypeDefinition;
866e5b51
FC
27import org.eclipse.linuxtools.ctf.core.event.types.StructDeclaration;
28import org.eclipse.linuxtools.ctf.core.event.types.StructDefinition;
29import org.eclipse.linuxtools.ctf.core.event.types.VariantDefinition;
8e964be1 30import org.eclipse.linuxtools.internal.ctf.core.event.EventDeclaration;
ce2388e0 31import org.eclipse.linuxtools.internal.ctf.core.trace.StreamInputPacketIndexEntry;
866e5b51
FC
32
33/**
d37aaa7f 34 * CTF trace packet reader. Reads the events of a packet of a trace file.
5c7202b5 35 *
d37aaa7f
FC
36 * @version 1.0
37 * @author Matthew Khouzam
38 * @author Simon Marchi
866e5b51 39 */
bfe038ff 40public class StreamInputPacketReader implements IDefinitionScope {
866e5b51
FC
41
42 // ------------------------------------------------------------------------
6bdc9fac 43 // Attributes
866e5b51
FC
44 // ------------------------------------------------------------------------
45
6bdc9fac
AM
46 /** BitBuffer used to read the trace file. */
47 private final BitBuffer bitBuffer;
866e5b51 48
6bdc9fac 49 /** StreamInputReader that uses this StreamInputPacketReader. */
866e5b51
FC
50 private final StreamInputReader streamInputReader;
51
6bdc9fac
AM
52 /** Trace packet header. */
53 private final StructDefinition tracePacketHeaderDef;
866e5b51 54
6bdc9fac
AM
55 /** Stream packet context definition. */
56 private final StructDefinition streamPacketContextDef;
866e5b51 57
6bdc9fac
AM
58 /** Stream event header definition. */
59 private final StructDefinition streamEventHeaderDef;
866e5b51 60
c26d0fe0 61 /** Stream event context definition. */
6bdc9fac 62 private final StructDefinition streamEventContextDef;
866e5b51 63
6bdc9fac
AM
64 /** Reference to the index entry of the current packet. */
65 private StreamInputPacketIndexEntry currentPacket = null;
66
866e5b51 67 /**
6bdc9fac
AM
68 * Last timestamp recorded.
69 *
70 * Needed to calculate the complete timestamp values for the events with
71 * compact headers.
866e5b51 72 */
6bdc9fac
AM
73 private long lastTimestamp = 0;
74
75 /** CPU id of current packet. */
866e5b51
FC
76 private int currentCpu = 0;
77
5c7202b5
MK
78 private int lostEventsInThisPacket;
79
c26d0fe0
AM
80 private long lostEventsDuration;
81
82 private boolean hasLost = false;
83
866e5b51 84 // ------------------------------------------------------------------------
6bdc9fac 85 // Constructors
866e5b51
FC
86 // ------------------------------------------------------------------------
87
88 /**
89 * Constructs a StreamInputPacketReader.
90 *
91 * @param streamInputReader
92 * The StreamInputReader to which this packet reader belongs to.
93 */
94 public StreamInputPacketReader(StreamInputReader streamInputReader) {
95 this.streamInputReader = streamInputReader;
96
6bdc9fac
AM
97 /* Set the BitBuffer's byte order. */
98 bitBuffer = new BitBuffer();
99 bitBuffer.setByteOrder(streamInputReader.getByteOrder());
33656d8e 100
6bdc9fac
AM
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$
106 } else {
107 tracePacketHeaderDef = null;
108 }
109
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$
114 } else {
115 streamPacketContextDef = null;
116 }
117
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$
122 } else {
123 streamEventHeaderDef = null;
124 }
125
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$
130 } else {
131 streamEventContextDef = null;
132 }
133
134 /* Create event definitions */
8e964be1 135 Collection<IEventDeclaration> eventDecls = streamInputReader.getStreamInput().getStream().getEvents().values();
6bdc9fac 136
8e964be1 137 for (IEventDeclaration event : eventDecls) {
7ff6d3cf 138 if (!streamInputReader.getEventDefinitions().containsKey(event.getId())) {
6bdc9fac 139 EventDefinition eventDef = event.createDefinition(streamInputReader);
7ff6d3cf 140 streamInputReader.addEventDefinition(event.getId(), eventDef);
6bdc9fac
AM
141 }
142 }
143 }
866e5b51 144
5d1c6919
PT
145 /**
146 * Dispose the StreamInputPacketReader
c26d0fe0 147 *
5d1c6919
PT
148 * @since 2.0
149 */
150 public void dispose() {
151 bitBuffer.setByteBuffer(null);
152 }
153
866e5b51
FC
154 // ------------------------------------------------------------------------
155 // Getters/Setters/Predicates
156 // ------------------------------------------------------------------------
157
9ac2eb62
MK
158 /**
159 * Gets the current packet
160 *
161 * @return the current packet
162 */
486efb2e 163 StreamInputPacketIndexEntry getCurrentPacket() {
866e5b51
FC
164 return this.currentPacket;
165 }
166
9ac2eb62
MK
167 /**
168 * Gets the steamPacketContext Definition
169 *
170 * @return steamPacketContext Definition
171 */
866e5b51
FC
172 public StructDefinition getStreamPacketContextDef() {
173 return this.streamPacketContextDef;
174 }
175
45cbd8dc
AM
176 /**
177 * Gets the stream's event context definition.
178 *
179 * @return The streamEventContext definition
180 */
181 public StructDefinition getStreamEventContextDef() {
182 return streamEventContextDef;
183 }
184
9ac2eb62
MK
185 /**
186 * Gets the CPU (core) number
187 *
188 * @return the CPU (core) number
189 */
866e5b51
FC
190 public int getCPU() {
191 return this.currentCpu;
192 }
193
194 @Override
195 public String getPath() {
196 return ""; //$NON-NLS-1$
197 }
198
199 // ------------------------------------------------------------------------
200 // Operations
201 // ------------------------------------------------------------------------
202
866e5b51
FC
203 /**
204 * Changes the current packet to the given one.
205 *
206 * @param currentPacket
207 * The index entry of the packet to switch to.
db8e8f7d
AM
208 * @throws CTFReaderException
209 * If we get an error reading the packet
866e5b51 210 */
db8e8f7d 211 void setCurrentPacket(StreamInputPacketIndexEntry currentPacket) throws CTFReaderException {
c26d0fe0 212 StreamInputPacketIndexEntry prevPacket = null;
866e5b51
FC
213 this.currentPacket = currentPacket;
214
215 if (this.currentPacket != null) {
216 /*
217 * Change the map of the BitBuffer.
218 */
219 MappedByteBuffer bb = null;
220 try {
6bdc9fac 221 bb = streamInputReader.getStreamInput().getFileChannel()
788ddcbc
MK
222 .map(MapMode.READ_ONLY,
223 this.currentPacket.getOffsetBytes(),
224 (this.currentPacket.getPacketSizeBits() + 7) / 8);
866e5b51
FC
225 } catch (IOException e) {
226 /*
227 * The streamInputReader object is already allocated, so this
228 * shouldn't fail bar some very bad kernel or RAM errors...
229 */
230 e.printStackTrace();
231 }
232
6bdc9fac 233 bitBuffer.setByteBuffer(bb);
866e5b51
FC
234
235 /*
236 * Read trace packet header.
237 */
6bdc9fac
AM
238 if (tracePacketHeaderDef != null) {
239 tracePacketHeaderDef.read(bitBuffer);
866e5b51
FC
240 }
241
242 /*
243 * Read stream packet context.
244 */
245 if (getStreamPacketContextDef() != null) {
6bdc9fac 246 getStreamPacketContextDef().read(bitBuffer);
33656d8e 247
132a02b0 248 /* Read CPU ID */
21fb02fa 249 if (this.getCurrentPacket().getTarget() != null) {
132a02b0 250 this.currentCpu = (int) this.getCurrentPacket().getTargetId();
866e5b51 251 }
21fb02fa 252
132a02b0
MK
253 /* Read number of lost events */
254 lostEventsInThisPacket = (int) this.getCurrentPacket().getLostEvents();
c26d0fe0
AM
255 if (lostEventsInThisPacket != 0) {
256 hasLost = true;
257 /*
258 * Compute the duration of the lost event time range. If the
259 * current packet is the first packet, duration will be set
260 * to 1.
261 */
262 long lostEventsStartTime;
263 int index = this.streamInputReader.getStreamInput().getIndex().getEntries().indexOf(currentPacket);
264 if (index == 0) {
265 lostEventsStartTime = currentPacket.getTimestampBegin() + 1;
266 } else {
267 prevPacket = this.streamInputReader.getStreamInput().getIndex().getEntries().get(index - 1);
268 lostEventsStartTime = prevPacket.getTimestampEnd();
269 }
270 lostEventsDuration = Math.abs(lostEventsStartTime - currentPacket.getTimestampBegin());
271 }
866e5b51
FC
272 }
273
274 /*
275 * Use the timestamp begin of the packet as the reference for the
276 * timestamp reconstitution.
277 */
ce2388e0 278 lastTimestamp = currentPacket.getTimestampBegin();
866e5b51 279 } else {
6bdc9fac 280 bitBuffer.setByteBuffer(null);
866e5b51
FC
281
282 lastTimestamp = 0;
283 }
284 }
285
286 /**
287 * Returns whether it is possible to read any more events from this packet.
288 *
289 * @return True if it is possible to read any more events from this packet.
290 */
291 public boolean hasMoreEvents() {
292 if (currentPacket != null) {
c26d0fe0 293 return hasLost || (bitBuffer.position() < currentPacket.getContentSizeBits());
866e5b51
FC
294 }
295 return false;
296 }
297
298 /**
299 * Reads the next event of the packet into the right event definition.
300 *
301 * @return The event definition containing the event data that was just
302 * read.
303 * @throws CTFReaderException
be6df2d8 304 * If there was a problem reading the trace
866e5b51
FC
305 */
306 public EventDefinition readNextEvent() throws CTFReaderException {
1fbaecd1 307 /* Default values for those fields */
b73145e2 308 long eventID = EventDeclaration.UNSET_EVENT_ID;
866e5b51 309 long timestamp = 0;
c26d0fe0
AM
310 if (hasLost) {
311 hasLost = false;
6bdc9fac 312 EventDefinition eventDef = EventDeclaration.getLostEventDeclaration().createDefinition(streamInputReader);
c26d0fe0
AM
313 ((IntegerDefinition) eventDef.getFields().getDefinitions().get(CTFStrings.LOST_EVENTS_FIELD)).setValue(lostEventsInThisPacket);
314 ((IntegerDefinition) eventDef.getFields().getDefinitions().get(CTFStrings.LOST_EVENTS_DURATION)).setValue(lostEventsDuration);
aa572e22 315 eventDef.setTimestamp(this.lastTimestamp);
33656d8e
MK
316 return eventDef;
317 }
132a02b0 318
6bdc9fac
AM
319 final StructDefinition sehd = streamEventHeaderDef;
320 final BitBuffer currentBitBuffer = bitBuffer;
2b7f6f09 321
1fbaecd1 322 /* Read the stream event header. */
2b7f6f09
MK
323 if (sehd != null) {
324 sehd.read(currentBitBuffer);
866e5b51 325
1fbaecd1
AM
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
866e5b51 331
c26d0fe0
AM
332 /*
333 * Get the timestamp from the event header (may be overridden later
334 * on)
335 */
0594c61c
AM
336 IntegerDefinition timestampDef = sehd.lookupInteger("timestamp"); //$NON-NLS-1$
337 if (timestampDef != null) {
338 timestamp = calculateTimestamp(timestampDef);
6bdc9fac 339 } // else timestamp remains 0
1fbaecd1
AM
340
341 /* Check for the variant v. */
6bdc9fac
AM
342 Definition variantDef = sehd.lookupDefinition("v"); //$NON-NLS-1$
343 if (variantDef instanceof VariantDefinition) {
866e5b51 344
1fbaecd1 345 /* Get the variant current field */
6bdc9fac 346 StructDefinition variantCurrentField = (StructDefinition) ((VariantDefinition) variantDef).getCurrentField();
866e5b51 347
21fb02fa
MK
348 /*
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.
351 */
6bdc9fac
AM
352 Definition idIntegerDef = variantCurrentField.lookupDefinition("id"); //$NON-NLS-1$
353 if (idIntegerDef instanceof IntegerDefinition) {
354 eventID = ((IntegerDefinition) idIntegerDef).getValue();
21fb02fa 355 }
866e5b51 356
c26d0fe0
AM
357 /*
358 * Get the timestamp. This would overwrite any previous
359 * timestamp definition
360 */
0594c61c
AM
361 Definition def = variantCurrentField.lookupDefinition("timestamp"); //$NON-NLS-1$
362 if (def instanceof IntegerDefinition) {
363 timestamp = calculateTimestamp((IntegerDefinition) def);
6bdc9fac 364 }
21fb02fa 365 }
866e5b51
FC
366 }
367
1fbaecd1
AM
368 /* Read the stream event context. */
369 if (streamEventContextDef != null) {
370 streamEventContextDef.read(currentBitBuffer);
866e5b51
FC
371 }
372
1fbaecd1 373 /* Get the right event definition using the event id. */
7ff6d3cf 374 EventDefinition eventDef = streamInputReader.getEventDefinitions().get(eventID);
866e5b51
FC
375 if (eventDef == null) {
376 throw new CTFReaderException("Incorrect event id : " + eventID); //$NON-NLS-1$
377 }
378
1fbaecd1 379 /* Read the event context. */
87b60a47
MK
380 if (eventDef.getEventContext() != null) {
381 eventDef.getEventContext().read(currentBitBuffer);
866e5b51
FC
382 }
383
1fbaecd1 384 /* Read the event fields. */
aa572e22
MK
385 if (eventDef.getFields() != null) {
386 eventDef.getFields().read(currentBitBuffer);
866e5b51
FC
387 }
388
389 /*
390 * Set the event timestamp using the timestamp calculated by
391 * updateTimestamp.
392 */
aa572e22 393 eventDef.setTimestamp(timestamp);
866e5b51
FC
394
395 return eventDef;
396 }
397
398 /**
399 * Calculates the timestamp value of the event, possibly using the timestamp
400 * from the last event.
401 *
402 * @param timestampDef
403 * Integer definition of the timestamp.
404 * @return The calculated timestamp value.
405 */
406 private long calculateTimestamp(IntegerDefinition timestampDef) {
407 long newval;
408 long majorasbitmask;
409 int len = timestampDef.getDeclaration().getLength();
410
411 /*
412 * If the timestamp length is 64 bits, it is a full timestamp.
413 */
414 if (timestampDef.getDeclaration().getLength() == 64) {
415 lastTimestamp = timestampDef.getValue();
416 return lastTimestamp;
417 }
418
419 /*
420 * Bit mask to keep / remove all old / new bits.
421 */
422 majorasbitmask = (1L << len) - 1;
423
424 /*
425 * If the new value is smaller than the corresponding bits of the last
426 * timestamp, we assume an overflow of the compact representation.
427 */
428 newval = timestampDef.getValue();
429 if (newval < (lastTimestamp & majorasbitmask)) {
430 newval = newval + (1L << len);
431 }
432
433 /* Keep only the high bits of the old value */
434 lastTimestamp = lastTimestamp & ~majorasbitmask;
435
436 /* Then add the low bits of the new value */
437 lastTimestamp = lastTimestamp + newval;
438
439 return lastTimestamp;
440 }
441
442 @Override
443 public Definition lookupDefinition(String lookupPath) {
866e5b51
FC
444 return null;
445 }
866e5b51 446}
This page took 0.062546 seconds and 5 git commands to generate.