1 /*******************************************************************************
2 * Copyright (c) 2009 Ericsson
4 * All rights reserved. This program and the accompanying materials are
5 * made available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * William Bourque (wbourque@gmail.com) - Initial API and implementation
11 *******************************************************************************/
13 package org
.eclipse
.linuxtools
.lttng
.trace
;
15 import java
.util
.HashMap
;
16 import java
.util
.Iterator
;
17 import java
.util
.Vector
;
19 import org
.eclipse
.linuxtools
.lttng
.LttngException
;
20 import org
.eclipse
.linuxtools
.lttng
.event
.LttngEvent
;
21 import org
.eclipse
.linuxtools
.lttng
.event
.LttngEventContent
;
22 import org
.eclipse
.linuxtools
.lttng
.event
.LttngEventReference
;
23 import org
.eclipse
.linuxtools
.lttng
.event
.LttngEventSource
;
24 import org
.eclipse
.linuxtools
.lttng
.event
.LttngEventType
;
25 import org
.eclipse
.linuxtools
.lttng
.event
.LttngLocation
;
26 import org
.eclipse
.linuxtools
.lttng
.event
.LttngTimestamp
;
27 import org
.eclipse
.linuxtools
.lttng
.jni
.JniEvent
;
28 import org
.eclipse
.linuxtools
.lttng
.jni
.JniMarker
;
29 import org
.eclipse
.linuxtools
.lttng
.jni
.JniTrace
;
30 import org
.eclipse
.linuxtools
.lttng
.jni
.JniTracefile
;
31 import org
.eclipse
.linuxtools
.lttng
.jni
.common
.JniTime
;
32 import org
.eclipse
.linuxtools
.lttng
.jni
.exception
.JniException
;
33 import org
.eclipse
.linuxtools
.lttng
.jni
.factory
.JniTraceFactory
;
34 import org
.eclipse
.linuxtools
.tmf
.event
.TmfTimeRange
;
35 import org
.eclipse
.linuxtools
.tmf
.event
.TmfTimestamp
;
36 import org
.eclipse
.linuxtools
.tmf
.trace
.ITmfContext
;
37 import org
.eclipse
.linuxtools
.tmf
.trace
.ITmfLocation
;
38 import org
.eclipse
.linuxtools
.tmf
.trace
.TmfCheckpoint
;
39 import org
.eclipse
.linuxtools
.tmf
.trace
.TmfContext
;
40 import org
.eclipse
.linuxtools
.tmf
.trace
.TmfTrace
;
42 class LTTngTraceException
extends LttngException
{
43 static final long serialVersionUID
= -1636648737081868146L;
45 public LTTngTraceException(String errMsg
) {
51 * <b><u>LTTngTrace</u></b>
54 * LTTng trace implementation. It accesses the C trace handling library
55 * (seeking, reading and parsing) through the JNI component.
57 public class LTTngTrace
extends TmfTrace
<LttngEvent
> {
59 public static boolean PrintDebug
= false;
60 public static boolean UniqueEvent
= true;
62 private final static boolean SHOW_LTT_DEBUG_DEFAULT
= false;
63 private final static boolean IS_PARSING_NEEDED_DEFAULT
= !UniqueEvent
;
64 private final static int CHECKPOINT_PAGE_SIZE
= 1000;
66 // Reference to our JNI trace
67 private JniTrace currentJniTrace
= null;
70 // UNHACKED : We can no longer do that because TCF need to maintain several
72 // This is very slow to do so in LTTng, this has to be temporary.
74 // To save time, we will declare all component of the LttngEvent during the
75 // construction of the trace
76 // Then, while reading the trace, we will just SET the values instead of
77 // declaring new object
79 LttngTimestamp eventTimestamp
= null;
80 LttngEventSource eventSource
= null;
81 LttngEventContent eventContent
= null;
82 LttngEventReference eventReference
= null;
85 LttngEvent currentLttngEvent
= null;
87 // The current location
88 LttngLocation previousLocation
= null;
90 LttngEventType eventType
= null;
91 // Hashmap of the possible types of events (Tracefile/CPU/Marker in the JNI)
92 HashMap
<Integer
, LttngEventType
> traceTypes
= null;
93 // This vector will be used to quickly find a marker name from a position
94 Vector
<Integer
> traceTypeNames
= null;
97 * Default Constructor.
101 * Path to a <b>directory</b> that contain an LTTng trace.
103 * @exception Exception
104 * (most likely LTTngTraceException or FileNotFoundException)
106 public LTTngTrace(String path
) throws Exception
{
107 // Call with "wait for completion" true and "skip indexing" false
108 this(path
, true, false);
112 * Constructor, with control over the indexing.
116 * Path to a <b>directory</b> that contain an LTTng trace.
117 * @param waitForCompletion
118 * Should we wait for indexign to complete before moving on.
120 * @exception Exception
121 * (most likely LTTngTraceException or FileNotFoundException)
123 public LTTngTrace(String path
, boolean waitForCompletion
) throws Exception
{
124 // Call with "skip indexing" false
125 this(path
, waitForCompletion
, false);
129 * Default constructor, with control over the indexing and possibility to
134 * Path to a <b>directory</b> that contain an LTTng trace.
135 * @param waitForCompletion
136 * Should we wait for indexign to complete before moving on.
137 * @param bypassIndexing
138 * Should we bypass indexing completly? This is should only be
139 * useful for unit testing.
141 * @exception Exception
142 * (most likely LTTngTraceException or FileNotFoundException)
145 public LTTngTrace(String path
, boolean waitForCompletion
,
146 boolean bypassIndexing
) throws Exception
{
147 super(path
, LttngEvent
.class, path
, CHECKPOINT_PAGE_SIZE
);
149 currentJniTrace
= JniTraceFactory
.getJniTrace(path
,
150 SHOW_LTT_DEBUG_DEFAULT
);
151 } catch (Exception e
) {
152 throw new LTTngTraceException(e
.getMessage());
155 // Export all the event types from the JNI side
156 traceTypes
= new HashMap
<Integer
, LttngEventType
>();
157 traceTypeNames
= new Vector
<Integer
>();
158 initialiseEventTypes(currentJniTrace
);
161 // Verify that all those "default constructor" are safe to use
162 eventTimestamp
= new LttngTimestamp();
163 eventSource
= new LttngEventSource();
164 eventType
= new LttngEventType();
165 eventContent
= new LttngEventContent(currentLttngEvent
);
166 eventReference
= new LttngEventReference(this.getName());
168 // Create the skeleton event
169 currentLttngEvent
= new LttngEvent(this, eventTimestamp
, eventSource
,
170 eventType
, eventContent
, eventReference
, null);
172 // Create a new current location
173 previousLocation
= new LttngLocation();
175 // Set the currentEvent to the eventContent
176 eventContent
.setEvent(currentLttngEvent
);
178 // // Bypass indexing if asked
179 // if ( bypassIndexing == false ) {
183 // Even if we don't have any index, set ONE checkpoint
184 // fCheckpoints.add(new TmfCheckpoint(new LttngTimestamp(0L) , new
185 // LttngLocation() ) );
187 // Set the time range of the trace
188 TmfContext context
= seekLocation(null);
189 LttngEvent event
= getNextEvent(context
);
190 LttngTimestamp startTime
= new LttngTimestamp(event
.getTimestamp());
191 LttngTimestamp endTime
= new LttngTimestamp(currentJniTrace
192 .getEndTime().getTime());
194 setTimeRange(new TmfTimeRange(startTime
, endTime
));
199 * Copy constructor is forbidden for LttngEvenmStream
201 public LTTngTrace(LTTngTrace oldTrace
) throws Exception
{
202 this(oldTrace
.getPath(), false, true);
206 this.fCheckpoints
= oldTrace
.fCheckpoints
;
209 * // This would only work if the index is already done
210 * this.fCheckpoints = new Vector<TmfCheckpoint>(
211 * oldTrace.fCheckpoints.size() ); for (int x = 0;
212 * x<oldTrace.fCheckpoints.size(); x++){ TmfCheckpoint tmpCheckPoint =
213 * oldTrace.fCheckpoints.get(x); this.fCheckpoints.add( new
214 * TmfCheckpoint(tmpCheckPoint.getTimestamp(),
215 * tmpCheckPoint.getLocation()) ); }
218 // Set the start time of the trace
219 setTimeRange(new TmfTimeRange(new LttngTimestamp(
220 oldTrace
.getStartTime()), new LttngTimestamp(
221 oldTrace
.getEndTime())));
227 public LTTngTrace
createTraceCopy() {
228 LTTngTrace returnedTrace
= null;
231 returnedTrace
= new LTTngTrace(this);
233 catch (Exception e
) {
234 System
.out
.println("ERROR : Could not create LTTngTrace copy (createTraceCopy).\nError is : " + e
.getStackTrace());
237 return returnedTrace
;
241 public synchronized LTTngTrace
clone() {
242 LTTngTrace clone
= null;
244 clone
= (LTTngTrace
) super.clone();
246 clone
.currentJniTrace
= JniTraceFactory
.getJniTrace(getPath(), SHOW_LTT_DEBUG_DEFAULT
);
247 } catch (JniException e
) {
248 // e.printStackTrace();
251 // Export all the event types from the JNI side
252 clone
.traceTypes
= new HashMap
<Integer
, LttngEventType
>();
253 clone
.traceTypeNames
= new Vector
<Integer
>();
254 clone
.initialiseEventTypes(clone
.currentJniTrace
);
256 // Verify that all those "default constructor" are safe to use
257 clone
.eventTimestamp
= new LttngTimestamp();
258 clone
.eventSource
= new LttngEventSource();
259 clone
.eventType
= new LttngEventType();
260 clone
.eventContent
= new LttngEventContent(clone
.currentLttngEvent
);
261 clone
.eventReference
= new LttngEventReference(this.getName());
263 // Create the skeleton event
264 clone
.currentLttngEvent
= new LttngEvent(this,
265 clone
.eventTimestamp
, clone
.eventSource
, clone
.eventType
,
266 clone
.eventContent
, clone
.eventReference
, null);
268 // Create a new current location
269 clone
.previousLocation
= new LttngLocation();
271 // Set the currentEvent to the eventContent
272 clone
.eventContent
.setEvent(clone
.currentLttngEvent
);
274 // Set the start time of the trace
275 setTimeRange(new TmfTimeRange(new LttngTimestamp(
276 clone
.currentJniTrace
.getStartTime().getTime()),
277 new LttngTimestamp(clone
.currentJniTrace
.getEndTime()
279 } catch (CloneNotSupportedException e
) {
286 * Fill out the HashMap with "Type" (Tracefile/Marker)
288 * This should be called at construction once the trace is open
290 private void initialiseEventTypes(JniTrace trace
) {
292 LttngEventType tmpType
= null;
293 String
[] markerFieldsLabels
= null;
295 String newTracefileKey
= null;
296 Integer newMarkerKey
= null;
298 JniTracefile newTracefile
= null;
299 JniMarker newMarker
= null;
301 // First, obtain an iterator on TRACEFILES of owned by the TRACE
302 Iterator
<String
> tracefileItr
= trace
.getTracefilesMap().keySet()
304 while (tracefileItr
.hasNext()) {
305 newTracefileKey
= tracefileItr
.next();
306 newTracefile
= trace
.getTracefilesMap().get(newTracefileKey
);
308 // From the TRACEFILE read, obtain its MARKER
309 Iterator
<Integer
> markerItr
= newTracefile
.getTracefileMarkersMap()
310 .keySet().iterator();
311 while (markerItr
.hasNext()) {
312 newMarkerKey
= markerItr
.next();
313 newMarker
= newTracefile
.getTracefileMarkersMap().get(
316 // From the MARKER we can obtain the MARKERFIELDS keys (i.e.
318 markerFieldsLabels
= newMarker
319 .getMarkerFieldsHashMap()
322 new String
[newMarker
.getMarkerFieldsHashMap()
324 tmpType
= new LttngEventType(newTracefile
.getTracefileName(),
325 newTracefile
.getCpuNumber(), newMarker
.getName(),
328 // Add the type to the map/vector
329 addEventTypeToMap(tmpType
);
335 * Add a new type to the HashMap
337 * As the hashmap use a key format that is a bit dangerous to use, we should
338 * always add using this function.
340 private void addEventTypeToMap(LttngEventType newEventType
) {
341 int newTypeKey
= EventTypeKey
.getEventTypeHash(newEventType
);
343 this.traceTypes
.put(newTypeKey
, newEventType
);
344 this.traceTypeNames
.add(newTypeKey
);
348 // * Index the current trace.
350 // * @param useless This boolean is only to comply to the interface and will
354 // public synchronized void indexTrace(boolean useless) {
358 // // Start time need to be null to detect none have been set
359 // // LastTime need to exist so we can ajust it as we go
360 // LttngTimestamp startTime = null;
361 // LttngTimestamp lastTime = new LttngTimestamp();
363 // // Position the trace at the beginning
364 // TmfContext context = seekEvent( new LttngTimestamp(0L) );
366 // // Read the first event and extract the location
367 // LttngEvent tmpEvent = (LttngEvent)getNextEvent(context);
369 // // If we read the first event, define the start time.
370 // if ( tmpEvent != null ) {
371 // startTime = new LttngTimestamp( tmpEvent.getTimestamp() );
372 // lastTime.setValue(tmpEvent.getTimestamp().getValue());
375 // // Now, we read each event until we hit the end of the trace
376 // // We will create a new checkpoint every "getCacheSize()" event
377 // while ( tmpEvent != null) {
378 // // Update the last time each time we read a new event
379 // lastTime.setValue(tmpEvent.getTimestamp().getValue());
381 // // Save a check point if needed
382 // if ((nbEvents++ % getCacheSize()) == 0) {
384 // // We need to NEW each stuff we put in checkpoint
385 // // Otherwise everything will be the same!
386 // LttngTimestamp tmpTimestamp = new LttngTimestamp(
387 // (LttngTimestamp)tmpEvent.getTimestamp() );
388 // LttngLocation newLocation = new LttngLocation(
389 // (LttngTimestamp)tmpEvent.getTimestamp() );
391 // fCheckpoints.add(new TmfCheckpoint(tmpTimestamp, newLocation ) );
393 // // Read the next event
394 // tmpEvent = (LttngEvent)getNextEvent(context);
397 // // If we have a start time, we should have an end time as well
398 // // Issue the new range
399 // if (startTime != null) {
400 // setTimeRange( new TmfTimeRange(startTime, lastTime) );
401 // notifyListeners(getTimeRange() );
404 // // Ajust the total number of event in the trace
405 // fNbEvents = nbEvents;
406 // //printCheckpointsVector();
407 // //printDebug = true;
411 * Return the latest saved location. Note : Modifying the returned location
412 * may result in buggy positionning!
414 * @return The LttngLocation as it was after the last operation.
416 * @see org.eclipse.linuxtools.lttng.event.LttngLocation
419 public synchronized ITmfLocation
<?
> getCurrentLocation() {
420 return previousLocation
;
424 * Position the trace to the event at the given location.
426 * NOTE : Seeking by location is very fast compare to seeking by position
427 * but is still slower than "ReadNext", avoid using it for small interval.
430 * Location of the event in the trace. If no event available at
431 * this exact location, we will position ourself to the next one.
433 * @return The TmfContext that point to this event
435 * @see org.eclipse.linuxtools.lttng.event.LttngLocation
436 * @see org.eclipse.linuxtools.tmf.trace.TmfContext
439 public synchronized TmfContext
seekLocation(ITmfLocation
<?
> location
) {
446 .println("seekLocation(location) location -> " + location
);
449 // If the location in context is null, create a new one
450 LttngLocation curLocation
= null;
451 if (location
== null) {
452 curLocation
= new LttngLocation();
453 TmfContext context
= seekEvent(curLocation
.getOperationTime());
454 context
.setRank(ITmfContext
.INITIAL_RANK
);
457 curLocation
= (LttngLocation
) location
;
461 // Update to location should (and will) be done in SeekEvent.
463 // The only seek valid in LTTng is with the time, we call
464 // seekEvent(timestamp)
465 TmfContext context
= seekEvent(curLocation
.getOperationTime());
467 // // Adjust the previousLocation flags
468 // if (location instanceof LttngLocation) {
469 // LttngLocation lttngLocation = (LttngLocation) location;
470 // if (lttngLocation.isLastOperationReadNext()) {
471 // previousLocation.setLastOperationReadNext();
472 // } else if (lttngLocation.isLastOperationParse()) {
473 // previousLocation.setLastOperationParse();
474 // } else if (lttngLocation.isLastOperationSeek()) {
475 // previousLocation.setLastOperationSeek();
483 * Position the trace to the event at the given time.
485 * NOTE : Seeking by time is very fast compare to seeking by position but is
486 * still slower than "ReadNext", avoid using it for small interval.
489 * Time of the event in the trace. If no event available at this
490 * exact time, we will position ourself to the next one.
492 * @return The TmfContext that point to this event
494 * @see org.eclipse.linuxtools.lttng.event.LttngLocation
495 * @see org.eclipse.linuxtools.tmf.trace.TmfContext
498 public synchronized TmfContext
seekEvent(TmfTimestamp timestamp
) {
505 .println("seekEvent(timestamp) timestamp -> " + timestamp
);
509 currentJniTrace
.seekToTime(new JniTime(timestamp
.getValue()));
511 // Save the time at which we seeked
512 previousLocation
.setOperationTime(timestamp
.getValue());
513 // Set the operation marker as seek, to be able to detect we did "seek"
515 previousLocation
.setLastOperationSeek();
518 // Is that too paranoid?
520 // We don't trust what upper level could do with our internal location
521 // so we create a new one to return instead
522 LttngLocation curLocation
= new LttngLocation(previousLocation
);
524 return new TmfContext(curLocation
);
528 * Position the trace to the event at the given position (rank).
530 * NOTE : Seeking by position is very slow in LTTng, consider seeking by
534 * Position (or rank) of the event in the trace, starting at 0.
536 * @return The TmfContext that point to this event
538 * @see org.eclipse.linuxtools.lttng.event.LttngLocation
539 * @see org.eclipse.linuxtools.tmf.trace.TmfContext
542 public synchronized TmfContext
seekEvent(long position
) {
545 System
.out
.println("seekEvent(position) position -> " + position
);
548 TmfTimestamp timestamp
= null;
549 long index
= position
/ getCacheSize();
551 // Get the timestamp of the closest check point to the given position
552 if (fCheckpoints
.size() > 0) {
553 if (index
>= fCheckpoints
.size()) {
554 index
= fCheckpoints
.size() - 1;
556 timestamp
= fCheckpoints
.elementAt((int) index
)
559 // If none, take the start time of the trace
561 timestamp
= getStartTime();
564 // Seek to the found time
565 TmfContext tmpContext
= seekEvent(timestamp
);
566 tmpContext
.setRank((index
+ 1) * fIndexPageSize
);
567 previousLocation
= (LttngLocation
) tmpContext
.getLocation();
569 // Ajust the index of the event we found at this check point position
570 Long currentPosition
= index
* getCacheSize();
572 Long lastTimeValueRead
= 0L;
574 // Get the event at current position. This won't move to the next one
575 JniEvent tmpJniEvent
= currentJniTrace
.findNextEvent();
576 // Now that we are positionned at the checkpoint,
577 // we need to "readNext" (Position - CheckpointPosition) times or until
579 while ((tmpJniEvent
!= null) && (currentPosition
< position
)) {
580 tmpJniEvent
= currentJniTrace
.readNextEvent();
584 // If we found our event, save its timestamp
585 if (tmpJniEvent
!= null) {
586 lastTimeValueRead
= tmpJniEvent
.getEventTime().getTime();
589 // Set the operation marker as seek, to be able to detect we did "seek"
591 previousLocation
.setLastOperationSeek();
592 // Save read event time
593 previousLocation
.setOperationTime(lastTimeValueRead
);
596 // Is that too paranoid?
598 // We don't trust what upper level could do with our internal location
599 // so we create a new one to return instead
600 LttngLocation curLocation
= new LttngLocation(previousLocation
);
602 return new TmfContext(curLocation
);
606 * Return the event in the trace according to the given context. Read it if
609 * Similar (same?) as ParseEvent except that calling GetNext twice read the
610 * next one the second time.
613 * Current TmfContext where to get the event
615 * @return The LttngEvent we read of null if no event are available
617 * @see org.eclipse.linuxtools.lttng.event.LttngLocation
618 * @see org.eclipse.linuxtools.tmf.trace.TmfContext
621 public int nbEventsRead
= 0;
624 public synchronized LttngEvent
getNextEvent(TmfContext context
) {
628 .println("getNextEvent(context) context.getLocation() -> "
629 + context
.getLocation());
632 LttngEvent returnedEvent
= null;
633 LttngLocation curLocation
= null;
635 curLocation
= (LttngLocation
)context
.getLocation();
636 // If the location in context is null, create a new one
637 if ( curLocation
== null ) {
638 curLocation
= getCurrentLocation(context
);
642 // TmfContext savedContext = context.clone();
646 // TMF assumes it is possible to read (GetNextEvent) to the next Event
647 // once ParseEvent() is called
648 // In LTTNG, there is not difference between "Parsing" and "Reading" an
650 // Since parsing/reading invalidate the previous event,
651 // we need to make sure the sequence ParseEvent() -> GetNextEvent() will
652 // not actually move to the next event.
653 // To do so, we avoid moving for call to "GetNextEvent()" that follow
654 // call to a call to "ParseEvent()".
655 // However, calling ParseEvent() -> GetNextEvent() -> GetNextEvent()
656 // will only move next by one.
658 // *** Positioning trick :
659 // GetNextEvent only read the trace if :
660 // 1- The last operation was NOT a ParseEvent --> A read is required
662 // 2- The time of the previous location is different from the current
663 // one --> A seek + a read is required
664 if ((!(curLocation
.isLastOperationParse()))
665 || (previousLocation
.getOperationTimeValue() != curLocation
666 .getOperationTimeValue())) {
667 if (previousLocation
.getOperationTimeValue() != curLocation
668 .getOperationTimeValue()) {
671 .println("\t\tSeeking in getNextEvent. [ LastTime : "
672 + previousLocation
.getOperationTimeValue()
674 + curLocation
.getOperationTimeValue()
677 seekEvent(curLocation
.getOperationTime());
679 // Read the next event from the trace. The last one will NO LONGER
681 returnedEvent
= readNextEvent(curLocation
);
684 // No event was read, just return the one currently loaded (the last
686 returnedEvent
= currentLttngEvent
;
689 // Reset (erase) the operation marker to both location, to be able
690 // to detect we did NOT "read" this event
691 previousLocation
.resetLocationState();
692 curLocation
.resetLocationState();
695 // If we read an event, set it's time to the locations (both previous
697 if (returnedEvent
!= null) {
698 setPreviousAndCurrentTimes(context
, returnedEvent
, curLocation
);
701 // LttngLocation prevLocation = (LttngLocation)
702 // savedContext.getLocation();
703 // LttngLocation currLocation = (LttngLocation)
704 // context.getLocation();
705 // if (prevLocation.equals(currLocation)) {
706 // System.out.println("Aie");
708 // Tracer.trace("Trc: " + context.getRank() + ": " +
709 // returnedEvent.getTimestamp().toString() + " (" +
710 // (prevLocation.isLastOperationParse() ? "T" : "F") + "," +
711 // (prevLocation.isLastOperationReadNext() ? "T" : "F") + "," +
712 // (prevLocation.isLastOperationSeek() ? "T" : "F") + "), (" +
713 // (currLocation.isLastOperationParse() ? "T" : "F") + "," +
714 // (currLocation.isLastOperationReadNext() ? "T" : "F") + "," +
715 // (currLocation.isLastOperationSeek() ? "T" : "F") + ")"
722 return returnedEvent
;
725 // this method was extracted for profiling purposes
726 private void setPreviousAndCurrentTimes(TmfContext context
, LttngEvent returnedEvent
,
727 LttngLocation curLocation
) {
729 TmfTimestamp eventTimestamp
= returnedEvent
.getTimestamp();
730 //long eventTime = eventTimestamp.getValue();
731 previousLocation
.setOperationTime(eventTimestamp
.getValue());
732 curLocation
.setOperationTime(eventTimestamp
.getValue());
733 updateIndex(context
, context
.getRank(), eventTimestamp
);
734 context
.updateRank(1);
737 protected void updateIndex(TmfContext context
, long rank
, TmfTimestamp timestamp
) {
739 if (getStartTime().compareTo(timestamp
, false) > 0) setStartTime( timestamp
);
740 if (getEndTime().compareTo(timestamp
, false) < 0) setEndTime(timestamp
);
741 if (rank
!= ITmfContext
.UNKNOWN_RANK
) {
742 if (fNbEvents
<= rank
)
743 fNbEvents
= rank
+ 1;
744 // Build the index as we go along
745 if ((rank
% fIndexPageSize
) == 0) {
746 // Determine the table position
747 long position
= rank
/ fIndexPageSize
;
748 // Add new entry at proper location (if empty)
749 if (fCheckpoints
.size() == position
) {
750 addCheckPoint(context
, timestamp
);
756 private void addCheckPoint(TmfContext context
, TmfTimestamp timestamp
) {
757 ITmfLocation
<?
> location
= context
.getLocation().clone();
758 fCheckpoints
.add(new TmfCheckpoint(timestamp
.clone(), location
));
761 // this method was extracted for profiling purposes
762 private LttngEvent
readNextEvent(LttngLocation curLocation
) {
763 LttngEvent returnedEvent
;
764 // Read the next event from the trace. The last one will NO LONGER BE VALID.
765 returnedEvent
= readEvent(curLocation
);
768 // Set the operation marker as read to both location, to be able to detect we did "read" this event
769 previousLocation
.setLastOperationReadNext();
770 curLocation
.setLastOperationReadNext();
771 return returnedEvent
;
774 // this method was extracted for profiling purposes
775 private LttngLocation
getCurrentLocation(TmfContext context
) {
776 LttngLocation curLocation
;
777 curLocation
= new LttngLocation();
778 context
.setLocation(curLocation
);
782 * Return the event in the trace according to the given context. Read it if
785 * Similar (same?) as GetNextEvent except that calling ParseEvent twice will
786 * return the same event
789 * Current TmfContext where to get the event
791 * @return The LttngEvent we read of null if no event are available
793 * @see org.eclipse.linuxtools.lttng.event.LttngLocation
794 * @see org.eclipse.linuxtools.tmf.trace.TmfContext
797 public synchronized LttngEvent
parseEvent(TmfContext context
) {
800 System
.out
.println("parseEvent(context) context.getLocation() -> "
801 + context
.getLocation());
804 LttngEvent returnedEvent
= null;
805 LttngLocation curLocation
= null;
807 // If the location in context is null, create a new one
808 if (context
.getLocation() == null) {
809 curLocation
= new LttngLocation();
810 context
.setLocation(curLocation
);
812 // Otherwise, we use the one in context; it should be a valid
815 curLocation
= (LttngLocation
) context
.getLocation();
819 // TMF assumes it is possible to read (GetNextEvent) to the next Event
820 // once ParseEvent() is called
821 // In LTTNG, there is not difference between "Parsing" and "Reading" an
823 // So, before "Parsing" an event, we have to make sure we didn't "Read"
825 // Also, "Reading" invalidate the previous Event in LTTNG and seek back
827 // so calling twice "Parse" will return the same event, giving a way to
828 // get the "Currently loaded" event
830 // *** Positionning trick :
831 // ParseEvent only read the trace if :
832 // 1- The last operation was NOT a ParseEvent or a GetNextEvent --> A
835 // 2- The time of the previous location is different from the current
836 // one --> A seek + a read is required
837 if (((!(curLocation
.isLastOperationParse())) && ((!(curLocation
838 .isLastOperationReadNext()))))
839 || (previousLocation
.getOperationTimeValue() != curLocation
840 .getOperationTimeValue())) {
841 // Previous time != Current time : We need to reposition to the
843 if (previousLocation
.getOperationTimeValue() != curLocation
844 .getOperationTimeValue()) {
847 .println("\t\tSeeking in getNextEvent. [ LastTime : "
848 + previousLocation
.getOperationTimeValue()
850 + curLocation
.getOperationTimeValue()
853 seekEvent(curLocation
.getOperationTime());
856 // Read the next event from the trace. The last one will NO LONGER
858 returnedEvent
= readEvent(curLocation
);
860 // No event was read, just return the one currently loaded (the last
862 returnedEvent
= currentLttngEvent
;
865 // If we read an event, set it's time to the locations (both previous
867 if (returnedEvent
!= null) {
868 previousLocation
.setOperationTime((LttngTimestamp
) returnedEvent
870 curLocation
.setOperationTime((LttngTimestamp
) returnedEvent
874 // Set the operation marker as parse to both location, to be able to
875 // detect we already "read" this event
876 previousLocation
.setLastOperationParse();
877 curLocation
.setLastOperationParse();
879 return returnedEvent
;
883 * Read the next event from the JNI and convert it as Lttng Event<p>
885 * @param location Current LttngLocation that to be updated with the event
888 * @return The LttngEvent we read of null if no event are available
890 * @see org.eclipse.linuxtools.lttng.event.LttngLocation
892 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniTrace
894 private synchronized LttngEvent
readEvent(LttngLocation location
) {
895 LttngEvent returnedEvent
= null;
896 JniEvent tmpEvent
= null;
898 // Read the next event from JNI. THIS WILL INVALIDATE THE CURRENT LTTNG
900 tmpEvent
= currentJniTrace
.readNextEvent();
902 if (tmpEvent
!= null) {
904 // Convert will update the currentLttngEvent
905 returnedEvent
= convertJniEventToTmf(tmpEvent
);
907 location
.setOperationTime((LttngTimestamp
) returnedEvent
911 // If the read failed (likely the last event in the trace), set the
912 // LastReadTime to the JNI time
913 // That way, even if we try to read again, we will step over the bogus
916 location
.setOperationTime(getEndTime().getValue() + 1);
919 return returnedEvent
;
923 * Method to convert a JniEvent into a LttngEvent.
926 * Note : This method will call LttngEvent convertEventJniToTmf(JniEvent,
927 * boolean) with a default value for isParsingNeeded
930 * The JniEvent to convert into LttngEvent
932 * @return The converted LttngEvent
934 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniEvent
935 * @see org.eclipse.linuxtools.lttng.event.LttngEvent
937 public synchronized LttngEvent
convertJniEventToTmf(JniEvent newEvent
) {
938 currentLttngEvent
= convertJniEventToTmf(newEvent
,
939 IS_PARSING_NEEDED_DEFAULT
);
941 return currentLttngEvent
;
945 * Method to convert a JniEvent into a LttngEvent
948 * The JniEvent to convert into LttngEvent
949 * @param isParsingNeeded
950 * A boolean value telling if the event should be parsed or not.
952 * @return The converted LttngEvent
954 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniEvent
955 * @see org.eclipse.linuxtools.lttng.event.LttngEvent
957 public synchronized LttngEvent
convertJniEventToTmf(JniEvent jniEvent
,
958 boolean isParsingNeeded
) {
963 // UNHACKED : We can no longer do that because TCF need to maintain
964 // several events at once.
965 // This is very slow to do so in LTTng, this has to be temporary.
967 // To save time here, we only set value instead of allocating new
969 // This give an HUGE performance improvement
970 // all allocation done in the LttngTrace constructor
972 eventTimestamp
.setValue(jniEvent
.getEventTime().getTime());
973 eventSource
.setSourceId(jniEvent
.requestEventSource());
975 eventType
= traceTypes
.get(EventTypeKey
.getEventTypeHash(jniEvent
));
977 eventReference
.setValue(jniEvent
.getParentTracefile()
978 .getTracefilePath());
979 eventReference
.setTracepath(this.getName());
981 eventContent
.emptyContent();
983 currentLttngEvent
.setType(eventType
);
984 // Save the jni reference
985 currentLttngEvent
.updateJniEventReference(jniEvent
);
987 // Parse now if was asked
988 // Warning : THIS IS SLOW
989 if (isParsingNeeded
) {
990 eventContent
.getFields();
993 return currentLttngEvent
;
995 return convertJniEventToTmfMultipleEventEvilFix(jniEvent
,
1002 * This method is a temporary fix to support multiple events at once in TMF
1003 * This is expected to be slow and should be fixed in another way. See
1004 * comment in convertJniEventToTmf();
1007 * The current JNI Event
1008 * @return Current Lttng Event fully parsed
1010 private synchronized LttngEvent
convertJniEventToTmfMultipleEventEvilFix(
1011 JniEvent jniEvent
, boolean isParsingNeeded
) {
1013 // Below : the "fix" with all the new and the full-parse
1014 // Allocating new memory is slow.
1015 // Parsing every events is very slow.
1016 eventTimestamp
= new LttngTimestamp(jniEvent
.getEventTime().getTime());
1017 eventSource
= new LttngEventSource(jniEvent
.requestEventSource());
1018 eventReference
= new LttngEventReference(jniEvent
.getParentTracefile()
1019 .getTracefilePath(), this.getName());
1020 eventType
= new LttngEventType(traceTypes
.get(EventTypeKey
1021 .getEventTypeHash(jniEvent
)));
1022 eventContent
= new LttngEventContent(currentLttngEvent
);
1023 currentLttngEvent
= new LttngEvent(this, eventTimestamp
, eventSource
,
1024 eventType
, eventContent
, eventReference
, null);
1026 // The jni reference is no longer reliable but we will keep it anyhow
1027 currentLttngEvent
.updateJniEventReference(jniEvent
);
1028 // Ensure that the content is correctly set
1029 eventContent
.setEvent(currentLttngEvent
);
1031 // Parse the event if it was needed
1033 // ONLY for testing, NOT parsing events with non-unique events WILL
1034 // result in segfault in the JVM
1035 if (isParsingNeeded
) {
1036 eventContent
.getFields();
1039 return currentLttngEvent
;
1043 * Reference to the current LttngTrace we are reading from.
1046 * Note : This bypass the framework and should not be use, except for
1049 * @return Reference to the current LttngTrace
1051 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniTrace
1053 public JniTrace
getCurrentJniTrace() {
1054 return currentJniTrace
;
1058 * Return a reference to the current LttngEvent we have in memory.
1060 * @return The current (last read) LttngEvent
1062 * @see org.eclipse.linuxtools.lttng.event.LttngEvent
1064 public synchronized LttngEvent
getCurrentEvent() {
1065 return currentLttngEvent
;
1069 * Get the major version number for the current trace
1071 * @return Version major or -1 if unknown
1073 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniTrace
1076 public short getVersionMajor() {
1077 if (currentJniTrace
!= null) {
1078 return currentJniTrace
.getLttMajorVersion();
1085 * Get the minor version number for the current trace
1087 * @return Version minor or -1 if unknown
1089 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniTrace
1092 public short getVersionMinor() {
1093 if (currentJniTrace
!= null) {
1094 return currentJniTrace
.getLttMinorVersion();
1101 * Get the number of CPU for this trace
1103 * @return Number of CPU or -1 if unknown
1105 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniTrace
1108 public int getCpuNumber() {
1109 if (currentJniTrace
!= null) {
1110 return currentJniTrace
.getCpuNumber();
1117 * Print the content of the checkpoint vector.
1120 * This is intended for debug purpose only.
1122 public void printCheckpointsVector() {
1123 System
.out
.println("StartTime : "
1124 + getTimeRange().getStartTime().getValue());
1125 System
.out
.println("EndTime : "
1126 + getTimeRange().getEndTime().getValue());
1128 for (int pos
= 0; pos
< fCheckpoints
.size(); pos
++) {
1129 System
.out
.print(pos
+ ": " + "\t");
1130 System
.out
.print(fCheckpoints
.get(pos
).getTimestamp() + "\t");
1131 System
.out
.println(fCheckpoints
.get(pos
).getLocation());
1136 * Return a String identifying this trace.
1138 * @return String that identify this trace
1141 @SuppressWarnings("nls")
1142 public String
toString() {
1143 String returnedData
= "";
1145 returnedData
+= "Path :" + getPath() + " ";
1146 returnedData
+= "Trace:" + currentJniTrace
+ " ";
1147 returnedData
+= "Event:" + currentLttngEvent
;
1149 return returnedData
;
1155 * EventTypeKey inner class
1157 * This class is used to make the process of generating the HashMap key more
1158 * transparent and so less error prone to use
1160 final class EventTypeKey
{
1162 // These two getEventTypeKey() functions should ALWAYS construct the key the
1164 // Otherwise, every type search will fail!
1166 // added final to encourage inlining.
1168 // generating a hash code by hand to avoid a string creation
1169 final static public int getEventTypeHash( LttngEventType newEventType
)
1171 return generateHash(newEventType
.getTracefileName(), newEventType
.getCpuId(), newEventType
.getMarkerName() );
1174 final private static int generateHash(String traceFileName
, long cpuNumber
, String markerName
) {
1175 // 0x1337 is a prime number. The number of CPUs is always under 8192 on the current kernel, so this will work with the current linux kernel.
1176 int cpuHash
= (int) (cpuNumber
*(0x1337));
1177 return traceFileName
.hashCode() ^
(cpuHash
) ^ markerName
.hashCode();
1180 // generating a hash code by hand to avoid a string creation
1181 final static public int getEventTypeHash( JniEvent newEvent
)
1183 return generateHash( newEvent
.getParentTracefile().getTracefileName(), newEvent
.getParentTracefile().getCpuNumber(),newEvent
.requestEventMarker().getName() );