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