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