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