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