CTF: Add support for custom attributes in an event
[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 import java.util.HashMap;
19
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 /** Maps event ID to event definitions. */
65 private final HashMap<Long, EventDefinition> events;
66
67 /** Reference to the index entry of the current packet. */
68 private StreamInputPacketIndexEntry currentPacket = null;
69
70 /**
71 * Last timestamp recorded.
72 *
73 * Needed to calculate the complete timestamp values for the events with
74 * compact headers.
75 */
76 private long lastTimestamp = 0;
77
78 /** CPU id of current packet. */
79 private int currentCpu = 0;
80
81 /** number of lost events in this packet */
82 private int lostSoFar;
83
84 private int lostEventsInThisPacket;
85
86 // ------------------------------------------------------------------------
87 // Constructors
88 // ------------------------------------------------------------------------
89
90 /**
91 * Constructs a StreamInputPacketReader.
92 *
93 * @param streamInputReader
94 * The StreamInputReader to which this packet reader belongs to.
95 */
96 public StreamInputPacketReader(StreamInputReader streamInputReader) {
97 this.streamInputReader = streamInputReader;
98
99 /* Set the BitBuffer's byte order. */
100 bitBuffer = new BitBuffer();
101 bitBuffer.setByteOrder(streamInputReader.getByteOrder());
102
103 events = streamInputReader.getStreamInput().getStream().getTrace().getEventDefs(streamInputReader.getStreamInput());
104 lostSoFar = 0;
105
106 /* Create trace packet header definition. */
107 final Stream currentStream = streamInputReader.getStreamInput().getStream();
108 StructDeclaration tracePacketHeaderDecl = currentStream.getTrace().getPacketHeader();
109 if (tracePacketHeaderDecl != null) {
110 tracePacketHeaderDef = tracePacketHeaderDecl.createDefinition(this, "trace.packet.header"); //$NON-NLS-1$
111 } else {
112 tracePacketHeaderDef = null;
113 }
114
115 /* Create stream packet context definition. */
116 StructDeclaration streamPacketContextDecl = currentStream.getPacketContextDecl();
117 if (streamPacketContextDecl != null) {
118 streamPacketContextDef = streamPacketContextDecl.createDefinition(this, "stream.packet.context"); //$NON-NLS-1$
119 } else {
120 streamPacketContextDef = null;
121 }
122
123 /* Create stream event header definition. */
124 StructDeclaration streamEventHeaderDecl = currentStream.getEventHeaderDecl();
125 if (streamEventHeaderDecl != null) {
126 streamEventHeaderDef = streamEventHeaderDecl.createDefinition(this, "stream.event.header"); //$NON-NLS-1$
127 } else {
128 streamEventHeaderDef = null;
129 }
130
131 /* Create stream event context definition. */
132 StructDeclaration streamEventContextDecl = currentStream.getEventContextDecl();
133 if (streamEventContextDecl != null) {
134 streamEventContextDef = streamEventContextDecl.createDefinition(this, "stream.event.context"); //$NON-NLS-1$
135 } else {
136 streamEventContextDef = null;
137 }
138
139 /* Create event definitions */
140 Collection<IEventDeclaration> eventDecls = streamInputReader.getStreamInput().getStream().getEvents().values();
141
142 for (IEventDeclaration event : eventDecls) {
143 if (!events.containsKey(event.getId())) {
144 EventDefinition eventDef = event.createDefinition(streamInputReader);
145 events.put(event.getId(), eventDef);
146 }
147 }
148 }
149
150 /**
151 * Dispose the StreamInputPacketReader
152 * @since 2.0
153 */
154 public void dispose() {
155 bitBuffer.setByteBuffer(null);
156 }
157
158 // ------------------------------------------------------------------------
159 // Getters/Setters/Predicates
160 // ------------------------------------------------------------------------
161
162 /**
163 * Gets the current packet
164 *
165 * @return the current packet
166 */
167 StreamInputPacketIndexEntry getCurrentPacket() {
168 return this.currentPacket;
169 }
170
171 /**
172 * Gets the steamPacketContext Definition
173 *
174 * @return steamPacketContext Definition
175 */
176 public StructDefinition getStreamPacketContextDef() {
177 return this.streamPacketContextDef;
178 }
179
180 /**
181 * Gets the stream's event context definition.
182 *
183 * @return The streamEventContext definition
184 */
185 public StructDefinition getStreamEventContextDef() {
186 return streamEventContextDef;
187 }
188
189 /**
190 * Gets the CPU (core) number
191 *
192 * @return the CPU (core) number
193 */
194 public int getCPU() {
195 return this.currentCpu;
196 }
197
198 @Override
199 public String getPath() {
200 return ""; //$NON-NLS-1$
201 }
202
203 // ------------------------------------------------------------------------
204 // Operations
205 // ------------------------------------------------------------------------
206
207 /**
208 * Changes the current packet to the given one.
209 *
210 * @param currentPacket
211 * The index entry of the packet to switch to.
212 */
213 void setCurrentPacket(StreamInputPacketIndexEntry currentPacket) {
214 this.currentPacket = currentPacket;
215
216 if (this.currentPacket != null) {
217 /*
218 * Change the map of the BitBuffer.
219 */
220 MappedByteBuffer bb = null;
221 try {
222 bb = streamInputReader.getStreamInput().getFileChannel()
223 .map(MapMode.READ_ONLY,
224 this.currentPacket.getOffsetBytes(),
225 (this.currentPacket.getPacketSizeBits() + 7) / 8);
226 } catch (IOException e) {
227 /*
228 * The streamInputReader object is already allocated, so this
229 * shouldn't fail bar some very bad kernel or RAM errors...
230 */
231 e.printStackTrace();
232 }
233
234 bitBuffer.setByteBuffer(bb);
235
236 /*
237 * Read trace packet header.
238 */
239 if (tracePacketHeaderDef != null) {
240 tracePacketHeaderDef.read(bitBuffer);
241 }
242
243 /*
244 * Read stream packet context.
245 */
246 if (getStreamPacketContextDef() != null) {
247 getStreamPacketContextDef().read(bitBuffer);
248
249 /* Read CPU ID */
250 if (this.getCurrentPacket().getTarget() != null) {
251 this.currentCpu = (int) this.getCurrentPacket().getTargetId();
252 }
253
254 /* Read number of lost events */
255 lostEventsInThisPacket = (int) this.getCurrentPacket().getLostEvents();
256 lostSoFar = 0;
257
258 }
259
260 /*
261 * Use the timestamp begin of the packet as the reference for the
262 * timestamp reconstitution.
263 */
264 lastTimestamp = currentPacket.getTimestampBegin();
265 } else {
266 bitBuffer.setByteBuffer(null);
267
268 lastTimestamp = 0;
269 }
270 }
271
272 /**
273 * Returns whether it is possible to read any more events from this packet.
274 *
275 * @return True if it is possible to read any more events from this packet.
276 */
277 public boolean hasMoreEvents() {
278 if (currentPacket != null) {
279 return bitBuffer.position() < currentPacket.getContentSizeBits();
280 }
281 return false;
282 }
283
284 /**
285 * Reads the next event of the packet into the right event definition.
286 *
287 * @return The event definition containing the event data that was just
288 * read.
289 * @throws CTFReaderException
290 * If there was a problem reading the trace
291 */
292 public EventDefinition readNextEvent() throws CTFReaderException {
293 /* Default values for those fields */
294 long eventID = 0;
295 long timestamp = 0;
296
297 if (lostEventsInThisPacket > lostSoFar) {
298 EventDefinition eventDef = EventDeclaration.getLostEventDeclaration().createDefinition(streamInputReader);
299 eventDef.setTimestamp(this.lastTimestamp);
300 ++lostSoFar;
301 return eventDef;
302 }
303
304 final StructDefinition sehd = streamEventHeaderDef;
305 final BitBuffer currentBitBuffer = bitBuffer;
306
307 /* Read the stream event header. */
308 if (sehd != null) {
309 sehd.read(currentBitBuffer);
310
311 /* Check for the event id. */
312 Definition idDef = sehd.lookupDefinition("id"); //$NON-NLS-1$
313 if (idDef instanceof SimpleDatatypeDefinition) {
314 eventID = ((SimpleDatatypeDefinition) idDef).getIntegerValue();
315 } // else, eventID remains 0
316
317 /* Get the timestamp from the event header (may be overridden later on) */
318 Definition timestampDef = sehd.lookupInteger("timestamp"); //$NON-NLS-1$
319 if (timestampDef instanceof IntegerDefinition) {
320 timestamp = calculateTimestamp((IntegerDefinition) timestampDef);
321 } // else timestamp remains 0
322
323 /* Check for the variant v. */
324 Definition variantDef = sehd.lookupDefinition("v"); //$NON-NLS-1$
325 if (variantDef instanceof VariantDefinition) {
326
327 /* Get the variant current field */
328 StructDefinition variantCurrentField = (StructDefinition) ((VariantDefinition) variantDef).getCurrentField();
329
330 /*
331 * Try to get the id field in the current field of the variant.
332 * If it is present, it overrides the previously read event id.
333 */
334 Definition idIntegerDef = variantCurrentField.lookupDefinition("id"); //$NON-NLS-1$
335 if (idIntegerDef instanceof IntegerDefinition) {
336 eventID = ((IntegerDefinition) idIntegerDef).getValue();
337 }
338
339 /* Get the timestamp. This would overwrite any previous timestamp definition */
340 timestampDef = variantCurrentField.lookupDefinition("timestamp"); //$NON-NLS-1$
341 if (timestampDef instanceof IntegerDefinition) {
342 timestamp = calculateTimestamp((IntegerDefinition) timestampDef);
343 }
344 }
345 }
346
347 /* Read the stream event context. */
348 if (streamEventContextDef != null) {
349 streamEventContextDef.read(currentBitBuffer);
350 }
351
352 /* Get the right event definition using the event id. */
353 EventDefinition eventDef = events.get(eventID);
354 if (eventDef == null) {
355 throw new CTFReaderException("Incorrect event id : " + eventID); //$NON-NLS-1$
356 }
357
358 /* Read the event context. */
359 if (eventDef.getContext() != null) {
360 eventDef.getContext().read(currentBitBuffer);
361 }
362
363 /* Read the event fields. */
364 if (eventDef.getFields() != null) {
365 eventDef.getFields().read(currentBitBuffer);
366 }
367
368 /*
369 * Set the event timestamp using the timestamp calculated by
370 * updateTimestamp.
371 */
372 eventDef.setTimestamp(timestamp);
373
374 return eventDef;
375 }
376
377 /**
378 * Calculates the timestamp value of the event, possibly using the timestamp
379 * from the last event.
380 *
381 * @param timestampDef
382 * Integer definition of the timestamp.
383 * @return The calculated timestamp value.
384 */
385 private long calculateTimestamp(IntegerDefinition timestampDef) {
386 long newval;
387 long majorasbitmask;
388 int len = timestampDef.getDeclaration().getLength();
389
390 /*
391 * If the timestamp length is 64 bits, it is a full timestamp.
392 */
393 if (timestampDef.getDeclaration().getLength() == 64) {
394 lastTimestamp = timestampDef.getValue();
395 return lastTimestamp;
396 }
397
398 /*
399 * Bit mask to keep / remove all old / new bits.
400 */
401 majorasbitmask = (1L << len) - 1;
402
403 /*
404 * If the new value is smaller than the corresponding bits of the last
405 * timestamp, we assume an overflow of the compact representation.
406 */
407 newval = timestampDef.getValue();
408 if (newval < (lastTimestamp & majorasbitmask)) {
409 newval = newval + (1L << len);
410 }
411
412 /* Keep only the high bits of the old value */
413 lastTimestamp = lastTimestamp & ~majorasbitmask;
414
415 /* Then add the low bits of the new value */
416 lastTimestamp = lastTimestamp + newval;
417
418 return lastTimestamp;
419 }
420
421 @Override
422 public Definition lookupDefinition(String lookupPath) {
423 // TODO Auto-generated method stub
424 return null;
425 }
426 }
This page took 0.040874 seconds and 6 git commands to generate.