ctf: Make CTFTrace and its reader classes AutoCloseable
[deliverable/tracecompass.git] / org.eclipse.linuxtools.ctf.core / src / org / eclipse / linuxtools / ctf / core / trace / StreamInputPacketReader.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 import java.util.Collection;
17
18 import org.eclipse.linuxtools.ctf.core.CTFStrings;
19 import org.eclipse.linuxtools.ctf.core.event.EventDefinition;
20 import org.eclipse.linuxtools.ctf.core.event.IEventDeclaration;
21 import org.eclipse.linuxtools.ctf.core.event.io.BitBuffer;
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.EventDeclaration;
30 import org.eclipse.linuxtools.internal.ctf.core.trace.StreamInputPacketIndexEntry;
31
32 /**
33 * CTF trace packet reader. Reads the events of a packet of a trace file.
34 *
35 * @version 1.0
36 * @author Matthew Khouzam
37 * @author Simon Marchi
38 */
39 public class StreamInputPacketReader implements IDefinitionScope, AutoCloseable {
40
41 // ------------------------------------------------------------------------
42 // Attributes
43 // ------------------------------------------------------------------------
44
45 /** BitBuffer used to read the trace file. */
46 private final BitBuffer fBitBuffer;
47
48 /** StreamInputReader that uses this StreamInputPacketReader. */
49 private final StreamInputReader fStreamInputReader;
50
51 /** Trace packet header. */
52 private final StructDefinition fTracePacketHeaderDef;
53
54 /** Stream packet context definition. */
55 private final StructDefinition fStreamPacketContextDef;
56
57 /** Stream event header definition. */
58 private final StructDefinition fStreamEventHeaderDef;
59
60 /** Stream event context definition. */
61 private final StructDefinition fStreamEventContextDef;
62
63 /** Reference to the index entry of the current packet. */
64 private StreamInputPacketIndexEntry fCurrentPacket = null;
65
66 /**
67 * Last timestamp recorded.
68 *
69 * Needed to calculate the complete timestamp values for the events with
70 * compact headers.
71 */
72 private long fLastTimestamp = 0;
73
74 /** CPU id of current packet. */
75 private int fCurrentCpu = 0;
76
77 private int fLostEventsInThisPacket;
78
79 private long fLostEventsDuration;
80
81 private boolean fHasLost = false;
82
83 // ------------------------------------------------------------------------
84 // Constructors
85 // ------------------------------------------------------------------------
86
87 /**
88 * Constructs a StreamInputPacketReader.
89 *
90 * @param streamInputReader
91 * The StreamInputReader to which this packet reader belongs to.
92 */
93 public StreamInputPacketReader(StreamInputReader streamInputReader) {
94 fStreamInputReader = streamInputReader;
95
96 /* Set the BitBuffer's byte order. */
97 fBitBuffer = new BitBuffer();
98 fBitBuffer.setByteOrder(streamInputReader.getByteOrder());
99
100 /* Create trace packet header definition. */
101 final Stream currentStream = streamInputReader.getStreamInput().getStream();
102 StructDeclaration tracePacketHeaderDecl = currentStream.getTrace().getPacketHeader();
103 if (tracePacketHeaderDecl != null) {
104 fTracePacketHeaderDef = tracePacketHeaderDecl.createDefinition(this, "trace.packet.header"); //$NON-NLS-1$
105 } else {
106 fTracePacketHeaderDef = null;
107 }
108
109 /* Create stream packet context definition. */
110 StructDeclaration streamPacketContextDecl = currentStream.getPacketContextDecl();
111 if (streamPacketContextDecl != null) {
112 fStreamPacketContextDef = streamPacketContextDecl.createDefinition(this, "stream.packet.context"); //$NON-NLS-1$
113 } else {
114 fStreamPacketContextDef = null;
115 }
116
117 /* Create stream event header definition. */
118 StructDeclaration streamEventHeaderDecl = currentStream.getEventHeaderDecl();
119 if (streamEventHeaderDecl != null) {
120 fStreamEventHeaderDef = streamEventHeaderDecl.createDefinition(this, "stream.event.header"); //$NON-NLS-1$
121 } else {
122 fStreamEventHeaderDef = null;
123 }
124
125 /* Create stream event context definition. */
126 StructDeclaration streamEventContextDecl = currentStream.getEventContextDecl();
127 if (streamEventContextDecl != null) {
128 fStreamEventContextDef = streamEventContextDecl.createDefinition(this, "stream.event.context"); //$NON-NLS-1$
129 } else {
130 fStreamEventContextDef = null;
131 }
132
133 /* Create event definitions */
134 Collection<IEventDeclaration> eventDecls = streamInputReader.getStreamInput().getStream().getEvents().values();
135
136 for (IEventDeclaration event : eventDecls) {
137 if (!streamInputReader.getEventDefinitions().containsKey(event.getId())) {
138 EventDefinition eventDef = event.createDefinition(streamInputReader);
139 streamInputReader.addEventDefinition(event.getId(), eventDef);
140 }
141 }
142 }
143
144 /**
145 * Dispose the StreamInputPacketReader
146 *
147 * @since 3.0
148 */
149 @Override
150 public void close() {
151 fBitBuffer.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 fCurrentPacket;
165 }
166
167 /**
168 * Gets the steamPacketContext Definition
169 *
170 * @return steamPacketContext Definition
171 */
172 public StructDefinition getStreamPacketContextDef() {
173 return fStreamPacketContextDef;
174 }
175
176 /**
177 * Gets the stream's event context definition.
178 *
179 * @return The streamEventContext definition
180 */
181 public StructDefinition getStreamEventContextDef() {
182 return fStreamEventContextDef;
183 }
184
185 /**
186 * Gets the CPU (core) number
187 *
188 * @return the CPU (core) number
189 */
190 public int getCPU() {
191 return fCurrentCpu;
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 fCurrentPacket = currentPacket;
214
215 if (fCurrentPacket != null) {
216 /*
217 * Change the map of the BitBuffer.
218 */
219 ByteBuffer bb = null;
220 try {
221 bb = fStreamInputReader.getStreamInput().getByteBufferAt(
222 fCurrentPacket.getOffsetBytes(),
223 (fCurrentPacket.getPacketSizeBits() + 7) / 8);
224 } catch (IOException e) {
225 throw new CTFReaderException(e.getMessage(), e);
226 }
227
228 fBitBuffer.setByteBuffer(bb);
229
230 /*
231 * Read trace packet header.
232 */
233 if (fTracePacketHeaderDef != null) {
234 fTracePacketHeaderDef.read(fBitBuffer);
235 }
236
237 /*
238 * Read stream packet context.
239 */
240 if (getStreamPacketContextDef() != null) {
241 getStreamPacketContextDef().read(fBitBuffer);
242
243 /* Read CPU ID */
244 if (getCurrentPacket().getTarget() != null) {
245 fCurrentCpu = (int) getCurrentPacket().getTargetId();
246 }
247
248 /* Read number of lost events */
249 fLostEventsInThisPacket = (int) getCurrentPacket().getLostEvents();
250 if (fLostEventsInThisPacket != 0) {
251 fHasLost = true;
252 /*
253 * Compute the duration of the lost event time range. If the
254 * current packet is the first packet, duration will be set
255 * to 1.
256 */
257 long lostEventsStartTime;
258 int index = fStreamInputReader.getStreamInput().getIndex().getEntries().indexOf(currentPacket);
259 if (index == 0) {
260 lostEventsStartTime = currentPacket.getTimestampBegin() + 1;
261 } else {
262 prevPacket = fStreamInputReader.getStreamInput().getIndex().getEntries().get(index - 1);
263 lostEventsStartTime = prevPacket.getTimestampEnd();
264 }
265 fLostEventsDuration = Math.abs(lostEventsStartTime - currentPacket.getTimestampBegin());
266 }
267 }
268
269 /*
270 * Use the timestamp begin of the packet as the reference for the
271 * timestamp reconstitution.
272 */
273 fLastTimestamp = currentPacket.getTimestampBegin();
274 } else {
275 fBitBuffer.setByteBuffer(null);
276
277 fLastTimestamp = 0;
278 }
279 }
280
281 /**
282 * Returns whether it is possible to read any more events from this packet.
283 *
284 * @return True if it is possible to read any more events from this packet.
285 */
286 public boolean hasMoreEvents() {
287 if (fCurrentPacket != null) {
288 return fHasLost || (fBitBuffer.position() < fCurrentPacket.getContentSizeBits());
289 }
290 return false;
291 }
292
293 /**
294 * Reads the next event of the packet into the right event definition.
295 *
296 * @return The event definition containing the event data that was just
297 * read.
298 * @throws CTFReaderException
299 * If there was a problem reading the trace
300 */
301 public EventDefinition readNextEvent() throws CTFReaderException {
302 /* Default values for those fields */
303 long eventID = EventDeclaration.UNSET_EVENT_ID;
304 long timestamp = 0;
305 if (fHasLost) {
306 fHasLost = false;
307 EventDefinition eventDef = EventDeclaration.getLostEventDeclaration().createDefinition(fStreamInputReader);
308 ((IntegerDefinition) eventDef.getFields().getDefinitions().get(CTFStrings.LOST_EVENTS_FIELD)).setValue(fLostEventsInThisPacket);
309 ((IntegerDefinition) eventDef.getFields().getDefinitions().get(CTFStrings.LOST_EVENTS_DURATION)).setValue(fLostEventsDuration);
310 eventDef.setTimestamp(fLastTimestamp);
311 return eventDef;
312 }
313
314 final StructDefinition sehd = fStreamEventHeaderDef;
315 final BitBuffer currentBitBuffer = fBitBuffer;
316 final long posStart = currentBitBuffer.position();
317 /* Read the stream event header. */
318 if (sehd != null) {
319 sehd.read(currentBitBuffer);
320
321 /* Check for the event id. */
322 Definition idDef = sehd.lookupDefinition("id"); //$NON-NLS-1$
323 if (idDef instanceof SimpleDatatypeDefinition) {
324 eventID = ((SimpleDatatypeDefinition) idDef).getIntegerValue();
325 } else if (idDef != null) {
326 throw new CTFReaderException("Incorrect event id : " + eventID); //$NON-NLS-1$
327 }
328
329 /*
330 * Get the timestamp from the event header (may be overridden later
331 * on)
332 */
333 IntegerDefinition timestampDef = sehd.lookupInteger("timestamp"); //$NON-NLS-1$
334 if (timestampDef != null) {
335 timestamp = calculateTimestamp(timestampDef);
336 } // else timestamp remains 0
337
338 /* Check for the variant v. */
339 Definition variantDef = sehd.lookupDefinition("v"); //$NON-NLS-1$
340 if (variantDef instanceof VariantDefinition) {
341
342 /* Get the variant current field */
343 StructDefinition variantCurrentField = (StructDefinition) ((VariantDefinition) variantDef).getCurrentField();
344
345 /*
346 * Try to get the id field in the current field of the variant.
347 * If it is present, it overrides the previously read event id.
348 */
349 Definition idIntegerDef = variantCurrentField.lookupDefinition("id"); //$NON-NLS-1$
350 if (idIntegerDef instanceof IntegerDefinition) {
351 eventID = ((IntegerDefinition) idIntegerDef).getValue();
352 }
353
354 /*
355 * Get the timestamp. This would overwrite any previous
356 * timestamp definition
357 */
358 Definition def = variantCurrentField.lookupDefinition("timestamp"); //$NON-NLS-1$
359 if (def instanceof IntegerDefinition) {
360 timestamp = calculateTimestamp((IntegerDefinition) def);
361 }
362 }
363 }
364
365 /* Read the stream event context. */
366 if (fStreamEventContextDef != null) {
367 fStreamEventContextDef.read(currentBitBuffer);
368 }
369
370 /* Get the right event definition using the event id. */
371 EventDefinition eventDef = fStreamInputReader.getEventDefinitions().get(eventID);
372 if (eventDef == null) {
373 throw new CTFReaderException("Incorrect event id : " + eventID); //$NON-NLS-1$
374 }
375
376 /* Read the event context. */
377 if (eventDef.getEventContext() != null) {
378 eventDef.getEventContext().read(currentBitBuffer);
379 }
380
381 /* Read the event fields. */
382 if (eventDef.getFields() != null) {
383 eventDef.getFields().read(currentBitBuffer);
384 }
385
386 /*
387 * Set the event timestamp using the timestamp calculated by
388 * updateTimestamp.
389 */
390 eventDef.setTimestamp(timestamp);
391
392 if (posStart == currentBitBuffer.position()) {
393 throw new CTFReaderException("Empty event not allowed, event: " + eventDef.getDeclaration().getName()); //$NON-NLS-1$
394 }
395
396 return eventDef;
397 }
398
399 /**
400 * Calculates the timestamp value of the event, possibly using the timestamp
401 * from the last event.
402 *
403 * @param timestampDef
404 * Integer definition of the timestamp.
405 * @return The calculated timestamp value.
406 */
407 private long calculateTimestamp(IntegerDefinition timestampDef) {
408 long newval;
409 long majorasbitmask;
410 int len = timestampDef.getDeclaration().getLength();
411
412 /*
413 * If the timestamp length is 64 bits, it is a full timestamp.
414 */
415 if (timestampDef.getDeclaration().getLength() == 64) {
416 fLastTimestamp = timestampDef.getValue();
417 return fLastTimestamp;
418 }
419
420 /*
421 * Bit mask to keep / remove all old / new bits.
422 */
423 majorasbitmask = (1L << len) - 1;
424
425 /*
426 * If the new value is smaller than the corresponding bits of the last
427 * timestamp, we assume an overflow of the compact representation.
428 */
429 newval = timestampDef.getValue();
430 if (newval < (fLastTimestamp & majorasbitmask)) {
431 newval = newval + (1L << len);
432 }
433
434 /* Keep only the high bits of the old value */
435 fLastTimestamp = fLastTimestamp & ~majorasbitmask;
436
437 /* Then add the low bits of the new value */
438 fLastTimestamp = fLastTimestamp + newval;
439
440 return fLastTimestamp;
441 }
442
443 @Override
444 public Definition lookupDefinition(String lookupPath) {
445 return null;
446 }
447 }
This page took 0.040599 seconds and 5 git commands to generate.