tmf: Fix rounding error in seekEvent by ratio for TextTrace class
[deliverable/tracecompass.git] / ctf / org.eclipse.tracecompass.ctf.core / src / org / eclipse / tracecompass / ctf / core / trace / CTFTraceReader.java
CommitLineData
866e5b51 1/*******************************************************************************
93a45b54 2 * Copyright (c) 2011, 2014 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 *
4311ac8b
MAL
9 * Contributors:
10 * Matthew Khouzam - Initial API and implementation
11 * Alexandre Montplaisir - Initial API and implementation
866e5b51
FC
12 *******************************************************************************/
13
f357bcd4 14package org.eclipse.tracecompass.ctf.core.trace;
866e5b51 15
b3151232 16import java.io.IOException;
0594c61c 17import java.util.ArrayList;
6a0ec7bc 18import java.util.Collections;
fe75d403 19import java.util.HashSet;
0594c61c 20import java.util.List;
866e5b51
FC
21import java.util.PriorityQueue;
22import java.util.Set;
866e5b51 23
680f9173 24import org.eclipse.tracecompass.ctf.core.CTFException;
f357bcd4
AM
25import org.eclipse.tracecompass.ctf.core.event.EventDefinition;
26import org.eclipse.tracecompass.ctf.core.event.IEventDeclaration;
27import org.eclipse.tracecompass.internal.ctf.core.Activator;
28import org.eclipse.tracecompass.internal.ctf.core.trace.StreamInputReaderTimestampComparator;
ce2388e0 29
53359017
MK
30import com.google.common.collect.ImmutableSet;
31import com.google.common.collect.ImmutableSet.Builder;
32
866e5b51 33/**
d37aaa7f 34 * A CTF trace reader. Reads the events of a trace.
1d7277f3 35 *
d37aaa7f
FC
36 * @version 1.0
37 * @author Matthew Khouzam
38 * @author Alexandre Montplaisir
866e5b51 39 */
dd9752d5 40public class CTFTraceReader implements AutoCloseable {
866e5b51 41
f068c622
MK
42 private static final int LINE_LENGTH = 60;
43
fe75d403
MK
44 private static final int MIN_PRIO_SIZE = 16;
45
866e5b51
FC
46 // ------------------------------------------------------------------------
47 // Attributes
48 // ------------------------------------------------------------------------
49
50 /**
51 * The trace to read from.
52 */
93a45b54 53 private final CTFTrace fTrace;
866e5b51
FC
54
55 /**
56 * Vector of all the trace file readers.
57 */
6a0ec7bc
AM
58 private final List<CTFStreamInputReader> fStreamInputReaders =
59 Collections.synchronizedList(new ArrayList<CTFStreamInputReader>());
866e5b51
FC
60
61 /**
62 * Priority queue to order the trace file readers by timestamp.
63 */
d84419e1 64 private PriorityQueue<CTFStreamInputReader> fPrio;
866e5b51
FC
65
66 /**
67 * Array to count the number of event per trace file.
68 */
93a45b54 69 private long[] fEventCountPerTraceFile;
866e5b51
FC
70
71 /**
72 * Timestamp of the first event in the trace
73 */
93a45b54 74 private long fStartTime;
866e5b51
FC
75
76 /**
77 * Timestamp of the last event read so far
78 */
93a45b54 79 private long fEndTime;
866e5b51 80
545d9101
RB
81 /**
82 * Boolean to indicate if the CTFTraceReader has been closed
83 */
84 private boolean fClosed = false;
85
866e5b51
FC
86 // ------------------------------------------------------------------------
87 // Constructors
88 // ------------------------------------------------------------------------
89
90 /**
91 * Constructs a TraceReader to read a trace.
92 *
93 * @param trace
94 * The trace to read from.
680f9173 95 * @throws CTFException
db8e8f7d 96 * if an error occurs
866e5b51 97 */
680f9173 98 public CTFTraceReader(CTFTrace trace) throws CTFException {
93a45b54
MK
99 fTrace = trace;
100 fStreamInputReaders.clear();
866e5b51
FC
101
102 /**
103 * Create the trace file readers.
104 */
105 createStreamInputReaders();
106
107 /**
108 * Populate the timestamp-based priority queue.
109 */
110 populateStreamInputReaderHeap();
111
112 /**
bfe038ff
MK
113 * Get the start Time of this trace bear in mind that the trace could be
114 * empty.
866e5b51 115 */
93a45b54 116 fStartTime = 0;
33656d8e 117 if (hasMoreEvents()) {
0af5eb9a 118 fStartTime = getTopStream().getCurrentEvent().getTimestamp();
93a45b54 119 setEndTime(fStartTime);
33656d8e 120 }
866e5b51
FC
121 }
122
123 /**
124 * Copy constructor
be6df2d8
AM
125 *
126 * @return The new CTFTraceReader
680f9173 127 * @throws CTFException
6a5251eb 128 * if an error occurs
866e5b51 129 */
680f9173 130 public CTFTraceReader copyFrom() throws CTFException {
866e5b51
FC
131 CTFTraceReader newReader = null;
132
93a45b54
MK
133 newReader = new CTFTraceReader(fTrace);
134 newReader.fStartTime = fStartTime;
135 newReader.setEndTime(fEndTime);
866e5b51
FC
136 return newReader;
137 }
138
5d1c6919
PT
139 /**
140 * Dispose the CTFTraceReader
5d1c6919 141 */
dd9752d5
AM
142 @Override
143 public void close() {
6a0ec7bc
AM
144 synchronized (fStreamInputReaders) {
145 for (CTFStreamInputReader reader : fStreamInputReaders) {
146 if (reader != null) {
147 try {
148 reader.close();
149 } catch (IOException e) {
150 Activator.logError(e.getMessage(), e);
151 }
b3151232 152 }
5d1c6919 153 }
6a0ec7bc 154 fStreamInputReaders.clear();
5d1c6919 155 }
74d66aa3 156 fPrio.clear();
545d9101 157 fClosed = true;
5d1c6919
PT
158 }
159
866e5b51
FC
160 // ------------------------------------------------------------------------
161 // Getters/Setters/Predicates
162 // ------------------------------------------------------------------------
163
164 /**
165 * Return the start time of this trace (== timestamp of the first event)
166 *
0d9a6d76 167 * @return the trace start time
866e5b51
FC
168 */
169 public long getStartTime() {
93a45b54 170 return fStartTime;
866e5b51
FC
171 }
172
6f4e8ec0
AM
173 /**
174 * Set the trace's end time
175 *
176 * @param endTime
177 * The end time to use
178 */
0594c61c 179 protected final void setEndTime(long endTime) {
93a45b54 180 fEndTime = endTime;
6f4e8ec0
AM
181 }
182
0594c61c
AM
183 /**
184 * Get the priority queue of this trace reader.
185 *
186 * @return The priority queue of input readers
0594c61c 187 */
d84419e1 188 protected PriorityQueue<CTFStreamInputReader> getPrio() {
93a45b54 189 return fPrio;
0594c61c
AM
190 }
191
866e5b51
FC
192 // ------------------------------------------------------------------------
193 // Operations
194 // ------------------------------------------------------------------------
195
196 /**
197 * Creates one trace file reader per trace file contained in the trace.
db8e8f7d 198 *
680f9173 199 * @throws CTFException
db8e8f7d 200 * if an error occurs
866e5b51 201 */
680f9173 202 private void createStreamInputReaders() throws CTFException {
866e5b51
FC
203 /*
204 * For each stream.
205 */
d84419e1
AM
206 for (CTFStream stream : fTrace.getStreams()) {
207 Set<CTFStreamInput> streamInputs = stream.getStreamInputs();
866e5b51
FC
208
209 /*
210 * For each trace file of the stream.
211 */
d84419e1 212 for (CTFStreamInput streamInput : streamInputs) {
866e5b51
FC
213
214 /*
05ce5fef 215 * Create a reader and add it to the group.
866e5b51 216 */
05ce5fef 217 fStreamInputReaders.add(new CTFStreamInputReader(streamInput));
866e5b51
FC
218 }
219 }
220
221 /*
222 * Create the array to count the number of event per trace file.
223 */
93a45b54 224 fEventCountPerTraceFile = new long[fStreamInputReaders.size()];
866e5b51
FC
225 }
226
545d9101
RB
227 /**
228 * Returns whether or not this CTFTraceReader has been closed
229 *
230 * @return true if it has been closed, false else
6b6f22ef 231 * @since 2.0
545d9101
RB
232 */
233 public boolean isClosed() {
234 return fClosed;
235 }
236
fe75d403
MK
237 /**
238 * Update the priority queue to make it match the parent trace
239 *
680f9173 240 * @throws CTFException
fe75d403 241 * An error occured
fe75d403 242 */
680f9173 243 public void update() throws CTFException {
d84419e1
AM
244 Set<CTFStreamInputReader> readers = new HashSet<>();
245 for (CTFStream stream : fTrace.getStreams()) {
246 Set<CTFStreamInput> streamInputs = stream.getStreamInputs();
247 for (CTFStreamInput streamInput : streamInputs) {
fe75d403
MK
248 /*
249 * Create a reader.
250 */
d84419e1 251 CTFStreamInputReader streamInputReader = new CTFStreamInputReader(
fe75d403
MK
252 streamInput);
253
254 /*
255 * Add it to the group.
256 */
257 if (!fStreamInputReaders.contains(streamInputReader)) {
258 streamInputReader.readNextEvent();
259 fStreamInputReaders.add(streamInputReader);
260 readers.add(streamInputReader);
261 }
262 }
263 }
264 long[] temp = fEventCountPerTraceFile;
265 fEventCountPerTraceFile = new long[readers.size() + temp.length];
d84419e1 266 for (CTFStreamInputReader reader : readers) {
fe75d403
MK
267 fPrio.add(reader);
268 }
269 for (int i = 0; i < temp.length; i++) {
270 fEventCountPerTraceFile[i] = temp[i];
271 }
272 }
273
53359017
MK
274 /**
275 * Gets an iterable of the stream input readers, useful for foreaches
276 *
277 * @return the iterable of the stream input readers
53359017
MK
278 */
279 public Iterable<IEventDeclaration> getEventDeclarations() {
280 ImmutableSet.Builder<IEventDeclaration> builder = new Builder<>();
d84419e1 281 for (CTFStreamInputReader sir : fStreamInputReaders) {
53359017
MK
282 builder.addAll(sir.getEventDeclarations());
283 }
284 return builder.build();
285 }
286
866e5b51
FC
287 /**
288 * Initializes the priority queue used to choose the trace file with the
289 * lower next event timestamp.
db8e8f7d 290 *
680f9173 291 * @throws CTFException
db8e8f7d 292 * if an error occurs
866e5b51 293 */
680f9173 294 private void populateStreamInputReaderHeap() throws CTFException {
93a45b54 295 if (fStreamInputReaders.isEmpty()) {
fe75d403
MK
296 fPrio = new PriorityQueue<>(MIN_PRIO_SIZE,
297 new StreamInputReaderTimestampComparator());
b5354daa
MAL
298 return;
299 }
300
866e5b51
FC
301 /*
302 * Create the priority queue with a size twice as bigger as the number
303 * of reader in order to avoid constant resizing.
304 */
93a45b54 305 fPrio = new PriorityQueue<>(
fe75d403 306 Math.max(fStreamInputReaders.size() * 2, MIN_PRIO_SIZE),
866e5b51
FC
307 new StreamInputReaderTimestampComparator());
308
309 int pos = 0;
310
d84419e1 311 for (CTFStreamInputReader reader : fStreamInputReaders) {
866e5b51
FC
312 /*
313 * Add each trace file reader in the priority queue, if we are able
314 * to read an event from it.
315 */
6a5251eb
MK
316 CTFResponse readNextEvent = reader.readNextEvent();
317 if (readNextEvent == CTFResponse.OK || readNextEvent == CTFResponse.WAIT) {
93a45b54 318 fPrio.add(reader);
866e5b51 319
93a45b54 320 fEventCountPerTraceFile[pos] = 0;
866e5b51
FC
321 reader.setName(pos);
322
323 pos++;
324 }
325 }
326 }
327
328 /**
329 * Get the current event, which is the current event of the trace file
330 * reader with the lowest timestamp.
331 *
332 * @return An event definition, or null of the trace reader reached the end
333 * of the trace.
334 */
335 public EventDefinition getCurrentEventDef() {
d84419e1 336 CTFStreamInputReader top = getTopStream();
866e5b51
FC
337 return (top != null) ? top.getCurrentEvent() : null;
338 }
339
340 /**
341 * Go to the next event.
342 *
343 * @return True if an event was read.
680f9173 344 * @throws CTFException
db8e8f7d 345 * if an error occurs
866e5b51 346 */
680f9173 347 public boolean advance() throws CTFException {
866e5b51
FC
348 /*
349 * Remove the reader from the top of the priority queue.
350 */
d84419e1 351 CTFStreamInputReader top = fPrio.poll();
866e5b51
FC
352
353 /*
354 * If the queue was empty.
355 */
356 if (top == null) {
357 return false;
358 }
866e5b51
FC
359 /*
360 * Read the next event of this reader.
361 */
6a5251eb
MK
362 switch (top.readNextEvent()) {
363 case OK: {
866e5b51
FC
364 /*
365 * Add it back in the queue.
366 */
93a45b54
MK
367 fPrio.add(top);
368 final long topEnd = fTrace.timestampCyclesToNanos(top.getCurrentEvent().getTimestamp());
369 setEndTime(Math.max(topEnd, getEndTime()));
370 fEventCountPerTraceFile[top.getName()]++;
866e5b51 371
bfe038ff 372 if (top.getCurrentEvent() != null) {
93a45b54
MK
373 fEndTime = Math.max(top.getCurrentEvent().getTimestamp(),
374 fEndTime);
bfe038ff 375 }
6a5251eb
MK
376 break;
377 }
378 case WAIT: {
379 fPrio.add(top);
380 break;
381 }
382 case FINISH:
383 break;
384 case ERROR:
385 default:
386 // something bad happend
bfe038ff 387 }
866e5b51
FC
388 /*
389 * If there is no reader in the queue, it means the trace reader reached
390 * the end of the trace.
391 */
bfe038ff 392 return hasMoreEvents();
866e5b51
FC
393 }
394
395 /**
396 * Go to the last event in the trace.
db8e8f7d 397 *
680f9173 398 * @throws CTFException
db8e8f7d 399 * if an error occurs
866e5b51 400 */
680f9173 401 public void goToLastEvent() throws CTFException {
93a45b54
MK
402 seek(getEndTime());
403 while (fPrio.size() > 1) {
404 advance();
866e5b51
FC
405 }
406 }
407
408 /**
ecb12461
EB
409 * Seeks to a given timestamp. It will seek to the nearest event greater or
410 * equal to timestamp. If a trace is [10 20 30 40] and you are looking for
411 * 19, it will give you 20. If you want 20, you will get 20, if you want 21,
412 * you will get 30. The value -inf will seek to the first element and the
413 * value +inf will seek to the end of the file (past the last event).
866e5b51
FC
414 *
415 * @param timestamp
416 * the timestamp to seek to
6a5251eb
MK
417 * @return true if there are events above or equal the seek timestamp, false
418 * if seek at the end of the trace (no valid event).
680f9173 419 * @throws CTFException
db8e8f7d 420 * if an error occurs
866e5b51 421 */
680f9173 422 public boolean seek(long timestamp) throws CTFException {
866e5b51
FC
423 /*
424 * Remove all the trace readers from the priority queue
425 */
93a45b54 426 fPrio.clear();
d84419e1 427 for (CTFStreamInputReader streamInputReader : fStreamInputReaders) {
866e5b51
FC
428 /*
429 * Seek the trace reader.
430 */
bfe038ff 431 streamInputReader.seek(timestamp);
ce2388e0
FC
432
433 /*
434 * Add it to the priority queue if there is a current event.
435 */
ce2388e0 436 if (streamInputReader.getCurrentEvent() != null) {
93a45b54 437 fPrio.add(streamInputReader);
ce2388e0
FC
438 }
439 }
866e5b51
FC
440 return hasMoreEvents();
441 }
442
9ac2eb62 443 /**
ecb12461 444 * Gets the stream with the oldest event
9ac2eb62
MK
445 *
446 * @return the stream with the oldest event
447 */
d84419e1 448 public CTFStreamInputReader getTopStream() {
93a45b54 449 return fPrio.peek();
ce2388e0
FC
450 }
451
866e5b51
FC
452 /**
453 * Does the trace have more events?
454 *
455 * @return true if yes.
456 */
0594c61c 457 public final boolean hasMoreEvents() {
93a45b54 458 return fPrio.size() > 0;
866e5b51
FC
459 }
460
461 /**
462 * Prints the event count stats.
463 */
464 public void printStats() {
f068c622 465 printStats(LINE_LENGTH);
866e5b51
FC
466 }
467
468 /**
469 * Prints the event count stats.
470 *
471 * @param width
472 * Width of the display.
473 */
474 public void printStats(int width) {
475 int numEvents = 0;
476 if (width == 0) {
477 return;
478 }
479
93a45b54 480 for (long i : fEventCountPerTraceFile) {
866e5b51
FC
481 numEvents += i;
482 }
483
93a45b54 484 for (int j = 0; j < fEventCountPerTraceFile.length; j++) {
d84419e1 485 CTFStreamInputReader se = fStreamInputReaders.get(j);
866e5b51 486
93a45b54 487 long len = (width * fEventCountPerTraceFile[se.getName()])
866e5b51
FC
488 / numEvents;
489
0594c61c
AM
490 StringBuilder sb = new StringBuilder(se.getFilename());
491 sb.append("\t["); //$NON-NLS-1$
866e5b51
FC
492
493 for (int i = 0; i < len; i++) {
494 sb.append('+');
495 }
496
bfe038ff 497 for (long i = len; i < width; i++) {
866e5b51
FC
498 sb.append(' ');
499 }
500
93a45b54 501 sb.append("]\t" + fEventCountPerTraceFile[se.getName()] + " Events"); //$NON-NLS-1$//$NON-NLS-2$
4311ac8b 502 Activator.log(sb.toString());
866e5b51
FC
503 }
504 }
505
9ac2eb62 506 /**
ecb12461 507 * Gets the last event timestamp that was read. This is NOT necessarily the
9ac2eb62
MK
508 * last event in a trace, just the last one read so far.
509 *
510 * @return the last event
511 */
866e5b51 512 public long getEndTime() {
93a45b54 513 return fEndTime;
866e5b51
FC
514 }
515
6a5251eb
MK
516 /**
517 * Sets a trace to be live or not
518 *
519 * @param live
520 * whether the trace is live
6a5251eb
MK
521 */
522 public void setLive(boolean live) {
d84419e1 523 for (CTFStreamInputReader s : fPrio) {
6a5251eb
MK
524 s.setLive(live);
525 }
526 }
527
528 /**
529 * Get if the trace is to read live or not
530 *
531 * @return whether the trace is live or not
6a5251eb
MK
532 */
533 public boolean isLive() {
0af5eb9a 534 return getTopStream().isLive();
6a5251eb
MK
535 }
536
866e5b51
FC
537 @Override
538 public int hashCode() {
539 final int prime = 31;
540 int result = 1;
93a45b54
MK
541 result = (prime * result) + (int) (fStartTime ^ (fStartTime >>> 32));
542 result = (prime * result) + fStreamInputReaders.hashCode();
543 result = (prime * result) + ((fTrace == null) ? 0 : fTrace.hashCode());
866e5b51
FC
544 return result;
545 }
546
547 @Override
548 public boolean equals(Object obj) {
549 if (this == obj) {
550 return true;
551 }
552 if (obj == null) {
553 return false;
554 }
07002e0a 555 if (!(obj instanceof CTFTraceReader)) {
866e5b51
FC
556 return false;
557 }
558 CTFTraceReader other = (CTFTraceReader) obj;
93a45b54 559 if (!fStreamInputReaders.equals(other.fStreamInputReaders)) {
866e5b51
FC
560 return false;
561 }
93a45b54
MK
562 if (fTrace == null) {
563 if (other.fTrace != null) {
866e5b51
FC
564 return false;
565 }
93a45b54 566 } else if (!fTrace.equals(other.fTrace)) {
866e5b51
FC
567 return false;
568 }
569 return true;
570 }
571
866e5b51
FC
572 @Override
573 public String toString() {
574 /* Only for debugging, shouldn't be externalized */
93a45b54 575 return "CTFTraceReader [trace=" + fTrace + ']'; //$NON-NLS-1$
866e5b51
FC
576 }
577
9ac2eb62
MK
578 /**
579 * Gets the parent trace
580 *
581 * @return the parent trace
582 */
866e5b51 583 public CTFTrace getTrace() {
93a45b54 584 return fTrace;
866e5b51 585 }
4a32dd11
MK
586
587 /**
588 * This will read the entire trace and populate all the indexes. The reader
589 * will then be reset to the first event in the trace.
590 *
591 * Do not call in the fast path.
592 *
593 * @throws CTFException
594 * A trace reading error occurred
595 * @since 1.0
596 */
597 public void populateIndex() throws CTFException {
598 for (CTFStreamInputReader sir : fPrio) {
599 sir.goToLastEvent();
600 }
601 seek(0);
602
603 }
866e5b51 604}
This page took 0.093948 seconds and 5 git commands to generate.