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 34static 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" 48HINSTANCE m_libHandle = NULL; 49#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 50#define DEFAULT_DLLNAME "libJitPI.so" 51void* 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 */ 58typedef unsigned int(*TPInitialize)(void); 59static TPInitialize FUNC_Initialize=NULL; 60 61typedef unsigned int(*TPNotify)(unsigned int, void*); 62static TPNotify FUNC_NotifyEvent=NULL; 63 64static 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 */ 74static int loadiJIT_Funcs(void); 75 76/* global representing whether the BistroJavaCollector can't be loaded */ 77static 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 88static DWORD threadLocalStorageHandle = 0; 89#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 90static pthread_key_t threadLocalStorageHandle = (pthread_key_t)0; 91#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 92 93#define INIT_TOP_Stack 10000 94 95typedef 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 113ITT_EXTERN_C int JITAPI 114iJIT_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 */ 244ITT_EXTERN_C void JITAPI 245iJIT_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 */ 263ITT_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 */ 278static 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 */ 421ITT_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*/ 449ITT_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 */ 474ITT_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