LTTng: Bug 433210: Populate the CPU usage view during analysis
[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 *
ab04fc6b 224 * <strong>This method is slow and can corrupt data if not used properly</strong>
9ac2eb62
MK
225 * @return true if there are more packets to add
226 * @throws CTFReaderException
be6df2d8 227 * If there was a problem reading the packed header
9ac2eb62 228 */
bfe038ff
MK
229 public boolean addPacketHeaderIndex() throws CTFReaderException {
230 long currentPos = 0L;
f224bebc
MK
231 if (!fIndex.getEntries().isEmpty()) {
232 StreamInputPacketIndexEntry pos = fIndex.getEntries().lastElement();
bfe038ff
MK
233 currentPos = computeNextOffset(pos);
234 }
235 long fileSize = getStreamSize();
236 if (currentPos < fileSize) {
237 BitBuffer bitBuffer = new BitBuffer();
f224bebc 238 bitBuffer.setByteOrder(getStream().getTrace().getByteOrder());
bfe038ff
MK
239 StreamInputPacketIndexEntry packetIndex = new StreamInputPacketIndexEntry(
240 currentPos);
241 createPacketIndexEntry(fileSize, currentPos, packetIndex,
a4fa4e36 242 fTracePacketHeaderDecl, fStreamPacketContextDecl, bitBuffer);
f224bebc 243 fIndex.addEntry(packetIndex);
bfe038ff
MK
244 return true;
245 }
246 return false;
247 }
248
bfe038ff 249 private long getStreamSize() {
f224bebc 250 return fFile.length();
bfe038ff
MK
251 }
252
bfe038ff
MK
253 private long createPacketIndexEntry(long fileSizeBytes,
254 long packetOffsetBytes, StreamInputPacketIndexEntry packetIndex,
a4fa4e36
MK
255 StructDeclaration tracePacketHeaderDecl,
256 StructDeclaration streamPacketContextDecl, @NonNull BitBuffer bitBuffer)
bfe038ff 257 throws CTFReaderException {
0594c61c 258
cf9a28da
MK
259 /*
260 * Ignoring the return value, but this call is needed to initialize the
261 * input
262 */
0594c61c 263 createPacketBitBuffer(fileSizeBytes, packetOffsetBytes, packetIndex, bitBuffer);
bfe038ff 264
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
321 * @param bitBuffer
322 * @return
323 * @throws CTFReaderException
324 */
526c823c 325 private ByteBuffer createPacketBitBuffer(long fileSizeBytes,
aa3b05ef
FC
326 long packetOffsetBytes, StreamInputPacketIndexEntry packetIndex,
327 BitBuffer bitBuffer) throws CTFReaderException {
328 /*
329 * Initial size, it should map at least the packet header + context
330 * size.
331 *
332 * TODO: use a less arbitrary size.
333 */
334 long mapSize = 4096;
335 /*
336 * If there is less data remaining than what we want to map, reduce the
337 * map size.
338 */
339 if ((fileSizeBytes - packetIndex.getOffsetBytes()) < mapSize) {
340 mapSize = fileSizeBytes - packetIndex.getOffsetBytes();
341 }
342
343 /*
344 * Map the packet.
345 */
526c823c 346 ByteBuffer bb;
aa3b05ef
FC
347
348 try {
526c823c 349 bb = getByteBufferAt(packetOffsetBytes, mapSize);
aa3b05ef
FC
350 } catch (IOException e) {
351 throw new CTFReaderException(e);
352 }
353 bitBuffer.setByteBuffer(bb);
354 return bb;
355 }
bfe038ff 356
a4fa4e36
MK
357 private void parseTracePacketHeader(StructDeclaration tracePacketHeaderDecl,
358 @NonNull BitBuffer bitBuffer) throws CTFReaderException {
7e13cd66 359 StructDefinition tracePacketHeaderDef = tracePacketHeaderDecl.createDefinition(fStream.getTrace(), LexicalScope.TRACE_PACKET_HEADER.getName(), bitBuffer);
866e5b51
FC
360
361 /*
bfe038ff 362 * Check the CTF magic number
866e5b51 363 */
bfe038ff
MK
364 IntegerDefinition magicDef = (IntegerDefinition) tracePacketHeaderDef
365 .lookupDefinition("magic"); //$NON-NLS-1$
366 if (magicDef != null) {
367 int magic = (int) magicDef.getValue();
368 if (magic != Utils.CTF_MAGIC) {
369 throw new CTFReaderException(
370 "CTF magic mismatch " + Integer.toHexString(magic) + " vs " + Integer.toHexString(Utils.CTF_MAGIC)); //$NON-NLS-1$//$NON-NLS-2$
371 }
866e5b51
FC
372 }
373
374 /*
bfe038ff 375 * Check the trace UUID
866e5b51 376 */
0594c61c
AM
377 ArrayDefinition uuidDef =
378 (ArrayDefinition) tracePacketHeaderDef.lookupDefinition("uuid"); //$NON-NLS-1$
bfe038ff 379 if (uuidDef != null) {
a4fa4e36 380 UUID uuid = Utils.getUUIDfromDefinition(uuidDef);
866e5b51 381
bfe038ff
MK
382 if (!getStream().getTrace().getUUID().equals(uuid)) {
383 throw new CTFReaderException("UUID mismatch"); //$NON-NLS-1$
866e5b51 384 }
bfe038ff 385 }
866e5b51 386
bfe038ff
MK
387 /*
388 * Check that the stream id did not change
389 */
390 IntegerDefinition streamIDDef = (IntegerDefinition) tracePacketHeaderDef
391 .lookupDefinition("stream_id"); //$NON-NLS-1$
392 if (streamIDDef != null) {
393 long streamID = streamIDDef.getValue();
866e5b51 394
bfe038ff 395 if (streamID != getStream().getId()) {
cf9a28da 396 throw new CTFReaderException("Stream ID changing within a StreamInput"); //$NON-NLS-1$
866e5b51 397 }
bfe038ff
MK
398 }
399 }
866e5b51 400
bfe038ff
MK
401 private static void setPacketContextNull(long fileSizeBytes,
402 StreamInputPacketIndexEntry packetIndex) {
403 /*
404 * If there is no packet context, infer the content and packet size from
405 * the file size (assume that there is only one packet and no padding)
406 */
47ca6c05
SM
407 packetIndex.setContentSizeBits(fileSizeBytes * 8);
408 packetIndex.setPacketSizeBits(fileSizeBytes * 8);
bfe038ff 409 }
866e5b51 410
bfe038ff 411 private void parsePacketContext(long fileSizeBytes,
a4fa4e36 412 StructDeclaration streamPacketContextDecl, @NonNull BitBuffer bitBuffer,
db8e8f7d 413 StreamInputPacketIndexEntry packetIndex) throws CTFReaderException {
a4fa4e36 414 StructDefinition streamPacketContextDef = streamPacketContextDecl.createDefinition(null, LexicalScope.STREAM_PACKET_CONTEXT.getName(), bitBuffer);
866e5b51 415
21fb02fa
MK
416 for (String field : streamPacketContextDef.getDeclaration()
417 .getFieldsList()) {
418 Definition id = streamPacketContextDef.lookupDefinition(field);
419 if (id instanceof IntegerDefinition) {
420 packetIndex.addAttribute(field,
421 ((IntegerDefinition) id).getValue());
422 } else if (id instanceof FloatDefinition) {
423 packetIndex.addAttribute(field,
424 ((FloatDefinition) id).getValue());
425 } else if (id instanceof EnumDefinition) {
426 packetIndex.addAttribute(field,
427 ((EnumDefinition) id).getValue());
428 } else if (id instanceof StringDefinition) {
429 packetIndex.addAttribute(field,
430 ((StringDefinition) id).getValue());
431 }
21fb02fa
MK
432 }
433
434 Long contentSize = (Long) packetIndex.lookupAttribute("content_size"); //$NON-NLS-1$
435 Long packetSize = (Long) packetIndex.lookupAttribute("packet_size"); //$NON-NLS-1$
0594c61c
AM
436 Long tsBegin = (Long) packetIndex.lookupAttribute("timestamp_begin"); //$NON-NLS-1$
437 Long tsEnd = (Long) packetIndex.lookupAttribute("timestamp_end"); //$NON-NLS-1$
21fb02fa
MK
438 String device = (String) packetIndex.lookupAttribute("device"); //$NON-NLS-1$
439 // LTTng Specific
0594c61c 440 Long cpuId = (Long) packetIndex.lookupAttribute("cpu_id"); //$NON-NLS-1$
cf9a28da 441 Long lostEvents = (Long) packetIndex.lookupAttribute("events_discarded"); //$NON-NLS-1$
132a02b0
MK
442
443 /* Read the content size in bits */
21fb02fa
MK
444 if (contentSize != null) {
445 packetIndex.setContentSizeBits(contentSize.intValue());
cf9a28da
MK
446 } else if (packetSize != null) {
447 packetIndex.setContentSizeBits(packetSize.longValue());
bfe038ff
MK
448 } else {
449 packetIndex.setContentSizeBits((int) (fileSizeBytes * 8));
450 }
866e5b51 451
132a02b0 452 /* Read the packet size in bits */
21fb02fa
MK
453 if (packetSize != null) {
454 packetIndex.setPacketSizeBits(packetSize.intValue());
51598b21
MK
455 } else if (packetIndex.getContentSizeBits() != 0) {
456 packetIndex.setPacketSizeBits(packetIndex.getContentSizeBits());
bfe038ff 457 } else {
51598b21 458 packetIndex.setPacketSizeBits((int) (fileSizeBytes * 8));
bfe038ff
MK
459 }
460
132a02b0 461 /* Read the begin timestamp */
0594c61c
AM
462 if (tsBegin != null) {
463 packetIndex.setTimestampBegin(tsBegin.longValue());
bfe038ff
MK
464 }
465
132a02b0 466 /* Read the end timestamp */
0594c61c 467 if (tsEnd != null) {
ecb12461 468 if (tsEnd == -1) {
0594c61c 469 tsEnd = Long.MAX_VALUE;
21fb02fa 470 }
0594c61c 471 packetIndex.setTimestampEnd(tsEnd.longValue());
bfe038ff 472 setTimestampEnd(packetIndex.getTimestampEnd());
866e5b51 473 }
21fb02fa
MK
474
475 if (device != null) {
476 packetIndex.setTarget(device);
477 }
478
0594c61c
AM
479 if (cpuId != null) {
480 packetIndex.setTarget("CPU" + cpuId.toString()); //$NON-NLS-1$
21fb02fa 481 }
132a02b0
MK
482
483 if (lostEvents != null) {
f224bebc
MK
484 packetIndex.setLostEvents(lostEvents - fLostSoFar);
485 fLostSoFar = lostEvents;
132a02b0 486 }
866e5b51
FC
487 }
488
81c8e6f7
MK
489 @Override
490 public int hashCode() {
491 final int prime = 31;
492 int result = 1;
f224bebc 493 result = (prime * result) + ((fFile == null) ? 0 : fFile.hashCode());
81c8e6f7
MK
494 return result;
495 }
496
81c8e6f7
MK
497 @Override
498 public boolean equals(Object obj) {
499 if (this == obj) {
500 return true;
501 }
502 if (obj == null) {
503 return false;
504 }
d84419e1 505 if (!(obj instanceof CTFStreamInput)) {
81c8e6f7
MK
506 return false;
507 }
d84419e1 508 CTFStreamInput other = (CTFStreamInput) obj;
f224bebc
MK
509 if (fFile == null) {
510 if (other.fFile != null) {
81c8e6f7
MK
511 return false;
512 }
f224bebc 513 } else if (!fFile.equals(other.fFile)) {
81c8e6f7
MK
514 return false;
515 }
516 return true;
517 }
518
866e5b51 519}
This page took 0.069528 seconds and 5 git commands to generate.