ctf: Fix lost events in a more elegant way
[deliverable/tracecompass.git] / org.eclipse.linuxtools.ctf.core / src / org / eclipse / linuxtools / ctf / core / trace / StreamInputPacketReader.java
1 /*******************************************************************************
2 * Copyright (c) 2011-2012 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.EventDeclaration;
21 import org.eclipse.linuxtools.ctf.core.event.EventDefinition;
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.io.BitBuffer;
30 import org.eclipse.linuxtools.internal.ctf.core.trace.Stream;
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 // Constants
44 // ------------------------------------------------------------------------
45
46 /**
47 * Reference to the index entry of the current packet.
48 */
49 private StreamInputPacketIndexEntry currentPacket = null;
50
51 /**
52 * BitBuffer used to read the trace file.
53 */
54 private final BitBuffer bitBuffer = new BitBuffer();
55
56 /**
57 * StreamInputReader that uses this StreamInputPacketReader.
58 */
59 private final StreamInputReader streamInputReader;
60
61 /**
62 * Last timestamp recorded.
63 *
64 * Needed to calculate the complete timestamp values for the events with
65 * compact headers.
66 */
67 private long lastTimestamp = 0;
68
69 /**
70 * Trace packet header.
71 */
72 private StructDefinition tracePacketHeaderDef = null;
73
74 /**
75 * Stream packet context definition.
76 */
77 private StructDefinition streamPacketContextDef = null;
78
79 /**
80 * Stream event header definition.
81 */
82 private StructDefinition streamEventHeaderDef = null;
83
84 /**
85 * Stream event context definition.
86 */
87 private StructDefinition streamEventContextDef = null;
88
89 /**
90 * Maps event ID to event definitions.
91 */
92 private final HashMap<Long, EventDefinition> events;
93
94 /**
95 * CPU id of current packet.
96 */
97 private int currentCpu = 0;
98
99 /**
100 * number of lost events in this packet
101 */
102 private int lostSoFar;
103
104 private int lostEventsInThisPacket;
105
106 // ------------------------------------------------------------------------
107 // Attributes
108 // ------------------------------------------------------------------------
109
110 /**
111 * Constructs a StreamInputPacketReader.
112 *
113 * @param streamInputReader
114 * The StreamInputReader to which this packet reader belongs to.
115 */
116 public StreamInputPacketReader(StreamInputReader streamInputReader) {
117 this.streamInputReader = streamInputReader;
118
119 /*
120 * Set the BitBuffer's byte order.
121 */
122 getBitBuffer().setByteOrder(streamInputReader.getByteOrder());
123
124 events = streamInputReader.getStreamInput().getStream().getTrace()
125 .getEventDefs(streamInputReader.getStreamInput());
126 /*
127 * Create definitions needed to read the events.
128 */
129 createDefinitions();
130
131 lostSoFar = 0;
132 }
133
134 // ------------------------------------------------------------------------
135 // Constructors
136 // ------------------------------------------------------------------------
137
138 // ------------------------------------------------------------------------
139 // Getters/Setters/Predicates
140 // ------------------------------------------------------------------------
141
142 /**
143 * Gets the current packet
144 *
145 * @return the current packet
146 */
147 public StreamInputPacketIndexEntry getCurrentPacket() {
148 return this.currentPacket;
149 }
150
151 /**
152 * Gets the steamPacketContext Definition
153 *
154 * @return steamPacketContext Definition
155 */
156 public StructDefinition getStreamPacketContextDef() {
157 return this.streamPacketContextDef;
158 }
159
160 /**
161 * Gets the CPU (core) number
162 *
163 * @return the CPU (core) number
164 */
165 public int getCPU() {
166 return this.currentCpu;
167 }
168
169 @Override
170 public String getPath() {
171 return ""; //$NON-NLS-1$
172 }
173
174 // ------------------------------------------------------------------------
175 // Operations
176 // ------------------------------------------------------------------------
177
178 /**
179 * Creates definitions needed to read events (stream-defined and
180 * event-defined).
181 */
182 private void createDefinitions() {
183 /*
184 * Create trace packet header definition.
185 */
186 final Stream currentStream = getStreamInputReader().getStreamInput()
187 .getStream();
188 StructDeclaration tracePacketHeaderDecl = currentStream.getTrace()
189 .getPacketHeader();
190 if (tracePacketHeaderDecl != null) {
191 setTracePacketHeaderDef(tracePacketHeaderDecl.createDefinition(
192 this, "trace.packet.header")); //$NON-NLS-1$
193 }
194
195 /*
196 * Create stream packet context definition.
197 */
198 StructDeclaration streamPacketContextDecl = currentStream
199 .getPacketContextDecl();
200 if (streamPacketContextDecl != null) {
201 setStreamPacketContextDef(streamPacketContextDecl.createDefinition(
202 this, "stream.packet.context")); //$NON-NLS-1$
203 }
204
205 /*
206 * Create stream event header definition.
207 */
208 StructDeclaration streamEventHeaderDecl = currentStream
209 .getEventHeaderDecl();
210 if (streamEventHeaderDecl != null) {
211 setStreamEventHeaderDef(streamEventHeaderDecl.createDefinition(
212 this, "stream.event.header")); //$NON-NLS-1$
213 }
214
215 /*
216 * Create stream event context definition.
217 */
218 StructDeclaration streamEventContextDecl = currentStream
219 .getEventContextDecl();
220 if (streamEventContextDecl != null) {
221 setStreamEventContextDef(streamEventContextDecl.createDefinition(
222 this, "stream.event.context")); //$NON-NLS-1$
223 }
224
225 createEventDefinitions();
226 }
227
228 /**
229 * Creates definitions needed to read the event. (event-defined).
230 */
231 private void createEventDefinitions() {
232 Collection<EventDeclaration> eventDecls = getStreamInputReader()
233 .getStreamInput().getStream().getEvents().values();
234
235 /*
236 * Create definitions for each event.
237 */
238 for (EventDeclaration event : eventDecls) {
239 if (!events.containsKey(event.getId())) {
240 EventDefinition eventDef = event
241 .createDefinition(getStreamInputReader());
242 events.put(event.getId(), eventDef);
243 }
244 }
245 }
246
247 /**
248 * Changes the current packet to the given one.
249 *
250 * @param currentPacket
251 * The index entry of the packet to switch to.
252 */
253 public void setCurrentPacket(StreamInputPacketIndexEntry currentPacket) {
254 this.currentPacket = currentPacket;
255
256 if (this.currentPacket != null) {
257 /*
258 * Change the map of the BitBuffer.
259 */
260 MappedByteBuffer bb = null;
261 try {
262 bb = getStreamInputReader()
263 .getStreamInput()
264 .getFileChannel()
265 .map(MapMode.READ_ONLY,
266 this.currentPacket.getOffsetBytes(),
267 (this.currentPacket.getPacketSizeBits() + 7) / 8);
268 } catch (IOException e) {
269 /*
270 * The streamInputReader object is already allocated, so this
271 * shouldn't fail bar some very bad kernel or RAM errors...
272 */
273 e.printStackTrace();
274 }
275
276 getBitBuffer().setByteBuffer(bb);
277
278 /*
279 * Read trace packet header.
280 */
281 if (getTracePacketHeaderDef() != null) {
282 getTracePacketHeaderDef().read(getBitBuffer());
283 }
284
285 /*
286 * Read stream packet context.
287 */
288 if (getStreamPacketContextDef() != null) {
289 getStreamPacketContextDef().read(getBitBuffer());
290
291 /* Read CPU ID */
292 if (this.getCurrentPacket().getTarget() != null) {
293 this.currentCpu = (int) this.getCurrentPacket().getTargetId();
294 }
295
296 /* Read number of lost events */
297 lostEventsInThisPacket = (int) this.getCurrentPacket().getLostEvents();
298 lostSoFar = 0;
299
300 }
301
302 /*
303 * Use the timestamp begin of the packet as the reference for the
304 * timestamp reconstitution.
305 */
306 lastTimestamp = currentPacket.getTimestampBegin();
307 } else {
308 getBitBuffer().setByteBuffer(null);
309
310 lastTimestamp = 0;
311 }
312 }
313
314 /**
315 * Returns whether it is possible to read any more events from this packet.
316 *
317 * @return True if it is possible to read any more events from this packet.
318 */
319 public boolean hasMoreEvents() {
320 if (currentPacket != null) {
321 return getBitBuffer().position() < currentPacket
322 .getContentSizeBits();
323 }
324 return false;
325 }
326
327 /**
328 * Reads the next event of the packet into the right event definition.
329 *
330 * @return The event definition containing the event data that was just
331 * read.
332 * @throws CTFReaderException
333 * If there was a problem reading the trace
334 */
335 public EventDefinition readNextEvent() throws CTFReaderException {
336 /* WARNING: This is still LTTng-specific. */
337 Long eventID = null;
338 long timestamp = 0;
339
340 if (lostEventsInThisPacket > lostSoFar) {
341 EventDefinition eventDef = EventDeclaration
342 .getLostEventDeclaration().createDefinition(
343 streamInputReader);
344 eventDef.setTimestamp(this.lastTimestamp);
345 ++lostSoFar;
346 return eventDef;
347 }
348
349 StructDefinition sehd = getStreamEventHeaderDef(); // acronym for a long
350 // variable name
351 BitBuffer currentBitBuffer = getBitBuffer();
352 /*
353 * Read the stream event header.
354 */
355
356 if (sehd != null) {
357 sehd.read(currentBitBuffer);
358
359 /*
360 * Check for an event id.
361 */
362 SimpleDatatypeDefinition idDef = (SimpleDatatypeDefinition) sehd
363 .lookupDefinition("id"); //$NON-NLS-1$
364 IntegerDefinition timestampDef = sehd.lookupInteger("timestamp"); //$NON-NLS-1$
365 eventID = idDef.getIntegerValue();
366
367 /*
368 * Check for the variant v.
369 */
370 VariantDefinition variantDef = (VariantDefinition) sehd
371 .lookupDefinition("v"); //$NON-NLS-1$
372 if (variantDef != null) {
373
374 /*
375 * Get the variant current field
376 */
377 StructDefinition variantCurrentField = (StructDefinition) variantDef
378 .getCurrentField();
379
380 /*
381 * Try to get the id field in the current field of the variant.
382 * If it is present, it overrides the previously read event id.
383 */
384 IntegerDefinition idIntegerDef = (IntegerDefinition) variantCurrentField
385 .lookupDefinition("id"); //$NON-NLS-1$
386 if (idIntegerDef != null) {
387 eventID = idIntegerDef.getValue();
388 }
389 /*
390 * Get the timestamp.
391 */
392 timestampDef = (IntegerDefinition) variantCurrentField
393 .lookupDefinition("timestamp"); //$NON-NLS-1$
394
395 }
396
397 /*
398 * Calculate the event timestamp.
399 */
400 timestamp = calculateTimestamp(timestampDef);
401 }
402
403 /*
404 * Read the stream event context.
405 */
406 if (getStreamEventContextDef() != null) {
407 getStreamEventContextDef().read(currentBitBuffer);
408 }
409
410 /*
411 * Get the right event definition using the event id.
412 */
413 EventDefinition eventDef = events.get(eventID);
414 if (eventDef == null) {
415 throw new CTFReaderException("Incorrect event id : " + eventID); //$NON-NLS-1$
416 }
417
418 /*
419 * Read the event context.
420 */
421 if (eventDef.getContext() != null) {
422 eventDef.getContext().read(currentBitBuffer);
423 }
424
425 /*
426 * Read the event fields.
427 */
428 if (eventDef.getFields() != null) {
429 eventDef.getFields().read(currentBitBuffer);
430 }
431
432 /*
433 * Set the event timestamp using the timestamp calculated by
434 * updateTimestamp.
435 */
436 eventDef.setTimestamp(timestamp);
437
438 return eventDef;
439 }
440
441 /**
442 * Calculates the timestamp value of the event, possibly using the timestamp
443 * from the last event.
444 *
445 * @param timestampDef
446 * Integer definition of the timestamp.
447 * @return The calculated timestamp value.
448 */
449 private long calculateTimestamp(IntegerDefinition timestampDef) {
450 long newval;
451 long majorasbitmask;
452 int len = timestampDef.getDeclaration().getLength();
453
454 /*
455 * If the timestamp length is 64 bits, it is a full timestamp.
456 */
457 if (timestampDef.getDeclaration().getLength() == 64) {
458 lastTimestamp = timestampDef.getValue();
459 return lastTimestamp;
460 }
461
462 /*
463 * Bit mask to keep / remove all old / new bits.
464 */
465 majorasbitmask = (1L << len) - 1;
466
467 /*
468 * If the new value is smaller than the corresponding bits of the last
469 * timestamp, we assume an overflow of the compact representation.
470 */
471 newval = timestampDef.getValue();
472 if (newval < (lastTimestamp & majorasbitmask)) {
473 newval = newval + (1L << len);
474 }
475
476 /* Keep only the high bits of the old value */
477 lastTimestamp = lastTimestamp & ~majorasbitmask;
478
479 /* Then add the low bits of the new value */
480 lastTimestamp = lastTimestamp + newval;
481
482 return lastTimestamp;
483 }
484
485 @Override
486 public Definition lookupDefinition(String lookupPath) {
487 // TODO Auto-generated method stub
488 return null;
489 }
490
491 /**
492 * Gets the stream event context definition (see CTF specs)
493 *
494 * @return the definition of the stream event context (the form not the
495 * content)
496 */
497 public StructDefinition getStreamEventContextDef() {
498 return this.streamEventContextDef;
499 }
500
501 /**
502 * Sets the stream event context definition
503 *
504 * @param streamEventContextDef
505 * The stream event context definition
506 */
507 public void setStreamEventContextDef(StructDefinition streamEventContextDef) {
508 this.streamEventContextDef = streamEventContextDef;
509 }
510
511 /**
512 * Gets the stream event header definition
513 *
514 * @return the stream event header definition
515 */
516 public StructDefinition getStreamEventHeaderDef() {
517 return this.streamEventHeaderDef;
518 }
519
520 /**
521 * Sets the stream event header definition
522 *
523 * @param streamEventHeaderDef
524 * the stream event header definition
525 */
526 public void setStreamEventHeaderDef(StructDefinition streamEventHeaderDef) {
527 this.streamEventHeaderDef = streamEventHeaderDef;
528 }
529
530 /**
531 * Sets the stream packet context definition
532 *
533 * @param streamPacketContextDef
534 * the stream packet context definition
535 */
536 public void setStreamPacketContextDef(
537 StructDefinition streamPacketContextDef) {
538 this.streamPacketContextDef = streamPacketContextDef;
539 }
540
541 /**
542 * Gets the trace packet header definition
543 *
544 * @return the trace packet header definition
545 */
546 public StructDefinition getTracePacketHeaderDef() {
547 return this.tracePacketHeaderDef;
548 }
549
550 /**
551 * Sets the trace packet header definition
552 *
553 * @param tracePacketHeaderDef
554 * the trace packet header definition
555 */
556 public void setTracePacketHeaderDef(StructDefinition tracePacketHeaderDef) {
557 this.tracePacketHeaderDef = tracePacketHeaderDef;
558 }
559
560 /**
561 * @return the parent stream input reader
562 */
563 public StreamInputReader getStreamInputReader() {
564 return this.streamInputReader;
565 }
566
567 /**
568 *
569 * @return THe bit buffer that reads the file.
570 */
571 public BitBuffer getBitBuffer() {
572 return bitBuffer;
573 }
574 }
This page took 0.04637 seconds and 5 git commands to generate.