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