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 #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 }
    482