tmf/lttng: Update 2014 copyrights
[deliverable/tracecompass.git] / org.eclipse.linuxtools.ctf.core / src / org / eclipse / linuxtools / ctf / core / trace / StreamInput.java
CommitLineData
866e5b51 1/*******************************************************************************
60ae41e1 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 *
9 * Contributors: Matthew Khouzam - Initial API and implementation
10 * Contributors: Simon Marchi - Initial API and implementation
11 *******************************************************************************/
12
486efb2e 13package org.eclipse.linuxtools.ctf.core.trace;
866e5b51
FC
14
15import java.io.File;
aa3b05ef 16import java.io.IOException;
526c823c 17import java.nio.ByteBuffer;
866e5b51 18import java.nio.channels.FileChannel;
aa3b05ef 19import java.nio.channels.FileChannel.MapMode;
866e5b51
FC
20import java.util.UUID;
21
486efb2e 22import org.eclipse.linuxtools.ctf.core.event.io.BitBuffer;
866e5b51
FC
23import org.eclipse.linuxtools.ctf.core.event.types.ArrayDefinition;
24import org.eclipse.linuxtools.ctf.core.event.types.Definition;
21fb02fa
MK
25import org.eclipse.linuxtools.ctf.core.event.types.EnumDefinition;
26import org.eclipse.linuxtools.ctf.core.event.types.FloatDefinition;
866e5b51
FC
27import org.eclipse.linuxtools.ctf.core.event.types.IDefinitionScope;
28import org.eclipse.linuxtools.ctf.core.event.types.IntegerDefinition;
21fb02fa 29import org.eclipse.linuxtools.ctf.core.event.types.StringDefinition;
866e5b51 30import org.eclipse.linuxtools.ctf.core.event.types.StructDefinition;
486efb2e
AM
31import org.eclipse.linuxtools.internal.ctf.core.trace.StreamInputPacketIndex;
32import org.eclipse.linuxtools.internal.ctf.core.trace.StreamInputPacketIndexEntry;
866e5b51
FC
33
34/**
35 * <b><u>StreamInput</u></b>
36 * <p>
37 * Represents a trace file that belongs to a certain stream.
cf9a28da 38 *
486efb2e 39 * @since 2.0
866e5b51
FC
40 */
41public class StreamInput implements IDefinitionScope {
42
43 // ------------------------------------------------------------------------
44 // Attributes
45 // ------------------------------------------------------------------------
46
47 /**
48 * The associated Stream
49 */
f224bebc 50 private final Stream fStream;
866e5b51
FC
51
52 /**
53 * FileChannel to the trace file
54 */
f224bebc 55 private final FileChannel fFileChannel;
866e5b51
FC
56
57 /**
58 * Information on the file (used for debugging)
59 */
f224bebc 60 private final File fFile;
866e5b51
FC
61
62 /**
63 * The packet index of this input
64 */
f224bebc 65 private final StreamInputPacketIndex fIndex;
866e5b51 66
f224bebc 67 private long fTimestampEnd;
866e5b51 68
bfe038ff
MK
69 /*
70 * Definition of trace packet header
71 */
f224bebc 72 private StructDefinition fTracePacketHeaderDef = null;
bfe038ff
MK
73
74 /*
75 * Definition of trace stream packet context
76 */
f224bebc 77 private StructDefinition fStreamPacketContextDef = null;
bfe038ff 78
132a02b0
MK
79 /*
80 * Total number of lost events in this stream
81 */
f224bebc 82 private long fLostSoFar = 0;
132a02b0 83
866e5b51
FC
84 // ------------------------------------------------------------------------
85 // Constructors
86 // ------------------------------------------------------------------------
87
88 /**
89 * Constructs a StreamInput.
90 *
91 * @param stream
92 * The stream to which this StreamInput belongs to.
93 * @param fileChannel
94 * The FileChannel to the trace file.
95 * @param file
96 * Information about the trace file (for debugging purposes).
97 */
98 public StreamInput(Stream stream, FileChannel fileChannel, File file) {
f224bebc
MK
99 fStream = stream;
100 fFileChannel = fileChannel;
101 fFile = file;
102 fIndex = new StreamInputPacketIndex();
866e5b51
FC
103 }
104
105 // ------------------------------------------------------------------------
106 // Getters/Setters/Predicates
107 // ------------------------------------------------------------------------
108
9ac2eb62
MK
109 /**
110 * Gets the stream the streamInput wrapper is wrapping
21fb02fa 111 *
9ac2eb62
MK
112 * @return the stream the streamInput wrapper is wrapping
113 */
866e5b51 114 public Stream getStream() {
f224bebc 115 return fStream;
866e5b51
FC
116 }
117
9ac2eb62 118 /**
ecb12461 119 * The common streamInput Index
21fb02fa 120 *
9ac2eb62
MK
121 * @return the stream input Index
122 */
486efb2e 123 StreamInputPacketIndex getIndex() {
f224bebc 124 return fIndex;
866e5b51
FC
125 }
126
9ac2eb62
MK
127 /**
128 * Gets the filename of the streamInput file.
21fb02fa 129 *
9ac2eb62
MK
130 * @return the filename of the streaminput file.
131 */
866e5b51 132 public String getFilename() {
f224bebc 133 return fFile.getName();
866e5b51
FC
134 }
135
9ac2eb62 136 /**
ecb12461 137 * Gets the last read timestamp of a stream. (this is not necessarily the
21fb02fa
MK
138 * last time in the stream.)
139 *
9ac2eb62
MK
140 * @return the last read timestamp
141 */
866e5b51 142 public long getTimestampEnd() {
f224bebc 143 return fTimestampEnd;
866e5b51
FC
144 }
145
9ac2eb62 146 /**
21fb02fa
MK
147 * Sets the last read timestamp of a stream. (this is not necessarily the
148 * last time in the stream.)
149 *
150 * @param timestampEnd
151 * the last read timestamp
9ac2eb62 152 */
866e5b51 153 public void setTimestampEnd(long timestampEnd) {
f224bebc 154 fTimestampEnd = timestampEnd;
866e5b51
FC
155 }
156
9ac2eb62 157 /**
ecb12461 158 * Useless for streaminputs
9ac2eb62 159 */
866e5b51
FC
160 @Override
161 public String getPath() {
162 return ""; //$NON-NLS-1$
163 }
164
165 // ------------------------------------------------------------------------
166 // Operations
167 // ------------------------------------------------------------------------
168
169 @Override
170 public Definition lookupDefinition(String lookupPath) {
171 /* TODO: lookup in different dynamic scopes is not supported yet. */
172 return null;
173 }
174
175 /**
176 * Create the index for this trace file.
bfe038ff
MK
177 */
178 public void setupIndex() {
179
bfe038ff
MK
180 /*
181 * The BitBuffer to extract data from the StreamInput
182 */
183 BitBuffer bitBuffer = new BitBuffer();
f224bebc 184 bitBuffer.setByteOrder(getStream().getTrace().getByteOrder());
bfe038ff
MK
185
186 /*
187 * Create the definitions we need to read the packet headers + contexts
188 */
189 if (getStream().getTrace().getPacketHeader() != null) {
f224bebc 190 fTracePacketHeaderDef = getStream().getTrace().getPacketHeader()
bfe038ff
MK
191 .createDefinition(this, "trace.packet.header"); //$NON-NLS-1$
192 }
193
194 if (getStream().getPacketContextDecl() != null) {
f224bebc 195 fStreamPacketContextDef = getStream().getPacketContextDecl()
bfe038ff
MK
196 .createDefinition(this, "stream.packet.context"); //$NON-NLS-1$
197 }
198
199 }
200
9ac2eb62
MK
201 /**
202 * Adds the next packet header index entry to the index of a stream input.
be6df2d8
AM
203 *
204 * @warning slow, can corrupt data if not used properly
9ac2eb62
MK
205 * @return true if there are more packets to add
206 * @throws CTFReaderException
be6df2d8 207 * If there was a problem reading the packed header
9ac2eb62 208 */
bfe038ff
MK
209 public boolean addPacketHeaderIndex() throws CTFReaderException {
210 long currentPos = 0L;
f224bebc
MK
211 if (!fIndex.getEntries().isEmpty()) {
212 StreamInputPacketIndexEntry pos = fIndex.getEntries().lastElement();
bfe038ff
MK
213 currentPos = computeNextOffset(pos);
214 }
215 long fileSize = getStreamSize();
216 if (currentPos < fileSize) {
217 BitBuffer bitBuffer = new BitBuffer();
f224bebc 218 bitBuffer.setByteOrder(getStream().getTrace().getByteOrder());
bfe038ff
MK
219 StreamInputPacketIndexEntry packetIndex = new StreamInputPacketIndexEntry(
220 currentPos);
221 createPacketIndexEntry(fileSize, currentPos, packetIndex,
f224bebc
MK
222 fTracePacketHeaderDef, fStreamPacketContextDef, bitBuffer);
223 fIndex.addEntry(packetIndex);
bfe038ff
MK
224 return true;
225 }
226 return false;
227 }
228
bfe038ff 229 private long getStreamSize() {
f224bebc 230 return fFile.length();
bfe038ff
MK
231 }
232
bfe038ff
MK
233 private long createPacketIndexEntry(long fileSizeBytes,
234 long packetOffsetBytes, StreamInputPacketIndexEntry packetIndex,
235 StructDefinition tracePacketHeaderDef,
236 StructDefinition streamPacketContextDef, BitBuffer bitBuffer)
237 throws CTFReaderException {
0594c61c 238
cf9a28da
MK
239 /*
240 * Ignoring the return value, but this call is needed to initialize the
241 * input
242 */
0594c61c 243 createPacketBitBuffer(fileSizeBytes, packetOffsetBytes, packetIndex, bitBuffer);
bfe038ff 244
866e5b51 245 /*
bfe038ff 246 * Read the trace packet header if it exists.
866e5b51 247 */
bfe038ff
MK
248 if (tracePacketHeaderDef != null) {
249 parseTracePacketHeader(tracePacketHeaderDef, bitBuffer);
866e5b51
FC
250 }
251
252 /*
bfe038ff 253 * Read the stream packet context if it exists.
866e5b51 254 */
bfe038ff
MK
255 if (streamPacketContextDef != null) {
256 parsePacketContext(fileSizeBytes, streamPacketContextDef,
257 bitBuffer, packetIndex);
258 } else {
259 setPacketContextNull(fileSizeBytes, packetIndex);
260 }
261
262 /* Basic validation */
263 if (packetIndex.getContentSizeBits() > packetIndex.getPacketSizeBits()) {
264 throw new CTFReaderException("Content size > packet size"); //$NON-NLS-1$
265 }
866e5b51 266
bfe038ff
MK
267 if (packetIndex.getPacketSizeBits() > ((fileSizeBytes - packetIndex
268 .getOffsetBytes()) * 8)) {
cf9a28da 269 throw new CTFReaderException("Not enough data remaining in the file for the size of this packet"); //$NON-NLS-1$
bfe038ff
MK
270 }
271
272 /*
273 * Offset in the file, in bits
274 */
275 packetIndex.setDataOffsetBits(bitBuffer.position());
276
277 /*
278 * Update the counting packet offset
279 */
21fb02fa 280 return computeNextOffset(packetIndex);
bfe038ff
MK
281 }
282
283 /**
284 * @param packetIndex
285 * @return
286 */
287 private static long computeNextOffset(
288 StreamInputPacketIndexEntry packetIndex) {
289 return packetIndex.getOffsetBytes()
290 + ((packetIndex.getPacketSizeBits() + 7) / 8);
291 }
292
526c823c 293 ByteBuffer getByteBufferAt(long position, long size) throws IOException {
f224bebc 294 return fFileChannel.map(MapMode.READ_ONLY, position, size);
526c823c
EB
295 }
296
aa3b05ef
FC
297 /**
298 * @param fileSizeBytes
299 * @param packetOffsetBytes
300 * @param packetIndex
301 * @param bitBuffer
302 * @return
303 * @throws CTFReaderException
304 */
526c823c 305 private ByteBuffer createPacketBitBuffer(long fileSizeBytes,
aa3b05ef
FC
306 long packetOffsetBytes, StreamInputPacketIndexEntry packetIndex,
307 BitBuffer bitBuffer) throws CTFReaderException {
308 /*
309 * Initial size, it should map at least the packet header + context
310 * size.
311 *
312 * TODO: use a less arbitrary size.
313 */
314 long mapSize = 4096;
315 /*
316 * If there is less data remaining than what we want to map, reduce the
317 * map size.
318 */
319 if ((fileSizeBytes - packetIndex.getOffsetBytes()) < mapSize) {
320 mapSize = fileSizeBytes - packetIndex.getOffsetBytes();
321 }
322
323 /*
324 * Map the packet.
325 */
526c823c 326 ByteBuffer bb;
aa3b05ef
FC
327
328 try {
526c823c 329 bb = getByteBufferAt(packetOffsetBytes, mapSize);
aa3b05ef
FC
330 } catch (IOException e) {
331 throw new CTFReaderException(e);
332 }
333 bitBuffer.setByteBuffer(bb);
334 return bb;
335 }
bfe038ff 336
bfe038ff
MK
337 private void parseTracePacketHeader(StructDefinition tracePacketHeaderDef,
338 BitBuffer bitBuffer) throws CTFReaderException {
339 tracePacketHeaderDef.read(bitBuffer);
866e5b51
FC
340
341 /*
bfe038ff 342 * Check the CTF magic number
866e5b51 343 */
bfe038ff
MK
344 IntegerDefinition magicDef = (IntegerDefinition) tracePacketHeaderDef
345 .lookupDefinition("magic"); //$NON-NLS-1$
346 if (magicDef != null) {
347 int magic = (int) magicDef.getValue();
348 if (magic != Utils.CTF_MAGIC) {
349 throw new CTFReaderException(
350 "CTF magic mismatch " + Integer.toHexString(magic) + " vs " + Integer.toHexString(Utils.CTF_MAGIC)); //$NON-NLS-1$//$NON-NLS-2$
351 }
866e5b51
FC
352 }
353
354 /*
bfe038ff 355 * Check the trace UUID
866e5b51 356 */
0594c61c
AM
357 ArrayDefinition uuidDef =
358 (ArrayDefinition) tracePacketHeaderDef.lookupDefinition("uuid"); //$NON-NLS-1$
bfe038ff
MK
359 if (uuidDef != null) {
360 byte[] uuidArray = new byte[16];
361
0594c61c
AM
362 for (int i = 0; i < uuidArray.length; i++) {
363 IntegerDefinition uuidByteDef = (IntegerDefinition) uuidDef.getElem(i);
bfe038ff 364 uuidArray[i] = (byte) uuidByteDef.getValue();
866e5b51 365 }
866e5b51 366
bfe038ff 367 UUID uuid = Utils.makeUUID(uuidArray);
866e5b51 368
bfe038ff
MK
369 if (!getStream().getTrace().getUUID().equals(uuid)) {
370 throw new CTFReaderException("UUID mismatch"); //$NON-NLS-1$
866e5b51 371 }
bfe038ff 372 }
866e5b51 373
bfe038ff
MK
374 /*
375 * Check that the stream id did not change
376 */
377 IntegerDefinition streamIDDef = (IntegerDefinition) tracePacketHeaderDef
378 .lookupDefinition("stream_id"); //$NON-NLS-1$
379 if (streamIDDef != null) {
380 long streamID = streamIDDef.getValue();
866e5b51 381
bfe038ff 382 if (streamID != getStream().getId()) {
cf9a28da 383 throw new CTFReaderException("Stream ID changing within a StreamInput"); //$NON-NLS-1$
866e5b51 384 }
bfe038ff
MK
385 }
386 }
866e5b51 387
bfe038ff
MK
388 private static void setPacketContextNull(long fileSizeBytes,
389 StreamInputPacketIndexEntry packetIndex) {
390 /*
391 * If there is no packet context, infer the content and packet size from
392 * the file size (assume that there is only one packet and no padding)
393 */
47ca6c05
SM
394 packetIndex.setContentSizeBits(fileSizeBytes * 8);
395 packetIndex.setPacketSizeBits(fileSizeBytes * 8);
bfe038ff 396 }
866e5b51 397
bfe038ff
MK
398 private void parsePacketContext(long fileSizeBytes,
399 StructDefinition streamPacketContextDef, BitBuffer bitBuffer,
db8e8f7d 400 StreamInputPacketIndexEntry packetIndex) throws CTFReaderException {
bfe038ff 401 streamPacketContextDef.read(bitBuffer);
866e5b51 402
21fb02fa
MK
403 for (String field : streamPacketContextDef.getDeclaration()
404 .getFieldsList()) {
405 Definition id = streamPacketContextDef.lookupDefinition(field);
406 if (id instanceof IntegerDefinition) {
407 packetIndex.addAttribute(field,
408 ((IntegerDefinition) id).getValue());
409 } else if (id instanceof FloatDefinition) {
410 packetIndex.addAttribute(field,
411 ((FloatDefinition) id).getValue());
412 } else if (id instanceof EnumDefinition) {
413 packetIndex.addAttribute(field,
414 ((EnumDefinition) id).getValue());
415 } else if (id instanceof StringDefinition) {
416 packetIndex.addAttribute(field,
417 ((StringDefinition) id).getValue());
418 }
21fb02fa
MK
419 }
420
421 Long contentSize = (Long) packetIndex.lookupAttribute("content_size"); //$NON-NLS-1$
422 Long packetSize = (Long) packetIndex.lookupAttribute("packet_size"); //$NON-NLS-1$
0594c61c
AM
423 Long tsBegin = (Long) packetIndex.lookupAttribute("timestamp_begin"); //$NON-NLS-1$
424 Long tsEnd = (Long) packetIndex.lookupAttribute("timestamp_end"); //$NON-NLS-1$
21fb02fa
MK
425 String device = (String) packetIndex.lookupAttribute("device"); //$NON-NLS-1$
426 // LTTng Specific
0594c61c 427 Long cpuId = (Long) packetIndex.lookupAttribute("cpu_id"); //$NON-NLS-1$
cf9a28da 428 Long lostEvents = (Long) packetIndex.lookupAttribute("events_discarded"); //$NON-NLS-1$
132a02b0
MK
429
430 /* Read the content size in bits */
21fb02fa
MK
431 if (contentSize != null) {
432 packetIndex.setContentSizeBits(contentSize.intValue());
cf9a28da
MK
433 } else if (packetSize != null) {
434 packetIndex.setContentSizeBits(packetSize.longValue());
bfe038ff
MK
435 } else {
436 packetIndex.setContentSizeBits((int) (fileSizeBytes * 8));
437 }
866e5b51 438
cf9a28da 439
132a02b0 440 /* Read the packet size in bits */
21fb02fa
MK
441 if (packetSize != null) {
442 packetIndex.setPacketSizeBits(packetSize.intValue());
51598b21
MK
443 } else if (packetIndex.getContentSizeBits() != 0) {
444 packetIndex.setPacketSizeBits(packetIndex.getContentSizeBits());
bfe038ff 445 } else {
51598b21 446 packetIndex.setPacketSizeBits((int) (fileSizeBytes * 8));
bfe038ff
MK
447 }
448
51598b21 449
132a02b0 450 /* Read the begin timestamp */
0594c61c
AM
451 if (tsBegin != null) {
452 packetIndex.setTimestampBegin(tsBegin.longValue());
bfe038ff
MK
453 }
454
132a02b0 455 /* Read the end timestamp */
0594c61c 456 if (tsEnd != null) {
ecb12461 457 if (tsEnd == -1) {
0594c61c 458 tsEnd = Long.MAX_VALUE;
21fb02fa 459 }
0594c61c 460 packetIndex.setTimestampEnd(tsEnd.longValue());
bfe038ff 461 setTimestampEnd(packetIndex.getTimestampEnd());
866e5b51 462 }
21fb02fa
MK
463
464 if (device != null) {
465 packetIndex.setTarget(device);
466 }
467
0594c61c
AM
468 if (cpuId != null) {
469 packetIndex.setTarget("CPU" + cpuId.toString()); //$NON-NLS-1$
21fb02fa 470 }
132a02b0
MK
471
472 if (lostEvents != null) {
f224bebc
MK
473 packetIndex.setLostEvents(lostEvents - fLostSoFar);
474 fLostSoFar = lostEvents;
132a02b0 475 }
866e5b51
FC
476 }
477
81c8e6f7
MK
478 @Override
479 public int hashCode() {
480 final int prime = 31;
481 int result = 1;
f224bebc 482 result = (prime * result) + ((fFile == null) ? 0 : fFile.hashCode());
81c8e6f7
MK
483 return result;
484 }
485
81c8e6f7
MK
486 @Override
487 public boolean equals(Object obj) {
488 if (this == obj) {
489 return true;
490 }
491 if (obj == null) {
492 return false;
493 }
494 if (!(obj instanceof StreamInput)) {
495 return false;
496 }
497 StreamInput other = (StreamInput) obj;
f224bebc
MK
498 if (fFile == null) {
499 if (other.fFile != null) {
81c8e6f7
MK
500 return false;
501 }
f224bebc 502 } else if (!fFile.equals(other.fFile)) {
81c8e6f7
MK
503 return false;
504 }
505 return true;
506 }
507
866e5b51 508}
This page took 0.070991 seconds and 5 git commands to generate.