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
.factory
.JniTraceFactory
;
33 import org
.eclipse
.linuxtools
.tmf
.event
.TmfTimeRange
;
34 import org
.eclipse
.linuxtools
.tmf
.event
.TmfTimestamp
;
35 import org
.eclipse
.linuxtools
.tmf
.trace
.ITmfLocation
;
36 import org
.eclipse
.linuxtools
.tmf
.trace
.TmfCheckpoint
;
37 import org
.eclipse
.linuxtools
.tmf
.trace
.TmfContext
;
38 import org
.eclipse
.linuxtools
.tmf
.trace
.TmfTrace
;
41 class LTTngTraceException
extends LttngException
{
42 static final long serialVersionUID
= -1636648737081868146L;
44 public LTTngTraceException(String errMsg
) {
50 * <b><u>LTTngTrace</u></b><p>
52 * LTTng trace implementation. It accesses the C trace handling library
53 * (seeking, reading and parsing) through the JNI component.
55 public class LTTngTrace
extends TmfTrace
<LttngEvent
> {
57 public static boolean joie
= false;
59 private final static boolean SHOW_LTT_DEBUG_DEFAULT
= false;
60 private final static boolean IS_PARSING_NEEDED_DEFAULT
= false;
61 private final static int CHECKPOINT_PAGE_SIZE
= 1000;
63 // Reference to our JNI trace
64 private JniTrace currentJniTrace
= null;
67 // To save time, we will declare all component of the LttngEvent during the construction of the trace
68 // Then, while reading the trace, we will just SET the values instead of declaring new object
69 LttngTimestamp eventTimestamp
= null;
70 LttngEventSource eventSource
= null;
71 LttngEventType eventType
= null;
72 LttngEventContent eventContent
= null;
73 LttngEventReference eventReference
= null;
75 LttngEvent currentLttngEvent
= null;
77 // The current location
78 LttngLocation currentLocation
= null;
81 // Hashmap of the possible types of events (Tracefile/CPU/Marker in the JNI)
82 HashMap
<String
, LttngEventType
> traceTypes
= null;
83 // This vector will be used to quickly find a marker name from a position
84 Vector
<String
> traceTypeNames
= null;
87 * Default Constructor.<p>
89 * @param path Path to a <b>directory</b> that contain an LTTng trace.
91 * @exception Exception (most likely LTTngTraceException or FileNotFoundException)
93 public LTTngTrace(String path
) throws Exception
{
94 // Call with "wait for completion" true and "skip indexing" false
95 this(path
, true, false);
99 * Constructor, with control over the indexing.
101 * @param path Path to a <b>directory</b> that contain an LTTng trace.
102 * @param waitForCompletion Should we wait for indexign to complete before moving on.
104 * @exception Exception (most likely LTTngTraceException or FileNotFoundException)
106 public LTTngTrace(String path
, boolean waitForCompletion
) throws Exception
{
107 // Call with "skip indexing" false
108 this(path
, waitForCompletion
, false);
112 * Default constructor, with control over the indexing and possibility to bypass indexation
114 * @param path Path to a <b>directory</b> that contain an LTTng trace.
115 * @param waitForCompletion Should we wait for indexign to complete before moving on.
116 * @param bypassIndexing Should we bypass indexing completly? This is should only be useful for unit testing.
118 * @exception Exception (most likely LTTngTraceException or FileNotFoundException)
121 public LTTngTrace(String path
, boolean waitForCompletion
, boolean bypassIndexing
) throws Exception
{
122 super(LttngEvent
.class, path
, CHECKPOINT_PAGE_SIZE
);
124 currentJniTrace
= JniTraceFactory
.getJniTrace(path
, SHOW_LTT_DEBUG_DEFAULT
);
126 catch (Exception e
) {
127 throw new LTTngTraceException(e
.getMessage());
130 // Export all the event types from the JNI side
131 traceTypes
= new HashMap
<String
, LttngEventType
>();
132 traceTypeNames
= new Vector
<String
>();
133 initialiseEventTypes(currentJniTrace
);
136 // Verify that all those "default constructor" are safe to use
137 eventTimestamp
= new LttngTimestamp();
138 eventSource
= new LttngEventSource();
139 eventType
= new LttngEventType();
140 eventContent
= new LttngEventContent(currentLttngEvent
);
141 eventReference
= new LttngEventReference(this.getName());
143 // Create the skeleton event
144 currentLttngEvent
= new LttngEvent(eventTimestamp
, eventSource
, eventType
, eventContent
, eventReference
, null);
146 // Create a new current location
147 currentLocation
= new LttngLocation();
150 // Set the currentEvent to the eventContent
151 eventContent
.setEvent(currentLttngEvent
);
153 // Bypass indexing if asked
154 if ( bypassIndexing
== false ) {
158 // Even if we don't have any index, set ONE checkpoint
159 fCheckpoints
.add(new TmfCheckpoint(new LttngTimestamp(0L) , new LttngLocation() ) );
161 // Set the start time of the trace
162 setTimeRange( new TmfTimeRange( new LttngTimestamp(currentJniTrace
.getStartTime().getTime()),
163 new LttngTimestamp(currentJniTrace
.getEndTime().getTime())
170 * Copy constructor is forbidden for LttngEvenmStream
172 * Events are only valid for a very limited period of time and
173 * JNI library does not support multiple access at once (yet?).
174 * For this reason, copy constructor should NEVER be used.
176 private LTTngTrace(LTTngTrace oldStream
) throws Exception
{
177 super(LttngEvent
.class, null);
178 throw new Exception("Copy constructor should never be use with a LTTngTrace!");
182 * Fill out the HashMap with "Type" (Tracefile/Marker)
184 * This should be called at construction once the trace is open
186 private void initialiseEventTypes(JniTrace trace
) {
188 LttngEventType tmpType
= null;
189 String
[] markerFieldsLabels
= null;
191 String newTracefileKey
= null;
192 Integer newMarkerKey
= null;
194 JniTracefile newTracefile
= null;
195 JniMarker newMarker
= null;
197 // First, obtain an iterator on TRACEFILES of owned by the TRACE
198 Iterator
<String
> tracefileItr
= trace
.getTracefilesMap().keySet().iterator();
199 while ( tracefileItr
.hasNext() ) {
200 newTracefileKey
= tracefileItr
.next();
201 newTracefile
= trace
.getTracefilesMap().get(newTracefileKey
);
203 // From the TRACEFILE read, obtain its MARKER
204 Iterator
<Integer
> markerItr
= newTracefile
.getTracefileMarkersMap().keySet().iterator();
205 while ( markerItr
.hasNext() ) {
206 newMarkerKey
= markerItr
.next();
207 newMarker
= newTracefile
.getTracefileMarkersMap().get(newMarkerKey
);
209 // From the MARKER we can obtain the MARKERFIELDS keys (i.e. labels)
210 markerFieldsLabels
= newMarker
.getMarkerFieldsHashMap().keySet().toArray( new String
[newMarker
.getMarkerFieldsHashMap().size()] );
211 tmpType
= new LttngEventType(newTracefile
.getTracefileName(), newTracefile
.getCpuNumber(), newMarker
.getName(), markerFieldsLabels
);
213 // Add the type to the map/vector
214 addEventTypeToMap(tmpType
);
220 * Add a new type to the HashMap
222 * As the hashmap use a key format that is a bit dangerous to use, we should always add using this function.
224 private void addEventTypeToMap(LttngEventType newEventType
) {
225 String newTypeKey
= EventTypeKey
.getEventTypeKey(newEventType
);
227 this.traceTypes
.put(newTypeKey
, newEventType
);
228 this.traceTypeNames
.add(newTypeKey
);
232 * Method to convert a JniEvent into a LttngEvent.<p>
234 * Note : This method will call LttngEvent convertEventJniToTmf(JniEvent, boolean)
235 * with a default value for isParsingNeeded
237 * @param newEvent The JniEvent to convert into LttngEvent
239 * @return The converted LttngEvent
241 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniEvent
242 * @see org.eclipse.linuxtools.lttng.event.LttngEvent
244 public LttngEvent
convertJniEventToTmf(JniEvent newEvent
) {
245 currentLttngEvent
= convertJniEventToTmf(newEvent
, IS_PARSING_NEEDED_DEFAULT
);
247 return currentLttngEvent
;
251 * Method to convert a JniEvent into a LttngEvent
253 * @param jniEvent The JniEvent to convert into LttngEvent
254 * @param isParsingNeeded A boolean value telling if the event should be parsed or not.
256 * @return The converted LttngEvent
258 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniEvent
259 * @see org.eclipse.linuxtools.lttng.event.LttngEvent
261 public LttngEvent
convertJniEventToTmf(JniEvent jniEvent
, boolean isParsingNeeded
) {
263 // To save time here, we only set value instead of allocating new object
264 // This give an HUGE performance improvement
265 // all allocation done in the LttngTrace constructor
267 eventTimestamp
.setValue(jniEvent
.getEventTime().getTime());
268 eventSource
.setSourceId(jniEvent
.requestEventSource());
270 eventType
= traceTypes
.get( EventTypeKey
.getEventTypeKey(jniEvent
) );
272 eventReference
.setValue(jniEvent
.getParentTracefile().getTracefilePath());
273 eventReference
.setTracepath(this.getName());
275 // eventContent.setEvent(currentLttngEvent);
276 // eventContent.setType(eventType);
277 eventContent
.emptyContent();
279 // currentLttngEvent.setContent(eventContent);
280 currentLttngEvent
.setType(eventType
);
281 // Save the jni reference
282 currentLttngEvent
.updateJniEventReference(jniEvent
);
284 // Parse now if was asked
285 // Warning : THIS IS SLOW
286 if (isParsingNeeded
== true ) {
287 eventContent
.getFields();
290 return currentLttngEvent
;
294 * Reference to the current LttngTrace we are reading from.<p>
296 * Note : This bypass the framework and should not be use, except for testing!
298 * @return Reference to the current LttngTrace
300 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniTrace
302 public JniTrace
getCurrentJniTrace() {
303 return currentJniTrace
;
308 * Return a reference to the current LttngEvent we have in memory.
310 * @return The current (last read) LttngEvent
312 * @see org.eclipse.linuxtools.lttng.event.LttngEvent
314 public LttngEvent
getCurrentEvent() {
315 return currentLttngEvent
;
319 * Get the major version number for the current trace
321 * @return Version major or -1 if unknown
323 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniTrace
326 public short getVersionMajor() {
327 if ( currentJniTrace
!= null ) {
328 return currentJniTrace
.getLttMajorVersion();
336 * Get the minor version number for the current trace
338 * @return Version minor or -1 if unknown
340 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniTrace
343 public short getVersionMinor() {
344 if ( currentJniTrace
!= null ) {
345 return currentJniTrace
.getLttMinorVersion();
353 * Get the number of CPU for this trace
355 * @return Number of CPU or -1 if unknown
357 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniTrace
360 public int getCpuNumber() {
361 if ( currentJniTrace
!= null ) {
362 return currentJniTrace
.getCpuNumber();
371 public String
toString() {
372 String returnedData
="";
374 returnedData
+= "Path :" + getPath() + " ";
375 returnedData
+= "Trace:" + currentJniTrace
+ " ";
376 returnedData
+= "Event:" + currentLttngEvent
;
390 public void bidon_function() {
392 System
.out
.println("START : " + getTimeRange().getStartTime().getValue());
393 System
.out
.println("END : " + getTimeRange().getEndTime().getValue());
395 for ( int pos
=0; pos
< fCheckpoints
.size(); pos
++) {
396 //for ( int pos=0; pos < 100; pos++) {
397 System
.out
.print(pos
+ ": " + "\t");
398 System
.out
.print( fCheckpoints
.get(pos
).getTimestamp() + "\t" );
399 System
.out
.println( fCheckpoints
.get(pos
).getLocation() );
404 public synchronized void indexTrace(boolean useless
) {
406 // Position the trace at the beginning
407 TmfContext context
= seekEvent( new LttngTimestamp(0L) );
412 LttngTimestamp startTime
= null;
413 LttngTimestamp lastTime
= new LttngTimestamp();
415 LttngEvent tmpEvent
= (LttngEvent
)getNextEvent(context
);
416 LttngLocation tmpLocation
= (LttngLocation
)context
.getLocation();
419 while ( tmpEvent
!= null) {
420 tmpLocation
= (LttngLocation
)context
.getLocation();
422 if ( startTime
== null ) {
423 startTime
= new LttngTimestamp( tmpLocation
.getCurrentTime() );
426 lastTime
.setValue(tmpEvent
.getTimestamp().getValue());
428 if ((nbEvents
% getCacheSize()) == 0) {
429 LttngTimestamp tmpTimestamp
= new LttngTimestamp( tmpLocation
.getCurrentTime() );
430 LttngLocation newLocation
= new LttngLocation( tmpLocation
.getCurrentTime() );
432 fCheckpoints
.add(new TmfCheckpoint(tmpTimestamp
, newLocation
) );
437 tmpEvent
= (LttngEvent
)getNextEvent(context
);
440 if (startTime
!= null) {
441 setTimeRange( new TmfTimeRange(startTime
, lastTime
) );
442 notifyListeners(getTimeRange() );
445 fNbEvents
= nbEvents
;
452 public ITmfLocation
<?
> getCurrentLocation() {
453 return currentLocation
;
457 public synchronized TmfContext
seekLocation(ITmfLocation
<?
> location
) {
459 if ( joie
== true ) {
460 System
.out
.println("seekLocation(location) location -> " + location
);
463 LttngTimestamp tmpTime
= null;
465 if ( location
== null ) {
466 tmpTime
= (LttngTimestamp
)getStartTime();
470 // NEED TO AVOID TIMESTAMP CREATION
471 tmpTime
= new LttngTimestamp( ((LttngLocation
)location
).getCurrentTime() );
474 // The only seek valid in LTTng is with the time, we call seekEvent(timestamp)
475 return seekEvent( tmpTime
);
479 public synchronized TmfContext
seekEvent(TmfTimestamp timestamp
) {
481 if ( joie
== true ) {
482 System
.out
.println("seekEvent(timestamp) timestamp -> " + timestamp
);
485 currentJniTrace
.seekToTime(new JniTime(timestamp
.getValue()));
487 // Update the current time for the location
488 currentLocation
.setCurrentTime( timestamp
.getValue() );
490 return new TmfContext(currentLocation
);
494 public synchronized TmfContext
seekEvent(long position
) {
496 if ( joie
== true ) {
497 System
.out
.println("seekEvent(position) position -> " + position
);
500 TmfTimestamp timestamp
= null;
501 long index
= position
/ getCacheSize();
503 if (fCheckpoints
.size() > 0) {
504 if (index
>= fCheckpoints
.size()) {
505 index
= fCheckpoints
.size() - 1;
507 timestamp
= (TmfTimestamp
)fCheckpoints
.elementAt((int)index
).getTimestamp();
510 timestamp
= getStartTime();
513 TmfContext tmpContext
= seekEvent(timestamp
);
514 LttngLocation tmpLocation
= (LttngLocation
)tmpContext
.getLocation();
516 Long currentPosition
= index
* getCacheSize();
518 JniEvent tmpJniEvent
= currentJniTrace
.findNextEvent();
519 while ( (tmpJniEvent
!= null) && ( currentPosition
< position
) ) {
520 tmpJniEvent
= currentJniTrace
.readNextEvent();
522 tmpLocation
.setCurrentTime( tmpJniEvent
.getEventTime().getTime() );
530 public synchronized LttngEvent
getNextEvent(TmfContext context
) {
532 if ( joie
== true ) {
533 System
.out
.println("getNextEvent(context) context.getLocation() -> " + context
.getLocation());
536 LttngEvent returnedEvent
= null;
537 LttngLocation tmpLocation
= null;
539 if ( context
.getLocation() == null ) {
540 tmpLocation
= new LttngLocation();
541 context
.setLocation(tmpLocation
);
544 tmpLocation
= (LttngLocation
)context
.getLocation();
547 if ( tmpLocation
.getCurrentTime() != currentJniTrace
.getCurrentEventTimestamp().getTime() ) {
548 seekLocation( tmpLocation
);
551 returnedEvent
= readEvent(tmpLocation
);
553 // No matter what happens, save the location
554 currentLocation
= tmpLocation
;
556 return returnedEvent
;
562 public synchronized LttngEvent
parseEvent(TmfContext context
) {
564 if ( joie
== true ) {
565 System
.out
.println("parseEvent(context) context.getLocation() -> " + context
.getLocation());
568 LttngEvent returnedEvent
= null;
569 LttngLocation tmpLocation
= null;
571 if ( context
.getLocation() == null ) {
572 tmpLocation
= new LttngLocation();
573 context
.setLocation(tmpLocation
);
576 tmpLocation
= (LttngLocation
)context
.getLocation();
579 if ( tmpLocation
.getCurrentTime() != currentJniTrace
.getCurrentEventTimestamp().getTime() ) {
580 seekLocation( tmpLocation
);
583 if ( currentLttngEvent
.getTimestamp().getValue() != currentJniTrace
.getCurrentEventTimestamp().getTime() ) {
584 returnedEvent
= readEvent(tmpLocation
);
587 returnedEvent
= currentLttngEvent
;
590 // No matter what happens, save the location
591 currentLocation
= tmpLocation
;
593 return returnedEvent
;
598 private synchronized LttngEvent
readEvent(LttngLocation location
) {
599 LttngEvent returnedEvent
= null;
600 JniEvent tmpEvent
= null;
602 tmpEvent
= currentJniTrace
.readNextEvent();
604 if ( tmpEvent
!= null ) {
606 // Convert will update the currentLttngEvent
607 returnedEvent
= convertJniEventToTmf(tmpEvent
);
610 // Set Last and Current time from the event read, as it could be different from the time requested
611 location
.setLastReadTime(returnedEvent
.getTimestamp().getValue() );
612 location
.setCurrentTime( returnedEvent
.getTimestamp().getValue() );
615 // If the read failed (likely the last event in the trace), set the LastReadTime to the JNI time
616 // That way, even if we try to read again, we will step over the bogus seek and read
618 // location.setLastReadTime( currentJniTrace.getEndTime().getTime() + 1 );
619 // location.setCurrentTime( currentJniTrace.getEndTime().getTime() + 1 );
620 location
.setLastReadTime( getEndTime().getValue() + 1 );
621 location
.setCurrentTime( getEndTime().getValue() + 1 );
622 // location.setLastReadTime( Long.MAX_VALUE );
623 // location.setCurrentTime( Long.MAX_VALUE );
624 // location.setLastReadTime( currentJniTrace.getEndTime().getNanoSeconds() + 1 );
625 // location.setCurrentTime( currentJniTrace.getEndTime().getNanoSeconds() + 1 );
626 // System.out.println("TMF End time " + getEndTime().getValue() );
627 // System.out.println("JNI End time " + currentJniTrace.getEndTime().getTime() );
628 // System.out.println("JNI Partial time " + currentJniTrace.getEndTime().getNanoSeconds() );
631 return returnedEvent
;
638 * EventTypeKey inner class
640 * This class is used to make the process of generating the HashMap key more transparent and so less error prone to use
645 // These two getEventTypeKey() functions should ALWAYS construct the key the same ways!
646 // Otherwise, every type search will fail!
648 static public String
getEventTypeKey(LttngEventType newEventType
) {
649 String key
= newEventType
.getTracefileName() + "/" + newEventType
.getCpuId().toString() + "/" + newEventType
.getMarkerName();
654 static public String
getEventTypeKey(JniEvent newEvent
) {
655 String key
= newEvent
.getParentTracefile().getTracefileName() + "/" + newEvent
.getParentTracefile().getCpuNumber() + "/" + newEvent
.requestEventMarker().getName();