2010-11-10 Francois Chouinard <fchouinard@gmail.com> Contribution for Bug315307
[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.TmfCheckpoint;
39 import org.eclipse.linuxtools.tmf.trace.TmfContext;
40 import org.eclipse.linuxtools.tmf.trace.TmfTrace;
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>
52 * <p>
53 *
54 * LTTng trace implementation. It accesses the C trace handling library
55 * (seeking, reading and parsing) through the JNI component.
56 */
57 public class LTTngTrace extends TmfTrace<LttngEvent> {
58
59 public static boolean PrintDebug = false;
60 public static boolean UniqueEvent = true;
61
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;
65
66 // Reference to our JNI trace
67 private JniTrace currentJniTrace = null;
68
69 // ***
70 // UNHACKED : We can no longer do that because TCF need to maintain several
71 // events at once.
72 // This is very slow to do so in LTTng, this has to be temporary.
73 // *** HACK ***
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
78 // ***
79 LttngTimestamp eventTimestamp = null;
80 LttngEventSource eventSource = null;
81 LttngEventContent eventContent = null;
82 LttngEventReference eventReference = null;
83
84 // The actual event
85 LttngEvent currentLttngEvent = null;
86
87 // The current location
88 LttngLocation previousLocation = null;
89
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;
95
96 /**
97 * Default Constructor.
98 * <p>
99 *
100 * @param path
101 * Path to a <b>directory</b> that contain an LTTng trace.
102 *
103 * @exception Exception
104 * (most likely LTTngTraceException or FileNotFoundException)
105 */
106 public LTTngTrace(String path) throws Exception {
107 // Call with "wait for completion" true and "skip indexing" false
108 this(path, true, false);
109 }
110
111 /**
112 * Constructor, with control over the indexing.
113 * <p>
114 *
115 * @param path
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.
119 *
120 * @exception Exception
121 * (most likely LTTngTraceException or FileNotFoundException)
122 */
123 public LTTngTrace(String path, boolean waitForCompletion) throws Exception {
124 // Call with "skip indexing" false
125 this(path, waitForCompletion, false);
126 }
127
128 /**
129 * Default constructor, with control over the indexing and possibility to
130 * bypass indexation
131 * <p>
132 *
133 * @param path
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.
140 *
141 * @exception Exception
142 * (most likely LTTngTraceException or FileNotFoundException)
143 *
144 */
145 public LTTngTrace(String path, boolean waitForCompletion,
146 boolean bypassIndexing) throws Exception {
147 super(path, LttngEvent.class, path, CHECKPOINT_PAGE_SIZE);
148 try {
149 currentJniTrace = JniTraceFactory.getJniTrace(path,
150 SHOW_LTT_DEBUG_DEFAULT);
151 } catch (Exception e) {
152 throw new LTTngTraceException(e.getMessage());
153 }
154
155 // Export all the event types from the JNI side
156 traceTypes = new HashMap<Integer, LttngEventType>();
157 traceTypeNames = new Vector<Integer>();
158 initialiseEventTypes(currentJniTrace);
159
160 // *** VERIFY ***
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());
167
168 // Create the skeleton event
169 currentLttngEvent = new LttngEvent(this, eventTimestamp, eventSource,
170 eventType, eventContent, eventReference, null);
171
172 // Create a new current location
173 previousLocation = new LttngLocation();
174
175 // Set the currentEvent to the eventContent
176 eventContent.setEvent(currentLttngEvent);
177
178 // // Bypass indexing if asked
179 // if ( bypassIndexing == false ) {
180 // indexTrace(true);
181 // }
182 // else {
183 // Even if we don't have any index, set ONE checkpoint
184 // fCheckpoints.add(new TmfCheckpoint(new LttngTimestamp(0L) , new
185 // LttngLocation() ) );
186
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());
193
194 setTimeRange(new TmfTimeRange(startTime, endTime));
195
196 }
197
198 /*
199 * Copy constructor is forbidden for LttngEvenmStream
200 */
201 public LTTngTrace(LTTngTrace oldTrace) throws Exception {
202 this(oldTrace.getPath(), false, true);
203
204 // *** VERIFY ***
205 // Is this safe?
206 this.fCheckpoints = oldTrace.fCheckpoints;
207
208 /*
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()) ); }
216 */
217
218 // Set the start time of the trace
219 setTimeRange(new TmfTimeRange(new LttngTimestamp(
220 oldTrace.getStartTime()), new LttngTimestamp(
221 oldTrace.getEndTime())));
222 }
223
224
225
226 @Override
227 public LTTngTrace createTraceCopy() {
228 LTTngTrace returnedTrace = null;
229
230 try {
231 returnedTrace = new LTTngTrace(this);
232 }
233 catch (Exception e) {
234 System.out.println("ERROR : Could not create LTTngTrace copy (createTraceCopy).\nError is : " + e.getStackTrace()); //$NON-NLS-1$
235 }
236
237 return returnedTrace;
238 }
239
240 @Override
241 public synchronized LTTngTrace clone() {
242 LTTngTrace clone = null;
243 try {
244 clone = (LTTngTrace) super.clone();
245 try {
246 clone.currentJniTrace = JniTraceFactory.getJniTrace(getPath(), SHOW_LTT_DEBUG_DEFAULT);
247 } catch (JniException e) {
248 // e.printStackTrace();
249 }
250
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);
255
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());
262
263 // Create the skeleton event
264 clone.currentLttngEvent = new LttngEvent(this,
265 clone.eventTimestamp, clone.eventSource, clone.eventType,
266 clone.eventContent, clone.eventReference, null);
267
268 // Create a new current location
269 clone.previousLocation = new LttngLocation();
270
271 // Set the currentEvent to the eventContent
272 clone.eventContent.setEvent(clone.currentLttngEvent);
273
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()
278 .getTime())));
279 } catch (CloneNotSupportedException e) {
280 }
281
282 return clone;
283 }
284
285 /*
286 * Fill out the HashMap with "Type" (Tracefile/Marker)
287 *
288 * This should be called at construction once the trace is open
289 */
290 private void initialiseEventTypes(JniTrace trace) {
291 // Work variables
292 LttngEventType tmpType = null;
293 String[] markerFieldsLabels = null;
294
295 String newTracefileKey = null;
296 Integer newMarkerKey = null;
297
298 JniTracefile newTracefile = null;
299 JniMarker newMarker = null;
300
301 // First, obtain an iterator on TRACEFILES of owned by the TRACE
302 Iterator<String> tracefileItr = trace.getTracefilesMap().keySet()
303 .iterator();
304 while (tracefileItr.hasNext()) {
305 newTracefileKey = tracefileItr.next();
306 newTracefile = trace.getTracefilesMap().get(newTracefileKey);
307
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(
314 newMarkerKey);
315
316 // From the MARKER we can obtain the MARKERFIELDS keys (i.e.
317 // labels)
318 markerFieldsLabels = newMarker
319 .getMarkerFieldsHashMap()
320 .keySet()
321 .toArray(
322 new String[newMarker.getMarkerFieldsHashMap()
323 .size()]);
324 tmpType = new LttngEventType(newTracefile.getTracefileName(),
325 newTracefile.getCpuNumber(), newMarker.getName(),
326 markerFieldsLabels);
327
328 // Add the type to the map/vector
329 addEventTypeToMap(tmpType);
330 }
331 }
332 }
333
334 /*
335 * Add a new type to the HashMap
336 *
337 * As the hashmap use a key format that is a bit dangerous to use, we should
338 * always add using this function.
339 */
340 private void addEventTypeToMap(LttngEventType newEventType) {
341 int newTypeKey = EventTypeKey.getEventTypeHash(newEventType);
342
343 this.traceTypes.put(newTypeKey, newEventType);
344 this.traceTypeNames.add(newTypeKey);
345 }
346
347 // /**
348 // * Index the current trace.
349 // *
350 // * @param useless This boolean is only to comply to the interface and will
351 // be ignored.
352 // */
353 // @Override
354 // public synchronized void indexTrace(boolean useless) {
355 //
356 // long nbEvents=0L;
357 //
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();
362 //
363 // // Position the trace at the beginning
364 // TmfContext context = seekEvent( new LttngTimestamp(0L) );
365 //
366 // // Read the first event and extract the location
367 // LttngEvent tmpEvent = (LttngEvent)getNextEvent(context);
368 //
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());
373 // }
374 //
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());
380 //
381 // // Save a check point if needed
382 // if ((nbEvents++ % getCacheSize()) == 0) {
383 // // *** IMPORTANT
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() );
390 //
391 // fCheckpoints.add(new TmfCheckpoint(tmpTimestamp, newLocation ) );
392 // }
393 // // Read the next event
394 // tmpEvent = (LttngEvent)getNextEvent(context);
395 // }
396 //
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() );
402 // }
403 //
404 // // Ajust the total number of event in the trace
405 // fNbEvents = nbEvents;
406 // //printCheckpointsVector();
407 // //printDebug = true;
408 // }
409
410 /**
411 * Return the latest saved location. Note : Modifying the returned location
412 * may result in buggy positionning!
413 *
414 * @return The LttngLocation as it was after the last operation.
415 *
416 * @see org.eclipse.linuxtools.lttng.event.LttngLocation
417 */
418 @Override
419 public synchronized ITmfLocation<?> getCurrentLocation() {
420 return previousLocation;
421 }
422
423 /**
424 * Position the trace to the event at the given location.
425 * <p>
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.
428 *
429 * @param location
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.
432 *
433 * @return The TmfContext that point to this event
434 *
435 * @see org.eclipse.linuxtools.lttng.event.LttngLocation
436 * @see org.eclipse.linuxtools.tmf.trace.TmfContext
437 */
438 @Override
439 public synchronized TmfContext seekLocation(ITmfLocation<?> location) {
440
441 // // [lmcfrch]
442 // lastTime = 0;
443
444 if (PrintDebug) {
445 System.out
446 .println("seekLocation(location) location -> " + location); //$NON-NLS-1$
447 }
448
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);
455 return context;
456 } else {
457 curLocation = (LttngLocation) location;
458 }
459
460 // *** NOTE :
461 // Update to location should (and will) be done in SeekEvent.
462
463 // The only seek valid in LTTng is with the time, we call
464 // seekEvent(timestamp)
465 TmfContext context = seekEvent(curLocation.getOperationTime());
466
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();
476 // }
477 // }
478
479 return context;
480 }
481
482 /**
483 * Position the trace to the event at the given time.
484 * <p>
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.
487 *
488 * @param timestamp
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.
491 *
492 * @return The TmfContext that point to this event
493 *
494 * @see org.eclipse.linuxtools.lttng.event.LttngLocation
495 * @see org.eclipse.linuxtools.tmf.trace.TmfContext
496 */
497 @Override
498 public synchronized TmfContext seekEvent(TmfTimestamp timestamp) {
499
500 // // [lmcfrch]
501 // lastTime = 0;
502
503 if (PrintDebug) {
504 System.out
505 .println("seekEvent(timestamp) timestamp -> " + timestamp); //$NON-NLS-1$
506 }
507
508 // Call JNI to seek
509 currentJniTrace.seekToTime(new JniTime(timestamp.getValue()));
510
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"
514 // this event
515 previousLocation.setLastOperationSeek();
516
517 // *** VERIFY ***
518 // Is that too paranoid?
519 //
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);
523
524 return new TmfContext(curLocation);
525 }
526
527 /**
528 * Position the trace to the event at the given position (rank).
529 * <p>
530 * NOTE : Seeking by position is very slow in LTTng, consider seeking by
531 * timestamp.
532 *
533 * @param position
534 * Position (or rank) of the event in the trace, starting at 0.
535 *
536 * @return The TmfContext that point to this event
537 *
538 * @see org.eclipse.linuxtools.lttng.event.LttngLocation
539 * @see org.eclipse.linuxtools.tmf.trace.TmfContext
540 */
541 @Override
542 public synchronized TmfContext seekEvent(long position) {
543
544 if (PrintDebug) {
545 System.out.println("seekEvent(position) position -> " + position); //$NON-NLS-1$
546 }
547
548 TmfTimestamp timestamp = null;
549 long index = position / getCacheSize();
550
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;
555 }
556 timestamp = fCheckpoints.elementAt((int) index)
557 .getTimestamp();
558 }
559 // If none, take the start time of the trace
560 else {
561 timestamp = getStartTime();
562 }
563
564 // Seek to the found time
565 TmfContext tmpContext = seekEvent(timestamp);
566 tmpContext.setRank((index + 1) * fIndexPageSize);
567 previousLocation = (LttngLocation) tmpContext.getLocation();
568
569 // Ajust the index of the event we found at this check point position
570 Long currentPosition = index * getCacheSize();
571
572 Long lastTimeValueRead = 0L;
573
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
578 // trace "run out"
579 while ((tmpJniEvent != null) && (currentPosition < position)) {
580 tmpJniEvent = currentJniTrace.readNextEvent();
581 currentPosition++;
582 }
583
584 // If we found our event, save its timestamp
585 if (tmpJniEvent != null) {
586 lastTimeValueRead = tmpJniEvent.getEventTime().getTime();
587 }
588
589 // Set the operation marker as seek, to be able to detect we did "seek"
590 // this event
591 previousLocation.setLastOperationSeek();
592 // Save read event time
593 previousLocation.setOperationTime(lastTimeValueRead);
594
595 // *** VERIFY ***
596 // Is that too paranoid?
597 //
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);
601
602 return new TmfContext(curLocation);
603 }
604
605 /**
606 * Return the event in the trace according to the given context. Read it if
607 * necessary.
608 * <p>
609 * Similar (same?) as ParseEvent except that calling GetNext twice read the
610 * next one the second time.
611 *
612 * @param context
613 * Current TmfContext where to get the event
614 *
615 * @return The LttngEvent we read of null if no event are available
616 *
617 * @see org.eclipse.linuxtools.lttng.event.LttngLocation
618 * @see org.eclipse.linuxtools.tmf.trace.TmfContext
619 */
620
621 public int nbEventsRead = 0;
622
623 @Override
624 public synchronized LttngEvent getNextEvent(TmfContext context) {
625
626 if (PrintDebug) {
627 System.out
628 .println("getNextEvent(context) context.getLocation() -> " //$NON-NLS-1$
629 + context.getLocation());
630 }
631
632 LttngEvent returnedEvent = null;
633 LttngLocation curLocation = null;
634
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);
639 }
640
641 // // [lmcfrch]
642 // TmfContext savedContext = context.clone();
643 // // [/lmcfrch]
644
645 // *** HACK ***
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
649 // event.
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.
657
658 // *** Positioning trick :
659 // GetNextEvent only read the trace if :
660 // 1- The last operation was NOT a ParseEvent --> A read is required
661 // OR
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()) {
669 if (PrintDebug) {
670 System.out
671 .println("\t\tSeeking in getNextEvent. [ LastTime : " //$NON-NLS-1$
672 + previousLocation.getOperationTimeValue()
673 + " CurrentTime" //$NON-NLS-1$
674 + curLocation.getOperationTimeValue()
675 + " ]"); //$NON-NLS-1$
676 }
677 seekEvent(curLocation.getOperationTime());
678 }
679 // Read the next event from the trace. The last one will NO LONGER
680 // BE VALID.
681 returnedEvent = readNextEvent(curLocation);
682
683 } else {
684 // No event was read, just return the one currently loaded (the last
685 // one we read)
686 returnedEvent = currentLttngEvent;
687
688 // *** IMPORTANT!
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();
693 }
694
695 // If we read an event, set it's time to the locations (both previous
696 // and current)
697 if (returnedEvent != null) {
698 setPreviousAndCurrentTimes(context, returnedEvent, curLocation);
699
700 // // [lmcfrch]
701 // LttngLocation prevLocation = (LttngLocation)
702 // savedContext.getLocation();
703 // LttngLocation currLocation = (LttngLocation)
704 // context.getLocation();
705 // if (prevLocation.equals(currLocation)) {
706 // System.out.println("Aie");
707 // }
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") + ")"
716 // );
717 // // [/lmcfrch]
718
719
720 }
721
722 return returnedEvent;
723 }
724
725 // this method was extracted for profiling purposes
726 private void setPreviousAndCurrentTimes(TmfContext context, LttngEvent returnedEvent,
727 LttngLocation curLocation) {
728
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);
735 }
736
737 protected void updateIndex(TmfContext context, long rank, TmfTimestamp timestamp) {
738
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);
751 }
752 }
753 }
754 }
755
756 private void addCheckPoint(TmfContext context, TmfTimestamp timestamp) {
757 ITmfLocation<?> location = context.getLocation().clone();
758 fCheckpoints.add(new TmfCheckpoint(timestamp.clone(), location));
759 }
760
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);
766 nbEventsRead++;
767
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;
772 }
773
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);
779 return curLocation;
780 }
781 /**
782 * Return the event in the trace according to the given context. Read it if
783 * necessary.
784 * <p>
785 * Similar (same?) as GetNextEvent except that calling ParseEvent twice will
786 * return the same event
787 *
788 * @param context
789 * Current TmfContext where to get the event
790 *
791 * @return The LttngEvent we read of null if no event are available
792 *
793 * @see org.eclipse.linuxtools.lttng.event.LttngLocation
794 * @see org.eclipse.linuxtools.tmf.trace.TmfContext
795 */
796 @Override
797 public synchronized LttngEvent parseEvent(TmfContext context) {
798
799 if (PrintDebug) {
800 System.out.println("parseEvent(context) context.getLocation() -> " //$NON-NLS-1$
801 + context.getLocation());
802 }
803
804 LttngEvent returnedEvent = null;
805 LttngLocation curLocation = null;
806
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);
811 }
812 // Otherwise, we use the one in context; it should be a valid
813 // LttngLocation
814 else {
815 curLocation = (LttngLocation) context.getLocation();
816 }
817
818 // *** HACK ***
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
822 // event.
823 // So, before "Parsing" an event, we have to make sure we didn't "Read"
824 // it alreafy.
825 // Also, "Reading" invalidate the previous Event in LTTNG and seek back
826 // is very costly,
827 // so calling twice "Parse" will return the same event, giving a way to
828 // get the "Currently loaded" event
829
830 // *** Positionning trick :
831 // ParseEvent only read the trace if :
832 // 1- The last operation was NOT a ParseEvent or a GetNextEvent --> A
833 // read is required
834 // OR
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
842 // current time
843 if (previousLocation.getOperationTimeValue() != curLocation
844 .getOperationTimeValue()) {
845 if (PrintDebug) {
846 System.out
847 .println("\t\tSeeking in getNextEvent. [ LastTime : " //$NON-NLS-1$
848 + previousLocation.getOperationTimeValue()
849 + " CurrentTime" //$NON-NLS-1$
850 + curLocation.getOperationTimeValue()
851 + " ]"); //$NON-NLS-1$
852 }
853 seekEvent(curLocation.getOperationTime());
854 }
855
856 // Read the next event from the trace. The last one will NO LONGER
857 // BE VALID.
858 returnedEvent = readEvent(curLocation);
859 } else {
860 // No event was read, just return the one currently loaded (the last
861 // one we read)
862 returnedEvent = currentLttngEvent;
863 }
864
865 // If we read an event, set it's time to the locations (both previous
866 // and current)
867 if (returnedEvent != null) {
868 previousLocation.setOperationTime((LttngTimestamp) returnedEvent
869 .getTimestamp());
870 curLocation.setOperationTime((LttngTimestamp) returnedEvent
871 .getTimestamp());
872 }
873
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();
878
879 return returnedEvent;
880 }
881
882 /*
883 * Read the next event from the JNI and convert it as Lttng Event<p>
884 *
885 * @param location Current LttngLocation that to be updated with the event
886 * timestamp
887 *
888 * @return The LttngEvent we read of null if no event are available
889 *
890 * @see org.eclipse.linuxtools.lttng.event.LttngLocation
891 *
892 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniTrace
893 */
894 private synchronized LttngEvent readEvent(LttngLocation location) {
895 LttngEvent returnedEvent = null;
896 JniEvent tmpEvent = null;
897
898 // Read the next event from JNI. THIS WILL INVALIDATE THE CURRENT LTTNG
899 // EVENT.
900 tmpEvent = currentJniTrace.readNextEvent();
901
902 if (tmpEvent != null) {
903 // *** NOTE
904 // Convert will update the currentLttngEvent
905 returnedEvent = convertJniEventToTmf(tmpEvent);
906
907 location.setOperationTime((LttngTimestamp) returnedEvent
908 .getTimestamp());
909 }
910 // *** NOTE
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
914 // seek and read
915 else {
916 location.setOperationTime(getEndTime().getValue() + 1);
917 }
918
919 return returnedEvent;
920 }
921
922 /**
923 * Method to convert a JniEvent into a LttngEvent.
924 * <p>
925 *
926 * Note : This method will call LttngEvent convertEventJniToTmf(JniEvent,
927 * boolean) with a default value for isParsingNeeded
928 *
929 * @param newEvent
930 * The JniEvent to convert into LttngEvent
931 *
932 * @return The converted LttngEvent
933 *
934 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniEvent
935 * @see org.eclipse.linuxtools.lttng.event.LttngEvent
936 */
937 public synchronized LttngEvent convertJniEventToTmf(JniEvent newEvent) {
938 currentLttngEvent = convertJniEventToTmf(newEvent,
939 IS_PARSING_NEEDED_DEFAULT);
940
941 return currentLttngEvent;
942 }
943
944 /**
945 * Method to convert a JniEvent into a LttngEvent
946 *
947 * @param jniEvent
948 * The JniEvent to convert into LttngEvent
949 * @param isParsingNeeded
950 * A boolean value telling if the event should be parsed or not.
951 *
952 * @return The converted LttngEvent
953 *
954 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniEvent
955 * @see org.eclipse.linuxtools.lttng.event.LttngEvent
956 */
957 public synchronized LttngEvent convertJniEventToTmf(JniEvent jniEvent,
958 boolean isParsingNeeded) {
959
960 if (UniqueEvent) {
961
962 // ***
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.
966 // *** HACK ***
967 // To save time here, we only set value instead of allocating new
968 // object
969 // This give an HUGE performance improvement
970 // all allocation done in the LttngTrace constructor
971 // ***
972 eventTimestamp.setValue(jniEvent.getEventTime().getTime());
973 eventSource.setSourceId(jniEvent.requestEventSource());
974
975 eventType = traceTypes.get(EventTypeKey.getEventTypeHash(jniEvent));
976
977 eventReference.setValue(jniEvent.getParentTracefile()
978 .getTracefilePath());
979 eventReference.setTracepath(this.getName());
980
981 eventContent.emptyContent();
982
983 currentLttngEvent.setType(eventType);
984 // Save the jni reference
985 currentLttngEvent.updateJniEventReference(jniEvent);
986
987 // Parse now if was asked
988 // Warning : THIS IS SLOW
989 if (isParsingNeeded) {
990 eventContent.getFields();
991 }
992
993 return currentLttngEvent;
994 } else {
995 return convertJniEventToTmfMultipleEventEvilFix(jniEvent,
996 isParsingNeeded);
997 }
998
999 }
1000
1001 /**
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();
1005 *
1006 * @param jniEvent
1007 * The current JNI Event
1008 * @return Current Lttng Event fully parsed
1009 */
1010 private synchronized LttngEvent convertJniEventToTmfMultipleEventEvilFix(
1011 JniEvent jniEvent, boolean isParsingNeeded) {
1012 // *** HACK ***
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);
1025
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);
1030
1031 // Parse the event if it was needed
1032 // *** WARNING ***
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();
1037 }
1038
1039 return currentLttngEvent;
1040 }
1041
1042 /**
1043 * Reference to the current LttngTrace we are reading from.
1044 * <p>
1045 *
1046 * Note : This bypass the framework and should not be use, except for
1047 * testing!
1048 *
1049 * @return Reference to the current LttngTrace
1050 *
1051 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniTrace
1052 */
1053 public JniTrace getCurrentJniTrace() {
1054 return currentJniTrace;
1055 }
1056
1057 /**
1058 * Return a reference to the current LttngEvent we have in memory.
1059 *
1060 * @return The current (last read) LttngEvent
1061 *
1062 * @see org.eclipse.linuxtools.lttng.event.LttngEvent
1063 */
1064 public synchronized LttngEvent getCurrentEvent() {
1065 return currentLttngEvent;
1066 }
1067
1068 /**
1069 * Get the major version number for the current trace
1070 *
1071 * @return Version major or -1 if unknown
1072 *
1073 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniTrace
1074 *
1075 */
1076 public short getVersionMajor() {
1077 if (currentJniTrace != null) {
1078 return currentJniTrace.getLttMajorVersion();
1079 } else {
1080 return -1;
1081 }
1082 }
1083
1084 /**
1085 * Get the minor version number for the current trace
1086 *
1087 * @return Version minor or -1 if unknown
1088 *
1089 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniTrace
1090 *
1091 */
1092 public short getVersionMinor() {
1093 if (currentJniTrace != null) {
1094 return currentJniTrace.getLttMinorVersion();
1095 } else {
1096 return -1;
1097 }
1098 }
1099
1100 /**
1101 * Get the number of CPU for this trace
1102 *
1103 * @return Number of CPU or -1 if unknown
1104 *
1105 * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniTrace
1106 *
1107 */
1108 public int getCpuNumber() {
1109 if (currentJniTrace != null) {
1110 return currentJniTrace.getCpuNumber();
1111 } else {
1112 return -1;
1113 }
1114 }
1115
1116 /**
1117 * Print the content of the checkpoint vector.
1118 * <p>
1119 *
1120 * This is intended for debug purpose only.
1121 */
1122 public void printCheckpointsVector() {
1123 System.out.println("StartTime : " //$NON-NLS-1$
1124 + getTimeRange().getStartTime().getValue());
1125 System.out.println("EndTime : " //$NON-NLS-1$
1126 + getTimeRange().getEndTime().getValue());
1127
1128 for (int pos = 0; pos < fCheckpoints.size(); pos++) {
1129 System.out.print(pos + ": " + "\t"); //$NON-NLS-1$ //$NON-NLS-2$
1130 System.out.print(fCheckpoints.get(pos).getTimestamp() + "\t"); //$NON-NLS-1$
1131 System.out.println(fCheckpoints.get(pos).getLocation());
1132 }
1133 }
1134
1135 /**
1136 * Return a String identifying this trace.
1137 *
1138 * @return String that identify this trace
1139 */
1140 @Override
1141 @SuppressWarnings("nls")
1142 public String toString() {
1143 String returnedData = "";
1144
1145 returnedData += "Path :" + getPath() + " ";
1146 returnedData += "Trace:" + currentJniTrace + " ";
1147 returnedData += "Event:" + currentLttngEvent;
1148
1149 return returnedData;
1150 }
1151
1152 }
1153
1154 /*
1155 * EventTypeKey inner class
1156 *
1157 * This class is used to make the process of generating the HashMap key more
1158 * transparent and so less error prone to use
1159 */
1160 final class EventTypeKey {
1161 // *** WARNING ***
1162 // These two getEventTypeKey() functions should ALWAYS construct the key the
1163 // same ways!
1164 // Otherwise, every type search will fail!
1165
1166 // added final to encourage inlining.
1167
1168 // generating a hash code by hand to avoid a string creation
1169 final static public int getEventTypeHash( LttngEventType newEventType )
1170 {
1171 return generateHash(newEventType.getTracefileName(), newEventType.getCpuId(), newEventType.getMarkerName() );
1172 }
1173
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();
1178 }
1179
1180 // generating a hash code by hand to avoid a string creation
1181 final static public int getEventTypeHash( JniEvent newEvent )
1182 {
1183 return generateHash( newEvent.getParentTracefile().getTracefileName(), newEvent.getParentTracefile().getCpuNumber(),newEvent.requestEventMarker().getName() );
1184 }
1185
1186
1187 }
This page took 0.061129 seconds and 5 git commands to generate.