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