Commit | Line | Data |
---|---|---|
5d10d135 ASL |
1 | /******************************************************************************* |
2 | * Copyright (c) 2009 Ericsson | |
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 | *******************************************************************************/ | |
12 | ||
13 | package org.eclipse.linuxtools.lttng.trace; | |
14 | ||
28b94d61 FC |
15 | import java.util.HashMap; |
16 | import java.util.Iterator; | |
17 | import java.util.Vector; | |
18 | ||
3fbd810a | 19 | import org.eclipse.linuxtools.lttng.LttngException; |
5d10d135 ASL |
20 | import org.eclipse.linuxtools.lttng.event.LttngEvent; |
21 | import org.eclipse.linuxtools.lttng.event.LttngEventContent; | |
22 | import org.eclipse.linuxtools.lttng.event.LttngEventReference; | |
28b94d61 | 23 | import org.eclipse.linuxtools.lttng.event.LttngEventSource; |
5d10d135 | 24 | import org.eclipse.linuxtools.lttng.event.LttngEventType; |
9f584e4c | 25 | import org.eclipse.linuxtools.lttng.event.LttngLocation; |
5d10d135 ASL |
26 | import org.eclipse.linuxtools.lttng.event.LttngTimestamp; |
27 | import org.eclipse.linuxtools.lttng.jni.JniEvent; | |
28b94d61 | 28 | import org.eclipse.linuxtools.lttng.jni.JniMarker; |
5d10d135 | 29 | import org.eclipse.linuxtools.lttng.jni.JniTrace; |
28b94d61 | 30 | import org.eclipse.linuxtools.lttng.jni.JniTracefile; |
004f471b WB |
31 | import org.eclipse.linuxtools.lttng.jni.common.JniTime; |
32 | import org.eclipse.linuxtools.lttng.jni.factory.JniTraceFactory; | |
5d10d135 ASL |
33 | import org.eclipse.linuxtools.tmf.event.TmfTimeRange; |
34 | import org.eclipse.linuxtools.tmf.event.TmfTimestamp; | |
9f584e4c | 35 | import org.eclipse.linuxtools.tmf.trace.ITmfLocation; |
a55a769e | 36 | import org.eclipse.linuxtools.tmf.trace.TmfCheckpoint; |
9f584e4c | 37 | import org.eclipse.linuxtools.tmf.trace.TmfContext; |
5d10d135 | 38 | import org.eclipse.linuxtools.tmf.trace.TmfTrace; |
5d10d135 | 39 | |
3fbd810a FC |
40 | |
41 | class LTTngTraceException extends LttngException { | |
42 | static final long serialVersionUID = -1636648737081868146L; | |
43 | ||
44 | public LTTngTraceException(String errMsg) { | |
45 | super(errMsg); | |
46 | } | |
47 | } | |
48 | ||
5d10d135 | 49 | /** |
07d9e2ee FC |
50 | * <b><u>LTTngTrace</u></b><p> |
51 | * | |
5d10d135 ASL |
52 | * LTTng trace implementation. It accesses the C trace handling library |
53 | * (seeking, reading and parsing) through the JNI component. | |
54 | */ | |
e31e01e8 | 55 | public class LTTngTrace extends TmfTrace<LttngEvent> { |
a55a769e | 56 | |
7f2f49e3 | 57 | public static boolean printDebug = false; |
fafd6325 | 58 | public static boolean uniqueEvent = false; |
a55a769e | 59 | |
fafd6325 | 60 | private final static boolean SHOW_LTT_DEBUG_DEFAULT = false; |
28b94d61 | 61 | private final static boolean IS_PARSING_NEEDED_DEFAULT = false; |
a55a769e | 62 | private final static int CHECKPOINT_PAGE_SIZE = 1000; |
5d10d135 ASL |
63 | |
64 | // Reference to our JNI trace | |
65 | private JniTrace currentJniTrace = null; | |
66 | ||
fafd6325 WB |
67 | // *** |
68 | // UNHACKED : We can no longer do that because TCF need to maintain several events at once. | |
69 | // This is very slow to do so in LTTng, this has to be temporary. | |
70 | // *** HACK *** | |
71 | // To save time, we will declare all component of the LttngEvent during the construction of the trace | |
72 | // Then, while reading the trace, we will just SET the values instead of declaring new object | |
73 | // *** | |
28b94d61 FC |
74 | LttngTimestamp eventTimestamp = null; |
75 | LttngEventSource eventSource = null; | |
28b94d61 FC |
76 | LttngEventContent eventContent = null; |
77 | LttngEventReference eventReference = null; | |
fafd6325 WB |
78 | |
79 | ||
28b94d61 FC |
80 | // The actual event |
81 | LttngEvent currentLttngEvent = null; | |
82 | ||
a55a769e | 83 | // The current location |
7f2f49e3 | 84 | LttngLocation previousLocation = null; |
a55a769e | 85 | |
fafd6325 | 86 | LttngEventType eventType = null; |
28b94d61 FC |
87 | // Hashmap of the possible types of events (Tracefile/CPU/Marker in the JNI) |
88 | HashMap<String, LttngEventType> traceTypes = null; | |
89 | // This vector will be used to quickly find a marker name from a position | |
90 | Vector<String> traceTypeNames = null; | |
91 | ||
5d10d135 | 92 | /** |
07d9e2ee | 93 | * Default Constructor.<p> |
5d10d135 | 94 | * |
07d9e2ee FC |
95 | * @param path Path to a <b>directory</b> that contain an LTTng trace. |
96 | * | |
97 | * @exception Exception (most likely LTTngTraceException or FileNotFoundException) | |
5d10d135 ASL |
98 | */ |
99 | public LTTngTrace(String path) throws Exception { | |
07d9e2ee FC |
100 | // Call with "wait for completion" true and "skip indexing" false |
101 | this(path, true, false); | |
5d10d135 ASL |
102 | } |
103 | ||
104 | /** | |
07d9e2ee FC |
105 | * Constructor, with control over the indexing. |
106 | * <p> | |
107 | * @param path Path to a <b>directory</b> that contain an LTTng trace. | |
108 | * @param waitForCompletion Should we wait for indexign to complete before moving on. | |
109 | * | |
110 | * @exception Exception (most likely LTTngTraceException or FileNotFoundException) | |
07d9e2ee FC |
111 | */ |
112 | public LTTngTrace(String path, boolean waitForCompletion) throws Exception { | |
28b94d61 | 113 | // Call with "skip indexing" false |
07d9e2ee FC |
114 | this(path, waitForCompletion, false); |
115 | } | |
116 | ||
117 | /** | |
118 | * Default constructor, with control over the indexing and possibility to bypass indexation | |
5d10d135 ASL |
119 | * <p> |
120 | * @param path Path to a <b>directory</b> that contain an LTTng trace. | |
121 | * @param waitForCompletion Should we wait for indexign to complete before moving on. | |
07d9e2ee | 122 | * @param bypassIndexing Should we bypass indexing completly? This is should only be useful for unit testing. |
5d10d135 | 123 | * |
07d9e2ee | 124 | * @exception Exception (most likely LTTngTraceException or FileNotFoundException) |
5d10d135 ASL |
125 | * |
126 | */ | |
07d9e2ee | 127 | public LTTngTrace(String path, boolean waitForCompletion, boolean bypassIndexing) throws Exception { |
ce785d7d | 128 | super(path, LttngEvent.class, path, CHECKPOINT_PAGE_SIZE); |
5d10d135 | 129 | try { |
004f471b | 130 | currentJniTrace = JniTraceFactory.getJniTrace(path, SHOW_LTT_DEBUG_DEFAULT); |
5d10d135 | 131 | } |
3fbd810a FC |
132 | catch (Exception e) { |
133 | throw new LTTngTraceException(e.getMessage()); | |
88144d4a | 134 | } |
28b94d61 | 135 | |
28b94d61 FC |
136 | // Export all the event types from the JNI side |
137 | traceTypes = new HashMap<String, LttngEventType>(); | |
138 | traceTypeNames = new Vector<String>(); | |
139 | initialiseEventTypes(currentJniTrace); | |
140 | ||
141 | // *** VERIFY *** | |
142 | // Verify that all those "default constructor" are safe to use | |
143 | eventTimestamp = new LttngTimestamp(); | |
144 | eventSource = new LttngEventSource(); | |
145 | eventType = new LttngEventType(); | |
146 | eventContent = new LttngEventContent(currentLttngEvent); | |
147 | eventReference = new LttngEventReference(this.getName()); | |
148 | ||
149 | // Create the skeleton event | |
b7f0ec69 | 150 | currentLttngEvent = new LttngEvent(this, eventTimestamp, eventSource, eventType, eventContent, eventReference, null); |
28b94d61 | 151 | |
a55a769e | 152 | // Create a new current location |
7f2f49e3 | 153 | previousLocation = new LttngLocation(); |
a55a769e WB |
154 | |
155 | ||
28b94d61 FC |
156 | // Set the currentEvent to the eventContent |
157 | eventContent.setEvent(currentLttngEvent); | |
158 | ||
07d9e2ee FC |
159 | // Bypass indexing if asked |
160 | if ( bypassIndexing == false ) { | |
e31e01e8 | 161 | indexTrace(true); |
07d9e2ee | 162 | } |
a55a769e WB |
163 | else { |
164 | // Even if we don't have any index, set ONE checkpoint | |
165 | fCheckpoints.add(new TmfCheckpoint(new LttngTimestamp(0L) , new LttngLocation() ) ); | |
166 | ||
167 | // Set the start time of the trace | |
168 | setTimeRange( new TmfTimeRange( new LttngTimestamp(currentJniTrace.getStartTime().getTime()), | |
169 | new LttngTimestamp(currentJniTrace.getEndTime().getTime()) | |
170 | ) ); | |
171 | } | |
5d10d135 ASL |
172 | } |
173 | ||
3fbd810a FC |
174 | /* |
175 | * Copy constructor is forbidden for LttngEvenmStream | |
5d10d135 ASL |
176 | * |
177 | */ | |
369aca6e WB |
178 | public LTTngTrace(LTTngTrace oldTrace) throws Exception { |
179 | this(oldTrace.getPath(), false, true); | |
180 | ||
181 | // *** VERIFY *** | |
182 | // Is this safe? | |
183 | this.fCheckpoints = oldTrace.fCheckpoints; | |
184 | ||
185 | /* | |
186 | // This would only work if the index is already done | |
187 | this.fCheckpoints = new Vector<TmfCheckpoint>( oldTrace.fCheckpoints.size() ); | |
188 | for (int x = 0; x<oldTrace.fCheckpoints.size(); x++){ | |
189 | TmfCheckpoint tmpCheckPoint = oldTrace.fCheckpoints.get(x); | |
190 | this.fCheckpoints.add( new TmfCheckpoint(tmpCheckPoint.getTimestamp(), tmpCheckPoint.getLocation()) ); | |
191 | } | |
192 | */ | |
193 | ||
194 | // Set the start time of the trace | |
195 | setTimeRange( new TmfTimeRange( new LttngTimestamp(oldTrace.getStartTime()), | |
196 | new LttngTimestamp(oldTrace.getEndTime())) | |
197 | ); | |
198 | } | |
199 | ||
200 | public LTTngTrace createTraceCopy() { | |
201 | LTTngTrace returnedTrace = null; | |
202 | ||
203 | try { | |
204 | returnedTrace = new LTTngTrace(this); | |
205 | } | |
206 | catch (Exception e) { | |
207 | System.out.println("ERROR : Could not create LTTngTrace copy (createTraceCopy).\nError is : " + e.getStackTrace()); | |
208 | } | |
209 | ||
210 | return returnedTrace; | |
9aae0442 ASL |
211 | } |
212 | ||
28b94d61 FC |
213 | /* |
214 | * Fill out the HashMap with "Type" (Tracefile/Marker) | |
215 | * | |
216 | * This should be called at construction once the trace is open | |
217 | */ | |
218 | private void initialiseEventTypes(JniTrace trace) { | |
219 | // Work variables | |
220 | LttngEventType tmpType = null; | |
221 | String[] markerFieldsLabels = null; | |
222 | ||
223 | String newTracefileKey = null; | |
224 | Integer newMarkerKey = null; | |
225 | ||
226 | JniTracefile newTracefile = null; | |
227 | JniMarker newMarker = null; | |
228 | ||
229 | // First, obtain an iterator on TRACEFILES of owned by the TRACE | |
230 | Iterator<String> tracefileItr = trace.getTracefilesMap().keySet().iterator(); | |
231 | while ( tracefileItr.hasNext() ) { | |
232 | newTracefileKey = tracefileItr.next(); | |
233 | newTracefile = trace.getTracefilesMap().get(newTracefileKey); | |
234 | ||
235 | // From the TRACEFILE read, obtain its MARKER | |
236 | Iterator<Integer> markerItr = newTracefile.getTracefileMarkersMap().keySet().iterator(); | |
237 | while ( markerItr.hasNext() ) { | |
238 | newMarkerKey = markerItr.next(); | |
239 | newMarker = newTracefile.getTracefileMarkersMap().get(newMarkerKey); | |
240 | ||
241 | // From the MARKER we can obtain the MARKERFIELDS keys (i.e. labels) | |
242 | markerFieldsLabels = newMarker.getMarkerFieldsHashMap().keySet().toArray( new String[newMarker.getMarkerFieldsHashMap().size()] ); | |
243 | tmpType = new LttngEventType(newTracefile.getTracefileName(), newTracefile.getCpuNumber(), newMarker.getName(), markerFieldsLabels ); | |
244 | ||
245 | // Add the type to the map/vector | |
246 | addEventTypeToMap(tmpType); | |
247 | } | |
248 | } | |
249 | } | |
250 | ||
251 | /* | |
252 | * Add a new type to the HashMap | |
253 | * | |
254 | * As the hashmap use a key format that is a bit dangerous to use, we should always add using this function. | |
255 | */ | |
256 | private void addEventTypeToMap(LttngEventType newEventType) { | |
257 | String newTypeKey = EventTypeKey.getEventTypeKey(newEventType); | |
258 | ||
259 | this.traceTypes.put(newTypeKey, newEventType); | |
260 | this.traceTypeNames.add(newTypeKey); | |
261 | } | |
262 | ||
7f2f49e3 WB |
263 | /** |
264 | * Index the current trace. | |
265 | * | |
266 | * @param useless This boolean is only to comply to the interface and will be ignored. | |
267 | */ | |
268 | @Override | |
269 | public synchronized void indexTrace(boolean useless) { | |
270 | ||
271 | long nbEvents=0L; | |
272 | ||
273 | // Start time need to be null to detect none have been set | |
274 | // LastTime need to exist so we can ajust it as we go | |
275 | LttngTimestamp startTime = null; | |
276 | LttngTimestamp lastTime = new LttngTimestamp(); | |
277 | ||
278 | // Position the trace at the beginning | |
279 | TmfContext context = seekEvent( new LttngTimestamp(0L) ); | |
280 | ||
281 | // Read the first event and extract the location | |
282 | LttngEvent tmpEvent = (LttngEvent)getNextEvent(context); | |
283 | ||
284 | // If we read the first event, define the start time. | |
285 | if ( tmpEvent != null ) { | |
286 | startTime = new LttngTimestamp( tmpEvent.getTimestamp() ); | |
287 | lastTime.setValue(tmpEvent.getTimestamp().getValue()); | |
288 | } | |
289 | ||
290 | // Now, we read each event until we hit the end of the trace | |
291 | // We will create a new checkpoint every "getCacheSize()" event | |
292 | while ( tmpEvent != null) { | |
293 | // Update the last time each time we read a new event | |
294 | lastTime.setValue(tmpEvent.getTimestamp().getValue()); | |
295 | ||
296 | // Save a check point if needed | |
297 | if ((nbEvents++ % getCacheSize()) == 0) { | |
298 | // *** IMPORTANT | |
299 | // We need to NEW each stuff we put in checkpoint | |
300 | // Otherwise everything will be the same! | |
301 | LttngTimestamp tmpTimestamp = new LttngTimestamp( (LttngTimestamp)tmpEvent.getTimestamp() ); | |
302 | LttngLocation newLocation = new LttngLocation( (LttngTimestamp)tmpEvent.getTimestamp() ); | |
303 | ||
304 | fCheckpoints.add(new TmfCheckpoint(tmpTimestamp, newLocation ) ); | |
305 | } | |
306 | // Read the next event | |
307 | tmpEvent = (LttngEvent)getNextEvent(context); | |
308 | } | |
309 | ||
310 | // If we have a start time, we should have an end time as well | |
311 | // Issue the new range | |
312 | if (startTime != null) { | |
313 | setTimeRange( new TmfTimeRange(startTime, lastTime) ); | |
314 | notifyListeners(getTimeRange() ); | |
315 | } | |
316 | ||
317 | // Ajust the total number of event in the trace | |
318 | fNbEvents = nbEvents; | |
319 | //printCheckpointsVector(); | |
320 | //printDebug = true; | |
321 | } | |
322 | ||
323 | /** | |
324 | * Return the latest saved location. | |
325 | * Note : Modifying the returned location may result in buggy positionning! | |
326 | * | |
327 | * @return The LttngLocation as it was after the last operation. | |
328 | * | |
329 | * @see org.eclipse.linuxtools.lttng.event.LttngLocation | |
330 | */ | |
331 | @Override | |
332 | public ITmfLocation<?> getCurrentLocation() { | |
333 | return previousLocation; | |
334 | } | |
335 | ||
336 | /** | |
337 | * Position the trace to the event at the given location.<p> | |
338 | * NOTE : Seeking by location is very fast compare to seeking by position | |
339 | * but is still slower than "ReadNext", avoid using it for small interval. | |
340 | * | |
341 | * @param location Location of the event in the trace. | |
342 | * If no event available at this exact location, we will position ourself to the next one. | |
343 | * | |
344 | * @return The TmfContext that point to this event | |
345 | * | |
346 | * @see org.eclipse.linuxtools.lttng.event.LttngLocation | |
347 | * @see org.eclipse.linuxtools.tmf.trace.TmfContext | |
348 | */ | |
fc6ccf6f FC |
349 | @Override |
350 | public synchronized TmfContext seekLocation(ITmfLocation<?> location) { | |
7f2f49e3 WB |
351 | |
352 | if ( printDebug == true ) { | |
353 | System.out.println("seekLocation(location) location -> " + location); | |
354 | } | |
355 | ||
356 | // If the location in context is null, create a new one | |
357 | LttngLocation curLocation = null; | |
358 | if ( location == null ) { | |
359 | curLocation = new LttngLocation(); | |
360 | } | |
361 | else { | |
362 | curLocation = (LttngLocation)location; | |
363 | } | |
364 | ||
365 | // *** NOTE : | |
366 | // Update to location should (and will) be done in SeekEvent. | |
367 | ||
368 | // The only seek valid in LTTng is with the time, we call seekEvent(timestamp) | |
369 | return seekEvent( curLocation.getOperationTime() ); | |
370 | } | |
371 | ||
372 | /** | |
373 | * Position the trace to the event at the given time.<p> | |
374 | * NOTE : Seeking by time is very fast compare to seeking by position | |
375 | * but is still slower than "ReadNext", avoid using it for small interval. | |
376 | * | |
377 | * @param timestamp Time of the event in the trace. | |
378 | * If no event available at this exact time, we will position ourself to the next one. | |
379 | * | |
380 | * @return The TmfContext that point to this event | |
381 | * | |
382 | * @see org.eclipse.linuxtools.lttng.event.LttngLocation | |
383 | * @see org.eclipse.linuxtools.tmf.trace.TmfContext | |
384 | */ | |
385 | @Override | |
386 | public synchronized TmfContext seekEvent(TmfTimestamp timestamp) { | |
387 | ||
388 | if ( printDebug == true ) { | |
389 | System.out.println("seekEvent(timestamp) timestamp -> " + timestamp); | |
390 | } | |
391 | ||
392 | // Call JNI to seek | |
393 | currentJniTrace.seekToTime(new JniTime(timestamp.getValue())); | |
394 | ||
395 | // Save the time at which we seeked | |
396 | previousLocation.setOperationTime(timestamp.getValue()); | |
397 | // Set the operation marker as seek, to be able to detect we did "seek" this event | |
398 | previousLocation.setLastOperationSeek(); | |
399 | ||
400 | // *** VERIFY *** | |
401 | // Is that too paranoid? | |
402 | // | |
403 | // We don't trust what upper level could do with our internal location | |
404 | // so we create a new one to return instead | |
405 | LttngLocation curLocation = new LttngLocation(previousLocation); | |
406 | ||
407 | return new TmfContext( curLocation ); | |
408 | } | |
409 | ||
410 | /** | |
411 | * Position the trace to the event at the given position (rank).<p> | |
412 | * NOTE : Seeking by position is very slow in LTTng, consider seeking by timestamp. | |
413 | * | |
414 | * @param position Position (or rank) of the event in the trace, starting at 0. | |
415 | * | |
416 | * @return The TmfContext that point to this event | |
417 | * | |
418 | * @see org.eclipse.linuxtools.lttng.event.LttngLocation | |
419 | * @see org.eclipse.linuxtools.tmf.trace.TmfContext | |
420 | */ | |
421 | @Override | |
422 | public synchronized TmfContext seekEvent(long position) { | |
423 | ||
424 | if ( printDebug == true ) { | |
425 | System.out.println("seekEvent(position) position -> " + position); | |
426 | } | |
427 | ||
428 | TmfTimestamp timestamp = null; | |
429 | long index = position / getCacheSize(); | |
430 | ||
431 | // Get the timestamp of the closest check point to the given position | |
432 | if (fCheckpoints.size() > 0) { | |
433 | if (index >= fCheckpoints.size()) { | |
434 | index = fCheckpoints.size() - 1; | |
435 | } | |
436 | timestamp = (TmfTimestamp)fCheckpoints.elementAt((int)index).getTimestamp(); | |
437 | } | |
438 | // If none, take the start time of the trace | |
439 | else { | |
440 | timestamp = getStartTime(); | |
441 | } | |
442 | ||
443 | // Seek to the found time | |
444 | TmfContext tmpContext = seekEvent(timestamp); | |
445 | previousLocation = (LttngLocation)tmpContext.getLocation(); | |
446 | ||
447 | // Ajust the index of the event we found at this check point position | |
448 | Long currentPosition = index * getCacheSize(); | |
449 | ||
450 | Long lastTimeValueRead = 0L; | |
451 | ||
452 | // Get the event at current position. This won't move to the next one | |
453 | JniEvent tmpJniEvent = currentJniTrace.findNextEvent(); | |
454 | // Now that we are positionned at the checkpoint, | |
455 | // we need to "readNext" (Position - CheckpointPosition) times or until trace "run out" | |
456 | while ( (tmpJniEvent != null) && ( currentPosition < position ) ) { | |
457 | tmpJniEvent = currentJniTrace.readNextEvent(); | |
458 | currentPosition++; | |
459 | } | |
460 | ||
461 | // If we found our event, save its timestamp | |
462 | if ( tmpJniEvent != null ) { | |
463 | lastTimeValueRead = tmpJniEvent.getEventTime().getTime(); | |
464 | } | |
465 | ||
466 | // Set the operation marker as seek, to be able to detect we did "seek" this event | |
467 | previousLocation.setLastOperationSeek(); | |
468 | // Save read event time | |
469 | previousLocation.setOperationTime(lastTimeValueRead); | |
470 | ||
471 | // *** VERIFY *** | |
472 | // Is that too paranoid? | |
473 | // | |
474 | // We don't trust what upper level could do with our internal location | |
475 | // so we create a new one to return instead | |
476 | LttngLocation curLocation = new LttngLocation(previousLocation); | |
477 | ||
478 | return new TmfContext( curLocation ); | |
479 | } | |
480 | ||
481 | /** | |
482 | * Return the event in the trace according to the given context. Read it if necessary.<p> | |
483 | * Similar (same?) as ParseEvent except that calling GetNext twice read the next one the second time. | |
484 | * | |
485 | * @param context Current TmfContext where to get the event | |
486 | * | |
487 | * @return The LttngEvent we read of null if no event are available | |
488 | * | |
489 | * @see org.eclipse.linuxtools.lttng.event.LttngLocation | |
490 | * @see org.eclipse.linuxtools.tmf.trace.TmfContext | |
491 | */ | |
492 | @Override | |
493 | public synchronized LttngEvent getNextEvent(TmfContext context) { | |
494 | ||
495 | if ( printDebug == true ) { | |
496 | System.out.println("getNextEvent(context) context.getLocation() -> " + context.getLocation()); | |
497 | } | |
498 | ||
499 | LttngEvent returnedEvent = null; | |
500 | LttngLocation curLocation = null; | |
501 | ||
502 | // If the location in context is null, create a new one | |
503 | if ( context.getLocation() == null ) { | |
504 | curLocation = new LttngLocation(); | |
505 | context.setLocation(curLocation); | |
506 | } | |
507 | else { | |
508 | // Otherwise, we use the one in context; it should be a valid LttngLocation | |
509 | curLocation = (LttngLocation)context.getLocation(); | |
510 | } | |
511 | ||
512 | // *** HACK *** | |
513 | // TMF assumes it is possible to read (GetNextEvent) to the next Event once ParseEvent() is called | |
514 | // In LTTNG, there is not difference between "Parsing" and "Reading" an event. | |
515 | // Since parsing/reading invalidate the previous event, | |
4f259636 | 516 | // we need to make sure the sequence ParseEvent() -> GetNextEvent() will not actually move to the next event. |
7f2f49e3 WB |
517 | // To do so, we avoid moving for call to "GetNextEvent()" that follow call to a call to "ParseEvent()". |
518 | // However, calling ParseEvent() -> GetNextEvent() -> GetNextEvent() will only move next by one. | |
519 | ||
520 | // *** Positionning trick : | |
521 | // GetNextEvent only read the trace if : | |
522 | // 1- The last operation was NOT a ParseEvent --> A read is required | |
523 | // OR | |
524 | // 2- The time of the previous location is different from the current one --> A seek + a read is required | |
525 | if ( (curLocation.isLastOperationParse() != true) || | |
526 | (previousLocation.getOperationTimeValue() != curLocation.getOperationTimeValue() ) ) | |
527 | { | |
528 | if ( previousLocation.getOperationTimeValue() != curLocation.getOperationTimeValue() ) { | |
529 | if ( printDebug == true ) { | |
530 | System.out.println("\t\tSeeking in getNextEvent. [ LastTime : " + previousLocation.getOperationTimeValue() + " CurrentTime" + curLocation.getOperationTimeValue() + " ]"); | |
531 | } | |
532 | seekEvent( curLocation.getOperationTime() ); | |
533 | } | |
534 | // Read the next event from the trace. The last one will NO LONGER BE VALID. | |
535 | returnedEvent = readEvent(curLocation); | |
536 | ||
537 | // Set the operation marker as read to both location, to be able to detect we did "read" this event | |
538 | previousLocation.setLastOperationReadNext(); | |
539 | curLocation.setLastOperationReadNext(); | |
540 | } | |
541 | else { | |
542 | // No event was read, just return the one currently loaded (the last one we read) | |
543 | returnedEvent = currentLttngEvent; | |
544 | ||
545 | // *** IMPORTANT! | |
546 | // Reset (erase) the operation marker to both location, to be able to detect we did NOT "read" this event | |
547 | previousLocation.resetLocationState(); | |
548 | curLocation.resetLocationState(); | |
549 | } | |
550 | ||
551 | // If we read an event, set it's time to the locations (both previous and current) | |
552 | if ( returnedEvent != null ) { | |
553 | previousLocation.setOperationTime((LttngTimestamp)returnedEvent.getTimestamp()); | |
554 | curLocation.setOperationTime((LttngTimestamp)returnedEvent.getTimestamp()); | |
555 | } | |
556 | ||
557 | return returnedEvent; | |
558 | } | |
559 | ||
560 | ||
561 | /** | |
562 | * Return the event in the trace according to the given context. Read it if necessary.<p> | |
563 | * Similar (same?) as GetNextEvent except that calling ParseEvent twice will return the same event | |
564 | * | |
565 | * @param context Current TmfContext where to get the event | |
566 | * | |
567 | * @return The LttngEvent we read of null if no event are available | |
568 | * | |
569 | * @see org.eclipse.linuxtools.lttng.event.LttngLocation | |
570 | * @see org.eclipse.linuxtools.tmf.trace.TmfContext | |
571 | */ | |
572 | @Override | |
573 | public synchronized LttngEvent parseEvent(TmfContext context) { | |
574 | ||
575 | if ( printDebug == true ) { | |
576 | System.out.println("parseEvent(context) context.getLocation() -> " + context.getLocation()); | |
577 | } | |
578 | ||
579 | LttngEvent returnedEvent = null; | |
580 | LttngLocation curLocation = null; | |
581 | ||
582 | // If the location in context is null, create a new one | |
583 | if ( context.getLocation() == null ) { | |
584 | curLocation = new LttngLocation(); | |
585 | context.setLocation(curLocation); | |
586 | } | |
587 | // Otherwise, we use the one in context; it should be a valid LttngLocation | |
588 | else { | |
589 | curLocation = (LttngLocation)context.getLocation(); | |
590 | } | |
591 | ||
592 | // *** HACK *** | |
593 | // TMF assumes it is possible to read (GetNextEvent) to the next Event once ParseEvent() is called | |
594 | // In LTTNG, there is not difference between "Parsing" and "Reading" an event. | |
595 | // So, before "Parsing" an event, we have to make sure we didn't "Read" it alreafy. | |
596 | // Also, "Reading" invalidate the previous Event in LTTNG and seek back is very costly, | |
597 | // so calling twice "Parse" will return the same event, giving a way to get the "Currently loaded" event | |
598 | ||
599 | // *** Positionning trick : | |
600 | // ParseEvent only read the trace if : | |
601 | // 1- The last operation was NOT a ParseEvent or a GetNextEvent --> A read is required | |
602 | // OR | |
603 | // 2- The time of the previous location is different from the current one --> A seek + a read is required | |
604 | if ( ( (curLocation.isLastOperationParse() != true) && ((curLocation.isLastOperationReadNext() != true)) ) || | |
605 | (previousLocation.getOperationTimeValue() != curLocation.getOperationTimeValue() ) ) | |
606 | { | |
607 | // Previous time != Current time : We need to reposition to the current time | |
608 | if (previousLocation.getOperationTimeValue() != curLocation.getOperationTimeValue() ) { | |
609 | if ( printDebug == true ) { | |
610 | System.out.println("\t\tSeeking in getNextEvent. [ LastTime : " + previousLocation.getOperationTimeValue() + " CurrentTime" + curLocation.getOperationTimeValue() + " ]"); | |
611 | } | |
612 | seekEvent( curLocation.getOperationTime() ); | |
613 | } | |
614 | ||
615 | // Read the next event from the trace. The last one will NO LONGER BE VALID. | |
616 | returnedEvent = readEvent(curLocation); | |
617 | } | |
618 | else { | |
619 | // No event was read, just return the one currently loaded (the last one we read) | |
620 | returnedEvent = currentLttngEvent; | |
621 | } | |
622 | ||
623 | // If we read an event, set it's time to the locations (both previous and current) | |
624 | if ( returnedEvent != null ) { | |
625 | previousLocation.setOperationTime((LttngTimestamp)returnedEvent.getTimestamp()); | |
626 | curLocation.setOperationTime((LttngTimestamp)returnedEvent.getTimestamp()); | |
627 | } | |
628 | ||
629 | // Set the operation marker as parse to both location, to be able to detect we already "read" this event | |
630 | previousLocation.setLastOperationParse(); | |
631 | curLocation.setLastOperationParse(); | |
632 | ||
633 | return returnedEvent; | |
634 | } | |
635 | ||
636 | /* | |
637 | * Read the next event from the JNI and convert it as Lttng Event<p> | |
638 | * | |
639 | * @param location Current LttngLocation that to be updated with the event timestamp | |
640 | * | |
641 | * @return The LttngEvent we read of null if no event are available | |
642 | * | |
643 | * @see org.eclipse.linuxtools.lttng.event.LttngLocation | |
644 | * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniTrace | |
645 | */ | |
646 | private synchronized LttngEvent readEvent(LttngLocation location) { | |
647 | LttngEvent returnedEvent = null; | |
648 | JniEvent tmpEvent = null; | |
649 | ||
650 | // Read the next event from JNI. THIS WILL INVALIDATE THE CURRENT LTTNG EVENT. | |
651 | tmpEvent = currentJniTrace.readNextEvent(); | |
652 | ||
653 | if ( tmpEvent != null ) { | |
654 | // *** NOTE | |
655 | // Convert will update the currentLttngEvent | |
656 | returnedEvent = convertJniEventToTmf(tmpEvent); | |
657 | ||
658 | location.setOperationTime( (LttngTimestamp)returnedEvent.getTimestamp() ); | |
659 | } | |
660 | // *** NOTE | |
661 | // If the read failed (likely the last event in the trace), set the LastReadTime to the JNI time | |
662 | // That way, even if we try to read again, we will step over the bogus seek and read | |
663 | else { | |
664 | location.setOperationTime( getEndTime().getValue() + 1 ); | |
665 | } | |
666 | ||
667 | return returnedEvent; | |
668 | } | |
669 | ||
07d9e2ee FC |
670 | /** |
671 | * Method to convert a JniEvent into a LttngEvent.<p> | |
672 | * | |
5d10d135 ASL |
673 | * Note : This method will call LttngEvent convertEventJniToTmf(JniEvent, boolean) |
674 | * with a default value for isParsingNeeded | |
675 | * | |
07d9e2ee | 676 | * @param newEvent The JniEvent to convert into LttngEvent |
3fbd810a | 677 | * |
28b94d61 | 678 | * @return The converted LttngEvent |
3fbd810a | 679 | * |
28b94d61 FC |
680 | * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniEvent |
681 | * @see org.eclipse.linuxtools.lttng.event.LttngEvent | |
5d10d135 | 682 | */ |
b20696db | 683 | public synchronized LttngEvent convertJniEventToTmf(JniEvent newEvent) { |
28b94d61 FC |
684 | currentLttngEvent = convertJniEventToTmf(newEvent, IS_PARSING_NEEDED_DEFAULT); |
685 | ||
686 | return currentLttngEvent; | |
5d10d135 ASL |
687 | } |
688 | ||
07d9e2ee | 689 | /** |
28b94d61 | 690 | * Method to convert a JniEvent into a LttngEvent |
5d10d135 | 691 | * |
07d9e2ee | 692 | * @param jniEvent The JniEvent to convert into LttngEvent |
5d10d135 | 693 | * @param isParsingNeeded A boolean value telling if the event should be parsed or not. |
3fbd810a | 694 | * |
28b94d61 | 695 | * @return The converted LttngEvent |
3fbd810a | 696 | * |
28b94d61 FC |
697 | * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniEvent |
698 | * @see org.eclipse.linuxtools.lttng.event.LttngEvent | |
5d10d135 | 699 | */ |
b20696db | 700 | public synchronized LttngEvent convertJniEventToTmf(JniEvent jniEvent, boolean isParsingNeeded) { |
fafd6325 WB |
701 | |
702 | if ( uniqueEvent == true ) { | |
703 | ||
704 | // *** | |
705 | // UNHACKED : We can no longer do that because TCF need to maintain several events at once. | |
706 | // This is very slow to do so in LTTng, this has to be temporary. | |
707 | // *** HACK *** | |
708 | // To save time here, we only set value instead of allocating new object | |
709 | // This give an HUGE performance improvement | |
710 | // all allocation done in the LttngTrace constructor | |
711 | // *** | |
712 | eventTimestamp.setValue(jniEvent.getEventTime().getTime()); | |
713 | eventSource.setSourceId(jniEvent.requestEventSource()); | |
714 | ||
715 | eventType = traceTypes.get( EventTypeKey.getEventTypeKey(jniEvent) ); | |
716 | ||
717 | eventReference.setValue(jniEvent.getParentTracefile().getTracefilePath()); | |
718 | eventReference.setTracepath(this.getName()); | |
719 | ||
720 | eventContent.emptyContent(); | |
721 | ||
722 | currentLttngEvent.setType(eventType); | |
723 | // Save the jni reference | |
724 | currentLttngEvent.updateJniEventReference(jniEvent); | |
725 | ||
726 | // Parse now if was asked | |
727 | // Warning : THIS IS SLOW | |
728 | if (isParsingNeeded == true ) { | |
729 | eventContent.getFields(); | |
730 | } | |
731 | ||
732 | return currentLttngEvent; | |
733 | } | |
734 | else { | |
4f259636 | 735 | return convertJniEventToTmfMultipleEventEvilFix(jniEvent, isParsingNeeded); |
fafd6325 WB |
736 | } |
737 | ||
738 | } | |
739 | ||
740 | /** | |
741 | * This method is a temporary fix to support multiple events at once in TMF | |
742 | * This is expected to be slow and should be fixed in another way. | |
743 | * See comment in convertJniEventToTmf(); | |
744 | * | |
745 | * @param jniEvent The current JNI Event | |
746 | * @return Current Lttng Event fully parsed | |
747 | */ | |
4f259636 | 748 | private synchronized LttngEvent convertJniEventToTmfMultipleEventEvilFix(JniEvent jniEvent, boolean isParsingNeeded) { |
fafd6325 WB |
749 | // *** HACK *** |
750 | // Below : the "fix" with all the new and the full-parse | |
751 | // Allocating new memory is slow. | |
752 | // Parsing every events is very slow. | |
753 | eventTimestamp = new LttngTimestamp(jniEvent.getEventTime().getTime()); | |
754 | eventSource = new LttngEventSource(jniEvent.requestEventSource()); | |
755 | eventReference = new LttngEventReference(jniEvent.getParentTracefile().getTracefilePath(), this.getName()); | |
756 | eventType = new LttngEventType(traceTypes.get( EventTypeKey.getEventTypeKey(jniEvent) )); | |
757 | eventContent = new LttngEventContent(currentLttngEvent); | |
b7f0ec69 | 758 | currentLttngEvent = new LttngEvent(this, eventTimestamp, eventSource, eventType, eventContent, eventReference, null); |
28b94d61 | 759 | |
fafd6325 | 760 | // The jni reference is no longer reliable but we will keep it anyhow |
a3fe52fc | 761 | currentLttngEvent.updateJniEventReference(jniEvent); |
fafd6325 WB |
762 | // Ensure that the content is correctly set |
763 | eventContent.setEvent(currentLttngEvent); | |
4f259636 WB |
764 | |
765 | // Parse the event if it was needed | |
766 | // *** WARNING *** | |
767 | // ONLY for testing, NOT parsing events with non-unique events WILL result in segfault in the JVM | |
768 | if ( isParsingNeeded == true ) { | |
769 | eventContent.getFields(); | |
770 | } | |
fafd6325 | 771 | |
28b94d61 | 772 | return currentLttngEvent; |
5d10d135 ASL |
773 | } |
774 | ||
fafd6325 WB |
775 | |
776 | ||
3fbd810a | 777 | /** |
07d9e2ee FC |
778 | * Reference to the current LttngTrace we are reading from.<p> |
779 | * | |
780 | * Note : This bypass the framework and should not be use, except for testing! | |
781 | * | |
782 | * @return Reference to the current LttngTrace | |
3fbd810a | 783 | * |
28b94d61 | 784 | * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniTrace |
3fbd810a FC |
785 | */ |
786 | public JniTrace getCurrentJniTrace() { | |
787 | return currentJniTrace; | |
788 | } | |
789 | ||
790 | ||
791 | /** | |
792 | * Return a reference to the current LttngEvent we have in memory. | |
793 | * | |
07d9e2ee FC |
794 | * @return The current (last read) LttngEvent |
795 | * | |
3fbd810a FC |
796 | * @see org.eclipse.linuxtools.lttng.event.LttngEvent |
797 | */ | |
798 | public LttngEvent getCurrentEvent() { | |
799 | return currentLttngEvent; | |
800 | } | |
801 | ||
a3fe52fc FC |
802 | /** |
803 | * Get the major version number for the current trace | |
804 | * | |
805 | * @return Version major or -1 if unknown | |
806 | * | |
807 | * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniTrace | |
808 | * | |
809 | */ | |
810 | public short getVersionMajor() { | |
811 | if ( currentJniTrace!= null ) { | |
812 | return currentJniTrace.getLttMajorVersion(); | |
813 | } | |
814 | else { | |
815 | return -1; | |
816 | } | |
817 | } | |
818 | ||
819 | /** | |
820 | * Get the minor version number for the current trace | |
821 | * | |
822 | * @return Version minor or -1 if unknown | |
823 | * | |
824 | * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniTrace | |
825 | * | |
826 | */ | |
827 | public short getVersionMinor() { | |
828 | if ( currentJniTrace!= null ) { | |
829 | return currentJniTrace.getLttMinorVersion(); | |
830 | } | |
831 | else { | |
832 | return -1; | |
833 | } | |
834 | } | |
835 | ||
836 | /** | |
837 | * Get the number of CPU for this trace | |
838 | * | |
839 | * @return Number of CPU or -1 if unknown | |
840 | * | |
841 | * @see org.eclipse.linuxtools.org.eclipse.linuxtools.lttng.jni.JniTrace | |
842 | * | |
843 | */ | |
844 | public int getCpuNumber() { | |
845 | if ( currentJniTrace!= null ) { | |
846 | return currentJniTrace.getCpuNumber(); | |
847 | } | |
848 | else { | |
849 | return -1; | |
850 | } | |
851 | } | |
852 | ||
7f2f49e3 WB |
853 | /** |
854 | * Print the content of the checkpoint vector.<p> | |
855 | * | |
856 | * This is intended for debug purpose only. | |
857 | */ | |
858 | public void printCheckpointsVector() { | |
859 | System.out.println("StartTime : " + getTimeRange().getStartTime().getValue()); | |
860 | System.out.println("EndTime : " + getTimeRange().getEndTime().getValue()); | |
a55a769e WB |
861 | |
862 | for ( int pos=0; pos < fCheckpoints.size(); pos++) { | |
a55a769e WB |
863 | System.out.print(pos + ": " + "\t"); |
864 | System.out.print( fCheckpoints.get(pos).getTimestamp() + "\t" ); | |
865 | System.out.println( fCheckpoints.get(pos).getLocation() ); | |
866 | } | |
867 | } | |
868 | ||
7f2f49e3 WB |
869 | /** |
870 | * Return a String identifying this trace. | |
871 | * | |
872 | * @return String that identify this trace | |
873 | */ | |
a55a769e | 874 | @Override |
7f2f49e3 WB |
875 | public String toString() { |
876 | String returnedData=""; | |
a55a769e | 877 | |
7f2f49e3 WB |
878 | returnedData += "Path :" + getPath() + " "; |
879 | returnedData += "Trace:" + currentJniTrace + " "; | |
880 | returnedData += "Event:" + currentLttngEvent; | |
a55a769e | 881 | |
7f2f49e3 | 882 | return returnedData; |
a55a769e | 883 | } |
28b94d61 FC |
884 | } |
885 | ||
886 | /* | |
887 | * EventTypeKey inner class | |
888 | * | |
889 | * This class is used to make the process of generating the HashMap key more transparent and so less error prone to use | |
890 | * | |
891 | */ | |
892 | class EventTypeKey { | |
893 | //*** WARNING *** | |
894 | // These two getEventTypeKey() functions should ALWAYS construct the key the same ways! | |
895 | // Otherwise, every type search will fail! | |
896 | ||
897 | static public String getEventTypeKey(LttngEventType newEventType) { | |
898 | String key = newEventType.getTracefileName() + "/" + newEventType.getCpuId().toString() + "/" + newEventType.getMarkerName(); | |
899 | ||
900 | return key; | |
901 | } | |
3fbd810a | 902 | |
28b94d61 FC |
903 | static public String getEventTypeKey(JniEvent newEvent) { |
904 | String key = newEvent.getParentTracefile().getTracefileName() + "/" + newEvent.getParentTracefile().getCpuNumber() + "/" + newEvent.requestEventMarker().getName(); | |
905 | ||
906 | return key; | |
907 | } | |
908 | ||
e31e01e8 | 909 | } |