Skip to main content
summaryrefslogtreecommitdiffstats
blob: 48dee4a666ef3e2c17226fbdcd4d57cce35cdd80 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
package org.eclipse.linuxtools.lttng.jni;
/*******************************************************************************
 * Copyright (c) 2009 Ericsson
 * 
 * All rights reserved. This program and the accompanying materials are
 * made available under the terms of the Eclipse Public License v1.0 which
 * accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors:
 *   William Bourque (wbourque@gmail.com) - Initial API and implementation
 *******************************************************************************/


import java.util.HashMap;

import org.eclipse.linuxtools.lttng.jni.common.JniTime;
import org.eclipse.linuxtools.lttng.jni.common.Jni_C_Pointer_And_Library_Id;
import org.eclipse.linuxtools.lttng.jni.exception.JniEventException;
import org.eclipse.linuxtools.lttng.jni.exception.JniException;
import org.eclipse.linuxtools.lttng.jni.exception.JniNoSuchEventException;

/**
 * <b><u>JniEvent</u></b> <p>
 * 
 * A JniEvent has the actual content that got traced by Lttng.<br>
 * Provides access to the LttEvent C structure in java. <p>
 * 
 * Most important fields in the JniEvent are :
 * <ul>
 * <li>an event time, which is a digested timestamp.
 * </ul>
 * Note that the JniEvent content is not directly accessibe and should be obtained
 * using the parseAllFields() or parseFieldBy...() methods.
 * 
 * <b>NOTE</b><p>
 * This class is ABSTRACT, you need to extends it to support your specific LTTng version.<p>
 * 
 */
public abstract class JniEvent extends Jni_C_Common implements Comparable<JniEvent> 
{
    // Variables to detect if the event have been filled at least once
    // this make possible the detection of "uninitialized" struct in Ltt
    // Can be "EOK", "ERANGE" or "EPERM" (defined in Jni_C_Common)
    private int eventState = EPERM; // Start with EPERM to ensure sanity

    // Internal C pointer of the JniEvent used in LTT
    private Jni_C_Pointer_And_Library_Id thisEventPtr = new Jni_C_Pointer_And_Library_Id();

    // Reference to the parent tracefile
    private JniTracefile parentTracefile = null;

    // This map hold marker relative to the parent tracefile of this event
    // They are "our" marker in this event
    private HashMap<Integer, JniMarker> markersMap = null;

    // Data we should populate from ltt
    // Note that all type have been scaled up as there is no "unsigned" in java
    // This might be a problem about "unsigned long" as there is no equivalent
    // in java
    private Jni_C_Pointer_And_Library_Id tracefilePtr = new Jni_C_Pointer_And_Library_Id();
    private JniTime eventTime = null;

    // These methods need a tracefile pointer, instead of a event pointer
    protected native int      ltt_readNextEvent(int libId, long tracefilePtr);
    protected native int      ltt_seekEvent(int libId, long tracefilePtr, JniTime givenTime);
    protected native int      ltt_positionToFirstEvent(int libId, long tracefilePtr);
        
    // Native access functions
    protected native long     ltt_getTracefilePtr(int libId, long eventPtr);
    protected native long     ltt_getBlock(int libId, long eventPtr);
    protected native long     ltt_getOffset(int libId, long eventPtr);
    protected native long     ltt_getCurrentTimestampCounter(int libId, long eventPtr);
    protected native long     ltt_getTimestamp(int libId, long eventPtr);
    protected native int      ltt_getEventMarkerId(int libId, long eventPtr);
    protected native long     ltt_getNanosencondsTime(int libId, long eventPtr);
    protected native void     ltt_feedEventTime(int libId, long eventPtr, JniTime eventTime);
    protected native long     ltt_getEventDataSize(int libId, long eventPtr);
    protected native long     ltt_getEventSize(int libId, long eventPtr);
    protected native int      ltt_getCount(int libId, long eventPtr);
    protected native long     ltt_getOverflowNanoSeconds(int libId, long eventPtr);
        
    // This method can be use to obtain the content as byte array
    // Warning : untested!
    protected native void     ltt_getDataContent(int libId, long eventPtr, long dataSize, byte[] returnedContent);
        
    // Debug native function, ask LTT to print event structure
    protected native void     ltt_printEvent(int libId, long eventPtr);
    
    /**
     * Default constructor is forbidden
     */
    protected JniEvent() {
    }

