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