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