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 synchronized void initTrace(String name
, String path
, Class
<LttngEvent
> eventType
) throws FileNotFoundException
{
120 super.initTrace(name
, path
, eventType
);
122 currentJniTrace
= JniTraceFactory
.getJniTrace(path
, traceLibPath
, SHOW_LTT_DEBUG_DEFAULT
);
123 } catch (Exception e
) {
124 throw new FileNotFoundException(e
.getMessage());
127 // Export all the event types from the JNI side
128 traceTypes
= new HashMap
<Integer
, LttngEventType
>();
129 traceTypeNames
= new Vector
<Integer
>();
130 initialiseEventTypes(currentJniTrace
);
132 // Build the re-used event structure
133 eventTimestamp
= new LttngTimestamp();
134 eventSource
= ""; //$NON-NLS-1$
135 this.eventType
= new LttngEventType();
136 eventContent
= new LttngEventContent(currentLttngEvent
);
137 eventReference
= getName();
139 // Create the skeleton event
140 currentLttngEvent
= new LttngEvent(this, eventTimestamp
, eventSource
, this.eventType
, eventContent
,
141 eventReference
, null);
143 // Create a new current location
144 previousLocation
= new LttngLocation();
146 // Set the currentEvent to the eventContent
147 eventContent
.setEvent(currentLttngEvent
);
149 // // Bypass indexing if asked
150 // if ( bypassIndexing == false ) {
154 // Even if we don't have any index, set ONE checkpoint
155 // fCheckpoints.add(new TmfCheckpoint(new LttngTimestamp(0L) , new
156 // LttngLocation() ) );
158 initializeStreamingMonitor();
161 private void initializeStreamingMonitor() {
162 JniTrace jniTrace
= getCurrentJniTrace();
163 if (jniTrace
== null || (!jniTrace
.isLiveTraceSupported() || !LiveTraceManager
.isLiveTrace(jniTrace
.getTracepath()))) {
164 // Set the time range of the trace
165 TmfContext context
= seekLocation(null);
166 LttngEvent event
= getNextEvent(context
);
167 LttngTimestamp startTime
= new LttngTimestamp(event
.getTimestamp());
168 LttngTimestamp endTime
= new LttngTimestamp(currentJniTrace
.getEndTime().getTime());
169 setTimeRange(new TmfTimeRange(startTime
, endTime
));
170 TmfTraceUpdatedSignal signal
= new TmfTraceUpdatedSignal(this, this, getTimeRange());
175 // Set the time range of the trace
176 TmfContext context
= seekLocation(null);
177 LttngEvent event
= getNextEvent(context
);
178 setEndTime(TmfTimestamp
.BIG_BANG
);
179 final long startTime
= event
!= null ? event
.getTimestamp().getValue() : TmfTimestamp
.BIG_BANG
.getValue();
180 fStreamingInterval
= LTTNG_STREAMING_INTERVAL
;
182 final Thread thread
= new Thread("Streaming Monitor for trace " + getName()) { //$NON-NLS-1$
183 LttngTimestamp safeTimestamp
= null;
184 TmfTimeRange timeRange
= null;
186 @SuppressWarnings("unchecked")
189 while (!fExecutor
.isShutdown()) {
190 TmfExperiment
<?
> experiment
= TmfExperiment
.getCurrentExperiment();
191 if (experiment
!= null) {
192 @SuppressWarnings("rawtypes")
193 final TmfEventRequest request
= new TmfEventRequest
<TmfEvent
>(TmfEvent
.class, TmfTimeRange
.ETERNITY
, 0, ExecutionType
.FOREGROUND
) {
195 public void handleCompleted() {
199 synchronized (experiment
) {
200 experiment
.sendRequest(request
);
203 request
.waitForCompletion();
204 } catch (InterruptedException e
) {
211 Thread
.sleep(LTTNG_STREAMING_INTERVAL
);
212 } catch (InterruptedException e
) {
218 private void updateJniTrace() {
219 JniTrace jniTrace
= getCurrentJniTrace();
220 currentJniTrace
.updateTrace();
221 long endTime
= jniTrace
.getEndTime().getTime();
222 LttngTimestamp startTimestamp
= new LttngTimestamp(startTime
);
223 LttngTimestamp endTimestamp
= new LttngTimestamp(endTime
);
224 if (safeTimestamp
!= null && safeTimestamp
.compareTo(getTimeRange().getEndTime(), false) > 0) {
225 timeRange
= new TmfTimeRange(startTimestamp
, safeTimestamp
);
229 safeTimestamp
= endTimestamp
;
230 if (timeRange
!= null) {
231 setTimeRange(timeRange
);
239 * @see org.eclipse.linuxtools.tmf.trace.TmfTrace#getStreamingInterval()
242 public long getStreamingInterval() {
243 return fStreamingInterval
;
247 * Default Constructor.
253 * Path to a <b>directory</b> that contain an LTTng trace.
255 * @exception Exception
256 * (most likely LTTngTraceException or FileNotFoundException)
258 public LTTngTrace(String name
, String path
) throws Exception
{
259 // Call with "wait for completion" true and "skip indexing" false
260 this(name
, path
, null, true, false);
264 * Constructor, with control over the indexing.
270 * Path to a <b>directory</b> that contain an LTTng trace.
271 * @param waitForCompletion
272 * Should we wait for indexign to complete before moving on.
274 * @exception Exception
275 * (most likely LTTngTraceException or FileNotFoundException)
277 public LTTngTrace(String name
, String path
, boolean waitForCompletion
) throws Exception
{
278 // Call with "skip indexing" false
279 this(name
, path
, null, waitForCompletion
, true);
283 * Default constructor, with control over the indexing and possibility to bypass indexation
289 * Path to a <b>directory</b> that contain an LTTng trace.
290 * @param traceLibPath
291 * Path to a <b>directory</b> that contains LTTng trace libraries.
292 * @param waitForCompletion
293 * Should we wait for indexign to complete before moving on.
294 * @param bypassIndexing
295 * Should we bypass indexing completly? This is should only be useful for unit testing.
297 * @exception Exception
298 * (most likely LTTngTraceException or FileNotFoundException)
301 public LTTngTrace(String name
, String path
, String traceLibPath
, boolean waitForCompletion
, boolean bypassIndexing
)
303 super(name
, LttngEvent
.class, path
, CHECKPOINT_PAGE_SIZE
, false);
304 initTrace(name
, path
, LttngEvent
.class);
307 this.traceLibPath
= traceLibPath
;
311 * Copy constructor is forbidden for LttngEvenmStream
313 public LTTngTrace(LTTngTrace other
) throws Exception
{
314 this(other
.getName(), other
.getPath(), other
.getTraceLibPath(), false, true);
315 this.fCheckpoints
= other
.fCheckpoints
;
316 setTimeRange(new TmfTimeRange(new LttngTimestamp(other
.getStartTime()), new LttngTimestamp(other
.getEndTime())));
320 public synchronized LTTngTrace
clone() {
321 LTTngTrace clone
= null;
323 clone
= (LTTngTrace
) super.clone();
325 clone
.currentJniTrace
= JniTraceFactory
.getJniTrace(getPath(), getTraceLibPath(),
326 SHOW_LTT_DEBUG_DEFAULT
);
327 } catch (JniException e
) {
328 // e.printStackTrace();
331 // Export all the event types from the JNI side
332 clone
.traceTypes
= new HashMap
<Integer
, LttngEventType
>();
333 clone
.traceTypeNames
= new Vector
<Integer
>();
334 clone
.initialiseEventTypes(clone
.currentJniTrace
);
336 // Verify that all those "default constructor" are safe to use
337 clone
.eventTimestamp
= new LttngTimestamp();
338 clone
.eventSource
= ""; //$NON-NLS-1$
339 clone
.eventType
= new LttngEventType();
340 clone
.eventContent
= new LttngEventContent(clone
.currentLttngEvent
);
341 clone
.eventReference
= getName();
343 // Create the skeleton event
344 clone
.currentLttngEvent
= new LttngEvent(this, clone
.eventTimestamp
, clone
.eventSource
, clone
.eventType
,
345 clone
.eventContent
, clone
.eventReference
, null);
347 // Create a new current location
348 clone
.previousLocation
= new LttngLocation();
350 // Set the currentEvent to the eventContent
351 clone
.eventContent
.setEvent(clone
.currentLttngEvent
);
353 // Set the start time of the trace
354 setTimeRange(new TmfTimeRange(new LttngTimestamp(clone
.currentJniTrace
.getStartTime().getTime()),
355 new LttngTimestamp(clone
.currentJniTrace
.getEndTime().getTime())));
356 } catch (CloneNotSupportedException e
) {
362 public String
getTraceLibPath() {
367 * Fill out the HashMap with "Type" (Tracefile/Marker)
369 * This should be called at construction once the trace is open
371 private void initialiseEventTypes(JniTrace trace
) {
373 LttngEventType tmpType
= null;
374 String
[] markerFieldsLabels
= null;
376 String newTracefileKey
= null;
377 Integer newMarkerKey
= null;
379 JniTracefile newTracefile
= null;
380 JniMarker newMarker
= null;
382 // First, obtain an iterator on TRACEFILES of owned by the TRACE
383 Iterator
<String
> tracefileItr
= trace
.getTracefilesMap().keySet().iterator();
385 while (tracefileItr
.hasNext()) {
386 newTracefileKey
= tracefileItr
.next();
387 newTracefile
= trace
.getTracefilesMap().get(newTracefileKey
);
389 // From the TRACEFILE read, obtain its MARKER
390 Iterator
<Integer
> markerItr
= newTracefile
.getTracefileMarkersMap().keySet().iterator();
391 while (markerItr
.hasNext()) {
392 newMarkerKey
= markerItr
.next();
393 newMarker
= newTracefile
.getTracefileMarkersMap().get(newMarkerKey
);
395 // From the MARKER we can obtain the MARKERFIELDS keys (i.e.
397 markerFieldsLabels
= newMarker
.getMarkerFieldsHashMap().keySet()
398 .toArray(new String
[newMarker
.getMarkerFieldsHashMap().size()]);
400 tmpType
= new LttngEventType(newTracefile
.getTracefileName(), newTracefile
.getCpuNumber(),
401 newMarker
.getName(), newMarkerKey
.intValue(), markerFieldsLabels
);
403 // Add the type to the map/vector
404 addEventTypeToMap(tmpType
);
410 * Add a new type to the HashMap
412 * As the hashmap use a key format that is a bit dangerous to use, we should always add using this function.
414 private void addEventTypeToMap(LttngEventType newEventType
) {
415 int newTypeKey
= EventTypeKey
.getEventTypeHash(newEventType
);
417 this.traceTypes
.put(newTypeKey
, newEventType
);
418 this.traceTypeNames
.add(newTypeKey
);
422 * Return the latest saved location. Note : Modifying the returned location may result in buggy positionning!
424 * @return The LttngLocation as it was after the last operation.
426 * @see org.eclipse.linuxtools.internal.lttng.core.event.LttngLocation
429 public synchronized ITmfLocation
<?
> getCurrentLocation() {
430 return previousLocation
;
434 * Position the trace to the event at the given location.
436 * NOTE : Seeking by location is very fast compare to seeking by position but is still slower than "ReadNext", avoid
437 * using it for small interval.
440 * Location of the event in the trace. If no event available at this exact location, we will position
441 * ourself to the next one.
443 * @return The TmfContext that point to this event
445 * @see org.eclipse.linuxtools.internal.lttng.core.event.LttngLocation
446 * @see org.eclipse.linuxtools.tmf.core.trace.TmfContext
449 public synchronized TmfContext
seekLocation(ITmfLocation
<?
> location
) {
455 System
.out
.println("seekLocation(location) location -> " + location
); //$NON-NLS-1$
458 // If the location in context is null, create a new one
459 LttngLocation curLocation
= null;
460 if (location
== null) {
461 curLocation
= new LttngLocation();
462 TmfContext context
= seekEvent(curLocation
.getOperationTime());
463 context
.setRank(ITmfContext
.INITIAL_RANK
);
466 curLocation
= (LttngLocation
) location
;
470 // Update to location should (and will) be done in SeekEvent.
472 // The only seek valid in LTTng is with the time, we call
473 // seekEvent(timestamp)
474 TmfContext context
= seekEvent(curLocation
.getOperationTime());
476 // If the location is marked with the read next flag
477 // then it is pointing to the next event following the operation time
478 if (curLocation
.isLastOperationReadNext()) {
479 getNextEvent(context
);
486 * Position the trace to the event at the given time.
488 * NOTE : Seeking by time is very fast compare to seeking by position but is still slower than "ReadNext", avoid
489 * using it for small interval.
492 * Time of the event in the trace. If no event available at this exact time, we will position ourself to
495 * @return The TmfContext that point to this event
497 * @see org.eclipse.linuxtools.internal.lttng.core.event.LttngLocation
498 * @see org.eclipse.linuxtools.tmf.core.trace.TmfContext
501 public synchronized TmfContext
seekEvent(ITmfTimestamp timestamp
) {
504 System
.out
.println("seekEvent(timestamp) timestamp -> " + timestamp
); //$NON-NLS-1$
508 currentJniTrace
.seekToTime(new JniTime(timestamp
.getValue()));
510 // Save the time at which we seeked
511 previousLocation
.setOperationTime(timestamp
.getValue());
512 // Set the operation marker as seek, to be able to detect we did "seek"
514 previousLocation
.setLastOperationSeek();
516 LttngLocation curLocation
= new LttngLocation(previousLocation
);
518 return new TmfContext(curLocation
);
522 * Position the trace to the event at the given position (rank).
524 * NOTE : Seeking by position is very slow in LTTng, consider seeking by timestamp.
527 * Position (or rank) of the event in the trace, starting at 0.
529 * @return The TmfContext that point to this event
531 * @see org.eclipse.linuxtools.internal.lttng.core.event.LttngLocation
532 * @see org.eclipse.linuxtools.tmf.core.trace.TmfContext
535 public synchronized TmfContext
seekEvent(long position
) {
538 System
.out
.println("seekEvent(position) position -> " + position
); //$NON-NLS-1$
541 ITmfTimestamp timestamp
= null;
542 long index
= position
/ getIndexPageSize();
544 // Get the timestamp of the closest check point to the given position
545 if (fCheckpoints
.size() > 0) {
546 if (index
>= fCheckpoints
.size()) {
547 index
= fCheckpoints
.size() - 1;
549 timestamp
= fCheckpoints
.elementAt((int) index
).getTimestamp();
551 // If none, take the start time of the trace
553 timestamp
= getStartTime();
556 // Seek to the found time
557 TmfContext tmpContext
= seekEvent(timestamp
);
558 tmpContext
.setRank((index
+ 1) * fIndexPageSize
);
559 previousLocation
= (LttngLocation
) tmpContext
.getLocation();
561 // Ajust the index of the event we found at this check point position
562 Long currentPosition
= index
* getIndexPageSize();
564 Long lastTimeValueRead
= 0L;
566 // Get the event at current position. This won't move to the next one
567 JniEvent tmpJniEvent
= currentJniTrace
.findNextEvent();
568 // Now that we are positionned at the checkpoint,
569 // we need to "readNext" (Position - CheckpointPosition) times or until
571 while ((tmpJniEvent
!= null) && (currentPosition
< position
)) {
572 tmpJniEvent
= currentJniTrace
.readNextEvent();
576 // If we found our event, save its timestamp
577 if (tmpJniEvent
!= null) {
578 lastTimeValueRead
= tmpJniEvent
.getEventTime().getTime();
581 // Set the operation marker as seek, to be able to detect we did "seek"
583 previousLocation
.setLastOperationSeek();
584 // Save read event time
585 previousLocation
.setOperationTime(lastTimeValueRead
);
588 // Is that too paranoid?
590 // We don't trust what upper level could do with our internal location
591 // so we create a new one to return instead
592 LttngLocation curLocation
= new LttngLocation(previousLocation
);
594 return new TmfContext(curLocation
);
598 public TmfContext
seekLocation(double ratio
) {
599 // TODO Auto-generated method stub
604 public double getLocationRatio(ITmfLocation
<?
> location
) {
605 // TODO Auto-generated method stub
610 * Return the event in the trace according to the given context. Read it if necessary.
612 * Similar (same?) as ParseEvent except that calling GetNext twice read the next one the second time.
615 * Current TmfContext where to get the event
617 * @return The LttngEvent we read of null if no event are available
619 * @see org.eclipse.linuxtools.internal.lttng.core.event.LttngLocation
620 * @see org.eclipse.linuxtools.tmf.core.trace.TmfContext
623 public int nbEventsRead
= 0;
626 public synchronized LttngEvent
getNextEvent(ITmfContext context
) {
629 System
.out
.println("getNextEvent(context) context.getLocation() -> " //$NON-NLS-1$
630 + context
.getLocation());
633 LttngEvent returnedEvent
= null;
634 LttngLocation curLocation
= null;
636 curLocation
= (LttngLocation
) context
.getLocation();
637 // If the location in context is null, create a new one
638 if (curLocation
== null) {
639 curLocation
= getCurrentLocation(context
);
642 // *** Positioning trick :
643 // GetNextEvent only read the trace if :
644 // 1- The last operation was NOT a ParseEvent --> A read is required
646 // 2- The time of the previous location is different from the current
647 // one --> A seek + a read is required
648 if ((!(curLocation
.isLastOperationParse()))
649 || (previousLocation
.getOperationTimeValue() != curLocation
.getOperationTimeValue())) {
650 if (previousLocation
.getOperationTimeValue() != curLocation
.getOperationTimeValue()) {
652 System
.out
.println("\t\tSeeking in getNextEvent. [ LastTime : " //$NON-NLS-1$
653 + previousLocation
.getOperationTimeValue() + " CurrentTime" //$NON-NLS-1$
654 + curLocation
.getOperationTimeValue() + " ]"); //$NON-NLS-1$
656 seekEvent(curLocation
.getOperationTime());
658 // Read the next event from the trace. The last one will NO LONGER
660 returnedEvent
= readNextEvent(curLocation
);
663 // No event was read, just return the one currently loaded (the last
665 returnedEvent
= currentLttngEvent
;
667 // Set the operation marker as read to both locations, to be able to
668 // detect we need to read the next event
669 previousLocation
.setLastOperationReadNext();
670 curLocation
.setLastOperationReadNext();
673 // If we read an event, set it's time to the locations (both previous
675 if (returnedEvent
!= null) {
676 setPreviousAndCurrentTimes(context
, returnedEvent
, curLocation
);
679 return returnedEvent
;
682 // this method was extracted for profiling purposes
683 private synchronized void setPreviousAndCurrentTimes(ITmfContext context
, LttngEvent returnedEvent
, LttngLocation curLocation
) {
685 ITmfTimestamp eventTimestamp
= returnedEvent
.getTimestamp();
686 // long eventTime = eventTimestamp.getValue();
687 previousLocation
.setOperationTime(eventTimestamp
.getValue());
688 curLocation
.setOperationTime(eventTimestamp
.getValue());
689 updateIndex(context
, context
.getRank(), eventTimestamp
);
690 context
.updateRank(1);
693 protected void updateIndex(TmfContext context
, long rank
, ITmfTimestamp timestamp
) {
695 if (getStartTime().compareTo(timestamp
, false) > 0)
696 setStartTime(timestamp
);
697 if (getEndTime().compareTo(timestamp
, false) < 0)
698 setEndTime(timestamp
);
699 if (rank
!= ITmfContext
.UNKNOWN_RANK
) {
700 if (fNbEvents
<= rank
)
701 fNbEvents
= rank
+ 1;
702 // Build the index as we go along
703 if ((rank
% fIndexPageSize
) == 0) {
704 // Determine the table position
705 long position
= rank
/ fIndexPageSize
;
706 // Add new entry at proper location (if empty)
707 if (fCheckpoints
.size() == position
) {
708 addCheckPoint(context
, timestamp
);
714 private void addCheckPoint(TmfContext context
, ITmfTimestamp timestamp
) {
715 ITmfLocation
<?
> location
= context
.getLocation().clone();
716 fCheckpoints
.add(new TmfCheckpoint(timestamp
.clone(), location
));
719 // this method was extracted for profiling purposes
720 private synchronized LttngEvent
readNextEvent(LttngLocation curLocation
) {
721 LttngEvent returnedEvent
;
722 // Read the next event from the trace. The last one will NO LONGER BE
724 returnedEvent
= readEvent(curLocation
);
727 // Set the operation marker as read to both locations, to be able to
728 // detect we need to read the next event
729 previousLocation
.setLastOperationReadNext();
730 curLocation
.setLastOperationReadNext();
731 return returnedEvent
;
734 // this method was extracted for profiling purposes
735 private LttngLocation
getCurrentLocation(ITmfContext context
) {
736 LttngLocation curLocation
;
737 curLocation
= new LttngLocation();
738 context
.setLocation(curLocation
);
743 * Return the event in the trace according to the given context. Read it if necessary.
745 * Similar (same?) as GetNextEvent except that calling ParseEvent twice will return the same event
748 * Current TmfContext where to get the event
750 * @return The LttngEvent we read of null if no event are available
752 * @see org.eclipse.linuxtools.internal.lttng.core.event.LttngLocation
753 * @see org.eclipse.linuxtools.tmf.core.trace.TmfContext
756 public synchronized LttngEvent
parseEvent(ITmfContext context
) {
759 System
.out
.println("parseEvent(context) context.getLocation() -> " //$NON-NLS-1$
760 + context
.getLocation());
763 LttngEvent returnedEvent
= null;
764 LttngLocation curLocation
= null;
766 // If the location in context is null, create a new one
767 if (context
.getLocation() == null) {
768 curLocation
= new LttngLocation();
769 context
.setLocation(curLocation
);
771 // Otherwise, we use the one in context; it should be a valid
774 curLocation
= (LttngLocation
) context
.getLocation();
778 // TMF assumes it is possible to read (GetNextEvent) to the next Event
779 // once ParseEvent() is called
780 // In LTTNG, there is not difference between "Parsing" and "Reading" an
782 // So, before "Parsing" an event, we have to make sure we didn't "Read"
784 // Also, "Reading" invalidate the previous Event in LTTNG and seek back
786 // so calling twice "Parse" will return the same event, giving a way to
787 // get the "Currently loaded" event
789 // *** Positionning trick :
790 // ParseEvent only read the trace if :
791 // 1- The last operation was NOT a ParseEvent --> A read is required
793 // 2- The time of the previous location is different from the current
794 // one --> A seek + a read is required
795 if (!curLocation
.isLastOperationParse()
796 || (previousLocation
.getOperationTimeValue() != curLocation
.getOperationTimeValue())) {
797 // Previous time != Current time : We need to reposition to the
799 if (previousLocation
.getOperationTimeValue() != curLocation
.getOperationTimeValue()) {
801 System
.out
.println("\t\tSeeking in getNextEvent. [ LastTime : " //$NON-NLS-1$
802 + previousLocation
.getOperationTimeValue() + " CurrentTime" //$NON-NLS-1$
803 + curLocation
.getOperationTimeValue() + " ]"); //$NON-NLS-1$
805 seekEvent(curLocation
.getOperationTime());
808 // Read the next event from the trace. The last one will NO LONGER
810 returnedEvent
= readEvent(curLocation
);
812 // No event was read, just return the one currently loaded (the last
814 returnedEvent
= currentLttngEvent
;
817 // If we read an event, set it's time to the locations (both previous
819 if (returnedEvent
!= null) {
820 previousLocation
.setOperationTime((LttngTimestamp
) returnedEvent
.getTimestamp());
821 curLocation
.setOperationTime((LttngTimestamp
) returnedEvent
.getTimestamp());
824 // Set the operation marker as parse to both location, to be able to
825 // detect we already "read" this event
826 previousLocation
.setLastOperationParse();
827 curLocation
.setLastOperationParse();
829 return returnedEvent
;
833 * Read the next event from the JNI and convert it as Lttng Event<p>
835 * @param location Current LttngLocation that to be updated with the event timestamp
837 * @return The LttngEvent we read of null if no event are available
839 * @see org.eclipse.linuxtools.lttng.event.LttngLocation
841 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniTrace
843 private synchronized LttngEvent
readEvent(LttngLocation location
) {
844 LttngEvent returnedEvent
= null;
845 JniEvent tmpEvent
= null;
847 // Read the next event from JNI. THIS WILL INVALIDATE THE CURRENT LTTNG
849 tmpEvent
= currentJniTrace
.readNextEvent();
851 if (tmpEvent
!= null) {
853 // Convert will update the currentLttngEvent
854 returnedEvent
= convertJniEventToTmf(tmpEvent
);
856 location
.setOperationTime((LttngTimestamp
) returnedEvent
.getTimestamp());
859 // If the read failed (likely the last event in the trace), set the
860 // LastReadTime to the JNI time
861 // That way, even if we try to read again, we will step over the bogus
864 location
.setOperationTime(getEndTime().getValue() + 1);
867 return returnedEvent
;
871 * Method to convert a JniEvent into a LttngEvent.
874 * Note : This method will call LttngEvent convertEventJniToTmf(JniEvent, boolean) with a default value for
878 * The JniEvent to convert into LttngEvent
880 * @return The converted LttngEvent
882 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniEvent
883 * @see org.eclipse.linuxtools.internal.lttng.core.event.LttngEvent
885 public synchronized LttngEvent
convertJniEventToTmf(JniEvent newEvent
) {
886 currentLttngEvent
= convertJniEventToTmf(newEvent
, IS_PARSING_NEEDED_DEFAULT
);
888 return currentLttngEvent
;
892 * Method to convert a JniEvent into a LttngEvent
895 * The JniEvent to convert into LttngEvent
896 * @param isParsingNeeded
897 * A boolean value telling if the event should be parsed or not.
899 * @return The converted LttngEvent
901 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniEvent
902 * @see org.eclipse.linuxtools.internal.lttng.core.event.LttngEvent
904 public synchronized LttngEvent
convertJniEventToTmf(JniEvent jniEvent
, boolean isParsingNeeded
) {
909 // UNHACKED : We can no longer do that because TCF need to maintain
910 // several events at once.
911 // This is very slow to do so in LTTng, this has to be temporary.
913 // To save time here, we only set value instead of allocating new
915 // This give an HUGE performance improvement
916 // all allocation done in the LttngTrace constructor
918 eventTimestamp
.setValue(jniEvent
.getEventTime().getTime());
919 eventSource
= jniEvent
.requestEventSource();
921 eventType
= traceTypes
.get(EventTypeKey
.getEventTypeHash(jniEvent
));
923 String fullTracePath
= getName();
924 String reference
= fullTracePath
.substring(fullTracePath
.lastIndexOf('/') + 1);
925 currentLttngEvent
.setReference(reference
);
927 eventContent
.emptyContent();
929 currentLttngEvent
.setType(eventType
);
930 // Save the jni reference
931 currentLttngEvent
.updateJniEventReference(jniEvent
);
933 // Parse now if was asked
934 // Warning : THIS IS SLOW
935 if (isParsingNeeded
) {
936 eventContent
.getFields();
939 return currentLttngEvent
;
941 return convertJniEventToTmfMultipleEventEvilFix(jniEvent
, isParsingNeeded
);
947 * This method is a temporary fix to support multiple events at once in TMF This is expected to be slow and should
948 * be fixed in another way. See comment in convertJniEventToTmf();
951 * The current JNI Event
952 * @return Current Lttng Event fully parsed
954 private synchronized LttngEvent
convertJniEventToTmfMultipleEventEvilFix(JniEvent jniEvent
, boolean isParsingNeeded
) {
956 // Below : the "fix" with all the new and the full-parse
957 // Allocating new memory is slow.
958 // Parsing every events is very slow.
959 eventTimestamp
= new LttngTimestamp(jniEvent
.getEventTime().getTime());
960 eventSource
= jniEvent
.requestEventSource();
961 eventReference
= getName();
962 eventType
= new LttngEventType(traceTypes
.get(EventTypeKey
.getEventTypeHash(jniEvent
)));
963 eventContent
= new LttngEventContent(currentLttngEvent
);
964 currentLttngEvent
= new LttngEvent(this, eventTimestamp
, eventSource
, eventType
, eventContent
, eventReference
,
967 // The jni reference is no longer reliable but we will keep it anyhow
968 currentLttngEvent
.updateJniEventReference(jniEvent
);
969 // Ensure that the content is correctly set
970 eventContent
.setEvent(currentLttngEvent
);
972 // Parse the event if it was needed
974 // ONLY for testing, NOT parsing events with non-unique events WILL
975 // result in segfault in the JVM
976 if (isParsingNeeded
) {
977 eventContent
.getFields();
980 return currentLttngEvent
;
984 * Reference to the current LttngTrace we are reading from.
987 * Note : This bypass the framework and should not be use, except for testing!
989 * @return Reference to the current LttngTrace
991 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniTrace
993 public JniTrace
getCurrentJniTrace() {
994 return currentJniTrace
;
998 * Return a reference to the current LttngEvent we have in memory.
1000 * @return The current (last read) LttngEvent
1002 * @see org.eclipse.linuxtools.internal.lttng.core.event.LttngEvent
1004 public synchronized LttngEvent
getCurrentEvent() {
1005 return currentLttngEvent
;
1009 * Get the major version number for the current trace
1011 * @return Version major or -1 if unknown
1013 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniTrace
1016 public short getVersionMajor() {
1017 if (currentJniTrace
!= null) {
1018 return currentJniTrace
.getLttMajorVersion();
1025 * Get the minor version number for the current trace
1027 * @return Version minor or -1 if unknown
1029 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniTrace
1032 public short getVersionMinor() {
1033 if (currentJniTrace
!= null) {
1034 return currentJniTrace
.getLttMinorVersion();
1041 * Get the number of CPU for this trace
1043 * @return Number of CPU or -1 if unknown
1045 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniTrace
1048 public int getCpuNumber() {
1049 if (currentJniTrace
!= null) {
1050 return currentJniTrace
.getCpuNumber();
1057 * Print the content of the checkpoint vector.
1060 * This is intended for debug purpose only.
1062 public void printCheckpointsVector() {
1063 System
.out
.println("StartTime : " //$NON-NLS-1$
1064 + getTimeRange().getStartTime().getValue());
1065 System
.out
.println("EndTime : " //$NON-NLS-1$
1066 + getTimeRange().getEndTime().getValue());
1068 for (int pos
= 0; pos
< fCheckpoints
.size(); pos
++) {
1069 System
.out
.print(pos
+ ": " + "\t"); //$NON-NLS-1$ //$NON-NLS-2$
1070 System
.out
.print(fCheckpoints
.get(pos
).getTimestamp() + "\t"); //$NON-NLS-1$
1071 System
.out
.println(fCheckpoints
.get(pos
).getLocation());
1076 public synchronized void dispose() {
1077 if (currentJniTrace
!= null)
1078 currentJniTrace
.closeTrace();
1083 * Return a String identifying this trace.
1085 * @return String that identify this trace
1088 @SuppressWarnings("nls")
1089 public String
toString() {
1090 String returnedData
= "";
1092 returnedData
+= "Path :" + getPath() + " ";
1093 returnedData
+= "Trace:" + currentJniTrace
+ " ";
1094 returnedData
+= "Event:" + currentLttngEvent
;
1096 return returnedData
;
1102 * EventTypeKey inner class
1104 * This class is used to make the process of generating the HashMap key more transparent and so less error prone to use
1106 final class EventTypeKey
{
1108 // These two getEventTypeKey() functions should ALWAYS construct the key the
1110 // Otherwise, every type search will fail!
1112 // added final to encourage inlining.
1114 // generating a hash code by hand to avoid a string creation
1115 final static public int getEventTypeHash(LttngEventType newEventType
) {
1116 return generateHash(newEventType
.getTracefileName(), newEventType
.getCpuId(), newEventType
.getMarkerName());
1119 final private static int generateHash(String traceFileName
, long cpuNumber
, String markerName
) {
1120 // 0x1337 is a prime number. The number of CPUs is always under 8192 on
1121 // the current kernel, so this will work with the current linux kernel.
1122 int cpuHash
= (int) (cpuNumber
* (0x1337));
1123 return traceFileName
.hashCode() ^
(cpuHash
) ^ markerName
.hashCode();
1126 // generating a hash code by hand to avoid a string creation
1127 final static public int getEventTypeHash(JniEvent newEvent
) {
1128 return generateHash(newEvent
.getParentTracefile().getTracefileName(), newEvent
.getParentTracefile()
1129 .getCpuNumber(), newEvent
.requestEventMarker().getName());