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