9317d550531b25bcdac7839cc7b6e9680ace97ed
[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.types.ArrayDefinition;
38 import org.eclipse.linuxtools.ctf.core.event.types.Definition;
39 import org.eclipse.linuxtools.ctf.core.event.types.IDefinitionScope;
40 import org.eclipse.linuxtools.ctf.core.event.types.IntegerDefinition;
41 import org.eclipse.linuxtools.ctf.core.event.types.StructDeclaration;
42 import org.eclipse.linuxtools.ctf.core.event.types.StructDefinition;
43 import org.eclipse.linuxtools.internal.ctf.core.Activator;
44 import org.eclipse.linuxtools.internal.ctf.core.event.io.BitBuffer;
45 import org.eclipse.linuxtools.internal.ctf.core.event.metadata.exceptions.ParseException;
46 import org.eclipse.linuxtools.internal.ctf.core.trace.Stream;
47 import org.eclipse.linuxtools.internal.ctf.core.trace.StreamInput;
48
49 /**
50 * <b><u>CTFTrace</u></b>
51 * <p>
52 * Represents a trace on the filesystem. It is responsible of parsing the
53 * metadata, creating declarations data structures, indexing the event packets
54 * (in other words, all the work that can be shared between readers), but the
55 * actual reading of events is left to TraceReader.
56 *
57 * @author Matthew Khouzam
58 * @version $Revision: 1.0 $
59 */
60 public class CTFTrace implements IDefinitionScope {
61
62 // ------------------------------------------------------------------------
63 // Attributes
64 // ------------------------------------------------------------------------
65
66 /*
67 * (non-Javadoc)
68 *
69 * @see java.lang.Object#toString()
70 */
71 @SuppressWarnings("nls")
72 @Override
73 public String toString() {
74 /* Only for debugging, shouldn't be externalized */
75 return "CTFTrace [path=" + path + ", major=" + major + ", minor="
76 + minor + ", uuid=" + uuid + "]";
77 }
78
79 /**
80 * The trace directory on the filesystem.
81 */
82 private final File path;
83
84 /**
85 * The metadata parsing object.
86 */
87 private final Metadata metadata;
88
89 /**
90 * Major CTF version number
91 */
92 private Long major;
93
94 /**
95 * Minor CTF version number
96 */
97 private Long minor;
98
99 /**
100 * Trace UUID
101 */
102 private UUID uuid;
103
104 /**
105 * Trace byte order
106 */
107 private ByteOrder byteOrder;
108
109 /**
110 * Packet header structure declaration
111 */
112 private StructDeclaration packetHeaderDecl = null;
113
114 /**
115 * Packet header structure definition
116 *
117 * This is only used when opening the trace files, to read the first packet
118 * header and see if they are valid trace files.
119 */
120 private StructDefinition packetHeaderDef;
121
122 /**
123 * Collection of streams contained in the trace.
124 */
125 private final HashMap<Long, Stream> streams;
126
127 /**
128 * Collection of environment variables set by the tracer
129 */
130 private final HashMap<String, String> environment;
131
132 /**
133 * Collection of all the clocks in a system.
134 */
135 private final HashMap<String, CTFClock> clocks;
136
137 /** FileChannels to the streams */
138 private final List<FileChannel> streamFileChannels;
139
140 /** Handlers for the metadata files */
141 private final static FileFilter metadataFileFilter = new MetadataFileFilter();
142 private final static Comparator<File> metadataComparator = new MetadataComparator(); // $codepro.audit.disable fieldJavadoc
143
144 /** map of all the event types */
145 private final HashMap<Long, EventDeclaration> events;
146
147 // ------------------------------------------------------------------------
148 // Constructors
149 // ------------------------------------------------------------------------
150
151 /**
152 * Trace constructor.
153 *
154 * @param path
155 * Filesystem path of the trace directory.
156 * @throws IOException
157 */
158 public CTFTrace(String path) throws CTFReaderException {
159 this(new File(path));
160
161 }
162
163 /**
164 * Trace constructor.
165 *
166 * @param path
167 * Filesystem path of the trace directory.
168 * @throws CTFReaderException
169 */
170 public CTFTrace(File path) throws CTFReaderException {
171 this.path = path;
172 this.metadata = new Metadata(this);
173
174 /* Set up the internal containers for this trace */
175 streams = new HashMap<Long, Stream>();
176 environment = new HashMap<String, String>();
177 clocks = new HashMap<String, CTFClock>();
178 streamFileChannels = new LinkedList<FileChannel>();
179
180 if (!this.path.isDirectory()) {
181 throw new CTFReaderException("Path must be a valid directory"); //$NON-NLS-1$
182 }
183
184 /* Open and parse the metadata file */
185 metadata.parse();
186
187 if (Activator.getDefault() != null) {
188 Activator.getDefault().log(metadata.toString());
189 }
190
191 /* Open all the trace files */
192 /* Create the definitions needed to read things from the files */
193 if (packetHeaderDecl != null) {
194 packetHeaderDef = packetHeaderDecl.createDefinition(this,
195 "packet.header"); //$NON-NLS-1$
196 }
197
198 /* List files not called metadata and not hidden. */
199 File[] files = path.listFiles(metadataFileFilter);
200 Arrays.sort(files, metadataComparator);
201
202 /* Try to open each file */
203 for (File streamFile : files) {
204 openStreamInput(streamFile);
205 }
206 events = new HashMap<Long, EventDeclaration>();
207 /* Create their index */
208 for (Map.Entry<Long, Stream> stream : streams.entrySet()) {
209 Set<StreamInput> inputs = stream.getValue().getStreamInputs();
210 for (StreamInput s : inputs) {
211 /*
212 * Copy the events
213 */
214 Iterator<Entry<Long, EventDeclaration>> it = s.getStream()
215 .getEvents().entrySet().iterator();
216 while (it.hasNext()) {
217 Map.Entry<Long, EventDeclaration> pairs = it.next();
218 Long eventNum = pairs.getKey();
219 EventDeclaration eventDec = pairs.getValue();
220 events.put(eventNum, eventDec);
221 }
222
223 /*
224 * index the trace
225 */
226 s.createIndex();
227 }
228 }
229 }
230
231 @Override
232 protected void finalize() {
233 /* If this trace gets closed, release the descriptors to the streams */
234 for (FileChannel fc : streamFileChannels) {
235 if (fc != null) {
236 try {
237 fc.close();
238 } catch (IOException e) {
239 // do nothing it's ok, we tried to close it.
240 }
241 }
242 }
243 try {
244 super.finalize();
245 } catch (Throwable e) {
246 // TODO Auto-generated catch block
247 }
248 }
249
250 // ------------------------------------------------------------------------
251 // Getters/Setters/Predicates
252 // ------------------------------------------------------------------------
253
254 /**
255 * Get an event by it's ID
256 *
257 * @param id
258 * the ID of the event
259 * @return the event declaration
260 */
261 public EventDeclaration getEventType(long id) {
262 return events.get(id);
263 }
264
265 /**
266 * Get the number of events in the trace so far.
267 *
268 * @return the number of events in the trace
269 */
270 public int getNbEventTypes() {
271 return events.size();
272 }
273
274 /**
275 * Method getStream gets the stream for a given id
276 *
277 * @param id
278 * Long the id of the stream
279 * @return Stream the stream that we need
280 */
281 public Stream getStream(Long id) {
282 return streams.get(id);
283 }
284
285 /**
286 * Method nbStreams gets the number of available streams
287 *
288 * @return int the number of streams
289 */
290 public int nbStreams() {
291 return streams.size();
292 }
293
294 /**
295 * Method setMajor sets the major version of the trace (DO NOT USE)
296 *
297 * @param major
298 * long the major version
299 */
300 public void setMajor(long major) {
301 this.major = major;
302 }
303
304 /**
305 * Method setMinor sets the minor version of the trace (DO NOT USE)
306 *
307 * @param minor
308 * long the minor version
309 */
310 public void setMinor(long minor) {
311 this.minor = minor;
312 }
313
314 /**
315 * Method setUUID sets the UUID of a trace
316 *
317 * @param uuid
318 * UUID
319 */
320 public void setUUID(UUID uuid) {
321 this.uuid = uuid;
322 }
323
324 /**
325 * Method setByteOrder sets the byte order
326 *
327 * @param byteOrder
328 * ByteOrder of the trace, can be little-endian or big-endian
329 */
330 public void setByteOrder(ByteOrder byteOrder) {
331 this.byteOrder = byteOrder;
332 }
333
334 /**
335 * Method setPacketHeader sets the packet header of a trace (DO NOT USE)
336 *
337 * @param packetHeader
338 * StructDeclaration the header in structdeclaration form
339 */
340 public void setPacketHeader(StructDeclaration packetHeader) {
341 this.packetHeaderDecl = packetHeader;
342 }
343
344 /**
345 * Method majortIsSet is the major version number set?
346 *
347 * @return boolean is the major set?
348 */
349 public boolean majortIsSet() {
350 return major != null;
351 }
352
353 /**
354 * Method minorIsSet. is the minor version number set?
355 *
356 * @return boolean is the minor set?
357 */
358 public boolean minorIsSet() {
359 return minor != null;
360 }
361
362 /**
363 * Method UUIDIsSet is the UUID set?
364 *
365 * @return boolean is the UUID set?
366 */
367 public boolean UUIDIsSet() {
368 return uuid != null;
369 }
370
371 /**
372 * Method byteOrderIsSet is the byteorder set?
373 *
374 * @return boolean is the byteorder set?
375 */
376 public boolean byteOrderIsSet() {
377 return byteOrder != null;
378 }
379
380 /**
381 * Method packetHeaderIsSet is the packet header set?
382 *
383 * @return boolean is the packet header set?
384 */
385 public boolean packetHeaderIsSet() {
386 return packetHeaderDecl != null;
387 }
388
389 /**
390 * Method getUUID gets the trace UUID
391 *
392 * @return UUID gets the trace UUID
393 */
394 public UUID getUUID() {
395 return uuid;
396 }
397
398 /**
399 * Method getMajor gets the trace major version
400 *
401 * @return long gets the trace major version
402 */
403 public long getMajor() {
404 return major;
405 }
406
407 /**
408 * Method getMinor gets the trace minor version
409 *
410 * @return long gets the trace minor version
411 */
412 public long getMinor() {
413 return minor;
414 }
415
416 /**
417 * Method getByteOrder gets the trace byte order
418 *
419 * @return ByteOrder gets the trace byte order
420 */
421 public ByteOrder getByteOrder() {
422 return byteOrder;
423 }
424
425 /**
426 * Method getPacketHeader gets the trace packet header
427 *
428 * @return StructDeclaration gets the trace packet header
429 */
430 public StructDeclaration getPacketHeader() {
431 return packetHeaderDecl;
432 }
433
434 /**
435 * Method getTraceDirectory gets the trace directory
436 *
437 * @return File the path in "File" format.
438 */
439 public File getTraceDirectory() {
440 return path;
441 }
442
443 /**
444 * Method getStreams get all the streams in a map format.
445 *
446 * @return Map<Long,Stream> a map of all the streams.
447 */
448 public Map<Long, Stream> getStreams() {
449 return streams;
450 }
451
452 /**
453 * Method getPath gets the path of the trace directory
454 *
455 * @return String the path of the trace directory, in string format.
456 * @see java.io.File#getPath()
457 */
458 @Override
459 public String getPath() {
460 return path.getPath();
461 }
462
463 // ------------------------------------------------------------------------
464 // Operations
465 // ------------------------------------------------------------------------
466
467 /**
468 * Tries to open the given file, reads the first packet header of the file
469 * and check its validity.
470 *
471 * @param streamFile
472 * A trace file in the trace directory.
473 * @param index
474 * Which index in the class' streamFileChannel array this file
475 * must use
476 * @throws CTFReaderException
477 */
478 private void openStreamInput(File streamFile) throws CTFReaderException {
479 MappedByteBuffer byteBuffer;
480 BitBuffer streamBitBuffer;
481 Stream stream;
482 FileChannel fc;
483
484 if (!streamFile.canRead()) {
485 throw new CTFReaderException("Unreadable file : " //$NON-NLS-1$
486 + streamFile.getPath());
487 }
488
489 try {
490 /* Open the file and get the FileChannel */
491 fc = new FileInputStream(streamFile).getChannel();
492 streamFileChannels.add(fc);
493
494 /* Map one memory page of 4 kiB */
495 byteBuffer = fc.map(MapMode.READ_ONLY, 0, 4096);
496 } catch (IOException e) {
497 /* Shouldn't happen at this stage if every other check passed */
498 throw new CTFReaderException();
499 }
500
501 /* Create a BitBuffer with this mapping and the trace byte order */
502 streamBitBuffer = new BitBuffer(byteBuffer, this.getByteOrder());
503
504 if (packetHeaderDef != null) {
505 /* Read the packet header */
506 packetHeaderDef.read(streamBitBuffer);
507
508 /* Check the magic number */
509 IntegerDefinition magicDef = (IntegerDefinition) packetHeaderDef
510 .lookupDefinition("magic"); //$NON-NLS-1$
511 int magic = (int) magicDef.getValue();
512 if (magic != Utils.CTF_MAGIC) {
513 throw new CTFReaderException("CTF magic mismatch"); //$NON-NLS-1$
514 }
515
516 /* Check UUID */
517 ArrayDefinition uuidDef = (ArrayDefinition) packetHeaderDef
518 .lookupDefinition("uuid"); //$NON-NLS-1$
519 assert ((uuidDef != null) && (uuidDef.getDeclaration().getLength() == Utils.UUID_LEN));
520 if (uuidDef != null) {
521 byte[] uuidArray = new byte[Utils.UUID_LEN];
522
523 for (int i = 0; i < Utils.UUID_LEN; i++) {
524 IntegerDefinition uuidByteDef = (IntegerDefinition) uuidDef
525 .getElem(i);
526 uuidArray[i] = (byte) uuidByteDef.getValue();
527 }
528
529 UUID otheruuid = Utils.makeUUID(uuidArray);
530
531 if (!this.uuid.equals(otheruuid)) {
532 throw new CTFReaderException("UUID mismatch"); //$NON-NLS-1$
533 }
534 }
535
536 /* Read stream ID */
537 // TODO: it hasn't been checked that the stream_id field exists and
538 // is an unsigned
539 // integer
540 IntegerDefinition streamIDDef = (IntegerDefinition) packetHeaderDef
541 .lookupDefinition("stream_id"); //$NON-NLS-1$
542 assert (streamIDDef != null);
543
544 long streamID = streamIDDef.getValue();
545
546 /* Get the stream to which this trace file belongs to */
547 stream = streams.get(streamID);
548 } else {
549 /* No packet header, we suppose there is only one stream */
550 stream = streams.get(null);
551 }
552
553 /* Create the stream input */
554 StreamInput streamInput = new StreamInput(stream, fc, streamFile);
555
556 /* Add a reference to the streamInput in the stream */
557 stream.addInput(streamInput);
558 }
559
560 /**
561 * Looks up a definition from packet
562 *
563 * @param lookupPath
564 * String
565 * @return Definition
566 * @see org.eclipse.linuxtools.ctf.core.event.types.IDefinitionScope#lookupDefinition(String)
567 */
568 @Override
569 public Definition lookupDefinition(String lookupPath) {
570 if (lookupPath.equals("trace.packet.header")) { //$NON-NLS-1$
571 return packetHeaderDef;
572 }
573 return null;
574 }
575
576 /**
577 * Adds a new stream to the trace.
578 *
579 * @param stream
580 * A stream object.
581 *
582 * @throws ParseException
583 */
584 public void addStream(Stream stream) throws ParseException {
585
586 /*
587 * If there is already a stream without id (the null key), it must be
588 * the only one
589 */
590 if (streams.get(null) != null) {
591 throw new ParseException("Stream without id with multiple streams"); //$NON-NLS-1$
592 }
593
594 /*
595 * If the stream we try to add has the null key, it must be the only
596 * one. Thus, if the streams container is not empty, it is not valid.
597 */
598 if ((stream.getId() == null) && (streams.size() != 0)) {
599 throw new ParseException("Stream without id with multiple streams"); //$NON-NLS-1$
600 }
601
602 /* If a stream with the same ID already exists, it is not valid. */
603 if (streams.get(stream.getId()) != null) {
604 throw new ParseException("Stream id already exists"); //$NON-NLS-1$
605 }
606
607 /* It should be ok now. */
608 streams.put(stream.getId(), stream);
609 }
610
611 public HashMap<String, String> getEnvironment() {
612 return environment;
613 }
614
615 public String lookupEnvironment(String key) {
616 return environment.get(key);
617 }
618
619 public void addEnvironmentVar(String varName, String varValue) {
620 environment.put(varName, varValue);
621 }
622
623 public void addClock(String nameValue, CTFClock ctfClock) {
624 clocks.put(nameValue, ctfClock);
625 }
626
627 public CTFClock getClock(String name) {
628 return clocks.get(name);
629 }
630
631 public CTFClock getClock() {
632 if (clocks.size() == 1) {
633 String key = (String) clocks.keySet().toArray()[0];
634 return clocks.get(key);
635 }
636 return null;
637 }
638
639 public long getOffset() {
640 if (getClock() == null) {
641 return 0;
642 }
643 return (Long) getClock().getProperty("offset"); //$NON-NLS-1$
644 }
645
646 }
647
648 class MetadataFileFilter implements FileFilter {
649
650 @Override
651 public boolean accept(File pathname) {
652 if (pathname.isDirectory()) {
653 return false;
654 }
655 if (pathname.isHidden()) {
656 return false;
657 }
658 if (pathname.getName().equals("metadata")) { //$NON-NLS-1$
659 return false;
660 }
661 return true;
662 }
663
664 }
665
666 class MetadataComparator implements Comparator<File>, Serializable {
667
668 @Override
669 public int compare(File o1, File o2) {
670 return o1.getName().compareTo(o2.getName());
671 }
672 }
This page took 0.048985 seconds and 5 git commands to generate.