ctf: support event-header-less traces
[deliverable/tracecompass.git] / ctf / org.eclipse.tracecompass.ctf.core / src / org / eclipse / tracecompass / ctf / core / trace / CTFStreamInputReader.java
1 /*******************************************************************************
2 * Copyright (c) 2011, 2015 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
13 package org.eclipse.tracecompass.ctf.core.trace;
14
15 import java.io.File;
16 import java.io.IOException;
17 import java.nio.ByteBuffer;
18 import java.nio.channels.FileChannel;
19 import java.nio.channels.FileChannel.MapMode;
20 import java.nio.file.StandardOpenOption;
21 import java.util.List;
22
23 import org.eclipse.jdt.annotation.NonNullByDefault;
24 import org.eclipse.jdt.annotation.Nullable;
25 import org.eclipse.tracecompass.common.core.NonNullUtils;
26 import org.eclipse.tracecompass.ctf.core.CTFException;
27 import org.eclipse.tracecompass.ctf.core.event.EventDefinition;
28 import org.eclipse.tracecompass.ctf.core.event.IEventDeclaration;
29 import org.eclipse.tracecompass.ctf.core.event.io.BitBuffer;
30 import org.eclipse.tracecompass.ctf.core.event.types.IDeclaration;
31 import org.eclipse.tracecompass.ctf.core.event.types.StructDeclaration;
32 import org.eclipse.tracecompass.internal.ctf.core.Activator;
33 import org.eclipse.tracecompass.internal.ctf.core.SafeMappedByteBuffer;
34 import org.eclipse.tracecompass.internal.ctf.core.trace.CTFPacketReader;
35 import org.eclipse.tracecompass.internal.ctf.core.trace.NullPacketReader;
36
37 /**
38 * A CTF trace event reader. Reads the events of a trace file.
39 *
40 * @author Matthew Khouzam
41 * @author Simon Marchi
42 * @since 2.0
43 */
44 @NonNullByDefault
45 public class CTFStreamInputReader implements AutoCloseable {
46
47 private static final int BITS_PER_BYTE = Byte.SIZE;
48
49 // ------------------------------------------------------------------------
50 // Attributes
51 // ------------------------------------------------------------------------
52
53 /**
54 * The StreamInput we are reading.
55 */
56 private final File fFile;
57
58 private final CTFStreamInput fStreamInput;
59
60 private final @Nullable FileChannel fFileChannel;
61
62 /**
63 * The packet reader used to read packets from this trace file.
64 */
65 private IPacketReader fPacketReader;
66
67 /**
68 * Iterator on the packet index
69 */
70 private int fPacketIndex;
71
72 /**
73 * Reference to the current event of this trace file (iow, the last on that
74 * was read, the next one to be returned)
75 */
76 private @Nullable EventDefinition fCurrentEvent = null;
77
78 private int fId;
79
80 /**
81 * Live trace reading
82 */
83 private boolean fLive = false;
84
85 // ------------------------------------------------------------------------
86 // Constructors
87 // ------------------------------------------------------------------------
88 /**
89 * Constructs a StreamInputReader that reads a StreamInput.
90 *
91 * @param streamInput
92 * The StreamInput to read.
93 * @throws CTFException
94 * If the file cannot be opened
95 */
96 public CTFStreamInputReader(CTFStreamInput streamInput) throws CTFException {
97 fStreamInput = streamInput;
98 fFile = fStreamInput.getFile();
99 try {
100 fFileChannel = FileChannel.open(fFile.toPath(), StandardOpenOption.READ);
101 } catch (IOException e) {
102 throw new CTFIOException(e);
103 }
104 try {
105 /*
106 * Get the iterator on the packet index.
107 */
108 fPacketIndex = 0;
109 /*
110 * Make first packet the current one.
111 */
112 // did we already index the packet?
113 if (getPacketSize() < (fPacketIndex + 1)) {
114 // go to the next packet if there is one, index it at the same
115 // time
116 if (fStreamInput.addPacketHeaderIndex()) {
117 fPacketIndex = getPacketSize() - 1;
118 }
119 }
120 ICTFPacketDescriptor packet = getPacket();
121 fPacketReader = getCurrentPacketReader(packet);
122 } catch (Exception e) {
123 try {
124 close();
125 } catch (IOException e1) {
126 // Ignore
127 }
128 throw e;
129 }
130 }
131
132 private IPacketReader getCurrentPacketReader(@Nullable ICTFPacketDescriptor packet) throws CTFException {
133 IPacketReader ctfPacketReader = NullPacketReader.INSTANCE;
134 if (packet != null) {
135 long size = packet.getContentSizeBits();
136 if (size < 0) {
137 throw new CTFIOException("Cannot have negative sized buffers."); //$NON-NLS-1$
138 }
139 BitBuffer bitBuffer = new BitBuffer(getByteBufferAt(packet.getOffsetBits(), size));
140 bitBuffer.position(packet.getPayloadStartBits());
141 IDeclaration eventHeaderDeclaration = getStreamInput().getStream().getEventHeaderDeclaration();
142 CTFTrace trace = getStreamInput().getStream().getTrace();
143 ctfPacketReader = new CTFPacketReader(bitBuffer, packet, getEventDeclarations(), eventHeaderDeclaration, getStreamEventContextDecl(), trace.getPacketHeaderDef(), trace);
144 }
145 return ctfPacketReader;
146 }
147
148 /**
149 * Get a bytebuffer map of the file
150 *
151 * @param position
152 * start offset in bits
153 * @param size
154 * size of the map in bits, use caution
155 * @return a byte buffer
156 * @throws CTFException
157 * if the map failed in its allocation
158 *
159 * @since 2.0
160 */
161 public ByteBuffer getByteBufferAt(long position, long size) throws CTFException {
162 ByteBuffer map;
163 try {
164 map = SafeMappedByteBuffer.map(fFileChannel, MapMode.READ_ONLY, position / BITS_PER_BYTE, (size + BITS_PER_BYTE - 1) / BITS_PER_BYTE);
165 } catch (IOException e) {
166 throw new CTFIOException(e.getMessage(), e);
167 }
168 if (map == null) {
169 throw new CTFIOException("Failed to allocate mapped byte buffer"); //$NON-NLS-1$
170 }
171 return map;
172 }
173
174 /**
175 * Dispose the StreamInputReader, closes the file channel and its packet
176 * reader
177 *
178 * @throws IOException
179 * If an I/O error occurs
180 */
181 @Override
182 public void close() throws IOException {
183 if (fFileChannel != null) {
184 fFileChannel.close();
185 }
186 fPacketReader = NullPacketReader.INSTANCE;
187 }
188
189 // ------------------------------------------------------------------------
190 // Getters/Setters/Predicates
191 // ------------------------------------------------------------------------
192
193 /**
194 * Gets the current event in this stream
195 *
196 * @return the current event in the stream, null if the stream is
197 * finished/empty/malformed
198 */
199 public @Nullable EventDefinition getCurrentEvent() {
200 return fCurrentEvent;
201 }
202
203 /**
204 * Gets the name of the stream (it's an id and a number)
205 *
206 * @return gets the stream name (it's a number)
207 */
208 public int getName() {
209 return fId;
210 }
211
212 /**
213 * Sets the name of the stream
214 *
215 * @param name
216 * the name of the stream, (it's a number)
217 */
218 public void setName(int name) {
219 fId = name;
220 }
221
222 /**
223 * Gets the CPU of a stream. It's the same as the one in /proc or running
224 * the asm CPUID instruction
225 *
226 * @return The CPU id (a number)
227 */
228 public int getCPU() {
229 return fPacketReader.getCPU();
230 }
231
232 /**
233 * Gets the filename of the stream being read
234 *
235 * @return The filename of the stream being read
236 */
237 public String getFilename() {
238 return fStreamInput.getFilename();
239 }
240
241 /*
242 * for internal use only
243 */
244 CTFStreamInput getStreamInput() {
245 return fStreamInput;
246 }
247
248 /**
249 * Gets the event definition set for this StreamInput
250 *
251 * @return Unmodifiable set with the event definitions
252 * @since 2.0
253 */
254 public List<@Nullable IEventDeclaration> getEventDeclarations() {
255 return fStreamInput.getStream().getEventDeclarations();
256 }
257
258 /**
259 * Set the trace to live mode
260 *
261 * @param live
262 * whether the trace is read live or not
263 */
264 public void setLive(boolean live) {
265 fLive = live;
266 }
267
268 /**
269 * Get if the trace is to read live or not
270 *
271 * @return whether the trace is live or not
272 */
273 public boolean isLive() {
274 return fLive;
275 }
276
277 /**
278 * Get the event context of the stream
279 *
280 * @return the event context declaration of the stream
281 */
282 public @Nullable StructDeclaration getStreamEventContextDecl() {
283 return getStreamInput().getStream().getEventContextDecl();
284 }
285
286 // ------------------------------------------------------------------------
287 // Operations
288 // ------------------------------------------------------------------------
289 /**
290 * Reads the next event in the current event variable.
291 *
292 * @return If an event has been successfully read.
293 * @throws CTFException
294 * if an error occurs
295 */
296 public CTFResponse readNextEvent() throws CTFException {
297
298 /*
299 * Change packet if needed
300 */
301 if (!fPacketReader.hasMoreEvents()) {
302 final ICTFPacketDescriptor prevPacket = fPacketReader.getCurrentPacket();
303 if (prevPacket != null || fLive) {
304 goToNextPacket();
305 }
306
307 }
308
309 /*
310 * If an event is available, read it.
311 */
312 if (fPacketReader.hasMoreEvents()) {
313 setCurrentEvent(fPacketReader.readNextEvent());
314 return CTFResponse.OK;
315 }
316 this.setCurrentEvent(null);
317 return fLive ? CTFResponse.WAIT : CTFResponse.FINISH;
318 }
319
320 /**
321 * Change the current packet of the packet reader to the next one.
322 *
323 * @throws CTFException
324 * if an error occurs
325 */
326 private void goToNextPacket() throws CTFException {
327 fPacketIndex++;
328 // did we already index the packet?
329 while (getPacketSize() < (fPacketIndex + 1)) {
330 // go to the next packet if there is one, index it at the same time
331 if (fStreamInput.addPacketHeaderIndex()) {
332 fPacketIndex = getPacketSize() - 1;
333 } else {
334 fPacketReader = NullPacketReader.INSTANCE;
335 return;
336 }
337
338 }
339 ICTFPacketDescriptor packet = getPacket();
340 fPacketReader = getCurrentPacketReader(packet);
341
342 }
343
344 /**
345 * @return
346 */
347 private int getPacketSize() {
348 return fStreamInput.getIndex().size();
349 }
350
351 /**
352 * Changes the location of the trace file reader so that the current event
353 * is the first event with a timestamp greater or equal the given timestamp.
354 *
355 * @param timestamp
356 * The timestamp to seek to.
357 * @return The offset compared to the current position
358 * @throws CTFException
359 * if an error occurs
360 */
361 public long seek(long timestamp) throws CTFException {
362 long offset = 0;
363
364 gotoPacket(timestamp);
365
366 /*
367 * index up to the desired timestamp.
368 */
369 while ((fPacketReader.getCurrentPacket() != null)
370 && (fPacketReader.getCurrentPacket().getTimestampEnd() < timestamp)) {
371 try {
372 fStreamInput.addPacketHeaderIndex();
373 goToNextPacket();
374 } catch (CTFException e) {
375 // do nothing here
376 Activator.log(e.getMessage());
377 }
378 }
379 if (fPacketReader.getCurrentPacket() == null) {
380 gotoPacket(timestamp);
381 }
382
383 /*
384 * Advance until either of these conditions are met:
385 *
386 * - reached the end of the trace file (the given timestamp is after the
387 * last event)
388 *
389 * - found the first event with a timestamp greater or equal the given
390 * timestamp.
391 */
392 readNextEvent();
393 EventDefinition currentEvent = getCurrentEvent();
394 while (currentEvent != null && (currentEvent.getTimestamp() < timestamp)) {
395 readNextEvent();
396 currentEvent = getCurrentEvent();
397 offset++;
398 }
399 return offset;
400 }
401
402 /**
403 * @param timestamp
404 * the time to seek
405 * @throws CTFException
406 * if an error occurs
407 */
408 private void gotoPacket(long timestamp) throws CTFException {
409 fPacketIndex = fStreamInput.getIndex().search(timestamp) - 1;
410 /*
411 * Switch to this packet.
412 */
413 goToNextPacket();
414 }
415
416 /**
417 * Seeks the last event of a stream and returns it.
418 *
419 * @throws CTFException
420 * if an error occurs
421 */
422 public void goToLastEvent() throws CTFException {
423
424 /*
425 * Go to the beginning of the trace
426 */
427 seek(0);
428
429 /*
430 * Check that there is at least one event
431 */
432 if ((fStreamInput.getIndex().isEmpty()) || (!fPacketReader.hasMoreEvents())) {
433 /*
434 * This means the trace is empty. abort.
435 */
436 return;
437 }
438
439 fPacketIndex = fStreamInput.getIndex().size() - 1;
440 /*
441 * Go to last indexed packet
442 */
443 fPacketReader = getCurrentPacketReader(getPacket());
444
445 /*
446 * Keep going until you cannot
447 */
448 while (fPacketReader.getCurrentPacket() != null) {
449 goToNextPacket();
450 }
451
452 final int lastPacketIndex = fStreamInput.getIndex().size() - 1;
453 /*
454 * Go to the last packet that contains events.
455 */
456 for (int pos = lastPacketIndex; pos > 0; pos--) {
457 fPacketIndex = pos;
458 fPacketReader = getCurrentPacketReader(getPacket());
459
460 if (fPacketReader.hasMoreEvents()) {
461 break;
462 }
463 }
464
465 /*
466 * Go until the end of that packet
467 */
468 EventDefinition prevEvent = null;
469 while (fCurrentEvent != null) {
470 prevEvent = fCurrentEvent;
471 this.readNextEvent();
472 }
473 /*
474 * Go back to the previous event
475 */
476 this.setCurrentEvent(prevEvent);
477 }
478
479 /**
480 * Sets the current event in a stream input reader
481 *
482 * @param currentEvent
483 * the event to set
484 */
485 public void setCurrentEvent(@Nullable EventDefinition currentEvent) {
486 fCurrentEvent = currentEvent;
487 }
488
489 /**
490 * @return the packetIndexIt
491 */
492 private int getPacketIndex() {
493 return fPacketIndex;
494 }
495
496 private @Nullable ICTFPacketDescriptor getPacket() {
497 if (getPacketIndex() >= fStreamInput.getIndex().size()) {
498 return null;
499 }
500 return fStreamInput.getIndex().getElement(getPacketIndex());
501 }
502
503 /**
504 * Get the current packet reader
505 *
506 * @return the packetReader
507 * @since 2.0
508 */
509 public IPacketReader getCurrentPacketReader() {
510 return fPacketReader;
511 }
512
513 @Override
514 public int hashCode() {
515 final int prime = 31;
516 int result = 1;
517 result = (prime * result) + fId;
518 result = (prime * result)
519 + fFile.hashCode();
520 return result;
521 }
522
523 @Override
524 public boolean equals(@Nullable Object obj) {
525 if (this == obj) {
526 return true;
527 }
528 if (obj == null) {
529 return false;
530 }
531 if (!(obj instanceof CTFStreamInputReader)) {
532 return false;
533 }
534 CTFStreamInputReader other = (CTFStreamInputReader) obj;
535 if (fId != other.fId) {
536 return false;
537 }
538 return fFile.equals(other.fFile);
539 }
540
541 @Override
542 public String toString() {
543 // this helps debugging
544 return fId + ' ' + NonNullUtils.nullToEmptyString(fCurrentEvent);
545 }
546
547 }
This page took 0.054437 seconds and 5 git commands to generate.