|  | /*===-- jitprofiling.c - JIT (Just-In-Time) Profiling API----------*- C -*-===* | 
|  | * | 
|  | *                     The LLVM Compiler Infrastructure | 
|  | * | 
|  | * This file is distributed under the University of Illinois Open Source | 
|  | * License. See LICENSE.TXT for details. | 
|  | * | 
|  | *===----------------------------------------------------------------------===* | 
|  | * | 
|  | * This file provides Intel(R) Performance Analyzer JIT (Just-In-Time) | 
|  | * Profiling API implementation. | 
|  | * | 
|  | * NOTE: This file comes in a style different from the rest of LLVM | 
|  | * source base since  this is a piece of code shared from Intel(R) | 
|  | * products.  Please do not reformat / re-style this code to make | 
|  | * subsequent merges and contributions from the original source base eaiser. | 
|  | * | 
|  | *===----------------------------------------------------------------------===*/ | 
|  | #include "ittnotify_config.h" | 
|  |  | 
|  | #if ITT_PLATFORM==ITT_PLATFORM_WIN | 
|  | #include <windows.h> | 
|  | #pragma optimize("", off) | 
|  | #else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */ | 
|  | #include <dlfcn.h> | 
|  | #include <pthread.h> | 
|  | #include <stdint.h> | 
|  | #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ | 
|  | #include <stdlib.h> | 
|  |  | 
|  | #include "jitprofiling.h" | 
|  |  | 
|  | static const char rcsid[] = "\n@(#) $Revision: 243501 $\n"; | 
|  |  | 
|  | #define DLL_ENVIRONMENT_VAR             "VS_PROFILER" | 
|  |  | 
|  | #ifndef NEW_DLL_ENVIRONMENT_VAR | 
|  | #if ITT_ARCH==ITT_ARCH_IA32 | 
|  | #define NEW_DLL_ENVIRONMENT_VAR	        "INTEL_JIT_PROFILER32" | 
|  | #else | 
|  | #define NEW_DLL_ENVIRONMENT_VAR	        "INTEL_JIT_PROFILER64" | 
|  | #endif | 
|  | #endif /* NEW_DLL_ENVIRONMENT_VAR */ | 
|  |  | 
|  | #if ITT_PLATFORM==ITT_PLATFORM_WIN | 
|  | #define DEFAULT_DLLNAME                 "JitPI.dll" | 
|  | HINSTANCE m_libHandle = NULL; | 
|  | #else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */ | 
|  | #define DEFAULT_DLLNAME                 "libJitPI.so" | 
|  | void* m_libHandle = NULL; | 
|  | #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ | 
|  |  | 
|  | /* default location of JIT profiling agent on Android */ | 
|  | #define ANDROID_JIT_AGENT_PATH  "/data/intel/libittnotify.so" | 
|  |  | 
|  | /* the function pointers */ | 
|  | typedef unsigned int(*TPInitialize)(void); | 
|  | static TPInitialize FUNC_Initialize=NULL; | 
|  |  | 
|  | typedef unsigned int(*TPNotify)(unsigned int, void*); | 
|  | static TPNotify FUNC_NotifyEvent=NULL; | 
|  |  | 
|  | static iJIT_IsProfilingActiveFlags executionMode = iJIT_NOTHING_RUNNING; | 
|  |  | 
|  | /* end collector dll part. */ | 
|  |  | 
|  | /* loadiJIT_Funcs() : this function is called just in the beginning | 
|  | *  and is responsible to load the functions from BistroJavaCollector.dll | 
|  | * result: | 
|  | *  on success: the functions loads, iJIT_DLL_is_missing=0, return value = 1 | 
|  | *  on failure: the functions are NULL, iJIT_DLL_is_missing=1, return value = 0 | 
|  | */ | 
|  | static int loadiJIT_Funcs(void); | 
|  |  | 
|  | /* global representing whether the BistroJavaCollector can't be loaded */ | 
|  | static int iJIT_DLL_is_missing = 0; | 
|  |  | 
|  | /* Virtual stack - the struct is used as a virtual stack for each thread. | 
|  | * Every thread initializes with a stack of size INIT_TOP_STACK. | 
|  | * Every method entry decreases from the current stack point, | 
|  | * and when a thread stack reaches its top of stack (return from the global | 
|  | * function), the top of stack and the current stack increase. Notice that | 
|  | * when returning from a function the stack pointer is the address of | 
|  | * the function return. | 
|  | */ | 
|  | #if ITT_PLATFORM==ITT_PLATFORM_WIN | 
|  | static DWORD threadLocalStorageHandle = 0; | 
|  | #else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */ | 
|  | static pthread_key_t threadLocalStorageHandle = (pthread_key_t)0; | 
|  | #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ | 
|  |  | 
|  | #define INIT_TOP_Stack 10000 | 
|  |  | 
|  | typedef struct | 
|  | { | 
|  | unsigned int TopStack; | 
|  | unsigned int CurrentStack; | 
|  | } ThreadStack, *pThreadStack; | 
|  |  | 
|  | /* end of virtual stack. */ | 
|  |  | 
|  | /* | 
|  | * The function for reporting virtual-machine related events to VTune. | 
|  | * Note: when reporting iJVM_EVENT_TYPE_ENTER_NIDS, there is no need to fill | 
|  | * in the stack_id field in the iJIT_Method_NIDS structure, as VTune fills it. | 
|  | * The return value in iJVM_EVENT_TYPE_ENTER_NIDS && | 
|  | * iJVM_EVENT_TYPE_LEAVE_NIDS events will be 0 in case of failure. | 
|  | * in iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED event | 
|  | * it will be -1 if EventSpecificData == 0 otherwise it will be 0. | 
|  | */ | 
|  |  | 
|  | ITT_EXTERN_C int JITAPI | 
|  | iJIT_NotifyEvent(iJIT_JVM_EVENT event_type, void *EventSpecificData) | 
|  | { | 
|  | int ReturnValue; | 
|  |  | 
|  | /* | 
|  | * This section is for debugging outside of VTune. | 
|  | * It creates the environment variables that indicates call graph mode. | 
|  | * If running outside of VTune remove the remark. | 
|  | * | 
|  | * | 
|  | * static int firstTime = 1; | 
|  | * char DoCallGraph[12] = "DoCallGraph"; | 
|  | * if (firstTime) | 
|  | * { | 
|  | * firstTime = 0; | 
|  | * SetEnvironmentVariable( "BISTRO_COLLECTORS_DO_CALLGRAPH", DoCallGraph); | 
|  | * } | 
|  | * | 
|  | * end of section. | 
|  | */ | 
|  |  | 
|  | /* initialization part - the functions have not been loaded yet. This part | 
|  | *        will load the functions, and check if we are in Call Graph mode. | 
|  | *        (for special treatment). | 
|  | */ | 
|  | if (!FUNC_NotifyEvent) | 
|  | { | 
|  | if (iJIT_DLL_is_missing) | 
|  | return 0; | 
|  |  | 
|  | /* load the Function from the DLL */ | 
|  | if (!loadiJIT_Funcs()) | 
|  | return 0; | 
|  |  | 
|  | /* Call Graph initialization. */ | 
|  | } | 
|  |  | 
|  | /* If the event is method entry/exit, check that in the current mode | 
|  | * VTune is allowed to receive it | 
|  | */ | 
|  | if ((event_type == iJVM_EVENT_TYPE_ENTER_NIDS || | 
|  | event_type == iJVM_EVENT_TYPE_LEAVE_NIDS) && | 
|  | (executionMode != iJIT_CALLGRAPH_ON)) | 
|  | { | 
|  | return 0; | 
|  | } | 
|  | /* This section is performed when method enter event occurs. | 
|  | * It updates the virtual stack, or creates it if this is the first | 
|  | * method entry in the thread. The stack pointer is decreased. | 
|  | */ | 
|  | if (event_type == iJVM_EVENT_TYPE_ENTER_NIDS) | 
|  | { | 
|  | #if ITT_PLATFORM==ITT_PLATFORM_WIN | 
|  | pThreadStack threadStack = | 
|  | (pThreadStack)TlsGetValue (threadLocalStorageHandle); | 
|  | #else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */ | 
|  | pThreadStack threadStack = | 
|  | (pThreadStack)pthread_getspecific(threadLocalStorageHandle); | 
|  | #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ | 
|  |  | 
|  | /* check for use of reserved method IDs */ | 
|  | if ( ((piJIT_Method_NIDS) EventSpecificData)->method_id <= 999 ) | 
|  | return 0; | 
|  |  | 
|  | if (!threadStack) | 
|  | { | 
|  | /* initialize the stack. */ | 
|  | threadStack = (pThreadStack) calloc (sizeof(ThreadStack), 1); | 
|  | threadStack->TopStack = INIT_TOP_Stack; | 
|  | threadStack->CurrentStack = INIT_TOP_Stack; | 
|  | #if ITT_PLATFORM==ITT_PLATFORM_WIN | 
|  | TlsSetValue(threadLocalStorageHandle,(void*)threadStack); | 
|  | #else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */ | 
|  | pthread_setspecific(threadLocalStorageHandle,(void*)threadStack); | 
|  | #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ | 
|  | } | 
|  |  | 
|  | /* decrease the stack. */ | 
|  | ((piJIT_Method_NIDS) EventSpecificData)->stack_id = | 
|  | (threadStack->CurrentStack)--; | 
|  | } | 
|  |  | 
|  | /* This section is performed when method leave event occurs | 
|  | * It updates the virtual stack. | 
|  | *    Increases the stack pointer. | 
|  | *    If the stack pointer reached the top (left the global function) | 
|  | *        increase the pointer and the top pointer. | 
|  | */ | 
|  | if (event_type == iJVM_EVENT_TYPE_LEAVE_NIDS) | 
|  | { | 
|  | #if ITT_PLATFORM==ITT_PLATFORM_WIN | 
|  | pThreadStack threadStack = | 
|  | (pThreadStack)TlsGetValue (threadLocalStorageHandle); | 
|  | #else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */ | 
|  | pThreadStack threadStack = | 
|  | (pThreadStack)pthread_getspecific(threadLocalStorageHandle); | 
|  | #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ | 
|  |  | 
|  | /* check for use of reserved method IDs */ | 
|  | if ( ((piJIT_Method_NIDS) EventSpecificData)->method_id <= 999 ) | 
|  | return 0; | 
|  |  | 
|  | if (!threadStack) | 
|  | { | 
|  | /* Error: first report in this thread is method exit */ | 
|  | exit (1); | 
|  | } | 
|  |  | 
|  | ((piJIT_Method_NIDS) EventSpecificData)->stack_id = | 
|  | ++(threadStack->CurrentStack) + 1; | 
|  |  | 
|  | if (((piJIT_Method_NIDS) EventSpecificData)->stack_id | 
|  | > threadStack->TopStack) | 
|  | ((piJIT_Method_NIDS) EventSpecificData)->stack_id = | 
|  | (unsigned int)-1; | 
|  | } | 
|  |  | 
|  | if (event_type == iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED) | 
|  | { | 
|  | /* check for use of reserved method IDs */ | 
|  | if ( ((piJIT_Method_Load) EventSpecificData)->method_id <= 999 ) | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | ReturnValue = (int)FUNC_NotifyEvent(event_type, EventSpecificData); | 
|  |  | 
|  | return ReturnValue; | 
|  | } | 
|  |  | 
|  | /* The new mode call back routine */ | 
|  | ITT_EXTERN_C void JITAPI | 
|  | iJIT_RegisterCallbackEx(void *userdata, iJIT_ModeChangedEx | 
|  | NewModeCallBackFuncEx) | 
|  | { | 
|  | /* is it already missing... or the load of functions from the DLL failed */ | 
|  | if (iJIT_DLL_is_missing || !loadiJIT_Funcs()) | 
|  | { | 
|  | /* then do not bother with notifications */ | 
|  | NewModeCallBackFuncEx(userdata, iJIT_NO_NOTIFICATIONS); | 
|  | /* Error: could not load JIT functions. */ | 
|  | return; | 
|  | } | 
|  | /* nothing to do with the callback */ | 
|  | } | 
|  |  | 
|  | /* | 
|  | * This function allows the user to query in which mode, if at all, | 
|  | *VTune is running | 
|  | */ | 
|  | ITT_EXTERN_C iJIT_IsProfilingActiveFlags JITAPI iJIT_IsProfilingActive() | 
|  | { | 
|  | if (!iJIT_DLL_is_missing) | 
|  | { | 
|  | loadiJIT_Funcs(); | 
|  | } | 
|  |  | 
|  | return executionMode; | 
|  | } | 
|  |  | 
|  | /* this function loads the collector dll (BistroJavaCollector) | 
|  | * and the relevant functions. | 
|  | * on success: all functions load,     iJIT_DLL_is_missing = 0, return value = 1 | 
|  | * on failure: all functions are NULL, iJIT_DLL_is_missing = 1, return value = 0 | 
|  | */ | 
|  | static int loadiJIT_Funcs() | 
|  | { | 
|  | static int bDllWasLoaded = 0; | 
|  | char *dllName = (char*)rcsid; /* !! Just to avoid unused code elimination */ | 
|  | #if ITT_PLATFORM==ITT_PLATFORM_WIN | 
|  | DWORD dNameLength = 0; | 
|  | #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ | 
|  |  | 
|  | if(bDllWasLoaded) | 
|  | { | 
|  | /* dll was already loaded, no need to do it for the second time */ | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | /* Assumes that the DLL will not be found */ | 
|  | iJIT_DLL_is_missing = 1; | 
|  | FUNC_NotifyEvent = NULL; | 
|  |  | 
|  | if (m_libHandle) | 
|  | { | 
|  | #if ITT_PLATFORM==ITT_PLATFORM_WIN | 
|  | FreeLibrary(m_libHandle); | 
|  | #else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */ | 
|  | dlclose(m_libHandle); | 
|  | #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ | 
|  | m_libHandle = NULL; | 
|  | } | 
|  |  | 
|  | /* Try to get the dll name from the environment */ | 
|  | #if ITT_PLATFORM==ITT_PLATFORM_WIN | 
|  | dNameLength = GetEnvironmentVariableA(NEW_DLL_ENVIRONMENT_VAR, NULL, 0); | 
|  | if (dNameLength) | 
|  | { | 
|  | DWORD envret = 0; | 
|  | dllName = (char*)malloc(sizeof(char) * (dNameLength + 1)); | 
|  | envret = GetEnvironmentVariableA(NEW_DLL_ENVIRONMENT_VAR, | 
|  | dllName, dNameLength); | 
|  | if (envret) | 
|  | { | 
|  | /* Try to load the dll from the PATH... */ | 
|  | m_libHandle = LoadLibraryExA(dllName, | 
|  | NULL, LOAD_WITH_ALTERED_SEARCH_PATH); | 
|  | } | 
|  | free(dllName); | 
|  | } else { | 
|  | /* Try to use old VS_PROFILER variable */ | 
|  | dNameLength = GetEnvironmentVariableA(DLL_ENVIRONMENT_VAR, NULL, 0); | 
|  | if (dNameLength) | 
|  | { | 
|  | DWORD envret = 0; | 
|  | dllName = (char*)malloc(sizeof(char) * (dNameLength + 1)); | 
|  | envret = GetEnvironmentVariableA(DLL_ENVIRONMENT_VAR, | 
|  | dllName, dNameLength); | 
|  | if (envret) | 
|  | { | 
|  | /* Try to load the dll from the PATH... */ | 
|  | m_libHandle = LoadLibraryA(dllName); | 
|  | } | 
|  | free(dllName); | 
|  | } | 
|  | } | 
|  | #else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */ | 
|  | dllName = getenv(NEW_DLL_ENVIRONMENT_VAR); | 
|  | if (!dllName) | 
|  | dllName = getenv(DLL_ENVIRONMENT_VAR); | 
|  | #ifdef ANDROID | 
|  | if (!dllName) | 
|  | dllName = ANDROID_JIT_AGENT_PATH; | 
|  | #endif | 
|  | if (dllName) | 
|  | { | 
|  | /* Try to load the dll from the PATH... */ | 
|  | m_libHandle = dlopen(dllName, RTLD_LAZY); | 
|  | } | 
|  | #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ | 
|  |  | 
|  | if (!m_libHandle) | 
|  | { | 
|  | #if ITT_PLATFORM==ITT_PLATFORM_WIN | 
|  | m_libHandle = LoadLibraryA(DEFAULT_DLLNAME); | 
|  | #else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */ | 
|  | m_libHandle = dlopen(DEFAULT_DLLNAME, RTLD_LAZY); | 
|  | #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ | 
|  | } | 
|  |  | 
|  | /* if the dll wasn't loaded - exit. */ | 
|  | if (!m_libHandle) | 
|  | { | 
|  | iJIT_DLL_is_missing = 1; /* don't try to initialize | 
|  | * JIT agent the second time | 
|  | */ | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | #if ITT_PLATFORM==ITT_PLATFORM_WIN | 
|  | FUNC_NotifyEvent = (TPNotify)GetProcAddress(m_libHandle, "NotifyEvent"); | 
|  | #else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */ | 
|  | FUNC_NotifyEvent = (TPNotify)(intptr_t)dlsym(m_libHandle, "NotifyEvent"); | 
|  | #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ | 
|  | if (!FUNC_NotifyEvent) | 
|  | { | 
|  | FUNC_Initialize = NULL; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | #if ITT_PLATFORM==ITT_PLATFORM_WIN | 
|  | FUNC_Initialize = (TPInitialize)GetProcAddress(m_libHandle, "Initialize"); | 
|  | #else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */ | 
|  | FUNC_Initialize = (TPInitialize)(intptr_t)dlsym(m_libHandle, "Initialize"); | 
|  | #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ | 
|  | if (!FUNC_Initialize) | 
|  | { | 
|  | FUNC_NotifyEvent = NULL; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | executionMode = (iJIT_IsProfilingActiveFlags)FUNC_Initialize(); | 
|  |  | 
|  | bDllWasLoaded = 1; | 
|  | iJIT_DLL_is_missing = 0; /* DLL is ok. */ | 
|  |  | 
|  | /* | 
|  | * Call Graph mode: init the thread local storage | 
|  | * (need to store the virtual stack there). | 
|  | */ | 
|  | if ( executionMode == iJIT_CALLGRAPH_ON ) | 
|  | { | 
|  | /* Allocate a thread local storage slot for the thread "stack" */ | 
|  | if (!threadLocalStorageHandle) | 
|  | #if ITT_PLATFORM==ITT_PLATFORM_WIN | 
|  | threadLocalStorageHandle = TlsAlloc(); | 
|  | #else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */ | 
|  | pthread_key_create(&threadLocalStorageHandle, NULL); | 
|  | #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ | 
|  | } | 
|  |  | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * This function should be called by the user whenever a thread ends, | 
|  | * to free the thread "virtual stack" storage | 
|  | */ | 
|  | ITT_EXTERN_C void JITAPI FinalizeThread() | 
|  | { | 
|  | if (threadLocalStorageHandle) | 
|  | { | 
|  | #if ITT_PLATFORM==ITT_PLATFORM_WIN | 
|  | pThreadStack threadStack = | 
|  | (pThreadStack)TlsGetValue (threadLocalStorageHandle); | 
|  | #else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */ | 
|  | pThreadStack threadStack = | 
|  | (pThreadStack)pthread_getspecific(threadLocalStorageHandle); | 
|  | #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ | 
|  | if (threadStack) | 
|  | { | 
|  | free (threadStack); | 
|  | threadStack = NULL; | 
|  | #if ITT_PLATFORM==ITT_PLATFORM_WIN | 
|  | TlsSetValue (threadLocalStorageHandle, threadStack); | 
|  | #else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */ | 
|  | pthread_setspecific(threadLocalStorageHandle, threadStack); | 
|  | #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /* | 
|  | * This function should be called by the user when the process ends, | 
|  | * to free the local storage index | 
|  | */ | 
|  | ITT_EXTERN_C void JITAPI FinalizeProcess() | 
|  | { | 
|  | if (m_libHandle) | 
|  | { | 
|  | #if ITT_PLATFORM==ITT_PLATFORM_WIN | 
|  | FreeLibrary(m_libHandle); | 
|  | #else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */ | 
|  | dlclose(m_libHandle); | 
|  | #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ | 
|  | m_libHandle = NULL; | 
|  | } | 
|  |  | 
|  | if (threadLocalStorageHandle) | 
|  | #if ITT_PLATFORM==ITT_PLATFORM_WIN | 
|  | TlsFree (threadLocalStorageHandle); | 
|  | #else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */ | 
|  | pthread_key_delete(threadLocalStorageHandle); | 
|  | #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ | 
|  | } | 
|  |  | 
|  | /* | 
|  | * This function should be called by the user for any method once. | 
|  | * The function will return a unique method ID, the user should maintain | 
|  | * the ID for each method | 
|  | */ | 
|  | ITT_EXTERN_C unsigned int JITAPI iJIT_GetNewMethodID() | 
|  | { | 
|  | static unsigned int methodID = 0x100000; | 
|  |  | 
|  | if (methodID == 0) | 
|  | return 0;  /* ERROR : this is not a valid value */ | 
|  |  | 
|  | return methodID++; | 
|  | } |