ctf: support traces with no content but a packet size
[deliverable/tracecompass.git] / org.eclipse.linuxtools.ctf.core / src / org / eclipse / linuxtools / ctf / core / trace / StreamInputPacketReader.java
1 /*******************************************************************************
2 * Copyright (c) 2011-2013 Ericsson, Ecole Polytechnique de Montreal and others
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 *******************************************************************************/
12 package org.eclipse.linuxtools.ctf.core.trace;
13
14 import java.io.IOException;
15 import java.nio.MappedByteBuffer;
16 import java.nio.channels.FileChannel.MapMode;
17 import java.util.Collection;
18
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;
32
33 /**
34 * CTF trace packet reader. Reads the events of a packet of a trace file.
35 *
36 * @version 1.0
37 * @author Matthew Khouzam
38 * @author Simon Marchi
39 */
40 public class StreamInputPacketReader implements IDefinitionScope {
41
42 // ------------------------------------------------------------------------
43 // Attributes
44 // ------------------------------------------------------------------------
45
46 /** BitBuffer used to read the trace file. */
47 private final BitBuffer bitBuffer;
48
49 /** StreamInputReader that uses this StreamInputPacketReader. */
50 private final StreamInputReader streamInputReader;
51
52 /** Trace packet header. */
53 private final StructDefinition tracePacketHeaderDef;
54
55 /** Stream packet context definition. */
56 private final StructDefinition streamPacketContextDef;
57
58 /** Stream event header definition. */
59 private final StructDefinition streamEventHeaderDef;
60
61 /** Stream event context definition. */
62 private final StructDefinition streamEventContextDef;
63
64 /** Reference to the index entry of the current packet. */
65 private StreamInputPacketIndexEntry currentPacket = null;
66
67 /**
68 * Last timestamp recorded.
69 *
70 * Needed to calculate the complete timestamp values for the events with
71 * compact headers.
72 */
73 private long lastTimestamp = 0;
74
75 /** CPU id of current packet. */
76 private int currentCpu = 0;
77
78 private int lostEventsInThisPacket;
79
80 private long lostEventsDuration;
81
82 private boolean hasLost = false;
83
84 // ------------------------------------------------------------------------
85 // Constructors
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
97 /* Set the BitBuffer's byte order. */
98 bitBuffer = new BitBuffer();
99 bitBuffer.setByteOrder(streamInputReader.getByteOrder());
100
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 */
135 Collection<IEventDeclaration> eventDecls = streamInputReader.getStreamInput().getStream().getEvents().values();
136
137 for (IEventDeclaration event : eventDecls) {
138 if (!streamInputReader.getEventDefinitions().containsKey(event.getId())) {
139 EventDefinition eventDef = event.createDefinition(streamInputReader);
140 streamInputReader.addEventDefinition(event.getId(), eventDef);
141 }
142 }
143 }
144
145 /**
146 * Dispose the StreamInputPacketReader
147 *
148 * @since 2.0
149 */
150 public void dispose() {
151 bitBuffer.setByteBuffer(null);
152 }
153
154 // ------------------------------------------------------------------------
155 // Getters/Setters/Predicates
156 // ------------------------------------------------------------------------
157
158 /**
159 * Gets the current packet
160 *
161 * @return the current packet
162 */
163 StreamInputPacketIndexEntry getCurrentPacket() {
164 return this.currentPacket;
165 }
166
167 /**
168 * Gets the steamPacketContext Definition
169 *
170 * @return steamPacketContext Definition
171 */
172 public StructDefinition getStreamPacketContextDef() {
173 return this.streamPacketContextDef;
174 }
175
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
185 /**
186 * Gets the CPU (core) number
187 *
188 * @return the CPU (core) number
189 */
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
203 /**
204 * Changes the current packet to the given one.
205 *
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
210 */
211 void setCurrentPacket(StreamInputPacketIndexEntry currentPacket) throws CTFReaderException {
212 StreamInputPacketIndexEntry prevPacket = null;
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 {
221 bb = streamInputReader.getStreamInput().getFileChannel()
222 .map(MapMode.READ_ONLY,
223 this.currentPacket.getOffsetBytes(),
224 (this.currentPacket.getPacketSizeBits() + 7) / 8);
225 } catch (IOException e) {
226 throw new CTFReaderException(e.getMessage(), e);
227 }
228
229 bitBuffer.setByteBuffer(bb);
230
231 /*
232 * Read trace packet header.
233 */
234 if (tracePacketHeaderDef != null) {
235 tracePacketHeaderDef.read(bitBuffer);
236 }
237
238 /*
239 * Read stream packet context.
240 */
241 if (getStreamPacketContextDef() != null) {
242 getStreamPacketContextDef().read(bitBuffer);
243
244 /* Read CPU ID */
245 if (this.getCurrentPacket().getTarget() != null) {
246 this.currentCpu = (int) this.getCurrentPacket().getTargetId();
247 }
248
249 /* Read number of lost events */
250 lostEventsInThisPacket = (int) this.getCurrentPacket().getLostEvents();
251 if (lostEventsInThisPacket != 0) {
252 hasLost = true;
253 /*
254 * Compute the duration of the lost event time range. If the
255 * current packet is the first packet, duration will be set
256 * to 1.
257 */
258 long lostEventsStartTime;
259 int index = this.streamInputReader.getStreamInput().getIndex().getEntries().indexOf(currentPacket);
260 if (index == 0) {
261 lostEventsStartTime = currentPacket.getTimestampBegin() + 1;
262 } else {
263 prevPacket = this.streamInputReader.getStreamInput().getIndex().getEntries().get(index - 1);
264 lostEventsStartTime = prevPacket.getTimestampEnd();
265 }
266 lostEventsDuration = Math.abs(lostEventsStartTime - currentPacket.getTimestampBegin());
267 }
268 }
269
270 /*
271 * Use the timestamp begin of the packet as the reference for the
272 * timestamp reconstitution.
273 */
274 lastTimestamp = currentPacket.getTimestampBegin();
275 } else {
276 bitBuffer.setByteBuffer(null);
277
278 lastTimestamp = 0;
279 }
280 }
281
282 /**
283 * Returns whether it is possible to read any more events from this packet.
284 *
285 * @return True if it is possible to read any more events from this packet.
286 */
287 public boolean hasMoreEvents() {
288 if (currentPacket != null) {
289 return hasLost || (bitBuffer.position() < currentPacket.getContentSizeBits());
290 }
291 return false;
292 }
293
294 /**
295 * Reads the next event of the packet into the right event definition.
296 *
297 * @return The event definition containing the event data that was just
298 * read.
299 * @throws CTFReaderException
300 * If there was a problem reading the trace
301 */
302 public EventDefinition readNextEvent() throws CTFReaderException {
303 /* Default values for those fields */
304 long eventID = EventDeclaration.UNSET_EVENT_ID;
305 long timestamp = 0;
306 if (hasLost) {
307 hasLost = false;
308 EventDefinition eventDef = EventDeclaration.getLostEventDeclaration().createDefinition(streamInputReader);
309 ((IntegerDefinition) eventDef.getFields().getDefinitions().get(CTFStrings.LOST_EVENTS_FIELD)).setValue(lostEventsInThisPacket);
310 ((IntegerDefinition) eventDef.getFields().getDefinitions().get(CTFStrings.LOST_EVENTS_DURATION)).setValue(lostEventsDuration);
311 eventDef.setTimestamp(this.lastTimestamp);
312 return eventDef;
313 }
314
315 final StructDefinition sehd = streamEventHeaderDef;
316 final BitBuffer currentBitBuffer = bitBuffer;
317 final long posStart = currentBitBuffer.position();
318 /* Read the stream event header. */
319 if (sehd != null) {
320 sehd.read(currentBitBuffer);
321
322 /* Check for the event id. */
323 Definition idDef = sehd.lookupDefinition("id"); //$NON-NLS-1$
324 if (idDef instanceof SimpleDatatypeDefinition) {
325 eventID = ((SimpleDatatypeDefinition) idDef).getIntegerValue();
326 } else if (idDef != null) {
327 throw new CTFReaderException("Incorrect event id : " + eventID);
328 }
329
330 /*
331 * Get the timestamp from the event header (may be overridden later
332 * on)
333 */
334 IntegerDefinition timestampDef = sehd.lookupInteger("timestamp"); //$NON-NLS-1$
335 if (timestampDef != null) {
336 timestamp = calculateTimestamp(timestampDef);
337 } // else timestamp remains 0
338
339 /* Check for the variant v. */
340 Definition variantDef = sehd.lookupDefinition("v"); //$NON-NLS-1$
341 if (variantDef instanceof VariantDefinition) {
342
343 /* Get the variant current field */
344 StructDefinition variantCurrentField = (StructDefinition) ((VariantDefinition) variantDef).getCurrentField();
345
346 /*
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.
349 */
350 Definition idIntegerDef = variantCurrentField.lookupDefinition("id"); //$NON-NLS-1$
351 if (idIntegerDef instanceof IntegerDefinition) {
352 eventID = ((IntegerDefinition) idIntegerDef).getValue();
353 }
354
355 /*
356 * Get the timestamp. This would overwrite any previous
357 * timestamp definition
358 */
359 Definition def = variantCurrentField.lookupDefinition("timestamp"); //$NON-NLS-1$
360 if (def instanceof IntegerDefinition) {
361 timestamp = calculateTimestamp((IntegerDefinition) def);
362 }
363 }
364 }
365
366 /* Read the stream event context. */
367 if (streamEventContextDef != null) {
368 streamEventContextDef.read(currentBitBuffer);
369 }
370
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$
375 }
376
377 /* Read the event context. */
378 if (eventDef.getEventContext() != null) {
379 eventDef.getEventContext().read(currentBitBuffer);
380 }
381
382 /* Read the event fields. */
383 if (eventDef.getFields() != null) {
384 eventDef.getFields().read(currentBitBuffer);
385 }
386
387 /*
388 * Set the event timestamp using the timestamp calculated by
389 * updateTimestamp.
390 */
391 eventDef.setTimestamp(timestamp);
392
393 if (posStart == currentBitBuffer.position()) {
394 throw new CTFReaderException("Empty event not allowed, event: " + eventDef.getDeclaration().getName()); //$NON-NLS-1$
395 }
396
397 return eventDef;
398 }
399
400 /**
401 * Calculates the timestamp value of the event, possibly using the timestamp
402 * from the last event.
403 *
404 * @param timestampDef
405 * Integer definition of the timestamp.
406 * @return The calculated timestamp value.
407 */
408 private long calculateTimestamp(IntegerDefinition timestampDef) {
409 long newval;
410 long majorasbitmask;
411 int len = timestampDef.getDeclaration().getLength();
412
413 /*
414 * If the timestamp length is 64 bits, it is a full timestamp.
415 */
416 if (timestampDef.getDeclaration().getLength() == 64) {
417 lastTimestamp = timestampDef.getValue();
418 return lastTimestamp;
419 }
420
421 /*
422 * Bit mask to keep / remove all old / new bits.
423 */
424 majorasbitmask = (1L << len) - 1;
425
426 /*
427 * If the new value is smaller than the corresponding bits of the last
428 * timestamp, we assume an overflow of the compact representation.
429 */
430 newval = timestampDef.getValue();
431 if (newval < (lastTimestamp & majorasbitmask)) {
432 newval = newval + (1L << len);
433 }
434
435 /* Keep only the high bits of the old value */
436 lastTimestamp = lastTimestamp & ~majorasbitmask;
437
438 /* Then add the low bits of the new value */
439 lastTimestamp = lastTimestamp + newval;
440
441 return lastTimestamp;
442 }
443
444 @Override
445 public Definition lookupDefinition(String lookupPath) {
446 return null;
447 }
448 }
This page took 0.043564 seconds and 6 git commands to generate.