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