    /**
     * Copy constructor.<p>
     * 
     * @param oldEvent      Reference to the JniEvent you want to copy. 
     */
    public JniEvent(JniEvent oldEvent) {
        thisEventPtr = oldEvent.thisEventPtr;
        markersMap = oldEvent.markersMap;
        parentTracefile = oldEvent.parentTracefile;
        eventState = oldEvent.eventState;

        tracefilePtr = oldEvent.tracefilePtr;
        eventTime = oldEvent.eventTime;
    }
    
    /**
     * Constructor with parameters<p>
     * 
     * This constructor could throw. It will happen if an event can not be populated on <u>first read</u>.<br>
     * In that case, the parent tracefile is probably useless and should be deleted.
     * 
     * @param newEventPtr         C pointer (converted in long) of the LttEvent C structure.
     * @param newMarkersMap       Reference an already populated HashMap of JniMarker objects 
     * @param newParentTracefile  Reference to the parent JniTracefile of this JniEvent
     *            
     * @exception JniException
     * 
     * @see org.eclipse.linuxtools.lttng.jni.common.Jni_C_Pointer_And_Library_Id
     * @see org.eclipse.linuxtools.lttng.jni.JniMarker
     * @see org.eclipse.linuxtools.lttng.jni.JniTracefile
     */
    public JniEvent(Jni_C_Pointer_And_Library_Id newEventPtr, HashMap<Integer, JniMarker> newMarkersMap, JniTracefile newParentTracefile) throws JniException {
    	
        // Basic test to make sure we didn't get null/empty value 
        if ((newEventPtr.getPointer() == NULL)
                || (newMarkersMap == null) 
                || (newMarkersMap.size() == 0)
                || (newParentTracefile == null)) {
            throw new JniEventException("Null or empty value passed to constructor, object is invalid! (JniEvent)");
        }
        
        thisEventPtr = newEventPtr;
        tracefilePtr = newParentTracefile.getTracefilePtr();
        markersMap = newMarkersMap;
        parentTracefile = newParentTracefile;

        eventTime = new JniTime();
        
        // Try to move to the first event
        // If the event is Out of Range (ERANGE) at the first read, 
        //  this event type will never be usable.
        // In that case, throw JniNoSuchEventException to warn the tracefile.
        eventState = positionToFirstEvent();
        if (eventState != EOK)  {
            throw new JniNoSuchEventException("Object not populated, unusable. There is probably no event of that type in the trace. (JniEvent)");
        }
        else {
            populateEventInformation();
        }
    }

    /**
     * Move to the next event and populate the java object with LttEvent structure.<p>
     * 
     * If the move fails, the event will not get populated and the last event data will still be available.
     * 
     * @return LTT read status, as defined in Jni_C_Constant.
     * 
     * @see org.eclipse.linuxtools.lttng.jni.common.Jni_C_Constant
     */
     public int readNextEvent() {
        // Ask Ltt to read the next event for this particular tracefile
        eventState = ltt_readNextEvent(tracefilePtr.getLibraryId(), tracefilePtr.getPointer() );
        // If the event state is sane populate it
        if (eventState == EOK) {
            populateEventInformation();
        }
        
        return eventState;
    }

    /**
     * Seek to a certain time.<p>
     * 
     * Seek to a certain time and read event at this exact time or the next one if there is no event there.<p>
     * 
     * Note that this function can seek in an invalid position if the timestamp is after the last event.<br>
     * In that case, a seek back would be required to get back to a consistent state.<p>
     * 
     * If the seek fails, the event will not get populated and the last event data will still be available.<p>
     * 
     * @return LTT read status, as defined in Jni_C_Constant
     * 
     * @see org.eclipse.linuxtools.lttng.jni.common.Jni_C_Constant
     */
    public int seekToTime(JniTime seekTime) {
        // Ask Ltt to read the next event for this particular tracefile
        eventState = ltt_seekEvent(tracefilePtr.getLibraryId(), tracefilePtr.getPointer(), seekTime);
        
        // If the event state is sane populate it
        if (eventState == EOK) {
            populateEventInformation();
        }

        return eventState;
    }

