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