CTF : Handle traces with events without eventID
[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.event.EventDefinition;
20 import org.eclipse.linuxtools.ctf.core.event.IEventDeclaration;
21 import org.eclipse.linuxtools.ctf.core.event.io.BitBuffer;
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.EventDeclaration;
30 import org.eclipse.linuxtools.internal.ctf.core.trace.StreamInputPacketIndexEntry;
31
32 /**
33 * CTF trace packet reader. Reads the events of a packet of a trace file.
34 *
35 * @version 1.0
36 * @author Matthew Khouzam
37 * @author Simon Marchi
38 */
39 public class StreamInputPacketReader implements IDefinitionScope {
40
41 // ------------------------------------------------------------------------
42 // Attributes
43 // ------------------------------------------------------------------------
44
45 /** BitBuffer used to read the trace file. */
46 private final BitBuffer bitBuffer;
47
48 /** StreamInputReader that uses this StreamInputPacketReader. */
49 private final StreamInputReader streamInputReader;
50
51 /** Trace packet header. */
52 private final StructDefinition tracePacketHeaderDef;
53
54 /** Stream packet context definition. */
55 private final StructDefinition streamPacketContextDef;
56
57 /** Stream event header definition. */
58 private final StructDefinition streamEventHeaderDef;
59
60 /** Stream event context definition.*/
61 private final StructDefinition streamEventContextDef;
62
63 /** Reference to the index entry of the current packet. */
64 private StreamInputPacketIndexEntry currentPacket = null;
65
66 /**
67 * Last timestamp recorded.
68 *
69 * Needed to calculate the complete timestamp values for the events with
70 * compact headers.
71 */
72 private long lastTimestamp = 0;
73
74 /** CPU id of current packet. */
75 private int currentCpu = 0;
76
77 /** number of lost events in this packet */
78 private int lostSoFar;
79
80 private int lostEventsInThisPacket;
81
82 // ------------------------------------------------------------------------
83 // Constructors
84 // ------------------------------------------------------------------------
85
86 /**
87 * Constructs a StreamInputPacketReader.
88 *
89 * @param streamInputReader
90 * The StreamInputReader to which this packet reader belongs to.
91 */
92 public StreamInputPacketReader(StreamInputReader streamInputReader) {
93 this.streamInputReader = streamInputReader;
94
95 /* Set the BitBuffer's byte order. */
96 bitBuffer = new BitBuffer();
97 bitBuffer.setByteOrder(streamInputReader.getByteOrder());
98
99 lostSoFar = 0;
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 * @since 2.0
148 */
149 public void dispose() {
150 bitBuffer.setByteBuffer(null);
151 }
152
153 // ------------------------------------------------------------------------
154 // Getters/Setters/Predicates
155 // ------------------------------------------------------------------------
156
157 /**
158 * Gets the current packet
159 *
160 * @return the current packet
161 */
162 StreamInputPacketIndexEntry getCurrentPacket() {
163 return this.currentPacket;
164 }
165
166 /**
167 * Gets the steamPacketContext Definition
168 *
169 * @return steamPacketContext Definition
170 */
171 public StructDefinition getStreamPacketContextDef() {
172 return this.streamPacketContextDef;
173 }
174
175 /**
176 * Gets the stream's event context definition.
177 *
178 * @return The streamEventContext definition
179 */
180 public StructDefinition getStreamEventContextDef() {
181 return streamEventContextDef;
182 }
183
184 /**
185 * Gets the CPU (core) number
186 *
187 * @return the CPU (core) number
188 */
189 public int getCPU() {
190 return this.currentCpu;
191 }
192
193 @Override
194 public String getPath() {
195 return ""; //$NON-NLS-1$
196 }
197
198 // ------------------------------------------------------------------------
199 // Operations
200 // ------------------------------------------------------------------------
201
202 /**
203 * Changes the current packet to the given one.
204 *
205 * @param currentPacket
206 * The index entry of the packet to switch to.
207 */
208 void setCurrentPacket(StreamInputPacketIndexEntry currentPacket) {
209 this.currentPacket = currentPacket;
210
211 if (this.currentPacket != null) {
212 /*
213 * Change the map of the BitBuffer.
214 */
215 MappedByteBuffer bb = null;
216 try {
217 bb = streamInputReader.getStreamInput().getFileChannel()
218 .map(MapMode.READ_ONLY,
219 this.currentPacket.getOffsetBytes(),
220 (this.currentPacket.getPacketSizeBits() + 7) / 8);
221 } catch (IOException e) {
222 /*
223 * The streamInputReader object is already allocated, so this
224 * shouldn't fail bar some very bad kernel or RAM errors...
225 */
226 e.printStackTrace();
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 lostSoFar = 0;
252
253 }
254
255 /*
256 * Use the timestamp begin of the packet as the reference for the
257 * timestamp reconstitution.
258 */
259 lastTimestamp = currentPacket.getTimestampBegin();
260 } else {
261 bitBuffer.setByteBuffer(null);
262
263 lastTimestamp = 0;
264 }
265 }
266
267 /**
268 * Returns whether it is possible to read any more events from this packet.
269 *
270 * @return True if it is possible to read any more events from this packet.
271 */
272 public boolean hasMoreEvents() {
273 if (currentPacket != null) {
274 return bitBuffer.position() < currentPacket.getContentSizeBits();
275 }
276 return false;
277 }
278
279 /**
280 * Reads the next event of the packet into the right event definition.
281 *
282 * @return The event definition containing the event data that was just
283 * read.
284 * @throws CTFReaderException
285 * If there was a problem reading the trace
286 */
287 public EventDefinition readNextEvent() throws CTFReaderException {
288 /* Default values for those fields */
289 long eventID = EventDeclaration.UNSET_EVENT_ID;
290 long timestamp = 0;
291
292 if (lostEventsInThisPacket > lostSoFar) {
293 EventDefinition eventDef = EventDeclaration.getLostEventDeclaration().createDefinition(streamInputReader);
294 eventDef.setTimestamp(this.lastTimestamp);
295 ++lostSoFar;
296 return eventDef;
297 }
298
299 final StructDefinition sehd = streamEventHeaderDef;
300 final BitBuffer currentBitBuffer = bitBuffer;
301
302 /* Read the stream event header. */
303 if (sehd != null) {
304 sehd.read(currentBitBuffer);
305
306 /* Check for the event id. */
307 Definition idDef = sehd.lookupDefinition("id"); //$NON-NLS-1$
308 if (idDef instanceof SimpleDatatypeDefinition) {
309 eventID = ((SimpleDatatypeDefinition) idDef).getIntegerValue();
310 } // else, eventID remains 0
311
312 /* Get the timestamp from the event header (may be overridden later on) */
313 IntegerDefinition timestampDef = sehd.lookupInteger("timestamp"); //$NON-NLS-1$
314 if (timestampDef != null) {
315 timestamp = calculateTimestamp(timestampDef);
316 } // else timestamp remains 0
317
318 /* Check for the variant v. */
319 Definition variantDef = sehd.lookupDefinition("v"); //$NON-NLS-1$
320 if (variantDef instanceof VariantDefinition) {
321
322 /* Get the variant current field */
323 StructDefinition variantCurrentField = (StructDefinition) ((VariantDefinition) variantDef).getCurrentField();
324
325 /*
326 * Try to get the id field in the current field of the variant.
327 * If it is present, it overrides the previously read event id.
328 */
329 Definition idIntegerDef = variantCurrentField.lookupDefinition("id"); //$NON-NLS-1$
330 if (idIntegerDef instanceof IntegerDefinition) {
331 eventID = ((IntegerDefinition) idIntegerDef).getValue();
332 }
333
334 /* Get the timestamp. This would overwrite any previous timestamp definition */
335 Definition def = variantCurrentField.lookupDefinition("timestamp"); //$NON-NLS-1$
336 if (def instanceof IntegerDefinition) {
337 timestamp = calculateTimestamp((IntegerDefinition) def);
338 }
339 }
340 }
341
342 /* Read the stream event context. */
343 if (streamEventContextDef != null) {
344 streamEventContextDef.read(currentBitBuffer);
345 }
346
347 /* Get the right event definition using the event id. */
348 EventDefinition eventDef = streamInputReader.getEventDefinitions().get(eventID);
349 if (eventDef == null) {
350 throw new CTFReaderException("Incorrect event id : " + eventID); //$NON-NLS-1$
351 }
352
353 /* Read the event context. */
354 if (eventDef.getEventContext() != null) {
355 eventDef.getEventContext().read(currentBitBuffer);
356 }
357
358 /* Read the event fields. */
359 if (eventDef.getFields() != null) {
360 eventDef.getFields().read(currentBitBuffer);
361 }
362
363 /*
364 * Set the event timestamp using the timestamp calculated by
365 * updateTimestamp.
366 */
367 eventDef.setTimestamp(timestamp);
368
369 return eventDef;
370 }
371
372 /**
373 * Calculates the timestamp value of the event, possibly using the timestamp
374 * from the last event.
375 *
376 * @param timestampDef
377 * Integer definition of the timestamp.
378 * @return The calculated timestamp value.
379 */
380 private long calculateTimestamp(IntegerDefinition timestampDef) {
381 long newval;
382 long majorasbitmask;
383 int len = timestampDef.getDeclaration().getLength();
384
385 /*
386 * If the timestamp length is 64 bits, it is a full timestamp.
387 */
388 if (timestampDef.getDeclaration().getLength() == 64) {
389 lastTimestamp = timestampDef.getValue();
390 return lastTimestamp;
391 }
392
393 /*
394 * Bit mask to keep / remove all old / new bits.
395 */
396 majorasbitmask = (1L << len) - 1;
397
398 /*
399 * If the new value is smaller than the corresponding bits of the last
400 * timestamp, we assume an overflow of the compact representation.
401 */
402 newval = timestampDef.getValue();
403 if (newval < (lastTimestamp & majorasbitmask)) {
404 newval = newval + (1L << len);
405 }
406
407 /* Keep only the high bits of the old value */
408 lastTimestamp = lastTimestamp & ~majorasbitmask;
409
410 /* Then add the low bits of the new value */
411 lastTimestamp = lastTimestamp + newval;
412
413 return lastTimestamp;
414 }
415
416 @Override
417 public Definition lookupDefinition(String lookupPath) {
418 return null;
419 }
420 }
This page took 0.041527 seconds and 5 git commands to generate.