1 /*******************************************************************************
2 * Copyright (c) 2009 Ericsson
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 *******************************************************************************/
13 package org
.eclipse
.linuxtools
.lttng
.trace
;
15 import java
.util
.HashMap
;
16 import java
.util
.Iterator
;
17 import java
.util
.Vector
;
19 import org
.eclipse
.linuxtools
.lttng
.LttngException
;
20 import org
.eclipse
.linuxtools
.lttng
.event
.LttngEvent
;
21 import org
.eclipse
.linuxtools
.lttng
.event
.LttngEventContent
;
22 import org
.eclipse
.linuxtools
.lttng
.event
.LttngEventReference
;
23 import org
.eclipse
.linuxtools
.lttng
.event
.LttngEventSource
;
24 import org
.eclipse
.linuxtools
.lttng
.event
.LttngEventType
;
25 import org
.eclipse
.linuxtools
.lttng
.event
.LttngLocation
;
26 import org
.eclipse
.linuxtools
.lttng
.event
.LttngTimestamp
;
27 import org
.eclipse
.linuxtools
.lttng
.jni
.JniEvent
;
28 import org
.eclipse
.linuxtools
.lttng
.jni
.JniMarker
;
29 import org
.eclipse
.linuxtools
.lttng
.jni
.JniTrace
;
30 import org
.eclipse
.linuxtools
.lttng
.jni
.JniTracefile
;
31 import org
.eclipse
.linuxtools
.lttng
.jni
.common
.JniTime
;
32 import org
.eclipse
.linuxtools
.lttng
.jni
.exception
.JniException
;
33 import org
.eclipse
.linuxtools
.lttng
.jni
.factory
.JniTraceFactory
;
34 import org
.eclipse
.linuxtools
.tmf
.event
.TmfTimeRange
;
35 import org
.eclipse
.linuxtools
.tmf
.event
.TmfTimestamp
;
36 import org
.eclipse
.linuxtools
.tmf
.trace
.ITmfContext
;
37 import org
.eclipse
.linuxtools
.tmf
.trace
.ITmfLocation
;
38 import org
.eclipse
.linuxtools
.tmf
.trace
.TmfContext
;
39 import org
.eclipse
.linuxtools
.tmf
.trace
.TmfTrace
;
42 class LTTngTraceException
extends LttngException
{
43 static final long serialVersionUID
= -1636648737081868146L;
45 public LTTngTraceException(String errMsg
) {
51 * <b><u>LTTngTrace</u></b><p>
53 * LTTng trace implementation. It accesses the C trace handling library
54 * (seeking, reading and parsing) through the JNI component.
56 public class LTTngTrace
extends TmfTrace
<LttngEvent
> {
58 public static boolean printDebug
= false;
59 public static boolean uniqueEvent
= false;
61 private final static boolean SHOW_LTT_DEBUG_DEFAULT
= false;
62 private final static boolean IS_PARSING_NEEDED_DEFAULT
= !uniqueEvent
;
63 private final static int CHECKPOINT_PAGE_SIZE
= 1000;
65 // Reference to our JNI trace
66 private JniTrace currentJniTrace
= null;
69 // UNHACKED : We can no longer do that because TCF need to maintain several events at once.
70 // This is very slow to do so in LTTng, this has to be temporary.
72 // To save time, we will declare all component of the LttngEvent during the construction of the trace
73 // Then, while reading the trace, we will just SET the values instead of declaring new object
75 LttngTimestamp eventTimestamp
= null;
76 LttngEventSource eventSource
= null;
77 LttngEventContent eventContent
= null;
78 LttngEventReference eventReference
= null;
82 LttngEvent currentLttngEvent
= null;
84 // The current location
85 LttngLocation previousLocation
= null;
87 LttngEventType eventType
= null;
88 // Hashmap of the possible types of events (Tracefile/CPU/Marker in the JNI)
89 HashMap
<String
, LttngEventType
> traceTypes
= null;
90 // This vector will be used to quickly find a marker name from a position
91 Vector
<String
> traceTypeNames
= null;
94 * Default Constructor.<p>
96 * @param path Path to a <b>directory</b> that contain an LTTng trace.
98 * @exception Exception (most likely LTTngTraceException or FileNotFoundException)
100 public LTTngTrace(String path
) throws Exception
{
101 // Call with "wait for completion" true and "skip indexing" false
102 this(path
, true, false);
106 * Constructor, with control over the indexing.
108 * @param path Path to a <b>directory</b> that contain an LTTng trace.
109 * @param waitForCompletion Should we wait for indexign to complete before moving on.
111 * @exception Exception (most likely LTTngTraceException or FileNotFoundException)
113 public LTTngTrace(String path
, boolean waitForCompletion
) throws Exception
{
114 // Call with "skip indexing" false
115 this(path
, waitForCompletion
, false);
119 * Default constructor, with control over the indexing and possibility to bypass indexation
121 * @param path Path to a <b>directory</b> that contain an LTTng trace.
122 * @param waitForCompletion Should we wait for indexign to complete before moving on.
123 * @param bypassIndexing Should we bypass indexing completly? This is should only be useful for unit testing.
125 * @exception Exception (most likely LTTngTraceException or FileNotFoundException)
128 public LTTngTrace(String path
, boolean waitForCompletion
, boolean bypassIndexing
) throws Exception
{
129 super(path
, LttngEvent
.class, path
, CHECKPOINT_PAGE_SIZE
);
131 currentJniTrace
= JniTraceFactory
.getJniTrace(path
, SHOW_LTT_DEBUG_DEFAULT
);
133 catch (Exception e
) {
134 throw new LTTngTraceException(e
.getMessage());
137 // Export all the event types from the JNI side
138 traceTypes
= new HashMap
<String
, LttngEventType
>();
139 traceTypeNames
= new Vector
<String
>();
140 initialiseEventTypes(currentJniTrace
);
143 // Verify that all those "default constructor" are safe to use
144 eventTimestamp
= new LttngTimestamp();
145 eventSource
= new LttngEventSource();
146 eventType
= new LttngEventType();
147 eventContent
= new LttngEventContent(currentLttngEvent
);
148 eventReference
= new LttngEventReference(this.getName());
150 // Create the skeleton event
151 currentLttngEvent
= new LttngEvent(this, eventTimestamp
, eventSource
, eventType
, eventContent
, eventReference
, null);
153 // Create a new current location
154 previousLocation
= new LttngLocation();
157 // Set the currentEvent to the eventContent
158 eventContent
.setEvent(currentLttngEvent
);
160 // // Bypass indexing if asked
161 // if ( bypassIndexing == false ) {
165 // Even if we don't have any index, set ONE checkpoint
166 // fCheckpoints.add(new TmfCheckpoint(new LttngTimestamp(0L) , new LttngLocation() ) );
168 // Set the start time of the trace
169 setTimeRange( new TmfTimeRange( new LttngTimestamp(currentJniTrace
.getStartTime().getTime()),
170 new LttngTimestamp(currentJniTrace
.getEndTime().getTime())
177 * Copy constructor is forbidden for LttngEvenmStream
180 public LTTngTrace(LTTngTrace oldTrace
) throws Exception
{
181 this(oldTrace
.getPath(), false, true);
185 this.fCheckpoints
= oldTrace
.fCheckpoints
;
188 // This would only work if the index is already done
189 this.fCheckpoints = new Vector<TmfCheckpoint>( oldTrace.fCheckpoints.size() );
190 for (int x = 0; x<oldTrace.fCheckpoints.size(); x++){
191 TmfCheckpoint tmpCheckPoint = oldTrace.fCheckpoints.get(x);
192 this.fCheckpoints.add( new TmfCheckpoint(tmpCheckPoint.getTimestamp(), tmpCheckPoint.getLocation()) );
196 // Set the start time of the trace
197 setTimeRange( new TmfTimeRange( new LttngTimestamp(oldTrace
.getStartTime()),
198 new LttngTimestamp(oldTrace
.getEndTime()))
202 public LTTngTrace
createTraceCopy() {
203 LTTngTrace returnedTrace
= null;
206 returnedTrace
= new LTTngTrace(this);
208 catch (Exception e
) {
209 System
.out
.println("ERROR : Could not create LTTngTrace copy (createTraceCopy).\nError is : " + e
.getStackTrace());
212 return returnedTrace
;
216 public synchronized LTTngTrace
clone() {
217 LTTngTrace clone
= null;
219 clone
= (LTTngTrace
) super.clone();
221 clone
.currentJniTrace
= JniTraceFactory
.getJniTrace(getPath(), SHOW_LTT_DEBUG_DEFAULT
);
222 } catch (JniException e
) {
223 // e.printStackTrace();
226 // Export all the event types from the JNI side
227 clone
.traceTypes
= new HashMap
<String
, LttngEventType
>();
228 clone
.traceTypeNames
= new Vector
<String
>();
229 clone
.initialiseEventTypes(clone
.currentJniTrace
);
231 // Verify that all those "default constructor" are safe to use
232 clone
.eventTimestamp
= new LttngTimestamp();
233 clone
.eventSource
= new LttngEventSource();
234 clone
.eventType
= new LttngEventType();
235 clone
.eventContent
= new LttngEventContent(clone
.currentLttngEvent
);
236 clone
.eventReference
= new LttngEventReference(this.getName());
238 // Create the skeleton event
239 clone
.currentLttngEvent
= new LttngEvent(this, clone
.eventTimestamp
, clone
.eventSource
, clone
.eventType
, clone
.eventContent
, clone
.eventReference
, null);
241 // Create a new current location
242 clone
.previousLocation
= new LttngLocation();
244 // Set the currentEvent to the eventContent
245 clone
.eventContent
.setEvent(clone
.currentLttngEvent
);
247 // Set the start time of the trace
248 setTimeRange(new TmfTimeRange(
249 new LttngTimestamp(clone
.currentJniTrace
.getStartTime().getTime()),
250 new LttngTimestamp(clone
.currentJniTrace
.getEndTime().getTime())
253 catch (CloneNotSupportedException e
) {
261 * Fill out the HashMap with "Type" (Tracefile/Marker)
263 * This should be called at construction once the trace is open
265 private void initialiseEventTypes(JniTrace trace
) {
267 LttngEventType tmpType
= null;
268 String
[] markerFieldsLabels
= null;
270 String newTracefileKey
= null;
271 Integer newMarkerKey
= null;
273 JniTracefile newTracefile
= null;
274 JniMarker newMarker
= null;
276 // First, obtain an iterator on TRACEFILES of owned by the TRACE
277 Iterator
<String
> tracefileItr
= trace
.getTracefilesMap().keySet().iterator();
278 while ( tracefileItr
.hasNext() ) {
279 newTracefileKey
= tracefileItr
.next();
280 newTracefile
= trace
.getTracefilesMap().get(newTracefileKey
);
282 // From the TRACEFILE read, obtain its MARKER
283 Iterator
<Integer
> markerItr
= newTracefile
.getTracefileMarkersMap().keySet().iterator();
284 while ( markerItr
.hasNext() ) {
285 newMarkerKey
= markerItr
.next();
286 newMarker
= newTracefile
.getTracefileMarkersMap().get(newMarkerKey
);
288 // From the MARKER we can obtain the MARKERFIELDS keys (i.e. labels)
289 markerFieldsLabels
= newMarker
.getMarkerFieldsHashMap().keySet().toArray( new String
[newMarker
.getMarkerFieldsHashMap().size()] );
290 tmpType
= new LttngEventType(newTracefile
.getTracefileName(), newTracefile
.getCpuNumber(), newMarker
.getName(), markerFieldsLabels
);
292 // Add the type to the map/vector
293 addEventTypeToMap(tmpType
);
299 * Add a new type to the HashMap
301 * As the hashmap use a key format that is a bit dangerous to use, we should always add using this function.
303 private void addEventTypeToMap(LttngEventType newEventType
) {
304 String newTypeKey
= EventTypeKey
.getEventTypeKey(newEventType
);
306 this.traceTypes
.put(newTypeKey
, newEventType
);
307 this.traceTypeNames
.add(newTypeKey
);
311 // * Index the current trace.
313 // * @param useless This boolean is only to comply to the interface and will be ignored.
316 // public synchronized void indexTrace(boolean useless) {
320 // // Start time need to be null to detect none have been set
321 // // LastTime need to exist so we can ajust it as we go
322 // LttngTimestamp startTime = null;
323 // LttngTimestamp lastTime = new LttngTimestamp();
325 // // Position the trace at the beginning
326 // TmfContext context = seekEvent( new LttngTimestamp(0L) );
328 // // Read the first event and extract the location
329 // LttngEvent tmpEvent = (LttngEvent)getNextEvent(context);
331 // // If we read the first event, define the start time.
332 // if ( tmpEvent != null ) {
333 // startTime = new LttngTimestamp( tmpEvent.getTimestamp() );
334 // lastTime.setValue(tmpEvent.getTimestamp().getValue());
337 // // Now, we read each event until we hit the end of the trace
338 // // We will create a new checkpoint every "getCacheSize()" event
339 // while ( tmpEvent != null) {
340 // // Update the last time each time we read a new event
341 // lastTime.setValue(tmpEvent.getTimestamp().getValue());
343 // // Save a check point if needed
344 // if ((nbEvents++ % getCacheSize()) == 0) {
346 // // We need to NEW each stuff we put in checkpoint
347 // // Otherwise everything will be the same!
348 // LttngTimestamp tmpTimestamp = new LttngTimestamp( (LttngTimestamp)tmpEvent.getTimestamp() );
349 // LttngLocation newLocation = new LttngLocation( (LttngTimestamp)tmpEvent.getTimestamp() );
351 // fCheckpoints.add(new TmfCheckpoint(tmpTimestamp, newLocation ) );
353 // // Read the next event
354 // tmpEvent = (LttngEvent)getNextEvent(context);
357 // // If we have a start time, we should have an end time as well
358 // // Issue the new range
359 // if (startTime != null) {
360 // setTimeRange( new TmfTimeRange(startTime, lastTime) );
361 // notifyListeners(getTimeRange() );
364 // // Ajust the total number of event in the trace
365 // fNbEvents = nbEvents;
366 // //printCheckpointsVector();
367 // //printDebug = true;
371 * Return the latest saved location.
372 * Note : Modifying the returned location may result in buggy positionning!
374 * @return The LttngLocation as it was after the last operation.
376 * @see org.eclipse.linuxtools.lttng.event.LttngLocation
379 public synchronized ITmfLocation
<?
> getCurrentLocation() {
380 return previousLocation
;
384 * Position the trace to the event at the given location.<p>
385 * NOTE : Seeking by location is very fast compare to seeking by position
386 * but is still slower than "ReadNext", avoid using it for small interval.
388 * @param location Location of the event in the trace.
389 * If no event available at this exact location, we will position ourself to the next one.
391 * @return The TmfContext that point to this event
393 * @see org.eclipse.linuxtools.lttng.event.LttngLocation
394 * @see org.eclipse.linuxtools.tmf.trace.TmfContext
397 public synchronized TmfContext
seekLocation(ITmfLocation
<?
> location
) {
402 if ( printDebug
== true ) {
403 System
.out
.println("seekLocation(location) location -> " + location
);
406 // If the location in context is null, create a new one
407 LttngLocation curLocation
= null;
408 if ( location
== null ) {
409 curLocation
= new LttngLocation();
410 TmfContext context
= seekEvent(curLocation
.getOperationTime());
411 context
.setRank(ITmfContext
.INITIAL_RANK
);
415 curLocation
= (LttngLocation
)location
;
419 // Update to location should (and will) be done in SeekEvent.
421 // The only seek valid in LTTng is with the time, we call seekEvent(timestamp)
422 TmfContext context
= seekEvent(curLocation
.getOperationTime());
424 // // Adjust the previousLocation flags
425 // if (location instanceof LttngLocation) {
426 // LttngLocation lttngLocation = (LttngLocation) location;
427 // if (lttngLocation.isLastOperationReadNext()) {
428 // previousLocation.setLastOperationReadNext();
429 // } else if (lttngLocation.isLastOperationParse()) {
430 // previousLocation.setLastOperationParse();
431 // } else if (lttngLocation.isLastOperationSeek()) {
432 // previousLocation.setLastOperationSeek();
440 * Position the trace to the event at the given time.<p>
441 * NOTE : Seeking by time is very fast compare to seeking by position
442 * but is still slower than "ReadNext", avoid using it for small interval.
444 * @param timestamp Time of the event in the trace.
445 * If no event available at this exact time, we will position ourself to the next one.
447 * @return The TmfContext that point to this event
449 * @see org.eclipse.linuxtools.lttng.event.LttngLocation
450 * @see org.eclipse.linuxtools.tmf.trace.TmfContext
453 public synchronized TmfContext
seekEvent(TmfTimestamp timestamp
) {
458 if ( printDebug
== true ) {
459 System
.out
.println("seekEvent(timestamp) timestamp -> " + timestamp
);
463 currentJniTrace
.seekToTime(new JniTime(timestamp
.getValue()));
465 // Save the time at which we seeked
466 previousLocation
.setOperationTime(timestamp
.getValue());
467 // Set the operation marker as seek, to be able to detect we did "seek" this event
468 previousLocation
.setLastOperationSeek();
471 // Is that too paranoid?
473 // We don't trust what upper level could do with our internal location
474 // so we create a new one to return instead
475 LttngLocation curLocation
= new LttngLocation(previousLocation
);
477 return new TmfContext( curLocation
);
481 * Position the trace to the event at the given position (rank).<p>
482 * NOTE : Seeking by position is very slow in LTTng, consider seeking by timestamp.
484 * @param position Position (or rank) of the event in the trace, starting at 0.
486 * @return The TmfContext that point to this event
488 * @see org.eclipse.linuxtools.lttng.event.LttngLocation
489 * @see org.eclipse.linuxtools.tmf.trace.TmfContext
492 public synchronized TmfContext
seekEvent(long position
) {
494 if ( printDebug
== true ) {
495 System
.out
.println("seekEvent(position) position -> " + position
);
498 TmfTimestamp timestamp
= null;
499 long index
= position
/ getCacheSize();
501 // Get the timestamp of the closest check point to the given position
502 if (fCheckpoints
.size() > 0) {
503 if (index
>= fCheckpoints
.size()) {
504 index
= fCheckpoints
.size() - 1;
506 timestamp
= (TmfTimestamp
)fCheckpoints
.elementAt((int)index
).getTimestamp();
508 // If none, take the start time of the trace
510 timestamp
= getStartTime();
513 // Seek to the found time
514 TmfContext tmpContext
= seekEvent(timestamp
);
515 tmpContext
.setRank((index
+ 1) * fIndexPageSize
);
516 previousLocation
= (LttngLocation
)tmpContext
.getLocation();
518 // Ajust the index of the event we found at this check point position
519 Long currentPosition
= index
* getCacheSize();
521 Long lastTimeValueRead
= 0L;
523 // Get the event at current position. This won't move to the next one
524 JniEvent tmpJniEvent
= currentJniTrace
.findNextEvent();
525 // Now that we are positionned at the checkpoint,
526 // we need to "readNext" (Position - CheckpointPosition) times or until trace "run out"
527 while ( (tmpJniEvent
!= null) && ( currentPosition
< position
) ) {
528 tmpJniEvent
= currentJniTrace
.readNextEvent();
532 // If we found our event, save its timestamp
533 if ( tmpJniEvent
!= null ) {
534 lastTimeValueRead
= tmpJniEvent
.getEventTime().getTime();
537 // Set the operation marker as seek, to be able to detect we did "seek" this event
538 previousLocation
.setLastOperationSeek();
539 // Save read event time
540 previousLocation
.setOperationTime(lastTimeValueRead
);
543 // Is that too paranoid?
545 // We don't trust what upper level could do with our internal location
546 // so we create a new one to return instead
547 LttngLocation curLocation
= new LttngLocation(previousLocation
);
549 return new TmfContext( curLocation
);
553 * Return the event in the trace according to the given context. Read it if necessary.<p>
554 * Similar (same?) as ParseEvent except that calling GetNext twice read the next one the second time.
556 * @param context Current TmfContext where to get the event
558 * @return The LttngEvent we read of null if no event are available
560 * @see org.eclipse.linuxtools.lttng.event.LttngLocation
561 * @see org.eclipse.linuxtools.tmf.trace.TmfContext
564 public int nbEventsRead
= 0;
566 public synchronized LttngEvent
getNextEvent(TmfContext context
) {
568 if ( printDebug
== true ) {
569 System
.out
.println("getNextEvent(context) context.getLocation() -> " + context
.getLocation());
572 LttngEvent returnedEvent
= null;
573 LttngLocation curLocation
= null;
575 // If the location in context is null, create a new one
576 if ( context
.getLocation() == null ) {
577 curLocation
= new LttngLocation();
578 context
.setLocation(curLocation
);
581 // Otherwise, we use the one in context; it should be a valid LttngLocation
582 curLocation
= (LttngLocation
)context
.getLocation();
586 // TmfContext savedContext = context.clone();
590 // TMF assumes it is possible to read (GetNextEvent) to the next Event once ParseEvent() is called
591 // In LTTNG, there is not difference between "Parsing" and "Reading" an event.
592 // Since parsing/reading invalidate the previous event,
593 // we need to make sure the sequence ParseEvent() -> GetNextEvent() will not actually move to the next event.
594 // To do so, we avoid moving for call to "GetNextEvent()" that follow call to a call to "ParseEvent()".
595 // However, calling ParseEvent() -> GetNextEvent() -> GetNextEvent() will only move next by one.
597 // *** Positioning trick :
598 // GetNextEvent only read the trace if :
599 // 1- The last operation was NOT a ParseEvent --> A read is required
601 // 2- The time of the previous location is different from the current one --> A seek + a read is required
602 if ( (curLocation
.isLastOperationParse() != true) ||
603 (previousLocation
.getOperationTimeValue() != curLocation
.getOperationTimeValue() ) )
605 if ( previousLocation
.getOperationTimeValue() != curLocation
.getOperationTimeValue() ) {
606 if ( printDebug
== true ) {
607 System
.out
.println("\t\tSeeking in getNextEvent. [ LastTime : " + previousLocation
.getOperationTimeValue() + " CurrentTime" + curLocation
.getOperationTimeValue() + " ]");
609 seekEvent( curLocation
.getOperationTime() );
611 // Read the next event from the trace. The last one will NO LONGER BE VALID.
612 returnedEvent
= readEvent(curLocation
);
615 // Set the operation marker as read to both location, to be able to detect we did "read" this event
616 previousLocation
.setLastOperationReadNext();
617 curLocation
.setLastOperationReadNext();
620 // No event was read, just return the one currently loaded (the last one we read)
621 returnedEvent
= currentLttngEvent
;
624 // Reset (erase) the operation marker to both location, to be able to detect we did NOT "read" this event
625 previousLocation
.resetLocationState();
626 curLocation
.resetLocationState();
629 // If we read an event, set it's time to the locations (both previous and current)
630 if ( returnedEvent
!= null ) {
631 previousLocation
.setOperationTime((LttngTimestamp
)returnedEvent
.getTimestamp());
632 curLocation
.setOperationTime((LttngTimestamp
)returnedEvent
.getTimestamp());
635 // LttngLocation prevLocation = (LttngLocation) savedContext.getLocation();
636 // LttngLocation currLocation = (LttngLocation) context.getLocation();
637 // if (prevLocation.equals(currLocation)) {
638 // System.out.println("Aie");
640 // Tracer.trace("Trc: " + context.getRank() + ": " + returnedEvent.getTimestamp().toString() + " (" +
641 // (prevLocation.isLastOperationParse() ? "T" : "F") + "," + (prevLocation.isLastOperationReadNext() ? "T" : "F") + "," + (prevLocation.isLastOperationSeek() ? "T" : "F") + "), (" +
642 // (currLocation.isLastOperationParse() ? "T" : "F") + "," + (currLocation.isLastOperationReadNext() ? "T" : "F") + "," + (currLocation.isLastOperationSeek() ? "T" : "F") + ")"
646 updateIndex(context
, context
.getRank(), returnedEvent
.getTimestamp());
647 context
.updateRank(1);
650 return returnedEvent
;
655 * Return the event in the trace according to the given context. Read it if necessary.<p>
656 * Similar (same?) as GetNextEvent except that calling ParseEvent twice will return the same event
658 * @param context Current TmfContext where to get the event
660 * @return The LttngEvent we read of null if no event are available
662 * @see org.eclipse.linuxtools.lttng.event.LttngLocation
663 * @see org.eclipse.linuxtools.tmf.trace.TmfContext
666 public synchronized LttngEvent
parseEvent(TmfContext context
) {
668 if ( printDebug
== true ) {
669 System
.out
.println("parseEvent(context) context.getLocation() -> " + context
.getLocation());
672 LttngEvent returnedEvent
= null;
673 LttngLocation curLocation
= null;
675 // If the location in context is null, create a new one
676 if ( context
.getLocation() == null ) {
677 curLocation
= new LttngLocation();
678 context
.setLocation(curLocation
);
680 // Otherwise, we use the one in context; it should be a valid LttngLocation
682 curLocation
= (LttngLocation
)context
.getLocation();
686 // TMF assumes it is possible to read (GetNextEvent) to the next Event once ParseEvent() is called
687 // In LTTNG, there is not difference between "Parsing" and "Reading" an event.
688 // So, before "Parsing" an event, we have to make sure we didn't "Read" it alreafy.
689 // Also, "Reading" invalidate the previous Event in LTTNG and seek back is very costly,
690 // so calling twice "Parse" will return the same event, giving a way to get the "Currently loaded" event
692 // *** Positionning trick :
693 // ParseEvent only read the trace if :
694 // 1- The last operation was NOT a ParseEvent or a GetNextEvent --> A read is required
696 // 2- The time of the previous location is different from the current one --> A seek + a read is required
697 if ( ( (curLocation
.isLastOperationParse() != true) && ((curLocation
.isLastOperationReadNext() != true)) ) ||
698 (previousLocation
.getOperationTimeValue() != curLocation
.getOperationTimeValue() ) )
700 // Previous time != Current time : We need to reposition to the current time
701 if (previousLocation
.getOperationTimeValue() != curLocation
.getOperationTimeValue() ) {
702 if ( printDebug
== true ) {
703 System
.out
.println("\t\tSeeking in getNextEvent. [ LastTime : " + previousLocation
.getOperationTimeValue() + " CurrentTime" + curLocation
.getOperationTimeValue() + " ]");
705 seekEvent( curLocation
.getOperationTime() );
708 // Read the next event from the trace. The last one will NO LONGER BE VALID.
709 returnedEvent
= readEvent(curLocation
);
712 // No event was read, just return the one currently loaded (the last one we read)
713 returnedEvent
= currentLttngEvent
;
716 // If we read an event, set it's time to the locations (both previous and current)
717 if ( returnedEvent
!= null ) {
718 previousLocation
.setOperationTime((LttngTimestamp
)returnedEvent
.getTimestamp());
719 curLocation
.setOperationTime((LttngTimestamp
)returnedEvent
.getTimestamp());
722 // Set the operation marker as parse to both location, to be able to detect we already "read" this event
723 previousLocation
.setLastOperationParse();
724 curLocation
.setLastOperationParse();
726 return returnedEvent
;
730 * Read the next event from the JNI and convert it as Lttng Event<p>
732 * @param location Current LttngLocation that to be updated with the event timestamp
734 * @return The LttngEvent we read of null if no event are available
736 * @see org.eclipse.linuxtools.lttng.event.LttngLocation
737 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniTrace
739 private synchronized LttngEvent
readEvent(LttngLocation location
) {
740 LttngEvent returnedEvent
= null;
741 JniEvent tmpEvent
= null;
743 // Read the next event from JNI. THIS WILL INVALIDATE THE CURRENT LTTNG EVENT.
744 tmpEvent
= currentJniTrace
.readNextEvent();
746 if ( tmpEvent
!= null ) {
748 // Convert will update the currentLttngEvent
749 returnedEvent
= convertJniEventToTmf(tmpEvent
);
751 location
.setOperationTime( (LttngTimestamp
)returnedEvent
.getTimestamp() );
754 // If the read failed (likely the last event in the trace), set the LastReadTime to the JNI time
755 // That way, even if we try to read again, we will step over the bogus seek and read
757 location
.setOperationTime( getEndTime().getValue() + 1 );
760 return returnedEvent
;
764 * Method to convert a JniEvent into a LttngEvent.<p>
766 * Note : This method will call LttngEvent convertEventJniToTmf(JniEvent, boolean)
767 * with a default value for isParsingNeeded
769 * @param newEvent The JniEvent to convert into LttngEvent
771 * @return The converted LttngEvent
773 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniEvent
774 * @see org.eclipse.linuxtools.lttng.event.LttngEvent
776 public synchronized LttngEvent
convertJniEventToTmf(JniEvent newEvent
) {
777 currentLttngEvent
= convertJniEventToTmf(newEvent
, IS_PARSING_NEEDED_DEFAULT
);
779 return currentLttngEvent
;
783 * Method to convert a JniEvent into a LttngEvent
785 * @param jniEvent The JniEvent to convert into LttngEvent
786 * @param isParsingNeeded A boolean value telling if the event should be parsed or not.
788 * @return The converted LttngEvent
790 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniEvent
791 * @see org.eclipse.linuxtools.lttng.event.LttngEvent
793 public synchronized LttngEvent
convertJniEventToTmf(JniEvent jniEvent
, boolean isParsingNeeded
) {
795 if ( uniqueEvent
== true ) {
798 // UNHACKED : We can no longer do that because TCF need to maintain several events at once.
799 // This is very slow to do so in LTTng, this has to be temporary.
801 // To save time here, we only set value instead of allocating new object
802 // This give an HUGE performance improvement
803 // all allocation done in the LttngTrace constructor
805 eventTimestamp
.setValue(jniEvent
.getEventTime().getTime());
806 eventSource
.setSourceId(jniEvent
.requestEventSource());
808 eventType
= traceTypes
.get( EventTypeKey
.getEventTypeKey(jniEvent
) );
810 eventReference
.setValue(jniEvent
.getParentTracefile().getTracefilePath());
811 eventReference
.setTracepath(this.getName());
813 eventContent
.emptyContent();
815 currentLttngEvent
.setType(eventType
);
816 // Save the jni reference
817 currentLttngEvent
.updateJniEventReference(jniEvent
);
819 // Parse now if was asked
820 // Warning : THIS IS SLOW
821 if (isParsingNeeded
== true ) {
822 eventContent
.getFields();
825 return currentLttngEvent
;
828 return convertJniEventToTmfMultipleEventEvilFix(jniEvent
, isParsingNeeded
);
834 * This method is a temporary fix to support multiple events at once in TMF
835 * This is expected to be slow and should be fixed in another way.
836 * See comment in convertJniEventToTmf();
838 * @param jniEvent The current JNI Event
839 * @return Current Lttng Event fully parsed
841 private synchronized LttngEvent
convertJniEventToTmfMultipleEventEvilFix(JniEvent jniEvent
, boolean isParsingNeeded
) {
843 // Below : the "fix" with all the new and the full-parse
844 // Allocating new memory is slow.
845 // Parsing every events is very slow.
846 eventTimestamp
= new LttngTimestamp(jniEvent
.getEventTime().getTime());
847 eventSource
= new LttngEventSource(jniEvent
.requestEventSource());
848 eventReference
= new LttngEventReference(jniEvent
.getParentTracefile().getTracefilePath(), this.getName());
849 eventType
= new LttngEventType(traceTypes
.get( EventTypeKey
.getEventTypeKey(jniEvent
) ));
850 eventContent
= new LttngEventContent(currentLttngEvent
);
851 currentLttngEvent
= new LttngEvent(this, eventTimestamp
, eventSource
, eventType
, eventContent
, eventReference
, null);
853 // The jni reference is no longer reliable but we will keep it anyhow
854 currentLttngEvent
.updateJniEventReference(jniEvent
);
855 // Ensure that the content is correctly set
856 eventContent
.setEvent(currentLttngEvent
);
858 // Parse the event if it was needed
860 // ONLY for testing, NOT parsing events with non-unique events WILL result in segfault in the JVM
861 if ( isParsingNeeded
== true ) {
862 eventContent
.getFields();
865 return currentLttngEvent
;
871 * Reference to the current LttngTrace we are reading from.<p>
873 * Note : This bypass the framework and should not be use, except for testing!
875 * @return Reference to the current LttngTrace
877 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniTrace
879 public JniTrace
getCurrentJniTrace() {
880 return currentJniTrace
;
885 * Return a reference to the current LttngEvent we have in memory.
887 * @return The current (last read) LttngEvent
889 * @see org.eclipse.linuxtools.lttng.event.LttngEvent
891 public synchronized LttngEvent
getCurrentEvent() {
892 return currentLttngEvent
;
896 * Get the major version number for the current trace
898 * @return Version major or -1 if unknown
900 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniTrace
903 public short getVersionMajor() {
904 if ( currentJniTrace
!= null ) {
905 return currentJniTrace
.getLttMajorVersion();
913 * Get the minor version number for the current trace
915 * @return Version minor or -1 if unknown
917 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniTrace
920 public short getVersionMinor() {
921 if ( currentJniTrace
!= null ) {
922 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();
947 * Print the content of the checkpoint vector.<p>
949 * This is intended for debug purpose only.
951 public void printCheckpointsVector() {
952 System
.out
.println("StartTime : " + getTimeRange().getStartTime().getValue());
953 System
.out
.println("EndTime : " + getTimeRange().getEndTime().getValue());
955 for ( int pos
=0; pos
< fCheckpoints
.size(); pos
++) {
956 System
.out
.print(pos
+ ": " + "\t");
957 System
.out
.print( fCheckpoints
.get(pos
).getTimestamp() + "\t" );
958 System
.out
.println( fCheckpoints
.get(pos
).getLocation() );
963 * Return a String identifying this trace.
965 * @return String that identify this trace
968 public String
toString() {
969 String returnedData
="";
971 returnedData
+= "Path :" + getPath() + " ";
972 returnedData
+= "Trace:" + currentJniTrace
+ " ";
973 returnedData
+= "Event:" + currentLttngEvent
;
981 * EventTypeKey inner class
983 * This class is used to make the process of generating the HashMap key more transparent and so less error prone to use
988 // These two getEventTypeKey() functions should ALWAYS construct the key the same ways!
989 // Otherwise, every type search will fail!
991 static public String
getEventTypeKey(LttngEventType newEventType
) {
992 String key
= newEventType
.getTracefileName() + "/" + newEventType
.getCpuId().toString() + "/" + newEventType
.getMarkerName();
997 static public String
getEventTypeKey(JniEvent newEvent
) {
998 String key
= newEvent
.getParentTracefile().getTracefileName() + "/" + newEvent
.getParentTracefile().getCpuNumber() + "/" + newEvent
.requestEventMarker().getName();