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