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
.LttngTimestamp
;
26 import org
.eclipse
.linuxtools
.lttng
.jni
.JniEvent
;
27 import org
.eclipse
.linuxtools
.lttng
.jni
.JniMarker
;
28 import org
.eclipse
.linuxtools
.lttng
.jni
.JniTime
;
29 import org
.eclipse
.linuxtools
.lttng
.jni
.JniTrace
;
30 import org
.eclipse
.linuxtools
.lttng
.jni
.JniTracefile
;
31 import org
.eclipse
.linuxtools
.tmf
.event
.TmfTimeRange
;
32 import org
.eclipse
.linuxtools
.tmf
.event
.TmfTimestamp
;
33 import org
.eclipse
.linuxtools
.tmf
.trace
.TmfTrace
;
34 import org
.eclipse
.linuxtools
.tmf
.trace
.TmfTraceContext
;
37 class LTTngTraceException
extends LttngException
{
38 static final long serialVersionUID
= -1636648737081868146L;
40 public LTTngTraceException(String errMsg
) {
46 * <b><u>LTTngTrace</u></b><p>
48 * LTTng trace implementation. It accesses the C trace handling library
49 * (seeking, reading and parsing) through the JNI component.
51 public class LTTngTrace
extends TmfTrace
{
52 private final static boolean SHOW_LTT_DEBUG_DEFAULT
= false;
53 private final static boolean IS_PARSING_NEEDED_DEFAULT
= false;
54 private final static int CHECKPOINT_PAGE_SIZE
= 1;
56 // Reference to our JNI trace
57 private JniTrace currentJniTrace
= null;
60 // To save time, we will declare all component of the LttngEvent during the construction of the trace
61 // Then, while reading the trace, we will just SET the values instead of declaring new object
62 LttngTimestamp eventTimestamp
= null;
63 LttngEventSource eventSource
= null;
64 LttngEventType eventType
= null;
65 LttngEventContent eventContent
= null;
66 LttngEventReference eventReference
= null;
68 LttngEvent currentLttngEvent
= null;
70 // Hashmap of the possible types of events (Tracefile/CPU/Marker in the JNI)
71 HashMap
<String
, LttngEventType
> traceTypes
= null;
72 // This vector will be used to quickly find a marker name from a position
73 Vector
<String
> traceTypeNames
= null;
76 * Default Constructor.<p>
78 * @param path Path to a <b>directory</b> that contain an LTTng trace.
80 * @exception Exception (most likely LTTngTraceException or FileNotFoundException)
82 public LTTngTrace(String path
) throws Exception
{
83 // Call with "wait for completion" true and "skip indexing" false
84 this(path
, true, false);
88 * Constructor, with control over the indexing.
90 * @param path Path to a <b>directory</b> that contain an LTTng trace.
91 * @param waitForCompletion Should we wait for indexign to complete before moving on.
93 * @exception Exception (most likely LTTngTraceException or FileNotFoundException)
95 public LTTngTrace(String path
, boolean waitForCompletion
) throws Exception
{
96 // Call with "skip indexing" false
97 this(path
, waitForCompletion
, false);
101 * Default constructor, with control over the indexing and possibility to bypass indexation
103 * @param path Path to a <b>directory</b> that contain an LTTng trace.
104 * @param waitForCompletion Should we wait for indexign to complete before moving on.
105 * @param bypassIndexing Should we bypass indexing completly? This is should only be useful for unit testing.
107 * @exception Exception (most likely LTTngTraceException or FileNotFoundException)
110 public LTTngTrace(String path
, boolean waitForCompletion
, boolean bypassIndexing
) throws Exception
{
111 super(path
, CHECKPOINT_PAGE_SIZE
, true);
113 currentJniTrace
= new JniTrace(path
, SHOW_LTT_DEBUG_DEFAULT
);
115 catch (Exception e
) {
116 throw new LTTngTraceException(e
.getMessage());
119 // Set the start time of the trace
120 LttngTimestamp startTime
= new LttngTimestamp(currentJniTrace
.getStartTimeFromTimestampCurrentCounter().getTime());
121 setTimeRange(new TmfTimeRange(startTime
, startTime
));
123 // Export all the event types from the JNI side
124 traceTypes
= new HashMap
<String
, LttngEventType
>();
125 traceTypeNames
= new Vector
<String
>();
126 initialiseEventTypes(currentJniTrace
);
129 // Verify that all those "default constructor" are safe to use
130 eventTimestamp
= new LttngTimestamp();
131 eventSource
= new LttngEventSource();
132 eventType
= new LttngEventType();
133 eventContent
= new LttngEventContent(currentLttngEvent
);
134 eventReference
= new LttngEventReference(this.getName());
136 // Create the skeleton event
137 currentLttngEvent
= new LttngEvent(eventTimestamp
, eventSource
, eventType
, eventContent
, eventReference
, null);
139 // Set the currentEvent to the eventContent
140 eventContent
.setEvent(currentLttngEvent
);
142 // Bypass indexing if asked
143 if ( bypassIndexing
== false ) {
149 * Copy constructor is forbidden for LttngEvenmStream
151 * Events are only valid for a very limited period of time and
152 * JNI library does not support multiple access at once (yet?).
153 * For this reason, copy constructor should NEVER be used.
155 private LTTngTrace(LTTngTrace oldStream
) throws Exception
{
157 throw new Exception("Copy constructor should never be use with a LTTngTrace!");
161 * Fill out the HashMap with "Type" (Tracefile/Marker)
163 * This should be called at construction once the trace is open
165 private void initialiseEventTypes(JniTrace trace
) {
167 LttngEventType tmpType
= null;
168 String
[] markerFieldsLabels
= null;
170 String newTracefileKey
= null;
171 Integer newMarkerKey
= null;
173 JniTracefile newTracefile
= null;
174 JniMarker newMarker
= null;
176 // First, obtain an iterator on TRACEFILES of owned by the TRACE
177 Iterator
<String
> tracefileItr
= trace
.getTracefilesMap().keySet().iterator();
178 while ( tracefileItr
.hasNext() ) {
179 newTracefileKey
= tracefileItr
.next();
180 newTracefile
= trace
.getTracefilesMap().get(newTracefileKey
);
182 // From the TRACEFILE read, obtain its MARKER
183 Iterator
<Integer
> markerItr
= newTracefile
.getTracefileMarkersMap().keySet().iterator();
184 while ( markerItr
.hasNext() ) {
185 newMarkerKey
= markerItr
.next();
186 newMarker
= newTracefile
.getTracefileMarkersMap().get(newMarkerKey
);
188 // From the MARKER we can obtain the MARKERFIELDS keys (i.e. labels)
189 markerFieldsLabels
= newMarker
.getMarkerFieldsHashMap().keySet().toArray( new String
[newMarker
.getMarkerFieldsHashMap().size()] );
190 tmpType
= new LttngEventType(newTracefile
.getTracefileName(), newTracefile
.getCpuNumber(), newMarker
.getName(), markerFieldsLabels
);
192 // Add the type to the map/vector
193 addEventTypeToMap(tmpType
);
199 * Add a new type to the HashMap
201 * As the hashmap use a key format that is a bit dangerous to use, we should always add using this function.
203 private void addEventTypeToMap(LttngEventType newEventType
) {
204 String newTypeKey
= EventTypeKey
.getEventTypeKey(newEventType
);
206 this.traceTypes
.put(newTypeKey
, newEventType
);
207 this.traceTypeNames
.add(newTypeKey
);
211 * Return the next event in the trace.<p>
213 * @param context The actual context of the trace
215 * @return The next event, or null if none available
217 * @see org.eclipse.linuxtools.lttng.event.LttngEvent
220 public LttngEvent
parseEvent(TmfTraceContext context
) {
222 LttngTimestamp timestamp
= null;
223 LttngEvent returnedEvent
= null;
225 synchronized (currentJniTrace
) {
226 // Seek to the context's location
227 seekLocation(context
.getLocation());
229 // Read an event from the JNI and convert it into a LttngEvent
230 jniEvent
= currentJniTrace
.readNextEvent();
232 //currentLttngEvent = (jniEvent != null) ? convertJniEventToTmf(jniEvent, true) : null;
233 if ( jniEvent
!= null ) {
234 currentLttngEvent
= convertJniEventToTmf(jniEvent
);
235 returnedEvent
= currentLttngEvent
;
239 timestamp
= (LttngTimestamp
) getCurrentLocation();
241 context
.setLocation(timestamp
);
242 context
.setTimestamp(timestamp
);
245 return returnedEvent
;
249 * Method to convert a JniEvent into a LttngEvent.<p>
251 * Note : This method will call LttngEvent convertEventJniToTmf(JniEvent, boolean)
252 * with a default value for isParsingNeeded
254 * @param newEvent The JniEvent to convert into LttngEvent
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 newEvent
) {
262 currentLttngEvent
= convertJniEventToTmf(newEvent
, IS_PARSING_NEEDED_DEFAULT
);
264 return currentLttngEvent
;
268 * Method to convert a JniEvent into a LttngEvent
270 * @param jniEvent The JniEvent to convert into LttngEvent
271 * @param isParsingNeeded A boolean value telling if the event should be parsed or not.
273 * @return The converted LttngEvent
275 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniEvent
276 * @see org.eclipse.linuxtools.lttng.event.LttngEvent
278 public LttngEvent
convertJniEventToTmf(JniEvent jniEvent
, boolean isParsingNeeded
) {
280 // To save time here, we only set value instead of allocating new object
281 // This give an HUGE performance improvement
282 // all allocation done in the LttngTrace constructor
284 eventTimestamp
.setValue(jniEvent
.getEventTime().getTime());
285 eventSource
.setSourceId(jniEvent
.requestEventSource());
287 eventType
= traceTypes
.get( EventTypeKey
.getEventTypeKey(jniEvent
) );
289 eventReference
.setValue(jniEvent
.getParentTracefile().getTracefilePath());
290 eventReference
.setTracepath(this.getName());
292 // eventContent.setEvent(currentLttngEvent);
293 // eventContent.setType(eventType);
294 eventContent
.emptyContent();
296 // currentLttngEvent.setContent(eventContent);
297 currentLttngEvent
.setType(eventType
);
298 // Save the jni reference
299 currentLttngEvent
.setJniEventReference(jniEvent
);
301 // Parse now if was asked
302 // Warning : THIS IS SLOW
303 if (isParsingNeeded
== true ) {
304 eventContent
.getFields();
307 return currentLttngEvent
;
311 * Seek (move) to a certain location in the trace.<p>
313 * WARNING : No event is read by this function, it just seek to a certain time.<br>
314 * Use "parseEvent()" or "getNextEvent()" to get the event we seeked to.
316 * @param location a TmfTimestamp of a position in the trace
318 * @return TmfTraceContext pointing the position in the trace at the seek location
320 public TmfTraceContext
seekLocation(Object location
) {
322 LttngTimestamp timestamp
= null;
324 // If location is null, interpret this as a request to get back to the beginning of the trace
325 // in that case, just change the location, the seek will happen below
326 if (location
== null) {
327 location
= getStartTime();
330 if (location
instanceof TmfTimestamp
) {
331 long value
= ((TmfTimestamp
) location
).getValue();
332 if (value
!= currentJniTrace
.getCurrentEventTimestamp().getTime()) {
333 synchronized (currentJniTrace
) {
334 currentJniTrace
.seekToTime(new JniTime(value
));
335 timestamp
= (LttngTimestamp
) getCurrentLocation();
340 System
.out
.println("ERROR : Location not instance of TmfTimestamp");
343 // FIXME: LTTng hack - start
344 // return new TmfTraceContext(timestamp, timestamp, 0); // Original
345 return new TmfTraceContext(timestamp
, timestamp
, -1); // Hacked
346 // FIXME: LTTng hack - end
350 * Location (timestamp) of our current position in the trace.<p>
352 * @return The time (in LttngTimestamp format) of the current event or AFTER endTime if no more event is available.
355 public Object
getCurrentLocation() {
357 LttngTimestamp returnedLocation
= null;
358 JniEvent tmpJniEvent
= currentJniTrace
.findNextEvent();
360 if ( tmpJniEvent
!= null ) {
361 returnedLocation
= new LttngTimestamp(tmpJniEvent
.getEventTime().getTime());
364 returnedLocation
= new LttngTimestamp( getEndTime().getValue() + 1 );
367 return returnedLocation
;
371 * Reference to the current LttngTrace we are reading from.<p>
373 * Note : This bypass the framework and should not be use, except for testing!
375 * @return Reference to the current LttngTrace
377 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniTrace
379 public JniTrace
getCurrentJniTrace() {
380 return currentJniTrace
;
385 * Return a reference to the current LttngEvent we have in memory.
387 * @return The current (last read) LttngEvent
389 * @see org.eclipse.linuxtools.lttng.event.LttngEvent
391 public LttngEvent
getCurrentEvent() {
392 return currentLttngEvent
;
397 public String
toString() {
398 String returnedData
="";
400 returnedData
+= "Path :" + getPath() + " ";
401 returnedData
+= "Trace:" + currentJniTrace
+ " ";
402 returnedData
+= "Event:" + currentLttngEvent
;
409 * EventTypeKey inner class
411 * This class is used to make the process of generating the HashMap key more transparent and so less error prone to use
416 // These two getEventTypeKey() functions should ALWAYS construct the key the same ways!
417 // Otherwise, every type search will fail!
419 static public String
getEventTypeKey(LttngEventType newEventType
) {
420 String key
= newEventType
.getTracefileName() + "/" + newEventType
.getCpuId().toString() + "/" + newEventType
.getMarkerName();
425 static public String
getEventTypeKey(JniEvent newEvent
) {
426 String key
= newEvent
.getParentTracefile().getTracefileName() + "/" + newEvent
.getParentTracefile().getCpuNumber() + "/" + newEvent
.requestEventMarker().getName();