1 /*******************************************************************************
2 * Copyright (c) 2009, 2011 Ericsson, MontaVista Software
4 * All rights reserved. This program and the accompanying materials are
5 * made 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
10 * William Bourque (wbourque@gmail.com) - Initial API and implementation
11 * Yufen Kuo (ykuo@mvista.com) - add support to allow user specify trace library path
12 *******************************************************************************/
14 package org
.eclipse
.linuxtools
.internal
.lttng
.core
.trace
;
16 import java
.io
.FileNotFoundException
;
17 import java
.util
.HashMap
;
18 import java
.util
.Iterator
;
19 import java
.util
.Vector
;
21 import org
.eclipse
.core
.resources
.IProject
;
22 import org
.eclipse
.linuxtools
.internal
.lttng
.core
.TraceHelper
;
23 import org
.eclipse
.linuxtools
.internal
.lttng
.core
.event
.LttngEvent
;
24 import org
.eclipse
.linuxtools
.internal
.lttng
.core
.event
.LttngEventContent
;
25 import org
.eclipse
.linuxtools
.internal
.lttng
.core
.event
.LttngEventType
;
26 import org
.eclipse
.linuxtools
.internal
.lttng
.core
.event
.LttngLocation
;
27 import org
.eclipse
.linuxtools
.internal
.lttng
.core
.event
.LttngTimestamp
;
28 import org
.eclipse
.linuxtools
.internal
.lttng
.core
.exceptions
.LttngException
;
29 import org
.eclipse
.linuxtools
.internal
.lttng
.core
.tracecontrol
.utility
.LiveTraceManager
;
30 import org
.eclipse
.linuxtools
.internal
.lttng
.jni
.common
.JniTime
;
31 import org
.eclipse
.linuxtools
.internal
.lttng
.jni
.exception
.JniException
;
32 import org
.eclipse
.linuxtools
.lttng
.jni
.JniEvent
;
33 import org
.eclipse
.linuxtools
.lttng
.jni
.JniMarker
;
34 import org
.eclipse
.linuxtools
.lttng
.jni
.JniTrace
;
35 import org
.eclipse
.linuxtools
.lttng
.jni
.JniTracefile
;
36 import org
.eclipse
.linuxtools
.lttng
.jni
.factory
.JniTraceFactory
;
37 import org
.eclipse
.linuxtools
.tmf
.core
.event
.ITmfTimestamp
;
38 import org
.eclipse
.linuxtools
.tmf
.core
.event
.TmfEvent
;
39 import org
.eclipse
.linuxtools
.tmf
.core
.event
.TmfTimeRange
;
40 import org
.eclipse
.linuxtools
.tmf
.core
.event
.TmfTimestamp
;
41 import org
.eclipse
.linuxtools
.tmf
.core
.experiment
.TmfExperiment
;
42 import org
.eclipse
.linuxtools
.tmf
.core
.request
.ITmfDataRequest
.ExecutionType
;
43 import org
.eclipse
.linuxtools
.tmf
.core
.request
.TmfEventRequest
;
44 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTraceUpdatedSignal
;
45 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.ITmfContext
;
46 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.ITmfLocation
;
47 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.TmfCheckpoint
;
48 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.TmfContext
;
49 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.TmfTrace
;
51 class LTTngTraceException
extends LttngException
{
52 static final long serialVersionUID
= -1636648737081868146L;
54 public LTTngTraceException(String errMsg
) {
60 * <b><u>LTTngTrace</u></b>
63 * LTTng trace implementation. It accesses the C trace handling library (seeking, reading and parsing) through the JNI
66 public class LTTngTrace
extends TmfTrace
<LttngEvent
> {
68 public final static boolean PRINT_DEBUG
= false;
69 public final static boolean UNIQUE_EVENT
= true;
71 private final static boolean SHOW_LTT_DEBUG_DEFAULT
= false;
72 private final static boolean IS_PARSING_NEEDED_DEFAULT
= !UNIQUE_EVENT
;
73 private final static int CHECKPOINT_PAGE_SIZE
= 50000;
74 private final static long LTTNG_STREAMING_INTERVAL
= 2000; // in ms
76 // Reference to our JNI trace
77 private JniTrace currentJniTrace
;
79 LttngTimestamp eventTimestamp
;
81 LttngEventContent eventContent
;
82 String eventReference
;
85 LttngEvent currentLttngEvent
;
87 // The current location
88 LttngLocation previousLocation
;
90 LttngEventType eventType
;
92 // Hashmap of the possible types of events (Tracefile/CPU/Marker in the JNI)
93 HashMap
<Integer
, LttngEventType
> traceTypes
;
95 // This vector will be used to quickly find a marker name from a position
96 Vector
<Integer
> traceTypeNames
;
98 private String traceLibPath
;
100 private long fStreamingInterval
= 0;
102 public LTTngTrace() {
106 public boolean validate(IProject project
, String path
) {
107 if (super.validate(project
, path
)) {
108 String traceLibPath
= TraceHelper
.getTraceLibDirFromProject(project
);
110 LTTngTraceVersion version
= new LTTngTraceVersion(path
, traceLibPath
);
111 return version
.isValidLttngTrace();
112 } catch (LttngException e
) {
119 public void initTrace(String name
, String path
, Class
<LttngEvent
> eventType
) throws FileNotFoundException
{
120 initLTTngTrace(name
, path
, eventType
, CHECKPOINT_PAGE_SIZE
, false);
124 public void initTrace(String name
, String path
, Class
<LttngEvent
> eventType
, int cacheSize
) throws FileNotFoundException
{
125 initLTTngTrace(name
, path
, eventType
, cacheSize
, false);
129 public void initTrace(String name
, String path
, Class
<LttngEvent
> eventType
, boolean indexTrace
) throws FileNotFoundException
{
130 initLTTngTrace(name
, path
, eventType
, CHECKPOINT_PAGE_SIZE
, indexTrace
);
134 public void initTrace(String name
, String path
, Class
<LttngEvent
> eventType
, int cacheSize
, boolean indexTrace
) throws FileNotFoundException
{
135 initLTTngTrace(name
, path
, eventType
, cacheSize
, indexTrace
);
138 private synchronized void initLTTngTrace(String name
, String path
, Class
<LttngEvent
> eventType
, int cacheSize
, boolean indexTrace
) throws FileNotFoundException
{
139 super.initTrace(name
, path
, eventType
, indexTrace
);
141 currentJniTrace
= JniTraceFactory
.getJniTrace(path
, traceLibPath
, SHOW_LTT_DEBUG_DEFAULT
);
142 } catch (Exception e
) {
143 throw new FileNotFoundException(e
.getMessage());
146 // Export all the event types from the JNI side
147 traceTypes
= new HashMap
<Integer
, LttngEventType
>();
148 traceTypeNames
= new Vector
<Integer
>();
149 initialiseEventTypes(currentJniTrace
);
151 // Build the re-used event structure
152 eventTimestamp
= new LttngTimestamp();
153 eventSource
= ""; //$NON-NLS-1$
154 this.eventType
= new LttngEventType();
155 eventContent
= new LttngEventContent(currentLttngEvent
);
156 eventReference
= getName();
158 // Create the skeleton event
159 currentLttngEvent
= new LttngEvent(this, eventTimestamp
, eventSource
, this.eventType
, eventContent
,
160 eventReference
, null);
162 // Create a new current location
163 previousLocation
= new LttngLocation();
165 // Set the currentEvent to the eventContent
166 eventContent
.setEvent(currentLttngEvent
);
168 // // Bypass indexing if asked
169 // if ( bypassIndexing == false ) {
173 // Even if we don't have any index, set ONE checkpoint
174 // fCheckpoints.add(new TmfCheckpoint(new LttngTimestamp(0L) , new
175 // LttngLocation() ) );
177 initializeStreamingMonitor();
180 private void initializeStreamingMonitor() {
181 JniTrace jniTrace
= getCurrentJniTrace();
182 if (jniTrace
== null || (!jniTrace
.isLiveTraceSupported() || !LiveTraceManager
.isLiveTrace(jniTrace
.getTracepath()))) {
183 // Set the time range of the trace
184 TmfContext context
= seekLocation(null);
185 LttngEvent event
= getNextEvent(context
);
186 LttngTimestamp startTime
= new LttngTimestamp(event
.getTimestamp());
187 LttngTimestamp endTime
= new LttngTimestamp(currentJniTrace
.getEndTime().getTime());
188 setTimeRange(new TmfTimeRange(startTime
, endTime
));
189 TmfTraceUpdatedSignal signal
= new TmfTraceUpdatedSignal(this, this, getTimeRange());
194 // Set the time range of the trace
195 TmfContext context
= seekLocation(null);
196 LttngEvent event
= getNextEvent(context
);
197 setEndTime(TmfTimestamp
.BIG_BANG
);
198 final long startTime
= event
!= null ? event
.getTimestamp().getValue() : TmfTimestamp
.BIG_BANG
.getValue();
199 fStreamingInterval
= LTTNG_STREAMING_INTERVAL
;
201 final Thread thread
= new Thread("Streaming Monitor for trace " + getName()) { //$NON-NLS-1$
202 LttngTimestamp safeTimestamp
= null;
203 TmfTimeRange timeRange
= null;
205 @SuppressWarnings("unchecked")
208 while (!fExecutor
.isShutdown()) {
209 TmfExperiment
<?
> experiment
= TmfExperiment
.getCurrentExperiment();
210 if (experiment
!= null) {
211 @SuppressWarnings("rawtypes")
212 final TmfEventRequest request
= new TmfEventRequest
<TmfEvent
>(TmfEvent
.class, TmfTimeRange
.ETERNITY
, 0, ExecutionType
.FOREGROUND
) {
214 public void handleCompleted() {
218 synchronized (experiment
) {
219 experiment
.sendRequest(request
);
222 request
.waitForCompletion();
223 } catch (InterruptedException e
) {
230 Thread
.sleep(LTTNG_STREAMING_INTERVAL
);
231 } catch (InterruptedException e
) {
237 private void updateJniTrace() {
238 JniTrace jniTrace
= getCurrentJniTrace();
239 currentJniTrace
.updateTrace();
240 long endTime
= jniTrace
.getEndTime().getTime();
241 LttngTimestamp startTimestamp
= new LttngTimestamp(startTime
);
242 LttngTimestamp endTimestamp
= new LttngTimestamp(endTime
);
243 if (safeTimestamp
!= null && safeTimestamp
.compareTo(getTimeRange().getEndTime(), false) > 0) {
244 timeRange
= new TmfTimeRange(startTimestamp
, safeTimestamp
);
248 safeTimestamp
= endTimestamp
;
249 if (timeRange
!= null) {
250 setTimeRange(timeRange
);
258 * @see org.eclipse.linuxtools.tmf.trace.TmfTrace#getStreamingInterval()
261 public long getStreamingInterval() {
262 return fStreamingInterval
;
266 * Default Constructor.
272 * Path to a <b>directory</b> that contain an LTTng trace.
274 * @exception Exception
275 * (most likely LTTngTraceException or FileNotFoundException)
277 public LTTngTrace(String name
, String path
) throws Exception
{
278 // Call with "wait for completion" true and "skip indexing" false
279 this(name
, path
, null, true, false);
283 * Constructor, with control over the indexing.
289 * Path to a <b>directory</b> that contain an LTTng trace.
290 * @param waitForCompletion
291 * Should we wait for indexign to complete before moving on.
293 * @exception Exception
294 * (most likely LTTngTraceException or FileNotFoundException)
296 public LTTngTrace(String name
, String path
, boolean waitForCompletion
) throws Exception
{
297 // Call with "skip indexing" false
298 this(name
, path
, null, waitForCompletion
, true);
302 * Default constructor, with control over the indexing and possibility to bypass indexation
308 * Path to a <b>directory</b> that contain an LTTng trace.
309 * @param traceLibPath
310 * Path to a <b>directory</b> that contains LTTng trace libraries.
311 * @param waitForCompletion
312 * Should we wait for indexign to complete before moving on.
313 * @param bypassIndexing
314 * Should we bypass indexing completly? This is should only be useful for unit testing.
316 * @exception Exception
317 * (most likely LTTngTraceException or FileNotFoundException)
320 public LTTngTrace(String name
, String path
, String traceLibPath
, boolean waitForCompletion
, boolean bypassIndexing
)
322 super(name
, LttngEvent
.class, path
, CHECKPOINT_PAGE_SIZE
, false);
323 initTrace(name
, path
, LttngEvent
.class, !bypassIndexing
);
324 this.traceLibPath
= traceLibPath
;
328 * Copy constructor is forbidden for LttngEvenmStream
330 public LTTngTrace(LTTngTrace other
) throws Exception
{
331 this(other
.getName(), other
.getPath(), other
.getTraceLibPath(), false, true);
332 this.fCheckpoints
= other
.fCheckpoints
;
333 setTimeRange(new TmfTimeRange(new LttngTimestamp(other
.getStartTime()), new LttngTimestamp(other
.getEndTime())));
337 public LTTngTrace
copy() {
338 LTTngTrace returnedTrace
= null;
341 returnedTrace
= new LTTngTrace(this);
342 } catch (Exception e
) {
343 System
.out
.println("ERROR : Could not create LTTngTrace copy (createTraceCopy)."); //$NON-NLS-1$
347 return returnedTrace
;
351 public synchronized LTTngTrace
clone() {
352 LTTngTrace clone
= null;
354 clone
= (LTTngTrace
) super.clone();
356 clone
.currentJniTrace
= JniTraceFactory
.getJniTrace(getPath(), getTraceLibPath(),
357 SHOW_LTT_DEBUG_DEFAULT
);
358 } catch (JniException e
) {
359 // e.printStackTrace();
362 // Export all the event types from the JNI side
363 clone
.traceTypes
= new HashMap
<Integer
, LttngEventType
>();
364 clone
.traceTypeNames
= new Vector
<Integer
>();
365 clone
.initialiseEventTypes(clone
.currentJniTrace
);
367 // Verify that all those "default constructor" are safe to use
368 clone
.eventTimestamp
= new LttngTimestamp();
369 clone
.eventSource
= ""; //$NON-NLS-1$
370 clone
.eventType
= new LttngEventType();
371 clone
.eventContent
= new LttngEventContent(clone
.currentLttngEvent
);
372 clone
.eventReference
= getName();
374 // Create the skeleton event
375 clone
.currentLttngEvent
= new LttngEvent(this, clone
.eventTimestamp
, clone
.eventSource
, clone
.eventType
,
376 clone
.eventContent
, clone
.eventReference
, null);
378 // Create a new current location
379 clone
.previousLocation
= new LttngLocation();
381 // Set the currentEvent to the eventContent
382 clone
.eventContent
.setEvent(clone
.currentLttngEvent
);
384 // Set the start time of the trace
385 setTimeRange(new TmfTimeRange(new LttngTimestamp(clone
.currentJniTrace
.getStartTime().getTime()),
386 new LttngTimestamp(clone
.currentJniTrace
.getEndTime().getTime())));
387 } catch (CloneNotSupportedException e
) {
393 public String
getTraceLibPath() {
398 * Fill out the HashMap with "Type" (Tracefile/Marker)
400 * This should be called at construction once the trace is open
402 private void initialiseEventTypes(JniTrace trace
) {
404 LttngEventType tmpType
= null;
405 String
[] markerFieldsLabels
= null;
407 String newTracefileKey
= null;
408 Integer newMarkerKey
= null;
410 JniTracefile newTracefile
= null;
411 JniMarker newMarker
= null;
413 // First, obtain an iterator on TRACEFILES of owned by the TRACE
414 Iterator
<String
> tracefileItr
= trace
.getTracefilesMap().keySet().iterator();
416 while (tracefileItr
.hasNext()) {
417 newTracefileKey
= tracefileItr
.next();
418 newTracefile
= trace
.getTracefilesMap().get(newTracefileKey
);
420 // From the TRACEFILE read, obtain its MARKER
421 Iterator
<Integer
> markerItr
= newTracefile
.getTracefileMarkersMap().keySet().iterator();
422 while (markerItr
.hasNext()) {
423 newMarkerKey
= markerItr
.next();
424 newMarker
= newTracefile
.getTracefileMarkersMap().get(newMarkerKey
);
426 // From the MARKER we can obtain the MARKERFIELDS keys (i.e.
428 markerFieldsLabels
= newMarker
.getMarkerFieldsHashMap().keySet()
429 .toArray(new String
[newMarker
.getMarkerFieldsHashMap().size()]);
431 tmpType
= new LttngEventType(newTracefile
.getTracefileName(), newTracefile
.getCpuNumber(),
432 newMarker
.getName(), newMarkerKey
.intValue(), markerFieldsLabels
);
434 // Add the type to the map/vector
435 addEventTypeToMap(tmpType
);
441 * Add a new type to the HashMap
443 * As the hashmap use a key format that is a bit dangerous to use, we should always add using this function.
445 private void addEventTypeToMap(LttngEventType newEventType
) {
446 int newTypeKey
= EventTypeKey
.getEventTypeHash(newEventType
);
448 this.traceTypes
.put(newTypeKey
, newEventType
);
449 this.traceTypeNames
.add(newTypeKey
);
453 * Return the latest saved location. Note : Modifying the returned location may result in buggy positionning!
455 * @return The LttngLocation as it was after the last operation.
457 * @see org.eclipse.linuxtools.internal.lttng.core.event.LttngLocation
460 public synchronized ITmfLocation
<?
> getCurrentLocation() {
461 return previousLocation
;
465 * Position the trace to the event at the given location.
467 * NOTE : Seeking by location is very fast compare to seeking by position but is still slower than "ReadNext", avoid
468 * using it for small interval.
471 * Location of the event in the trace. If no event available at this exact location, we will position
472 * ourself to the next one.
474 * @return The TmfContext that point to this event
476 * @see org.eclipse.linuxtools.internal.lttng.core.event.LttngLocation
477 * @see org.eclipse.linuxtools.tmf.core.trace.TmfContext
480 public synchronized TmfContext
seekLocation(ITmfLocation
<?
> location
) {
486 System
.out
.println("seekLocation(location) location -> " + location
); //$NON-NLS-1$
489 // If the location in context is null, create a new one
490 LttngLocation curLocation
= null;
491 if (location
== null) {
492 curLocation
= new LttngLocation();
493 TmfContext context
= seekEvent(curLocation
.getOperationTime());
494 context
.setRank(ITmfContext
.INITIAL_RANK
);
497 curLocation
= (LttngLocation
) location
;
501 // Update to location should (and will) be done in SeekEvent.
503 // The only seek valid in LTTng is with the time, we call
504 // seekEvent(timestamp)
505 TmfContext context
= seekEvent(curLocation
.getOperationTime());
507 // If the location is marked with the read next flag
508 // then it is pointing to the next event following the operation time
509 if (curLocation
.isLastOperationReadNext()) {
510 getNextEvent(context
);
517 * Position the trace to the event at the given time.
519 * NOTE : Seeking by time is very fast compare to seeking by position but is still slower than "ReadNext", avoid
520 * using it for small interval.
523 * Time of the event in the trace. If no event available at this exact time, we will position ourself to
526 * @return The TmfContext that point to this event
528 * @see org.eclipse.linuxtools.internal.lttng.core.event.LttngLocation
529 * @see org.eclipse.linuxtools.tmf.core.trace.TmfContext
532 public synchronized TmfContext
seekEvent(ITmfTimestamp timestamp
) {
535 System
.out
.println("seekEvent(timestamp) timestamp -> " + timestamp
); //$NON-NLS-1$
539 currentJniTrace
.seekToTime(new JniTime(timestamp
.getValue()));
541 // Save the time at which we seeked
542 previousLocation
.setOperationTime(timestamp
.getValue());
543 // Set the operation marker as seek, to be able to detect we did "seek"
545 previousLocation
.setLastOperationSeek();
547 LttngLocation curLocation
= new LttngLocation(previousLocation
);
549 return new TmfContext(curLocation
);
553 * Position the trace to the event at the given position (rank).
555 * NOTE : Seeking by position is very slow in LTTng, consider seeking by timestamp.
558 * Position (or rank) of the event in the trace, starting at 0.
560 * @return The TmfContext that point to this event
562 * @see org.eclipse.linuxtools.internal.lttng.core.event.LttngLocation
563 * @see org.eclipse.linuxtools.tmf.core.trace.TmfContext
566 public synchronized TmfContext
seekEvent(long position
) {
569 System
.out
.println("seekEvent(position) position -> " + position
); //$NON-NLS-1$
572 ITmfTimestamp timestamp
= null;
573 long index
= position
/ getCacheSize();
575 // Get the timestamp of the closest check point to the given position
576 if (fCheckpoints
.size() > 0) {
577 if (index
>= fCheckpoints
.size()) {
578 index
= fCheckpoints
.size() - 1;
580 timestamp
= fCheckpoints
.elementAt((int) index
).getTimestamp();
582 // If none, take the start time of the trace
584 timestamp
= getStartTime();
587 // Seek to the found time
588 TmfContext tmpContext
= seekEvent(timestamp
);
589 tmpContext
.setRank((index
+ 1) * fIndexPageSize
);
590 previousLocation
= (LttngLocation
) tmpContext
.getLocation();
592 // Ajust the index of the event we found at this check point position
593 Long currentPosition
= index
* getCacheSize();
595 Long lastTimeValueRead
= 0L;
597 // Get the event at current position. This won't move to the next one
598 JniEvent tmpJniEvent
= currentJniTrace
.findNextEvent();
599 // Now that we are positionned at the checkpoint,
600 // we need to "readNext" (Position - CheckpointPosition) times or until
602 while ((tmpJniEvent
!= null) && (currentPosition
< position
)) {
603 tmpJniEvent
= currentJniTrace
.readNextEvent();
607 // If we found our event, save its timestamp
608 if (tmpJniEvent
!= null) {
609 lastTimeValueRead
= tmpJniEvent
.getEventTime().getTime();
612 // Set the operation marker as seek, to be able to detect we did "seek"
614 previousLocation
.setLastOperationSeek();
615 // Save read event time
616 previousLocation
.setOperationTime(lastTimeValueRead
);
619 // Is that too paranoid?
621 // We don't trust what upper level could do with our internal location
622 // so we create a new one to return instead
623 LttngLocation curLocation
= new LttngLocation(previousLocation
);
625 return new TmfContext(curLocation
);
629 public TmfContext
seekLocation(double ratio
) {
630 // TODO Auto-generated method stub
635 public double getLocationRatio(ITmfLocation
<?
> location
) {
636 // TODO Auto-generated method stub
641 * Return the event in the trace according to the given context. Read it if necessary.
643 * Similar (same?) as ParseEvent except that calling GetNext twice read the next one the second time.
646 * Current TmfContext where to get the event
648 * @return The LttngEvent we read of null if no event are available
650 * @see org.eclipse.linuxtools.internal.lttng.core.event.LttngLocation
651 * @see org.eclipse.linuxtools.tmf.core.trace.TmfContext
654 public int nbEventsRead
= 0;
657 public synchronized LttngEvent
getNextEvent(ITmfContext context
) {
660 System
.out
.println("getNextEvent(context) context.getLocation() -> " //$NON-NLS-1$
661 + context
.getLocation());
664 LttngEvent returnedEvent
= null;
665 LttngLocation curLocation
= null;
667 curLocation
= (LttngLocation
) context
.getLocation();
668 // If the location in context is null, create a new one
669 if (curLocation
== null) {
670 curLocation
= getCurrentLocation(context
);
673 // *** Positioning trick :
674 // GetNextEvent only read the trace if :
675 // 1- The last operation was NOT a ParseEvent --> A read is required
677 // 2- The time of the previous location is different from the current
678 // one --> A seek + a read is required
679 if ((!(curLocation
.isLastOperationParse()))
680 || (previousLocation
.getOperationTimeValue() != curLocation
.getOperationTimeValue())) {
681 if (previousLocation
.getOperationTimeValue() != curLocation
.getOperationTimeValue()) {
683 System
.out
.println("\t\tSeeking in getNextEvent. [ LastTime : " //$NON-NLS-1$
684 + previousLocation
.getOperationTimeValue() + " CurrentTime" //$NON-NLS-1$
685 + curLocation
.getOperationTimeValue() + " ]"); //$NON-NLS-1$
687 seekEvent(curLocation
.getOperationTime());
689 // Read the next event from the trace. The last one will NO LONGER
691 returnedEvent
= readNextEvent(curLocation
);
694 // No event was read, just return the one currently loaded (the last
696 returnedEvent
= currentLttngEvent
;
698 // Set the operation marker as read to both locations, to be able to
699 // detect we need to read the next event
700 previousLocation
.setLastOperationReadNext();
701 curLocation
.setLastOperationReadNext();
704 // If we read an event, set it's time to the locations (both previous
706 if (returnedEvent
!= null) {
707 setPreviousAndCurrentTimes(context
, returnedEvent
, curLocation
);
710 return returnedEvent
;
713 // this method was extracted for profiling purposes
714 private synchronized void setPreviousAndCurrentTimes(ITmfContext context
, LttngEvent returnedEvent
, LttngLocation curLocation
) {
716 ITmfTimestamp eventTimestamp
= returnedEvent
.getTimestamp();
717 // long eventTime = eventTimestamp.getValue();
718 previousLocation
.setOperationTime(eventTimestamp
.getValue());
719 curLocation
.setOperationTime(eventTimestamp
.getValue());
720 updateIndex(context
, context
.getRank(), eventTimestamp
);
721 context
.updateRank(1);
724 protected void updateIndex(TmfContext context
, long rank
, ITmfTimestamp timestamp
) {
726 if (getStartTime().compareTo(timestamp
, false) > 0)
727 setStartTime(timestamp
);
728 if (getEndTime().compareTo(timestamp
, false) < 0)
729 setEndTime(timestamp
);
730 if (rank
!= ITmfContext
.UNKNOWN_RANK
) {
731 if (fNbEvents
<= rank
)
732 fNbEvents
= rank
+ 1;
733 // Build the index as we go along
734 if ((rank
% fIndexPageSize
) == 0) {
735 // Determine the table position
736 long position
= rank
/ fIndexPageSize
;
737 // Add new entry at proper location (if empty)
738 if (fCheckpoints
.size() == position
) {
739 addCheckPoint(context
, timestamp
);
745 private void addCheckPoint(TmfContext context
, ITmfTimestamp timestamp
) {
746 ITmfLocation
<?
> location
= context
.getLocation().clone();
747 fCheckpoints
.add(new TmfCheckpoint(timestamp
.clone(), location
));
750 // this method was extracted for profiling purposes
751 private synchronized LttngEvent
readNextEvent(LttngLocation curLocation
) {
752 LttngEvent returnedEvent
;
753 // Read the next event from the trace. The last one will NO LONGER BE
755 returnedEvent
= readEvent(curLocation
);
758 // Set the operation marker as read to both locations, to be able to
759 // detect we need to read the next event
760 previousLocation
.setLastOperationReadNext();
761 curLocation
.setLastOperationReadNext();
762 return returnedEvent
;
765 // this method was extracted for profiling purposes
766 private LttngLocation
getCurrentLocation(ITmfContext context
) {
767 LttngLocation curLocation
;
768 curLocation
= new LttngLocation();
769 context
.setLocation(curLocation
);
774 * Return the event in the trace according to the given context. Read it if necessary.
776 * Similar (same?) as GetNextEvent except that calling ParseEvent twice will return the same event
779 * Current TmfContext where to get the event
781 * @return The LttngEvent we read of null if no event are available
783 * @see org.eclipse.linuxtools.internal.lttng.core.event.LttngLocation
784 * @see org.eclipse.linuxtools.tmf.core.trace.TmfContext
787 public synchronized LttngEvent
parseEvent(ITmfContext context
) {
790 System
.out
.println("parseEvent(context) context.getLocation() -> " //$NON-NLS-1$
791 + context
.getLocation());
794 LttngEvent returnedEvent
= null;
795 LttngLocation curLocation
= null;
797 // If the location in context is null, create a new one
798 if (context
.getLocation() == null) {
799 curLocation
= new LttngLocation();
800 context
.setLocation(curLocation
);
802 // Otherwise, we use the one in context; it should be a valid
805 curLocation
= (LttngLocation
) context
.getLocation();
809 // TMF assumes it is possible to read (GetNextEvent) to the next Event
810 // once ParseEvent() is called
811 // In LTTNG, there is not difference between "Parsing" and "Reading" an
813 // So, before "Parsing" an event, we have to make sure we didn't "Read"
815 // Also, "Reading" invalidate the previous Event in LTTNG and seek back
817 // so calling twice "Parse" will return the same event, giving a way to
818 // get the "Currently loaded" event
820 // *** Positionning trick :
821 // ParseEvent only read the trace if :
822 // 1- The last operation was NOT a ParseEvent --> A read is required
824 // 2- The time of the previous location is different from the current
825 // one --> A seek + a read is required
826 if (!curLocation
.isLastOperationParse()
827 || (previousLocation
.getOperationTimeValue() != curLocation
.getOperationTimeValue())) {
828 // Previous time != Current time : We need to reposition to the
830 if (previousLocation
.getOperationTimeValue() != curLocation
.getOperationTimeValue()) {
832 System
.out
.println("\t\tSeeking in getNextEvent. [ LastTime : " //$NON-NLS-1$
833 + previousLocation
.getOperationTimeValue() + " CurrentTime" //$NON-NLS-1$
834 + curLocation
.getOperationTimeValue() + " ]"); //$NON-NLS-1$
836 seekEvent(curLocation
.getOperationTime());
839 // Read the next event from the trace. The last one will NO LONGER
841 returnedEvent
= readEvent(curLocation
);
843 // No event was read, just return the one currently loaded (the last
845 returnedEvent
= currentLttngEvent
;
848 // If we read an event, set it's time to the locations (both previous
850 if (returnedEvent
!= null) {
851 previousLocation
.setOperationTime((LttngTimestamp
) returnedEvent
.getTimestamp());
852 curLocation
.setOperationTime((LttngTimestamp
) returnedEvent
.getTimestamp());
855 // Set the operation marker as parse to both location, to be able to
856 // detect we already "read" this event
857 previousLocation
.setLastOperationParse();
858 curLocation
.setLastOperationParse();
860 return returnedEvent
;
864 * Read the next event from the JNI and convert it as Lttng Event<p>
866 * @param location Current LttngLocation that to be updated with the event timestamp
868 * @return The LttngEvent we read of null if no event are available
870 * @see org.eclipse.linuxtools.lttng.event.LttngLocation
872 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniTrace
874 private synchronized LttngEvent
readEvent(LttngLocation location
) {
875 LttngEvent returnedEvent
= null;
876 JniEvent tmpEvent
= null;
878 // Read the next event from JNI. THIS WILL INVALIDATE THE CURRENT LTTNG
880 tmpEvent
= currentJniTrace
.readNextEvent();
882 if (tmpEvent
!= null) {
884 // Convert will update the currentLttngEvent
885 returnedEvent
= convertJniEventToTmf(tmpEvent
);
887 location
.setOperationTime((LttngTimestamp
) returnedEvent
.getTimestamp());
890 // If the read failed (likely the last event in the trace), set the
891 // LastReadTime to the JNI time
892 // That way, even if we try to read again, we will step over the bogus
895 location
.setOperationTime(getEndTime().getValue() + 1);
898 return returnedEvent
;
902 * Method to convert a JniEvent into a LttngEvent.
905 * Note : This method will call LttngEvent convertEventJniToTmf(JniEvent, boolean) with a default value for
909 * The JniEvent to convert into LttngEvent
911 * @return The converted LttngEvent
913 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniEvent
914 * @see org.eclipse.linuxtools.internal.lttng.core.event.LttngEvent
916 public synchronized LttngEvent
convertJniEventToTmf(JniEvent newEvent
) {
917 currentLttngEvent
= convertJniEventToTmf(newEvent
, IS_PARSING_NEEDED_DEFAULT
);
919 return currentLttngEvent
;
923 * Method to convert a JniEvent into a LttngEvent
926 * The JniEvent to convert into LttngEvent
927 * @param isParsingNeeded
928 * A boolean value telling if the event should be parsed or not.
930 * @return The converted LttngEvent
932 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniEvent
933 * @see org.eclipse.linuxtools.internal.lttng.core.event.LttngEvent
935 public synchronized LttngEvent
convertJniEventToTmf(JniEvent jniEvent
, boolean isParsingNeeded
) {
940 // UNHACKED : We can no longer do that because TCF need to maintain
941 // several events at once.
942 // This is very slow to do so in LTTng, this has to be temporary.
944 // To save time here, we only set value instead of allocating new
946 // This give an HUGE performance improvement
947 // all allocation done in the LttngTrace constructor
949 eventTimestamp
.setValue(jniEvent
.getEventTime().getTime());
950 eventSource
= jniEvent
.requestEventSource();
952 eventType
= traceTypes
.get(EventTypeKey
.getEventTypeHash(jniEvent
));
954 String fullTracePath
= getName();
955 String reference
= fullTracePath
.substring(fullTracePath
.lastIndexOf('/') + 1);
956 currentLttngEvent
.setReference(reference
);
958 eventContent
.emptyContent();
960 currentLttngEvent
.setType(eventType
);
961 // Save the jni reference
962 currentLttngEvent
.updateJniEventReference(jniEvent
);
964 // Parse now if was asked
965 // Warning : THIS IS SLOW
966 if (isParsingNeeded
) {
967 eventContent
.getFields();
970 return currentLttngEvent
;
972 return convertJniEventToTmfMultipleEventEvilFix(jniEvent
, isParsingNeeded
);
978 * This method is a temporary fix to support multiple events at once in TMF This is expected to be slow and should
979 * be fixed in another way. See comment in convertJniEventToTmf();
982 * The current JNI Event
983 * @return Current Lttng Event fully parsed
985 private synchronized LttngEvent
convertJniEventToTmfMultipleEventEvilFix(JniEvent jniEvent
, boolean isParsingNeeded
) {
987 // Below : the "fix" with all the new and the full-parse
988 // Allocating new memory is slow.
989 // Parsing every events is very slow.
990 eventTimestamp
= new LttngTimestamp(jniEvent
.getEventTime().getTime());
991 eventSource
= jniEvent
.requestEventSource();
992 eventReference
= getName();
993 eventType
= new LttngEventType(traceTypes
.get(EventTypeKey
.getEventTypeHash(jniEvent
)));
994 eventContent
= new LttngEventContent(currentLttngEvent
);
995 currentLttngEvent
= new LttngEvent(this, eventTimestamp
, eventSource
, eventType
, eventContent
, eventReference
,
998 // The jni reference is no longer reliable but we will keep it anyhow
999 currentLttngEvent
.updateJniEventReference(jniEvent
);
1000 // Ensure that the content is correctly set
1001 eventContent
.setEvent(currentLttngEvent
);
1003 // Parse the event if it was needed
1005 // ONLY for testing, NOT parsing events with non-unique events WILL
1006 // result in segfault in the JVM
1007 if (isParsingNeeded
) {
1008 eventContent
.getFields();
1011 return currentLttngEvent
;
1015 * Reference to the current LttngTrace we are reading from.
1018 * Note : This bypass the framework and should not be use, except for testing!
1020 * @return Reference to the current LttngTrace
1022 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniTrace
1024 public JniTrace
getCurrentJniTrace() {
1025 return currentJniTrace
;
1029 * Return a reference to the current LttngEvent we have in memory.
1031 * @return The current (last read) LttngEvent
1033 * @see org.eclipse.linuxtools.internal.lttng.core.event.LttngEvent
1035 public synchronized LttngEvent
getCurrentEvent() {
1036 return currentLttngEvent
;
1040 * Get the major version number for the current trace
1042 * @return Version major or -1 if unknown
1044 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniTrace
1047 public short getVersionMajor() {
1048 if (currentJniTrace
!= null) {
1049 return currentJniTrace
.getLttMajorVersion();
1056 * Get the minor version number for the current trace
1058 * @return Version minor or -1 if unknown
1060 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniTrace
1063 public short getVersionMinor() {
1064 if (currentJniTrace
!= null) {
1065 return currentJniTrace
.getLttMinorVersion();
1072 * Get the number of CPU for this trace
1074 * @return Number of CPU or -1 if unknown
1076 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniTrace
1079 public int getCpuNumber() {
1080 if (currentJniTrace
!= null) {
1081 return currentJniTrace
.getCpuNumber();
1088 * Print the content of the checkpoint vector.
1091 * This is intended for debug purpose only.
1093 public void printCheckpointsVector() {
1094 System
.out
.println("StartTime : " //$NON-NLS-1$
1095 + getTimeRange().getStartTime().getValue());
1096 System
.out
.println("EndTime : " //$NON-NLS-1$
1097 + getTimeRange().getEndTime().getValue());
1099 for (int pos
= 0; pos
< fCheckpoints
.size(); pos
++) {
1100 System
.out
.print(pos
+ ": " + "\t"); //$NON-NLS-1$ //$NON-NLS-2$
1101 System
.out
.print(fCheckpoints
.get(pos
).getTimestamp() + "\t"); //$NON-NLS-1$
1102 System
.out
.println(fCheckpoints
.get(pos
).getLocation());
1107 public synchronized void dispose() {
1108 if (currentJniTrace
!= null)
1109 currentJniTrace
.closeTrace();
1114 * Return a String identifying this trace.
1116 * @return String that identify this trace
1119 @SuppressWarnings("nls")
1120 public String
toString() {
1121 String returnedData
= "";
1123 returnedData
+= "Path :" + getPath() + " ";
1124 returnedData
+= "Trace:" + currentJniTrace
+ " ";
1125 returnedData
+= "Event:" + currentLttngEvent
;
1127 return returnedData
;
1133 * EventTypeKey inner class
1135 * This class is used to make the process of generating the HashMap key more transparent and so less error prone to use
1137 final class EventTypeKey
{
1139 // These two getEventTypeKey() functions should ALWAYS construct the key the
1141 // Otherwise, every type search will fail!
1143 // added final to encourage inlining.
1145 // generating a hash code by hand to avoid a string creation
1146 final static public int getEventTypeHash(LttngEventType newEventType
) {
1147 return generateHash(newEventType
.getTracefileName(), newEventType
.getCpuId(), newEventType
.getMarkerName());
1150 final private static int generateHash(String traceFileName
, long cpuNumber
, String markerName
) {
1151 // 0x1337 is a prime number. The number of CPUs is always under 8192 on
1152 // the current kernel, so this will work with the current linux kernel.
1153 int cpuHash
= (int) (cpuNumber
* (0x1337));
1154 return traceFileName
.hashCode() ^
(cpuHash
) ^ markerName
.hashCode();
1157 // generating a hash code by hand to avoid a string creation
1158 final static public int getEventTypeHash(JniEvent newEvent
) {
1159 return generateHash(newEvent
.getParentTracefile().getTracefileName(), newEvent
.getParentTracefile()
1160 .getCpuNumber(), newEvent
.requestEventMarker().getName());