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