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