gdbtrace: Rename packages to org.eclipse.tracecompass.*
[deliverable/tracecompass.git] / org.eclipse.tracecompass.ctf.core / src / org / eclipse / linuxtools / ctf / core / trace / CTFTrace.java
CommitLineData
866e5b51 1/*******************************************************************************
fe75d403 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 *
4311ac8b
MAL
9 * Contributors:
10 * Matthew Khouzam - Initial API and implementation
11 * Alexandre Montplaisir - Initial API and implementation
890f9136 12 * Simon Delisle - Replace LinkedList by TreeSet in callsitesByName attribute
866e5b51
FC
13 *******************************************************************************/
14
15package org.eclipse.linuxtools.ctf.core.trace;
16
17import java.io.File;
18import java.io.FileFilter;
866e5b51 19import java.io.IOException;
debcffff 20import java.io.Serializable;
f4a474e3 21import java.nio.ByteBuffer;
866e5b51 22import java.nio.ByteOrder;
866e5b51
FC
23import java.nio.channels.FileChannel;
24import java.nio.channels.FileChannel.MapMode;
219d054e 25import java.nio.file.StandardOpenOption;
866e5b51 26import java.util.Arrays;
5f715709 27import java.util.Collection;
a95fddf5 28import java.util.Collections;
866e5b51
FC
29import java.util.Comparator;
30import java.util.HashMap;
31import java.util.Map;
32import java.util.Set;
4c9d2941 33import java.util.TreeSet;
866e5b51
FC
34import java.util.UUID;
35
4c9d2941 36import org.eclipse.linuxtools.ctf.core.event.CTFCallsite;
866e5b51 37import org.eclipse.linuxtools.ctf.core.event.CTFClock;
8e964be1 38import org.eclipse.linuxtools.ctf.core.event.IEventDeclaration;
486efb2e 39import org.eclipse.linuxtools.ctf.core.event.io.BitBuffer;
a4fa4e36
MK
40import org.eclipse.linuxtools.ctf.core.event.scope.IDefinitionScope;
41import org.eclipse.linuxtools.ctf.core.event.scope.LexicalScope;
866e5b51 42import org.eclipse.linuxtools.ctf.core.event.types.Definition;
cc98c947 43import org.eclipse.linuxtools.ctf.core.event.types.IDefinition;
866e5b51
FC
44import org.eclipse.linuxtools.ctf.core.event.types.IntegerDefinition;
45import org.eclipse.linuxtools.ctf.core.event.types.StructDeclaration;
46import org.eclipse.linuxtools.ctf.core.event.types.StructDefinition;
f4a474e3 47import org.eclipse.linuxtools.internal.ctf.core.SafeMappedByteBuffer;
890f9136 48import org.eclipse.linuxtools.internal.ctf.core.event.CTFCallsiteComparator;
ce2388e0 49import org.eclipse.linuxtools.internal.ctf.core.event.metadata.exceptions.ParseException;
7b4f13e6 50import org.eclipse.linuxtools.internal.ctf.core.event.types.ArrayDefinition;
866e5b51
FC
51
52/**
d37aaa7f
FC
53 * A CTF trace on the file system.
54 *
866e5b51
FC
55 * Represents a trace on the filesystem. It is responsible of parsing the
56 * metadata, creating declarations data structures, indexing the event packets
57 * (in other words, all the work that can be shared between readers), but the
58 * actual reading of events is left to TraceReader.
debcffff 59 *
866e5b51
FC
60 * @author Matthew Khouzam
61 * @version $Revision: 1.0 $
62 */
dd9752d5 63public class CTFTrace implements IDefinitionScope, AutoCloseable {
866e5b51 64
866e5b51
FC
65 @Override
66 public String toString() {
67 /* Only for debugging, shouldn't be externalized */
a4fa4e36
MK
68 return "CTFTrace [path=" + fPath + ", major=" + fMajor + ", minor=" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
69 + fMinor + ", uuid=" + fUuid + "]"; //$NON-NLS-1$ //$NON-NLS-2$
866e5b51
FC
70 }
71
72 /**
73 * The trace directory on the filesystem.
74 */
fe75d403 75 private final File fPath;
866e5b51 76
866e5b51
FC
77 /**
78 * Major CTF version number
79 */
fe75d403 80 private Long fMajor;
866e5b51
FC
81
82 /**
83 * Minor CTF version number
84 */
fe75d403 85 private Long fMinor;
866e5b51
FC
86
87 /**
88 * Trace UUID
89 */
fe75d403 90 private UUID fUuid;
866e5b51
FC
91
92 /**
93 * Trace byte order
94 */
fe75d403 95 private ByteOrder fByteOrder;
866e5b51
FC
96
97 /**
98 * Packet header structure declaration
99 */
fe75d403 100 private StructDeclaration fPacketHeaderDecl = null;
866e5b51 101
1d7277f3
MK
102 /**
103 * The clock of the trace
104 */
ede59fc8 105 private CTFClock fSingleClock = null;
1d7277f3 106
866e5b51
FC
107 /**
108 * Packet header structure definition
debcffff 109 *
866e5b51
FC
110 * This is only used when opening the trace files, to read the first packet
111 * header and see if they are valid trace files.
112 */
fe75d403 113 private StructDefinition fPacketHeaderDef;
866e5b51
FC
114
115 /**
116 * Collection of streams contained in the trace.
117 */
d84419e1 118 private final Map<Long, CTFStream> fStreams = new HashMap<>();
866e5b51
FC
119
120 /**
121 * Collection of environment variables set by the tracer
122 */
fe75d403 123 private final Map<String, String> fEnvironment = new HashMap<>();
866e5b51
FC
124
125 /**
126 * Collection of all the clocks in a system.
127 */
fe75d403 128 private final Map<String, CTFClock> fClocks = new HashMap<>();
866e5b51 129
c88e827d 130 /** Handlers for the metadata files */
0594c61c
AM
131 private static final FileFilter METADATA_FILE_FILTER = new MetadataFileFilter();
132 private static final Comparator<File> METADATA_COMPARATOR = new MetadataComparator();
866e5b51 133
4c9d2941 134 /** Callsite helpers */
fe75d403 135 private CTFCallsiteComparator fCtfCallsiteComparator = new CTFCallsiteComparator();
890f9136 136
fe75d403 137 private Map<String, TreeSet<CTFCallsite>> fCallsitesByName = new HashMap<>();
0594c61c 138
4c9d2941 139 /** Callsite helpers */
fe75d403 140 private TreeSet<CTFCallsite> fCallsitesByIP = new TreeSet<>();
788ddcbc 141
866e5b51
FC
142 // ------------------------------------------------------------------------
143 // Constructors
144 // ------------------------------------------------------------------------
145
146 /**
147 * Trace constructor.
debcffff 148 *
866e5b51 149 * @param path
be6df2d8
AM
150 * Filesystem path of the trace directory
151 * @throws CTFReaderException
152 * If no CTF trace was found at the path
866e5b51
FC
153 */
154 public CTFTrace(String path) throws CTFReaderException {
155 this(new File(path));
aa572e22 156
866e5b51
FC
157 }
158
159 /**
160 * Trace constructor.
debcffff 161 *
866e5b51
FC
162 * @param path
163 * Filesystem path of the trace directory.
164 * @throws CTFReaderException
be6df2d8 165 * If no CTF trace was found at the path
866e5b51 166 */
866e5b51 167 public CTFTrace(File path) throws CTFReaderException {
fe75d403 168 fPath = path;
0594c61c 169 final Metadata metadata = new Metadata(this);
866e5b51 170
c88e827d 171 /* Set up the internal containers for this trace */
fe75d403 172 if (!fPath.exists()) {
8a95ce5a
BH
173 throw new CTFReaderException("Trace (" + path.getPath() + ") doesn't exist. Deleted or moved?"); //$NON-NLS-1$ //$NON-NLS-2$
174 }
d0d3aa1b 175
fe75d403 176 if (!fPath.isDirectory()) {
d0d3aa1b
AM
177 throw new CTFReaderException("Path must be a valid directory"); //$NON-NLS-1$
178 }
c88e827d
AM
179
180 /* Open and parse the metadata file */
58129ff7 181 metadata.parseFile();
c88e827d 182
58129ff7
MK
183 init(path);
184 }
185
186 /**
187 * Streamed constructor
fe75d403 188 *
58129ff7
MK
189 * @since 3.0
190 */
191 public CTFTrace() {
fe75d403 192 fPath = null;
58129ff7
MK
193 }
194
195 private void init(File path) throws CTFReaderException {
196
58129ff7 197 /* Open all the trace files */
c88e827d
AM
198
199 /* List files not called metadata and not hidden. */
0594c61c
AM
200 File[] files = path.listFiles(METADATA_FILE_FILTER);
201 Arrays.sort(files, METADATA_COMPARATOR);
fe75d403 202
c88e827d 203 /* Try to open each file */
d0d3aa1b
AM
204 for (File streamFile : files) {
205 openStreamInput(streamFile);
c88e827d 206 }
788ddcbc 207
c88e827d 208 /* Create their index */
d84419e1
AM
209 for (CTFStream stream : getStreams()) {
210 Set<CTFStreamInput> inputs = stream.getStreamInputs();
211 for (CTFStreamInput s : inputs) {
fe75d403 212 addStream(s);
c88e827d
AM
213 }
214 }
866e5b51
FC
215 }
216
5d1c6919
PT
217 /**
218 * Dispose the trace
a7297cd3 219 *
05ce5fef
AM
220 * FIXME Not needed anymore, class doesn't need to be AutoCloseable.
221 *
dd9752d5 222 * @since 3.0
5d1c6919 223 */
dd9752d5
AM
224 @Override
225 public void close() {
26ea03d2
AM
226 }
227
866e5b51
FC
228 // ------------------------------------------------------------------------
229 // Getters/Setters/Predicates
230 // ------------------------------------------------------------------------
231
aa572e22 232 /**
be6df2d8
AM
233 * Gets an event declaration hash map for a given streamID
234 *
235 * @param streamId
236 * The ID of the stream from which to read
237 * @return The Hash map with the event declarations
0594c61c 238 * @since 2.0
5f715709 239 * @deprecated use {@link CTFTrace#getEventDeclarations(Long)}
788ddcbc 240 */
5f715709 241 @Deprecated
0594c61c 242 public Map<Long, IEventDeclaration> getEvents(Long streamId) {
fe75d403 243 return fStreams.get(streamId).getEvents();
788ddcbc
MK
244 }
245
5f715709
MK
246 /**
247 * Gets an event declaration list for a given streamID
248 *
249 * @param streamId
250 * The ID of the stream from which to read
251 * @return The list of event declarations
a465519a 252 * @since 3.2
5f715709
MK
253 */
254 public Collection<IEventDeclaration> getEventDeclarations(Long streamId) {
255 return fStreams.get(streamId).getEventDeclarations();
256 }
257
788ddcbc
MK
258 /**
259 * Get an event by it's ID
aa572e22 260 *
be6df2d8
AM
261 * @param streamId
262 * The ID of the stream from which to read
788ddcbc
MK
263 * @param id
264 * the ID of the event
265 * @return the event declaration
8e964be1 266 * @since 2.0
5f715709 267 * @deprecated use {@link CTFTrace#getEventType(long, int)} instead
aa572e22 268 */
5f715709 269 @Deprecated
8e964be1 270 public IEventDeclaration getEventType(long streamId, long id) {
5f715709
MK
271 return getStream(streamId).getEventDeclaration((int) id);
272 }
273
5f715709
MK
274 /**
275 * Get an event by it's ID
276 *
277 * @param streamId
278 * The ID of the stream from which to read
279 * @param id
280 * the ID of the event
281 * @return the event declaration
a465519a 282 * @since 3.2
5f715709
MK
283 */
284 public IEventDeclaration getEventType(long streamId, int id) {
788ddcbc 285 return getEvents(streamId).get(id);
aa572e22
MK
286 }
287
866e5b51
FC
288 /**
289 * Method getStream gets the stream for a given id
debcffff 290 *
866e5b51
FC
291 * @param id
292 * Long the id of the stream
293 * @return Stream the stream that we need
d84419e1 294 * @since 3.0
866e5b51 295 */
d84419e1 296 public CTFStream getStream(Long id) {
fe75d403 297 return fStreams.get(id);
866e5b51
FC
298 }
299
300 /**
301 * Method nbStreams gets the number of available streams
debcffff 302 *
866e5b51
FC
303 * @return int the number of streams
304 */
305 public int nbStreams() {
fe75d403 306 return fStreams.size();
866e5b51
FC
307 }
308
309 /**
310 * Method setMajor sets the major version of the trace (DO NOT USE)
debcffff 311 *
866e5b51
FC
312 * @param major
313 * long the major version
314 */
315 public void setMajor(long major) {
fe75d403 316 fMajor = major;
866e5b51
FC
317 }
318
319 /**
320 * Method setMinor sets the minor version of the trace (DO NOT USE)
debcffff 321 *
866e5b51
FC
322 * @param minor
323 * long the minor version
324 */
325 public void setMinor(long minor) {
fe75d403 326 fMinor = minor;
866e5b51
FC
327 }
328
329 /**
330 * Method setUUID sets the UUID of a trace
debcffff 331 *
866e5b51
FC
332 * @param uuid
333 * UUID
334 */
335 public void setUUID(UUID uuid) {
fe75d403 336 fUuid = uuid;
866e5b51
FC
337 }
338
339 /**
340 * Method setByteOrder sets the byte order
debcffff 341 *
866e5b51
FC
342 * @param byteOrder
343 * ByteOrder of the trace, can be little-endian or big-endian
344 */
345 public void setByteOrder(ByteOrder byteOrder) {
fe75d403 346 fByteOrder = byteOrder;
866e5b51
FC
347 }
348
349 /**
350 * Method setPacketHeader sets the packet header of a trace (DO NOT USE)
debcffff 351 *
866e5b51
FC
352 * @param packetHeader
353 * StructDeclaration the header in structdeclaration form
354 */
355 public void setPacketHeader(StructDeclaration packetHeader) {
fe75d403 356 fPacketHeaderDecl = packetHeader;
866e5b51
FC
357 }
358
359 /**
07804639 360 * Method majorIsSet is the major version number set?
debcffff 361 *
866e5b51 362 * @return boolean is the major set?
c4767854 363 * @since 3.0
866e5b51 364 */
07804639 365 public boolean majorIsSet() {
fe75d403 366 return fMajor != null;
866e5b51
FC
367 }
368
369 /**
370 * Method minorIsSet. is the minor version number set?
debcffff 371 *
866e5b51
FC
372 * @return boolean is the minor set?
373 */
374 public boolean minorIsSet() {
fe75d403 375 return fMinor != null;
866e5b51
FC
376 }
377
378 /**
379 * Method UUIDIsSet is the UUID set?
debcffff 380 *
866e5b51 381 * @return boolean is the UUID set?
0594c61c 382 * @since 2.0
866e5b51 383 */
0594c61c 384 public boolean uuidIsSet() {
fe75d403 385 return fUuid != null;
866e5b51
FC
386 }
387
388 /**
389 * Method byteOrderIsSet is the byteorder set?
debcffff 390 *
866e5b51
FC
391 * @return boolean is the byteorder set?
392 */
393 public boolean byteOrderIsSet() {
fe75d403 394 return fByteOrder != null;
866e5b51
FC
395 }
396
397 /**
398 * Method packetHeaderIsSet is the packet header set?
debcffff 399 *
866e5b51
FC
400 * @return boolean is the packet header set?
401 */
402 public boolean packetHeaderIsSet() {
fe75d403 403 return fPacketHeaderDecl != null;
866e5b51
FC
404 }
405
406 /**
407 * Method getUUID gets the trace UUID
debcffff 408 *
866e5b51
FC
409 * @return UUID gets the trace UUID
410 */
411 public UUID getUUID() {
fe75d403 412 return fUuid;
866e5b51
FC
413 }
414
415 /**
416 * Method getMajor gets the trace major version
debcffff 417 *
866e5b51
FC
418 * @return long gets the trace major version
419 */
420 public long getMajor() {
fe75d403 421 return fMajor;
866e5b51
FC
422 }
423
424 /**
425 * Method getMinor gets the trace minor version
debcffff 426 *
866e5b51
FC
427 * @return long gets the trace minor version
428 */
429 public long getMinor() {
fe75d403 430 return fMinor;
866e5b51
FC
431 }
432
433 /**
434 * Method getByteOrder gets the trace byte order
debcffff 435 *
866e5b51
FC
436 * @return ByteOrder gets the trace byte order
437 */
0594c61c 438 public final ByteOrder getByteOrder() {
fe75d403 439 return fByteOrder;
866e5b51
FC
440 }
441
442 /**
443 * Method getPacketHeader gets the trace packet header
debcffff 444 *
866e5b51
FC
445 * @return StructDeclaration gets the trace packet header
446 */
447 public StructDeclaration getPacketHeader() {
fe75d403 448 return fPacketHeaderDecl;
866e5b51
FC
449 }
450
451 /**
452 * Method getTraceDirectory gets the trace directory
debcffff 453 *
866e5b51
FC
454 * @return File the path in "File" format.
455 */
456 public File getTraceDirectory() {
fe75d403 457 return fPath;
866e5b51
FC
458 }
459
460 /**
f7c5789a 461 * Get all the streams as an iterable.
debcffff 462 *
ab04fc6b 463 * @return Iterable&lt;Stream&gt; an iterable over streams.
951bb9d9 464 * @since 3.0
866e5b51 465 */
d84419e1 466 public Iterable<CTFStream> getStreams() {
fe75d403 467 return fStreams.values();
866e5b51
FC
468 }
469
470 /**
471 * Method getPath gets the path of the trace directory
debcffff 472 *
866e5b51
FC
473 * @return String the path of the trace directory, in string format.
474 * @see java.io.File#getPath()
475 */
866e5b51 476 public String getPath() {
fe75d403 477 return (fPath != null) ? fPath.getPath() : ""; //$NON-NLS-1$
866e5b51
FC
478 }
479
480 // ------------------------------------------------------------------------
481 // Operations
482 // ------------------------------------------------------------------------
483
d84419e1 484 private void addStream(CTFStreamInput s) {
fe75d403
MK
485
486 /*
5f715709 487 * add the stream
fe75d403 488 */
5f715709
MK
489 CTFStream stream = s.getStream();
490 fStreams.put(stream.getId(), stream);
fe75d403
MK
491
492 /*
493 * index the trace
494 */
495 s.setupIndex();
496 }
497
866e5b51
FC
498 /**
499 * Tries to open the given file, reads the first packet header of the file
fe75d403 500 * and check its validity. This will add a file to a stream as a streaminput
debcffff 501 *
866e5b51
FC
502 * @param streamFile
503 * A trace file in the trace directory.
26ea03d2
AM
504 * @param index
505 * Which index in the class' streamFileChannel array this file
506 * must use
866e5b51 507 * @throws CTFReaderException
fe75d403 508 * if there is a file error
866e5b51 509 */
d84419e1 510 private CTFStream openStreamInput(File streamFile) throws CTFReaderException {
f4a474e3 511 ByteBuffer byteBuffer;
866e5b51 512 BitBuffer streamBitBuffer;
d84419e1 513 CTFStream stream;
866e5b51
FC
514
515 if (!streamFile.canRead()) {
516 throw new CTFReaderException("Unreadable file : " //$NON-NLS-1$
517 + streamFile.getPath());
518 }
519
219d054e 520 try (FileChannel fc = FileChannel.open(streamFile.toPath(), StandardOpenOption.READ)) {
866e5b51 521 /* Map one memory page of 4 kiB */
f4a474e3 522 byteBuffer = SafeMappedByteBuffer.map(fc, MapMode.READ_ONLY, 0, (int) Math.min(fc.size(), 4096L));
b3151232 523 if (byteBuffer == null) {
aefc5c83
MK
524 throw new IllegalStateException("Failed to allocate memory"); //$NON-NLS-1$
525 }
219d054e
MK
526 /* Create a BitBuffer with this mapping and the trace byte order */
527 streamBitBuffer = new BitBuffer(byteBuffer, this.getByteOrder());
528
529 if (fPacketHeaderDecl != null) {
530 /* Read the packet header */
531 fPacketHeaderDef = fPacketHeaderDecl.createDefinition(this, LexicalScope.PACKET_HEADER, streamBitBuffer);
532 }
866e5b51
FC
533 } catch (IOException e) {
534 /* Shouldn't happen at this stage if every other check passed */
0594c61c 535 throw new CTFReaderException(e);
866e5b51 536 }
219d054e
MK
537 if (fPacketHeaderDef != null) {
538 validateMagicNumber(fPacketHeaderDef);
866e5b51 539
219d054e 540 validateUUID(fPacketHeaderDef);
866e5b51 541
1fbaecd1 542 /* Read the stream ID */
cc98c947 543 IDefinition streamIDDef = fPacketHeaderDef.lookupDefinition("stream_id"); //$NON-NLS-1$
1fbaecd1 544
219d054e
MK
545 if (streamIDDef instanceof IntegerDefinition) {
546 /* This doubles as a null check */
1fbaecd1 547 long streamID = ((IntegerDefinition) streamIDDef).getValue();
fe75d403 548 stream = fStreams.get(streamID);
1fbaecd1
AM
549 } else {
550 /* No stream_id in the packet header */
fe75d403 551 stream = fStreams.get(null);
1fbaecd1
AM
552 }
553
866e5b51
FC
554 } else {
555 /* No packet header, we suppose there is only one stream */
fe75d403 556 stream = fStreams.get(null);
d0d3aa1b 557 }
866e5b51 558
4311ac8b
MAL
559 if (stream == null) {
560 throw new CTFReaderException("Unexpected end of stream"); //$NON-NLS-1$
561 }
562
8e15b929
MK
563 /*
564 * Create the stream input and add a reference to the streamInput in the
219d054e 565 * stream.
8e15b929 566 */
d84419e1 567 stream.addInput(new CTFStreamInput(stream, streamFile));
fe75d403 568 return stream;
866e5b51
FC
569 }
570
219d054e
MK
571 private void validateUUID(StructDefinition packetHeaderDef) throws CTFReaderException {
572 IDefinition lookupDefinition = packetHeaderDef.lookupDefinition("uuid"); //$NON-NLS-1$
573 ArrayDefinition uuidDef = (ArrayDefinition) lookupDefinition;
574 if (uuidDef != null) {
575 UUID otheruuid = Utils.getUUIDfromDefinition(uuidDef);
576 if (!fUuid.equals(otheruuid)) {
577 throw new CTFReaderException("UUID mismatch"); //$NON-NLS-1$
578 }
579 }
580 }
581
582 private static void validateMagicNumber(StructDefinition packetHeaderDef) throws CTFReaderException {
583 IntegerDefinition magicDef = (IntegerDefinition) packetHeaderDef.lookupDefinition("magic"); //$NON-NLS-1$
584 int magic = (int) magicDef.getValue();
585 if (magic != Utils.CTF_MAGIC) {
586 throw new CTFReaderException("CTF magic mismatch"); //$NON-NLS-1$
587 }
588 }
589
708cb26c
MK
590 // ------------------------------------------------------------------------
591 // IDefinitionScope
592 // ------------------------------------------------------------------------
593
594 /**
595 * @since 3.0
596 */
597 @Override
598 public LexicalScope getScopePath() {
599 return LexicalScope.TRACE;
600 }
601
866e5b51
FC
602 /**
603 * Looks up a definition from packet
debcffff 604 *
866e5b51
FC
605 * @param lookupPath
606 * String
607 * @return Definition
a4fa4e36 608 * @see org.eclipse.linuxtools.ctf.core.event.scope.IDefinitionScope#lookupDefinition(String)
866e5b51
FC
609 */
610 @Override
611 public Definition lookupDefinition(String lookupPath) {
708cb26c 612 if (lookupPath.equals(LexicalScope.TRACE_PACKET_HEADER.toString())) {
fe75d403 613 return fPacketHeaderDef;
866e5b51
FC
614 }
615 return null;
616 }
617
708cb26c
MK
618 // ------------------------------------------------------------------------
619 // Live trace reading
620 // ------------------------------------------------------------------------
621
866e5b51 622 /**
fe75d403
MK
623 * Add a new stream file to support new streams while the trace is being
624 * read.
625 *
626 * @param streamFile
627 * the file of the stream
628 * @throws CTFReaderException
629 * A stream had an issue being read
fe75d403
MK
630 * @since 3.0
631 */
632 public void addStreamFile(File streamFile) throws CTFReaderException {
633 openStreamInput(streamFile);
634 }
635
636 /**
637 * Registers a new stream to the trace.
debcffff 638 *
866e5b51
FC
639 * @param stream
640 * A stream object.
866e5b51 641 * @throws ParseException
be6df2d8 642 * If there was some problem reading the metadata
d84419e1 643 * @since 3.0
866e5b51 644 */
d84419e1 645 public void addStream(CTFStream stream) throws ParseException {
866e5b51
FC
646 /*
647 * If there is already a stream without id (the null key), it must be
648 * the only one
649 */
fe75d403 650 if (fStreams.get(null) != null) {
866e5b51
FC
651 throw new ParseException("Stream without id with multiple streams"); //$NON-NLS-1$
652 }
653
654 /*
1d7277f3
MK
655 * If the stream we try to add has the null key, it must be the only
656 * one. Thus, if the streams container is not empty, it is not valid.
866e5b51 657 */
fe75d403 658 if ((stream.getId() == null) && (fStreams.size() != 0)) {
866e5b51
FC
659 throw new ParseException("Stream without id with multiple streams"); //$NON-NLS-1$
660 }
661
fe75d403
MK
662 /*
663 * If a stream with the same ID already exists, it is not valid.
664 */
d84419e1 665 CTFStream existingStream = fStreams.get(stream.getId());
fe75d403 666 if (existingStream != null) {
866e5b51
FC
667 throw new ParseException("Stream id already exists"); //$NON-NLS-1$
668 }
669
29a7d6ee 670 /* This stream is valid and has a unique id. */
fe75d403 671 fStreams.put(stream.getId(), stream);
866e5b51
FC
672 }
673
9ac2eb62 674 /**
29a7d6ee 675 * Gets the Environment variables from the trace metadata (See CTF spec)
a7297cd3 676 *
a95fddf5
EB
677 * @return The environment variables in the form of an unmodifiable map
678 * (key, value)
486efb2e 679 * @since 2.0
9ac2eb62 680 */
791072b0 681 public Map<String, String> getEnvironment() {
fe75d403 682 return Collections.unmodifiableMap(fEnvironment);
866e5b51
FC
683 }
684
9ac2eb62
MK
685 /**
686 * Add a variable to the environment variables
a7297cd3
SD
687 *
688 * @param varName
689 * the name of the variable
690 * @param varValue
691 * the value of the variable
9ac2eb62 692 */
c88e827d 693 public void addEnvironmentVar(String varName, String varValue) {
fe75d403 694 fEnvironment.put(varName, varValue);
866e5b51
FC
695 }
696
9ac2eb62
MK
697 /**
698 * Add a clock to the clock list
a7297cd3
SD
699 *
700 * @param nameValue
701 * the name of the clock (full name with scope)
702 * @param ctfClock
703 * the clock
9ac2eb62 704 */
866e5b51 705 public void addClock(String nameValue, CTFClock ctfClock) {
fe75d403 706 fClocks.put(nameValue, ctfClock);
866e5b51
FC
707 }
708
9ac2eb62
MK
709 /**
710 * gets the clock with a specific name
a7297cd3
SD
711 *
712 * @param name
713 * the name of the clock.
9ac2eb62
MK
714 * @return the clock
715 */
c88e827d 716 public CTFClock getClock(String name) {
fe75d403 717 return fClocks.get(name);
866e5b51
FC
718 }
719
9ac2eb62 720 /**
1d7277f3
MK
721 * gets the clock if there is only one. (this is 100% of the use cases as of
722 * June 2012)
723 *
9ac2eb62
MK
724 * @return the clock
725 */
8ecc80f3 726 public final CTFClock getClock() {
ede59fc8
GB
727 if (fSingleClock != null && fClocks.size() == 1) {
728 return fSingleClock;
729 }
fe75d403
MK
730 if (fClocks.size() == 1) {
731 fSingleClock = fClocks.get(fClocks.keySet().iterator().next());
732 return fSingleClock;
866e5b51
FC
733 }
734 return null;
735 }
736
9ac2eb62
MK
737 /**
738 * gets the time offset of a clock with respect to UTC in nanoseconds
1d7277f3 739 *
9ac2eb62
MK
740 * @return the time offset of a clock with respect to UTC in nanoseconds
741 */
8ecc80f3 742 public final long getOffset() {
c88e827d 743 if (getClock() == null) {
ce2388e0
FC
744 return 0;
745 }
fe75d403 746 return fSingleClock.getClockOffset();
1d7277f3
MK
747 }
748
749 /**
750 * gets the time offset of a clock with respect to UTC in nanoseconds
751 *
752 * @return the time offset of a clock with respect to UTC in nanoseconds
753 */
0594c61c 754 private double getTimeScale() {
1d7277f3
MK
755 if (getClock() == null) {
756 return 1.0;
757 }
fe75d403 758 return fSingleClock.getClockScale();
1d7277f3
MK
759 }
760
962fb72f
PT
761 /**
762 * Gets the current first packet start time
b3151232 763 *
962fb72f
PT
764 * @return the current start time
765 * @since 3.0
766 */
767 public long getCurrentStartTime() {
768 long currentStart = Long.MAX_VALUE;
769 for (CTFStream stream : fStreams.values()) {
770 for (CTFStreamInput si : stream.getStreamInputs()) {
771 currentStart = Math.min(currentStart, si.getIndex().getEntries().get(0).getTimestampBegin());
772 }
773 }
774 return timestampCyclesToNanos(currentStart);
775 }
776
777 /**
778 * Gets the current last packet end time
b3151232 779 *
962fb72f
PT
780 * @return the current end time
781 * @since 3.0
782 */
783 public long getCurrentEndTime() {
784 long currentEnd = Long.MIN_VALUE;
785 for (CTFStream stream : fStreams.values()) {
786 for (CTFStreamInput si : stream.getStreamInputs()) {
787 currentEnd = Math.max(currentEnd, si.getTimestampEnd());
788 }
789 }
790 return timestampCyclesToNanos(currentEnd);
791 }
792
1d7277f3
MK
793 /**
794 * Does the trace need to time scale?
795 *
796 * @return if the trace is in ns or cycles.
797 */
0594c61c 798 private boolean clockNeedsScale() {
1d7277f3
MK
799 if (getClock() == null) {
800 return false;
801 }
fe75d403 802 return fSingleClock.isClockScaled();
1d7277f3
MK
803 }
804
805 /**
806 * the inverse clock for returning to a scale.
807 *
808 * @return 1.0 / scale
809 */
0594c61c 810 private double getInverseTimeScale() {
1d7277f3
MK
811 if (getClock() == null) {
812 return 1.0;
813 }
fe75d403 814 return fSingleClock.getClockAntiScale();
1d7277f3
MK
815 }
816
817 /**
818 * @param cycles
819 * clock cycles since boot
820 * @return time in nanoseconds UTC offset
486efb2e 821 * @since 2.0
1d7277f3
MK
822 */
823 public long timestampCyclesToNanos(long cycles) {
824 long retVal = cycles + getOffset();
825 /*
826 * this fix is since quite often the offset will be > than 53 bits and
827 * therefore the conversion will be lossy
828 */
829 if (clockNeedsScale()) {
830 retVal = (long) (retVal * getTimeScale());
831 }
832 return retVal;
833 }
834
835 /**
836 * @param nanos
837 * time in nanoseconds UTC offset
838 * @return clock cycles since boot.
486efb2e 839 * @since 2.0
1d7277f3
MK
840 */
841 public long timestampNanoToCycles(long nanos) {
842 long retVal;
843 /*
844 * this fix is since quite often the offset will be > than 53 bits and
845 * therefore the conversion will be lossy
846 */
847 if (clockNeedsScale()) {
848 retVal = (long) (nanos * getInverseTimeScale());
849 } else {
850 retVal = nanos;
851 }
852 return retVal - getOffset();
ce2388e0
FC
853 }
854
4c9d2941
MK
855 /**
856 * Adds a callsite
857 *
858 * @param eventName
859 * the event name of the callsite
860 * @param funcName
861 * the name of the callsite function
862 * @param ip
863 * the ip of the callsite
864 * @param fileName
865 * the filename of the callsite
866 * @param lineNumber
867 * the line number of the callsite
868 */
869 public void addCallsite(String eventName, String funcName, long ip,
870 String fileName, long lineNumber) {
871 final CTFCallsite cs = new CTFCallsite(eventName, funcName, ip,
872 fileName, lineNumber);
fe75d403 873 TreeSet<CTFCallsite> csl = fCallsitesByName.get(eventName);
4c9d2941 874 if (csl == null) {
fe75d403
MK
875 csl = new TreeSet<>(fCtfCallsiteComparator);
876 fCallsitesByName.put(eventName, csl);
4c9d2941
MK
877 }
878
890f9136 879 csl.add(cs);
4c9d2941 880
fe75d403 881 fCallsitesByIP.add(cs);
4c9d2941
MK
882 }
883
884 /**
890f9136 885 * Gets the set of callsites associated to an event name. O(1)
4c9d2941
MK
886 *
887 * @param eventName
888 * the event name
890f9136
SD
889 * @return the callsite set can be empty
890 * @since 3.0
4c9d2941 891 */
890f9136 892 public TreeSet<CTFCallsite> getCallsiteCandidates(String eventName) {
fe75d403 893 TreeSet<CTFCallsite> retVal = fCallsitesByName.get(eventName);
890f9136 894 if (retVal == null) {
fe75d403 895 retVal = new TreeSet<>(fCtfCallsiteComparator);
4c9d2941
MK
896 }
897 return retVal;
898 }
899
900 /**
901 * The I'm feeling lucky of getCallsiteCandidates O(1)
902 *
903 * @param eventName
904 * the event name
905 * @return the first callsite that has that event name, can be null
906 * @since 1.2
907 */
908 public CTFCallsite getCallsite(String eventName) {
fe75d403 909 TreeSet<CTFCallsite> callsites = fCallsitesByName.get(eventName);
60fb38b8 910 if (callsites != null) {
890f9136 911 return callsites.first();
60fb38b8
PT
912 }
913 return null;
4c9d2941
MK
914 }
915
916 /**
917 * Gets a callsite from the instruction pointer O(log(n))
918 *
919 * @param ip
920 * the instruction pointer to lookup
921 * @return the callsite just before that IP in the list remember the IP is
922 * backwards on X86, can be null if no callsite is before the IP.
923 * @since 1.2
924 */
925 public CTFCallsite getCallsite(long ip) {
926 CTFCallsite cs = new CTFCallsite(null, null, ip, null, 0L);
fe75d403 927 return fCallsitesByIP.ceiling(cs);
4c9d2941
MK
928 }
929
930 /**
931 * Gets a callsite using the event name and instruction pointer O(log(n))
932 *
933 * @param eventName
934 * the name of the event
935 * @param ip
936 * the instruction pointer
937 * @return the closest matching callsite, can be null
938 */
939 public CTFCallsite getCallsite(String eventName, long ip) {
fe75d403 940 final TreeSet<CTFCallsite> candidates = fCallsitesByName.get(eventName);
c5471ddf
BH
941 if (candidates == null) {
942 return null;
943 }
4c9d2941 944 final CTFCallsite dummyCs = new CTFCallsite(null, null, ip, null, -1);
890f9136
SD
945 final CTFCallsite callsite = candidates.ceiling(dummyCs);
946 if (callsite == null) {
947 return candidates.floor(dummyCs);
4c9d2941 948 }
890f9136 949 return callsite;
4c9d2941 950 }
8e15b929
MK
951
952 /**
953 * Add a new stream
954 *
955 * @param id
956 * the ID of the stream
957 * @param streamFile
958 * new file in the stream
959 * @throws CTFReaderException
960 * The file must exist
961 * @since 3.0
962 */
b3151232
MK
963 // TODO: remove suppress warning
964 @SuppressWarnings("resource")
8e15b929 965 public void addStream(long id, File streamFile) throws CTFReaderException {
d84419e1 966 CTFStream stream = null;
b3151232
MK
967 final File file = streamFile;
968 if (file == null) {
969 throw new CTFReaderException("cannot create a stream with no file"); //$NON-NLS-1$
970 }
8e15b929
MK
971 if (fStreams.containsKey(id)) {
972 stream = fStreams.get(id);
973 } else {
d84419e1 974 stream = new CTFStream(this);
8e15b929
MK
975 fStreams.put(id, stream);
976 }
b3151232 977 stream.addInput(new CTFStreamInput(stream, file));
8e15b929 978 }
866e5b51 979}
c88e827d
AM
980
981class MetadataFileFilter implements FileFilter {
982
983 @Override
984 public boolean accept(File pathname) {
985 if (pathname.isDirectory()) {
986 return false;
987 }
988 if (pathname.isHidden()) {
989 return false;
990 }
991 if (pathname.getName().equals("metadata")) { //$NON-NLS-1$
992 return false;
993 }
994 return true;
995 }
996
997}
998
debcffff 999class MetadataComparator implements Comparator<File>, Serializable {
c88e827d 1000
8fd82db5
FC
1001 private static final long serialVersionUID = 1L;
1002
c88e827d
AM
1003 @Override
1004 public int compare(File o1, File o2) {
1005 return o1.getName().compareTo(o2.getName());
1006 }
1007}
This page took 0.100089 seconds and 5 git commands to generate.