Remove all existing @since annotations
[deliverable/tracecompass.git] / org.eclipse.tracecompass.ctf.core / src / org / eclipse / tracecompass / 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
f357bcd4 13package org.eclipse.tracecompass.ctf.core.trace;
866e5b51
FC
14
15import java.io.File;
aa3b05ef 16import java.io.IOException;
f4a474e3 17import java.nio.ByteBuffer;
866e5b51 18import java.nio.channels.FileChannel;
aa3b05ef 19import java.nio.channels.FileChannel.MapMode;
b3151232 20import java.nio.file.StandardOpenOption;
866e5b51
FC
21import java.util.UUID;
22
a4fa4e36 23import org.eclipse.jdt.annotation.NonNull;
453a59f0 24import org.eclipse.tracecompass.ctf.core.CTFReaderException;
f357bcd4
AM
25import org.eclipse.tracecompass.ctf.core.event.io.BitBuffer;
26import org.eclipse.tracecompass.ctf.core.event.scope.IDefinitionScope;
27import org.eclipse.tracecompass.ctf.core.event.scope.LexicalScope;
28import org.eclipse.tracecompass.ctf.core.event.types.Definition;
29import org.eclipse.tracecompass.ctf.core.event.types.EnumDefinition;
30import org.eclipse.tracecompass.ctf.core.event.types.FloatDefinition;
31import org.eclipse.tracecompass.ctf.core.event.types.IDefinition;
32import org.eclipse.tracecompass.ctf.core.event.types.IntegerDefinition;
33import org.eclipse.tracecompass.ctf.core.event.types.StringDefinition;
34import org.eclipse.tracecompass.ctf.core.event.types.StructDeclaration;
35import org.eclipse.tracecompass.ctf.core.event.types.StructDefinition;
36import org.eclipse.tracecompass.internal.ctf.core.SafeMappedByteBuffer;
37import org.eclipse.tracecompass.internal.ctf.core.event.types.ArrayDefinition;
38import org.eclipse.tracecompass.internal.ctf.core.trace.StreamInputPacketIndex;
39import org.eclipse.tracecompass.internal.ctf.core.trace.StreamInputPacketIndexEntry;
866e5b51
FC
40
41/**
42 * <b><u>StreamInput</u></b>
43 * <p>
44 * Represents a trace file that belongs to a certain stream.
45 */
46167f03 46public class CTFStreamInput implements IDefinitionScope {
866e5b51
FC
47
48 // ------------------------------------------------------------------------
49 // Attributes
50 // ------------------------------------------------------------------------
51
f068c622
MK
52 private static final int BITS_PER_BYTE = Byte.SIZE;
53
866e5b51
FC
54 /**
55 * The associated Stream
56 */
d84419e1 57 private final CTFStream fStream;
866e5b51 58
866e5b51
FC
59 /**
60 * Information on the file (used for debugging)
61 */
b3151232 62 @NonNull
f224bebc 63 private final File fFile;
866e5b51
FC
64
65 /**
66 * The packet index of this input
67 */
f224bebc 68 private final StreamInputPacketIndex fIndex;
866e5b51 69
f224bebc 70 private long fTimestampEnd;
866e5b51 71
8e15b929 72 /**
bfe038ff
MK
73 * Definition of trace packet header
74 */
a4fa4e36 75 private StructDeclaration fTracePacketHeaderDecl = null;
bfe038ff 76
8e15b929 77 /**
bfe038ff
MK
78 * Definition of trace stream packet context
79 */
a4fa4e36 80 private StructDeclaration fStreamPacketContextDecl = null;
bfe038ff 81
8e15b929 82 /**
132a02b0
MK
83 * Total number of lost events in this stream
84 */
f224bebc 85 private long fLostSoFar = 0;
132a02b0 86
866e5b51
FC
87 // ------------------------------------------------------------------------
88 // Constructors
89 // ------------------------------------------------------------------------
90
91 /**
92 * Constructs a StreamInput.
93 *
94 * @param stream
95 * The stream to which this StreamInput belongs to.
866e5b51
FC
96 * @param file
97 * Information about the trace file (for debugging purposes).
98 */
b3151232 99 public CTFStreamInput(CTFStream stream, @NonNull File file) {
f224bebc 100 fStream = stream;
f224bebc
MK
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 */
d84419e1 114 public CTFStream 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 160 @Override
a4fa4e36
MK
161 public LexicalScope getScopePath() {
162 return LexicalScope.STREAM;
866e5b51
FC
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) {
a4fa4e36 190 fTracePacketHeaderDecl = getStream().getTrace().getPacketHeader();
bfe038ff
MK
191 }
192
193 if (getStream().getPacketContextDecl() != null) {
a4fa4e36 194 fStreamPacketContextDecl = getStream().getPacketContextDecl();
bfe038ff
MK
195 }
196
197 }
198
9ac2eb62
MK
199 /**
200 * Adds the next packet header index entry to the index of a stream input.
be6df2d8 201 *
733c614c
MK
202 * <strong>This method is slow and can corrupt data if not used
203 * properly</strong>
204 *
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;
3f02ac64
MK
211 if (!fIndex.isEmpty()) {
212 StreamInputPacketIndexEntry pos = fIndex.lastElement();
bfe038ff
MK
213 currentPos = computeNextOffset(pos);
214 }
215 long fileSize = getStreamSize();
216 if (currentPos < fileSize) {
733c614c 217
bfe038ff
MK
218 StreamInputPacketIndexEntry packetIndex = new StreamInputPacketIndexEntry(
219 currentPos);
b3151232 220 createPacketIndexEntry(fileSize, currentPos, packetIndex);
3f02ac64 221 fIndex.append(packetIndex);
bfe038ff
MK
222 return true;
223 }
224 return false;
225 }
226
bfe038ff 227 private long getStreamSize() {
f224bebc 228 return fFile.length();
bfe038ff
MK
229 }
230
b3151232 231 private long createPacketIndexEntry(long fileSizeBytes, long packetOffsetBytes, StreamInputPacketIndexEntry packetIndex)
bfe038ff 232 throws CTFReaderException {
0594c61c 233
b3151232 234 long pos = readPacketHeader(fileSizeBytes, packetOffsetBytes, packetIndex);
bfe038ff
MK
235
236 /* Basic validation */
237 if (packetIndex.getContentSizeBits() > packetIndex.getPacketSizeBits()) {
238 throw new CTFReaderException("Content size > packet size"); //$NON-NLS-1$
239 }
866e5b51 240
bfe038ff 241 if (packetIndex.getPacketSizeBits() > ((fileSizeBytes - packetIndex
f068c622 242 .getOffsetBytes()) * BITS_PER_BYTE)) {
cf9a28da 243 throw new CTFReaderException("Not enough data remaining in the file for the size of this packet"); //$NON-NLS-1$
bfe038ff
MK
244 }
245
246 /*
247 * Offset in the file, in bits
248 */
b3151232 249 packetIndex.setDataOffsetBits(pos);
bfe038ff
MK
250
251 /*
252 * Update the counting packet offset
253 */
21fb02fa 254 return computeNextOffset(packetIndex);
bfe038ff
MK
255 }
256
257 /**
258 * @param packetIndex
259 * @return
260 */
261 private static long computeNextOffset(
262 StreamInputPacketIndexEntry packetIndex) {
263 return packetIndex.getOffsetBytes()
f068c622 264 + ((packetIndex.getPacketSizeBits() + BITS_PER_BYTE - 1) / BITS_PER_BYTE);
bfe038ff
MK
265 }
266
b3151232 267 private long readPacketHeader(long fileSizeBytes,
733c614c 268 long packetOffsetBytes, StreamInputPacketIndexEntry packetIndex) throws CTFReaderException {
b3151232 269 long position = -1;
aa3b05ef
FC
270 /*
271 * Initial size, it should map at least the packet header + context
272 * size.
273 *
274 * TODO: use a less arbitrary size.
275 */
276 long mapSize = 4096;
277 /*
278 * If there is less data remaining than what we want to map, reduce the
279 * map size.
280 */
281 if ((fileSizeBytes - packetIndex.getOffsetBytes()) < mapSize) {
282 mapSize = fileSizeBytes - packetIndex.getOffsetBytes();
283 }
284
285 /*
286 * Map the packet.
287 */
b3151232 288 try (FileChannel fc = FileChannel.open(fFile.toPath(), StandardOpenOption.READ)) {
f4a474e3 289 ByteBuffer map = SafeMappedByteBuffer.map(fc, MapMode.READ_ONLY, packetOffsetBytes, mapSize);
b3151232
MK
290 if (map == null) {
291 throw new CTFReaderException("Failed to allocate mapped byte buffer"); //$NON-NLS-1$
292 }
293 /*
294 * create a packet bit buffer to read the packet header
295 */
296 BitBuffer bitBuffer = new BitBuffer(map);
297 bitBuffer.setByteOrder(getStream().getTrace().getByteOrder());
298 /*
299 * Read the trace packet header if it exists.
300 */
301 if (fTracePacketHeaderDecl != null) {
302 parseTracePacketHeader(fTracePacketHeaderDecl, bitBuffer);
303 }
304
305 /*
306 * Read the stream packet context if it exists.
307 */
308 if (fStreamPacketContextDecl != null) {
309 parsePacketContext(fileSizeBytes, fStreamPacketContextDecl,
310 bitBuffer, packetIndex);
311 } else {
312 setPacketContextNull(fileSizeBytes, packetIndex);
313 }
314
315 position = bitBuffer.position();
aa3b05ef
FC
316 } catch (IOException e) {
317 throw new CTFReaderException(e);
318 }
b3151232 319 return position;
aa3b05ef 320 }
bfe038ff 321
a4fa4e36
MK
322 private void parseTracePacketHeader(StructDeclaration tracePacketHeaderDecl,
323 @NonNull BitBuffer bitBuffer) throws CTFReaderException {
70f60307 324 StructDefinition tracePacketHeaderDef = tracePacketHeaderDecl.createDefinition(fStream.getTrace(), LexicalScope.TRACE_PACKET_HEADER, bitBuffer);
866e5b51
FC
325
326 /*
bfe038ff 327 * Check the CTF magic number
866e5b51 328 */
bfe038ff
MK
329 IntegerDefinition magicDef = (IntegerDefinition) tracePacketHeaderDef
330 .lookupDefinition("magic"); //$NON-NLS-1$
331 if (magicDef != null) {
332 int magic = (int) magicDef.getValue();
333 if (magic != Utils.CTF_MAGIC) {
334 throw new CTFReaderException(
335 "CTF magic mismatch " + Integer.toHexString(magic) + " vs " + Integer.toHexString(Utils.CTF_MAGIC)); //$NON-NLS-1$//$NON-NLS-2$
336 }
866e5b51
FC
337 }
338
339 /*
bfe038ff 340 * Check the trace UUID
866e5b51 341 */
0594c61c
AM
342 ArrayDefinition uuidDef =
343 (ArrayDefinition) tracePacketHeaderDef.lookupDefinition("uuid"); //$NON-NLS-1$
bfe038ff 344 if (uuidDef != null) {
a4fa4e36 345 UUID uuid = Utils.getUUIDfromDefinition(uuidDef);
866e5b51 346
bfe038ff
MK
347 if (!getStream().getTrace().getUUID().equals(uuid)) {
348 throw new CTFReaderException("UUID mismatch"); //$NON-NLS-1$
866e5b51 349 }
bfe038ff 350 }
866e5b51 351
bfe038ff
MK
352 /*
353 * Check that the stream id did not change
354 */
355 IntegerDefinition streamIDDef = (IntegerDefinition) tracePacketHeaderDef
356 .lookupDefinition("stream_id"); //$NON-NLS-1$
357 if (streamIDDef != null) {
358 long streamID = streamIDDef.getValue();
866e5b51 359
bfe038ff 360 if (streamID != getStream().getId()) {
cf9a28da 361 throw new CTFReaderException("Stream ID changing within a StreamInput"); //$NON-NLS-1$
866e5b51 362 }
bfe038ff
MK
363 }
364 }
866e5b51 365
b3151232
MK
366 /**
367 * Gets the wrapped file
368 *
369 * @return the file
370 */
371 @NonNull
372 File getFile() {
373 return fFile;
374 }
375
bfe038ff
MK
376 private static void setPacketContextNull(long fileSizeBytes,
377 StreamInputPacketIndexEntry packetIndex) {
378 /*
379 * If there is no packet context, infer the content and packet size from
380 * the file size (assume that there is only one packet and no padding)
381 */
f068c622
MK
382 packetIndex.setContentSizeBits(fileSizeBytes * BITS_PER_BYTE);
383 packetIndex.setPacketSizeBits(fileSizeBytes * BITS_PER_BYTE);
bfe038ff 384 }
866e5b51 385
bfe038ff 386 private void parsePacketContext(long fileSizeBytes,
a4fa4e36 387 StructDeclaration streamPacketContextDecl, @NonNull BitBuffer bitBuffer,
db8e8f7d 388 StreamInputPacketIndexEntry packetIndex) throws CTFReaderException {
70f60307 389 StructDefinition streamPacketContextDef = streamPacketContextDecl.createDefinition(this, LexicalScope.STREAM_PACKET_CONTEXT, bitBuffer);
866e5b51 390
21fb02fa
MK
391 for (String field : streamPacketContextDef.getDeclaration()
392 .getFieldsList()) {
cc98c947 393 IDefinition id = streamPacketContextDef.lookupDefinition(field);
21fb02fa
MK
394 if (id instanceof IntegerDefinition) {
395 packetIndex.addAttribute(field,
396 ((IntegerDefinition) id).getValue());
397 } else if (id instanceof FloatDefinition) {
398 packetIndex.addAttribute(field,
399 ((FloatDefinition) id).getValue());
400 } else if (id instanceof EnumDefinition) {
401 packetIndex.addAttribute(field,
402 ((EnumDefinition) id).getValue());
403 } else if (id instanceof StringDefinition) {
404 packetIndex.addAttribute(field,
405 ((StringDefinition) id).getValue());
406 }
21fb02fa
MK
407 }
408
409 Long contentSize = (Long) packetIndex.lookupAttribute("content_size"); //$NON-NLS-1$
410 Long packetSize = (Long) packetIndex.lookupAttribute("packet_size"); //$NON-NLS-1$
0594c61c
AM
411 Long tsBegin = (Long) packetIndex.lookupAttribute("timestamp_begin"); //$NON-NLS-1$
412 Long tsEnd = (Long) packetIndex.lookupAttribute("timestamp_end"); //$NON-NLS-1$
21fb02fa
MK
413 String device = (String) packetIndex.lookupAttribute("device"); //$NON-NLS-1$
414 // LTTng Specific
0594c61c 415 Long cpuId = (Long) packetIndex.lookupAttribute("cpu_id"); //$NON-NLS-1$
cf9a28da 416 Long lostEvents = (Long) packetIndex.lookupAttribute("events_discarded"); //$NON-NLS-1$
132a02b0
MK
417
418 /* Read the content size in bits */
21fb02fa 419 if (contentSize != null) {
b6dfd62a 420 packetIndex.setContentSizeBits(contentSize.longValue());
cf9a28da
MK
421 } else if (packetSize != null) {
422 packetIndex.setContentSizeBits(packetSize.longValue());
bfe038ff 423 } else {
f068c622 424 packetIndex.setContentSizeBits((int) (fileSizeBytes * BITS_PER_BYTE));
bfe038ff 425 }
866e5b51 426
132a02b0 427 /* Read the packet size in bits */
21fb02fa 428 if (packetSize != null) {
b6dfd62a 429 packetIndex.setPacketSizeBits(packetSize.longValue());
51598b21
MK
430 } else if (packetIndex.getContentSizeBits() != 0) {
431 packetIndex.setPacketSizeBits(packetIndex.getContentSizeBits());
bfe038ff 432 } else {
f068c622 433 packetIndex.setPacketSizeBits((int) (fileSizeBytes * BITS_PER_BYTE));
bfe038ff
MK
434 }
435
132a02b0 436 /* Read the begin timestamp */
0594c61c
AM
437 if (tsBegin != null) {
438 packetIndex.setTimestampBegin(tsBegin.longValue());
bfe038ff
MK
439 }
440
132a02b0 441 /* Read the end timestamp */
0594c61c 442 if (tsEnd != null) {
ecb12461 443 if (tsEnd == -1) {
0594c61c 444 tsEnd = Long.MAX_VALUE;
21fb02fa 445 }
0594c61c 446 packetIndex.setTimestampEnd(tsEnd.longValue());
bfe038ff 447 setTimestampEnd(packetIndex.getTimestampEnd());
866e5b51 448 }
21fb02fa
MK
449
450 if (device != null) {
451 packetIndex.setTarget(device);
452 }
453
0594c61c
AM
454 if (cpuId != null) {
455 packetIndex.setTarget("CPU" + cpuId.toString()); //$NON-NLS-1$
21fb02fa 456 }
132a02b0
MK
457
458 if (lostEvents != null) {
f224bebc
MK
459 packetIndex.setLostEvents(lostEvents - fLostSoFar);
460 fLostSoFar = lostEvents;
132a02b0 461 }
866e5b51
FC
462 }
463
81c8e6f7
MK
464 @Override
465 public int hashCode() {
466 final int prime = 31;
467 int result = 1;
b3151232 468 result = (prime * result) + fFile.hashCode();
81c8e6f7
MK
469 return result;
470 }
471
81c8e6f7
MK
472 @Override
473 public boolean equals(Object obj) {
474 if (this == obj) {
475 return true;
476 }
477 if (obj == null) {
478 return false;
479 }
d84419e1 480 if (!(obj instanceof CTFStreamInput)) {
81c8e6f7
MK
481 return false;
482 }
d84419e1 483 CTFStreamInput other = (CTFStreamInput) obj;
b3151232 484 if (!fFile.equals(other.fFile)) {
81c8e6f7
MK
485 return false;
486 }
487 return true;
488 }
489
866e5b51 490}
This page took 0.082224 seconds and 5 git commands to generate.