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