LTTNG: Bug 436857: Keep process selection in CPU Usage tree viewer
[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;
866e5b51 20import java.nio.channels.FileChannel;
aa3b05ef 21import java.nio.channels.FileChannel.MapMode;
866e5b51
FC
22import java.util.UUID;
23
a4fa4e36 24import org.eclipse.jdt.annotation.NonNull;
486efb2e 25import org.eclipse.linuxtools.ctf.core.event.io.BitBuffer;
a4fa4e36
MK
26import org.eclipse.linuxtools.ctf.core.event.scope.IDefinitionScope;
27import org.eclipse.linuxtools.ctf.core.event.scope.LexicalScope;
866e5b51 28import org.eclipse.linuxtools.ctf.core.event.types.Definition;
21fb02fa
MK
29import org.eclipse.linuxtools.ctf.core.event.types.EnumDefinition;
30import org.eclipse.linuxtools.ctf.core.event.types.FloatDefinition;
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;
7b4f13e6 35import org.eclipse.linuxtools.internal.ctf.core.event.types.ArrayDefinition;
486efb2e
AM
36import org.eclipse.linuxtools.internal.ctf.core.trace.StreamInputPacketIndex;
37import org.eclipse.linuxtools.internal.ctf.core.trace.StreamInputPacketIndexEntry;
866e5b51
FC
38
39/**
40 * <b><u>StreamInput</u></b>
41 * <p>
42 * Represents a trace file that belongs to a certain stream.
cf9a28da 43 *
d84419e1 44 * @since 3.0
866e5b51 45 */
d84419e1 46public class CTFStreamInput implements IDefinitionScope, AutoCloseable {
866e5b51
FC
47
48 // ------------------------------------------------------------------------
49 // Attributes
50 // ------------------------------------------------------------------------
51
52 /**
53 * The associated Stream
54 */
d84419e1 55 private final CTFStream fStream;
866e5b51
FC
56
57 /**
58 * FileChannel to the trace file
59 */
f224bebc 60 private final FileChannel fFileChannel;
866e5b51
FC
61
62 /**
63 * Information on the file (used for debugging)
64 */
f224bebc 65 private final File fFile;
866e5b51
FC
66
67 /**
68 * The packet index of this input
69 */
f224bebc 70 private final StreamInputPacketIndex fIndex;
866e5b51 71
f224bebc 72 private long fTimestampEnd;
866e5b51 73
8e15b929 74 /**
bfe038ff
MK
75 * Definition of trace packet header
76 */
a4fa4e36 77 private StructDeclaration fTracePacketHeaderDecl = null;
bfe038ff 78
8e15b929 79 /**
bfe038ff
MK
80 * Definition of trace stream packet context
81 */
a4fa4e36 82 private StructDeclaration fStreamPacketContextDecl = null;
bfe038ff 83
8e15b929 84 /**
132a02b0
MK
85 * Total number of lost events in this stream
86 */
f224bebc 87 private long fLostSoFar = 0;
132a02b0 88
8e15b929
MK
89 /**
90 * File input stream, the parent input file
91 */
92 private final FileInputStream fFileInputStream;
93
866e5b51
FC
94 // ------------------------------------------------------------------------
95 // Constructors
96 // ------------------------------------------------------------------------
97
98 /**
99 * Constructs a StreamInput.
100 *
101 * @param stream
102 * The stream to which this StreamInput belongs to.
866e5b51
FC
103 * @param file
104 * Information about the trace file (for debugging purposes).
8e15b929
MK
105 * @throws CTFReaderException
106 * The file must exist
866e5b51 107 */
d84419e1 108 public CTFStreamInput(CTFStream stream, File file) throws CTFReaderException {
f224bebc 109 fStream = stream;
f224bebc 110 fFile = file;
8e15b929
MK
111 try {
112 fFileInputStream = new FileInputStream(file);
113 } catch (FileNotFoundException e) {
114 throw new CTFReaderException(e);
115 }
116
117 fFileChannel = fFileInputStream.getChannel();
f224bebc 118 fIndex = new StreamInputPacketIndex();
866e5b51
FC
119 }
120
8e15b929
MK
121 @Override
122 public void close() throws IOException {
123 fFileChannel.close();
124 fFileInputStream.close();
125 }
126
866e5b51
FC
127 // ------------------------------------------------------------------------
128 // Getters/Setters/Predicates
129 // ------------------------------------------------------------------------
130
9ac2eb62
MK
131 /**
132 * Gets the stream the streamInput wrapper is wrapping
21fb02fa 133 *
9ac2eb62
MK
134 * @return the stream the streamInput wrapper is wrapping
135 */
d84419e1 136 public CTFStream getStream() {
f224bebc 137 return fStream;
866e5b51
FC
138 }
139
9ac2eb62 140 /**
ecb12461 141 * The common streamInput Index
21fb02fa 142 *
9ac2eb62
MK
143 * @return the stream input Index
144 */
486efb2e 145 StreamInputPacketIndex getIndex() {
f224bebc 146 return fIndex;
866e5b51
FC
147 }
148
9ac2eb62
MK
149 /**
150 * Gets the filename of the streamInput file.
21fb02fa 151 *
9ac2eb62
MK
152 * @return the filename of the streaminput file.
153 */
866e5b51 154 public String getFilename() {
f224bebc 155 return fFile.getName();
866e5b51
FC
156 }
157
9ac2eb62 158 /**
ecb12461 159 * Gets the last read timestamp of a stream. (this is not necessarily the
21fb02fa
MK
160 * last time in the stream.)
161 *
9ac2eb62
MK
162 * @return the last read timestamp
163 */
866e5b51 164 public long getTimestampEnd() {
f224bebc 165 return fTimestampEnd;
866e5b51
FC
166 }
167
9ac2eb62 168 /**
21fb02fa
MK
169 * Sets the last read timestamp of a stream. (this is not necessarily the
170 * last time in the stream.)
171 *
172 * @param timestampEnd
173 * the last read timestamp
9ac2eb62 174 */
866e5b51 175 public void setTimestampEnd(long timestampEnd) {
f224bebc 176 fTimestampEnd = timestampEnd;
866e5b51
FC
177 }
178
9ac2eb62 179 /**
ecb12461 180 * Useless for streaminputs
9ac2eb62 181 */
866e5b51 182 @Override
a4fa4e36
MK
183 public LexicalScope getScopePath() {
184 return LexicalScope.STREAM;
866e5b51
FC
185 }
186
187 // ------------------------------------------------------------------------
188 // Operations
189 // ------------------------------------------------------------------------
190
191 @Override
192 public Definition lookupDefinition(String lookupPath) {
193 /* TODO: lookup in different dynamic scopes is not supported yet. */
194 return null;
195 }
196
197 /**
198 * Create the index for this trace file.
bfe038ff
MK
199 */
200 public void setupIndex() {
201
bfe038ff
MK
202 /*
203 * The BitBuffer to extract data from the StreamInput
204 */
205 BitBuffer bitBuffer = new BitBuffer();
f224bebc 206 bitBuffer.setByteOrder(getStream().getTrace().getByteOrder());
bfe038ff
MK
207
208 /*
209 * Create the definitions we need to read the packet headers + contexts
210 */
211 if (getStream().getTrace().getPacketHeader() != null) {
a4fa4e36 212 fTracePacketHeaderDecl = getStream().getTrace().getPacketHeader();
bfe038ff
MK
213 }
214
215 if (getStream().getPacketContextDecl() != null) {
a4fa4e36 216 fStreamPacketContextDecl = getStream().getPacketContextDecl();
bfe038ff
MK
217 }
218
219 }
220
9ac2eb62
MK
221 /**
222 * Adds the next packet header index entry to the index of a stream input.
be6df2d8 223 *
733c614c
MK
224 * <strong>This method is slow and can corrupt data if not used
225 * properly</strong>
226 *
9ac2eb62
MK
227 * @return true if there are more packets to add
228 * @throws CTFReaderException
be6df2d8 229 * If there was a problem reading the packed header
9ac2eb62 230 */
bfe038ff
MK
231 public boolean addPacketHeaderIndex() throws CTFReaderException {
232 long currentPos = 0L;
f224bebc
MK
233 if (!fIndex.getEntries().isEmpty()) {
234 StreamInputPacketIndexEntry pos = fIndex.getEntries().lastElement();
bfe038ff
MK
235 currentPos = computeNextOffset(pos);
236 }
237 long fileSize = getStreamSize();
238 if (currentPos < fileSize) {
733c614c 239
bfe038ff
MK
240 StreamInputPacketIndexEntry packetIndex = new StreamInputPacketIndexEntry(
241 currentPos);
242 createPacketIndexEntry(fileSize, currentPos, packetIndex,
733c614c 243 fTracePacketHeaderDecl, fStreamPacketContextDecl);
f224bebc 244 fIndex.addEntry(packetIndex);
bfe038ff
MK
245 return true;
246 }
247 return false;
248 }
249
bfe038ff 250 private long getStreamSize() {
f224bebc 251 return fFile.length();
bfe038ff
MK
252 }
253
bfe038ff
MK
254 private long createPacketIndexEntry(long fileSizeBytes,
255 long packetOffsetBytes, StreamInputPacketIndexEntry packetIndex,
a4fa4e36 256 StructDeclaration tracePacketHeaderDecl,
733c614c 257 StructDeclaration streamPacketContextDecl)
bfe038ff 258 throws CTFReaderException {
0594c61c 259
cf9a28da 260 /*
733c614c 261 * create a packet bit buffer to read the packet header
cf9a28da 262 */
733c614c
MK
263 BitBuffer bitBuffer = new BitBuffer(createPacketBitBuffer(fileSizeBytes, packetOffsetBytes, packetIndex));
264 bitBuffer.setByteOrder(getStream().getTrace().getByteOrder());
866e5b51 265 /*
bfe038ff 266 * Read the trace packet header if it exists.
866e5b51 267 */
a4fa4e36
MK
268 if (tracePacketHeaderDecl != null) {
269 parseTracePacketHeader(tracePacketHeaderDecl, bitBuffer);
866e5b51
FC
270 }
271
272 /*
bfe038ff 273 * Read the stream packet context if it exists.
866e5b51 274 */
a4fa4e36
MK
275 if (streamPacketContextDecl != null) {
276 parsePacketContext(fileSizeBytes, streamPacketContextDecl,
bfe038ff
MK
277 bitBuffer, packetIndex);
278 } else {
279 setPacketContextNull(fileSizeBytes, packetIndex);
280 }
281
282 /* Basic validation */
283 if (packetIndex.getContentSizeBits() > packetIndex.getPacketSizeBits()) {
284 throw new CTFReaderException("Content size > packet size"); //$NON-NLS-1$
285 }
866e5b51 286
bfe038ff
MK
287 if (packetIndex.getPacketSizeBits() > ((fileSizeBytes - packetIndex
288 .getOffsetBytes()) * 8)) {
cf9a28da 289 throw new CTFReaderException("Not enough data remaining in the file for the size of this packet"); //$NON-NLS-1$
bfe038ff
MK
290 }
291
292 /*
293 * Offset in the file, in bits
294 */
295 packetIndex.setDataOffsetBits(bitBuffer.position());
296
297 /*
298 * Update the counting packet offset
299 */
21fb02fa 300 return computeNextOffset(packetIndex);
bfe038ff
MK
301 }
302
303 /**
304 * @param packetIndex
305 * @return
306 */
307 private static long computeNextOffset(
308 StreamInputPacketIndexEntry packetIndex) {
309 return packetIndex.getOffsetBytes()
310 + ((packetIndex.getPacketSizeBits() + 7) / 8);
311 }
312
526c823c 313 ByteBuffer getByteBufferAt(long position, long size) throws IOException {
f224bebc 314 return fFileChannel.map(MapMode.READ_ONLY, position, size);
526c823c
EB
315 }
316
aa3b05ef
FC
317 /**
318 * @param fileSizeBytes
319 * @param packetOffsetBytes
320 * @param packetIndex
aa3b05ef
FC
321 * @return
322 * @throws CTFReaderException
323 */
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 {
7e13cd66 353 StructDefinition tracePacketHeaderDef = tracePacketHeaderDecl.createDefinition(fStream.getTrace(), LexicalScope.TRACE_PACKET_HEADER.getName(), 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 {
a4fa4e36 408 StructDefinition streamPacketContextDef = streamPacketContextDecl.createDefinition(null, LexicalScope.STREAM_PACKET_CONTEXT.getName(), 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.068079 seconds and 5 git commands to generate.