2010-10-26 Francois Chouinard <fchouinard@gmail.com> Contribution for Bug309042
[deliverable/tracecompass.git] / org.eclipse.linuxtools.lttng / src / org / eclipse / linuxtools / lttng / trace / LTTngTrace.java
1 /*******************************************************************************
2 * Copyright (c) 2009 Ericsson
3 *
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
8 *
9 * Contributors:
10 * William Bourque (wbourque@gmail.com) - Initial API and implementation
11 *******************************************************************************/
12
13 package org.eclipse.linuxtools.lttng.trace;
14
15 import java.util.HashMap;
16 import java.util.Iterator;
17 import java.util.Vector;
18
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.TmfContext;
39 import org.eclipse.linuxtools.tmf.trace.TmfTrace;
40
41
42 class LTTngTraceException extends LttngException {
43 static final long serialVersionUID = -1636648737081868146L;
44
45 public LTTngTraceException(String errMsg) {
46 super(errMsg);
47 }
48 }
49
50 /**
51 * <b><u>LTTngTrace</u></b><p>
52 *
53 * LTTng trace implementation. It accesses the C trace handling library
54 * (seeking, reading and parsing) through the JNI component.
55 */
56 public class LTTngTrace extends TmfTrace<LttngEvent> {
57
58 public static boolean printDebug = false;
59 public static boolean uniqueEvent = true;
60
61 private final static boolean SHOW_LTT_DEBUG_DEFAULT = false;
62 private final static boolean IS_PARSING_NEEDED_DEFAULT = !uniqueEvent;
63 private final static int CHECKPOINT_PAGE_SIZE = 1000;
64
65 // Reference to our JNI trace
66 private JniTrace currentJniTrace = null;
67
68 // ***
69 // UNHACKED : We can no longer do that because TCF need to maintain several events at once.
70 // This is very slow to do so in LTTng, this has to be temporary.
71 // *** HACK ***
72 // To save time, we will declare all component of the LttngEvent during the construction of the trace
73 // Then, while reading the trace, we will just SET the values instead of declaring new object
74 // ***
75 LttngTimestamp eventTimestamp = null;
76 LttngEventSource eventSource = null;
77 LttngEventContent eventContent = null;
78 LttngEventReference eventReference = null;
79
80 // The actual event
81 LttngEvent currentLttngEvent = null;
82
83 // The current location
84 LttngLocation previousLocation = null;
85
86 LttngEventType eventType = null;
87 // Hashmap of the possible types of events (Tracefile/CPU/Marker in the JNI)
88 HashMap<String, LttngEventType> traceTypes = null;
89 // This vector will be used to quickly find a marker name from a position
90 Vector<String> traceTypeNames = null;
91
92 /**
93 * Default Constructor.<p>
94 *
95 * @param path Path to a <b>directory</b> that contain an LTTng trace.
96 *
97 * @exception Exception (most likely LTTngTraceException or FileNotFoundException)
98 */
99 public LTTngTrace(String path) throws Exception {
100 // Call with "wait for completion" true and "skip indexing" false
101 this(path, true, false);
102 }
103
104 /**
105 * Constructor, with control over the indexing.
106 * <p>
107 * @param path Path to a <b>directory</b> that contain an LTTng trace.
108 * @param waitForCompletion Should we wait for indexign to complete before moving on.
109 *
110 * @exception Exception (most likely LTTngTraceException or FileNotFoundException)
111 */
112 public LTTngTrace(String path, boolean waitForCompletion) throws Exception {
113 // Call with "skip indexing" false
114 this(path, waitForCompletion, false);
115 }
116
117 /**
118 * Default constructor, with control over the indexing and possibility to bypass indexation
119 * <p>
120 * @param path Path to a <b>directory</b> that contain an LTTng trace.
121 * @param waitForCompletion Should we wait for indexign to complete before moving on.
122 * @param bypassIndexing Should we bypass indexing completly? This is should only be useful for unit testing.
123 *
124 * @exception Exception (most likely LTTngTraceException or FileNotFoundException)
125 *
126 */
127 public LTTngTrace(String path, boolean waitForCompletion, boolean bypassIndexing) throws Exception {
128 super(path, LttngEvent.class, path, CHECKPOINT_PAGE_SIZE);
129 try {
130 currentJniTrace = JniTraceFactory.getJniTrace(path, SHOW_LTT_DEBUG_DEFAULT);
131 }
132 catch (Exception e) {
133 throw new LTTngTraceException(e.getMessage());
134 }
135
136 // Export all the event types from the JNI side
137 traceTypes = new HashMap<String, LttngEventType>();
138 traceTypeNames = new Vector<String>();
139 initialiseEventTypes(currentJniTrace);
140
141 // *** VERIFY ***
142 // Verify that all those "default constructor" are safe to use
143 eventTimestamp = new LttngTimestamp();
144 eventSource = new LttngEventSource();
145 eventType = new LttngEventType();
146 eventContent = new LttngEventContent(currentLttngEvent);
147 eventReference = new LttngEventReference(this.getName());
148
149 // Create the skeleton event
150 currentLttngEvent = new LttngEvent(this, eventTimestamp, eventSource, eventType, eventContent, eventReference, null);
151
152 // Create a new current location
153 previousLocation = new LttngLocation();
154
155
156 // Set the currentEvent to the eventContent
157 eventContent.setEvent(currentLttngEvent);
158
159 // // Bypass indexing if asked
160 // if ( bypassIndexing == false ) {
161 // indexTrace(true);
162 // }
163 // else {
164 // Even if we don't have any index, set ONE checkpoint
165 // fCheckpoints.add(new TmfCheckpoint(new LttngTimestamp(0L) , new LttngLocation() ) );
166
167 // Set the time range of the trace
168 TmfContext context = seekLocation(null);
169 LttngEvent event = getNextEvent(context);
170 LttngTimestamp startTime = new LttngTimestamp(event.getTimestamp());
171 LttngTimestamp endTime = new LttngTimestamp(currentJniTrace.getEndTime().getTime());
172
173 setTimeRange(new TmfTimeRange(startTime, endTime));
174
175 }
176
177 /*
178 * Copy constructor is forbidden for LttngEvenmStream
179 *
180 */
181 public LTTngTrace(LTTngTrace oldTrace) throws Exception {
182 this(oldTrace.getPath(), false, true);
183
184 // *** VERIFY ***
185 // Is this safe?
186 this.fCheckpoints = oldTrace.fCheckpoints;
187
188 /*
189 // This would only work if the index is already done
190 this.fCheckpoints = new Vector<TmfCheckpoint>( oldTrace.fCheckpoints.size() );
191 for (int x = 0; x<oldTrace.fCheckpoints.size(); x++){
192 TmfCheckpoint tmpCheckPoint = oldTrace.fCheckpoints.get(x);
193 this.fCheckpoints.add( new TmfCheckpoint(tmpCheckPoint.getTimestamp(), tmpCheckPoint.getLocation()) );
194 }
195 */
196
197 // Set the start time of the trace
198 setTimeRange( new TmfTimeRange( new LttngTimestamp(oldTrace.getStartTime()),
199 new LttngTimestamp(oldTrace.getEndTime()))
200 );
201 }
202
203 @Override
204 public LTTngTrace createTraceCopy() {
205 LTTngTrace returnedTrace = null;
206
207 try {
208 returnedTrace = new LTTngTrace(this);
209 }
210 catch (Exception e) {
211 System.out.println("ERROR : Could not create LTTngTrace copy (createTraceCopy).\nError is : " + e.getStackTrace());
212 }
213
214 return returnedTrace;
215 }
216
217 @Override
218 public synchronized LTTngTrace clone() {
219 LTTngTrace clone = null;
220 try {
221 clone = (LTTngTrace) super.clone();
222 try {
223 clone.currentJniTrace = JniTraceFactory.getJniTrace(getPath(), SHOW_LTT_DEBUG_DEFAULT);
224 } catch (JniException e) {
225 // e.printStackTrace();
226 }
227
228 // Export all the event types from the JNI side
229 clone.traceTypes = new HashMap<String, LttngEventType>();
230 clone.traceTypeNames = new Vector<String>();
231 clone.initialiseEventTypes(clone.currentJniTrace);
232
233 // Verify that all those "default constructor" are safe to use
234 clone.eventTimestamp = new LttngTimestamp();
235 clone.eventSource = new LttngEventSource();
236 clone.eventType = new LttngEventType();
237 clone.eventContent = new LttngEventContent(clone.currentLttngEvent);
238 clone.eventReference = new LttngEventReference(this.getName());
239
240 // Create the skeleton event
241 clone.currentLttngEvent = new LttngEvent(this, clone.eventTimestamp, clone.eventSource, clone.eventType, clone.eventContent, clone.eventReference, null);
242
243 // Create a new current location
244 clone.previousLocation = new LttngLocation();
245
246 // Set the currentEvent to the eventContent
247 clone.eventContent.setEvent(clone.currentLttngEvent);
248
249 // Set the start time of the trace
250 setTimeRange(new TmfTimeRange(
251 new LttngTimestamp(clone.currentJniTrace.getStartTime().getTime()),
252 new LttngTimestamp(clone.currentJniTrace.getEndTime().getTime())
253 ));
254 }
255 catch (CloneNotSupportedException e) {
256 }
257
258 return clone;
259 }
260
261
262 /*
263 * Fill out the HashMap with "Type" (Tracefile/Marker)
264 *
265 * This should be called at construction once the trace is open
266 */
267 private void initialiseEventTypes(JniTrace trace) {
268 // Work variables
269 LttngEventType tmpType = null;
270 String[] markerFieldsLabels = null;
271
272 String newTracefileKey = null;
273 Integer newMarkerKey = null;
274
275 JniTracefile newTracefile = null;
276 JniMarker newMarker = null;
277
278 // First, obtain an iterator on TRACEFILES of owned by the TRACE
279 Iterator<String> tracefileItr = trace.getTracefilesMap().keySet().iterator();
280 while ( tracefileItr.hasNext() ) {
281 newTracefileKey = tracefileItr.next();
282 newTracefile = trace.getTracefilesMap().get(newTracefileKey);
283
284 // From the TRACEFILE read, obtain its MARKER
285 Iterator<Integer> markerItr = newTracefile.getTracefileMarkersMap().keySet().iterator();
286 while ( markerItr.hasNext() ) {
287 newMarkerKey = markerItr.next();
288 newMarker = newTracefile.getTracefileMarkersMap().get(newMarkerKey);
289
290 // From the MARKER we can obtain the MARKERFIELDS keys (i.e. labels)
291 markerFieldsLabels = newMarker.getMarkerFieldsHashMap().keySet().toArray( new String[newMarker.getMarkerFieldsHashMap().size()] );
292 tmpType = new LttngEventType(newTracefile.getTracefileName(), newTracefile.getCpuNumber(), newMarker.getName(), markerFieldsLabels );
293
294 // Add the type to the map/vector
295 addEventTypeToMap(tmpType);
296 }
297 }
298 }
299
300 /*
301 * Add a new type to the HashMap
302 *
303 * As the hashmap use a key format that is a bit dangerous to use, we should always add using this function.
304 */
305 private void addEventTypeToMap(LttngEventType newEventType) {
306 String newTypeKey = EventTypeKey.getEventTypeKey(newEventType);
307
308 this.traceTypes.put(newTypeKey, newEventType);
309 this.traceTypeNames.add(newTypeKey);
310 }
311
312 // /**
313 // * Index the current trace.
314 // *
315 // * @param useless This boolean is only to comply to the interface and will be ignored.
316 // */
317 // @Override
318 // public synchronized void indexTrace(boolean useless) {
319 //
320 // long nbEvents=0L;
321 //
322 // // Start time need to be null to detect none have been set
323 // // LastTime need to exist so we can ajust it as we go
324 // LttngTimestamp startTime = null;
325 // LttngTimestamp lastTime = new LttngTimestamp();
326 //
327 // // Position the trace at the beginning
328 // TmfContext context = seekEvent( new LttngTimestamp(0L) );
329 //
330 // // Read the first event and extract the location
331 // LttngEvent tmpEvent = (LttngEvent)getNextEvent(context);
332 //
333 // // If we read the first event, define the start time.
334 // if ( tmpEvent != null ) {
335 // startTime = new LttngTimestamp( tmpEvent.getTimestamp() );
336 // lastTime.setValue(tmpEvent.getTimestamp().getValue());
337 // }
338 //
339 // // Now, we read each event until we hit the end of the trace
340 // // We will create a new checkpoint every "getCacheSize()" event
341 // while ( tmpEvent != null) {
342 // // Update the last time each time we read a new event
343 // lastTime.setValue(tmpEvent.getTimestamp().getValue());
344 //
345 // // Save a check point if needed
346 // if ((nbEvents++ % getCacheSize()) == 0) {
347 // // *** IMPORTANT
348 // // We need to NEW each stuff we put in checkpoint
349 // // Otherwise everything will be the same!
350 // LttngTimestamp tmpTimestamp = new LttngTimestamp( (LttngTimestamp)tmpEvent.getTimestamp() );
351 // LttngLocation newLocation = new LttngLocation( (LttngTimestamp)tmpEvent.getTimestamp() );
352 //
353 // fCheckpoints.add(new TmfCheckpoint(tmpTimestamp, newLocation ) );
354 // }
355 // // Read the next event
356 // tmpEvent = (LttngEvent)getNextEvent(context);
357 // }
358 //
359 // // If we have a start time, we should have an end time as well
360 // // Issue the new range
361 // if (startTime != null) {
362 // setTimeRange( new TmfTimeRange(startTime, lastTime) );
363 // notifyListeners(getTimeRange() );
364 // }
365 //
366 // // Ajust the total number of event in the trace
367 // fNbEvents = nbEvents;
368 // //printCheckpointsVector();
369 // //printDebug = true;
370 // }
371
372 /**
373 * Return the latest saved location.
374 * Note : Modifying the returned location may result in buggy positionning!
375 *
376 * @return The LttngLocation as it was after the last operation.
377 *
378 * @see org.eclipse.linuxtools.lttng.event.LttngLocation
379 */
380 @Override
381 public synchronized ITmfLocation<?> getCurrentLocation() {
382 return previousLocation;
383 }
384
385 /**
386 * Position the trace to the event at the given location.<p>
387 * NOTE : Seeking by location is very fast compare to seeking by position
388 * but is still slower than "ReadNext", avoid using it for small interval.
389 *
390 * @param location Location of the event in the trace.
391 * If no event available at this exact location, we will position ourself to the next one.
392 *
393 * @return The TmfContext that point to this event
394 *
395 * @see org.eclipse.linuxtools.lttng.event.LttngLocation
396 * @see org.eclipse.linuxtools.tmf.trace.TmfContext
397 */
398 @Override
399 public synchronized TmfContext seekLocation(ITmfLocation<?> location) {
400
401 // // [lmcfrch]
402 // lastTime = 0;
403
404 if ( printDebug == true ) {
405 System.out.println("seekLocation(location) location -> " + location);
406 }
407
408 // If the location in context is null, create a new one
409 LttngLocation curLocation = null;
410 if ( location == null ) {
411 curLocation = new LttngLocation();
412 TmfContext context = seekEvent(curLocation.getOperationTime());
413 context.setRank(ITmfContext.INITIAL_RANK);
414 return context;
415 }
416 else {
417 curLocation = (LttngLocation)location;
418 }
419
420 // *** NOTE :
421 // Update to location should (and will) be done in SeekEvent.
422
423 // The only seek valid in LTTng is with the time, we call seekEvent(timestamp)
424 TmfContext context = seekEvent(curLocation.getOperationTime());
425
426 // // Adjust the previousLocation flags
427 // if (location instanceof LttngLocation) {
428 // LttngLocation lttngLocation = (LttngLocation) location;
429 // if (lttngLocation.isLastOperationReadNext()) {
430 // previousLocation.setLastOperationReadNext();
431 // } else if (lttngLocation.isLastOperationParse()) {
432 // previousLocation.setLastOperationParse();
433 // } else if (lttngLocation.isLastOperationSeek()) {
434 // previousLocation.setLastOperationSeek();
435 // }
436 // }
437
438 return context;
439 }
440
441 /**
442 * Position the trace to the event at the given time.<p>
443 * NOTE : Seeking by time is very fast compare to seeking by position
444 * but is still slower than "ReadNext", avoid using it for small interval.
445 *
446 * @param timestamp Time of the event in the trace.
447 * If no event available at this exact time, we will position ourself to the next one.
448 *
449 * @return The TmfContext that point to this event
450 *
451 * @see org.eclipse.linuxtools.lttng.event.LttngLocation
452 * @see org.eclipse.linuxtools.tmf.trace.TmfContext
453 */
454 @Override
455 public synchronized TmfContext seekEvent(TmfTimestamp timestamp) {
456
457 // // [lmcfrch]
458 // lastTime = 0;
459
460 if ( printDebug == true ) {
461 System.out.println("seekEvent(timestamp) timestamp -> " + timestamp);
462 }
463
464 // Call JNI to seek
465 currentJniTrace.seekToTime(new JniTime(timestamp.getValue()));
466
467 // Save the time at which we seeked
468 previousLocation.setOperationTime(timestamp.getValue());
469 // Set the operation marker as seek, to be able to detect we did "seek" this event
470 previousLocation.setLastOperationSeek();
471
472 // *** VERIFY ***
473 // Is that too paranoid?
474 //
475 // We don't trust what upper level could do with our internal location
476 // so we create a new one to return instead
477 LttngLocation curLocation = new LttngLocation(previousLocation);
478
479 return new TmfContext( curLocation );
480 }
481
482 /**
483 * Position the trace to the event at the given position (rank).<p>
484 * NOTE : Seeking by position is very slow in LTTng, consider seeking by timestamp.
485 *
486 * @param position Position (or rank) of the event in the trace, starting at 0.
487 *
488 * @return The TmfContext that point to this event
489 *
490 * @see org.eclipse.linuxtools.lttng.event.LttngLocation
491 * @see org.eclipse.linuxtools.tmf.trace.TmfContext
492 */
493 @Override
494 public synchronized TmfContext seekEvent(long position) {
495
496 if ( printDebug == true ) {
497 System.out.println("seekEvent(position) position -> " + position);
498 }
499
500 TmfTimestamp timestamp = null;
501 long index = position / getCacheSize();
502
503 // Get the timestamp of the closest check point to the given position
504 if (fCheckpoints.size() > 0) {
505 if (index >= fCheckpoints.size()) {
506 index = fCheckpoints.size() - 1;
507 }
508 timestamp = (TmfTimestamp)fCheckpoints.elementAt((int)index).getTimestamp();
509 }
510 // If none, take the start time of the trace
511 else {
512 timestamp = getStartTime();
513 }
514
515 // Seek to the found time
516 TmfContext tmpContext = seekEvent(timestamp);
517 tmpContext.setRank((index + 1) * fIndexPageSize);
518 previousLocation = (LttngLocation)tmpContext.getLocation();
519
520 // Ajust the index of the event we found at this check point position
521 Long currentPosition = index * getCacheSize();
522
523 Long lastTimeValueRead = 0L;
524
525 // Get the event at current position. This won't move to the next one
526 JniEvent tmpJniEvent = currentJniTrace.findNextEvent();
527 // Now that we are positionned at the checkpoint,
528 // we need to "readNext" (Position - CheckpointPosition) times or until trace "run out"
529 while ( (tmpJniEvent != null) && ( currentPosition < position ) ) {
530 tmpJniEvent = currentJniTrace.readNextEvent();
531 currentPosition++;
532 }
533
534 // If we found our event, save its timestamp
535 if ( tmpJniEvent != null ) {
536 lastTimeValueRead = tmpJniEvent.getEventTime().getTime();
537 }
538
539 // Set the operation marker as seek, to be able to detect we did "seek" this event
540 previousLocation.setLastOperationSeek();
541 // Save read event time
542 previousLocation.setOperationTime(lastTimeValueRead);
543
544 // *** VERIFY ***
545 // Is that too paranoid?
546 //
547 // We don't trust what upper level could do with our internal location
548 // so we create a new one to return instead
549 LttngLocation curLocation = new LttngLocation(previousLocation);
550
551 return new TmfContext( curLocation );
552 }
553
554 /**
555 * Return the event in the trace according to the given context. Read it if necessary.<p>
556 * Similar (same?) as ParseEvent except that calling GetNext twice read the next one the second time.
557 *
558 * @param context Current TmfContext where to get the event
559 *
560 * @return The LttngEvent we read of null if no event are available
561 *
562 * @see org.eclipse.linuxtools.lttng.event.LttngLocation
563 * @see org.eclipse.linuxtools.tmf.trace.TmfContext
564 */
565
566 public int nbEventsRead = 0;
567 @Override
568 public synchronized LttngEvent getNextEvent(TmfContext context) {
569
570 if ( printDebug == true ) {
571 System.out.println("getNextEvent(context) context.getLocation() -> " + context.getLocation());
572 }
573
574 LttngEvent returnedEvent = null;
575 LttngLocation curLocation = null;
576
577 // If the location in context is null, create a new one
578 if ( context.getLocation() == null ) {
579 curLocation = new LttngLocation();
580 context.setLocation(curLocation);
581 }
582 else {
583 // Otherwise, we use the one in context; it should be a valid LttngLocation
584 curLocation = (LttngLocation)context.getLocation();
585 }
586
587 //// [lmcfrch]
588 // TmfContext savedContext = context.clone();
589 //// [/lmcfrch]
590
591 // *** HACK ***
592 // TMF assumes it is possible to read (GetNextEvent) to the next Event once ParseEvent() is called
593 // In LTTNG, there is not difference between "Parsing" and "Reading" an event.
594 // Since parsing/reading invalidate the previous event,
595 // we need to make sure the sequence ParseEvent() -> GetNextEvent() will not actually move to the next event.
596 // To do so, we avoid moving for call to "GetNextEvent()" that follow call to a call to "ParseEvent()".
597 // However, calling ParseEvent() -> GetNextEvent() -> GetNextEvent() will only move next by one.
598
599 // *** Positioning trick :
600 // GetNextEvent only read the trace if :
601 // 1- The last operation was NOT a ParseEvent --> A read is required
602 // OR
603 // 2- The time of the previous location is different from the current one --> A seek + a read is required
604 if ( (curLocation.isLastOperationParse() != true) ||
605 (previousLocation.getOperationTimeValue() != curLocation.getOperationTimeValue() ) )
606 {
607 if ( previousLocation.getOperationTimeValue() != curLocation.getOperationTimeValue() ) {
608 if ( printDebug == true ) {
609 System.out.println("\t\tSeeking in getNextEvent. [ LastTime : " + previousLocation.getOperationTimeValue() + " CurrentTime" + curLocation.getOperationTimeValue() + " ]");
610 }
611 seekEvent( curLocation.getOperationTime() );
612 }
613 // Read the next event from the trace. The last one will NO LONGER BE VALID.
614 returnedEvent = readEvent(curLocation);
615 nbEventsRead++;
616
617 // Set the operation marker as read to both location, to be able to detect we did "read" this event
618 previousLocation.setLastOperationReadNext();
619 curLocation.setLastOperationReadNext();
620 }
621 else {
622 // No event was read, just return the one currently loaded (the last one we read)
623 returnedEvent = currentLttngEvent;
624
625 // *** IMPORTANT!
626 // Reset (erase) the operation marker to both location, to be able to detect we did NOT "read" this event
627 previousLocation.resetLocationState();
628 curLocation.resetLocationState();
629 }
630
631 // If we read an event, set it's time to the locations (both previous and current)
632 if ( returnedEvent != null ) {
633 previousLocation.setOperationTime((LttngTimestamp)returnedEvent.getTimestamp());
634 curLocation.setOperationTime((LttngTimestamp)returnedEvent.getTimestamp());
635
636 //// [lmcfrch]
637 // LttngLocation prevLocation = (LttngLocation) savedContext.getLocation();
638 // LttngLocation currLocation = (LttngLocation) context.getLocation();
639 // if (prevLocation.equals(currLocation)) {
640 // System.out.println("Aie");
641 // }
642 // Tracer.trace("Trc: " + context.getRank() + ": " + returnedEvent.getTimestamp().toString() + " (" +
643 // (prevLocation.isLastOperationParse() ? "T" : "F") + "," + (prevLocation.isLastOperationReadNext() ? "T" : "F") + "," + (prevLocation.isLastOperationSeek() ? "T" : "F") + "), (" +
644 // (currLocation.isLastOperationParse() ? "T" : "F") + "," + (currLocation.isLastOperationReadNext() ? "T" : "F") + "," + (currLocation.isLastOperationSeek() ? "T" : "F") + ")"
645 // );
646 //// [/lmcfrch]
647
648 updateIndex(context, context.getRank(), returnedEvent.getTimestamp());
649 context.updateRank(1);
650 }
651
652 return returnedEvent;
653 }
654
655
656 /**
657 * Return the event in the trace according to the given context. Read it if necessary.<p>
658 * Similar (same?) as GetNextEvent except that calling ParseEvent twice will return the same event
659 *
660 * @param context Current TmfContext where to get the event
661 *
662 * @return The LttngEvent we read of null if no event are available
663 *
664 * @see org.eclipse.linuxtools.lttng.event.LttngLocation
665 * @see org.eclipse.linuxtools.tmf.trace.TmfContext
666 */
667 @Override
668 public synchronized LttngEvent parseEvent(TmfContext context) {
669
670 if ( printDebug == true ) {
671 System.out.println("parseEvent(context) context.getLocation() -> " + context.getLocation());
672 }
673
674 LttngEvent returnedEvent = null;
675 LttngLocation curLocation = null;
676
677 // If the location in context is null, create a new one
678 if ( context.getLocation() == null ) {
679 curLocation = new LttngLocation();
680 context.setLocation(curLocation);
681 }
682 // Otherwise, we use the one in context; it should be a valid LttngLocation
683 else {
684 curLocation = (LttngLocation)context.getLocation();
685 }
686
687 // *** HACK ***
688 // TMF assumes it is possible to read (GetNextEvent) to the next Event once ParseEvent() is called
689 // In LTTNG, there is not difference between "Parsing" and "Reading" an event.
690 // So, before "Parsing" an event, we have to make sure we didn't "Read" it alreafy.
691 // Also, "Reading" invalidate the previous Event in LTTNG and seek back is very costly,
692 // so calling twice "Parse" will return the same event, giving a way to get the "Currently loaded" event
693
694 // *** Positionning trick :
695 // ParseEvent only read the trace if :
696 // 1- The last operation was NOT a ParseEvent or a GetNextEvent --> A read is required
697 // OR
698 // 2- The time of the previous location is different from the current one --> A seek + a read is required
699 if ( ( (curLocation.isLastOperationParse() != true) && ((curLocation.isLastOperationReadNext() != true)) ) ||
700 (previousLocation.getOperationTimeValue() != curLocation.getOperationTimeValue() ) )
701 {
702 // Previous time != Current time : We need to reposition to the current time
703 if (previousLocation.getOperationTimeValue() != curLocation.getOperationTimeValue() ) {
704 if ( printDebug == true ) {
705 System.out.println("\t\tSeeking in getNextEvent. [ LastTime : " + previousLocation.getOperationTimeValue() + " CurrentTime" + curLocation.getOperationTimeValue() + " ]");
706 }
707 seekEvent( curLocation.getOperationTime() );
708 }
709
710 // Read the next event from the trace. The last one will NO LONGER BE VALID.
711 returnedEvent = readEvent(curLocation);
712 }
713 else {
714 // No event was read, just return the one currently loaded (the last one we read)
715 returnedEvent = currentLttngEvent;
716 }
717
718 // If we read an event, set it's time to the locations (both previous and current)
719 if ( returnedEvent != null ) {
720 previousLocation.setOperationTime((LttngTimestamp)returnedEvent.getTimestamp());
721 curLocation.setOperationTime((LttngTimestamp)returnedEvent.getTimestamp());
722 }
723
724 // Set the operation marker as parse to both location, to be able to detect we already "read" this event
725 previousLocation.setLastOperationParse();
726 curLocation.setLastOperationParse();
727
728 return returnedEvent;
729 }
730
731 /*
732 * Read the next event from the JNI and convert it as Lttng Event<p>
733 *
734 * @param location Current LttngLocation that to be updated with the event timestamp
735 *
736 * @return The LttngEvent we read of null if no event are available
737 *
738 * @see org.eclipse.linuxtools.lttng.event.LttngLocation
739 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniTrace
740 */
741 private synchronized LttngEvent readEvent(LttngLocation location) {
742 LttngEvent returnedEvent = null;
743 JniEvent tmpEvent = null;
744
745 // Read the next event from JNI. THIS WILL INVALIDATE THE CURRENT LTTNG EVENT.
746 tmpEvent = currentJniTrace.readNextEvent();
747
748 if ( tmpEvent != null ) {
749 // *** NOTE
750 // Convert will update the currentLttngEvent
751 returnedEvent = convertJniEventToTmf(tmpEvent);
752
753 location.setOperationTime( (LttngTimestamp)returnedEvent.getTimestamp() );
754 }
755 // *** NOTE
756 // If the read failed (likely the last event in the trace), set the LastReadTime to the JNI time
757 // That way, even if we try to read again, we will step over the bogus seek and read
758 else {
759 location.setOperationTime( getEndTime().getValue() + 1 );
760 }
761
762 return returnedEvent;
763 }
764
765 /**
766 * Method to convert a JniEvent into a LttngEvent.<p>
767 *
768 * Note : This method will call LttngEvent convertEventJniToTmf(JniEvent, boolean)
769 * with a default value for isParsingNeeded
770 *
771 * @param newEvent The JniEvent to convert into LttngEvent
772 *
773 * @return The converted LttngEvent
774 *
775 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniEvent
776 * @see org.eclipse.linuxtools.lttng.event.LttngEvent
777 */
778 public synchronized LttngEvent convertJniEventToTmf(JniEvent newEvent) {
779 currentLttngEvent = convertJniEventToTmf(newEvent, IS_PARSING_NEEDED_DEFAULT);
780
781 return currentLttngEvent;
782 }
783
784 /**
785 * Method to convert a JniEvent into a LttngEvent
786 *
787 * @param jniEvent The JniEvent to convert into LttngEvent
788 * @param isParsingNeeded A boolean value telling if the event should be parsed or not.
789 *
790 * @return The converted LttngEvent
791 *
792 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniEvent
793 * @see org.eclipse.linuxtools.lttng.event.LttngEvent
794 */
795 public synchronized LttngEvent convertJniEventToTmf(JniEvent jniEvent, boolean isParsingNeeded) {
796
797 if ( uniqueEvent == true ) {
798
799 // ***
800 // UNHACKED : We can no longer do that because TCF need to maintain several events at once.
801 // This is very slow to do so in LTTng, this has to be temporary.
802 // *** HACK ***
803 // To save time here, we only set value instead of allocating new object
804 // This give an HUGE performance improvement
805 // all allocation done in the LttngTrace constructor
806 // ***
807 eventTimestamp.setValue(jniEvent.getEventTime().getTime());
808 eventSource.setSourceId(jniEvent.requestEventSource());
809
810 eventType = traceTypes.get( EventTypeKey.getEventTypeKey(jniEvent) );
811
812 eventReference.setValue(jniEvent.getParentTracefile().getTracefilePath());
813 eventReference.setTracepath(this.getName());
814
815 eventContent.emptyContent();
816
817 currentLttngEvent.setType(eventType);
818 // Save the jni reference
819 currentLttngEvent.updateJniEventReference(jniEvent);
820
821 // Parse now if was asked
822 // Warning : THIS IS SLOW
823 if (isParsingNeeded == true ) {
824 eventContent.getFields();
825 }
826
827 return currentLttngEvent;
828 }
829 else {
830 return convertJniEventToTmfMultipleEventEvilFix(jniEvent, isParsingNeeded);
831 }
832
833 }
834
835 /**
836 * This method is a temporary fix to support multiple events at once in TMF
837 * This is expected to be slow and should be fixed in another way.
838 * See comment in convertJniEventToTmf();
839 *
840 * @param jniEvent The current JNI Event
841 * @return Current Lttng Event fully parsed
842 */
843 private synchronized LttngEvent convertJniEventToTmfMultipleEventEvilFix(JniEvent jniEvent, boolean isParsingNeeded) {
844 // *** HACK ***
845 // Below : the "fix" with all the new and the full-parse
846 // Allocating new memory is slow.
847 // Parsing every events is very slow.
848 eventTimestamp = new LttngTimestamp(jniEvent.getEventTime().getTime());
849 eventSource = new LttngEventSource(jniEvent.requestEventSource());
850 eventReference = new LttngEventReference(jniEvent.getParentTracefile().getTracefilePath(), this.getName());
851 eventType = new LttngEventType(traceTypes.get( EventTypeKey.getEventTypeKey(jniEvent) ));
852 eventContent = new LttngEventContent(currentLttngEvent);
853 currentLttngEvent = new LttngEvent(this, eventTimestamp, eventSource, eventType, eventContent, eventReference, null);
854
855 // The jni reference is no longer reliable but we will keep it anyhow
856 currentLttngEvent.updateJniEventReference(jniEvent);
857 // Ensure that the content is correctly set
858 eventContent.setEvent(currentLttngEvent);
859
860 // Parse the event if it was needed
861 // *** WARNING ***
862 // ONLY for testing, NOT parsing events with non-unique events WILL result in segfault in the JVM
863 if ( isParsingNeeded == true ) {
864 eventContent.getFields();
865 }
866
867 return currentLttngEvent;
868 }
869
870
871
872 /**
873 * Reference to the current LttngTrace we are reading from.<p>
874 *
875 * Note : This bypass the framework and should not be use, except for testing!
876 *
877 * @return Reference to the current LttngTrace
878 *
879 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniTrace
880 */
881 public JniTrace getCurrentJniTrace() {
882 return currentJniTrace;
883 }
884
885
886 /**
887 * Return a reference to the current LttngEvent we have in memory.
888 *
889 * @return The current (last read) LttngEvent
890 *
891 * @see org.eclipse.linuxtools.lttng.event.LttngEvent
892 */
893 public synchronized LttngEvent getCurrentEvent() {
894 return currentLttngEvent;
895 }
896
897 /**
898 * Get the major version number for the current trace
899 *
900 * @return Version major or -1 if unknown
901 *
902 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniTrace
903 *
904 */
905 public short getVersionMajor() {
906 if ( currentJniTrace!= null ) {
907 return currentJniTrace.getLttMajorVersion();
908 }
909 else {
910 return -1;
911 }
912 }
913
914 /**
915 * Get the minor version number for the current trace
916 *
917 * @return Version minor or -1 if unknown
918 *
919 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniTrace
920 *
921 */
922 public short getVersionMinor() {
923 if ( currentJniTrace!= null ) {
924 return currentJniTrace.getLttMinorVersion();
925 }
926 else {
927 return -1;
928 }
929 }
930
931 /**
932 * Get the number of CPU for this trace
933 *
934 * @return Number of CPU or -1 if unknown
935 *
936 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniTrace
937 *
938 */
939 public int getCpuNumber() {
940 if ( currentJniTrace!= null ) {
941 return currentJniTrace.getCpuNumber();
942 }
943 else {
944 return -1;
945 }
946 }
947
948 /**
949 * Print the content of the checkpoint vector.<p>
950 *
951 * This is intended for debug purpose only.
952 */
953 public void printCheckpointsVector() {
954 System.out.println("StartTime : " + getTimeRange().getStartTime().getValue());
955 System.out.println("EndTime : " + getTimeRange().getEndTime().getValue());
956
957 for ( int pos=0; pos < fCheckpoints.size(); pos++) {
958 System.out.print(pos + ": " + "\t");
959 System.out.print( fCheckpoints.get(pos).getTimestamp() + "\t" );
960 System.out.println( fCheckpoints.get(pos).getLocation() );
961 }
962 }
963
964 /**
965 * Return a String identifying this trace.
966 *
967 * @return String that identify this trace
968 */
969 @Override
970 public String toString() {
971 String returnedData="";
972
973 returnedData += "Path :" + getPath() + " ";
974 returnedData += "Trace:" + currentJniTrace + " ";
975 returnedData += "Event:" + currentLttngEvent;
976
977 return returnedData;
978 }
979
980 }
981
982 /*
983 * EventTypeKey inner class
984 *
985 * This class is used to make the process of generating the HashMap key more transparent and so less error prone to use
986 *
987 */
988 class EventTypeKey {
989 //*** WARNING ***
990 // These two getEventTypeKey() functions should ALWAYS construct the key the same ways!
991 // Otherwise, every type search will fail!
992
993 static public String getEventTypeKey(LttngEventType newEventType) {
994 String key = newEventType.getTracefileName() + "/" + newEventType.getCpuId().toString() + "/" + newEventType.getMarkerName();
995
996 return key;
997 }
998
999 static public String getEventTypeKey(JniEvent newEvent) {
1000 String key = newEvent.getParentTracefile().getTracefileName() + "/" + newEvent.getParentTracefile().getCpuNumber() + "/" + newEvent.requestEventMarker().getName();
1001
1002 return key;
1003 }
1004
1005 }
This page took 0.054375 seconds and 5 git commands to generate.