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