Add new @since 1.0 annotations
[deliverable/tracecompass.git] / org.eclipse.tracecompass.tmf.ctf.core / src / org / eclipse / tracecompass / tmf / ctf / core / trace / CtfTmfTrace.java
1 /*******************************************************************************
2 * Copyright (c) 2012, 2014 Ericsson, École Polytechnique de Montréal
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 * Patrick Tasse - Updated for removal of context clone
12 * Geneviève Bastien - Added the createTimestamp function
13 *******************************************************************************/
14
15 package org.eclipse.tracecompass.tmf.ctf.core.trace;
16
17 import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
18
19 import java.nio.BufferOverflowException;
20 import java.nio.ByteBuffer;
21 import java.util.ArrayList;
22 import java.util.Collection;
23 import java.util.Collections;
24 import java.util.HashMap;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.Set;
28
29 import org.eclipse.core.resources.IProject;
30 import org.eclipse.core.resources.IResource;
31 import org.eclipse.core.runtime.CoreException;
32 import org.eclipse.core.runtime.IStatus;
33 import org.eclipse.core.runtime.Status;
34 import org.eclipse.jdt.annotation.NonNull;
35 import org.eclipse.jdt.annotation.Nullable;
36 import org.eclipse.tracecompass.ctf.core.CTFReaderException;
37 import org.eclipse.tracecompass.ctf.core.event.CTFCallsite;
38 import org.eclipse.tracecompass.ctf.core.event.CTFClock;
39 import org.eclipse.tracecompass.ctf.core.event.IEventDeclaration;
40 import org.eclipse.tracecompass.ctf.core.trace.CTFTrace;
41 import org.eclipse.tracecompass.ctf.core.trace.CTFTraceReader;
42 import org.eclipse.tracecompass.internal.tmf.ctf.core.Activator;
43 import org.eclipse.tracecompass.internal.tmf.ctf.core.trace.iterator.CtfIterator;
44 import org.eclipse.tracecompass.internal.tmf.ctf.core.trace.iterator.CtfIteratorManager;
45 import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
46 import org.eclipse.tracecompass.tmf.core.event.ITmfEventField;
47 import org.eclipse.tracecompass.tmf.core.event.TmfEventField;
48 import org.eclipse.tracecompass.tmf.core.event.aspect.ITmfEventAspect;
49 import org.eclipse.tracecompass.tmf.core.exceptions.TmfTraceException;
50 import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp;
51 import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestamp;
52 import org.eclipse.tracecompass.tmf.core.trace.ITmfContext;
53 import org.eclipse.tracecompass.tmf.core.trace.ITmfTraceProperties;
54 import org.eclipse.tracecompass.tmf.core.trace.ITmfTraceWithPreDefinedEvents;
55 import org.eclipse.tracecompass.tmf.core.trace.TmfTrace;
56 import org.eclipse.tracecompass.tmf.core.trace.TraceValidationStatus;
57 import org.eclipse.tracecompass.tmf.core.trace.indexer.ITmfPersistentlyIndexable;
58 import org.eclipse.tracecompass.tmf.core.trace.indexer.ITmfTraceIndexer;
59 import org.eclipse.tracecompass.tmf.core.trace.indexer.TmfBTreeTraceIndexer;
60 import org.eclipse.tracecompass.tmf.core.trace.indexer.checkpoint.ITmfCheckpoint;
61 import org.eclipse.tracecompass.tmf.core.trace.indexer.checkpoint.TmfCheckpoint;
62 import org.eclipse.tracecompass.tmf.core.trace.location.ITmfLocation;
63 import org.eclipse.tracecompass.tmf.ctf.core.CtfConstants;
64 import org.eclipse.tracecompass.tmf.ctf.core.context.CtfLocation;
65 import org.eclipse.tracecompass.tmf.ctf.core.context.CtfLocationInfo;
66 import org.eclipse.tracecompass.tmf.ctf.core.context.CtfTmfContext;
67 import org.eclipse.tracecompass.tmf.ctf.core.event.CtfTmfEvent;
68 import org.eclipse.tracecompass.tmf.ctf.core.event.CtfTmfEventType;
69 import org.eclipse.tracecompass.tmf.ctf.core.event.aspect.CtfChannelAspect;
70 import org.eclipse.tracecompass.tmf.ctf.core.event.aspect.CtfCpuAspect;
71 import org.eclipse.tracecompass.tmf.ctf.core.event.lookup.CtfTmfCallsite;
72 import org.eclipse.tracecompass.tmf.ctf.core.timestamp.CtfTmfTimestamp;
73
74 import com.google.common.collect.ImmutableList;
75 import com.google.common.collect.ImmutableSet;
76
77 /**
78 * The CTf trace handler
79 *
80 * @version 1.0
81 * @author Matthew khouzam
82 */
83 public class CtfTmfTrace extends TmfTrace
84 implements ITmfTraceProperties, ITmfPersistentlyIndexable,
85 ITmfTraceWithPreDefinedEvents, AutoCloseable {
86
87 // -------------------------------------------
88 // Constants
89 // -------------------------------------------
90
91 /**
92 * Default cache size for CTF traces
93 */
94 protected static final int DEFAULT_CACHE_SIZE = 50000;
95
96 /**
97 * Event aspects available for all CTF traces
98 * @since 1.0
99 */
100 protected static final @NonNull Collection<ITmfEventAspect> CTF_ASPECTS =
101 checkNotNull(ImmutableList.of(
102 ITmfEventAspect.BaseAspects.TIMESTAMP,
103 new CtfChannelAspect(),
104 new CtfCpuAspect(),
105 ITmfEventAspect.BaseAspects.EVENT_TYPE,
106 ITmfEventAspect.BaseAspects.CONTENTS
107 ));
108
109 /**
110 * The Ctf clock unique identifier field
111 */
112 private static final String CLOCK_HOST_PROPERTY = "uuid"; //$NON-NLS-1$
113 private static final int CONFIDENCE = 10;
114
115 // -------------------------------------------
116 // Fields
117 // -------------------------------------------
118
119 private final Map<String, CtfTmfEventType> fContainedEventTypes =
120 Collections.synchronizedMap(new HashMap<String, CtfTmfEventType>());
121
122 private final CtfIteratorManager fIteratorManager =
123 new CtfIteratorManager(this);
124
125 /* Reference to the CTF Trace */
126 private CTFTrace fTrace;
127
128 // -------------------------------------------
129 // TmfTrace Overrides
130 // -------------------------------------------
131 /**
132 * Method initTrace.
133 *
134 * @param resource
135 * The resource associated with this trace
136 * @param path
137 * The path to the trace file
138 * @param eventType
139 * The type of events that will be read from this trace
140 * @throws TmfTraceException
141 * If something went wrong while reading the trace
142 */
143 @Override
144 public void initTrace(final IResource resource, final String path, final Class<? extends ITmfEvent> eventType)
145 throws TmfTraceException {
146 /*
147 * Set the cache size. This has to be done before the call to super()
148 * because the super needs to know the cache size.
149 */
150 setCacheSize();
151
152 super.initTrace(resource, path, eventType);
153
154 try {
155 this.fTrace = new CTFTrace(path);
156 CtfTmfContext ctx;
157 /* Set the start and (current) end times for this trace */
158 ctx = (CtfTmfContext) seekEvent(0L);
159 CtfTmfEvent event = getNext(ctx);
160 if ((ctx.getLocation().equals(CtfIterator.NULL_LOCATION)) || (ctx.getCurrentEvent() == null)) {
161 /* Handle the case where the trace is empty */
162 this.setStartTime(TmfTimestamp.BIG_BANG);
163 } else {
164 final ITmfTimestamp curTime = event.getTimestamp();
165 this.setStartTime(curTime);
166 this.setEndTime(curTime);
167 }
168 /*
169 * Register every event type. When you call getType, it will
170 * register a trace to that type in the TmfEventTypeManager
171 */
172 try (CtfIterator iter = fIteratorManager.getIterator(ctx)) {
173 for (IEventDeclaration ied : iter.getEventDeclarations()) {
174 CtfTmfEventType ctfTmfEventType = fContainedEventTypes.get(ied.getName());
175 if (ctfTmfEventType == null) {
176 List<ITmfEventField> content = new ArrayList<>();
177 /* Should only return null the first time */
178 for (String fieldName : ied.getFields().getFieldsList()) {
179 content.add(new TmfEventField(fieldName, null, null));
180 }
181 ITmfEventField contentTree = new TmfEventField(
182 ITmfEventField.ROOT_FIELD_ID,
183 null,
184 content.toArray(new ITmfEventField[content.size()])
185 );
186
187 ctfTmfEventType = new CtfTmfEventType(ied.getName(), contentTree);
188 fContainedEventTypes.put(ctfTmfEventType.getName(), ctfTmfEventType);
189 }
190 }
191 }
192 } catch (final CTFReaderException e) {
193 /*
194 * If it failed at the init(), we can assume it's because the file
195 * was not found or was not recognized as a CTF trace. Throw into
196 * the new type of exception expected by the rest of TMF.
197 */
198 throw new TmfTraceException(e.getMessage(), e);
199 }
200 }
201
202 /**
203 * Return the iterator manager of this trace
204 *
205 * @return The iterator manager
206 */
207 public CtfIteratorManager getIteratorManager() {
208 return fIteratorManager;
209 }
210
211 @Override
212 public void close() {
213 dispose();
214 }
215
216 @Override
217 public synchronized void dispose() {
218 fIteratorManager.dispose();
219 if (fTrace != null) {
220 fTrace = null;
221 }
222 super.dispose();
223 }
224
225 /**
226 * {@inheritDoc}
227 * <p>
228 * The default implementation sets the confidence to 10 if the trace is a
229 * valid CTF trace.
230 */
231 @Override
232 public IStatus validate(final IProject project, final String path) {
233 IStatus status = new TraceValidationStatus(CONFIDENCE, Activator.PLUGIN_ID);
234 try {
235 final CTFTrace temp = new CTFTrace(path);
236 if (!temp.majorIsSet()) {
237 status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, Messages.CtfTmfTrace_MajorNotSet);
238 } else {
239 try (CTFTraceReader ctfTraceReader = new CTFTraceReader(temp);) {
240 if (!ctfTraceReader.hasMoreEvents()) {
241 // TODO: This will need an additional check when we
242 // support live traces
243 // because having no event is valid for a live trace
244 status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, Messages.CtfTmfTrace_NoEvent);
245 }
246 }
247 }
248 } catch (final CTFReaderException e) {
249 status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, Messages.CtfTmfTrace_ReadingError + ": " + e.toString()); //$NON-NLS-1$
250 } catch (final BufferOverflowException e) {
251 status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, Messages.CtfTmfTrace_ReadingError + ": " + Messages.CtfTmfTrace_BufferOverflowErrorMessage); //$NON-NLS-1$
252 }
253
254 return status;
255 }
256
257 @Override
258 public Iterable<ITmfEventAspect> getEventAspects() {
259 return CTF_ASPECTS;
260 }
261
262 /**
263 * Method getCurrentLocation. This is not applicable in CTF
264 *
265 * @return null, since the trace has no knowledge of the current location
266 * @see org.eclipse.tracecompass.tmf.core.trace.ITmfTrace#getCurrentLocation()
267 */
268 @Override
269 public ITmfLocation getCurrentLocation() {
270 return null;
271 }
272
273 @Override
274 public double getLocationRatio(ITmfLocation location) {
275 final CtfLocation curLocation = (CtfLocation) location;
276 final CtfTmfContext context = new CtfTmfContext(this);
277 context.setLocation(curLocation);
278 context.seek(curLocation.getLocationInfo());
279 final CtfLocationInfo currentTime = ((CtfLocationInfo) context.getLocation().getLocationInfo());
280 final long startTime = fIteratorManager.getIterator(context).getStartTime();
281 final long endTime = fIteratorManager.getIterator(context).getEndTime();
282 return ((double) currentTime.getTimestamp() - startTime)
283 / (endTime - startTime);
284 }
285
286 /**
287 * Method seekEvent.
288 *
289 * @param location
290 * ITmfLocation<?>
291 * @return ITmfContext
292 */
293 @Override
294 public synchronized ITmfContext seekEvent(final ITmfLocation location) {
295 CtfLocation currentLocation = (CtfLocation) location;
296 CtfTmfContext context = new CtfTmfContext(this);
297 if (fTrace == null) {
298 context.setLocation(null);
299 context.setRank(ITmfContext.UNKNOWN_RANK);
300 return context;
301 }
302 /*
303 * The rank is set to 0 if the iterator seeks the beginning. If not, it
304 * will be set to UNKNOWN_RANK, since CTF traces don't support seeking
305 * by rank for now.
306 */
307 if (currentLocation == null) {
308 currentLocation = new CtfLocation(new CtfLocationInfo(0L, 0L));
309 context.setRank(0);
310 }
311 if (currentLocation.getLocationInfo() == CtfLocation.INVALID_LOCATION) {
312 currentLocation = new CtfLocation(fTrace.getCurrentEndTime() + 1, 0L);
313 }
314 context.setLocation(currentLocation);
315 if (location == null) {
316 long timestamp = fIteratorManager.getIterator(context).getCurrentTimestamp();
317 currentLocation = new CtfLocation(timestamp, 0);
318 }
319 if (context.getRank() != 0) {
320 context.setRank(ITmfContext.UNKNOWN_RANK);
321 }
322 return context;
323 }
324
325 @Override
326 public synchronized ITmfContext seekEvent(double ratio) {
327 CtfTmfContext context = new CtfTmfContext(this);
328 if (fTrace == null) {
329 context.setLocation(null);
330 context.setRank(ITmfContext.UNKNOWN_RANK);
331 return context;
332 }
333 final long end = fTrace.getCurrentEndTime();
334 final long start = fTrace.getCurrentStartTime();
335 final long diff = end - start;
336 final long ratioTs = Math.round(diff * ratio) + start;
337 context.seek(ratioTs);
338 context.setRank(ITmfContext.UNKNOWN_RANK);
339 return context;
340 }
341
342 /**
343 * Method readNextEvent.
344 *
345 * @param context
346 * ITmfContext
347 * @return CtfTmfEvent
348 * @see org.eclipse.tracecompass.tmf.core.trace.ITmfTrace#getNext(ITmfContext)
349 */
350 @Override
351 public synchronized CtfTmfEvent getNext(final ITmfContext context) {
352 if (fTrace == null) {
353 return null;
354 }
355 CtfTmfEvent event = null;
356 if (context instanceof CtfTmfContext) {
357 if (context.getLocation() == null || CtfLocation.INVALID_LOCATION.equals(context.getLocation().getLocationInfo())) {
358 return null;
359 }
360 CtfTmfContext ctfContext = (CtfTmfContext) context;
361 event = ctfContext.getCurrentEvent();
362
363 if (event != null) {
364 updateAttributes(context, event.getTimestamp());
365 ctfContext.advance();
366 ctfContext.increaseRank();
367 }
368 }
369
370 return event;
371 }
372
373 /**
374 * Ctf traces have a clock with a unique uuid that will be used to identify
375 * the host. Traces with the same clock uuid will be known to have been made
376 * on the same machine.
377 *
378 * Note: uuid is an optional field, it may not be there for a clock.
379 */
380 @Override
381 public String getHostId() {
382 CTFClock clock = fTrace.getClock();
383 if (clock != null) {
384 String clockHost = (String) clock.getProperty(CLOCK_HOST_PROPERTY);
385 if (clockHost != null) {
386 return clockHost;
387 }
388 }
389 return super.getHostId();
390 }
391
392 /**
393 * Get the first callsite that matches the event name
394 *
395 * @param eventName The event name to look for
396 * @return The best callsite candidate
397 */
398 public @Nullable CtfTmfCallsite getCallsite(String eventName) {
399 CTFCallsite callsite = fTrace.getCallsite(eventName);
400 if (callsite != null) {
401 return new CtfTmfCallsite(callsite);
402 }
403 return null;
404 }
405
406 /**
407 * Get the closest matching callsite for given event name and instruction
408 * pointer
409 *
410 * @param eventName
411 * The event name
412 * @param ip
413 * The instruction pointer
414 * @return The closest matching callsite
415 */
416 public @Nullable CtfTmfCallsite getCallsite(String eventName, long ip) {
417 CTFCallsite calliste = fTrace.getCallsite(eventName, ip);
418 if (calliste != null) {
419 return new CtfTmfCallsite(calliste);
420 }
421 return null;
422 }
423
424 /**
425 * Get the CTF environment variables defined in this CTF trace, in <name,
426 * value> form. This comes from the trace's CTF metadata.
427 *
428 * @return The CTF environment
429 */
430 public Map<String, String> getEnvironment() {
431 return fTrace.getEnvironment();
432 }
433
434 // -------------------------------------------
435 // ITmfTraceProperties
436 // -------------------------------------------
437
438 @Override
439 public Map<String, String> getTraceProperties() {
440 Map<String, String> properties = new HashMap<>();
441 properties.putAll(fTrace.getEnvironment());
442 properties.put(Messages.CtfTmfTrace_HostID, getHostId());
443 return properties;
444 }
445
446 // -------------------------------------------
447 // Clocks
448 // -------------------------------------------
449
450 /**
451 * gets the clock offset
452 *
453 * @return the clock offset in ns
454 */
455 public long getOffset() {
456 if (fTrace != null) {
457 return fTrace.getOffset();
458 }
459 return 0;
460 }
461
462 /**
463 * Convert a CTF timestamp in CPU cycles to its equivalent in nanoseconds
464 * for this trace.
465 *
466 * @param cycles
467 * The timestamp in cycles
468 * @return The timestamp in nanoseconds
469 */
470 public long timestampCyclesToNanos(long cycles) {
471 return fTrace.timestampCyclesToNanos(cycles);
472 }
473
474 /**
475 * Convert a CTF timestamp in nanoseconds to its equivalent in CPU cycles
476 * for this trace.
477 *
478 * @param nanos
479 * The timestamp in nanoseconds
480 * @return The timestamp in cycles
481 */
482 public long timestampNanoToCycles(long nanos) {
483 return fTrace.timestampNanoToCycles(nanos);
484 }
485
486 /**
487 * Gets the list of declared events
488 */
489 @Override
490 public Set<CtfTmfEventType> getContainedEventTypes() {
491 return ImmutableSet.copyOf(fContainedEventTypes.values());
492 }
493
494 /**
495 * Register an event type to this trace.
496 *
497 * Public visibility so that {@link CtfTmfEvent#getType} can call it.
498 *
499 * FIXME This could probably be made cleaner?
500 *
501 * @param eventType
502 * The event type to register
503 */
504 public void registerEventType(CtfTmfEventType eventType) {
505 fContainedEventTypes.put(eventType.getName(), eventType);
506 }
507
508 // -------------------------------------------
509 // Parser
510 // -------------------------------------------
511
512 @Override
513 public CtfTmfEvent parseEvent(ITmfContext context) {
514 CtfTmfEvent event = null;
515 if (context instanceof CtfTmfContext) {
516 final ITmfContext tmpContext = seekEvent(context.getLocation());
517 event = getNext(tmpContext);
518 }
519 return event;
520 }
521
522 /**
523 * Sets the cache size for a CtfTmfTrace.
524 */
525 protected void setCacheSize() {
526 setCacheSize(DEFAULT_CACHE_SIZE);
527 }
528
529 // -------------------------------------------
530 // CtfIterator factory methods
531 // -------------------------------------------
532
533 /**
534 * Get an iterator to the trace
535 *
536 * @return an iterator to the trace
537 */
538 public ITmfContext createIterator() {
539 try {
540 return new CtfIterator(fTrace, this);
541 } catch (CTFReaderException e) {
542 Activator.getDefault().logError(e.getMessage(), e);
543 }
544 return null;
545 }
546
547 /**
548 * Get an iterator to the trace, , which will initially point to the given
549 * location/rank.
550 *
551 * @param ctfLocationData
552 * The initial timestamp the iterator will be pointing to
553 * @param rank
554 * The initial rank
555 * @return The new iterator
556 */
557 public ITmfContext createIterator(CtfLocationInfo ctfLocationData, long rank) {
558 try {
559 return new CtfIterator(fTrace, this, ctfLocationData, rank);
560 } catch (CTFReaderException e) {
561 Activator.getDefault().logError(e.getMessage(), e);
562 }
563 return null;
564 }
565
566 // ------------------------------------------------------------------------
567 // Timestamp transformation functions
568 // ------------------------------------------------------------------------
569
570 @Override
571 public CtfTmfTimestamp createTimestamp(long ts) {
572 return new CtfTmfTimestamp(getTimestampTransform().transform(ts));
573 }
574
575 private static int fCheckpointSize = -1;
576
577 @Override
578 public synchronized int getCheckpointSize() {
579 if (fCheckpointSize == -1) {
580 TmfCheckpoint c = new TmfCheckpoint(new CtfTmfTimestamp(0), new CtfLocation(0, 0), 0);
581 ByteBuffer b = ByteBuffer.allocate(ITmfCheckpoint.MAX_SERIALIZE_SIZE);
582 b.clear();
583 c.serialize(b);
584 fCheckpointSize = b.position();
585 }
586
587 return fCheckpointSize;
588 }
589
590 @Override
591 protected ITmfTraceIndexer createIndexer(int interval) {
592 return new TmfBTreeTraceIndexer(this, interval);
593 }
594
595 @Override
596 public ITmfLocation restoreLocation(ByteBuffer bufferIn) {
597 return new CtfLocation(bufferIn);
598 }
599
600 @Override
601 public boolean isComplete() {
602 if (getResource() == null) {
603 return true;
604 }
605
606 String host = null;
607 String port = null;
608 String sessionName = null;
609 try {
610 host = getResource().getPersistentProperty(CtfConstants.LIVE_HOST);
611 port = getResource().getPersistentProperty(CtfConstants.LIVE_PORT);
612 sessionName = getResource().getPersistentProperty(CtfConstants.LIVE_SESSION_NAME);
613 } catch (CoreException e) {
614 Activator.getDefault().logError(e.getMessage(), e);
615 // Something happened to the resource, assume we won't get any more
616 // data from it
617 return true;
618 }
619 return host == null || port == null || sessionName == null;
620 }
621
622 @Override
623 public void setComplete(final boolean isComplete) {
624 super.setComplete(isComplete);
625 try {
626 if (isComplete) {
627 getResource().setPersistentProperty(CtfConstants.LIVE_HOST, null);
628 getResource().setPersistentProperty(CtfConstants.LIVE_PORT, null);
629 getResource().setPersistentProperty(CtfConstants.LIVE_SESSION_NAME, null);
630 }
631 } catch (CoreException e) {
632 Activator.getDefault().logError(e.getMessage(), e);
633 }
634 }
635 }
This page took 0.046104 seconds and 6 git commands to generate.