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