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