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