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
;
73 LttngTimestamp eventTimestamp
;
74 LttngEventSource eventSource
;
75 LttngEventContent eventContent
;
76 LttngEventReference eventReference
;
79 LttngEvent currentLttngEvent
;
81 // The current location
82 LttngLocation previousLocation
;
84 LttngEventType eventType
;
86 // Hashmap of the possible types of events (Tracefile/CPU/Marker in the JNI)
87 HashMap
<Integer
, LttngEventType
> traceTypes
;
89 // This vector will be used to quickly find a marker name from a position
90 Vector
<Integer
> traceTypeNames
;
92 private String traceLibPath
;
97 public boolean validate(IProject project
, String path
) {
98 if (super.validate(project
, path
)) {
99 String traceLibPath
= TraceHelper
.getTraceLibDirFromProject(project
);
101 LTTngTraceVersion version
= new LTTngTraceVersion(path
, traceLibPath
);
102 return version
.isValidLttngTrace();
103 } catch (LttngException e
) {
109 public void initTrace(String path
, Class
<LttngEvent
> eventType
) throws FileNotFoundException
{
110 initLTTngTrace(path
, eventType
, CHECKPOINT_PAGE_SIZE
, false);
113 public void initTrace(String path
, Class
<LttngEvent
> eventType
, int cacheSize
) throws FileNotFoundException
{
114 initLTTngTrace(path
, eventType
, cacheSize
, false);
117 public void initTrace(String path
, Class
<LttngEvent
> eventType
, boolean indexTrace
) throws FileNotFoundException
{
118 initLTTngTrace(path
, eventType
, CHECKPOINT_PAGE_SIZE
, indexTrace
);
121 public void initTrace(String path
, Class
<LttngEvent
> eventType
, int cacheSize
, boolean indexTrace
) throws FileNotFoundException
{
122 initLTTngTrace(path
, eventType
, cacheSize
, indexTrace
);
125 private void initLTTngTrace(String path
, Class
<LttngEvent
> eventType
, int cacheSize
, boolean indexTrace
) throws FileNotFoundException
{
126 super.initTrace(path
, eventType
, indexTrace
);
128 currentJniTrace
= JniTraceFactory
.getJniTrace(path
, traceLibPath
, SHOW_LTT_DEBUG_DEFAULT
);
129 } catch (Exception e
) {
130 throw new FileNotFoundException(e
.getMessage());
133 // Export all the event types from the JNI side
134 traceTypes
= new HashMap
<Integer
, LttngEventType
>();
135 traceTypeNames
= new Vector
<Integer
>();
136 initialiseEventTypes(currentJniTrace
);
138 // Build the re-used event structure
139 eventTimestamp
= new LttngTimestamp();
140 eventSource
= new LttngEventSource();
141 this.eventType
= new LttngEventType();
142 eventContent
= new LttngEventContent(currentLttngEvent
);
143 eventReference
= new LttngEventReference(this.getName());
145 // Create the skeleton event
146 currentLttngEvent
= new LttngEvent(this, eventTimestamp
, eventSource
, this.eventType
, eventContent
,
147 eventReference
, null);
149 // Create a new current location
150 previousLocation
= new LttngLocation();
152 // Set the currentEvent to the eventContent
153 eventContent
.setEvent(currentLttngEvent
);
155 // Set the time range of the trace
156 TmfContext context
= seekLocation(null);
157 LttngEvent event
= getNextEvent(context
);
158 LttngTimestamp startTime
= new LttngTimestamp(event
.getTimestamp());
159 LttngTimestamp endTime
= new LttngTimestamp(currentJniTrace
.getEndTime().getTime());
161 setTimeRange(new TmfTimeRange(startTime
, endTime
));
163 if (currentJniTrace
== null) {
164 System
.out
.println("Problem");
169 * Default Constructor.
173 * Path to a <b>directory</b> that contain an LTTng trace.
175 * @exception Exception
176 * (most likely LTTngTraceException or FileNotFoundException)
178 public LTTngTrace(String path
) throws Exception
{
179 // Call with "wait for completion" true and "skip indexing" false
180 this(path
, null, true, false);
184 * Constructor, with control over the indexing.
188 * Path to a <b>directory</b> that contain an LTTng trace.
189 * @param waitForCompletion
190 * Should we wait for indexign to complete before moving on.
192 * @exception Exception
193 * (most likely LTTngTraceException or FileNotFoundException)
195 public LTTngTrace(String path
, boolean waitForCompletion
) throws Exception
{
196 // Call with "skip indexing" false
197 this(path
, null, waitForCompletion
, true);
201 * Default constructor, with control over the indexing and possibility to bypass indexation
205 * Path to a <b>directory</b> that contain an LTTng trace.
206 * @param traceLibPath
207 * Path to a <b>directory</b> that contains LTTng trace libraries.
208 * @param waitForCompletion
209 * Should we wait for indexign to complete before moving on.
210 * @param bypassIndexing
211 * Should we bypass indexing completly? This is should only be useful for unit testing.
213 * @exception Exception
214 * (most likely LTTngTraceException or FileNotFoundException)
217 public LTTngTrace(String path
, String traceLibPath
, boolean waitForCompletion
, boolean bypassIndexing
)
219 super(path
, LttngEvent
.class, path
, CHECKPOINT_PAGE_SIZE
, false);
220 initTrace(path
, LttngEvent
.class, !bypassIndexing
);
221 this.traceLibPath
= traceLibPath
;
225 * Copy constructor is forbidden for LttngEvenmStream
227 public LTTngTrace(LTTngTrace other
) throws Exception
{
228 this(other
.getPath(), other
.getTraceLibPath(), false, true);
229 this.fCheckpoints
= other
.fCheckpoints
;
230 setTimeRange(new TmfTimeRange(new LttngTimestamp(other
.getStartTime()), new LttngTimestamp(other
.getEndTime())));
234 public LTTngTrace
copy() {
235 LTTngTrace returnedTrace
= null;
238 returnedTrace
= new LTTngTrace(this);
239 } catch (Exception e
) {
241 .println("ERROR : Could not create LTTngTrace copy (createTraceCopy).\nError is : " + e
.getStackTrace()); //$NON-NLS-1$
244 return returnedTrace
;
248 public synchronized LTTngTrace
clone() {
249 LTTngTrace clone
= null;
251 clone
= (LTTngTrace
) super.clone();
253 clone
.currentJniTrace
= JniTraceFactory
.getJniTrace(getPath(), getTraceLibPath(),
254 SHOW_LTT_DEBUG_DEFAULT
);
255 } catch (JniException e
) {
256 // e.printStackTrace();
259 // Export all the event types from the JNI side
260 clone
.traceTypes
= new HashMap
<Integer
, LttngEventType
>();
261 clone
.traceTypeNames
= new Vector
<Integer
>();
262 clone
.initialiseEventTypes(clone
.currentJniTrace
);
264 // Verify that all those "default constructor" are safe to use
265 clone
.eventTimestamp
= new LttngTimestamp();
266 clone
.eventSource
= new LttngEventSource();
267 clone
.eventType
= new LttngEventType();
268 clone
.eventContent
= new LttngEventContent(clone
.currentLttngEvent
);
269 clone
.eventReference
= new LttngEventReference(this.getName());
271 // Create the skeleton event
272 clone
.currentLttngEvent
= new LttngEvent(this, clone
.eventTimestamp
, clone
.eventSource
, clone
.eventType
,
273 clone
.eventContent
, clone
.eventReference
, null);
275 // Create a new current location
276 clone
.previousLocation
= new LttngLocation();
278 // Set the currentEvent to the eventContent
279 clone
.eventContent
.setEvent(clone
.currentLttngEvent
);
281 // Set the start time of the trace
282 setTimeRange(new TmfTimeRange(new LttngTimestamp(clone
.currentJniTrace
.getStartTime().getTime()),
283 new LttngTimestamp(clone
.currentJniTrace
.getEndTime().getTime())));
284 } catch (CloneNotSupportedException e
) {
290 public String
getTraceLibPath() {
295 * Fill out the HashMap with "Type" (Tracefile/Marker)
297 * This should be called at construction once the trace is open
299 private void initialiseEventTypes(JniTrace trace
) {
301 LttngEventType tmpType
= null;
302 String
[] markerFieldsLabels
= null;
304 String newTracefileKey
= null;
305 Integer newMarkerKey
= null;
307 JniTracefile newTracefile
= null;
308 JniMarker newMarker
= null;
310 // First, obtain an iterator on TRACEFILES of owned by the TRACE
311 Iterator
<String
> tracefileItr
= trace
.getTracefilesMap().keySet().iterator();
313 while (tracefileItr
.hasNext()) {
314 newTracefileKey
= tracefileItr
.next();
315 newTracefile
= trace
.getTracefilesMap().get(newTracefileKey
);
317 // From the TRACEFILE read, obtain its MARKER
318 Iterator
<Integer
> markerItr
= newTracefile
.getTracefileMarkersMap().keySet().iterator();
319 while (markerItr
.hasNext()) {
320 newMarkerKey
= markerItr
.next();
321 newMarker
= newTracefile
.getTracefileMarkersMap().get(newMarkerKey
);
323 // From the MARKER we can obtain the MARKERFIELDS keys (i.e.
325 markerFieldsLabels
= newMarker
.getMarkerFieldsHashMap().keySet()
326 .toArray(new String
[newMarker
.getMarkerFieldsHashMap().size()]);
328 tmpType
= new LttngEventType(newTracefile
.getTracefileName(), newTracefile
.getCpuNumber(),
329 newMarker
.getName(), newMarkerKey
.intValue(), markerFieldsLabels
);
331 // Add the type to the map/vector
332 addEventTypeToMap(tmpType
);
338 * Add a new type to the HashMap
340 * As the hashmap use a key format that is a bit dangerous to use, we should always add using this function.
342 private void addEventTypeToMap(LttngEventType newEventType
) {
343 int newTypeKey
= EventTypeKey
.getEventTypeHash(newEventType
);
345 this.traceTypes
.put(newTypeKey
, newEventType
);
346 this.traceTypeNames
.add(newTypeKey
);
350 * Return the latest saved location. Note : Modifying the returned location may result in buggy positionning!
352 * @return The LttngLocation as it was after the last operation.
354 * @see org.eclipse.linuxtools.lttng.event.LttngLocation
357 public synchronized ITmfLocation
<?
> getCurrentLocation() {
358 return previousLocation
;
362 * Position the trace to the event at the given location.
364 * NOTE : Seeking by location is very fast compare to seeking by position but is still slower than "ReadNext", avoid
365 * using it for small interval.
368 * Location of the event in the trace. If no event available at this exact location, we will position
369 * ourself to the next one.
371 * @return The TmfContext that point to this event
373 * @see org.eclipse.linuxtools.lttng.event.LttngLocation
374 * @see org.eclipse.linuxtools.tmf.trace.TmfContext
377 public synchronized TmfContext
seekLocation(ITmfLocation
<?
> location
) {
383 System
.out
.println("seekLocation(location) location -> " + location
); //$NON-NLS-1$
386 // If the location in context is null, create a new one
387 LttngLocation curLocation
= null;
388 if (location
== null) {
389 curLocation
= new LttngLocation();
390 TmfContext context
= seekEvent(curLocation
.getOperationTime());
391 context
.setRank(ITmfContext
.INITIAL_RANK
);
394 curLocation
= (LttngLocation
) location
;
398 // Update to location should (and will) be done in SeekEvent.
400 // The only seek valid in LTTng is with the time, we call
401 // seekEvent(timestamp)
402 TmfContext context
= seekEvent(curLocation
.getOperationTime());
408 * Position the trace to the event at the given time.
410 * NOTE : Seeking by time is very fast compare to seeking by position but is still slower than "ReadNext", avoid
411 * using it for small interval.
414 * Time of the event in the trace. If no event available at this exact time, we will position ourself to
417 * @return The TmfContext that point to this event
419 * @see org.eclipse.linuxtools.lttng.event.LttngLocation
420 * @see org.eclipse.linuxtools.tmf.trace.TmfContext
423 public synchronized TmfContext
seekEvent(TmfTimestamp timestamp
) {
426 System
.out
.println("seekEvent(timestamp) timestamp -> " + timestamp
); //$NON-NLS-1$
429 if (currentJniTrace
== null) {
430 System
.out
.println("aie");
434 currentJniTrace
.seekToTime(new JniTime(timestamp
.getValue()));
436 // Save the time at which we seeked
437 previousLocation
.setOperationTime(timestamp
.getValue());
438 // Set the operation marker as seek, to be able to detect we did "seek"
440 previousLocation
.setLastOperationSeek();
442 LttngLocation curLocation
= new LttngLocation(previousLocation
);
444 return new TmfContext(curLocation
);
448 * Position the trace to the event at the given position (rank).
450 * NOTE : Seeking by position is very slow in LTTng, consider seeking by timestamp.
453 * Position (or rank) of the event in the trace, starting at 0.
455 * @return The TmfContext that point to this event
457 * @see org.eclipse.linuxtools.lttng.event.LttngLocation
458 * @see org.eclipse.linuxtools.tmf.trace.TmfContext
461 public synchronized TmfContext
seekEvent(long position
) {
464 System
.out
.println("seekEvent(position) position -> " + position
); //$NON-NLS-1$
467 TmfTimestamp timestamp
= null;
468 long index
= position
/ getCacheSize();
470 // Get the timestamp of the closest check point to the given position
471 if (fCheckpoints
.size() > 0) {
472 if (index
>= fCheckpoints
.size()) {
473 index
= fCheckpoints
.size() - 1;
475 timestamp
= fCheckpoints
.elementAt((int) index
).getTimestamp();
477 // If none, take the start time of the trace
479 timestamp
= getStartTime();
482 // Seek to the found time
483 TmfContext tmpContext
= seekEvent(timestamp
);
484 tmpContext
.setRank((index
+ 1) * fIndexPageSize
);
485 previousLocation
= (LttngLocation
) tmpContext
.getLocation();
487 // Ajust the index of the event we found at this check point position
488 Long currentPosition
= index
* getCacheSize();
490 Long lastTimeValueRead
= 0L;
492 // Get the event at current position. This won't move to the next one
493 JniEvent tmpJniEvent
= currentJniTrace
.findNextEvent();
494 // Now that we are positionned at the checkpoint,
495 // we need to "readNext" (Position - CheckpointPosition) times or until
497 while ((tmpJniEvent
!= null) && (currentPosition
< position
)) {
498 tmpJniEvent
= currentJniTrace
.readNextEvent();
502 // If we found our event, save its timestamp
503 if (tmpJniEvent
!= null) {
504 lastTimeValueRead
= tmpJniEvent
.getEventTime().getTime();
507 // Set the operation marker as seek, to be able to detect we did "seek"
509 previousLocation
.setLastOperationSeek();
510 // Save read event time
511 previousLocation
.setOperationTime(lastTimeValueRead
);
514 // Is that too paranoid?
516 // We don't trust what upper level could do with our internal location
517 // so we create a new one to return instead
518 LttngLocation curLocation
= new LttngLocation(previousLocation
);
520 return new TmfContext(curLocation
);
524 public TmfContext
seekLocation(double ratio
) {
525 // TODO Auto-generated method stub
530 public double getLocationRatio(ITmfLocation
<?
> location
) {
531 // TODO Auto-generated method stub
536 * Return the event in the trace according to the given context. Read it if necessary.
538 * Similar (same?) as ParseEvent except that calling GetNext twice read the next one the second time.
541 * Current TmfContext where to get the event
543 * @return The LttngEvent we read of null if no event are available
545 * @see org.eclipse.linuxtools.lttng.event.LttngLocation
546 * @see org.eclipse.linuxtools.tmf.trace.TmfContext
549 public int nbEventsRead
= 0;
552 public synchronized LttngEvent
getNextEvent(TmfContext context
) {
555 System
.out
.println("getNextEvent(context) context.getLocation() -> " //$NON-NLS-1$
556 + context
.getLocation());
559 LttngEvent returnedEvent
= null;
560 LttngLocation curLocation
= null;
562 curLocation
= (LttngLocation
) context
.getLocation();
563 // If the location in context is null, create a new one
564 if (curLocation
== null) {
565 curLocation
= getCurrentLocation(context
);
568 // *** Positioning trick :
569 // GetNextEvent only read the trace if :
570 // 1- The last operation was NOT a ParseEvent --> A read is required
572 // 2- The time of the previous location is different from the current
573 // one --> A seek + a read is required
574 if ((!(curLocation
.isLastOperationParse()))
575 || (previousLocation
.getOperationTimeValue() != curLocation
.getOperationTimeValue())) {
576 if (previousLocation
.getOperationTimeValue() != curLocation
.getOperationTimeValue()) {
578 System
.out
.println("\t\tSeeking in getNextEvent. [ LastTime : " //$NON-NLS-1$
579 + previousLocation
.getOperationTimeValue() + " CurrentTime" //$NON-NLS-1$
580 + curLocation
.getOperationTimeValue() + " ]"); //$NON-NLS-1$
582 seekEvent(curLocation
.getOperationTime());
584 // Read the next event from the trace. The last one will NO LONGER
586 returnedEvent
= readNextEvent(curLocation
);
589 // No event was read, just return the one currently loaded (the last
591 returnedEvent
= currentLttngEvent
;
594 // Reset (erase) the operation marker to both location, to be able
595 // to detect we did NOT "read" this event
596 previousLocation
.resetLocationState();
597 curLocation
.resetLocationState();
600 // If we read an event, set it's time to the locations (both previous
602 if (returnedEvent
!= null) {
603 setPreviousAndCurrentTimes(context
, returnedEvent
, curLocation
);
606 return returnedEvent
;
609 // this method was extracted for profiling purposes
610 private void setPreviousAndCurrentTimes(TmfContext context
, LttngEvent returnedEvent
, LttngLocation curLocation
) {
612 TmfTimestamp eventTimestamp
= returnedEvent
.getTimestamp();
613 // long eventTime = eventTimestamp.getValue();
614 previousLocation
.setOperationTime(eventTimestamp
.getValue());
615 curLocation
.setOperationTime(eventTimestamp
.getValue());
616 updateIndex(context
, context
.getRank(), eventTimestamp
);
617 context
.updateRank(1);
620 protected void updateIndex(TmfContext context
, long rank
, TmfTimestamp timestamp
) {
622 if (getStartTime().compareTo(timestamp
, false) > 0)
623 setStartTime(timestamp
);
624 if (getEndTime().compareTo(timestamp
, false) < 0)
625 setEndTime(timestamp
);
626 if (rank
!= ITmfContext
.UNKNOWN_RANK
) {
627 if (fNbEvents
<= rank
)
628 fNbEvents
= rank
+ 1;
629 // Build the index as we go along
630 if ((rank
% fIndexPageSize
) == 0) {
631 // Determine the table position
632 long position
= rank
/ fIndexPageSize
;
633 // Add new entry at proper location (if empty)
634 if (fCheckpoints
.size() == position
) {
635 addCheckPoint(context
, timestamp
);
641 private void addCheckPoint(TmfContext context
, TmfTimestamp timestamp
) {
642 ITmfLocation
<?
> location
= context
.getLocation().clone();
643 fCheckpoints
.add(new TmfCheckpoint(timestamp
.clone(), location
));
646 // this method was extracted for profiling purposes
647 private LttngEvent
readNextEvent(LttngLocation curLocation
) {
648 LttngEvent returnedEvent
;
649 // Read the next event from the trace. The last one will NO LONGER BE
651 returnedEvent
= readEvent(curLocation
);
654 // Set the operation marker as read to both location, to be able to
655 // detect we did "read" this event
656 previousLocation
.setLastOperationReadNext();
657 curLocation
.setLastOperationReadNext();
658 return returnedEvent
;
661 // this method was extracted for profiling purposes
662 private LttngLocation
getCurrentLocation(TmfContext context
) {
663 LttngLocation curLocation
;
664 curLocation
= new LttngLocation();
665 context
.setLocation(curLocation
);
670 * Return the event in the trace according to the given context. Read it if necessary.
672 * Similar (same?) as GetNextEvent except that calling ParseEvent twice will return the same event
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 synchronized LttngEvent
parseEvent(TmfContext context
) {
686 System
.out
.println("parseEvent(context) context.getLocation() -> " //$NON-NLS-1$
687 + context
.getLocation());
690 LttngEvent returnedEvent
= null;
691 LttngLocation curLocation
= null;
693 // If the location in context is null, create a new one
694 if (context
.getLocation() == null) {
695 curLocation
= new LttngLocation();
696 context
.setLocation(curLocation
);
698 // Otherwise, we use the one in context; it should be a valid
701 curLocation
= (LttngLocation
) context
.getLocation();
705 // TMF assumes it is possible to read (GetNextEvent) to the next Event
706 // once ParseEvent() is called
707 // In LTTNG, there is not difference between "Parsing" and "Reading" an
709 // So, before "Parsing" an event, we have to make sure we didn't "Read"
711 // Also, "Reading" invalidate the previous Event in LTTNG and seek back
713 // so calling twice "Parse" will return the same event, giving a way to
714 // get the "Currently loaded" event
716 // *** Positionning trick :
717 // ParseEvent only read the trace if :
718 // 1- The last operation was NOT a ParseEvent or a GetNextEvent --> A
721 // 2- The time of the previous location is different from the current
722 // one --> A seek + a read is required
723 if (((!(curLocation
.isLastOperationParse())) && ((!(curLocation
.isLastOperationReadNext()))))
724 || (previousLocation
.getOperationTimeValue() != curLocation
.getOperationTimeValue())) {
725 // Previous time != Current time : We need to reposition to the
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());
736 // Read the next event from the trace. The last one will NO LONGER
738 returnedEvent
= readEvent(curLocation
);
740 // No event was read, just return the one currently loaded (the last
742 returnedEvent
= currentLttngEvent
;
745 // If we read an event, set it's time to the locations (both previous
747 if (returnedEvent
!= null) {
748 previousLocation
.setOperationTime((LttngTimestamp
) returnedEvent
.getTimestamp());
749 curLocation
.setOperationTime((LttngTimestamp
) returnedEvent
.getTimestamp());
752 // Set the operation marker as parse to both location, to be able to
753 // detect we already "read" this event
754 previousLocation
.setLastOperationParse();
755 curLocation
.setLastOperationParse();
757 return returnedEvent
;
761 * Read the next event from the JNI and convert it as Lttng Event<p>
763 * @param location Current LttngLocation that to be updated with the event timestamp
765 * @return The LttngEvent we read of null if no event are available
767 * @see org.eclipse.linuxtools.lttng.event.LttngLocation
769 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniTrace
771 private synchronized LttngEvent
readEvent(LttngLocation location
) {
772 LttngEvent returnedEvent
= null;
773 JniEvent tmpEvent
= null;
775 // Read the next event from JNI. THIS WILL INVALIDATE THE CURRENT LTTNG
777 tmpEvent
= currentJniTrace
.readNextEvent();
779 if (tmpEvent
!= null) {
781 // Convert will update the currentLttngEvent
782 returnedEvent
= convertJniEventToTmf(tmpEvent
);
784 location
.setOperationTime((LttngTimestamp
) returnedEvent
.getTimestamp());
787 // If the read failed (likely the last event in the trace), set the
788 // LastReadTime to the JNI time
789 // That way, even if we try to read again, we will step over the bogus
792 location
.setOperationTime(getEndTime().getValue() + 1);
795 return returnedEvent
;
799 * Method to convert a JniEvent into a LttngEvent.
802 * Note : This method will call LttngEvent convertEventJniToTmf(JniEvent, boolean) with a default value for
806 * The JniEvent to convert into LttngEvent
808 * @return The converted LttngEvent
810 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniEvent
811 * @see org.eclipse.linuxtools.lttng.event.LttngEvent
813 public synchronized LttngEvent
convertJniEventToTmf(JniEvent newEvent
) {
814 currentLttngEvent
= convertJniEventToTmf(newEvent
, IS_PARSING_NEEDED_DEFAULT
);
816 return currentLttngEvent
;
820 * Method to convert a JniEvent into a LttngEvent
823 * The JniEvent to convert into LttngEvent
824 * @param isParsingNeeded
825 * A boolean value telling if the event should be parsed or not.
827 * @return The converted LttngEvent
829 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniEvent
830 * @see org.eclipse.linuxtools.lttng.event.LttngEvent
832 public synchronized LttngEvent
convertJniEventToTmf(JniEvent jniEvent
, boolean isParsingNeeded
) {
837 // UNHACKED : We can no longer do that because TCF need to maintain
838 // several events at once.
839 // This is very slow to do so in LTTng, this has to be temporary.
841 // To save time here, we only set value instead of allocating new
843 // This give an HUGE performance improvement
844 // all allocation done in the LttngTrace constructor
846 eventTimestamp
.setValue(jniEvent
.getEventTime().getTime());
847 eventSource
.setSourceId(jniEvent
.requestEventSource());
849 eventType
= traceTypes
.get(EventTypeKey
.getEventTypeHash(jniEvent
));
851 eventReference
.setValue(jniEvent
.getParentTracefile().getTracefilePath());
852 eventReference
.setTracepath(this.getName());
854 eventContent
.emptyContent();
856 currentLttngEvent
.setType(eventType
);
857 // Save the jni reference
858 currentLttngEvent
.updateJniEventReference(jniEvent
);
860 // Parse now if was asked
861 // Warning : THIS IS SLOW
862 if (isParsingNeeded
) {
863 eventContent
.getFields();
866 return currentLttngEvent
;
868 return convertJniEventToTmfMultipleEventEvilFix(jniEvent
, isParsingNeeded
);
874 * This method is a temporary fix to support multiple events at once in TMF This is expected to be slow and should
875 * be fixed in another way. See comment in convertJniEventToTmf();
878 * The current JNI Event
879 * @return Current Lttng Event fully parsed
881 private synchronized LttngEvent
convertJniEventToTmfMultipleEventEvilFix(JniEvent jniEvent
, boolean isParsingNeeded
) {
883 // Below : the "fix" with all the new and the full-parse
884 // Allocating new memory is slow.
885 // Parsing every events is very slow.
886 eventTimestamp
= new LttngTimestamp(jniEvent
.getEventTime().getTime());
887 eventSource
= new LttngEventSource(jniEvent
.requestEventSource());
888 eventReference
= new LttngEventReference(jniEvent
.getParentTracefile().getTracefilePath(), this.getName());
889 eventType
= new LttngEventType(traceTypes
.get(EventTypeKey
.getEventTypeHash(jniEvent
)));
890 eventContent
= new LttngEventContent(currentLttngEvent
);
891 currentLttngEvent
= new LttngEvent(this, eventTimestamp
, eventSource
, eventType
, eventContent
, eventReference
,
894 // The jni reference is no longer reliable but we will keep it anyhow
895 currentLttngEvent
.updateJniEventReference(jniEvent
);
896 // Ensure that the content is correctly set
897 eventContent
.setEvent(currentLttngEvent
);
899 // Parse the event if it was needed
901 // ONLY for testing, NOT parsing events with non-unique events WILL
902 // result in segfault in the JVM
903 if (isParsingNeeded
) {
904 eventContent
.getFields();
907 return currentLttngEvent
;
911 * Reference to the current LttngTrace we are reading from.
914 * Note : This bypass the framework and should not be use, except for testing!
916 * @return Reference to the current LttngTrace
918 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniTrace
920 public JniTrace
getCurrentJniTrace() {
921 return currentJniTrace
;
925 * Return a reference to the current LttngEvent we have in memory.
927 * @return The current (last read) LttngEvent
929 * @see org.eclipse.linuxtools.lttng.event.LttngEvent
931 public synchronized LttngEvent
getCurrentEvent() {
932 return currentLttngEvent
;
936 * Get the major version number for the current trace
938 * @return Version major or -1 if unknown
940 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniTrace
943 public short getVersionMajor() {
944 if (currentJniTrace
!= null) {
945 return currentJniTrace
.getLttMajorVersion();
952 * Get the minor version number for the current trace
954 * @return Version minor or -1 if unknown
956 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniTrace
959 public short getVersionMinor() {
960 if (currentJniTrace
!= null) {
961 return currentJniTrace
.getLttMinorVersion();
968 * Get the number of CPU for this trace
970 * @return Number of CPU or -1 if unknown
972 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniTrace
975 public int getCpuNumber() {
976 if (currentJniTrace
!= null) {
977 return currentJniTrace
.getCpuNumber();
984 * Print the content of the checkpoint vector.
987 * This is intended for debug purpose only.
989 public void printCheckpointsVector() {
990 System
.out
.println("StartTime : " //$NON-NLS-1$
991 + getTimeRange().getStartTime().getValue());
992 System
.out
.println("EndTime : " //$NON-NLS-1$
993 + getTimeRange().getEndTime().getValue());
995 for (int pos
= 0; pos
< fCheckpoints
.size(); pos
++) {
996 System
.out
.print(pos
+ ": " + "\t"); //$NON-NLS-1$ //$NON-NLS-2$
997 System
.out
.print(fCheckpoints
.get(pos
).getTimestamp() + "\t"); //$NON-NLS-1$
998 System
.out
.println(fCheckpoints
.get(pos
).getLocation());
1003 public synchronized void dispose() {
1004 if (currentJniTrace
!= null)
1005 currentJniTrace
.closeTrace();
1010 * Return a String identifying this trace.
1012 * @return String that identify this trace
1015 @SuppressWarnings("nls")
1016 public String
toString() {
1017 String returnedData
= "";
1019 returnedData
+= "Path :" + getPath() + " ";
1020 returnedData
+= "Trace:" + currentJniTrace
+ " ";
1021 returnedData
+= "Event:" + currentLttngEvent
;
1023 return returnedData
;
1029 * EventTypeKey inner class
1031 * This class is used to make the process of generating the HashMap key more transparent and so less error prone to use
1033 final class EventTypeKey
{
1035 // These two getEventTypeKey() functions should ALWAYS construct the key the
1037 // Otherwise, every type search will fail!
1039 // added final to encourage inlining.
1041 // generating a hash code by hand to avoid a string creation
1042 final static public int getEventTypeHash(LttngEventType newEventType
) {
1043 return generateHash(newEventType
.getTracefileName(), newEventType
.getCpuId(), newEventType
.getMarkerName());
1046 final private static int generateHash(String traceFileName
, long cpuNumber
, String markerName
) {
1047 // 0x1337 is a prime number. The number of CPUs is always under 8192 on
1048 // the current kernel, so this will work with the current linux kernel.
1049 int cpuHash
= (int) (cpuNumber
* (0x1337));
1050 return traceFileName
.hashCode() ^
(cpuHash
) ^ markerName
.hashCode();
1053 // generating a hash code by hand to avoid a string creation
1054 final static public int getEventTypeHash(JniEvent newEvent
) {
1055 return generateHash(newEvent
.getParentTracefile().getTracefileName(), newEvent
.getParentTracefile()
1056 .getCpuNumber(), newEvent
.requestEventMarker().getName());