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
);
131 // Verify that all those "default constructor" are safe to use
132 eventTimestamp
= new LttngTimestamp();
133 eventSource
= new LttngEventSource();
134 this.eventType
= new LttngEventType();
135 eventContent
= new LttngEventContent(currentLttngEvent
);
136 eventReference
= new LttngEventReference(this.getName());
138 // Create the skeleton event
139 currentLttngEvent
= new LttngEvent(this, eventTimestamp
, eventSource
, this.eventType
, eventContent
,
140 eventReference
, null);
142 // Create a new current location
143 previousLocation
= new LttngLocation();
145 // Set the currentEvent to the eventContent
146 eventContent
.setEvent(currentLttngEvent
);
148 // // Bypass indexing if asked
149 // if ( bypassIndexing == false ) {
153 // Even if we don't have any index, set ONE checkpoint
154 // fCheckpoints.add(new TmfCheckpoint(new LttngTimestamp(0L) , new
155 // LttngLocation() ) );
157 // Set the time range of the trace
158 TmfContext context
= seekLocation(null);
159 LttngEvent event
= getNextEvent(context
);
160 LttngTimestamp startTime
= new LttngTimestamp(event
.getTimestamp());
161 LttngTimestamp endTime
= new LttngTimestamp(currentJniTrace
.getEndTime().getTime());
163 setTimeRange(new TmfTimeRange(startTime
, endTime
));
167 * Default Constructor.
171 * Path to a <b>directory</b> that contain an LTTng trace.
173 * @exception Exception
174 * (most likely LTTngTraceException or FileNotFoundException)
176 public LTTngTrace(String path
) throws Exception
{
177 // Call with "wait for completion" true and "skip indexing" false
178 this(path
, null, true, false);
182 * Constructor, with control over the indexing.
186 * Path to a <b>directory</b> that contain an LTTng trace.
187 * @param waitForCompletion
188 * Should we wait for indexign to complete before moving on.
190 * @exception Exception
191 * (most likely LTTngTraceException or FileNotFoundException)
193 public LTTngTrace(String path
, boolean waitForCompletion
) throws Exception
{
194 // Call with "skip indexing" false
195 this(path
, null, waitForCompletion
, false);
199 * Default constructor, with control over the indexing and possibility to bypass indexation
203 * Path to a <b>directory</b> that contain an LTTng trace.
204 * @param traceLibPath
205 * Path to a <b>directory</b> that contains LTTng trace libraries.
206 * @param waitForCompletion
207 * Should we wait for indexign to complete before moving on.
208 * @param bypassIndexing
209 * Should we bypass indexing completly? This is should only be useful for unit testing.
211 * @exception Exception
212 * (most likely LTTngTraceException or FileNotFoundException)
215 public LTTngTrace(String path
, String traceLibPath
, boolean waitForCompletion
, boolean bypassIndexing
)
217 super(path
, LttngEvent
.class, path
, CHECKPOINT_PAGE_SIZE
, false);
219 currentJniTrace
= JniTraceFactory
.getJniTrace(path
, traceLibPath
, SHOW_LTT_DEBUG_DEFAULT
);
220 } catch (Exception e
) {
221 throw new FileNotFoundException(e
.getMessage());
224 this.traceLibPath
= traceLibPath
;
225 // Export all the event types from the JNI side
226 traceTypes
= new HashMap
<Integer
, LttngEventType
>();
227 traceTypeNames
= new Vector
<Integer
>();
228 initialiseEventTypes(currentJniTrace
);
231 // Verify that all those "default constructor" are safe to use
232 eventTimestamp
= new LttngTimestamp();
233 eventSource
= new LttngEventSource();
234 eventType
= new LttngEventType();
235 eventContent
= new LttngEventContent(currentLttngEvent
);
236 eventReference
= new LttngEventReference(this.getName());
238 // Create the skeleton event
239 currentLttngEvent
= new LttngEvent(this, eventTimestamp
, eventSource
, eventType
, eventContent
, eventReference
,
242 // Create a new current location
243 previousLocation
= new LttngLocation();
245 // Set the currentEvent to the eventContent
246 eventContent
.setEvent(currentLttngEvent
);
248 // // Bypass indexing if asked
249 // if ( bypassIndexing == false ) {
253 // Even if we don't have any index, set ONE checkpoint
254 // fCheckpoints.add(new TmfCheckpoint(new LttngTimestamp(0L) , new
255 // LttngLocation() ) );
257 // Set the time range of the trace
258 TmfContext context
= seekLocation(null);
259 LttngEvent event
= getNextEvent(context
);
260 LttngTimestamp startTime
= new LttngTimestamp(event
.getTimestamp());
261 LttngTimestamp endTime
= new LttngTimestamp(currentJniTrace
.getEndTime().getTime());
263 setTimeRange(new TmfTimeRange(startTime
, endTime
));
267 * Copy constructor is forbidden for LttngEvenmStream
269 public LTTngTrace(LTTngTrace oldTrace
) throws Exception
{
270 this(oldTrace
.getPath(), oldTrace
.getTraceLibPath(), false, true);
274 this.fCheckpoints
= oldTrace
.fCheckpoints
;
277 * // This would only work if the index is already done this.fCheckpoints = new Vector<TmfCheckpoint>(
278 * oldTrace.fCheckpoints.size() ); for (int x = 0; x<oldTrace.fCheckpoints.size(); x++){ TmfCheckpoint
279 * tmpCheckPoint = oldTrace.fCheckpoints.get(x); this.fCheckpoints.add( new
280 * TmfCheckpoint(tmpCheckPoint.getTimestamp(), tmpCheckPoint.getLocation()) ); }
283 // Set the start time of the trace
284 setTimeRange(new TmfTimeRange(new LttngTimestamp(oldTrace
.getStartTime()), new LttngTimestamp(
285 oldTrace
.getEndTime())));
289 public LTTngTrace
copy() {
290 LTTngTrace returnedTrace
= null;
293 returnedTrace
= new LTTngTrace(this);
294 } catch (Exception e
) {
296 .println("ERROR : Could not create LTTngTrace copy (createTraceCopy).\nError is : " + e
.getStackTrace()); //$NON-NLS-1$
299 return returnedTrace
;
303 public synchronized LTTngTrace
clone() {
304 LTTngTrace clone
= null;
306 clone
= (LTTngTrace
) super.clone();
308 clone
.currentJniTrace
= JniTraceFactory
.getJniTrace(getPath(), getTraceLibPath(),
309 SHOW_LTT_DEBUG_DEFAULT
);
310 } catch (JniException e
) {
311 // e.printStackTrace();
314 // Export all the event types from the JNI side
315 clone
.traceTypes
= new HashMap
<Integer
, LttngEventType
>();
316 clone
.traceTypeNames
= new Vector
<Integer
>();
317 clone
.initialiseEventTypes(clone
.currentJniTrace
);
319 // Verify that all those "default constructor" are safe to use
320 clone
.eventTimestamp
= new LttngTimestamp();
321 clone
.eventSource
= new LttngEventSource();
322 clone
.eventType
= new LttngEventType();
323 clone
.eventContent
= new LttngEventContent(clone
.currentLttngEvent
);
324 clone
.eventReference
= new LttngEventReference(this.getName());
326 // Create the skeleton event
327 clone
.currentLttngEvent
= new LttngEvent(this, clone
.eventTimestamp
, clone
.eventSource
, clone
.eventType
,
328 clone
.eventContent
, clone
.eventReference
, null);
330 // Create a new current location
331 clone
.previousLocation
= new LttngLocation();
333 // Set the currentEvent to the eventContent
334 clone
.eventContent
.setEvent(clone
.currentLttngEvent
);
336 // Set the start time of the trace
337 setTimeRange(new TmfTimeRange(new LttngTimestamp(clone
.currentJniTrace
.getStartTime().getTime()),
338 new LttngTimestamp(clone
.currentJniTrace
.getEndTime().getTime())));
339 } catch (CloneNotSupportedException e
) {
345 public String
getTraceLibPath() {
350 * Fill out the HashMap with "Type" (Tracefile/Marker)
352 * This should be called at construction once the trace is open
354 private void initialiseEventTypes(JniTrace trace
) {
356 LttngEventType tmpType
= null;
357 String
[] markerFieldsLabels
= null;
359 String newTracefileKey
= null;
360 Integer newMarkerKey
= null;
362 JniTracefile newTracefile
= null;
363 JniMarker newMarker
= null;
365 // First, obtain an iterator on TRACEFILES of owned by the TRACE
366 Iterator
<String
> tracefileItr
= trace
.getTracefilesMap().keySet().iterator();
368 while (tracefileItr
.hasNext()) {
369 newTracefileKey
= tracefileItr
.next();
370 newTracefile
= trace
.getTracefilesMap().get(newTracefileKey
);
372 // From the TRACEFILE read, obtain its MARKER
373 Iterator
<Integer
> markerItr
= newTracefile
.getTracefileMarkersMap().keySet().iterator();
374 while (markerItr
.hasNext()) {
375 newMarkerKey
= markerItr
.next();
376 newMarker
= newTracefile
.getTracefileMarkersMap().get(newMarkerKey
);
378 // From the MARKER we can obtain the MARKERFIELDS keys (i.e.
380 markerFieldsLabels
= newMarker
.getMarkerFieldsHashMap().keySet()
381 .toArray(new String
[newMarker
.getMarkerFieldsHashMap().size()]);
383 tmpType
= new LttngEventType(newTracefile
.getTracefileName(), newTracefile
.getCpuNumber(),
384 newMarker
.getName(), newMarkerKey
.intValue(), markerFieldsLabels
);
386 // Add the type to the map/vector
387 addEventTypeToMap(tmpType
);
393 * Add a new type to the HashMap
395 * As the hashmap use a key format that is a bit dangerous to use, we should always add using this function.
397 private void addEventTypeToMap(LttngEventType newEventType
) {
398 int newTypeKey
= EventTypeKey
.getEventTypeHash(newEventType
);
400 this.traceTypes
.put(newTypeKey
, newEventType
);
401 this.traceTypeNames
.add(newTypeKey
);
405 // * Index the current trace.
407 // * @param useless This boolean is only to comply to the interface and will
411 // public synchronized void indexTrace(boolean useless) {
415 // // Start time need to be null to detect none have been set
416 // // LastTime need to exist so we can ajust it as we go
417 // LttngTimestamp startTime = null;
418 // LttngTimestamp lastTime = new LttngTimestamp();
420 // // Position the trace at the beginning
421 // TmfContext context = seekEvent( new LttngTimestamp(0L) );
423 // // Read the first event and extract the location
424 // LttngEvent tmpEvent = (LttngEvent)getNextEvent(context);
426 // // If we read the first event, define the start time.
427 // if ( tmpEvent != null ) {
428 // startTime = new LttngTimestamp( tmpEvent.getTimestamp() );
429 // lastTime.setValue(tmpEvent.getTimestamp().getValue());
432 // // Now, we read each event until we hit the end of the trace
433 // // We will create a new checkpoint every "getCacheSize()" event
434 // while ( tmpEvent != null) {
435 // // Update the last time each time we read a new event
436 // lastTime.setValue(tmpEvent.getTimestamp().getValue());
438 // // Save a check point if needed
439 // if ((nbEvents++ % getCacheSize()) == 0) {
441 // // We need to NEW each stuff we put in checkpoint
442 // // Otherwise everything will be the same!
443 // LttngTimestamp tmpTimestamp = new LttngTimestamp(
444 // (LttngTimestamp)tmpEvent.getTimestamp() );
445 // LttngLocation newLocation = new LttngLocation(
446 // (LttngTimestamp)tmpEvent.getTimestamp() );
448 // fCheckpoints.add(new TmfCheckpoint(tmpTimestamp, newLocation ) );
450 // // Read the next event
451 // tmpEvent = (LttngEvent)getNextEvent(context);
454 // // If we have a start time, we should have an end time as well
455 // // Issue the new range
456 // if (startTime != null) {
457 // setTimeRange( new TmfTimeRange(startTime, lastTime) );
458 // notifyListeners(getTimeRange() );
461 // // Ajust the total number of event in the trace
462 // fNbEvents = nbEvents;
463 // //printCheckpointsVector();
464 // //printDebug = true;
468 * Return the latest saved location. Note : Modifying the returned location may result in buggy positionning!
470 * @return The LttngLocation as it was after the last operation.
472 * @see org.eclipse.linuxtools.lttng.event.LttngLocation
475 public synchronized ITmfLocation
<?
> getCurrentLocation() {
476 return previousLocation
;
480 * Position the trace to the event at the given location.
482 * NOTE : Seeking by location is very fast compare to seeking by position but is still slower than "ReadNext", avoid
483 * using it for small interval.
486 * Location of the event in the trace. If no event available at this exact location, we will position
487 * ourself to the next one.
489 * @return The TmfContext that point to this event
491 * @see org.eclipse.linuxtools.lttng.event.LttngLocation
492 * @see org.eclipse.linuxtools.tmf.trace.TmfContext
495 public synchronized TmfContext
seekLocation(ITmfLocation
<?
> location
) {
501 System
.out
.println("seekLocation(location) location -> " + location
); //$NON-NLS-1$
504 // If the location in context is null, create a new one
505 LttngLocation curLocation
= null;
506 if (location
== null) {
507 curLocation
= new LttngLocation();
508 TmfContext context
= seekEvent(curLocation
.getOperationTime());
509 context
.setRank(ITmfContext
.INITIAL_RANK
);
512 curLocation
= (LttngLocation
) location
;
516 // Update to location should (and will) be done in SeekEvent.
518 // The only seek valid in LTTng is with the time, we call
519 // seekEvent(timestamp)
520 TmfContext context
= seekEvent(curLocation
.getOperationTime());
522 // // Adjust the previousLocation flags
523 // if (location instanceof LttngLocation) {
524 // LttngLocation lttngLocation = (LttngLocation) location;
525 // if (lttngLocation.isLastOperationReadNext()) {
526 // previousLocation.setLastOperationReadNext();
527 // } else if (lttngLocation.isLastOperationParse()) {
528 // previousLocation.setLastOperationParse();
529 // } else if (lttngLocation.isLastOperationSeek()) {
530 // previousLocation.setLastOperationSeek();
538 * Position the trace to the event at the given time.
540 * NOTE : Seeking by time is very fast compare to seeking by position but is still slower than "ReadNext", avoid
541 * using it for small interval.
544 * Time of the event in the trace. If no event available at this exact time, we will position ourself to
547 * @return The TmfContext that point to this event
549 * @see org.eclipse.linuxtools.lttng.event.LttngLocation
550 * @see org.eclipse.linuxtools.tmf.trace.TmfContext
553 public synchronized TmfContext
seekEvent(TmfTimestamp timestamp
) {
559 System
.out
.println("seekEvent(timestamp) timestamp -> " + timestamp
); //$NON-NLS-1$
563 currentJniTrace
.seekToTime(new JniTime(timestamp
.getValue()));
565 // Save the time at which we seeked
566 previousLocation
.setOperationTime(timestamp
.getValue());
567 // Set the operation marker as seek, to be able to detect we did "seek"
569 previousLocation
.setLastOperationSeek();
572 // Is that too paranoid?
574 // We don't trust what upper level could do with our internal location
575 // so we create a new one to return instead
576 LttngLocation curLocation
= new LttngLocation(previousLocation
);
578 return new TmfContext(curLocation
);
582 * Position the trace to the event at the given position (rank).
584 * NOTE : Seeking by position is very slow in LTTng, consider seeking by timestamp.
587 * Position (or rank) of the event in the trace, starting at 0.
589 * @return The TmfContext that point to this event
591 * @see org.eclipse.linuxtools.lttng.event.LttngLocation
592 * @see org.eclipse.linuxtools.tmf.trace.TmfContext
595 public synchronized TmfContext
seekEvent(long position
) {
598 System
.out
.println("seekEvent(position) position -> " + position
); //$NON-NLS-1$
601 TmfTimestamp timestamp
= null;
602 long index
= position
/ getCacheSize();
604 // Get the timestamp of the closest check point to the given position
605 if (fCheckpoints
.size() > 0) {
606 if (index
>= fCheckpoints
.size()) {
607 index
= fCheckpoints
.size() - 1;
609 timestamp
= fCheckpoints
.elementAt((int) index
).getTimestamp();
611 // If none, take the start time of the trace
613 timestamp
= getStartTime();
616 // Seek to the found time
617 TmfContext tmpContext
= seekEvent(timestamp
);
618 tmpContext
.setRank((index
+ 1) * fIndexPageSize
);
619 previousLocation
= (LttngLocation
) tmpContext
.getLocation();
621 // Ajust the index of the event we found at this check point position
622 Long currentPosition
= index
* getCacheSize();
624 Long lastTimeValueRead
= 0L;
626 // Get the event at current position. This won't move to the next one
627 JniEvent tmpJniEvent
= currentJniTrace
.findNextEvent();
628 // Now that we are positionned at the checkpoint,
629 // we need to "readNext" (Position - CheckpointPosition) times or until
631 while ((tmpJniEvent
!= null) && (currentPosition
< position
)) {
632 tmpJniEvent
= currentJniTrace
.readNextEvent();
636 // If we found our event, save its timestamp
637 if (tmpJniEvent
!= null) {
638 lastTimeValueRead
= tmpJniEvent
.getEventTime().getTime();
641 // Set the operation marker as seek, to be able to detect we did "seek"
643 previousLocation
.setLastOperationSeek();
644 // Save read event time
645 previousLocation
.setOperationTime(lastTimeValueRead
);
648 // Is that too paranoid?
650 // We don't trust what upper level could do with our internal location
651 // so we create a new one to return instead
652 LttngLocation curLocation
= new LttngLocation(previousLocation
);
654 return new TmfContext(curLocation
);
658 public TmfContext
seekLocation(double ratio
) {
659 // TODO Auto-generated method stub
664 public double getLocationRatio(ITmfLocation
<?
> location
) {
665 // TODO Auto-generated method stub
670 * Return the event in the trace according to the given context. Read it if necessary.
672 * Similar (same?) as ParseEvent except that calling GetNext twice read the next one the second time.
675 * Current TmfContext where to get the event
677 * @return The LttngEvent we read of null if no event are available
679 * @see org.eclipse.linuxtools.lttng.event.LttngLocation
680 * @see org.eclipse.linuxtools.tmf.trace.TmfContext
683 public int nbEventsRead
= 0;
686 public synchronized LttngEvent
getNextEvent(TmfContext context
) {
689 System
.out
.println("getNextEvent(context) context.getLocation() -> " //$NON-NLS-1$
690 + context
.getLocation());
693 LttngEvent returnedEvent
= null;
694 LttngLocation curLocation
= null;
696 curLocation
= (LttngLocation
) context
.getLocation();
697 // If the location in context is null, create a new one
698 if (curLocation
== null) {
699 curLocation
= getCurrentLocation(context
);
703 // TmfContext savedContext = context.clone();
707 // TMF assumes it is possible to read (GetNextEvent) to the next Event
708 // once ParseEvent() is called
709 // In LTTNG, there is not difference between "Parsing" and "Reading" an
711 // Since parsing/reading invalidate the previous event,
712 // we need to make sure the sequence ParseEvent() -> GetNextEvent() will
713 // not actually move to the next event.
714 // To do so, we avoid moving for call to "GetNextEvent()" that follow
715 // call to a call to "ParseEvent()".
716 // However, calling ParseEvent() -> GetNextEvent() -> GetNextEvent()
717 // will only move next by one.
719 // *** Positioning trick :
720 // GetNextEvent only read the trace if :
721 // 1- The last operation was NOT a ParseEvent --> A read is required
723 // 2- The time of the previous location is different from the current
724 // one --> A seek + a read is required
725 if ((!(curLocation
.isLastOperationParse()))
726 || (previousLocation
.getOperationTimeValue() != curLocation
.getOperationTimeValue())) {
727 if (previousLocation
.getOperationTimeValue() != curLocation
.getOperationTimeValue()) {
729 System
.out
.println("\t\tSeeking in getNextEvent. [ LastTime : " //$NON-NLS-1$
730 + previousLocation
.getOperationTimeValue() + " CurrentTime" //$NON-NLS-1$
731 + curLocation
.getOperationTimeValue() + " ]"); //$NON-NLS-1$
733 seekEvent(curLocation
.getOperationTime());
735 // Read the next event from the trace. The last one will NO LONGER
737 returnedEvent
= readNextEvent(curLocation
);
740 // No event was read, just return the one currently loaded (the last
742 returnedEvent
= currentLttngEvent
;
745 // Reset (erase) the operation marker to both location, to be able
746 // to detect we did NOT "read" this event
747 previousLocation
.resetLocationState();
748 curLocation
.resetLocationState();
751 // If we read an event, set it's time to the locations (both previous
753 if (returnedEvent
!= null) {
754 setPreviousAndCurrentTimes(context
, returnedEvent
, curLocation
);
757 // LttngLocation prevLocation = (LttngLocation)
758 // savedContext.getLocation();
759 // LttngLocation currLocation = (LttngLocation)
760 // context.getLocation();
761 // if (prevLocation.equals(currLocation)) {
762 // System.out.println("Aie");
764 // Tracer.trace("Trc: " + context.getRank() + ": " +
765 // returnedEvent.getTimestamp().toString() + " (" +
766 // (prevLocation.isLastOperationParse() ? "T" : "F") + "," +
767 // (prevLocation.isLastOperationReadNext() ? "T" : "F") + "," +
768 // (prevLocation.isLastOperationSeek() ? "T" : "F") + "), (" +
769 // (currLocation.isLastOperationParse() ? "T" : "F") + "," +
770 // (currLocation.isLastOperationReadNext() ? "T" : "F") + "," +
771 // (currLocation.isLastOperationSeek() ? "T" : "F") + ")"
777 return returnedEvent
;
780 // this method was extracted for profiling purposes
781 private void setPreviousAndCurrentTimes(TmfContext context
, LttngEvent returnedEvent
, LttngLocation curLocation
) {
783 TmfTimestamp eventTimestamp
= returnedEvent
.getTimestamp();
784 // long eventTime = eventTimestamp.getValue();
785 previousLocation
.setOperationTime(eventTimestamp
.getValue());
786 curLocation
.setOperationTime(eventTimestamp
.getValue());
787 updateIndex(context
, context
.getRank(), eventTimestamp
);
788 context
.updateRank(1);
791 protected void updateIndex(TmfContext context
, long rank
, TmfTimestamp timestamp
) {
793 if (getStartTime().compareTo(timestamp
, false) > 0)
794 setStartTime(timestamp
);
795 if (getEndTime().compareTo(timestamp
, false) < 0)
796 setEndTime(timestamp
);
797 if (rank
!= ITmfContext
.UNKNOWN_RANK
) {
798 if (fNbEvents
<= rank
)
799 fNbEvents
= rank
+ 1;
800 // Build the index as we go along
801 if ((rank
% fIndexPageSize
) == 0) {
802 // Determine the table position
803 long position
= rank
/ fIndexPageSize
;
804 // Add new entry at proper location (if empty)
805 if (fCheckpoints
.size() == position
) {
806 addCheckPoint(context
, timestamp
);
812 private void addCheckPoint(TmfContext context
, TmfTimestamp timestamp
) {
813 ITmfLocation
<?
> location
= context
.getLocation().clone();
814 fCheckpoints
.add(new TmfCheckpoint(timestamp
.clone(), location
));
817 // this method was extracted for profiling purposes
818 private LttngEvent
readNextEvent(LttngLocation curLocation
) {
819 LttngEvent returnedEvent
;
820 // Read the next event from the trace. The last one will NO LONGER BE
822 returnedEvent
= readEvent(curLocation
);
825 // Set the operation marker as read to both location, to be able to
826 // detect we did "read" this event
827 previousLocation
.setLastOperationReadNext();
828 curLocation
.setLastOperationReadNext();
829 return returnedEvent
;
832 // this method was extracted for profiling purposes
833 private LttngLocation
getCurrentLocation(TmfContext context
) {
834 LttngLocation curLocation
;
835 curLocation
= new LttngLocation();
836 context
.setLocation(curLocation
);
841 * Return the event in the trace according to the given context. Read it if necessary.
843 * Similar (same?) as GetNextEvent except that calling ParseEvent twice will return the same event
846 * Current TmfContext where to get the event
848 * @return The LttngEvent we read of null if no event are available
850 * @see org.eclipse.linuxtools.lttng.event.LttngLocation
851 * @see org.eclipse.linuxtools.tmf.trace.TmfContext
854 public synchronized LttngEvent
parseEvent(TmfContext context
) {
857 System
.out
.println("parseEvent(context) context.getLocation() -> " //$NON-NLS-1$
858 + context
.getLocation());
861 LttngEvent returnedEvent
= null;
862 LttngLocation curLocation
= null;
864 // If the location in context is null, create a new one
865 if (context
.getLocation() == null) {
866 curLocation
= new LttngLocation();
867 context
.setLocation(curLocation
);
869 // Otherwise, we use the one in context; it should be a valid
872 curLocation
= (LttngLocation
) context
.getLocation();
876 // TMF assumes it is possible to read (GetNextEvent) to the next Event
877 // once ParseEvent() is called
878 // In LTTNG, there is not difference between "Parsing" and "Reading" an
880 // So, before "Parsing" an event, we have to make sure we didn't "Read"
882 // Also, "Reading" invalidate the previous Event in LTTNG and seek back
884 // so calling twice "Parse" will return the same event, giving a way to
885 // get the "Currently loaded" event
887 // *** Positionning trick :
888 // ParseEvent only read the trace if :
889 // 1- The last operation was NOT a ParseEvent or a GetNextEvent --> A
892 // 2- The time of the previous location is different from the current
893 // one --> A seek + a read is required
894 if (((!(curLocation
.isLastOperationParse())) && ((!(curLocation
.isLastOperationReadNext()))))
895 || (previousLocation
.getOperationTimeValue() != curLocation
.getOperationTimeValue())) {
896 // Previous time != Current time : We need to reposition to the
898 if (previousLocation
.getOperationTimeValue() != curLocation
.getOperationTimeValue()) {
900 System
.out
.println("\t\tSeeking in getNextEvent. [ LastTime : " //$NON-NLS-1$
901 + previousLocation
.getOperationTimeValue() + " CurrentTime" //$NON-NLS-1$
902 + curLocation
.getOperationTimeValue() + " ]"); //$NON-NLS-1$
904 seekEvent(curLocation
.getOperationTime());
907 // Read the next event from the trace. The last one will NO LONGER
909 returnedEvent
= readEvent(curLocation
);
911 // No event was read, just return the one currently loaded (the last
913 returnedEvent
= currentLttngEvent
;
916 // If we read an event, set it's time to the locations (both previous
918 if (returnedEvent
!= null) {
919 previousLocation
.setOperationTime((LttngTimestamp
) returnedEvent
.getTimestamp());
920 curLocation
.setOperationTime((LttngTimestamp
) returnedEvent
.getTimestamp());
923 // Set the operation marker as parse to both location, to be able to
924 // detect we already "read" this event
925 previousLocation
.setLastOperationParse();
926 curLocation
.setLastOperationParse();
928 return returnedEvent
;
932 * Read the next event from the JNI and convert it as Lttng Event<p>
934 * @param location Current LttngLocation that to be updated with the event timestamp
936 * @return The LttngEvent we read of null if no event are available
938 * @see org.eclipse.linuxtools.lttng.event.LttngLocation
940 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniTrace
942 private synchronized LttngEvent
readEvent(LttngLocation location
) {
943 LttngEvent returnedEvent
= null;
944 JniEvent tmpEvent
= null;
946 // Read the next event from JNI. THIS WILL INVALIDATE THE CURRENT LTTNG
948 tmpEvent
= currentJniTrace
.readNextEvent();
950 if (tmpEvent
!= null) {
952 // Convert will update the currentLttngEvent
953 returnedEvent
= convertJniEventToTmf(tmpEvent
);
955 location
.setOperationTime((LttngTimestamp
) returnedEvent
.getTimestamp());
958 // If the read failed (likely the last event in the trace), set the
959 // LastReadTime to the JNI time
960 // That way, even if we try to read again, we will step over the bogus
963 location
.setOperationTime(getEndTime().getValue() + 1);
966 return returnedEvent
;
970 * Method to convert a JniEvent into a LttngEvent.
973 * Note : This method will call LttngEvent convertEventJniToTmf(JniEvent, boolean) with a default value for
977 * The JniEvent to convert into LttngEvent
979 * @return The converted LttngEvent
981 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniEvent
982 * @see org.eclipse.linuxtools.lttng.event.LttngEvent
984 public synchronized LttngEvent
convertJniEventToTmf(JniEvent newEvent
) {
985 currentLttngEvent
= convertJniEventToTmf(newEvent
, IS_PARSING_NEEDED_DEFAULT
);
987 return currentLttngEvent
;
991 * Method to convert a JniEvent into a LttngEvent
994 * The JniEvent to convert into LttngEvent
995 * @param isParsingNeeded
996 * A boolean value telling if the event should be parsed or not.
998 * @return The converted LttngEvent
1000 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniEvent
1001 * @see org.eclipse.linuxtools.lttng.event.LttngEvent
1003 public synchronized LttngEvent
convertJniEventToTmf(JniEvent jniEvent
, boolean isParsingNeeded
) {
1008 // UNHACKED : We can no longer do that because TCF need to maintain
1009 // several events at once.
1010 // This is very slow to do so in LTTng, this has to be temporary.
1012 // To save time here, we only set value instead of allocating new
1014 // This give an HUGE performance improvement
1015 // all allocation done in the LttngTrace constructor
1017 eventTimestamp
.setValue(jniEvent
.getEventTime().getTime());
1018 eventSource
.setSourceId(jniEvent
.requestEventSource());
1020 eventType
= traceTypes
.get(EventTypeKey
.getEventTypeHash(jniEvent
));
1022 eventReference
.setValue(jniEvent
.getParentTracefile().getTracefilePath());
1023 eventReference
.setTracepath(this.getName());
1025 eventContent
.emptyContent();
1027 currentLttngEvent
.setType(eventType
);
1028 // Save the jni reference
1029 currentLttngEvent
.updateJniEventReference(jniEvent
);
1031 // Parse now if was asked
1032 // Warning : THIS IS SLOW
1033 if (isParsingNeeded
) {
1034 eventContent
.getFields();
1037 return currentLttngEvent
;
1039 return convertJniEventToTmfMultipleEventEvilFix(jniEvent
, isParsingNeeded
);
1045 * This method is a temporary fix to support multiple events at once in TMF This is expected to be slow and should
1046 * be fixed in another way. See comment in convertJniEventToTmf();
1049 * The current JNI Event
1050 * @return Current Lttng Event fully parsed
1052 private synchronized LttngEvent
convertJniEventToTmfMultipleEventEvilFix(JniEvent jniEvent
, boolean isParsingNeeded
) {
1054 // Below : the "fix" with all the new and the full-parse
1055 // Allocating new memory is slow.
1056 // Parsing every events is very slow.
1057 eventTimestamp
= new LttngTimestamp(jniEvent
.getEventTime().getTime());
1058 eventSource
= new LttngEventSource(jniEvent
.requestEventSource());
1059 eventReference
= new LttngEventReference(jniEvent
.getParentTracefile().getTracefilePath(), this.getName());
1060 eventType
= new LttngEventType(traceTypes
.get(EventTypeKey
.getEventTypeHash(jniEvent
)));
1061 eventContent
= new LttngEventContent(currentLttngEvent
);
1062 currentLttngEvent
= new LttngEvent(this, eventTimestamp
, eventSource
, eventType
, eventContent
, eventReference
,
1065 // The jni reference is no longer reliable but we will keep it anyhow
1066 currentLttngEvent
.updateJniEventReference(jniEvent
);
1067 // Ensure that the content is correctly set
1068 eventContent
.setEvent(currentLttngEvent
);
1070 // Parse the event if it was needed
1072 // ONLY for testing, NOT parsing events with non-unique events WILL
1073 // result in segfault in the JVM
1074 if (isParsingNeeded
) {
1075 eventContent
.getFields();
1078 return currentLttngEvent
;
1082 * Reference to the current LttngTrace we are reading from.
1085 * Note : This bypass the framework and should not be use, except for testing!
1087 * @return Reference to the current LttngTrace
1089 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniTrace
1091 public JniTrace
getCurrentJniTrace() {
1092 return currentJniTrace
;
1096 * Return a reference to the current LttngEvent we have in memory.
1098 * @return The current (last read) LttngEvent
1100 * @see org.eclipse.linuxtools.lttng.event.LttngEvent
1102 public synchronized LttngEvent
getCurrentEvent() {
1103 return currentLttngEvent
;
1107 * Get the major version number for the current trace
1109 * @return Version major or -1 if unknown
1111 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniTrace
1114 public short getVersionMajor() {
1115 if (currentJniTrace
!= null) {
1116 return currentJniTrace
.getLttMajorVersion();
1123 * Get the minor version number for the current trace
1125 * @return Version minor or -1 if unknown
1127 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniTrace
1130 public short getVersionMinor() {
1131 if (currentJniTrace
!= null) {
1132 return currentJniTrace
.getLttMinorVersion();
1139 * Get the number of CPU for this trace
1141 * @return Number of CPU or -1 if unknown
1143 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniTrace
1146 public int getCpuNumber() {
1147 if (currentJniTrace
!= null) {
1148 return currentJniTrace
.getCpuNumber();
1155 * Print the content of the checkpoint vector.
1158 * This is intended for debug purpose only.
1160 public void printCheckpointsVector() {
1161 System
.out
.println("StartTime : " //$NON-NLS-1$
1162 + getTimeRange().getStartTime().getValue());
1163 System
.out
.println("EndTime : " //$NON-NLS-1$
1164 + getTimeRange().getEndTime().getValue());
1166 for (int pos
= 0; pos
< fCheckpoints
.size(); pos
++) {
1167 System
.out
.print(pos
+ ": " + "\t"); //$NON-NLS-1$ //$NON-NLS-2$
1168 System
.out
.print(fCheckpoints
.get(pos
).getTimestamp() + "\t"); //$NON-NLS-1$
1169 System
.out
.println(fCheckpoints
.get(pos
).getLocation());
1174 public synchronized void dispose() {
1175 if (currentJniTrace
!= null)
1176 currentJniTrace
.closeTrace();
1181 * Return a String identifying this trace.
1183 * @return String that identify this trace
1186 @SuppressWarnings("nls")
1187 public String
toString() {
1188 String returnedData
= "";
1190 returnedData
+= "Path :" + getPath() + " ";
1191 returnedData
+= "Trace:" + currentJniTrace
+ " ";
1192 returnedData
+= "Event:" + currentLttngEvent
;
1194 return returnedData
;
1200 * EventTypeKey inner class
1202 * This class is used to make the process of generating the HashMap key more transparent and so less error prone to use
1204 final class EventTypeKey
{
1206 // These two getEventTypeKey() functions should ALWAYS construct the key the
1208 // Otherwise, every type search will fail!
1210 // added final to encourage inlining.
1212 // generating a hash code by hand to avoid a string creation
1213 final static public int getEventTypeHash(LttngEventType newEventType
) {
1214 return generateHash(newEventType
.getTracefileName(), newEventType
.getCpuId(), newEventType
.getMarkerName());
1217 final private static int generateHash(String traceFileName
, long cpuNumber
, String markerName
) {
1218 // 0x1337 is a prime number. The number of CPUs is always under 8192 on
1219 // the current kernel, so this will work with the current linux kernel.
1220 int cpuHash
= (int) (cpuNumber
* (0x1337));
1221 return traceFileName
.hashCode() ^
(cpuHash
) ^ markerName
.hashCode();
1224 // generating a hash code by hand to avoid a string creation
1225 final static public int getEventTypeHash(JniEvent newEvent
) {
1226 return generateHash(newEvent
.getParentTracefile().getTracefileName(), newEvent
.getParentTracefile()
1227 .getCpuNumber(), newEvent
.requestEventMarker().getName());