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