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
.lttng
.trace
;
16 import java
.io
.FileNotFoundException
;
17 import java
.util
.HashMap
;
18 import java
.util
.Iterator
;
19 import java
.util
.Vector
;
21 import org
.eclipse
.core
.resources
.IProject
;
22 import org
.eclipse
.linuxtools
.lttng
.TraceHelper
;
23 import org
.eclipse
.linuxtools
.lttng
.event
.LttngEvent
;
24 import org
.eclipse
.linuxtools
.lttng
.event
.LttngEventContent
;
25 import org
.eclipse
.linuxtools
.lttng
.event
.LttngEventReference
;
26 import org
.eclipse
.linuxtools
.lttng
.event
.LttngEventSource
;
27 import org
.eclipse
.linuxtools
.lttng
.event
.LttngEventType
;
28 import org
.eclipse
.linuxtools
.lttng
.event
.LttngLocation
;
29 import org
.eclipse
.linuxtools
.lttng
.event
.LttngTimestamp
;
30 import org
.eclipse
.linuxtools
.lttng
.exceptions
.LttngException
;
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
.common
.JniTime
;
36 import org
.eclipse
.linuxtools
.lttng
.jni
.exception
.JniException
;
37 import org
.eclipse
.linuxtools
.lttng
.jni
.factory
.JniTraceFactory
;
38 import org
.eclipse
.linuxtools
.tmf
.event
.TmfTimeRange
;
39 import org
.eclipse
.linuxtools
.tmf
.event
.TmfTimestamp
;
40 import org
.eclipse
.linuxtools
.tmf
.trace
.ITmfContext
;
41 import org
.eclipse
.linuxtools
.tmf
.trace
.ITmfLocation
;
42 import org
.eclipse
.linuxtools
.tmf
.trace
.TmfCheckpoint
;
43 import org
.eclipse
.linuxtools
.tmf
.trace
.TmfContext
;
44 import org
.eclipse
.linuxtools
.tmf
.trace
.TmfTrace
;
46 class LTTngTraceException
extends LttngException
{
47 static final long serialVersionUID
= -1636648737081868146L;
49 public LTTngTraceException(String errMsg
) {
55 * <b><u>LTTngTrace</u></b>
58 * LTTng trace implementation. It accesses the C trace handling library (seeking, reading and parsing) through the JNI
61 public class LTTngTrace
extends TmfTrace
<LttngEvent
> {
63 public static boolean PrintDebug
= false;
64 public static boolean UniqueEvent
= true;
66 private final static boolean SHOW_LTT_DEBUG_DEFAULT
= false;
67 private final static boolean IS_PARSING_NEEDED_DEFAULT
= !UniqueEvent
;
68 private final static int CHECKPOINT_PAGE_SIZE
= 50000;
70 // Reference to our JNI trace
71 private JniTrace currentJniTrace
= null;
74 // UNHACKED : We can no longer do that because TCF need to maintain several
76 // This is very slow to do so in LTTng, this has to be temporary.
78 // To save time, we will declare all component of the LttngEvent during the
79 // construction of the trace
80 // Then, while reading the trace, we will just SET the values instead of
81 // declaring new object
83 LttngTimestamp eventTimestamp
= null;
84 LttngEventSource eventSource
= null;
85 LttngEventContent eventContent
= null;
86 LttngEventReference eventReference
= null;
89 LttngEvent currentLttngEvent
= null;
91 // The current location
92 LttngLocation previousLocation
= null;
94 LttngEventType eventType
= null;
95 // Hashmap of the possible types of events (Tracefile/CPU/Marker in the JNI)
96 HashMap
<Integer
, LttngEventType
> traceTypes
= null;
97 // This vector will be used to quickly find a marker name from a position
98 Vector
<Integer
> traceTypeNames
= null;
99 private String traceLibPath
= null;
101 public LTTngTrace() {
104 public boolean validate(IProject project
, String path
) {
105 if (super.validate(project
, path
)) {
106 String traceLibPath
= TraceHelper
.getTraceLibDirFromProject(project
);
108 LTTngTraceVersion version
= new LTTngTraceVersion(path
, traceLibPath
);
109 return version
.isValidLttngTrace();
110 } catch (LttngException e
) {
117 public void initTrace(String path
, Class
<LttngEvent
> eventType
, boolean indexTrace
) throws FileNotFoundException
{
118 super.initTrace(path
, eventType
, indexTrace
);
120 currentJniTrace
= JniTraceFactory
.getJniTrace(path
, traceLibPath
, SHOW_LTT_DEBUG_DEFAULT
);
121 } catch (Exception e
) {
122 throw new FileNotFoundException(e
.getMessage());
125 // Export all the event types from the JNI side
126 traceTypes
= new HashMap
<Integer
, LttngEventType
>();
127 traceTypeNames
= new Vector
<Integer
>();
128 initialiseEventTypes(currentJniTrace
);
130 // Build the re-used event structure
131 eventTimestamp
= new LttngTimestamp();
132 eventSource
= new LttngEventSource();
133 this.eventType
= new LttngEventType();
134 eventContent
= new LttngEventContent(currentLttngEvent
);
135 eventReference
= new LttngEventReference(this.getName());
137 // Create the skeleton event
138 currentLttngEvent
= new LttngEvent(this, eventTimestamp
, eventSource
, this.eventType
, eventContent
,
139 eventReference
, null);
141 // Create a new current location
142 previousLocation
= new LttngLocation();
144 // Set the currentEvent to the eventContent
145 eventContent
.setEvent(currentLttngEvent
);
147 // Set the time range of the trace
148 TmfContext context
= seekLocation(null);
149 LttngEvent event
= getNextEvent(context
);
150 LttngTimestamp startTime
= new LttngTimestamp(event
.getTimestamp());
151 LttngTimestamp endTime
= new LttngTimestamp(currentJniTrace
.getEndTime().getTime());
153 setTimeRange(new TmfTimeRange(startTime
, endTime
));
157 * Default Constructor.
161 * Path to a <b>directory</b> that contain an LTTng trace.
163 * @exception Exception
164 * (most likely LTTngTraceException or FileNotFoundException)
166 public LTTngTrace(String path
) throws Exception
{
167 // Call with "wait for completion" true and "skip indexing" false
168 this(path
, null, true, false);
172 * Constructor, with control over the indexing.
176 * Path to a <b>directory</b> that contain an LTTng trace.
177 * @param waitForCompletion
178 * Should we wait for indexign to complete before moving on.
180 * @exception Exception
181 * (most likely LTTngTraceException or FileNotFoundException)
183 public LTTngTrace(String path
, boolean waitForCompletion
) throws Exception
{
184 // Call with "skip indexing" false
185 this(path
, null, waitForCompletion
, false);
189 * Default constructor, with control over the indexing and possibility to bypass indexation
193 * Path to a <b>directory</b> that contain an LTTng trace.
194 * @param traceLibPath
195 * Path to a <b>directory</b> that contains LTTng trace libraries.
196 * @param waitForCompletion
197 * Should we wait for indexign to complete before moving on.
198 * @param bypassIndexing
199 * Should we bypass indexing completly? This is should only be useful for unit testing.
201 * @exception Exception
202 * (most likely LTTngTraceException or FileNotFoundException)
205 public LTTngTrace(String path
, String traceLibPath
, boolean waitForCompletion
, boolean bypassIndexing
)
207 super(path
, LttngEvent
.class, path
, CHECKPOINT_PAGE_SIZE
, false);
208 initTrace(path
, LttngEvent
.class, !bypassIndexing
);
209 this.traceLibPath
= traceLibPath
;
212 // currentJniTrace = JniTraceFactory.getJniTrace(path, traceLibPath, SHOW_LTT_DEBUG_DEFAULT);
213 // } catch (Exception e) {
214 // throw new FileNotFoundException(e.getMessage());
217 // // Export all the event types from the JNI side
218 // traceTypes = new HashMap<Integer, LttngEventType>();
219 // traceTypeNames = new Vector<Integer>();
220 // initialiseEventTypes(currentJniTrace);
223 // // Verify that all those "default constructor" are safe to use
224 // eventTimestamp = new LttngTimestamp();
225 // eventSource = new LttngEventSource();
226 // eventType = new LttngEventType();
227 // eventContent = new LttngEventContent(currentLttngEvent);
228 // eventReference = new LttngEventReference(this.getName());
230 // // Create the skeleton event
231 // currentLttngEvent = new LttngEvent(this, eventTimestamp, eventSource, eventType, eventContent, eventReference,
234 // // Create a new current location
235 // previousLocation = new LttngLocation();
237 // // Set the currentEvent to the eventContent
238 // eventContent.setEvent(currentLttngEvent);
240 // // // Bypass indexing if asked
241 // // if ( bypassIndexing == false ) {
242 // // indexTrace(true);
245 // // Even if we don't have any index, set ONE checkpoint
246 // // fCheckpoints.add(new TmfCheckpoint(new LttngTimestamp(0L) , new
247 // // LttngLocation() ) );
249 // // Set the time range of the trace
250 // TmfContext context = seekLocation(null);
251 // LttngEvent event = getNextEvent(context);
252 // LttngTimestamp startTime = new LttngTimestamp(event.getTimestamp());
253 // LttngTimestamp endTime = new LttngTimestamp(currentJniTrace.getEndTime().getTime());
255 // setTimeRange(new TmfTimeRange(startTime, endTime));
259 * Copy constructor is forbidden for LttngEvenmStream
261 public LTTngTrace(LTTngTrace other
) throws Exception
{
262 this(other
.getPath(), other
.getTraceLibPath(), false, true);
263 this.fCheckpoints
= other
.fCheckpoints
;
264 setTimeRange(new TmfTimeRange(new LttngTimestamp(other
.getStartTime()), new LttngTimestamp(other
.getEndTime())));
268 public LTTngTrace
copy() {
269 LTTngTrace returnedTrace
= null;
272 returnedTrace
= new LTTngTrace(this);
273 } catch (Exception e
) {
275 .println("ERROR : Could not create LTTngTrace copy (createTraceCopy).\nError is : " + e
.getStackTrace()); //$NON-NLS-1$
278 return returnedTrace
;
282 public synchronized LTTngTrace
clone() {
283 LTTngTrace clone
= null;
285 clone
= (LTTngTrace
) super.clone();
287 clone
.currentJniTrace
= JniTraceFactory
.getJniTrace(getPath(), getTraceLibPath(),
288 SHOW_LTT_DEBUG_DEFAULT
);
289 } catch (JniException e
) {
290 // e.printStackTrace();
293 // Export all the event types from the JNI side
294 clone
.traceTypes
= new HashMap
<Integer
, LttngEventType
>();
295 clone
.traceTypeNames
= new Vector
<Integer
>();
296 clone
.initialiseEventTypes(clone
.currentJniTrace
);
298 // Verify that all those "default constructor" are safe to use
299 clone
.eventTimestamp
= new LttngTimestamp();
300 clone
.eventSource
= new LttngEventSource();
301 clone
.eventType
= new LttngEventType();
302 clone
.eventContent
= new LttngEventContent(clone
.currentLttngEvent
);
303 clone
.eventReference
= new LttngEventReference(this.getName());
305 // Create the skeleton event
306 clone
.currentLttngEvent
= new LttngEvent(this, clone
.eventTimestamp
, clone
.eventSource
, clone
.eventType
,
307 clone
.eventContent
, clone
.eventReference
, null);
309 // Create a new current location
310 clone
.previousLocation
= new LttngLocation();
312 // Set the currentEvent to the eventContent
313 clone
.eventContent
.setEvent(clone
.currentLttngEvent
);
315 // Set the start time of the trace
316 setTimeRange(new TmfTimeRange(new LttngTimestamp(clone
.currentJniTrace
.getStartTime().getTime()),
317 new LttngTimestamp(clone
.currentJniTrace
.getEndTime().getTime())));
318 } catch (CloneNotSupportedException e
) {
324 public String
getTraceLibPath() {
329 * Fill out the HashMap with "Type" (Tracefile/Marker)
331 * This should be called at construction once the trace is open
333 private void initialiseEventTypes(JniTrace trace
) {
335 LttngEventType tmpType
= null;
336 String
[] markerFieldsLabels
= null;
338 String newTracefileKey
= null;
339 Integer newMarkerKey
= null;
341 JniTracefile newTracefile
= null;
342 JniMarker newMarker
= null;
344 // First, obtain an iterator on TRACEFILES of owned by the TRACE
345 Iterator
<String
> tracefileItr
= trace
.getTracefilesMap().keySet().iterator();
347 while (tracefileItr
.hasNext()) {
348 newTracefileKey
= tracefileItr
.next();
349 newTracefile
= trace
.getTracefilesMap().get(newTracefileKey
);
351 // From the TRACEFILE read, obtain its MARKER
352 Iterator
<Integer
> markerItr
= newTracefile
.getTracefileMarkersMap().keySet().iterator();
353 while (markerItr
.hasNext()) {
354 newMarkerKey
= markerItr
.next();
355 newMarker
= newTracefile
.getTracefileMarkersMap().get(newMarkerKey
);
357 // From the MARKER we can obtain the MARKERFIELDS keys (i.e.
359 markerFieldsLabels
= newMarker
.getMarkerFieldsHashMap().keySet()
360 .toArray(new String
[newMarker
.getMarkerFieldsHashMap().size()]);
362 tmpType
= new LttngEventType(newTracefile
.getTracefileName(), newTracefile
.getCpuNumber(),
363 newMarker
.getName(), newMarkerKey
.intValue(), markerFieldsLabels
);
365 // Add the type to the map/vector
366 addEventTypeToMap(tmpType
);
372 * Add a new type to the HashMap
374 * As the hashmap use a key format that is a bit dangerous to use, we should always add using this function.
376 private void addEventTypeToMap(LttngEventType newEventType
) {
377 int newTypeKey
= EventTypeKey
.getEventTypeHash(newEventType
);
379 this.traceTypes
.put(newTypeKey
, newEventType
);
380 this.traceTypeNames
.add(newTypeKey
);
384 // * Index the current trace.
386 // * @param useless This boolean is only to comply to the interface and will
390 // public synchronized void indexTrace(boolean useless) {
394 // // Start time need to be null to detect none have been set
395 // // LastTime need to exist so we can ajust it as we go
396 // LttngTimestamp startTime = null;
397 // LttngTimestamp lastTime = new LttngTimestamp();
399 // // Position the trace at the beginning
400 // TmfContext context = seekEvent( new LttngTimestamp(0L) );
402 // // Read the first event and extract the location
403 // LttngEvent tmpEvent = (LttngEvent)getNextEvent(context);
405 // // If we read the first event, define the start time.
406 // if ( tmpEvent != null ) {
407 // startTime = new LttngTimestamp( tmpEvent.getTimestamp() );
408 // lastTime.setValue(tmpEvent.getTimestamp().getValue());
411 // // Now, we read each event until we hit the end of the trace
412 // // We will create a new checkpoint every "getCacheSize()" event
413 // while ( tmpEvent != null) {
414 // // Update the last time each time we read a new event
415 // lastTime.setValue(tmpEvent.getTimestamp().getValue());
417 // // Save a check point if needed
418 // if ((nbEvents++ % getCacheSize()) == 0) {
420 // // We need to NEW each stuff we put in checkpoint
421 // // Otherwise everything will be the same!
422 // LttngTimestamp tmpTimestamp = new LttngTimestamp(
423 // (LttngTimestamp)tmpEvent.getTimestamp() );
424 // LttngLocation newLocation = new LttngLocation(
425 // (LttngTimestamp)tmpEvent.getTimestamp() );
427 // fCheckpoints.add(new TmfCheckpoint(tmpTimestamp, newLocation ) );
429 // // Read the next event
430 // tmpEvent = (LttngEvent)getNextEvent(context);
433 // // If we have a start time, we should have an end time as well
434 // // Issue the new range
435 // if (startTime != null) {
436 // setTimeRange( new TmfTimeRange(startTime, lastTime) );
437 // notifyListeners(getTimeRange() );
440 // // Ajust the total number of event in the trace
441 // fNbEvents = nbEvents;
442 // //printCheckpointsVector();
443 // //printDebug = true;
447 * Return the latest saved location. Note : Modifying the returned location may result in buggy positionning!
449 * @return The LttngLocation as it was after the last operation.
451 * @see org.eclipse.linuxtools.lttng.event.LttngLocation
454 public synchronized ITmfLocation
<?
> getCurrentLocation() {
455 return previousLocation
;
459 * Position the trace to the event at the given location.
461 * NOTE : Seeking by location is very fast compare to seeking by position but is still slower than "ReadNext", avoid
462 * using it for small interval.
465 * Location of the event in the trace. If no event available at this exact location, we will position
466 * ourself to the next one.
468 * @return The TmfContext that point to this event
470 * @see org.eclipse.linuxtools.lttng.event.LttngLocation
471 * @see org.eclipse.linuxtools.tmf.trace.TmfContext
474 public synchronized TmfContext
seekLocation(ITmfLocation
<?
> location
) {
480 System
.out
.println("seekLocation(location) location -> " + location
); //$NON-NLS-1$
483 // If the location in context is null, create a new one
484 LttngLocation curLocation
= null;
485 if (location
== null) {
486 curLocation
= new LttngLocation();
487 TmfContext context
= seekEvent(curLocation
.getOperationTime());
488 context
.setRank(ITmfContext
.INITIAL_RANK
);
491 curLocation
= (LttngLocation
) location
;
495 // Update to location should (and will) be done in SeekEvent.
497 // The only seek valid in LTTng is with the time, we call
498 // seekEvent(timestamp)
499 TmfContext context
= seekEvent(curLocation
.getOperationTime());
501 // // Adjust the previousLocation flags
502 // if (location instanceof LttngLocation) {
503 // LttngLocation lttngLocation = (LttngLocation) location;
504 // if (lttngLocation.isLastOperationReadNext()) {
505 // previousLocation.setLastOperationReadNext();
506 // } else if (lttngLocation.isLastOperationParse()) {
507 // previousLocation.setLastOperationParse();
508 // } else if (lttngLocation.isLastOperationSeek()) {
509 // previousLocation.setLastOperationSeek();
517 * Position the trace to the event at the given time.
519 * NOTE : Seeking by time is very fast compare to seeking by position but is still slower than "ReadNext", avoid
520 * using it for small interval.
523 * Time of the event in the trace. If no event available at this exact time, we will position ourself to
526 * @return The TmfContext that point to this event
528 * @see org.eclipse.linuxtools.lttng.event.LttngLocation
529 * @see org.eclipse.linuxtools.tmf.trace.TmfContext
532 public synchronized TmfContext
seekEvent(TmfTimestamp timestamp
) {
538 System
.out
.println("seekEvent(timestamp) timestamp -> " + timestamp
); //$NON-NLS-1$
542 currentJniTrace
.seekToTime(new JniTime(timestamp
.getValue()));
544 // Save the time at which we seeked
545 previousLocation
.setOperationTime(timestamp
.getValue());
546 // Set the operation marker as seek, to be able to detect we did "seek"
548 previousLocation
.setLastOperationSeek();
551 // Is that too paranoid?
553 // We don't trust what upper level could do with our internal location
554 // so we create a new one to return instead
555 LttngLocation curLocation
= new LttngLocation(previousLocation
);
557 return new TmfContext(curLocation
);
561 * Position the trace to the event at the given position (rank).
563 * NOTE : Seeking by position is very slow in LTTng, consider seeking by timestamp.
566 * Position (or rank) of the event in the trace, starting at 0.
568 * @return The TmfContext that point to this event
570 * @see org.eclipse.linuxtools.lttng.event.LttngLocation
571 * @see org.eclipse.linuxtools.tmf.trace.TmfContext
574 public synchronized TmfContext
seekEvent(long position
) {
577 System
.out
.println("seekEvent(position) position -> " + position
); //$NON-NLS-1$
580 TmfTimestamp timestamp
= null;
581 long index
= position
/ getCacheSize();
583 // Get the timestamp of the closest check point to the given position
584 if (fCheckpoints
.size() > 0) {
585 if (index
>= fCheckpoints
.size()) {
586 index
= fCheckpoints
.size() - 1;
588 timestamp
= fCheckpoints
.elementAt((int) index
).getTimestamp();
590 // If none, take the start time of the trace
592 timestamp
= getStartTime();
595 // Seek to the found time
596 TmfContext tmpContext
= seekEvent(timestamp
);
597 tmpContext
.setRank((index
+ 1) * fIndexPageSize
);
598 previousLocation
= (LttngLocation
) tmpContext
.getLocation();
600 // Ajust the index of the event we found at this check point position
601 Long currentPosition
= index
* getCacheSize();
603 Long lastTimeValueRead
= 0L;
605 // Get the event at current position. This won't move to the next one
606 JniEvent tmpJniEvent
= currentJniTrace
.findNextEvent();
607 // Now that we are positionned at the checkpoint,
608 // we need to "readNext" (Position - CheckpointPosition) times or until
610 while ((tmpJniEvent
!= null) && (currentPosition
< position
)) {
611 tmpJniEvent
= currentJniTrace
.readNextEvent();
615 // If we found our event, save its timestamp
616 if (tmpJniEvent
!= null) {
617 lastTimeValueRead
= tmpJniEvent
.getEventTime().getTime();
620 // Set the operation marker as seek, to be able to detect we did "seek"
622 previousLocation
.setLastOperationSeek();
623 // Save read event time
624 previousLocation
.setOperationTime(lastTimeValueRead
);
627 // Is that too paranoid?
629 // We don't trust what upper level could do with our internal location
630 // so we create a new one to return instead
631 LttngLocation curLocation
= new LttngLocation(previousLocation
);
633 return new TmfContext(curLocation
);
637 public TmfContext
seekLocation(double ratio
) {
638 // TODO Auto-generated method stub
643 public double getLocationRatio(ITmfLocation
<?
> location
) {
644 // TODO Auto-generated method stub
649 * Return the event in the trace according to the given context. Read it if necessary.
651 * Similar (same?) as ParseEvent except that calling GetNext twice read the next one the second time.
654 * Current TmfContext where to get the event
656 * @return The LttngEvent we read of null if no event are available
658 * @see org.eclipse.linuxtools.lttng.event.LttngLocation
659 * @see org.eclipse.linuxtools.tmf.trace.TmfContext
662 public int nbEventsRead
= 0;
665 public synchronized LttngEvent
getNextEvent(TmfContext context
) {
668 System
.out
.println("getNextEvent(context) context.getLocation() -> " //$NON-NLS-1$
669 + context
.getLocation());
672 LttngEvent returnedEvent
= null;
673 LttngLocation curLocation
= null;
675 curLocation
= (LttngLocation
) context
.getLocation();
676 // If the location in context is null, create a new one
677 if (curLocation
== null) {
678 curLocation
= getCurrentLocation(context
);
682 // TmfContext savedContext = context.clone();
686 // TMF assumes it is possible to read (GetNextEvent) to the next Event
687 // once ParseEvent() is called
688 // In LTTNG, there is not difference between "Parsing" and "Reading" an
690 // Since parsing/reading invalidate the previous event,
691 // we need to make sure the sequence ParseEvent() -> GetNextEvent() will
692 // not actually move to the next event.
693 // To do so, we avoid moving for call to "GetNextEvent()" that follow
694 // call to a call to "ParseEvent()".
695 // However, calling ParseEvent() -> GetNextEvent() -> GetNextEvent()
696 // will only move next by one.
698 // *** Positioning trick :
699 // GetNextEvent only read the trace if :
700 // 1- The last operation was NOT a ParseEvent --> A read is required
702 // 2- The time of the previous location is different from the current
703 // one --> A seek + a read is required
704 if ((!(curLocation
.isLastOperationParse()))
705 || (previousLocation
.getOperationTimeValue() != curLocation
.getOperationTimeValue())) {
706 if (previousLocation
.getOperationTimeValue() != curLocation
.getOperationTimeValue()) {
708 System
.out
.println("\t\tSeeking in getNextEvent. [ LastTime : " //$NON-NLS-1$
709 + previousLocation
.getOperationTimeValue() + " CurrentTime" //$NON-NLS-1$
710 + curLocation
.getOperationTimeValue() + " ]"); //$NON-NLS-1$
712 seekEvent(curLocation
.getOperationTime());
714 // Read the next event from the trace. The last one will NO LONGER
716 returnedEvent
= readNextEvent(curLocation
);
719 // No event was read, just return the one currently loaded (the last
721 returnedEvent
= currentLttngEvent
;
724 // Reset (erase) the operation marker to both location, to be able
725 // to detect we did NOT "read" this event
726 previousLocation
.resetLocationState();
727 curLocation
.resetLocationState();
730 // If we read an event, set it's time to the locations (both previous
732 if (returnedEvent
!= null) {
733 setPreviousAndCurrentTimes(context
, returnedEvent
, curLocation
);
736 // LttngLocation prevLocation = (LttngLocation)
737 // savedContext.getLocation();
738 // LttngLocation currLocation = (LttngLocation)
739 // context.getLocation();
740 // if (prevLocation.equals(currLocation)) {
741 // System.out.println("Aie");
743 // Tracer.trace("Trc: " + context.getRank() + ": " +
744 // returnedEvent.getTimestamp().toString() + " (" +
745 // (prevLocation.isLastOperationParse() ? "T" : "F") + "," +
746 // (prevLocation.isLastOperationReadNext() ? "T" : "F") + "," +
747 // (prevLocation.isLastOperationSeek() ? "T" : "F") + "), (" +
748 // (currLocation.isLastOperationParse() ? "T" : "F") + "," +
749 // (currLocation.isLastOperationReadNext() ? "T" : "F") + "," +
750 // (currLocation.isLastOperationSeek() ? "T" : "F") + ")"
756 return returnedEvent
;
759 // this method was extracted for profiling purposes
760 private void setPreviousAndCurrentTimes(TmfContext context
, LttngEvent returnedEvent
, LttngLocation curLocation
) {
762 TmfTimestamp eventTimestamp
= returnedEvent
.getTimestamp();
763 // long eventTime = eventTimestamp.getValue();
764 previousLocation
.setOperationTime(eventTimestamp
.getValue());
765 curLocation
.setOperationTime(eventTimestamp
.getValue());
766 updateIndex(context
, context
.getRank(), eventTimestamp
);
767 context
.updateRank(1);
770 protected void updateIndex(TmfContext context
, long rank
, TmfTimestamp timestamp
) {
772 if (getStartTime().compareTo(timestamp
, false) > 0)
773 setStartTime(timestamp
);
774 if (getEndTime().compareTo(timestamp
, false) < 0)
775 setEndTime(timestamp
);
776 if (rank
!= ITmfContext
.UNKNOWN_RANK
) {
777 if (fNbEvents
<= rank
)
778 fNbEvents
= rank
+ 1;
779 // Build the index as we go along
780 if ((rank
% fIndexPageSize
) == 0) {
781 // Determine the table position
782 long position
= rank
/ fIndexPageSize
;
783 // Add new entry at proper location (if empty)
784 if (fCheckpoints
.size() == position
) {
785 addCheckPoint(context
, timestamp
);
791 private void addCheckPoint(TmfContext context
, TmfTimestamp timestamp
) {
792 ITmfLocation
<?
> location
= context
.getLocation().clone();
793 fCheckpoints
.add(new TmfCheckpoint(timestamp
.clone(), location
));
796 // this method was extracted for profiling purposes
797 private LttngEvent
readNextEvent(LttngLocation curLocation
) {
798 LttngEvent returnedEvent
;
799 // Read the next event from the trace. The last one will NO LONGER BE
801 returnedEvent
= readEvent(curLocation
);
804 // Set the operation marker as read to both location, to be able to
805 // detect we did "read" this event
806 previousLocation
.setLastOperationReadNext();
807 curLocation
.setLastOperationReadNext();
808 return returnedEvent
;
811 // this method was extracted for profiling purposes
812 private LttngLocation
getCurrentLocation(TmfContext context
) {
813 LttngLocation curLocation
;
814 curLocation
= new LttngLocation();
815 context
.setLocation(curLocation
);
820 * Return the event in the trace according to the given context. Read it if necessary.
822 * Similar (same?) as GetNextEvent except that calling ParseEvent twice will return the same event
825 * Current TmfContext where to get the event
827 * @return The LttngEvent we read of null if no event are available
829 * @see org.eclipse.linuxtools.lttng.event.LttngLocation
830 * @see org.eclipse.linuxtools.tmf.trace.TmfContext
833 public synchronized LttngEvent
parseEvent(TmfContext context
) {
836 System
.out
.println("parseEvent(context) context.getLocation() -> " //$NON-NLS-1$
837 + context
.getLocation());
840 LttngEvent returnedEvent
= null;
841 LttngLocation curLocation
= null;
843 // If the location in context is null, create a new one
844 if (context
.getLocation() == null) {
845 curLocation
= new LttngLocation();
846 context
.setLocation(curLocation
);
848 // Otherwise, we use the one in context; it should be a valid
851 curLocation
= (LttngLocation
) context
.getLocation();
855 // TMF assumes it is possible to read (GetNextEvent) to the next Event
856 // once ParseEvent() is called
857 // In LTTNG, there is not difference between "Parsing" and "Reading" an
859 // So, before "Parsing" an event, we have to make sure we didn't "Read"
861 // Also, "Reading" invalidate the previous Event in LTTNG and seek back
863 // so calling twice "Parse" will return the same event, giving a way to
864 // get the "Currently loaded" event
866 // *** Positionning trick :
867 // ParseEvent only read the trace if :
868 // 1- The last operation was NOT a ParseEvent or a GetNextEvent --> A
871 // 2- The time of the previous location is different from the current
872 // one --> A seek + a read is required
873 if (((!(curLocation
.isLastOperationParse())) && ((!(curLocation
.isLastOperationReadNext()))))
874 || (previousLocation
.getOperationTimeValue() != curLocation
.getOperationTimeValue())) {
875 // Previous time != Current time : We need to reposition to the
877 if (previousLocation
.getOperationTimeValue() != curLocation
.getOperationTimeValue()) {
879 System
.out
.println("\t\tSeeking in getNextEvent. [ LastTime : " //$NON-NLS-1$
880 + previousLocation
.getOperationTimeValue() + " CurrentTime" //$NON-NLS-1$
881 + curLocation
.getOperationTimeValue() + " ]"); //$NON-NLS-1$
883 seekEvent(curLocation
.getOperationTime());
886 // Read the next event from the trace. The last one will NO LONGER
888 returnedEvent
= readEvent(curLocation
);
890 // No event was read, just return the one currently loaded (the last
892 returnedEvent
= currentLttngEvent
;
895 // If we read an event, set it's time to the locations (both previous
897 if (returnedEvent
!= null) {
898 previousLocation
.setOperationTime((LttngTimestamp
) returnedEvent
.getTimestamp());
899 curLocation
.setOperationTime((LttngTimestamp
) returnedEvent
.getTimestamp());
902 // Set the operation marker as parse to both location, to be able to
903 // detect we already "read" this event
904 previousLocation
.setLastOperationParse();
905 curLocation
.setLastOperationParse();
907 return returnedEvent
;
911 * Read the next event from the JNI and convert it as Lttng Event<p>
913 * @param location Current LttngLocation that to be updated with the event timestamp
915 * @return The LttngEvent we read of null if no event are available
917 * @see org.eclipse.linuxtools.lttng.event.LttngLocation
919 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniTrace
921 private synchronized LttngEvent
readEvent(LttngLocation location
) {
922 LttngEvent returnedEvent
= null;
923 JniEvent tmpEvent
= null;
925 // Read the next event from JNI. THIS WILL INVALIDATE THE CURRENT LTTNG
927 tmpEvent
= currentJniTrace
.readNextEvent();
929 if (tmpEvent
!= null) {
931 // Convert will update the currentLttngEvent
932 returnedEvent
= convertJniEventToTmf(tmpEvent
);
934 location
.setOperationTime((LttngTimestamp
) returnedEvent
.getTimestamp());
937 // If the read failed (likely the last event in the trace), set the
938 // LastReadTime to the JNI time
939 // That way, even if we try to read again, we will step over the bogus
942 location
.setOperationTime(getEndTime().getValue() + 1);
945 return returnedEvent
;
949 * Method to convert a JniEvent into a LttngEvent.
952 * Note : This method will call LttngEvent convertEventJniToTmf(JniEvent, boolean) with a default value for
956 * The JniEvent to convert into LttngEvent
958 * @return The converted LttngEvent
960 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniEvent
961 * @see org.eclipse.linuxtools.lttng.event.LttngEvent
963 public synchronized LttngEvent
convertJniEventToTmf(JniEvent newEvent
) {
964 currentLttngEvent
= convertJniEventToTmf(newEvent
, IS_PARSING_NEEDED_DEFAULT
);
966 return currentLttngEvent
;
970 * Method to convert a JniEvent into a LttngEvent
973 * The JniEvent to convert into LttngEvent
974 * @param isParsingNeeded
975 * A boolean value telling if the event should be parsed or not.
977 * @return The converted LttngEvent
979 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniEvent
980 * @see org.eclipse.linuxtools.lttng.event.LttngEvent
982 public synchronized LttngEvent
convertJniEventToTmf(JniEvent jniEvent
, boolean isParsingNeeded
) {
987 // UNHACKED : We can no longer do that because TCF need to maintain
988 // several events at once.
989 // This is very slow to do so in LTTng, this has to be temporary.
991 // To save time here, we only set value instead of allocating new
993 // This give an HUGE performance improvement
994 // all allocation done in the LttngTrace constructor
996 eventTimestamp
.setValue(jniEvent
.getEventTime().getTime());
997 eventSource
.setSourceId(jniEvent
.requestEventSource());
999 eventType
= traceTypes
.get(EventTypeKey
.getEventTypeHash(jniEvent
));
1001 eventReference
.setValue(jniEvent
.getParentTracefile().getTracefilePath());
1002 eventReference
.setTracepath(this.getName());
1004 eventContent
.emptyContent();
1006 currentLttngEvent
.setType(eventType
);
1007 // Save the jni reference
1008 currentLttngEvent
.updateJniEventReference(jniEvent
);
1010 // Parse now if was asked
1011 // Warning : THIS IS SLOW
1012 if (isParsingNeeded
) {
1013 eventContent
.getFields();
1016 return currentLttngEvent
;
1018 return convertJniEventToTmfMultipleEventEvilFix(jniEvent
, isParsingNeeded
);
1024 * This method is a temporary fix to support multiple events at once in TMF This is expected to be slow and should
1025 * be fixed in another way. See comment in convertJniEventToTmf();
1028 * The current JNI Event
1029 * @return Current Lttng Event fully parsed
1031 private synchronized LttngEvent
convertJniEventToTmfMultipleEventEvilFix(JniEvent jniEvent
, boolean isParsingNeeded
) {
1033 // Below : the "fix" with all the new and the full-parse
1034 // Allocating new memory is slow.
1035 // Parsing every events is very slow.
1036 eventTimestamp
= new LttngTimestamp(jniEvent
.getEventTime().getTime());
1037 eventSource
= new LttngEventSource(jniEvent
.requestEventSource());
1038 eventReference
= new LttngEventReference(jniEvent
.getParentTracefile().getTracefilePath(), this.getName());
1039 eventType
= new LttngEventType(traceTypes
.get(EventTypeKey
.getEventTypeHash(jniEvent
)));
1040 eventContent
= new LttngEventContent(currentLttngEvent
);
1041 currentLttngEvent
= new LttngEvent(this, eventTimestamp
, eventSource
, eventType
, eventContent
, eventReference
,
1044 // The jni reference is no longer reliable but we will keep it anyhow
1045 currentLttngEvent
.updateJniEventReference(jniEvent
);
1046 // Ensure that the content is correctly set
1047 eventContent
.setEvent(currentLttngEvent
);
1049 // Parse the event if it was needed
1051 // ONLY for testing, NOT parsing events with non-unique events WILL
1052 // result in segfault in the JVM
1053 if (isParsingNeeded
) {
1054 eventContent
.getFields();
1057 return currentLttngEvent
;
1061 * Reference to the current LttngTrace we are reading from.
1064 * Note : This bypass the framework and should not be use, except for testing!
1066 * @return Reference to the current LttngTrace
1068 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniTrace
1070 public JniTrace
getCurrentJniTrace() {
1071 return currentJniTrace
;
1075 * Return a reference to the current LttngEvent we have in memory.
1077 * @return The current (last read) LttngEvent
1079 * @see org.eclipse.linuxtools.lttng.event.LttngEvent
1081 public synchronized LttngEvent
getCurrentEvent() {
1082 return currentLttngEvent
;
1086 * Get the major version number for the current trace
1088 * @return Version major or -1 if unknown
1090 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniTrace
1093 public short getVersionMajor() {
1094 if (currentJniTrace
!= null) {
1095 return currentJniTrace
.getLttMajorVersion();
1102 * Get the minor version number for the current trace
1104 * @return Version minor or -1 if unknown
1106 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniTrace
1109 public short getVersionMinor() {
1110 if (currentJniTrace
!= null) {
1111 return currentJniTrace
.getLttMinorVersion();
1118 * Get the number of CPU for this trace
1120 * @return Number of CPU or -1 if unknown
1122 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniTrace
1125 public int getCpuNumber() {
1126 if (currentJniTrace
!= null) {
1127 return currentJniTrace
.getCpuNumber();
1134 * Print the content of the checkpoint vector.
1137 * This is intended for debug purpose only.
1139 public void printCheckpointsVector() {
1140 System
.out
.println("StartTime : " //$NON-NLS-1$
1141 + getTimeRange().getStartTime().getValue());
1142 System
.out
.println("EndTime : " //$NON-NLS-1$
1143 + getTimeRange().getEndTime().getValue());
1145 for (int pos
= 0; pos
< fCheckpoints
.size(); pos
++) {
1146 System
.out
.print(pos
+ ": " + "\t"); //$NON-NLS-1$ //$NON-NLS-2$
1147 System
.out
.print(fCheckpoints
.get(pos
).getTimestamp() + "\t"); //$NON-NLS-1$
1148 System
.out
.println(fCheckpoints
.get(pos
).getLocation());
1153 public synchronized void dispose() {
1154 if (currentJniTrace
!= null)
1155 currentJniTrace
.closeTrace();
1160 * Return a String identifying this trace.
1162 * @return String that identify this trace
1165 @SuppressWarnings("nls")
1166 public String
toString() {
1167 String returnedData
= "";
1169 returnedData
+= "Path :" + getPath() + " ";
1170 returnedData
+= "Trace:" + currentJniTrace
+ " ";
1171 returnedData
+= "Event:" + currentLttngEvent
;
1173 return returnedData
;
1179 * EventTypeKey inner class
1181 * This class is used to make the process of generating the HashMap key more transparent and so less error prone to use
1183 final class EventTypeKey
{
1185 // These two getEventTypeKey() functions should ALWAYS construct the key the
1187 // Otherwise, every type search will fail!
1189 // added final to encourage inlining.
1191 // generating a hash code by hand to avoid a string creation
1192 final static public int getEventTypeHash(LttngEventType newEventType
) {
1193 return generateHash(newEventType
.getTracefileName(), newEventType
.getCpuId(), newEventType
.getMarkerName());
1196 final private static int generateHash(String traceFileName
, long cpuNumber
, String markerName
) {
1197 // 0x1337 is a prime number. The number of CPUs is always under 8192 on
1198 // the current kernel, so this will work with the current linux kernel.
1199 int cpuHash
= (int) (cpuNumber
* (0x1337));
1200 return traceFileName
.hashCode() ^
(cpuHash
) ^ markerName
.hashCode();
1203 // generating a hash code by hand to avoid a string creation
1204 final static public int getEventTypeHash(JniEvent newEvent
) {
1205 return generateHash(newEvent
.getParentTracefile().getTracefileName(), newEvent
.getParentTracefile()
1206 .getCpuNumber(), newEvent
.requestEventMarker().getName());