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