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
.util
.HashMap
;
17 import java
.util
.Iterator
;
18 import java
.util
.Vector
;
20 import org
.eclipse
.core
.resources
.IProject
;
21 import org
.eclipse
.core
.resources
.IResource
;
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
.lttng
.jni
.JniEvent
;
32 import org
.eclipse
.linuxtools
.lttng
.jni
.JniMarker
;
33 import org
.eclipse
.linuxtools
.lttng
.jni
.JniTrace
;
34 import org
.eclipse
.linuxtools
.lttng
.jni
.JniTracefile
;
35 import org
.eclipse
.linuxtools
.lttng
.jni
.factory
.JniTraceFactory
;
36 import org
.eclipse
.linuxtools
.tmf
.core
.event
.ITmfTimestamp
;
37 import org
.eclipse
.linuxtools
.tmf
.core
.event
.TmfEvent
;
38 import org
.eclipse
.linuxtools
.tmf
.core
.event
.TmfTimeRange
;
39 import org
.eclipse
.linuxtools
.tmf
.core
.event
.TmfTimestamp
;
40 import org
.eclipse
.linuxtools
.tmf
.core
.exceptions
.TmfTraceException
;
41 import org
.eclipse
.linuxtools
.tmf
.core
.request
.ITmfDataRequest
.ExecutionType
;
42 import org
.eclipse
.linuxtools
.tmf
.core
.request
.TmfEventRequest
;
43 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTraceUpdatedSignal
;
44 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.ITmfContext
;
45 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.ITmfEventParser
;
46 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.ITmfLocation
;
47 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.TmfCheckpointIndexer
;
48 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.TmfContext
;
49 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.TmfExperiment
;
50 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.TmfTrace
;
52 class LTTngTraceException
extends LttngException
{
54 static final long serialVersionUID
= -1636648737081868146L;
56 public LTTngTraceException(final String errMsg
) {
62 * <b><u>LTTngTrace</u></b>
65 * LTTng trace implementation. It accesses the C trace handling library
66 * (seeking, reading and parsing) through the JNI component.
68 public class LTTngTrace
extends TmfTrace
<LttngEvent
> implements ITmfEventParser
<LttngEvent
> {
70 public final static boolean PRINT_DEBUG
= false;
71 public final static boolean UNIQUE_EVENT
= true;
73 private final static boolean SHOW_LTT_DEBUG_DEFAULT
= false;
74 private final static boolean IS_PARSING_NEEDED_DEFAULT
= !UNIQUE_EVENT
;
75 private final static int CHECKPOINT_PAGE_SIZE
= 50000;
76 private final static long LTTNG_STREAMING_INTERVAL
= 2000; // in ms
78 // Reference to our JNI trace
79 private JniTrace currentJniTrace
;
81 LttngTimestamp eventTimestamp
;
83 LttngEventContent eventContent
;
84 String eventReference
;
87 LttngEvent currentLttngEvent
;
89 // The current location
90 LttngLocation previousLocation
;
92 LttngEventType eventType
;
94 // Hashmap of the possible types of events (Tracefile/CPU/Marker in the JNI)
95 HashMap
<Integer
, LttngEventType
> traceTypes
;
97 // This vector will be used to quickly find a marker name from a position
98 Vector
<Integer
> traceTypeNames
;
100 private String traceLibPath
;
102 public LTTngTrace() {
106 public boolean validate(final IProject project
, final String path
) {
107 if (fileExists(path
)) {
108 final String traceLibPath
= TraceHelper
.getTraceLibDirFromProject(project
);
110 final LTTngTraceVersion version
= new LTTngTraceVersion(path
, traceLibPath
);
111 return version
.isValidLttngTrace();
112 } catch (final LttngException e
) {
118 @SuppressWarnings({ "unchecked", "rawtypes" })
120 public synchronized void initTrace(final IResource resource
, final String path
, final Class
<LttngEvent
> eventType
)
121 throws TmfTraceException
{
122 super.initialize(resource
, path
, eventType
);
123 setIndexer(new TmfCheckpointIndexer(this, getCacheSize()));
124 initialize(resource
, path
, eventType
);
128 protected synchronized void initialize(final IResource resource
, final String path
, final Class
<LttngEvent
> eventType
)
129 throws TmfTraceException
{
131 if (resource
!= null) {
132 IProject project
= resource
.getProject();
133 traceLibPath
= (project
!= null) ? TraceHelper
.getTraceLibDirFromProject(project
) : null;
135 currentJniTrace
= JniTraceFactory
.getJniTrace(path
, traceLibPath
, SHOW_LTT_DEBUG_DEFAULT
);
136 } catch (final Exception e
) {
137 throw new TmfTraceException(e
.getMessage());
140 // Export all the event types from the JNI side
141 traceTypes
= new HashMap
<Integer
, LttngEventType
>();
142 traceTypeNames
= new Vector
<Integer
>();
143 initialiseEventTypes(currentJniTrace
);
145 // Build the re-used event structure
146 eventTimestamp
= new LttngTimestamp();
147 eventSource
= ""; //$NON-NLS-1$
148 this.eventType
= new LttngEventType();
149 eventContent
= new LttngEventContent(currentLttngEvent
);
150 eventReference
= getName();
152 // Create the skeleton event
153 currentLttngEvent
= new LttngEvent(this, eventTimestamp
, eventSource
, this.eventType
, eventContent
,
154 eventReference
, null);
156 // Create a new current location
157 previousLocation
= new LttngLocation();
159 // Set the currentEvent to the eventContent
160 eventContent
.setEvent(currentLttngEvent
);
162 setParser((ITmfEventParser
<LttngEvent
>) this);
163 setCacheSize(CHECKPOINT_PAGE_SIZE
);
165 initializeStreamingMonitor();
168 private void initializeStreamingMonitor() {
169 final JniTrace jniTrace
= getCurrentJniTrace();
171 || (!jniTrace
.isLiveTraceSupported() || !LiveTraceManager
.isLiveTrace(jniTrace
.getTracepath()))) {
172 // Set the time range of the trace
173 final ITmfContext context
= seekEvent(0);
174 final LttngEvent event
= getNext(context
);
175 final LttngTimestamp startTime
= new LttngTimestamp(event
.getTimestamp());
176 final LttngTimestamp endTime
= new LttngTimestamp(currentJniTrace
.getEndTime().getTime());
177 setTimeRange(new TmfTimeRange(startTime
, endTime
));
178 final TmfTraceUpdatedSignal signal
= new TmfTraceUpdatedSignal(this, this, getTimeRange());
183 // Set the time range of the trace
184 final ITmfContext context
= seekEvent(0);
185 final LttngEvent event
= getNext(context
);
186 setEndTime(TmfTimestamp
.BIG_BANG
);
187 final long startTime
= event
!= null ? event
.getTimestamp().getValue() : TmfTimestamp
.BIG_BANG
.getValue();
188 setStreamingInterval(LTTNG_STREAMING_INTERVAL
);
190 final Thread thread
= new Thread("Streaming Monitor for trace " + getName()) { //$NON-NLS-1$
192 LttngTimestamp safeTimestamp
= null;
193 TmfTimeRange timeRange
= null;
195 @SuppressWarnings({ "unchecked", "restriction" })
198 while (!fExecutor
.isShutdown()) {
199 final TmfExperiment
<?
> experiment
= TmfExperiment
.getCurrentExperiment();
200 if (experiment
!= null) {
201 @SuppressWarnings("rawtypes")
202 final TmfEventRequest request
= new TmfEventRequest
<TmfEvent
>(TmfEvent
.class,
203 TmfTimeRange
.ETERNITY
, 0, ExecutionType
.FOREGROUND
) {
206 public void handleCompleted() {
210 experiment
.sendRequest(request
);
212 request
.waitForCompletion();
213 } catch (final InterruptedException e
) {
218 Thread
.sleep(LTTNG_STREAMING_INTERVAL
);
219 } catch (final InterruptedException e
) {
224 private void updateJniTrace() {
225 final JniTrace jniTrace
= getCurrentJniTrace();
226 currentJniTrace
.updateTrace();
227 final long endTime
= jniTrace
.getEndTime().getTime();
228 final LttngTimestamp startTimestamp
= new LttngTimestamp(startTime
);
229 final LttngTimestamp endTimestamp
= new LttngTimestamp(endTime
);
230 if (safeTimestamp
!= null && safeTimestamp
.compareTo(getTimeRange().getEndTime(), false) > 0)
231 timeRange
= new TmfTimeRange(startTimestamp
, safeTimestamp
);
234 safeTimestamp
= endTimestamp
;
235 if (timeRange
!= null)
236 setTimeRange(timeRange
);
243 * Default Constructor.
246 * @param name Name of the trace
247 * @param path Path to a <b>directory</b> that contain an LTTng trace.
249 * @exception Exception (most likely LTTngTraceException or
250 * FileNotFoundException)
252 public LTTngTrace(final IResource resource
, final String path
) throws Exception
{
253 // Call with "wait for completion" true and "skip indexing" false
254 this(resource
, path
, null, true, false);
258 * Constructor, with control over the indexing.
261 * @param name Name of the trace
262 * @param path Path to a <b>directory</b> that contain an LTTng trace.
263 * @param waitForCompletion Should we wait for indexign to complete before
266 * @exception Exception (most likely LTTngTraceException or
267 * FileNotFoundException)
269 public LTTngTrace(final IResource resource
, final String path
, final boolean waitForCompletion
) throws Exception
{
270 // Call with "skip indexing" false
271 this(resource
, path
, null, waitForCompletion
, true);
275 * Default constructor, with control over the indexing and possibility to
279 * @param name Name of the trace
280 * @param path Path to a <b>directory</b> that contain an LTTng trace.
281 * @param traceLibPath Path to a <b>directory</b> that contains LTTng trace
283 * @param waitForCompletion Should we wait for indexign to complete before
285 * @param bypassIndexing Should we bypass indexing completly? This is should
286 * only be useful for unit testing.
288 * @exception Exception (most likely LTTngTraceException or
289 * FileNotFoundException)
292 public LTTngTrace(final IResource resource
, final String path
, final String traceLibPath
, final boolean waitForCompletion
,
293 final boolean bypassIndexing
)
295 // super(resource, LttngEvent.class, path, CHECKPOINT_PAGE_SIZE, false);
296 super(resource
, LttngEvent
.class, path
, CHECKPOINT_PAGE_SIZE
);
297 initialize(resource
, path
, LttngEvent
.class);
298 // if (!bypassIndexing)
299 // indexTrace(false);
300 this.traceLibPath
= traceLibPath
;
304 * Copy constructor is forbidden for LttngEvenmStream
306 public LTTngTrace(final LTTngTrace other
) throws Exception
{
307 this(other
.getResource(), other
.getPath(), other
.getTraceLibPath(), false, true);
308 setTimeRange(new TmfTimeRange(new LttngTimestamp(other
.getStartTime()), new LttngTimestamp(other
.getEndTime())));
311 public String
getTraceLibPath() {
316 * Fill out the HashMap with "Type" (Tracefile/Marker)
318 * This should be called at construction once the trace is open
320 private void initialiseEventTypes(final JniTrace trace
) {
322 LttngEventType tmpType
= null;
323 String
[] markerFieldsLabels
= null;
325 String newTracefileKey
= null;
326 Integer newMarkerKey
= null;
328 JniTracefile newTracefile
= null;
329 JniMarker newMarker
= null;
331 // First, obtain an iterator on TRACEFILES of owned by the TRACE
332 final Iterator
<String
> tracefileItr
= trace
.getTracefilesMap().keySet().iterator();
334 while (tracefileItr
.hasNext()) {
335 newTracefileKey
= tracefileItr
.next();
336 newTracefile
= trace
.getTracefilesMap().get(newTracefileKey
);
338 // From the TRACEFILE read, obtain its MARKER
339 final Iterator
<Integer
> markerItr
= newTracefile
.getTracefileMarkersMap().keySet().iterator();
340 while (markerItr
.hasNext()) {
341 newMarkerKey
= markerItr
.next();
342 newMarker
= newTracefile
.getTracefileMarkersMap().get(newMarkerKey
);
344 // From the MARKER we can obtain the MARKERFIELDS keys (i.e.
346 markerFieldsLabels
= newMarker
.getMarkerFieldsHashMap().keySet()
347 .toArray(new String
[newMarker
.getMarkerFieldsHashMap().size()]);
349 tmpType
= new LttngEventType(newTracefile
.getTracefileName(), newTracefile
.getCpuNumber(),
350 newMarker
.getName(), newMarkerKey
.intValue(), markerFieldsLabels
);
352 // Add the type to the map/vector
353 addEventTypeToMap(tmpType
);
359 * Add a new type to the HashMap
361 * As the hashmap use a key format that is a bit dangerous to use, we should
362 * always add using this function.
364 private void addEventTypeToMap(final LttngEventType newEventType
) {
365 final int newTypeKey
= EventTypeKey
.getEventTypeHash(newEventType
);
367 this.traceTypes
.put(newTypeKey
, newEventType
);
368 this.traceTypeNames
.add(newTypeKey
);
372 * Return the latest saved location. Note : Modifying the returned location
373 * may result in buggy positionning!
375 * @return The LttngLocation as it was after the last operation.
377 * @see org.eclipse.linuxtools.internal.lttng.core.event.LttngLocation
380 public synchronized ITmfLocation
<?
> getCurrentLocation() {
381 return previousLocation
;
385 * Position the trace to the event at the given location.
387 * NOTE : Seeking by location is very fast compare to seeking by position
388 * but is still slower than "ReadNext", avoid using it for small interval.
390 * @param location Location of the event in the trace. If no event available
391 * at this exact location, we will position ourself to the next
394 * @return The TmfContext that point to this event
396 * @see org.eclipse.linuxtools.internal.lttng.core.event.LttngLocation
397 * @see org.eclipse.linuxtools.tmf.core.trace.TmfContext
400 public synchronized ITmfContext
seekEvent(final ITmfLocation
<?
> location
) {
403 System
.out
.println("seekLocation(location) location -> " + location
); //$NON-NLS-1$
405 // If the location in context is null, create a new one
406 if (location
== null) {
407 LttngLocation curLocation
= new LttngLocation();
408 final ITmfContext context
= seekEvent(curLocation
.getOperationTime());
413 // The only seek valid in LTTng is with the time, we call
414 // seekEvent(timestamp)
415 LttngLocation curLocation
= (LttngLocation
) location
;
416 final ITmfContext context
= seekEvent(curLocation
.getOperationTime());
418 // If the location is marked with the read next flag
419 // then it is pointing to the next event following the operation time
420 if (curLocation
.isLastOperationReadNext())
427 * Position the trace to the event at the given time.
429 * NOTE : Seeking by time is very fast compare to seeking by position but is
430 * still slower than "ReadNext", avoid using it for small interval.
432 * @param timestamp Time of the event in the trace. If no event available at
433 * this exact time, we will position ourself to the next one.
435 * @return The TmfContext that point to this event
437 * @see org.eclipse.linuxtools.internal.lttng.core.event.LttngLocation
438 * @see org.eclipse.linuxtools.tmf.core.trace.TmfContext
441 public synchronized TmfContext
seekEvent(final ITmfTimestamp timestamp
) {
444 System
.out
.println("seekEvent(timestamp) timestamp -> " + timestamp
); //$NON-NLS-1$
447 currentJniTrace
.seekToTime(new JniTime(timestamp
.getValue()));
449 // Save the time at which we seeked
450 previousLocation
.setOperationTime(timestamp
.getValue());
451 // Set the operation marker as seek, to be able to detect we did "seek"
453 previousLocation
.setLastOperationSeek();
455 final LttngLocation curLocation
= new LttngLocation(previousLocation
);
457 return new TmfContext(curLocation
);
461 * Position the trace to the event at the given position (rank).
463 * NOTE : Seeking by position is very slow in LTTng, consider seeking by
466 * @param rank Position (or rank) of the event in the trace, starting at 0.
468 * @return The TmfContext that point to this event
470 * @see org.eclipse.linuxtools.internal.lttng.core.event.LttngLocation
471 * @see org.eclipse.linuxtools.tmf.core.trace.TmfContext
474 public synchronized TmfContext
seekEvent(final long rank
) {
477 System
.out
.println("seekEvent(rank) rank -> " + rank
); //$NON-NLS-1$
479 // Position the trace at the checkpoint
480 final ITmfContext checkpointContext
= getIndexer().seekIndex(rank
);
481 LttngLocation location
= (LttngLocation
) checkpointContext
.getLocation();
482 ITmfTimestamp timestamp
= location
.getLocation();
483 long index
= rank
/ getCacheSize();
485 // Seek to the found time
486 final TmfContext tmpContext
= seekEvent(timestamp
);
487 tmpContext
.setRank((index
+ 1) * getCacheSize());
488 previousLocation
= (LttngLocation
) tmpContext
.getLocation();
490 // Ajust the index of the event we found at this check point position
491 Long currentPosition
= index
* getCacheSize();
493 Long lastTimeValueRead
= 0L;
495 // Get the event at current position. This won't move to the next one
496 JniEvent tmpJniEvent
= currentJniTrace
.findNextEvent();
497 // Now that we are positionned at the checkpoint,
498 // we need to "readNext" (Position - CheckpointPosition) times or until
500 while ((tmpJniEvent
!= null) && (currentPosition
< rank
)) {
501 tmpJniEvent
= currentJniTrace
.readNextEvent();
505 // If we found our event, save its timestamp
506 if (tmpJniEvent
!= null)
507 lastTimeValueRead
= tmpJniEvent
.getEventTime().getTime();
509 // Set the operation marker as seek, to be able to detect we did "seek"
511 previousLocation
.setLastOperationSeek();
512 // Save read event time
513 previousLocation
.setOperationTime(lastTimeValueRead
);
516 // Is that too paranoid?
518 // We don't trust what upper level could do with our internal location
519 // so we create a new one to return instead
520 final LttngLocation curLocation
= new LttngLocation(previousLocation
);
522 return new TmfContext(curLocation
, rank
);
526 public TmfContext
seekEvent(final double ratio
) {
527 // TODO Auto-generated method stub
532 public double getLocationRatio(final ITmfLocation
<?
> location
) {
533 // TODO Auto-generated method stub
538 * Return the event in the trace according to the given context. Read it if
541 * Similar (same?) as ParseEvent except that calling GetNext twice read the
542 * next one the second time.
544 * @param context Current TmfContext where to get the event
546 * @return The LttngEvent we read of null if no event are available
548 * @see org.eclipse.linuxtools.internal.lttng.core.event.LttngLocation
549 * @see org.eclipse.linuxtools.tmf.core.trace.TmfContext
552 public int nbEventsRead
= 0;
555 public synchronized LttngEvent
getNext(final ITmfContext context
) {
558 System
.out
.println("getNextEvent(context) context.getLocation() -> " //$NON-NLS-1$
559 + context
.getLocation());
561 LttngEvent returnedEvent
= null;
562 LttngLocation curLocation
= null;
564 curLocation
= (LttngLocation
) context
.getLocation();
565 // If the location in context is null, create a new one
566 if (curLocation
== null)
567 curLocation
= getCurrentLocation(context
);
569 // *** Positioning trick :
570 // GetNextEvent only read the trace if :
571 // 1- The last operation was NOT a ParseEvent --> A read is required
573 // 2- The time of the previous location is different from the current
574 // one --> A seek + a read is required
575 if ((!(curLocation
.isLastOperationParse()))
576 || (previousLocation
.getOperationTimeValue() != curLocation
.getOperationTimeValue())) {
577 if (previousLocation
.getOperationTimeValue() != curLocation
.getOperationTimeValue()) {
579 System
.out
.println("\t\tSeeking in getNextEvent. [ LastTime : " //$NON-NLS-1$
580 + previousLocation
.getOperationTimeValue() + " CurrentTime" //$NON-NLS-1$
581 + curLocation
.getOperationTimeValue() + " ]"); //$NON-NLS-1$
582 seekEvent(curLocation
.getOperationTime());
584 // If the location is marked with the read next flag
585 // then it is pointing to the next event following the operation time
586 if (curLocation
.isLastOperationReadNext()) {
587 readNextEvent(curLocation
);
590 // Read the next event from the trace. The last one will NO LONGER
592 returnedEvent
= readNextEvent(curLocation
);
595 // No event was read, just return the one currently loaded (the last
597 returnedEvent
= currentLttngEvent
;
599 // Set the operation marker as read to both locations, to be able to
600 // detect we need to read the next event
601 previousLocation
.setLastOperationReadNext();
602 curLocation
.setLastOperationReadNext();
605 // If we read an event, set it's time to the locations (both previous
607 if (returnedEvent
!= null)
608 setPreviousAndCurrentTimes(context
, returnedEvent
, curLocation
);
610 return returnedEvent
;
613 // this method was extracted for profiling purposes
614 private synchronized void setPreviousAndCurrentTimes(final ITmfContext context
, final LttngEvent returnedEvent
,
615 final LttngLocation curLocation
) {
617 final ITmfTimestamp eventTimestamp
= returnedEvent
.getTimestamp();
618 // long eventTime = eventTimestamp.getValue();
619 previousLocation
.setOperationTime(eventTimestamp
.getValue());
620 curLocation
.setOperationTime(eventTimestamp
.getValue());
621 updateAttributes(context
, eventTimestamp
);
622 context
.increaseRank();
625 // this method was extracted for profiling purposes
626 private synchronized LttngEvent
readNextEvent(final LttngLocation curLocation
) {
627 LttngEvent returnedEvent
;
628 // Read the next event from the trace. The last one will NO LONGER BE
630 returnedEvent
= readEvent(curLocation
);
633 // Set the operation marker as read to both locations, to be able to
634 // detect we need to read the next event
635 previousLocation
.setLastOperationReadNext();
636 curLocation
.setLastOperationReadNext();
637 return returnedEvent
;
640 // this method was extracted for profiling purposes
641 private LttngLocation
getCurrentLocation(final ITmfContext context
) {
642 LttngLocation curLocation
;
643 curLocation
= new LttngLocation();
644 context
.setLocation(curLocation
);
649 * Return the event in the trace according to the given context. Read it if
652 * Similar (same?) as GetNextEvent except that calling ParseEvent twice will
653 * return the same event
655 * @param context Current TmfContext where to get the event
657 * @return The LttngEvent we read of null if no event are available
659 * @see org.eclipse.linuxtools.internal.lttng.core.event.LttngLocation
660 * @see org.eclipse.linuxtools.tmf.core.trace.TmfContext
663 public synchronized LttngEvent
parseEvent(final ITmfContext context
) {
666 System
.out
.println("parseEvent(context) context.getLocation() -> " //$NON-NLS-1$
667 + context
.getLocation());
669 LttngEvent returnedEvent
= null;
670 LttngLocation curLocation
= null;
672 // If the location in context is null, create a new one
673 if (context
.getLocation() == null) {
674 curLocation
= new LttngLocation();
675 context
.setLocation(curLocation
);
677 curLocation
= (LttngLocation
) context
.getLocation();
680 // TMF assumes it is possible to read (GetNextEvent) to the next Event
681 // once ParseEvent() is called
682 // In LTTNG, there is not difference between "Parsing" and "Reading" an
684 // So, before "Parsing" an event, we have to make sure we didn't "Read"
686 // Also, "Reading" invalidate the previous Event in LTTNG and seek back
688 // so calling twice "Parse" will return the same event, giving a way to
689 // get the "Currently loaded" event
691 // *** Positionning trick :
692 // ParseEvent only read the trace if :
693 // 1- The last operation was NOT a ParseEvent --> A read is required
695 // 2- The time of the previous location is different from the current
696 // one --> A seek + a read is required
697 if (!curLocation
.isLastOperationParse()
698 || (previousLocation
.getOperationTimeValue() != curLocation
.getOperationTimeValue())) {
699 // Previous time != Current time : We need to reposition to the
701 if (previousLocation
.getOperationTimeValue() != curLocation
.getOperationTimeValue()) {
703 System
.out
.println("\t\tSeeking in getNextEvent. [ LastTime : " //$NON-NLS-1$
704 + previousLocation
.getOperationTimeValue() + " CurrentTime" //$NON-NLS-1$
705 + curLocation
.getOperationTimeValue() + " ]"); //$NON-NLS-1$
706 seekEvent(curLocation
.getOperationTime());
709 // Read the next event from the trace. The last one will NO LONGER
711 returnedEvent
= readEvent(curLocation
);
713 // No event was read, just return the one currently loaded (the last
715 returnedEvent
= currentLttngEvent
;
717 // If we read an event, set it's time to the locations (both previous
719 if (returnedEvent
!= null) {
720 previousLocation
.setOperationTime((LttngTimestamp
) returnedEvent
.getTimestamp());
721 curLocation
.setOperationTime((LttngTimestamp
) returnedEvent
.getTimestamp());
724 // Set the operation marker as parse to both location, to be able to
725 // detect we already "read" this event
726 previousLocation
.setLastOperationParse();
727 curLocation
.setLastOperationParse();
729 return returnedEvent
;
733 * Read the next event from the JNI and convert it as Lttng Event<p>
735 * @param location Current LttngLocation that to be updated with the event
738 * @return The LttngEvent we read of null if no event are available
740 * @see org.eclipse.linuxtools.lttng.event.LttngLocation
742 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniTrace
744 private synchronized LttngEvent
readEvent(final LttngLocation location
) {
745 LttngEvent returnedEvent
= null;
746 JniEvent tmpEvent
= null;
748 // Read the next event from JNI. THIS WILL INVALIDATE THE CURRENT LTTNG
750 tmpEvent
= currentJniTrace
.readNextEvent();
752 if (tmpEvent
!= null) {
754 // Convert will update the currentLttngEvent
755 returnedEvent
= convertJniEventToTmf(tmpEvent
);
757 location
.setOperationTime((LttngTimestamp
) returnedEvent
.getTimestamp());
759 location
.setOperationTime(getEndTime().getValue() + 1);
761 return returnedEvent
;
765 * Method to convert a JniEvent into a LttngEvent.
768 * Note : This method will call LttngEvent convertEventJniToTmf(JniEvent,
769 * boolean) with a default value for isParsingNeeded
771 * @param newEvent The JniEvent to convert into LttngEvent
773 * @return The converted LttngEvent
775 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniEvent
776 * @see org.eclipse.linuxtools.internal.lttng.core.event.LttngEvent
778 public synchronized LttngEvent
convertJniEventToTmf(final JniEvent newEvent
) {
779 currentLttngEvent
= convertJniEventToTmf(newEvent
, IS_PARSING_NEEDED_DEFAULT
);
781 return currentLttngEvent
;
785 * Method to convert a JniEvent into a LttngEvent
787 * @param jniEvent The JniEvent to convert into LttngEvent
788 * @param isParsingNeeded A boolean value telling if the event should be
791 * @return The converted LttngEvent
793 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniEvent
794 * @see org.eclipse.linuxtools.internal.lttng.core.event.LttngEvent
796 public synchronized LttngEvent
convertJniEventToTmf(final JniEvent jniEvent
, final boolean isParsingNeeded
) {
801 // UNHACKED : We can no longer do that because TCF need to maintain
802 // several events at once.
803 // This is very slow to do so in LTTng, this has to be temporary.
805 // To save time here, we only set value instead of allocating new
807 // This give an HUGE performance improvement
808 // all allocation done in the LttngTrace constructor
810 eventTimestamp
.setValue(jniEvent
.getEventTime().getTime());
811 eventSource
= jniEvent
.requestEventSource();
813 eventType
= traceTypes
.get(EventTypeKey
.getEventTypeHash(jniEvent
));
815 final String fullTracePath
= getName();
816 final String reference
= fullTracePath
.substring(fullTracePath
.lastIndexOf('/') + 1);
817 currentLttngEvent
.setReference(reference
);
819 eventContent
.emptyContent();
821 currentLttngEvent
.setType(eventType
);
822 // Save the jni reference
823 currentLttngEvent
.updateJniEventReference(jniEvent
);
825 // Parse now if was asked
826 // Warning : THIS IS SLOW
828 eventContent
.getFields();
830 return currentLttngEvent
;
832 return convertJniEventToTmfMultipleEventEvilFix(jniEvent
, isParsingNeeded
);
837 * This method is a temporary fix to support multiple events at once in TMF
838 * This is expected to be slow and should be fixed in another way. See
839 * comment in convertJniEventToTmf();
841 * @param jniEvent The current JNI Event
842 * @return Current Lttng Event fully parsed
844 private synchronized LttngEvent
convertJniEventToTmfMultipleEventEvilFix(final JniEvent jniEvent
,
845 final boolean isParsingNeeded
) {
847 // Below : the "fix" with all the new and the full-parse
848 // Allocating new memory is slow.
849 // Parsing every events is very slow.
850 eventTimestamp
= new LttngTimestamp(jniEvent
.getEventTime().getTime());
851 eventSource
= jniEvent
.requestEventSource();
852 eventReference
= getName();
853 eventType
= new LttngEventType(traceTypes
.get(EventTypeKey
.getEventTypeHash(jniEvent
)));
854 eventContent
= new LttngEventContent(currentLttngEvent
);
855 currentLttngEvent
= new LttngEvent(this, eventTimestamp
, eventSource
, eventType
, eventContent
, eventReference
,
858 // The jni reference is no longer reliable but we will keep it anyhow
859 currentLttngEvent
.updateJniEventReference(jniEvent
);
860 // Ensure that the content is correctly set
861 eventContent
.setEvent(currentLttngEvent
);
863 // Parse the event if it was needed
865 // ONLY for testing, NOT parsing events with non-unique events WILL
866 // result in segfault in the JVM
868 eventContent
.getFields();
870 return currentLttngEvent
;
874 * Reference to the current LttngTrace we are reading from.
877 * Note : This bypass the framework and should not be use, except for
880 * @return Reference to the current LttngTrace
882 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniTrace
884 public JniTrace
getCurrentJniTrace() {
885 return currentJniTrace
;
889 * Return a reference to the current LttngEvent we have in memory.
891 * @return The current (last read) LttngEvent
893 * @see org.eclipse.linuxtools.internal.lttng.core.event.LttngEvent
895 public synchronized LttngEvent
getCurrentEvent() {
896 return currentLttngEvent
;
900 * Get the major version number for the current trace
902 * @return Version major or -1 if unknown
904 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniTrace
907 public short getVersionMajor() {
908 if (currentJniTrace
!= null)
909 return currentJniTrace
.getLttMajorVersion();
915 * Get the minor version number for the current trace
917 * @return Version minor or -1 if unknown
919 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniTrace
922 public short getVersionMinor() {
923 if (currentJniTrace
!= null)
924 return currentJniTrace
.getLttMinorVersion();
930 * Get the number of CPU for this trace
932 * @return Number of CPU or -1 if unknown
934 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniTrace
937 public int getCpuNumber() {
938 if (currentJniTrace
!= null)
939 return currentJniTrace
.getCpuNumber();
945 public synchronized void dispose() {
946 if (currentJniTrace
!= null)
947 currentJniTrace
.closeTrace();
952 * Return a String identifying this trace.
954 * @return String that identify this trace
957 @SuppressWarnings("nls")
958 public String
toString() {
959 String returnedData
= "";
961 returnedData
+= "Path :" + getPath() + " ";
962 returnedData
+= "Trace:" + currentJniTrace
+ " ";
963 returnedData
+= "Event:" + currentLttngEvent
;
971 * EventTypeKey inner class
973 * This class is used to make the process of generating the HashMap key more
974 * transparent and so less error prone to use
976 final class EventTypeKey
{
979 // These two getEventTypeKey() functions should ALWAYS construct the key the
981 // Otherwise, every type search will fail!
983 // added final to encourage inlining.
985 // generating a hash code by hand to avoid a string creation
986 final static public int getEventTypeHash(final LttngEventType newEventType
) {
987 return generateHash(newEventType
.getTracefileName(), newEventType
.getCpuId(), newEventType
.getMarkerName());
990 final private static int generateHash(final String traceFileName
, final long cpuNumber
, final String markerName
) {
991 // 0x1337 is a prime number. The number of CPUs is always under 8192 on
992 // the current kernel, so this will work with the current linux kernel.
993 final int cpuHash
= (int) (cpuNumber
* (0x1337));
994 return traceFileName
.hashCode() ^
(cpuHash
) ^ markerName
.hashCode();
997 // generating a hash code by hand to avoid a string creation
998 final static public int getEventTypeHash(final JniEvent newEvent
) {
999 return generateHash(newEvent
.getParentTracefile().getTracefileName(), newEvent
.getParentTracefile()
1000 .getCpuNumber(), newEvent
.requestEventMarker().getName());