58b833263d2b6db5ee306359051572d7d0e30849
[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 /*
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
233 bitBuffer.setByteBuffer(bb);
234
235 /*
236 * Read trace packet header.
237 */
238 if (tracePacketHeaderDef != null) {
239 tracePacketHeaderDef.read(bitBuffer);
240 }
241
242 /*
243 * Read stream packet context.
244 */
245 if (getStreamPacketContextDef() != null) {
246 getStreamPacketContextDef().read(bitBuffer);
247
248 /* Read CPU ID */
249 if (this.getCurrentPacket().getTarget() != null) {
250 this.currentCpu = (int) this.getCurrentPacket().getTargetId();
251 }
252
253 /* Read number of lost events */
254 lostEventsInThisPacket = (int) this.getCurrentPacket().getLostEvents();
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 }
272 }
273
274 /*
275 * Use the timestamp begin of the packet as the reference for the
276 * timestamp reconstitution.
277 */
278 lastTimestamp = currentPacket.getTimestampBegin();
279 } else {
280 bitBuffer.setByteBuffer(null);
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) {
293 return hasLost || (bitBuffer.position() < currentPacket.getContentSizeBits());
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
304 * If there was a problem reading the trace
305 */
306 public EventDefinition readNextEvent() throws CTFReaderException {
307 /* Default values for those fields */
308 long eventID = EventDeclaration.UNSET_EVENT_ID;
309 long timestamp = 0;
310 if (hasLost) {
311 hasLost = false;
312 EventDefinition eventDef = EventDeclaration.getLostEventDeclaration().createDefinition(streamInputReader);
313 ((IntegerDefinition) eventDef.getFields().getDefinitions().get(CTFStrings.LOST_EVENTS_FIELD)).setValue(lostEventsInThisPacket);
314 ((IntegerDefinition) eventDef.getFields().getDefinitions().get(CTFStrings.LOST_EVENTS_DURATION)).setValue(lostEventsDuration);
315 eventDef.setTimestamp(this.lastTimestamp);
316 return eventDef;
317 }
318
319 final StructDefinition sehd = streamEventHeaderDef;
320 final BitBuffer currentBitBuffer = bitBuffer;
321
322 /* Read the stream event header. */
323 if (sehd != null) {
324 sehd.read(currentBitBuffer);
325
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
331
332 /*
333 * Get the timestamp from the event header (may be overridden later
334 * on)
335 */
336 IntegerDefinition timestampDef = sehd.lookupInteger("timestamp"); //$NON-NLS-1$
337 if (timestampDef != null) {
338 timestamp = calculateTimestamp(timestampDef);
339 } // else timestamp remains 0
340
341 /* Check for the variant v. */
342 Definition variantDef = sehd.lookupDefinition("v"); //$NON-NLS-1$
343 if (variantDef instanceof VariantDefinition) {
344
345 /* Get the variant current field */
346 StructDefinition variantCurrentField = (StructDefinition) ((VariantDefinition) variantDef).getCurrentField();
347
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 */
352 Definition idIntegerDef = variantCurrentField.lookupDefinition("id"); //$NON-NLS-1$
353 if (idIntegerDef instanceof IntegerDefinition) {
354 eventID = ((IntegerDefinition) idIntegerDef).getValue();
355 }
356
357 /*
358 * Get the timestamp. This would overwrite any previous
359 * timestamp definition
360 */
361 Definition def = variantCurrentField.lookupDefinition("timestamp"); //$NON-NLS-1$
362 if (def instanceof IntegerDefinition) {
363 timestamp = calculateTimestamp((IntegerDefinition) def);
364 }
365 }
366 }
367
368 /* Read the stream event context. */
369 if (streamEventContextDef != null) {
370 streamEventContextDef.read(currentBitBuffer);
371 }
372
373 /* Get the right event definition using the event id. */
374 EventDefinition eventDef = streamInputReader.getEventDefinitions().get(eventID);
375 if (eventDef == null) {
376 throw new CTFReaderException("Incorrect event id : " + eventID); //$NON-NLS-1$
377 }
378
379 /* Read the event context. */
380 if (eventDef.getEventContext() != null) {
381 eventDef.getEventContext().read(currentBitBuffer);
382 }
383
384 /* Read the event fields. */
385 if (eventDef.getFields() != null) {
386 eventDef.getFields().read(currentBitBuffer);
387 }
388
389 /*
390 * Set the event timestamp using the timestamp calculated by
391 * updateTimestamp.
392 */
393 eventDef.setTimestamp(timestamp);
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) {
444 return null;
445 }
446 }
This page took 0.041815 seconds and 5 git commands to generate.