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