More javadoc updates
[deliverable/tracecompass.git] / org.eclipse.linuxtools.ctf.core / src / org / eclipse / linuxtools / ctf / core / trace / CTFTrace.java
1 /*******************************************************************************
2 * Copyright (c) 2011-2012 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: Matthew Khouzam - Initial API and implementation
10 * Contributors: Alexandre Montplaisir - Initial API and implementation
11 *******************************************************************************/
12
13 package org.eclipse.linuxtools.ctf.core.trace;
14
15 import java.io.File;
16 import java.io.FileFilter;
17 import java.io.FileInputStream;
18 import java.io.IOException;
19 import java.io.Serializable;
20 import java.nio.ByteOrder;
21 import java.nio.MappedByteBuffer;
22 import java.nio.channels.FileChannel;
23 import java.nio.channels.FileChannel.MapMode;
24 import java.util.Arrays;
25 import java.util.Comparator;
26 import java.util.HashMap;
27 import java.util.Iterator;
28 import java.util.LinkedList;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.Map.Entry;
32 import java.util.Set;
33 import java.util.UUID;
34
35 import org.eclipse.linuxtools.ctf.core.event.CTFClock;
36 import org.eclipse.linuxtools.ctf.core.event.EventDeclaration;
37 import org.eclipse.linuxtools.ctf.core.event.EventDefinition;
38 import org.eclipse.linuxtools.ctf.core.event.types.ArrayDefinition;
39 import org.eclipse.linuxtools.ctf.core.event.types.Definition;
40 import org.eclipse.linuxtools.ctf.core.event.types.IDefinitionScope;
41 import org.eclipse.linuxtools.ctf.core.event.types.IntegerDefinition;
42 import org.eclipse.linuxtools.ctf.core.event.types.StructDeclaration;
43 import org.eclipse.linuxtools.ctf.core.event.types.StructDefinition;
44 import org.eclipse.linuxtools.internal.ctf.core.Activator;
45 import org.eclipse.linuxtools.internal.ctf.core.event.io.BitBuffer;
46 import org.eclipse.linuxtools.internal.ctf.core.event.metadata.exceptions.ParseException;
47 import org.eclipse.linuxtools.internal.ctf.core.trace.Stream;
48 import org.eclipse.linuxtools.internal.ctf.core.trace.StreamInput;
49 import org.eclipse.linuxtools.internal.ctf.core.trace.StreamInputPacketIndex;
50
51 /**
52 * A CTF trace on the file system.
53 *
54 * Represents a trace on the filesystem. It is responsible of parsing the
55 * metadata, creating declarations data structures, indexing the event packets
56 * (in other words, all the work that can be shared between readers), but the
57 * actual reading of events is left to TraceReader.
58 *
59 * @author Matthew Khouzam
60 * @version $Revision: 1.0 $
61 */
62 public class CTFTrace implements IDefinitionScope {
63
64 // ------------------------------------------------------------------------
65 // Attributes
66 // ------------------------------------------------------------------------
67
68 /*
69 * (non-Javadoc)
70 *
71 * @see java.lang.Object#toString()
72 */
73 @SuppressWarnings("nls")
74 @Override
75 public String toString() {
76 /* Only for debugging, shouldn't be externalized */
77 return "CTFTrace [path=" + path + ", major=" + major + ", minor="
78 + minor + ", uuid=" + uuid + "]";
79 }
80
81 /**
82 * The trace directory on the filesystem.
83 */
84 private final File path;
85
86 /**
87 * The metadata parsing object.
88 */
89 private final Metadata metadata;
90
91 /**
92 * Major CTF version number
93 */
94 private Long major;
95
96 /**
97 * Minor CTF version number
98 */
99 private Long minor;
100
101 /**
102 * Trace UUID
103 */
104 private UUID uuid;
105
106 /**
107 * Trace byte order
108 */
109 private ByteOrder byteOrder;
110
111 /**
112 * Packet header structure declaration
113 */
114 private StructDeclaration packetHeaderDecl = null;
115
116 /**
117 * Packet header structure definition
118 *
119 * This is only used when opening the trace files, to read the first packet
120 * header and see if they are valid trace files.
121 */
122 private StructDefinition packetHeaderDef;
123
124 /**
125 * Collection of streams contained in the trace.
126 */
127 private final HashMap<Long, Stream> streams;
128
129 /**
130 * Collection of environment variables set by the tracer
131 */
132 private final HashMap<String, String> environment;
133
134 /**
135 * Collection of all the clocks in a system.
136 */
137 private final HashMap<String, CTFClock> clocks;
138
139 /** FileChannels to the streams */
140 private final List<FileChannel> streamFileChannels;
141
142 /** Handlers for the metadata files */
143 private final static FileFilter metadataFileFilter = new MetadataFileFilter();
144 private final static Comparator<File> metadataComparator = new MetadataComparator(); // $codepro.audit.disable
145 // fieldJavadoc
146
147 /** map of all the event types */
148 private final HashMap<Long,HashMap<Long, EventDeclaration>> eventDecs;
149 /** map of all the event types */
150 private final HashMap<StreamInput,HashMap<Long, EventDefinition>> eventDefs;
151 /** map of all the indexes */
152 private final HashMap<StreamInput, StreamInputPacketIndex> indexes;
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 this.metadata = new Metadata(this);
184
185 /* Set up the internal containers for this trace */
186 streams = new HashMap<Long, Stream>();
187 environment = new HashMap<String, String>();
188 clocks = new HashMap<String, CTFClock>();
189 streamFileChannels = new LinkedList<FileChannel>();
190 eventDecs = new HashMap<Long, HashMap<Long, EventDeclaration>>();
191 eventDefs = new HashMap<StreamInput, HashMap<Long, EventDefinition>>();
192
193 if (!this.path.isDirectory()) {
194 throw new CTFReaderException("Path must be a valid directory"); //$NON-NLS-1$
195 }
196
197 /* Open and parse the metadata file */
198 metadata.parse();
199
200 if (Activator.getDefault() != null) {
201 Activator.getDefault().log(metadata.toString());
202 }
203
204 /* Open all the trace files */
205 /* Create the definitions needed to read things from the files */
206 if (packetHeaderDecl != null) {
207 packetHeaderDef = packetHeaderDecl.createDefinition(this,
208 "packet.header"); //$NON-NLS-1$
209 }
210
211 /* List files not called metadata and not hidden. */
212 File[] files = path.listFiles(metadataFileFilter);
213 Arrays.sort(files, metadataComparator);
214 indexes = new HashMap<StreamInput, StreamInputPacketIndex>();
215 /* Try to open each file */
216 for (File streamFile : files) {
217 openStreamInput(streamFile);
218 }
219
220 /* Create their index */
221 for (Map.Entry<Long, Stream> stream : streams.entrySet()) {
222 Set<StreamInput> inputs = stream.getValue().getStreamInputs();
223 for (StreamInput s : inputs) {
224 /*
225 * Copy the events
226 */
227 Iterator<Entry<Long, EventDeclaration>> it = s.getStream()
228 .getEvents().entrySet().iterator();
229 while (it.hasNext()) {
230 Map.Entry<Long, EventDeclaration> pairs = it.next();
231 Long eventNum = pairs.getKey();
232 EventDeclaration eventDec = pairs.getValue();
233 getEvents(s.getStream().getId()).put(eventNum, eventDec);
234 }
235
236 /*
237 * index the trace
238 */
239 s.setupIndex();
240 }
241 }
242 }
243
244 @Override
245 protected void finalize() throws Throwable {
246 /* If this trace gets closed, release the descriptors to the streams */
247 for (FileChannel fc : streamFileChannels) {
248 if (fc != null) {
249 try {
250 fc.close();
251 } catch (IOException e) {
252 // do nothing it's ok, we tried to close it.
253 }
254 }
255 }
256 super.finalize();
257
258 }
259
260 // ------------------------------------------------------------------------
261 // Getters/Setters/Predicates
262 // ------------------------------------------------------------------------
263
264 /**
265 * Gets an event declaration hash map for a given streamID
266 *
267 * @param streamId
268 * The ID of the stream from which to read
269 * @return The Hash map with the event declarations
270 */
271 public HashMap<Long, EventDeclaration> getEvents(Long streamId) {
272 return eventDecs.get(streamId);
273 }
274
275 /**
276 * Gets an index for a given StreamInput
277 * @param id the StreamInput
278 * @return The index
279 */
280 public StreamInputPacketIndex getIndex(StreamInput id){
281 if(! indexes.containsKey(id)){
282 indexes.put(id, new StreamInputPacketIndex());
283 }
284 return indexes.get(id);
285 }
286
287 /**
288 * Gets an event Declaration hashmap for a given StreamInput
289 * @param id the StreamInput
290 * @return the hashmap with the event definitions
291 */
292 public HashMap<Long, EventDefinition> getEventDefs(StreamInput id) {
293 if(! eventDefs.containsKey(id)){
294 eventDefs.put(id, new HashMap<Long, EventDefinition>());
295 }
296 return eventDefs.get(id);
297 }
298
299 /**
300 * Get an event by it's ID
301 *
302 * @param streamId
303 * The ID of the stream from which to read
304 * @param id
305 * the ID of the event
306 * @return the event declaration
307 */
308 public EventDeclaration getEventType(long streamId, long id) {
309 return getEvents(streamId).get(id);
310 }
311
312 /**
313 * Method getStream gets the stream for a given id
314 *
315 * @param id
316 * Long the id of the stream
317 * @return Stream the stream that we need
318 */
319 public Stream getStream(Long id) {
320 return streams.get(id);
321 }
322
323 /**
324 * Method nbStreams gets the number of available streams
325 *
326 * @return int the number of streams
327 */
328 public int nbStreams() {
329 return streams.size();
330 }
331
332 /**
333 * Method setMajor sets the major version of the trace (DO NOT USE)
334 *
335 * @param major
336 * long the major version
337 */
338 public void setMajor(long major) {
339 this.major = major;
340 }
341
342 /**
343 * Method setMinor sets the minor version of the trace (DO NOT USE)
344 *
345 * @param minor
346 * long the minor version
347 */
348 public void setMinor(long minor) {
349 this.minor = minor;
350 }
351
352 /**
353 * Method setUUID sets the UUID of a trace
354 *
355 * @param uuid
356 * UUID
357 */
358 public void setUUID(UUID uuid) {
359 this.uuid = uuid;
360 }
361
362 /**
363 * Method setByteOrder sets the byte order
364 *
365 * @param byteOrder
366 * ByteOrder of the trace, can be little-endian or big-endian
367 */
368 public void setByteOrder(ByteOrder byteOrder) {
369 this.byteOrder = byteOrder;
370 }
371
372 /**
373 * Method setPacketHeader sets the packet header of a trace (DO NOT USE)
374 *
375 * @param packetHeader
376 * StructDeclaration the header in structdeclaration form
377 */
378 public void setPacketHeader(StructDeclaration packetHeader) {
379 this.packetHeaderDecl = packetHeader;
380 }
381
382 /**
383 * Method majortIsSet is the major version number set?
384 *
385 * @return boolean is the major set?
386 */
387 public boolean majortIsSet() {
388 return major != null;
389 }
390
391 /**
392 * Method minorIsSet. is the minor version number set?
393 *
394 * @return boolean is the minor set?
395 */
396 public boolean minorIsSet() {
397 return minor != null;
398 }
399
400 /**
401 * Method UUIDIsSet is the UUID set?
402 *
403 * @return boolean is the UUID set?
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 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 fc = new FileInputStream(streamFile).getChannel();
530 streamFileChannels.add(fc);
531
532 /* Map one memory page of 4 kiB */
533 byteBuffer = fc.map(MapMode.READ_ONLY, 0, 4096);
534 } catch (IOException e) {
535 /* Shouldn't happen at this stage if every other check passed */
536 throw new CTFReaderException();
537 }
538
539 /* Create a BitBuffer with this mapping and the trace byte order */
540 streamBitBuffer = new BitBuffer(byteBuffer, this.getByteOrder());
541
542 if (packetHeaderDef != null) {
543 /* Read the packet header */
544 packetHeaderDef.read(streamBitBuffer);
545
546 /* Check the magic number */
547 IntegerDefinition magicDef = (IntegerDefinition) packetHeaderDef
548 .lookupDefinition("magic"); //$NON-NLS-1$
549 int magic = (int) magicDef.getValue();
550 if (magic != Utils.CTF_MAGIC) {
551 throw new CTFReaderException("CTF magic mismatch"); //$NON-NLS-1$
552 }
553
554 /* Check UUID */
555 ArrayDefinition uuidDef = (ArrayDefinition) packetHeaderDef
556 .lookupDefinition("uuid"); //$NON-NLS-1$
557 if (uuidDef != null) {
558 byte[] uuidArray = new byte[Utils.UUID_LEN];
559
560 for (int i = 0; i < Utils.UUID_LEN; i++) {
561 IntegerDefinition uuidByteDef = (IntegerDefinition) uuidDef
562 .getElem(i);
563 uuidArray[i] = (byte) uuidByteDef.getValue();
564 }
565
566 UUID otheruuid = Utils.makeUUID(uuidArray);
567
568 if (!this.uuid.equals(otheruuid)) {
569 throw new CTFReaderException("UUID mismatch"); //$NON-NLS-1$
570 }
571 }
572
573 /* Read stream ID */
574 // TODO: it hasn't been checked that the stream_id field exists and
575 // is an unsigned
576 // integer
577 IntegerDefinition streamIDDef = (IntegerDefinition) packetHeaderDef
578 .lookupDefinition("stream_id"); //$NON-NLS-1$
579 assert (streamIDDef != null);
580
581 long streamID = streamIDDef.getValue();
582
583 /* Get the stream to which this trace file belongs to */
584 stream = streams.get(streamID);
585 } else {
586 /* No packet header, we suppose there is only one stream */
587 stream = streams.get(null);
588 }
589
590 /* Create the stream input */
591 StreamInput streamInput = new StreamInput(stream, fc, streamFile);
592
593 /* Add a reference to the streamInput in the stream */
594 stream.addInput(streamInput);
595 }
596
597 /**
598 * Looks up a definition from packet
599 *
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.
615 *
616 * @param stream
617 * A stream object.
618 * @throws ParseException
619 * If there was some problem reading the metadata
620 */
621 public void addStream(Stream stream) throws ParseException {
622
623 /*
624 * If there is already a stream without id (the null key), it must be
625 * the only one
626 */
627 if (streams.get(null) != null) {
628 throw new ParseException("Stream without id with multiple streams"); //$NON-NLS-1$
629 }
630
631 /*
632 * If the stream we try to add has the null key, it must be the onl * one. Thus, if the streams container is not empty, it is not valid.
633 */
634 if ((stream.getId() == null) && (streams.size() != 0)) {
635 throw new ParseException("Stream without id with multiple streams"); //$NON-NLS-1$
636 }
637
638 /* If a stream with the same ID already exists, it is not valid. */
639 if (streams.get(stream.getId()) != null) {
640 throw new ParseException("Stream id already exists"); //$NON-NLS-1$
641 }
642
643 /* It should be ok now. */
644 streams.put(stream.getId(), stream);
645 eventDecs.put(stream.getId(), new HashMap<Long,EventDeclaration>());
646 }
647
648 /**
649 * gets the Environment variables from the trace metadata (See CTF spec)
650 * @return the environment variables in a hashmap form (key value)
651 */
652 public HashMap<String, String> getEnvironment() {
653 return environment;
654 }
655
656 /**
657 * Look up a specific environment variable
658 * @param key the key to look for
659 * @return the value of the variable, can be null.
660 */
661 public String lookupEnvironment(String key) {
662 return environment.get(key);
663 }
664
665 /**
666 * Add a variable to the environment variables
667 * @param varName the name of the variable
668 * @param varValue the value of the variable
669 */
670 public void addEnvironmentVar(String varName, String varValue) {
671 environment.put(varName, varValue);
672 }
673
674 /**
675 * Add a clock to the clock list
676 * @param nameValue the name of the clock (full name with scope)
677 * @param ctfClock the clock
678 */
679 public void addClock(String nameValue, CTFClock ctfClock) {
680 clocks.put(nameValue, ctfClock);
681 }
682
683 /**
684 * gets the clock with a specific name
685 * @param name the name of the clock.
686 * @return the clock
687 */
688 public CTFClock getClock(String name) {
689 return clocks.get(name);
690 }
691
692 private CTFClock singleClock;
693 private long singleOffset;
694
695 /**
696 * gets the clock if there is only one. (this is 100% of the use cases as of June 2012)
697 * @return the clock
698 */
699 public final CTFClock getClock() {
700 if (clocks.size() == 1) {
701 if (singleClock == null) {
702 singleClock = clocks.get(clocks.keySet().toArray()[0]);
703 singleOffset = (Long) getClock().getProperty("offset"); //$NON-NLS-1$
704 }
705 return singleClock;
706 }
707 return null;
708 }
709
710 /**
711 * gets the time offset of a clock with respect to UTC in nanoseconds
712 * @return the time offset of a clock with respect to UTC in nanoseconds
713 */
714 public final long getOffset() {
715 if (getClock() == null) {
716 return 0;
717 }
718 return singleOffset;
719 }
720
721 /**
722 * Does a given stream contain any events?
723 * @param id the stream ID
724 * @return true if the stream has events.
725 */
726 public boolean hasEvents(Long id){
727 return eventDecs.containsKey(id);
728 }
729
730 /**
731 * Add an event declaration map to the events map.
732 * @param id the id of a stream
733 * @return the hashmap containing events.
734 */
735 public HashMap<Long, EventDeclaration> createEvents(Long id){
736 HashMap<Long, EventDeclaration> value = eventDecs.get(id);
737 if( value == null ) {
738 value = new HashMap<Long, EventDeclaration>();
739 eventDecs.put(id, value);
740 }
741 return value;
742 }
743
744 }
745
746 class MetadataFileFilter implements FileFilter {
747
748 @Override
749 public boolean accept(File pathname) {
750 if (pathname.isDirectory()) {
751 return false;
752 }
753 if (pathname.isHidden()) {
754 return false;
755 }
756 if (pathname.getName().equals("metadata")) { //$NON-NLS-1$
757 return false;
758 }
759 return true;
760 }
761
762 }
763
764 class MetadataComparator implements Comparator<File>, Serializable {
765
766 private static final long serialVersionUID = 1L;
767
768 @Override
769 public int compare(File o1, File o2) {
770 return o1.getName().compareTo(o2.getName());
771 }
772 }
This page took 0.047299 seconds and 5 git commands to generate.