ctf: update api to 2.0 baseline
[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 if (streamFile.length() == 0) {
469 return null;
470 }
471 try (FileChannel fc = FileChannel.open(streamFile.toPath(), StandardOpenOption.READ)) {
472 /* Map one memory page of 4 kiB */
473 byteBuffer = SafeMappedByteBuffer.map(fc, MapMode.READ_ONLY, 0, (int) Math.min(fc.size(), 4096L));
474 if (byteBuffer == null) {
475 throw new IllegalStateException("Failed to allocate memory"); //$NON-NLS-1$
476 }
477 /* Create a BitBuffer with this mapping and the trace byte order */
478 streamBitBuffer = new BitBuffer(byteBuffer, this.getByteOrder());
479 if (fPacketHeaderDecl != null) {
480 /* Read the packet header */
481 fPacketHeaderDef = fPacketHeaderDecl.createDefinition(this, ILexicalScope.PACKET_HEADER, streamBitBuffer);
482 }
483 } catch (IOException e) {
484 /* Shouldn't happen at this stage if every other check passed */
485 throw new CTFException(e);
486 }
487 if (fPacketHeaderDef != null) {
488 validateMagicNumber(fPacketHeaderDef);
489
490 validateUUID(fPacketHeaderDef);
491
492 /* Read the stream ID */
493 IDefinition streamIDDef = fPacketHeaderDef.lookupDefinition("stream_id"); //$NON-NLS-1$
494
495 if (streamIDDef instanceof IntegerDefinition) {
496 /* This doubles as a null check */
497 long streamID = ((IntegerDefinition) streamIDDef).getValue();
498 stream = fStreams.get(streamID);
499 } else {
500 /* No stream_id in the packet header */
501 stream = getStream(null);
502 }
503
504 } else {
505 /* No packet header, we suppose there is only one stream */
506 stream = getStream(null);
507 }
508
509 if (stream == null) {
510 throw new CTFException("Unexpected end of stream"); //$NON-NLS-1$
511 }
512
513 /*
514 * Create the stream input and add a reference to the streamInput in the
515 * stream.
516 */
517 stream.addInput(new CTFStreamInput(stream, streamFile));
518
519 return stream;
520 }
521
522 private void validateUUID(StructDefinition packetHeaderDef) throws CTFException {
523 IDefinition lookupDefinition = packetHeaderDef.lookupDefinition("uuid"); //$NON-NLS-1$
524 AbstractArrayDefinition uuidDef = (AbstractArrayDefinition) lookupDefinition;
525 if (uuidDef != null) {
526 UUID otheruuid = Utils.getUUIDfromDefinition(uuidDef);
527 if (!fUuid.equals(otheruuid)) {
528 throw new CTFException("UUID mismatch"); //$NON-NLS-1$
529 }
530 }
531 }
532
533 private static void validateMagicNumber(StructDefinition packetHeaderDef) throws CTFException {
534 IntegerDefinition magicDef = (IntegerDefinition) packetHeaderDef.lookupDefinition(CTFStrings.MAGIC);
535 if (magicDef != null) {
536 int magic = (int) magicDef.getValue();
537 if (magic != Utils.CTF_MAGIC) {
538 throw new CTFException("CTF magic mismatch"); //$NON-NLS-1$
539 }
540 }
541 }
542
543 // ------------------------------------------------------------------------
544 // IDefinitionScope
545 // ------------------------------------------------------------------------
546
547 /**
548 * @since 1.0
549 */
550 @Override
551 public ILexicalScope getScopePath() {
552 return ILexicalScope.TRACE;
553 }
554
555 /**
556 * Looks up a definition from packet
557 *
558 * @param lookupPath
559 * String
560 * @return Definition
561 * @see org.eclipse.tracecompass.ctf.core.event.scope.IDefinitionScope#lookupDefinition(String)
562 */
563 @Override
564 public Definition lookupDefinition(String lookupPath) {
565 if (lookupPath.equals(ILexicalScope.TRACE_PACKET_HEADER.getPath())) {
566 return fPacketHeaderDef;
567 }
568 return null;
569 }
570
571 // ------------------------------------------------------------------------
572 // Live trace reading
573 // ------------------------------------------------------------------------
574
575 /**
576 * Add a new stream file to support new streams while the trace is being
577 * read.
578 *
579 * @param streamFile
580 * the file of the stream
581 * @throws CTFException
582 * A stream had an issue being read
583 */
584 public void addStreamFile(File streamFile) throws CTFException {
585 openStreamInput(streamFile);
586 }
587
588 /**
589 * Registers a new stream to the trace.
590 *
591 * @param stream
592 * A stream object.
593 * @throws ParseException
594 * If there was some problem reading the metadata
595 */
596 public void addStream(CTFStream stream) throws ParseException {
597 /*
598 * If there is already a stream without id (the null key), it must be
599 * the only one
600 */
601 if (fStreams.get(null) != null) {
602 throw new ParseException("Stream without id with multiple streams"); //$NON-NLS-1$
603 }
604
605 /*
606 * If the stream we try to add has no key set, it must be the only one.
607 * Thus, if the streams container is not empty, it is not valid.
608 */
609 if ((!stream.isIdSet()) && (!fStreams.isEmpty())) {
610 throw new ParseException("Stream without id with multiple streams"); //$NON-NLS-1$
611 }
612
613 /*
614 * If a stream with the same ID already exists, it is not valid.
615 */
616 CTFStream existingStream = fStreams.get(stream.getId());
617 if (existingStream != null) {
618 throw new ParseException("Stream id already exists"); //$NON-NLS-1$
619 }
620
621 /* This stream is valid and has a unique id. */
622 fStreams.put(stream.getId(), stream);
623 }
624
625 /**
626 * Gets the Environment variables from the trace metadata (See CTF spec)
627 *
628 * @return The environment variables in the form of an unmodifiable map
629 * (key, value)
630 */
631 public Map<String, String> getEnvironment() {
632 return Collections.unmodifiableMap(fEnvironment);
633 }
634
635 /**
636 * Add a variable to the environment variables
637 *
638 * @param varName
639 * the name of the variable
640 * @param varValue
641 * the value of the variable
642 */
643 public void addEnvironmentVar(String varName, String varValue) {
644 fEnvironment.put(varName, varValue);
645 }
646
647 /**
648 * Add a clock to the clock list
649 *
650 * @param nameValue
651 * the name of the clock (full name with scope)
652 * @param ctfClock
653 * the clock
654 */
655 public void addClock(String nameValue, CTFClock ctfClock) {
656 fClocks.put(nameValue, ctfClock);
657 }
658
659 /**
660 * gets the clock with a specific name
661 *
662 * @param name
663 * the name of the clock.
664 * @return the clock
665 */
666 public CTFClock getClock(String name) {
667 return fClocks.get(name);
668 }
669
670 /**
671 * gets the clock if there is only one. (this is 100% of the use cases as of
672 * June 2012)
673 *
674 * @return the clock
675 */
676 public final CTFClock getClock() {
677 if (fSingleClock != null && fClocks.size() == 1) {
678 return fSingleClock;
679 }
680 if (fClocks.size() == 1) {
681 fSingleClock = fClocks.get(fClocks.keySet().iterator().next());
682 return fSingleClock;
683 }
684 return null;
685 }
686
687 /**
688 * gets the time offset of a clock with respect to UTC in nanoseconds
689 *
690 * @return the time offset of a clock with respect to UTC in nanoseconds
691 */
692 public final long getOffset() {
693 if (getClock() == null) {
694 return 0;
695 }
696 return fSingleClock.getClockOffset();
697 }
698
699 /**
700 * gets the time offset of a clock with respect to UTC in nanoseconds
701 *
702 * @return the time offset of a clock with respect to UTC in nanoseconds
703 */
704 private double getTimeScale() {
705 if (getClock() == null) {
706 return 1.0;
707 }
708 return fSingleClock.getClockScale();
709 }
710
711 /**
712 * Gets the current first packet start time
713 *
714 * @return the current start time
715 */
716 public long getCurrentStartTime() {
717 long currentStart = Long.MAX_VALUE;
718 for (CTFStream stream : fStreams.values()) {
719 for (CTFStreamInput si : stream.getStreamInputs()) {
720 currentStart = Math.min(currentStart, si.getIndex().getElement(0).getTimestampBegin());
721 }
722 }
723 return timestampCyclesToNanos(currentStart);
724 }
725
726 /**
727 * Gets the current last packet end time
728 *
729 * @return the current end time
730 */
731 public long getCurrentEndTime() {
732 long currentEnd = Long.MIN_VALUE;
733 for (CTFStream stream : fStreams.values()) {
734 for (CTFStreamInput si : stream.getStreamInputs()) {
735 currentEnd = Math.max(currentEnd, si.getTimestampEnd());
736 }
737 }
738 return timestampCyclesToNanos(currentEnd);
739 }
740
741 /**
742 * Does the trace need to time scale?
743 *
744 * @return if the trace is in ns or cycles.
745 */
746 private boolean clockNeedsScale() {
747 if (getClock() == null) {
748 return false;
749 }
750 return fSingleClock.isClockScaled();
751 }
752
753 /**
754 * the inverse clock for returning to a scale.
755 *
756 * @return 1.0 / scale
757 */
758 private double getInverseTimeScale() {
759 if (getClock() == null) {
760 return 1.0;
761 }
762 return fSingleClock.getClockAntiScale();
763 }
764
765 /**
766 * @param cycles
767 * clock cycles since boot
768 * @return time in nanoseconds UTC offset
769 */
770 public long timestampCyclesToNanos(long cycles) {
771 long retVal = cycles + getOffset();
772 /*
773 * this fix is since quite often the offset will be > than 53 bits and
774 * therefore the conversion will be lossy
775 */
776 if (clockNeedsScale()) {
777 retVal = (long) (retVal * getTimeScale());
778 }
779 return retVal;
780 }
781
782 /**
783 * @param nanos
784 * time in nanoseconds UTC offset
785 * @return clock cycles since boot.
786 */
787 public long timestampNanoToCycles(long nanos) {
788 long retVal;
789 /*
790 * this fix is since quite often the offset will be > than 53 bits and
791 * therefore the conversion will be lossy
792 */
793 if (clockNeedsScale()) {
794 retVal = (long) (nanos * getInverseTimeScale());
795 } else {
796 retVal = nanos;
797 }
798 return retVal - getOffset();
799 }
800
801 /**
802 * Adds a callsite
803 *
804 * @param eventName
805 * the event name of the callsite
806 * @param funcName
807 * the name of the callsite function
808 * @param ip
809 * the ip of the callsite
810 * @param fileName
811 * the filename of the callsite
812 * @param lineNumber
813 * the line number of the callsite
814 */
815 public void addCallsite(String eventName, String funcName, long ip,
816 String fileName, long lineNumber) {
817 final CTFCallsite cs = new CTFCallsite(eventName, funcName, ip,
818 fileName, lineNumber);
819 TreeSet<CTFCallsite> csl = fCallsitesByName.get(eventName);
820 if (csl == null) {
821 csl = new TreeSet<>(fCtfCallsiteComparator);
822 fCallsitesByName.put(eventName, csl);
823 }
824
825 csl.add(cs);
826
827 fCallsitesByIP.add(cs);
828 }
829
830 /**
831 * Gets the set of callsites associated to an event name. O(1)
832 *
833 * @param eventName
834 * the event name
835 * @return the callsite set can be empty
836 */
837 public TreeSet<CTFCallsite> getCallsiteCandidates(String eventName) {
838 TreeSet<CTFCallsite> retVal = fCallsitesByName.get(eventName);
839 if (retVal == null) {
840 retVal = new TreeSet<>(fCtfCallsiteComparator);
841 }
842 return retVal;
843 }
844
845 /**
846 * The I'm feeling lucky of getCallsiteCandidates O(1)
847 *
848 * @param eventName
849 * the event name
850 * @return the first callsite that has that event name, can be null
851 */
852 public CTFCallsite getCallsite(String eventName) {
853 TreeSet<CTFCallsite> callsites = fCallsitesByName.get(eventName);
854 if (callsites != null) {
855 return callsites.first();
856 }
857 return null;
858 }
859
860 /**
861 * Gets a callsite from the instruction pointer O(log(n))
862 *
863 * @param ip
864 * the instruction pointer to lookup
865 * @return the callsite just before that IP in the list remember the IP is
866 * backwards on X86, can be null if no callsite is before the IP.
867 */
868 public CTFCallsite getCallsite(long ip) {
869 CTFCallsite cs = new CTFCallsite(null, null, ip, null, 0L);
870 return fCallsitesByIP.ceiling(cs);
871 }
872
873 /**
874 * Gets a callsite using the event name and instruction pointer O(log(n))
875 *
876 * @param eventName
877 * the name of the event
878 * @param ip
879 * the instruction pointer
880 * @return the closest matching callsite, can be null
881 */
882 public CTFCallsite getCallsite(String eventName, long ip) {
883 final TreeSet<CTFCallsite> candidates = fCallsitesByName.get(eventName);
884 if (candidates == null) {
885 return null;
886 }
887 final CTFCallsite dummyCs = new CTFCallsite(null, null, ip, null, -1);
888 final CTFCallsite callsite = candidates.ceiling(dummyCs);
889 if (callsite == null) {
890 return candidates.floor(dummyCs);
891 }
892 return callsite;
893 }
894
895 /**
896 * Add a new stream
897 *
898 * @param id
899 * the ID of the stream
900 * @param streamFile
901 * new file in the stream
902 * @throws CTFException
903 * The file must exist
904 */
905 public void addStream(long id, File streamFile) throws CTFException {
906 CTFStream stream = null;
907 final File file = streamFile;
908 if (file == null) {
909 throw new CTFException("cannot create a stream with no file"); //$NON-NLS-1$
910 }
911 if (fStreams.containsKey(id)) {
912 stream = fStreams.get(id);
913 } else {
914 stream = new CTFStream(this);
915 fStreams.put(id, stream);
916 }
917 stream.addInput(new CTFStreamInput(stream, file));
918 }
919
920 /**
921 * Gets the current trace scope
922 *
923 * @return the current declaration scope
924 *
925 * @since 2.0
926 */
927 public DeclarationScope getScope() {
928 return fScope;
929 }
930 }
931
932 class MetadataFileFilter implements FileFilter {
933
934 @Override
935 public boolean accept(File pathname) {
936 if (pathname.isDirectory()) {
937 return false;
938 }
939 if (pathname.isHidden()) {
940 return false;
941 }
942 if (pathname.getName().equals("metadata")) { //$NON-NLS-1$
943 return false;
944 }
945 return true;
946 }
947
948 }
949
950 class MetadataComparator implements Comparator<File>, Serializable {
951
952 private static final long serialVersionUID = 1L;
953
954 @Override
955 public int compare(File o1, File o2) {
956 return o1.getName().compareTo(o2.getName());
957 }
958 }
This page took 0.066709 seconds and 6 git commands to generate.