Removing dependency on third party library for Intel JIT event support.
[oota-llvm.git] / lib / ExecutionEngine / IntelJITEvents / jitprofiling.c
1 /*===-- jitprofiling.c - JIT (Just-In-Time) Profiling API----------*- C -*-===*
2  *
3  *                     The LLVM Compiler Infrastructure
4  *
5  * This file is distributed under the University of Illinois Open Source
6  * License. See LICENSE.TXT for details.
7  *
8  *===----------------------------------------------------------------------===*
9  *
10  * This file provides Intel(R) Performance Analyzer JIT (Just-In-Time) 
11  * Profiling API implementation. 
12  *
13  *===----------------------------------------------------------------------===*/
14 #include "ittnotify_config.h"
15
16 #if ITT_PLATFORM==ITT_PLATFORM_WIN
17 #include <windows.h>
18 #pragma optimize("", off)
19 #else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
20 #include <pthread.h>
21 #include <dlfcn.h>
22 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
23 #include <malloc.h>
24 #include <stdlib.h>
25
26 #include "jitprofiling.h"
27
28 static const char rcsid[] = "\n@(#) $Revision: 243501 $\n";
29
30 #define DLL_ENVIRONMENT_VAR             "VS_PROFILER"
31
32 #ifndef NEW_DLL_ENVIRONMENT_VAR
33 #if ITT_ARCH==ITT_ARCH_IA32
34 #define NEW_DLL_ENVIRONMENT_VAR         "INTEL_JIT_PROFILER32"
35 #else
36 #define NEW_DLL_ENVIRONMENT_VAR         "INTEL_JIT_PROFILER64"
37 #endif
38 #endif /* NEW_DLL_ENVIRONMENT_VAR */
39
40 #if ITT_PLATFORM==ITT_PLATFORM_WIN
41 #define DEFAULT_DLLNAME                 "JitPI.dll"
42 HINSTANCE m_libHandle = NULL;
43 #else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
44 #define DEFAULT_DLLNAME                 "libJitPI.so"
45 void* m_libHandle = NULL;
46 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
47
48 /* default location of JIT profiling agent on Android */
49 #define ANDROID_JIT_AGENT_PATH  "/data/intel/libittnotify.so"
50
51 /* the function pointers */
52 typedef unsigned int(*TPInitialize)(void);
53 static TPInitialize FUNC_Initialize=NULL;
54
55 typedef unsigned int(*TPNotify)(unsigned int, void*);
56 static TPNotify FUNC_NotifyEvent=NULL;
57
58 static iJIT_IsProfilingActiveFlags executionMode = iJIT_NOTHING_RUNNING;
59
60 /* end collector dll part. */
61
62 /* loadiJIT_Funcs() : this function is called just in the beginning 
63  *  and is responsible to load the functions from BistroJavaCollector.dll
64  * result:
65  *  on success: the functions loads, iJIT_DLL_is_missing=0, return value = 1
66  *  on failure: the functions are NULL, iJIT_DLL_is_missing=1, return value = 0
67  */ 
68 static int loadiJIT_Funcs(void);
69
70 /* global representing whether the BistroJavaCollector can't be loaded */
71 static int iJIT_DLL_is_missing = 0;
72
73 /* Virtual stack - the struct is used as a virtual stack for each thread.
74  * Every thread initializes with a stack of size INIT_TOP_STACK.
75  * Every method entry decreases from the current stack point,
76  * and when a thread stack reaches its top of stack (return from the global 
77  * function), the top of stack and the current stack increase. Notice that 
78  * when returning from a function the stack pointer is the address of 
79  * the function return.
80 */
81 #if ITT_PLATFORM==ITT_PLATFORM_WIN
82 static DWORD threadLocalStorageHandle = 0;
83 #else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
84 static pthread_key_t threadLocalStorageHandle = (pthread_key_t)0;
85 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
86
87 #define INIT_TOP_Stack 10000
88
89 typedef struct 
90 {
91     unsigned int TopStack;
92     unsigned int CurrentStack;
93 } ThreadStack, *pThreadStack;
94
95 /* end of virtual stack. */
96
97 /*
98  * The function for reporting virtual-machine related events to VTune.
99  * Note: when reporting iJVM_EVENT_TYPE_ENTER_NIDS, there is no need to fill 
100  * in the stack_id field in the iJIT_Method_NIDS structure, as VTune fills it.
101  * The return value in iJVM_EVENT_TYPE_ENTER_NIDS && 
102  * iJVM_EVENT_TYPE_LEAVE_NIDS events will be 0 in case of failure.
103  * in iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED event 
104  * it will be -1 if EventSpecificData == 0 otherwise it will be 0.
105 */
106
107 ITT_EXTERN_C int JITAPI 
108 iJIT_NotifyEvent(iJIT_JVM_EVENT event_type, void *EventSpecificData)
109 {
110     int ReturnValue;
111
112     /*
113      * This section is for debugging outside of VTune. 
114      * It creates the environment variables that indicates call graph mode.
115      * If running outside of VTune remove the remark.
116      *
117      *
118      * static int firstTime = 1;
119      * char DoCallGraph[12] = "DoCallGraph";
120      * if (firstTime)
121      * {
122      * firstTime = 0;
123      * SetEnvironmentVariable( "BISTRO_COLLECTORS_DO_CALLGRAPH", DoCallGraph);
124      * }
125      *
126      * end of section.
127     */
128
129     /* initialization part - the functions have not been loaded yet. This part
130      *        will load the functions, and check if we are in Call Graph mode. 
131      *        (for special treatment).
132      */
133     if (!FUNC_NotifyEvent) 
134     {
135         if (iJIT_DLL_is_missing) 
136             return 0;
137
138         /* load the Function from the DLL */
139         if (!loadiJIT_Funcs()) 
140             return 0;
141
142         /* Call Graph initialization. */
143     }
144
145     /* If the event is method entry/exit, check that in the current mode 
146      * VTune is allowed to receive it
147      */
148     if ((event_type == iJVM_EVENT_TYPE_ENTER_NIDS || 
149          event_type == iJVM_EVENT_TYPE_LEAVE_NIDS) &&
150         (executionMode != iJIT_CALLGRAPH_ON))
151     {
152         return 0;
153     }
154     /* This section is performed when method enter event occurs.
155      * It updates the virtual stack, or creates it if this is the first 
156      * method entry in the thread. The stack pointer is decreased.
157      */
158     if (event_type == iJVM_EVENT_TYPE_ENTER_NIDS)
159     {
160 #if ITT_PLATFORM==ITT_PLATFORM_WIN
161         pThreadStack threadStack = 
162             (pThreadStack)TlsGetValue (threadLocalStorageHandle);
163 #else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
164         pThreadStack threadStack = 
165             (pThreadStack)pthread_getspecific(threadLocalStorageHandle);
166 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
167
168         /* check for use of reserved method IDs */
169         if ( ((piJIT_Method_NIDS) EventSpecificData)->method_id <= 999 )
170             return 0;
171
172         if (!threadStack)
173         {
174             /* initialize the stack. */
175             threadStack = (pThreadStack) calloc (sizeof(ThreadStack), 1);
176             threadStack->TopStack = INIT_TOP_Stack;
177             threadStack->CurrentStack = INIT_TOP_Stack;
178 #if ITT_PLATFORM==ITT_PLATFORM_WIN
179             TlsSetValue(threadLocalStorageHandle,(void*)threadStack);
180 #else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
181             pthread_setspecific(threadLocalStorageHandle,(void*)threadStack);
182 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
183         }
184
185         /* decrease the stack. */
186         ((piJIT_Method_NIDS) EventSpecificData)->stack_id = 
187             (threadStack->CurrentStack)--;
188     }
189
190     /* This section is performed when method leave event occurs
191      * It updates the virtual stack.
192      *    Increases the stack pointer.
193      *    If the stack pointer reached the top (left the global function)
194      *        increase the pointer and the top pointer.
195      */
196     if (event_type == iJVM_EVENT_TYPE_LEAVE_NIDS)
197     {
198 #if ITT_PLATFORM==ITT_PLATFORM_WIN
199         pThreadStack threadStack = 
200            (pThreadStack)TlsGetValue (threadLocalStorageHandle);
201 #else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
202         pThreadStack threadStack = 
203             (pThreadStack)pthread_getspecific(threadLocalStorageHandle);
204 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
205
206         /* check for use of reserved method IDs */
207         if ( ((piJIT_Method_NIDS) EventSpecificData)->method_id <= 999 )
208             return 0;
209
210         if (!threadStack)
211         {
212             /* Error: first report in this thread is method exit */
213             exit (1);
214         }
215
216         ((piJIT_Method_NIDS) EventSpecificData)->stack_id = 
217             ++(threadStack->CurrentStack) + 1;
218
219         if (((piJIT_Method_NIDS) EventSpecificData)->stack_id 
220                > threadStack->TopStack)
221             ((piJIT_Method_NIDS) EventSpecificData)->stack_id = 
222                 (unsigned int)-1;
223     }
224
225     if (event_type == iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED)
226     {
227         /* check for use of reserved method IDs */
228         if ( ((piJIT_Method_Load) EventSpecificData)->method_id <= 999 )
229             return 0;
230     }
231
232     ReturnValue = (int)FUNC_NotifyEvent(event_type, EventSpecificData);   
233
234     return ReturnValue;
235 }
236
237 /* The new mode call back routine */
238 ITT_EXTERN_C void JITAPI 
239 iJIT_RegisterCallbackEx(void *userdata, iJIT_ModeChangedEx 
240                         NewModeCallBackFuncEx) 
241 {
242     /* is it already missing... or the load of functions from the DLL failed */
243     if (iJIT_DLL_is_missing || !loadiJIT_Funcs())
244     {
245         /* then do not bother with notifications */
246         NewModeCallBackFuncEx(userdata, iJIT_NO_NOTIFICATIONS);  
247         /* Error: could not load JIT functions. */
248         return;
249     }
250     /* nothing to do with the callback */
251 }
252
253 /*
254  * This function allows the user to query in which mode, if at all, 
255  *VTune is running
256  */
257 ITT_EXTERN_C iJIT_IsProfilingActiveFlags JITAPI iJIT_IsProfilingActive()
258 {
259     if (!iJIT_DLL_is_missing)
260     {
261         loadiJIT_Funcs();
262     }
263
264     return executionMode;
265 }
266
267 /* this function loads the collector dll (BistroJavaCollector) 
268  * and the relevant functions.
269  * on success: all functions load,     iJIT_DLL_is_missing = 0, return value = 1
270  * on failure: all functions are NULL, iJIT_DLL_is_missing = 1, return value = 0
271  */ 
272 static int loadiJIT_Funcs()
273 {
274     static int bDllWasLoaded = 0;
275     char *dllName = (char*)rcsid; /* !! Just to avoid unused code elimination */
276 #if ITT_PLATFORM==ITT_PLATFORM_WIN
277     DWORD dNameLength = 0;
278 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
279
280     if(bDllWasLoaded)
281     {
282         /* dll was already loaded, no need to do it for the second time */
283         return 1;
284     }
285
286     /* Assumes that the DLL will not be found */
287     iJIT_DLL_is_missing = 1;
288     FUNC_NotifyEvent = NULL;
289
290     if (m_libHandle) 
291     {
292 #if ITT_PLATFORM==ITT_PLATFORM_WIN
293         FreeLibrary(m_libHandle);
294 #else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
295         dlclose(m_libHandle);
296 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
297         m_libHandle = NULL;
298     }
299
300     /* Try to get the dll name from the environment */
301 #if ITT_PLATFORM==ITT_PLATFORM_WIN
302     dNameLength = GetEnvironmentVariableA(NEW_DLL_ENVIRONMENT_VAR, NULL, 0);
303     if (dNameLength)
304     {
305         DWORD envret = 0;
306         dllName = (char*)malloc(sizeof(char) * (dNameLength + 1));
307         envret = GetEnvironmentVariableA(NEW_DLL_ENVIRONMENT_VAR, 
308                                          dllName, dNameLength);
309         if (envret)
310         {
311             /* Try to load the dll from the PATH... */
312             m_libHandle = LoadLibraryExA(dllName, 
313                                          NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
314         }
315         free(dllName);
316     } else {
317         /* Try to use old VS_PROFILER variable */
318         dNameLength = GetEnvironmentVariableA(DLL_ENVIRONMENT_VAR, NULL, 0);
319         if (dNameLength)
320         {
321             DWORD envret = 0;
322             dllName = (char*)malloc(sizeof(char) * (dNameLength + 1));
323             envret = GetEnvironmentVariableA(DLL_ENVIRONMENT_VAR, 
324                                              dllName, dNameLength);
325             if (envret)
326             {
327                 /* Try to load the dll from the PATH... */
328                 m_libHandle = LoadLibraryA(dllName);
329             }
330             free(dllName);
331         }
332     }
333 #else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
334     dllName = getenv(NEW_DLL_ENVIRONMENT_VAR);
335     if (!dllName)
336         dllName = getenv(DLL_ENVIRONMENT_VAR);
337 #ifdef ANDROID
338     if (!dllName)
339         dllName = ANDROID_JIT_AGENT_PATH;
340 #endif
341     if (dllName)
342     {
343         /* Try to load the dll from the PATH... */
344         m_libHandle = dlopen(dllName, RTLD_LAZY);
345     }
346 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
347
348     if (!m_libHandle)
349     {
350 #if ITT_PLATFORM==ITT_PLATFORM_WIN
351         m_libHandle = LoadLibraryA(DEFAULT_DLLNAME);
352 #else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
353         m_libHandle = dlopen(DEFAULT_DLLNAME, RTLD_LAZY);
354 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
355     }
356
357     /* if the dll wasn't loaded - exit. */
358     if (!m_libHandle)
359     {
360         iJIT_DLL_is_missing = 1; /* don't try to initialize 
361                                   * JIT agent the second time 
362                                   */
363         return 0;
364     }
365
366 #if ITT_PLATFORM==ITT_PLATFORM_WIN
367     FUNC_NotifyEvent = (TPNotify)GetProcAddress(m_libHandle, "NotifyEvent");
368 #else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
369     FUNC_NotifyEvent = (TPNotify)dlsym(m_libHandle, "NotifyEvent");
370 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
371     if (!FUNC_NotifyEvent) 
372     {
373         FUNC_Initialize = NULL;
374         return 0;
375     }
376
377 #if ITT_PLATFORM==ITT_PLATFORM_WIN
378     FUNC_Initialize = (TPInitialize)GetProcAddress(m_libHandle, "Initialize");
379 #else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
380     FUNC_Initialize = (TPInitialize)dlsym(m_libHandle, "Initialize");
381 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
382     if (!FUNC_Initialize) 
383     {
384         FUNC_NotifyEvent = NULL;
385         return 0;
386     }
387
388     executionMode = (iJIT_IsProfilingActiveFlags)FUNC_Initialize();
389
390     bDllWasLoaded = 1;
391     iJIT_DLL_is_missing = 0; /* DLL is ok. */
392
393     /*
394      * Call Graph mode: init the thread local storage
395      * (need to store the virtual stack there).
396      */
397     if ( executionMode == iJIT_CALLGRAPH_ON )
398     {
399         /* Allocate a thread local storage slot for the thread "stack" */
400         if (!threadLocalStorageHandle)
401 #if ITT_PLATFORM==ITT_PLATFORM_WIN
402             threadLocalStorageHandle = TlsAlloc();
403 #else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
404         pthread_key_create(&threadLocalStorageHandle, NULL);
405 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
406     }
407
408     return 1;
409 }
410
411 /*
412  * This function should be called by the user whenever a thread ends, 
413  * to free the thread "virtual stack" storage
414  */
415 ITT_EXTERN_C void JITAPI FinalizeThread()
416 {
417     if (threadLocalStorageHandle)
418     {
419 #if ITT_PLATFORM==ITT_PLATFORM_WIN
420         pThreadStack threadStack = 
421             (pThreadStack)TlsGetValue (threadLocalStorageHandle);
422 #else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
423         pThreadStack threadStack = 
424             (pThreadStack)pthread_getspecific(threadLocalStorageHandle);
425 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
426         if (threadStack)
427         {
428             free (threadStack);
429             threadStack = NULL;
430 #if ITT_PLATFORM==ITT_PLATFORM_WIN
431             TlsSetValue (threadLocalStorageHandle, threadStack);
432 #else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
433             pthread_setspecific(threadLocalStorageHandle, threadStack);
434 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
435         }
436     }
437 }
438
439 /*
440  * This function should be called by the user when the process ends, 
441  * to free the local storage index
442 */
443 ITT_EXTERN_C void JITAPI FinalizeProcess()
444 {
445     if (m_libHandle) 
446     {
447 #if ITT_PLATFORM==ITT_PLATFORM_WIN
448         FreeLibrary(m_libHandle);
449 #else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
450         dlclose(m_libHandle);
451 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
452         m_libHandle = NULL;
453     }
454
455     if (threadLocalStorageHandle)
456 #if ITT_PLATFORM==ITT_PLATFORM_WIN
457         TlsFree (threadLocalStorageHandle);
458 #else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
459     pthread_key_delete(threadLocalStorageHandle);
460 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
461 }
462
463 /*
464  * This function should be called by the user for any method once.
465  * The function will return a unique method ID, the user should maintain 
466  * the ID for each method
467  */
468 ITT_EXTERN_C unsigned int JITAPI iJIT_GetNewMethodID()
469 {
470     static unsigned int methodID = 0x100000;
471
472     if (methodID == 0)
473         return 0;  /* ERROR : this is not a valid value */
474
475     return methodID++;
476 }