    /**
     * Try to seek to a certain time and seek back if it failed.<p>
     * 
     * Seek to a certain time and read event at this exact time or the next one if there is no event there.<p>
     * 
     * If the seek fails, we will seek back to the previous position, so the event will stay in a consistent state.<p> 
     * 
     * @return LTT read status, as defined in Jni_C_Constant
     * 
     * @see org.eclipse.linuxtools.lttng.jni.common.Jni_C_Constant
     */
    public int seekOrFallBack(JniTime seekTime) {
        // Save the old time
        JniTime oldTime = new JniTime(eventTime);

        // Call seek to move ahead
        // Save the state for the return (eventState will be modified if we seek back)
        int returnState = seekToTime(seekTime);

        // If the event state is sane populate it
        if (returnState == EOK) {
            populateEventInformation();
        }
        else {
            seekToTime(oldTime);
        }

        return returnState;
    }

    /**
     * Position on the first event in the tracefile.<p>
     * 
     * The function return the read status after the first event.<p>
     * 
     * A status different of EOK probably means there is no event associated to this tracefile.
     * 
     * @return LTT read status, as defined in Jni_C_Constant
     * 
     * @see org.eclipse.linuxtools.lttng.jni.common.Jni_C_Constant
     */
    public int positionToFirstEvent() {
        eventState = ltt_positionToFirstEvent(tracefilePtr.getLibraryId(), tracefilePtr.getPointer());
        
        return eventState;
    }
    
    /**
     * Obtain a marker associated with this tracefile's event.
     * 
     * @return Reference to the marker for this tracefile's event or null if none.
     *  
     * @see org.eclipse.linuxtools.lttng.jni.JniMarker
     */
    public JniMarker requestEventMarker() {
        return markersMap.get(getEventMarkerId());
    }

    /**
     * Obtain the raw data of a LttEvent object.<p>
     * 
     * The data will be in raw C bytes, not java bytes.<br>
     * Note : This function is mostly untested and provided "as is".
     * 
     * @return  Bytes array of raw data (contain raw C bytes).
     */
    public byte[] requestEventContent() {
        byte dataContent[] = new byte[(int) getEventDataSize()];

        ltt_getDataContent(thisEventPtr.getLibraryId(), thisEventPtr.getPointer(), getEventDataSize(), dataContent);

        return dataContent;
    }
    
    /**
     * Obtain an event source.<p>
     * 
     * This is not implemented yet and will always return "Kernel core" for now.
     * 
     * @return  Reference to the JniMarker object for this event or null if none. 
     * 
     * @see org.eclipse.linuxtools.lttng.jni.JniMarker
     */
    public String requestEventSource() {
        // *** TODO ***
        // No "Source" of event exists in Ltt so far
        // It would be a good addition to have a way to detect where an event come
        // from, like "kernel" or "userspace"
        // 
        return "Kernel Core";
    }
    
    /**
     * Parse a particular field in the event payload, identified by its id (position).<p>
     * 
     * Note : Position are relative to an event marker (i.e. requestEventMarker().getMarkerFieldsArrayList() )
     * 
     * @param fieldId   Position of the field to parse.
     * 
     * @return Object that contain the parsed payload
     * 
     * @see org.eclipse.linuxtools.lttng.jni.JniParser
     */
    public Object parseFieldById(int fieldId) {
        return JniParser.parseField(this, fieldId);
    }
    
    /**
     * Parse a particular field in the event payload, identified by its name.<p>
     * 
     * Note : Name are relative to an event marker (i.e. requestEventMarker().getMarkerFieldsHashMap() )
     * 
     * @param fieldName   Position of the field to parse.
     * 
     * @return Object that contain the parsed payload
     * 
     * @see org.eclipse.linuxtools.lttng.jni.JniParser
     */
    public Object parseFieldByName(String fieldName) {
        return JniParser.parseField(this, fieldName);
    }
    
    /**
     * Method to parse all the event payload.<p>
     * 
     * @return HashMap<String, Object> which is the parsedContent objects and their name as key.
     * 
     * @see org.eclipse.linuxtools.lttng.jni.JniParser 
     */
    public HashMap<String, Object> parseAllFields() {
        return JniParser.parseAllFields(this);
    }

    /* 
     * This function populates the event data with data from LTT
     * 
     * NOTE : To get better performance, we copy very few data into memory here
     * 
     */
    private void populateEventInformation() {
    	// We need to save the time, as it is not a primitive (can't be dynamically called in getter)
    	eventTime.setTime(ltt_getNanosencondsTime(thisEventPtr.getLibraryId(), thisEventPtr.getPointer()));
    }
    
