jitprofiling.c revision 256281
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
33static 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"
47HINSTANCE m_libHandle = NULL;
48#else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
49#define DEFAULT_DLLNAME                 "libJitPI.so"
50void* 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 */
57typedef unsigned int(*TPInitialize)(void);
58static TPInitialize FUNC_Initialize=NULL;
59
60typedef unsigned int(*TPNotify)(unsigned int, void*);
61static TPNotify FUNC_NotifyEvent=NULL;
62
63static 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 */
73static int loadiJIT_Funcs(void);
74
75/* global representing whether the BistroJavaCollector can't be loaded */
76static 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
87static DWORD threadLocalStorageHandle = 0;
88#else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
89static pthread_key_t threadLocalStorageHandle = (pthread_key_t)0;
90#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
91
92#define INIT_TOP_Stack 10000
93
94typedef 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
112ITT_EXTERN_C int JITAPI
113iJIT_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 */
243ITT_EXTERN_C void JITAPI
244iJIT_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 */
262ITT_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 */
277static 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 */
420ITT_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*/
448ITT_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 */
473ITT_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}
482