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