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