07fa8d804dbadd4fb65eb29764487d99d96aa38e
[deliverable/tracecompass.git] / org.eclipse.linuxtools.ctf.core / src / org / eclipse / linuxtools / ctf / core / trace / CTFStreamInputPacketReader.java
1 /*******************************************************************************
2 * Copyright (c) 2011, 2014 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.ByteBuffer;
16
17 import org.eclipse.jdt.annotation.NonNull;
18 import org.eclipse.jdt.annotation.Nullable;
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.scope.IDefinitionScope;
24 import org.eclipse.linuxtools.ctf.core.event.scope.LexicalScope;
25 import org.eclipse.linuxtools.ctf.core.event.types.Definition;
26 import org.eclipse.linuxtools.ctf.core.event.types.ICompositeDefinition;
27 import org.eclipse.linuxtools.ctf.core.event.types.IDeclaration;
28 import org.eclipse.linuxtools.ctf.core.event.types.IDefinition;
29 import org.eclipse.linuxtools.ctf.core.event.types.IEventHeaderDeclaration;
30 import org.eclipse.linuxtools.ctf.core.event.types.IntegerDeclaration;
31 import org.eclipse.linuxtools.ctf.core.event.types.IntegerDefinition;
32 import org.eclipse.linuxtools.ctf.core.event.types.SimpleDatatypeDefinition;
33 import org.eclipse.linuxtools.ctf.core.event.types.StructDeclaration;
34 import org.eclipse.linuxtools.ctf.core.event.types.StructDefinition;
35 import org.eclipse.linuxtools.ctf.core.event.types.VariantDefinition;
36 import org.eclipse.linuxtools.internal.ctf.core.event.EventDeclaration;
37 import org.eclipse.linuxtools.internal.ctf.core.event.types.composite.EventHeaderDefinition;
38 import org.eclipse.linuxtools.internal.ctf.core.trace.StreamInputPacketIndexEntry;
39
40 import com.google.common.collect.ImmutableList;
41
42 /**
43 * CTF trace packet reader. Reads the events of a packet of a trace file.
44 *
45 * @author Matthew Khouzam
46 * @author Simon Marchi
47 * @since 3.0
48 */
49 public class CTFStreamInputPacketReader implements IDefinitionScope, AutoCloseable {
50
51 // ------------------------------------------------------------------------
52 // Attributes
53 // ------------------------------------------------------------------------
54
55 /** BitBuffer used to read the trace file. */
56 @Nullable
57 private BitBuffer fBitBuffer;
58
59 /** StreamInputReader that uses this StreamInputPacketReader. */
60 private final CTFStreamInputReader fStreamInputReader;
61
62 /** Trace packet header. */
63 private final StructDeclaration fTracePacketHeaderDecl;
64
65 /** Stream packet context definition. */
66 private final StructDeclaration fStreamPacketContextDecl;
67
68 /** Stream event header definition. */
69 private final IDeclaration fStreamEventHeaderDecl;
70
71 /** Stream event context definition. */
72 private final StructDeclaration fStreamEventContextDecl;
73
74 private ICompositeDefinition fCurrentTracePacketHeaderDef;
75 private ICompositeDefinition fCurrentStreamEventHeaderDef;
76 private ICompositeDefinition fCurrentStreamPacketContextDef;
77 /** Reference to the index entry of the current packet. */
78 private StreamInputPacketIndexEntry fCurrentPacket = null;
79
80 /**
81 * Last timestamp recorded.
82 *
83 * Needed to calculate the complete timestamp values for the events with
84 * compact headers.
85 */
86 private long fLastTimestamp = 0;
87
88 /** CPU id of current packet. */
89 private int fCurrentCpu = 0;
90
91 private int fLostEventsInThisPacket;
92
93 private long fLostEventsDuration;
94
95 private boolean fHasLost = false;
96
97 // ------------------------------------------------------------------------
98 // Constructors
99 // ------------------------------------------------------------------------
100
101 /**
102 * Constructs a StreamInputPacketReader.
103 *
104 * @param streamInputReader
105 * The StreamInputReader to which this packet reader belongs to.
106 */
107 public CTFStreamInputPacketReader(CTFStreamInputReader streamInputReader) {
108 fStreamInputReader = streamInputReader;
109
110 /* Set the BitBuffer's byte order. */
111 ByteBuffer allocateDirect = ByteBuffer.allocateDirect(0);
112 if (allocateDirect == null) {
113 throw new IllegalStateException("Unable to allocate 0 bytes!"); //$NON-NLS-1$
114 }
115 fBitBuffer = new BitBuffer(allocateDirect);
116
117 final CTFStream currentStream = streamInputReader.getStreamInput().getStream();
118 fTracePacketHeaderDecl = currentStream.getTrace().getPacketHeader();
119 fStreamPacketContextDecl = currentStream.getPacketContextDecl();
120 fStreamEventHeaderDecl = currentStream.getEventHeaderDeclaration();
121 fStreamEventContextDecl = currentStream.getEventContextDecl();
122 }
123
124 /**
125 * Get the event context defintiion
126 *
127 * @param input
128 * the bitbuffer to read from
129 * @return an context definition, can be null
130 * @throws CTFReaderException
131 * out of bounds exception or such
132 */
133 public StructDefinition getEventContextDefinition(@NonNull BitBuffer input) throws CTFReaderException {
134 return fStreamEventContextDecl.createDefinition(fStreamInputReader.getStreamInput(), LexicalScope.STREAM_EVENT_CONTEXT, input);
135 }
136
137 /**
138 * Get the stream context defintiion
139 *
140 * @param input
141 * the bitbuffer to read from
142 * @return an context definition, can be null
143 * @throws CTFReaderException
144 * out of bounds exception or such
145 * @deprecated it was not used
146 */
147 @Deprecated
148 public StructDefinition getStreamEventHeaderDefinition(@NonNull BitBuffer input) throws CTFReaderException {
149 if (!(fStreamEventHeaderDecl instanceof StructDeclaration)) {
150 throw new IllegalStateException("Definition is not a struct definition, this is a deprecated method that doesn't work so well, stop using it."); //$NON-NLS-1$
151 }
152 return ((StructDeclaration) fStreamEventHeaderDecl).createDefinition(this, LexicalScope.STREAM_EVENT_HEADER, input);
153 }
154
155 /**
156 * Get the packet context defintiion
157 *
158 * @param input
159 * the bitbuffer to read from
160 * @return an context definition, can be null
161 * @throws CTFReaderException
162 * out of bounds exception or such
163 */
164 public StructDefinition getStreamPacketContextDefinition(@NonNull BitBuffer input) throws CTFReaderException {
165 return fStreamPacketContextDecl.createDefinition(fStreamInputReader.getStreamInput(), LexicalScope.STREAM_PACKET_CONTEXT, input);
166 }
167
168 /**
169 * Get the event header defintiion
170 *
171 * @param input
172 * the bitbuffer to read from
173 * @return an header definition, can be null
174 * @throws CTFReaderException
175 * out of bounds exception or such
176 */
177 public StructDefinition getTracePacketHeaderDefinition(@NonNull BitBuffer input) throws CTFReaderException {
178 return fTracePacketHeaderDecl.createDefinition(fStreamInputReader.getStreamInput().getStream().getTrace(), LexicalScope.TRACE_PACKET_HEADER, input);
179 }
180
181 /**
182 * Dispose the StreamInputPacketReader
183 */
184 @Override
185 public void close() {
186 fBitBuffer = null;
187 }
188
189 // ------------------------------------------------------------------------
190 // Getters/Setters/Predicates
191 // ------------------------------------------------------------------------
192
193 /**
194 * Gets the current packet
195 *
196 * @return the current packet
197 */
198 StreamInputPacketIndexEntry getCurrentPacket() {
199 return fCurrentPacket;
200 }
201
202 /**
203 * Gets the CPU (core) number
204 *
205 * @return the CPU (core) number
206 */
207 public int getCPU() {
208 return fCurrentCpu;
209 }
210
211 @Override
212 public LexicalScope getScopePath() {
213 return LexicalScope.PACKET;
214 }
215
216 // ------------------------------------------------------------------------
217 // Operations
218 // ------------------------------------------------------------------------
219
220 /**
221 * Changes the current packet to the given one.
222 *
223 * @param currentPacket
224 * The index entry of the packet to switch to.
225 * @throws CTFReaderException
226 * If we get an error reading the packet
227 */
228 void setCurrentPacket(StreamInputPacketIndexEntry currentPacket) throws CTFReaderException {
229 StreamInputPacketIndexEntry prevPacket = null;
230 fCurrentPacket = currentPacket;
231
232 if (fCurrentPacket != null) {
233 /*
234 * Change the map of the BitBuffer.
235 */
236 ByteBuffer bb = null;
237 try {
238 bb = fStreamInputReader.getStreamInput().getByteBufferAt(
239 fCurrentPacket.getOffsetBytes(),
240 (fCurrentPacket.getPacketSizeBits() + 7) / 8);
241 } catch (IOException e) {
242 throw new CTFReaderException(e.getMessage(), e);
243 }
244
245 BitBuffer bitBuffer = new BitBuffer(bb);
246 fBitBuffer = bitBuffer;
247 /*
248 * Read trace packet header.
249 */
250 if (fTracePacketHeaderDecl != null) {
251 fCurrentTracePacketHeaderDef = getTracePacketHeaderDefinition(bitBuffer);
252 }
253
254 /*
255 * Read stream packet context.
256 */
257 if (fStreamPacketContextDecl != null) {
258 fCurrentStreamPacketContextDef = getStreamPacketContextDefinition(bitBuffer);
259
260 /* Read CPU ID */
261 if (getCurrentPacket().getTarget() != null) {
262 fCurrentCpu = (int) getCurrentPacket().getTargetId();
263 }
264
265 /* Read number of lost events */
266 fLostEventsInThisPacket = (int) getCurrentPacket().getLostEvents();
267 if (fLostEventsInThisPacket != 0) {
268 fHasLost = true;
269 /*
270 * Compute the duration of the lost event time range. If the
271 * current packet is the first packet, duration will be set
272 * to 1.
273 */
274 long lostEventsStartTime;
275 int index = fStreamInputReader.getStreamInput().getIndex().getEntries().indexOf(currentPacket);
276 if (index == 0) {
277 lostEventsStartTime = currentPacket.getTimestampBegin() + 1;
278 } else {
279 prevPacket = fStreamInputReader.getStreamInput().getIndex().getEntries().get(index - 1);
280 lostEventsStartTime = prevPacket.getTimestampEnd();
281 }
282 fLostEventsDuration = Math.abs(lostEventsStartTime - currentPacket.getTimestampBegin());
283 }
284 }
285
286 /*
287 * Use the timestamp begin of the packet as the reference for the
288 * timestamp reconstitution.
289 */
290 fLastTimestamp = currentPacket.getTimestampBegin();
291 } else {
292 fBitBuffer = null;
293 fLastTimestamp = 0;
294 }
295 }
296
297 /**
298 * Returns whether it is possible to read any more events from this packet.
299 *
300 * @return True if it is possible to read any more events from this packet.
301 */
302 public boolean hasMoreEvents() {
303 BitBuffer bitBuffer = fBitBuffer;
304 StreamInputPacketIndexEntry currentPacket = fCurrentPacket;
305 if (currentPacket != null && bitBuffer != null) {
306 return fHasLost || (bitBuffer.position() < currentPacket.getContentSizeBits());
307 }
308 return false;
309 }
310
311 /**
312 * Reads the next event of the packet into the right event definition.
313 *
314 * @return The event definition containing the event data that was just
315 * read.
316 * @throws CTFReaderException
317 * If there was a problem reading the trace
318 */
319 public EventDefinition readNextEvent() throws CTFReaderException {
320 /* Default values for those fields */
321 long eventID = EventDeclaration.UNSET_EVENT_ID;
322 long timestamp = 0;
323 if (fHasLost) {
324 fHasLost = false;
325 EventDeclaration lostEventDeclaration = EventDeclaration.getLostEventDeclaration();
326 StructDeclaration lostFields = lostEventDeclaration.getFields();
327 // this is a hard coded map, we know it's not null
328 IntegerDeclaration lostFieldsDecl = (IntegerDeclaration) lostFields.getField(CTFStrings.LOST_EVENTS_FIELD);
329 if (lostFieldsDecl == null)
330 {
331 throw new IllegalStateException("Lost events count not declared!"); //$NON-NLS-1$
332 }
333 IntegerDeclaration lostEventsDurationDecl = (IntegerDeclaration) lostFields.getField(CTFStrings.LOST_EVENTS_DURATION);
334 if (lostEventsDurationDecl == null) {
335 throw new IllegalStateException("Lost events duration not declared!"); //$NON-NLS-1$
336 }
337 IntegerDefinition lostDurationDef = new IntegerDefinition(lostFieldsDecl, null, CTFStrings.LOST_EVENTS_DURATION, fLostEventsDuration);
338 IntegerDefinition lostCountDef = new IntegerDefinition(lostEventsDurationDecl, null, CTFStrings.LOST_EVENTS_FIELD, fLostEventsInThisPacket);
339 IntegerDefinition[] fields = new IntegerDefinition[] { lostCountDef, lostDurationDef };
340 /* this is weird notation, but it's the java notation */
341 final ImmutableList<String> fieldNameList = ImmutableList.<String> builder().add(CTFStrings.LOST_EVENTS_FIELD).add(CTFStrings.LOST_EVENTS_DURATION).build();
342 return new EventDefinition(
343 lostEventDeclaration,
344 fStreamInputReader,
345 fLastTimestamp,
346 null,
347 null,
348 null,
349 new StructDefinition(
350 lostFields,
351 this, "fields", //$NON-NLS-1$
352 fieldNameList,
353 fields
354 ));
355
356 }
357
358 final BitBuffer currentBitBuffer = fBitBuffer;
359 if (currentBitBuffer == null) {
360 return null;
361 }
362 final long posStart = currentBitBuffer.position();
363 /* Read the stream event header. */
364 if (fStreamEventHeaderDecl != null) {
365 if (fStreamEventHeaderDecl instanceof IEventHeaderDeclaration) {
366 fCurrentStreamEventHeaderDef = (ICompositeDefinition) fStreamEventHeaderDecl.createDefinition(null, "", currentBitBuffer); //$NON-NLS-1$
367 EventHeaderDefinition ehd = (EventHeaderDefinition) fCurrentStreamEventHeaderDef;
368 eventID = ehd.getId();
369 timestamp = calculateTimestamp(ehd.getTimestamp(), ehd.getTimestampLength());
370 } else {
371 fCurrentStreamEventHeaderDef = ((StructDeclaration) fStreamEventHeaderDecl).createDefinition(null, LexicalScope.EVENT_HEADER, currentBitBuffer);
372 StructDefinition StructEventHeaderDef = (StructDefinition) fCurrentStreamEventHeaderDef;
373 /* Check for the event id. */
374 IDefinition idDef = StructEventHeaderDef.lookupDefinition("id"); //$NON-NLS-1$
375 SimpleDatatypeDefinition simpleIdDef = null;
376 if (idDef instanceof SimpleDatatypeDefinition) {
377 simpleIdDef = ((SimpleDatatypeDefinition) idDef);
378 } else if (idDef != null) {
379 throw new CTFReaderException("Id defintion not an integer, enum or float definiton in event header."); //$NON-NLS-1$
380 }
381
382 /*
383 * Get the timestamp from the event header (may be overridden
384 * later on)
385 */
386 IntegerDefinition timestampDef = StructEventHeaderDef.lookupInteger("timestamp"); //$NON-NLS-1$
387
388 /* Check for the variant v. */
389 IDefinition variantDef = StructEventHeaderDef.lookupDefinition("v"); //$NON-NLS-1$
390 if (variantDef instanceof VariantDefinition) {
391
392 /* Get the variant current field */
393 StructDefinition variantCurrentField = (StructDefinition) ((VariantDefinition) variantDef).getCurrentField();
394
395 /*
396 * Try to get the id field in the current field of the
397 * variant. If it is present, it overrides the previously
398 * read event id.
399 */
400 IDefinition vIdDef = variantCurrentField.lookupDefinition("id"); //$NON-NLS-1$
401 if (vIdDef instanceof IntegerDefinition) {
402 simpleIdDef = (SimpleDatatypeDefinition) vIdDef;
403 }
404
405 /*
406 * Get the timestamp. This would overwrite any previous
407 * timestamp definition
408 */
409 timestampDef = variantCurrentField.lookupInteger("timestamp"); //$NON-NLS-1$
410 }
411 if (simpleIdDef != null) {
412 eventID = simpleIdDef.getIntegerValue();
413 }
414 if (timestampDef != null) {
415 timestamp = calculateTimestamp(timestampDef);
416 } // else timestamp remains 0
417 }
418 }
419 /* Get the right event definition using the event id. */
420 IEventDeclaration eventDeclaration = fStreamInputReader.getStreamInput().getStream().getEvents().get(eventID);
421 if (eventDeclaration == null) {
422 throw new CTFReaderException("Incorrect event id : " + eventID); //$NON-NLS-1$
423 }
424 EventDefinition eventDef = eventDeclaration.createDefinition(fStreamInputReader, currentBitBuffer, timestamp);
425
426 /*
427 * Set the event timestamp using the timestamp calculated by
428 * updateTimestamp.
429 */
430
431 if (posStart == currentBitBuffer.position()) {
432 throw new CTFReaderException("Empty event not allowed, event: " + eventDef.getDeclaration().getName()); //$NON-NLS-1$
433 }
434
435 return eventDef;
436 }
437
438 /**
439 * Calculates the timestamp value of the event, possibly using the timestamp
440 * from the last event.
441 *
442 * @param timestampDef
443 * Integer definition of the timestamp.
444 * @return The calculated timestamp value.
445 */
446 private long calculateTimestamp(IntegerDefinition timestampDef) {
447 int len = timestampDef.getDeclaration().getLength();
448 final long value = timestampDef.getValue();
449
450 return calculateTimestamp(value, len);
451 }
452
453 private long calculateTimestamp(final long value, int len) {
454 long newval;
455 long majorasbitmask;
456 /*
457 * If the timestamp length is 64 bits, it is a full timestamp.
458 */
459 if (len == 64) {
460 fLastTimestamp = value;
461 return fLastTimestamp;
462 }
463
464 /*
465 * Bit mask to keep / remove all old / new bits.
466 */
467 majorasbitmask = (1L << len) - 1;
468
469 /*
470 * If the new value is smaller than the corresponding bits of the last
471 * timestamp, we assume an overflow of the compact representation.
472 */
473 newval = value;
474 if (newval < (fLastTimestamp & majorasbitmask)) {
475 newval = newval + (1L << len);
476 }
477
478 /* Keep only the high bits of the old value */
479 fLastTimestamp = fLastTimestamp & ~majorasbitmask;
480
481 /* Then add the low bits of the new value */
482 fLastTimestamp = fLastTimestamp + newval;
483
484 return fLastTimestamp;
485 }
486
487 @Override
488 public Definition lookupDefinition(String lookupPath) {
489 if (lookupPath.equals(LexicalScope.STREAM_PACKET_CONTEXT.toString())) {
490 return (Definition) fCurrentStreamPacketContextDef;
491 }
492 if (lookupPath.equals(LexicalScope.TRACE_PACKET_HEADER.toString())) {
493 return (Definition) fCurrentTracePacketHeaderDef;
494 }
495 return null;
496 }
497
498 /**
499 * Get stream event header
500 *
501 * @return the stream event header
502 * @deprecated use
503 * {@link CTFStreamInputPacketReader#getStreamEventHeaderDefinition()}
504 */
505 @Deprecated
506 public StructDefinition getCurrentStreamEventHeader() {
507 return (StructDefinition) ((fCurrentStreamEventHeaderDef instanceof StructDefinition) ? fCurrentStreamEventHeaderDef : null);
508 }
509
510 /**
511 * Get stream event header
512 *
513 * @return the stream event header
514 * @since 3.1
515 */
516 public ICompositeDefinition getStreamEventHeaderDefinition() {
517 return fCurrentStreamEventHeaderDef;
518 }
519
520 /**
521 * Get the current packet event header
522 *
523 * @return the current packet event header
524 */
525 public StructDefinition getCurrentPacketEventHeader() {
526 if (fCurrentTracePacketHeaderDef instanceof StructDefinition) {
527 return (StructDefinition) fCurrentTracePacketHeaderDef;
528 }
529 return null;
530 }
531 }
This page took 0.041384 seconds and 4 git commands to generate.