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