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