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-exception 6 * 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 LLVM 13 * source base since this is a piece of code shared from Intel(R) 14 * products. Please do not reformat / re-style this code to make 15 * subsequent merges and contributions from the original source base eaiser. 16 * 17 *===----------------------------------------------------------------------===*/ 18#include "ittnotify_config.h" 19 20#if ITT_PLATFORM==ITT_PLATFORM_WIN 21#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_VAR 37#if ITT_ARCH==ITT_ARCH_IA32 38#define NEW_DLL_ENVIRONMENT_VAR "INTEL_JIT_PROFILER32" 39#else 40#define NEW_DLL_ENVIRONMENT_VAR "INTEL_JIT_PROFILER64" 41#endif 42#endif /* NEW_DLL_ENVIRONMENT_VAR */ 43 44#if ITT_PLATFORM==ITT_PLATFORM_WIN 45#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.dll 68 * result: 69 * on success: the functions loads, iJIT_DLL_is_missing=0, return value = 1 70 * on failure: the functions are NULL, iJIT_DLL_is_missing=1, return value = 0 71 */ 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_WIN 86static 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 10000 92 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 part 134 * 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 it 151 */ 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_WIN 165 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_WIN 183 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 occurs 195 * 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_WIN 203 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 running 260 */ 261ITT_EXTERN_C iJIT_IsProfilingActiveFlags JITAPI iJIT_IsProfilingActive() 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 = 1 274 * on failure: all functions are NULL, iJIT_DLL_is_missing = 1, return value = 0 275 */ 276static int loadiJIT_Funcs() 277{ 278 static int bDllWasLoaded = 0; 279 char *dllName = (char*)rcsid; /* !! Just to avoid unused code elimination */ 280#if ITT_PLATFORM==ITT_PLATFORM_WIN 281 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_WIN 297 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_WIN 306 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 ANDROID 342 if (!dllName) 343 dllName = ANDROID_JIT_AGENT_PATH; 344#endif 345 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_WIN 355 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_WIN 371 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_WIN 382 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 storage 399 * (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_WIN 406 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" storage 418 */ 419ITT_EXTERN_C void JITAPI FinalizeThread() 420{ 421 if (threadLocalStorageHandle) 422 { 423#if ITT_PLATFORM==ITT_PLATFORM_WIN 424 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_WIN 435 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 index 446*/ 447ITT_EXTERN_C void JITAPI FinalizeProcess() 448{ 449 if (m_libHandle) 450 { 451#if ITT_PLATFORM==ITT_PLATFORM_WIN 452 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_WIN 461 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 method 471 */ 472ITT_EXTERN_C unsigned int JITAPI iJIT_GetNewMethodID() 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