ctf: Update copyright headers and add missing ones
[deliverable/tracecompass.git] / org.eclipse.linuxtools.ctf.core / src / org / eclipse / linuxtools / ctf / core / trace / CTFTraceReader.java
1 /*******************************************************************************
2 * Copyright (c) 2011, 2013 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: Alexandre Montplaisir - Initial API and implementation
11 *******************************************************************************/
12
13 package org.eclipse.linuxtools.ctf.core.trace;
14
15 import java.util.Collection;
16 import java.util.PriorityQueue;
17 import java.util.Set;
18 import java.util.Vector;
19
20 import org.eclipse.linuxtools.ctf.core.event.EventDefinition;
21 import org.eclipse.linuxtools.internal.ctf.core.Activator;
22 import org.eclipse.linuxtools.internal.ctf.core.trace.StreamInputReaderTimestampComparator;
23
24 /**
25 * A CTF trace reader. Reads the events of a trace.
26 *
27 * @version 1.0
28 * @author Matthew Khouzam
29 * @author Alexandre Montplaisir
30 */
31 public class CTFTraceReader {
32
33 // ------------------------------------------------------------------------
34 // Attributes
35 // ------------------------------------------------------------------------
36
37 /**
38 * The trace to read from.
39 */
40 private final CTFTrace trace;
41
42 /**
43 * Vector of all the trace file readers.
44 */
45 private final Vector<StreamInputReader> streamInputReaders = new Vector<StreamInputReader>();
46
47 /**
48 * Priority queue to order the trace file readers by timestamp.
49 */
50 protected PriorityQueue<StreamInputReader> prio;
51
52 /**
53 * Array to count the number of event per trace file.
54 */
55 private long[] eventCountPerTraceFile;
56
57 /**
58 * Timestamp of the first event in the trace
59 */
60 private long startTime;
61
62 /**
63 * Timestamp of the last event read so far
64 */
65 private long endTime;
66
67 // ------------------------------------------------------------------------
68 // Constructors
69 // ------------------------------------------------------------------------
70
71 /**
72 * Constructs a TraceReader to read a trace.
73 *
74 * @param trace
75 * The trace to read from.
76 */
77 public CTFTraceReader(CTFTrace trace) {
78 this.trace = trace;
79 streamInputReaders.clear();
80
81 /**
82 * Create the trace file readers.
83 */
84 createStreamInputReaders();
85
86 /**
87 * Populate the timestamp-based priority queue.
88 */
89 populateStreamInputReaderHeap();
90
91 /**
92 * Get the start Time of this trace bear in mind that the trace could be
93 * empty.
94 */
95 this.startTime = 0;// prio.peek().getPacketReader().getCurrentPacket().getTimestampBegin();
96 if (hasMoreEvents()) {
97 this.startTime = prio.peek().getCurrentEvent().getTimestamp();
98 this.setEndTime(this.startTime);
99 }
100 }
101
102 /**
103 * Copy constructor
104 *
105 * @return The new CTFTraceReader
106 */
107 public CTFTraceReader copyFrom() {
108 CTFTraceReader newReader = null;
109
110 newReader = new CTFTraceReader(this.trace);
111 newReader.startTime = this.startTime;
112 newReader.setEndTime(this.endTime);
113 return newReader;
114 }
115
116 /**
117 * Dispose the CTFTraceReader
118 * @since 2.0
119 */
120 public void dispose() {
121 for (StreamInputReader reader : streamInputReaders) {
122 if (reader != null) {
123 reader.dispose();
124 }
125 }
126 streamInputReaders.clear();
127 }
128
129 // ------------------------------------------------------------------------
130 // Getters/Setters/Predicates
131 // ------------------------------------------------------------------------
132
133 /**
134 * Return the start time of this trace (== timestamp of the first event)
135 *
136 * @return the trace start time
137 */
138 public long getStartTime() {
139 return this.startTime;
140 }
141
142 /**
143 * Set the trace's end time
144 *
145 * @param endTime
146 * The end time to use
147 */
148 protected void setEndTime(long endTime) {
149 this.endTime = endTime;
150 }
151
152
153 // ------------------------------------------------------------------------
154 // Operations
155 // ------------------------------------------------------------------------
156
157 /**
158 * Creates one trace file reader per trace file contained in the trace.
159 */
160 private void createStreamInputReaders() {
161 Collection<Stream> streams = this.trace.getStreams().values();
162
163 /*
164 * For each stream.
165 */
166 for (Stream stream : streams) {
167 Set<StreamInput> streamInputs = stream.getStreamInputs();
168
169 /*
170 * For each trace file of the stream.
171 */
172 for (StreamInput streamInput : streamInputs) {
173 /*
174 * Create a reader.
175 */
176 StreamInputReader streamInputReader = new StreamInputReader(
177 streamInput);
178
179 /*
180 * Add it to the group.
181 */
182 this.streamInputReaders.add(streamInputReader);
183 }
184 }
185
186 /*
187 * Create the array to count the number of event per trace file.
188 */
189 this.eventCountPerTraceFile = new long[this.streamInputReaders.size()];
190 }
191
192 /**
193 * Initializes the priority queue used to choose the trace file with the
194 * lower next event timestamp.
195 */
196 private void populateStreamInputReaderHeap() {
197 /*
198 * Create the priority queue with a size twice as bigger as the number
199 * of reader in order to avoid constant resizing.
200 */
201 this.prio = new PriorityQueue<StreamInputReader>(
202 this.streamInputReaders.size() * 2,
203 new StreamInputReaderTimestampComparator());
204
205 int pos = 0;
206
207 for (StreamInputReader reader : this.streamInputReaders) {
208 /*
209 * Add each trace file reader in the priority queue, if we are able
210 * to read an event from it.
211 */
212 reader.setParent(this);
213 if (reader.readNextEvent()) {
214 this.prio.add(reader);
215
216 this.eventCountPerTraceFile[pos] = 0;
217 reader.setName(pos);
218
219 pos++;
220 }
221 }
222 }
223
224 /**
225 * Get the current event, which is the current event of the trace file
226 * reader with the lowest timestamp.
227 *
228 * @return An event definition, or null of the trace reader reached the end
229 * of the trace.
230 */
231 public EventDefinition getCurrentEventDef() {
232 StreamInputReader top = getTopStream();
233
234 return (top != null) ? top.getCurrentEvent() : null;
235 }
236
237 /**
238 * Go to the next event.
239 *
240 * @return True if an event was read.
241 */
242 public boolean advance() {
243 /*
244 * Index the
245 */
246 /*
247 * Remove the reader from the top of the priority queue.
248 */
249 StreamInputReader top = this.prio.poll();
250
251 /*
252 * If the queue was empty.
253 */
254 if (top == null) {
255 return false;
256 }
257 /*
258 * Read the next event of this reader.
259 */
260 if (top.readNextEvent()) {
261 /*
262 * Add it back in the queue.
263 */
264 this.prio.add(top);
265 final long topEnd = this.trace.timestampCyclesToNanos(top.getCurrentEvent().getTimestamp());
266 this.setEndTime(Math.max(topEnd, this.getEndTime()));
267 this.eventCountPerTraceFile[top.getName()]++;
268
269 if (top.getCurrentEvent() != null) {
270 this.endTime = Math.max(top.getCurrentEvent().getTimestamp(),
271 this.endTime);
272 }
273 }
274 /*
275 * If there is no reader in the queue, it means the trace reader reached
276 * the end of the trace.
277 */
278 return hasMoreEvents();
279 }
280
281 /**
282 * Go to the last event in the trace.
283 */
284 public void goToLastEvent() {
285 seek(this.getEndTime());
286 while (this.prio.size() > 1) {
287 this.advance();
288 }
289 }
290
291 /**
292 * Seeks to a given timestamp It will go to the event just after the
293 * timestamp or the timestamp itself. if a if a trace is 10 20 30 40 and
294 * you're looking for 19, it'll give you 20, it you want 20, you'll get 20,
295 * if you want 21, you'll get 30. You want -inf, you'll get the first
296 * element, you want +inf, you'll get the end of the file with no events.
297 *
298 * @param timestamp
299 * the timestamp to seek to
300 * @return true if the trace has more events following the timestamp
301 */
302 public boolean seek(long timestamp) {
303 /*
304 * Remove all the trace readers from the priority queue
305 */
306 this.prio.clear();
307 for (StreamInputReader streamInputReader : this.streamInputReaders) {
308 /*
309 * Seek the trace reader.
310 */
311 streamInputReader.seek(timestamp);
312
313 /*
314 * Add it to the priority queue if there is a current event.
315 */
316
317 }
318 for (StreamInputReader streamInputReader : this.streamInputReaders) {
319 if (streamInputReader.getCurrentEvent() != null) {
320 this.prio.add(streamInputReader);
321
322 }
323 }
324 return hasMoreEvents();
325 }
326
327 // /**
328 // * Go to the first entry of a trace
329 // *
330 // * @return 0, the first index.
331 // */
332 // private long goToZero() {
333 // long tempIndex;
334 // for (StreamInputReader streamInputReader : this.streamInputReaders) {
335 // /*
336 // * Seek the trace reader.
337 // */
338 // streamInputReader.seek(0);
339 // }
340 // tempIndex = 0;
341 // return tempIndex;
342 // }
343
344 /**
345 * gets the stream with the oldest event
346 *
347 * @return the stream with the oldest event
348 */
349 public StreamInputReader getTopStream() {
350 return this.prio.peek();
351 }
352
353 /**
354 * Does the trace have more events?
355 *
356 * @return true if yes.
357 */
358 public boolean hasMoreEvents() {
359 return this.prio.size() > 0;
360 }
361
362 /**
363 * Prints the event count stats.
364 */
365 public void printStats() {
366 printStats(60);
367 }
368
369 /**
370 * Prints the event count stats.
371 *
372 * @param width
373 * Width of the display.
374 */
375 public void printStats(int width) {
376 int numEvents = 0;
377 if (width == 0) {
378 return;
379 }
380
381 for (long i : this.eventCountPerTraceFile) {
382 numEvents += i;
383 }
384
385 for (int j = 0; j < this.eventCountPerTraceFile.length; j++) {
386 StreamInputReader se = this.streamInputReaders.get(j);
387
388 long len = (width * this.eventCountPerTraceFile[se.getName()])
389 / numEvents;
390
391 StringBuilder sb = new StringBuilder(se.getFilename() + "\t["); //$NON-NLS-1$
392
393 for (int i = 0; i < len; i++) {
394 sb.append('+');
395 }
396
397 for (long i = len; i < width; i++) {
398 sb.append(' ');
399 }
400
401 sb.append("]\t" + this.eventCountPerTraceFile[se.getName()] + " Events"); //$NON-NLS-1$//$NON-NLS-2$
402 Activator.getDefault().log(sb.toString());
403 }
404 }
405
406 /**
407 * gets the last event timestamp that was read. This is NOT necessarily the
408 * last event in a trace, just the last one read so far.
409 *
410 * @return the last event
411 */
412 public long getEndTime() {
413 return this.endTime;
414 }
415
416 @Override
417 public int hashCode() {
418 final int prime = 31;
419 int result = 1;
420 result = (prime * result) + (int) (startTime ^ (startTime >>> 32));
421 result = (prime * result) + streamInputReaders.hashCode();
422 result = (prime * result) + ((trace == null) ? 0 : trace.hashCode());
423 return result;
424 }
425
426 @Override
427 public boolean equals(Object obj) {
428 if (this == obj) {
429 return true;
430 }
431 if (obj == null) {
432 return false;
433 }
434 if (!(obj instanceof CTFTraceReader)) {
435 return false;
436 }
437 CTFTraceReader other = (CTFTraceReader) obj;
438 if (!streamInputReaders.equals(other.streamInputReaders)) {
439 return false;
440 }
441 if (trace == null) {
442 if (other.trace != null) {
443 return false;
444 }
445 } else if (!trace.equals(other.trace)) {
446 return false;
447 }
448 return true;
449 }
450
451 /*
452 * (non-Javadoc)
453 *
454 * @see java.lang.Object#toString()
455 */
456 @Override
457 public String toString() {
458 /* Only for debugging, shouldn't be externalized */
459 return "CTFTraceReader [trace=" + trace + ']'; //$NON-NLS-1$
460 }
461
462 /**
463 * Gets the parent trace
464 *
465 * @return the parent trace
466 */
467 public CTFTrace getTrace() {
468 return trace;
469 }
470 }
This page took 0.042956 seconds and 6 git commands to generate.