    public JniTime getEventTime() {
        return eventTime;
    }
    
    // *** To get better performance, all getter belows call LTT directly ****
    //     That way, we can avoid copying data into memory
    public int getEventMarkerId() {
        return ltt_getEventMarkerId(thisEventPtr.getLibraryId(), thisEventPtr.getPointer());
    }

    public long getEventDataSize() {
        return ltt_getEventDataSize(thisEventPtr.getLibraryId(), thisEventPtr.getPointer());
    }

    public HashMap<Integer, JniMarker> getMarkersMap() {
        return markersMap;
    }

    /**
     * Pointer to the parent LTTTracefile C structure.<br>
     * <br>
     * The pointer should only be used <u>INTERNALY</u>, do not use unless you
     * know what you are doing.
     * 
     * @return The actual (long converted) pointer or NULL.
     * 
     * @see org.eclipse.linuxtools.lttng.jni.common.Jni_C_Pointer_And_Library_Id
     */
    public Jni_C_Pointer_And_Library_Id getTracefilePtr() {
        return new Jni_C_Pointer_And_Library_Id(thisEventPtr.getLibraryId(), ltt_getTracefilePtr(thisEventPtr.getLibraryId(), thisEventPtr.getPointer()) );
    }

    /**
     * Pointer to the LttEvent C structure.<br>
     * <br>
     * The pointer should only be used <u>INTERNALY</u>, do not use unless you
     * know what you are doing.
     * 
     * @return The actual (long converted) pointer or NULL.
     * 
     * @see org.eclipse.linuxtools.lttng.jni.common.Jni_C_Pointer_And_Library_Id
     */
    public Jni_C_Pointer_And_Library_Id getEventPtr() {
        return thisEventPtr;
    }

    public int getEventState() {
        return eventState;
    }

    /**
     * Getter to the parent tracefile for this event.
     *
     * @return  The parent tracefile 
     * 
     * @see org.eclipse.linuxtools.lttng.jni.JniTracefile
     */
    public JniTracefile getParentTracefile() {
        return parentTracefile;
    }
    
    /**
     * Compare fonction for JNIEvent.<p>
     * <p>
     * This will compare the current JNIEvent with a passed one by timestamp AND tracefile ("type").<br>
     * If both are equal but type differs, current event is considered to be older (-1 returned).
     * 
     * @return -1 if given event happens before, 0 if equal, 1 if passed event happens after.
     */
    public int compareTo(JniEvent rightEvent ){
    	
    	// Note : this = left hand operand
    	
        // By default, we consider the current event to be older.
        int eventComparaison = -1; 
        
        // Test against null before performing anything
        if ( rightEvent != null ) {
            // Compare the timestamp first
            eventComparaison = this.getEventTime().compareTo( rightEvent.getEventTime() );
            
            // If timestamp is equal, compare the parent tracefile ("event type")
            if ( (eventComparaison == 0) && ( !this.parentTracefile.equals(rightEvent.parentTracefile)) ) {
                eventComparaison = 1;
            }
        }
        return eventComparaison;
    }
    
    /**
     * Print information for this event. 
     * <u>Intended to debug</u><br>
     * 
     * This function will call Ltt to print, so information printed will be 
     * the one from the C structure, not the one populated in java.<p>
     */
    public void printEventInformation() {
        ltt_printEvent(thisEventPtr.getLibraryId(), thisEventPtr.getPointer());
    }
    
    /**
     * toString() method. 
     * <u>Intended to debug.</u><p>
     * 
     * @return Attributes of the object concatenated in String
     */
    @Override
	public String toString() {
        String returnData = "";

        returnData += "tracefilePtr            : " + tracefilePtr + "\n";
        returnData += "eventMarkerId           : " + getEventMarkerId() + "\n";
        returnData += "eventTime               : " + eventTime.getReferenceToString() + "\n";
        returnData += "   seconds              : " + eventTime.getSeconds() + "\n";
        returnData += "   nanoSeconds          : " + eventTime.getNanoSeconds() + "\n";
        returnData += "eventDataSize           : " + getEventDataSize() + "\n";
        returnData += "markersMap              : " + markersMap.keySet() + "\n"; // Hack to avoid ending up with markersMap.toString()

        return returnData;
    }
    
}

Back to the top