LLVM API Documentation

jitprofiling.c
Go to the documentation of this file.
00001 /*===-- jitprofiling.c - JIT (Just-In-Time) Profiling API----------*- C -*-===*
00002  *
00003  *                     The LLVM Compiler Infrastructure
00004  *
00005  * This file is distributed under the University of Illinois Open Source
00006  * License. See LICENSE.TXT for details.
00007  *
00008  *===----------------------------------------------------------------------===*
00009  *
00010  * This file provides Intel(R) Performance Analyzer JIT (Just-In-Time) 
00011  * Profiling API implementation. 
00012  *
00013  * NOTE: This file comes in a style different from the rest of LLVM
00014  * source base since  this is a piece of code shared from Intel(R)
00015  * products.  Please do not reformat / re-style this code to make
00016  * subsequent merges and contributions from the original source base eaiser.
00017  *
00018  *===----------------------------------------------------------------------===*/
00019 #include "ittnotify_config.h"
00020 
00021 #if ITT_PLATFORM==ITT_PLATFORM_WIN
00022 #include <windows.h>
00023 #pragma optimize("", off)
00024 #else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
00025 #include <pthread.h>
00026 #include <dlfcn.h>
00027 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
00028 #include <malloc.h>
00029 #include <stdlib.h>
00030 
00031 #include "jitprofiling.h"
00032 
00033 static const char rcsid[] = "\n@(#) $Revision: 243501 $\n";
00034 
00035 #define DLL_ENVIRONMENT_VAR             "VS_PROFILER"
00036 
00037 #ifndef NEW_DLL_ENVIRONMENT_VAR
00038 #if ITT_ARCH==ITT_ARCH_IA32
00039 #define NEW_DLL_ENVIRONMENT_VAR         "INTEL_JIT_PROFILER32"
00040 #else
00041 #define NEW_DLL_ENVIRONMENT_VAR         "INTEL_JIT_PROFILER64"
00042 #endif
00043 #endif /* NEW_DLL_ENVIRONMENT_VAR */
00044 
00045 #if ITT_PLATFORM==ITT_PLATFORM_WIN
00046 #define DEFAULT_DLLNAME                 "JitPI.dll"
00047 HINSTANCE m_libHandle = NULL;
00048 #else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
00049 #define DEFAULT_DLLNAME                 "libJitPI.so"
00050 void* m_libHandle = NULL;
00051 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
00052 
00053 /* default location of JIT profiling agent on Android */
00054 #define ANDROID_JIT_AGENT_PATH  "/data/intel/libittnotify.so"
00055 
00056 /* the function pointers */
00057 typedef unsigned int(*TPInitialize)(void);
00058 static TPInitialize FUNC_Initialize=NULL;
00059 
00060 typedef unsigned int(*TPNotify)(unsigned int, void*);
00061 static TPNotify FUNC_NotifyEvent=NULL;
00062 
00063 static iJIT_IsProfilingActiveFlags executionMode = iJIT_NOTHING_RUNNING;
00064 
00065 /* end collector dll part. */
00066 
00067 /* loadiJIT_Funcs() : this function is called just in the beginning 
00068  *  and is responsible to load the functions from BistroJavaCollector.dll
00069  * result:
00070  *  on success: the functions loads, iJIT_DLL_is_missing=0, return value = 1
00071  *  on failure: the functions are NULL, iJIT_DLL_is_missing=1, return value = 0
00072  */ 
00073 static int loadiJIT_Funcs(void);
00074 
00075 /* global representing whether the BistroJavaCollector can't be loaded */
00076 static int iJIT_DLL_is_missing = 0;
00077 
00078 /* Virtual stack - the struct is used as a virtual stack for each thread.
00079  * Every thread initializes with a stack of size INIT_TOP_STACK.
00080  * Every method entry decreases from the current stack point,
00081  * and when a thread stack reaches its top of stack (return from the global 
00082  * function), the top of stack and the current stack increase. Notice that 
00083  * when returning from a function the stack pointer is the address of 
00084  * the function return.
00085 */
00086 #if ITT_PLATFORM==ITT_PLATFORM_WIN
00087 static DWORD threadLocalStorageHandle = 0;
00088 #else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
00089 static pthread_key_t threadLocalStorageHandle = (pthread_key_t)0;
00090 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
00091 
00092 #define INIT_TOP_Stack 10000
00093 
00094 typedef struct 
00095 {
00096     unsigned int TopStack;
00097     unsigned int CurrentStack;
00098 } ThreadStack, *pThreadStack;
00099 
00100 /* end of virtual stack. */
00101 
00102 /*
00103  * The function for reporting virtual-machine related events to VTune.
00104  * Note: when reporting iJVM_EVENT_TYPE_ENTER_NIDS, there is no need to fill 
00105  * in the stack_id field in the iJIT_Method_NIDS structure, as VTune fills it.
00106  * The return value in iJVM_EVENT_TYPE_ENTER_NIDS && 
00107  * iJVM_EVENT_TYPE_LEAVE_NIDS events will be 0 in case of failure.
00108  * in iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED event 
00109  * it will be -1 if EventSpecificData == 0 otherwise it will be 0.
00110 */
00111 
00112 ITT_EXTERN_C int JITAPI 
00113 iJIT_NotifyEvent(iJIT_JVM_EVENT event_type, void *EventSpecificData)
00114 {
00115     int ReturnValue;
00116 
00117     /*
00118      * This section is for debugging outside of VTune. 
00119      * It creates the environment variables that indicates call graph mode.
00120      * If running outside of VTune remove the remark.
00121      *
00122      *
00123      * static int firstTime = 1;
00124      * char DoCallGraph[12] = "DoCallGraph";
00125      * if (firstTime)
00126      * {
00127      * firstTime = 0;
00128      * SetEnvironmentVariable( "BISTRO_COLLECTORS_DO_CALLGRAPH", DoCallGraph);
00129      * }
00130      *
00131      * end of section.
00132     */
00133 
00134     /* initialization part - the functions have not been loaded yet. This part
00135      *        will load the functions, and check if we are in Call Graph mode. 
00136      *        (for special treatment).
00137      */
00138     if (!FUNC_NotifyEvent) 
00139     {
00140         if (iJIT_DLL_is_missing) 
00141             return 0;
00142 
00143         /* load the Function from the DLL */
00144         if (!loadiJIT_Funcs()) 
00145             return 0;
00146 
00147         /* Call Graph initialization. */
00148     }
00149 
00150     /* If the event is method entry/exit, check that in the current mode 
00151      * VTune is allowed to receive it
00152      */
00153     if ((event_type == iJVM_EVENT_TYPE_ENTER_NIDS || 
00154          event_type == iJVM_EVENT_TYPE_LEAVE_NIDS) &&
00155         (executionMode != iJIT_CALLGRAPH_ON))
00156     {
00157         return 0;
00158     }
00159     /* This section is performed when method enter event occurs.
00160      * It updates the virtual stack, or creates it if this is the first 
00161      * method entry in the thread. The stack pointer is decreased.
00162      */
00163     if (event_type == iJVM_EVENT_TYPE_ENTER_NIDS)
00164     {
00165 #if ITT_PLATFORM==ITT_PLATFORM_WIN
00166         pThreadStack threadStack = 
00167             (pThreadStack)TlsGetValue (threadLocalStorageHandle);
00168 #else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
00169         pThreadStack threadStack = 
00170             (pThreadStack)pthread_getspecific(threadLocalStorageHandle);
00171 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
00172 
00173         /* check for use of reserved method IDs */
00174         if ( ((piJIT_Method_NIDS) EventSpecificData)->method_id <= 999 )
00175             return 0;
00176 
00177         if (!threadStack)
00178         {
00179             /* initialize the stack. */
00180             threadStack = (pThreadStack) calloc (sizeof(ThreadStack), 1);
00181             threadStack->TopStack = INIT_TOP_Stack;
00182             threadStack->CurrentStack = INIT_TOP_Stack;
00183 #if ITT_PLATFORM==ITT_PLATFORM_WIN
00184             TlsSetValue(threadLocalStorageHandle,(void*)threadStack);
00185 #else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
00186             pthread_setspecific(threadLocalStorageHandle,(void*)threadStack);
00187 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
00188         }
00189 
00190         /* decrease the stack. */
00191         ((piJIT_Method_NIDS) EventSpecificData)->stack_id = 
00192             (threadStack->CurrentStack)--;
00193     }
00194 
00195     /* This section is performed when method leave event occurs
00196      * It updates the virtual stack.
00197      *    Increases the stack pointer.
00198      *    If the stack pointer reached the top (left the global function)
00199      *        increase the pointer and the top pointer.
00200      */
00201     if (event_type == iJVM_EVENT_TYPE_LEAVE_NIDS)
00202     {
00203 #if ITT_PLATFORM==ITT_PLATFORM_WIN
00204         pThreadStack threadStack = 
00205            (pThreadStack)TlsGetValue (threadLocalStorageHandle);
00206 #else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
00207         pThreadStack threadStack = 
00208             (pThreadStack)pthread_getspecific(threadLocalStorageHandle);
00209 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
00210 
00211         /* check for use of reserved method IDs */
00212         if ( ((piJIT_Method_NIDS) EventSpecificData)->method_id <= 999 )
00213             return 0;
00214 
00215         if (!threadStack)
00216         {
00217             /* Error: first report in this thread is method exit */
00218             exit (1);
00219         }
00220 
00221         ((piJIT_Method_NIDS) EventSpecificData)->stack_id = 
00222             ++(threadStack->CurrentStack) + 1;
00223 
00224         if (((piJIT_Method_NIDS) EventSpecificData)->stack_id 
00225                > threadStack->TopStack)
00226             ((piJIT_Method_NIDS) EventSpecificData)->stack_id = 
00227                 (unsigned int)-1;
00228     }
00229 
00230     if (event_type == iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED)
00231     {
00232         /* check for use of reserved method IDs */
00233         if ( ((piJIT_Method_Load) EventSpecificData)->method_id <= 999 )
00234             return 0;
00235     }
00236 
00237     ReturnValue = (int)FUNC_NotifyEvent(event_type, EventSpecificData);   
00238 
00239     return ReturnValue;
00240 }
00241 
00242 /* The new mode call back routine */
00243 ITT_EXTERN_C void JITAPI 
00244 iJIT_RegisterCallbackEx(void *userdata, iJIT_ModeChangedEx 
00245                         NewModeCallBackFuncEx) 
00246 {
00247     /* is it already missing... or the load of functions from the DLL failed */
00248     if (iJIT_DLL_is_missing || !loadiJIT_Funcs())
00249     {
00250         /* then do not bother with notifications */
00251         NewModeCallBackFuncEx(userdata, iJIT_NO_NOTIFICATIONS);  
00252         /* Error: could not load JIT functions. */
00253         return;
00254     }
00255     /* nothing to do with the callback */
00256 }
00257 
00258 /*
00259  * This function allows the user to query in which mode, if at all, 
00260  *VTune is running
00261  */
00262 ITT_EXTERN_C iJIT_IsProfilingActiveFlags JITAPI iJIT_IsProfilingActive()
00263 {
00264     if (!iJIT_DLL_is_missing)
00265     {
00266         loadiJIT_Funcs();
00267     }
00268 
00269     return executionMode;
00270 }
00271 
00272 /* this function loads the collector dll (BistroJavaCollector) 
00273  * and the relevant functions.
00274  * on success: all functions load,     iJIT_DLL_is_missing = 0, return value = 1
00275  * on failure: all functions are NULL, iJIT_DLL_is_missing = 1, return value = 0
00276  */ 
00277 static int loadiJIT_Funcs()
00278 {
00279     static int bDllWasLoaded = 0;
00280     char *dllName = (char*)rcsid; /* !! Just to avoid unused code elimination */
00281 #if ITT_PLATFORM==ITT_PLATFORM_WIN
00282     DWORD dNameLength = 0;
00283 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
00284 
00285     if(bDllWasLoaded)
00286     {
00287         /* dll was already loaded, no need to do it for the second time */
00288         return 1;
00289     }
00290 
00291     /* Assumes that the DLL will not be found */
00292     iJIT_DLL_is_missing = 1;
00293     FUNC_NotifyEvent = NULL;
00294 
00295     if (m_libHandle) 
00296     {
00297 #if ITT_PLATFORM==ITT_PLATFORM_WIN
00298         FreeLibrary(m_libHandle);
00299 #else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
00300         dlclose(m_libHandle);
00301 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
00302         m_libHandle = NULL;
00303     }
00304 
00305     /* Try to get the dll name from the environment */
00306 #if ITT_PLATFORM==ITT_PLATFORM_WIN
00307     dNameLength = GetEnvironmentVariableA(NEW_DLL_ENVIRONMENT_VAR, NULL, 0);
00308     if (dNameLength)
00309     {
00310         DWORD envret = 0;
00311         dllName = (char*)malloc(sizeof(char) * (dNameLength + 1));
00312         envret = GetEnvironmentVariableA(NEW_DLL_ENVIRONMENT_VAR, 
00313                                          dllName, dNameLength);
00314         if (envret)
00315         {
00316             /* Try to load the dll from the PATH... */
00317             m_libHandle = LoadLibraryExA(dllName, 
00318                                          NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
00319         }
00320         free(dllName);
00321     } else {
00322         /* Try to use old VS_PROFILER variable */
00323         dNameLength = GetEnvironmentVariableA(DLL_ENVIRONMENT_VAR, NULL, 0);
00324         if (dNameLength)
00325         {
00326             DWORD envret = 0;
00327             dllName = (char*)malloc(sizeof(char) * (dNameLength + 1));
00328             envret = GetEnvironmentVariableA(DLL_ENVIRONMENT_VAR, 
00329                                              dllName, dNameLength);
00330             if (envret)
00331             {
00332                 /* Try to load the dll from the PATH... */
00333                 m_libHandle = LoadLibraryA(dllName);
00334             }
00335             free(dllName);
00336         }
00337     }
00338 #else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
00339     dllName = getenv(NEW_DLL_ENVIRONMENT_VAR);
00340     if (!dllName)
00341         dllName = getenv(DLL_ENVIRONMENT_VAR);
00342 #ifdef ANDROID
00343     if (!dllName)
00344         dllName = ANDROID_JIT_AGENT_PATH;
00345 #endif
00346     if (dllName)
00347     {
00348         /* Try to load the dll from the PATH... */
00349         m_libHandle = dlopen(dllName, RTLD_LAZY);
00350     }
00351 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
00352 
00353     if (!m_libHandle)
00354     {
00355 #if ITT_PLATFORM==ITT_PLATFORM_WIN
00356         m_libHandle = LoadLibraryA(DEFAULT_DLLNAME);
00357 #else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
00358         m_libHandle = dlopen(DEFAULT_DLLNAME, RTLD_LAZY);
00359 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
00360     }
00361 
00362     /* if the dll wasn't loaded - exit. */
00363     if (!m_libHandle)
00364     {
00365         iJIT_DLL_is_missing = 1; /* don't try to initialize 
00366                                   * JIT agent the second time 
00367                                   */
00368         return 0;
00369     }
00370 
00371 #if ITT_PLATFORM==ITT_PLATFORM_WIN
00372     FUNC_NotifyEvent = (TPNotify)GetProcAddress(m_libHandle, "NotifyEvent");
00373 #else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
00374     FUNC_NotifyEvent = (TPNotify)dlsym(m_libHandle, "NotifyEvent");
00375 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
00376     if (!FUNC_NotifyEvent) 
00377     {
00378         FUNC_Initialize = NULL;
00379         return 0;
00380     }
00381 
00382 #if ITT_PLATFORM==ITT_PLATFORM_WIN
00383     FUNC_Initialize = (TPInitialize)GetProcAddress(m_libHandle, "Initialize");
00384 #else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
00385     FUNC_Initialize = (TPInitialize)dlsym(m_libHandle, "Initialize");
00386 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
00387     if (!FUNC_Initialize) 
00388     {
00389         FUNC_NotifyEvent = NULL;
00390         return 0;
00391     }
00392 
00393     executionMode = (iJIT_IsProfilingActiveFlags)FUNC_Initialize();
00394 
00395     bDllWasLoaded = 1;
00396     iJIT_DLL_is_missing = 0; /* DLL is ok. */
00397 
00398     /*
00399      * Call Graph mode: init the thread local storage
00400      * (need to store the virtual stack there).
00401      */
00402     if ( executionMode == iJIT_CALLGRAPH_ON )
00403     {
00404         /* Allocate a thread local storage slot for the thread "stack" */
00405         if (!threadLocalStorageHandle)
00406 #if ITT_PLATFORM==ITT_PLATFORM_WIN
00407             threadLocalStorageHandle = TlsAlloc();
00408 #else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
00409         pthread_key_create(&threadLocalStorageHandle, NULL);
00410 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
00411     }
00412 
00413     return 1;
00414 }
00415 
00416 /*
00417  * This function should be called by the user whenever a thread ends, 
00418  * to free the thread "virtual stack" storage
00419  */
00420 ITT_EXTERN_C void JITAPI FinalizeThread()
00421 {
00422     if (threadLocalStorageHandle)
00423     {
00424 #if ITT_PLATFORM==ITT_PLATFORM_WIN
00425         pThreadStack threadStack = 
00426             (pThreadStack)TlsGetValue (threadLocalStorageHandle);
00427 #else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
00428         pThreadStack threadStack = 
00429             (pThreadStack)pthread_getspecific(threadLocalStorageHandle);
00430 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
00431         if (threadStack)
00432         {
00433             free (threadStack);
00434             threadStack = NULL;
00435 #if ITT_PLATFORM==ITT_PLATFORM_WIN
00436             TlsSetValue (threadLocalStorageHandle, threadStack);
00437 #else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
00438             pthread_setspecific(threadLocalStorageHandle, threadStack);
00439 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
00440         }
00441     }
00442 }
00443 
00444 /*
00445  * This function should be called by the user when the process ends, 
00446  * to free the local storage index
00447 */
00448 ITT_EXTERN_C void JITAPI FinalizeProcess()
00449 {
00450     if (m_libHandle) 
00451     {
00452 #if ITT_PLATFORM==ITT_PLATFORM_WIN
00453         FreeLibrary(m_libHandle);
00454 #else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
00455         dlclose(m_libHandle);
00456 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
00457         m_libHandle = NULL;
00458     }
00459 
00460     if (threadLocalStorageHandle)
00461 #if ITT_PLATFORM==ITT_PLATFORM_WIN
00462         TlsFree (threadLocalStorageHandle);
00463 #else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
00464     pthread_key_delete(threadLocalStorageHandle);
00465 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
00466 }
00467 
00468 /*
00469  * This function should be called by the user for any method once.
00470  * The function will return a unique method ID, the user should maintain 
00471  * the ID for each method
00472  */
00473 ITT_EXTERN_C unsigned int JITAPI iJIT_GetNewMethodID()
00474 {
00475     static unsigned int methodID = 0x100000;
00476 
00477     if (methodID == 0)
00478         return 0;  /* ERROR : this is not a valid value */
00479 
00480     return methodID++;
00481 }