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