LLVM API Documentation
00001 /*===-- jitprofiling.c - JIT (Just-In-Time) Profiling API----------*- C -*-===* 00002 * 00003 * The LLVM Compiler Infrastructure 00004 * 00005 * This file is distributed under the University of Illinois Open Source 00006 * License. See LICENSE.TXT for details. 00007 * 00008 *===----------------------------------------------------------------------===* 00009 * 00010 * This file provides Intel(R) Performance Analyzer JIT (Just-In-Time) 00011 * Profiling API implementation. 00012 * 00013 * NOTE: This file comes in a style different from the rest of LLVM 00014 * source base since this is a piece of code shared from Intel(R) 00015 * products. Please do not reformat / re-style this code to make 00016 * subsequent merges and contributions from the original source base eaiser. 00017 * 00018 *===----------------------------------------------------------------------===*/ 00019 #include "ittnotify_config.h" 00020 00021 #if ITT_PLATFORM==ITT_PLATFORM_WIN 00022 #include <windows.h> 00023 #pragma optimize("", off) 00024 #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 00025 #include <pthread.h> 00026 #include <dlfcn.h> 00027 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 00028 #include <malloc.h> 00029 #include <stdlib.h> 00030 00031 #include "jitprofiling.h" 00032 00033 static const char rcsid[] = "\n@(#) $Revision: 243501 $\n"; 00034 00035 #define DLL_ENVIRONMENT_VAR "VS_PROFILER" 00036 00037 #ifndef NEW_DLL_ENVIRONMENT_VAR 00038 #if ITT_ARCH==ITT_ARCH_IA32 00039 #define NEW_DLL_ENVIRONMENT_VAR "INTEL_JIT_PROFILER32" 00040 #else 00041 #define NEW_DLL_ENVIRONMENT_VAR "INTEL_JIT_PROFILER64" 00042 #endif 00043 #endif /* NEW_DLL_ENVIRONMENT_VAR */ 00044 00045 #if ITT_PLATFORM==ITT_PLATFORM_WIN 00046 #define DEFAULT_DLLNAME "JitPI.dll" 00047 HINSTANCE m_libHandle = NULL; 00048 #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 00049 #define DEFAULT_DLLNAME "libJitPI.so" 00050 void* m_libHandle = NULL; 00051 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 00052 00053 /* default location of JIT profiling agent on Android */ 00054 #define ANDROID_JIT_AGENT_PATH "/data/intel/libittnotify.so" 00055 00056 /* the function pointers */ 00057 typedef unsigned int(*TPInitialize)(void); 00058 static TPInitialize FUNC_Initialize=NULL; 00059 00060 typedef unsigned int(*TPNotify)(unsigned int, void*); 00061 static TPNotify FUNC_NotifyEvent=NULL; 00062 00063 static iJIT_IsProfilingActiveFlags executionMode = iJIT_NOTHING_RUNNING; 00064 00065 /* end collector dll part. */ 00066 00067 /* loadiJIT_Funcs() : this function is called just in the beginning 00068 * and is responsible to load the functions from BistroJavaCollector.dll 00069 * result: 00070 * on success: the functions loads, iJIT_DLL_is_missing=0, return value = 1 00071 * on failure: the functions are NULL, iJIT_DLL_is_missing=1, return value = 0 00072 */ 00073 static int loadiJIT_Funcs(void); 00074 00075 /* global representing whether the BistroJavaCollector can't be loaded */ 00076 static int iJIT_DLL_is_missing = 0; 00077 00078 /* Virtual stack - the struct is used as a virtual stack for each thread. 00079 * Every thread initializes with a stack of size INIT_TOP_STACK. 00080 * Every method entry decreases from the current stack point, 00081 * and when a thread stack reaches its top of stack (return from the global 00082 * function), the top of stack and the current stack increase. Notice that 00083 * when returning from a function the stack pointer is the address of 00084 * the function return. 00085 */ 00086 #if ITT_PLATFORM==ITT_PLATFORM_WIN 00087 static DWORD threadLocalStorageHandle = 0; 00088 #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 00089 static pthread_key_t threadLocalStorageHandle = (pthread_key_t)0; 00090 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 00091 00092 #define INIT_TOP_Stack 10000 00093 00094 typedef struct 00095 { 00096 unsigned int TopStack; 00097 unsigned int CurrentStack; 00098 } ThreadStack, *pThreadStack; 00099 00100 /* end of virtual stack. */ 00101 00102 /* 00103 * The function for reporting virtual-machine related events to VTune. 00104 * Note: when reporting iJVM_EVENT_TYPE_ENTER_NIDS, there is no need to fill 00105 * in the stack_id field in the iJIT_Method_NIDS structure, as VTune fills it. 00106 * The return value in iJVM_EVENT_TYPE_ENTER_NIDS && 00107 * iJVM_EVENT_TYPE_LEAVE_NIDS events will be 0 in case of failure. 00108 * in iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED event 00109 * it will be -1 if EventSpecificData == 0 otherwise it will be 0. 00110 */ 00111 00112 ITT_EXTERN_C int JITAPI 00113 iJIT_NotifyEvent(iJIT_JVM_EVENT event_type, void *EventSpecificData) 00114 { 00115 int ReturnValue; 00116 00117 /* 00118 * This section is for debugging outside of VTune. 00119 * It creates the environment variables that indicates call graph mode. 00120 * If running outside of VTune remove the remark. 00121 * 00122 * 00123 * static int firstTime = 1; 00124 * char DoCallGraph[12] = "DoCallGraph"; 00125 * if (firstTime) 00126 * { 00127 * firstTime = 0; 00128 * SetEnvironmentVariable( "BISTRO_COLLECTORS_DO_CALLGRAPH", DoCallGraph); 00129 * } 00130 * 00131 * end of section. 00132 */ 00133 00134 /* initialization part - the functions have not been loaded yet. This part 00135 * will load the functions, and check if we are in Call Graph mode. 00136 * (for special treatment). 00137 */ 00138 if (!FUNC_NotifyEvent) 00139 { 00140 if (iJIT_DLL_is_missing) 00141 return 0; 00142 00143 /* load the Function from the DLL */ 00144 if (!loadiJIT_Funcs()) 00145 return 0; 00146 00147 /* Call Graph initialization. */ 00148 } 00149 00150 /* If the event is method entry/exit, check that in the current mode 00151 * VTune is allowed to receive it 00152 */ 00153 if ((event_type == iJVM_EVENT_TYPE_ENTER_NIDS || 00154 event_type == iJVM_EVENT_TYPE_LEAVE_NIDS) && 00155 (executionMode != iJIT_CALLGRAPH_ON)) 00156 { 00157 return 0; 00158 } 00159 /* This section is performed when method enter event occurs. 00160 * It updates the virtual stack, or creates it if this is the first 00161 * method entry in the thread. The stack pointer is decreased. 00162 */ 00163 if (event_type == iJVM_EVENT_TYPE_ENTER_NIDS) 00164 { 00165 #if ITT_PLATFORM==ITT_PLATFORM_WIN 00166 pThreadStack threadStack = 00167 (pThreadStack)TlsGetValue (threadLocalStorageHandle); 00168 #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 00169 pThreadStack threadStack = 00170 (pThreadStack)pthread_getspecific(threadLocalStorageHandle); 00171 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 00172 00173 /* check for use of reserved method IDs */ 00174 if ( ((piJIT_Method_NIDS) EventSpecificData)->method_id <= 999 ) 00175 return 0; 00176 00177 if (!threadStack) 00178 { 00179 /* initialize the stack. */ 00180 threadStack = (pThreadStack) calloc (sizeof(ThreadStack), 1); 00181 threadStack->TopStack = INIT_TOP_Stack; 00182 threadStack->CurrentStack = INIT_TOP_Stack; 00183 #if ITT_PLATFORM==ITT_PLATFORM_WIN 00184 TlsSetValue(threadLocalStorageHandle,(void*)threadStack); 00185 #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 00186 pthread_setspecific(threadLocalStorageHandle,(void*)threadStack); 00187 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 00188 } 00189 00190 /* decrease the stack. */ 00191 ((piJIT_Method_NIDS) EventSpecificData)->stack_id = 00192 (threadStack->CurrentStack)--; 00193 } 00194 00195 /* This section is performed when method leave event occurs 00196 * It updates the virtual stack. 00197 * Increases the stack pointer. 00198 * If the stack pointer reached the top (left the global function) 00199 * increase the pointer and the top pointer. 00200 */ 00201 if (event_type == iJVM_EVENT_TYPE_LEAVE_NIDS) 00202 { 00203 #if ITT_PLATFORM==ITT_PLATFORM_WIN 00204 pThreadStack threadStack = 00205 (pThreadStack)TlsGetValue (threadLocalStorageHandle); 00206 #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 00207 pThreadStack threadStack = 00208 (pThreadStack)pthread_getspecific(threadLocalStorageHandle); 00209 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 00210 00211 /* check for use of reserved method IDs */ 00212 if ( ((piJIT_Method_NIDS) EventSpecificData)->method_id <= 999 ) 00213 return 0; 00214 00215 if (!threadStack) 00216 { 00217 /* Error: first report in this thread is method exit */ 00218 exit (1); 00219 } 00220 00221 ((piJIT_Method_NIDS) EventSpecificData)->stack_id = 00222 ++(threadStack->CurrentStack) + 1; 00223 00224 if (((piJIT_Method_NIDS) EventSpecificData)->stack_id 00225 > threadStack->TopStack) 00226 ((piJIT_Method_NIDS) EventSpecificData)->stack_id = 00227 (unsigned int)-1; 00228 } 00229 00230 if (event_type == iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED) 00231 { 00232 /* check for use of reserved method IDs */ 00233 if ( ((piJIT_Method_Load) EventSpecificData)->method_id <= 999 ) 00234 return 0; 00235 } 00236 00237 ReturnValue = (int)FUNC_NotifyEvent(event_type, EventSpecificData); 00238 00239 return ReturnValue; 00240 } 00241 00242 /* The new mode call back routine */ 00243 ITT_EXTERN_C void JITAPI 00244 iJIT_RegisterCallbackEx(void *userdata, iJIT_ModeChangedEx 00245 NewModeCallBackFuncEx) 00246 { 00247 /* is it already missing... or the load of functions from the DLL failed */ 00248 if (iJIT_DLL_is_missing || !loadiJIT_Funcs()) 00249 { 00250 /* then do not bother with notifications */ 00251 NewModeCallBackFuncEx(userdata, iJIT_NO_NOTIFICATIONS); 00252 /* Error: could not load JIT functions. */ 00253 return; 00254 } 00255 /* nothing to do with the callback */ 00256 } 00257 00258 /* 00259 * This function allows the user to query in which mode, if at all, 00260 *VTune is running 00261 */ 00262 ITT_EXTERN_C iJIT_IsProfilingActiveFlags JITAPI iJIT_IsProfilingActive() 00263 { 00264 if (!iJIT_DLL_is_missing) 00265 { 00266 loadiJIT_Funcs(); 00267 } 00268 00269 return executionMode; 00270 } 00271 00272 /* this function loads the collector dll (BistroJavaCollector) 00273 * and the relevant functions. 00274 * on success: all functions load, iJIT_DLL_is_missing = 0, return value = 1 00275 * on failure: all functions are NULL, iJIT_DLL_is_missing = 1, return value = 0 00276 */ 00277 static int loadiJIT_Funcs() 00278 { 00279 static int bDllWasLoaded = 0; 00280 char *dllName = (char*)rcsid; /* !! Just to avoid unused code elimination */ 00281 #if ITT_PLATFORM==ITT_PLATFORM_WIN 00282 DWORD dNameLength = 0; 00283 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 00284 00285 if(bDllWasLoaded) 00286 { 00287 /* dll was already loaded, no need to do it for the second time */ 00288 return 1; 00289 } 00290 00291 /* Assumes that the DLL will not be found */ 00292 iJIT_DLL_is_missing = 1; 00293 FUNC_NotifyEvent = NULL; 00294 00295 if (m_libHandle) 00296 { 00297 #if ITT_PLATFORM==ITT_PLATFORM_WIN 00298 FreeLibrary(m_libHandle); 00299 #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 00300 dlclose(m_libHandle); 00301 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 00302 m_libHandle = NULL; 00303 } 00304 00305 /* Try to get the dll name from the environment */ 00306 #if ITT_PLATFORM==ITT_PLATFORM_WIN 00307 dNameLength = GetEnvironmentVariableA(NEW_DLL_ENVIRONMENT_VAR, NULL, 0); 00308 if (dNameLength) 00309 { 00310 DWORD envret = 0; 00311 dllName = (char*)malloc(sizeof(char) * (dNameLength + 1)); 00312 envret = GetEnvironmentVariableA(NEW_DLL_ENVIRONMENT_VAR, 00313 dllName, dNameLength); 00314 if (envret) 00315 { 00316 /* Try to load the dll from the PATH... */ 00317 m_libHandle = LoadLibraryExA(dllName, 00318 NULL, LOAD_WITH_ALTERED_SEARCH_PATH); 00319 } 00320 free(dllName); 00321 } else { 00322 /* Try to use old VS_PROFILER variable */ 00323 dNameLength = GetEnvironmentVariableA(DLL_ENVIRONMENT_VAR, NULL, 0); 00324 if (dNameLength) 00325 { 00326 DWORD envret = 0; 00327 dllName = (char*)malloc(sizeof(char) * (dNameLength + 1)); 00328 envret = GetEnvironmentVariableA(DLL_ENVIRONMENT_VAR, 00329 dllName, dNameLength); 00330 if (envret) 00331 { 00332 /* Try to load the dll from the PATH... */ 00333 m_libHandle = LoadLibraryA(dllName); 00334 } 00335 free(dllName); 00336 } 00337 } 00338 #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 00339 dllName = getenv(NEW_DLL_ENVIRONMENT_VAR); 00340 if (!dllName) 00341 dllName = getenv(DLL_ENVIRONMENT_VAR); 00342 #ifdef ANDROID 00343 if (!dllName) 00344 dllName = ANDROID_JIT_AGENT_PATH; 00345 #endif 00346 if (dllName) 00347 { 00348 /* Try to load the dll from the PATH... */ 00349 m_libHandle = dlopen(dllName, RTLD_LAZY); 00350 } 00351 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 00352 00353 if (!m_libHandle) 00354 { 00355 #if ITT_PLATFORM==ITT_PLATFORM_WIN 00356 m_libHandle = LoadLibraryA(DEFAULT_DLLNAME); 00357 #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 00358 m_libHandle = dlopen(DEFAULT_DLLNAME, RTLD_LAZY); 00359 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 00360 } 00361 00362 /* if the dll wasn't loaded - exit. */ 00363 if (!m_libHandle) 00364 { 00365 iJIT_DLL_is_missing = 1; /* don't try to initialize 00366 * JIT agent the second time 00367 */ 00368 return 0; 00369 } 00370 00371 #if ITT_PLATFORM==ITT_PLATFORM_WIN 00372 FUNC_NotifyEvent = (TPNotify)GetProcAddress(m_libHandle, "NotifyEvent"); 00373 #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 00374 FUNC_NotifyEvent = (TPNotify)dlsym(m_libHandle, "NotifyEvent"); 00375 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 00376 if (!FUNC_NotifyEvent) 00377 { 00378 FUNC_Initialize = NULL; 00379 return 0; 00380 } 00381 00382 #if ITT_PLATFORM==ITT_PLATFORM_WIN 00383 FUNC_Initialize = (TPInitialize)GetProcAddress(m_libHandle, "Initialize"); 00384 #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 00385 FUNC_Initialize = (TPInitialize)dlsym(m_libHandle, "Initialize"); 00386 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 00387 if (!FUNC_Initialize) 00388 { 00389 FUNC_NotifyEvent = NULL; 00390 return 0; 00391 } 00392 00393 executionMode = (iJIT_IsProfilingActiveFlags)FUNC_Initialize(); 00394 00395 bDllWasLoaded = 1; 00396 iJIT_DLL_is_missing = 0; /* DLL is ok. */ 00397 00398 /* 00399 * Call Graph mode: init the thread local storage 00400 * (need to store the virtual stack there). 00401 */ 00402 if ( executionMode == iJIT_CALLGRAPH_ON ) 00403 { 00404 /* Allocate a thread local storage slot for the thread "stack" */ 00405 if (!threadLocalStorageHandle) 00406 #if ITT_PLATFORM==ITT_PLATFORM_WIN 00407 threadLocalStorageHandle = TlsAlloc(); 00408 #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 00409 pthread_key_create(&threadLocalStorageHandle, NULL); 00410 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 00411 } 00412 00413 return 1; 00414 } 00415 00416 /* 00417 * This function should be called by the user whenever a thread ends, 00418 * to free the thread "virtual stack" storage 00419 */ 00420 ITT_EXTERN_C void JITAPI FinalizeThread() 00421 { 00422 if (threadLocalStorageHandle) 00423 { 00424 #if ITT_PLATFORM==ITT_PLATFORM_WIN 00425 pThreadStack threadStack = 00426 (pThreadStack)TlsGetValue (threadLocalStorageHandle); 00427 #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 00428 pThreadStack threadStack = 00429 (pThreadStack)pthread_getspecific(threadLocalStorageHandle); 00430 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 00431 if (threadStack) 00432 { 00433 free (threadStack); 00434 threadStack = NULL; 00435 #if ITT_PLATFORM==ITT_PLATFORM_WIN 00436 TlsSetValue (threadLocalStorageHandle, threadStack); 00437 #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 00438 pthread_setspecific(threadLocalStorageHandle, threadStack); 00439 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 00440 } 00441 } 00442 } 00443 00444 /* 00445 * This function should be called by the user when the process ends, 00446 * to free the local storage index 00447 */ 00448 ITT_EXTERN_C void JITAPI FinalizeProcess() 00449 { 00450 if (m_libHandle) 00451 { 00452 #if ITT_PLATFORM==ITT_PLATFORM_WIN 00453 FreeLibrary(m_libHandle); 00454 #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 00455 dlclose(m_libHandle); 00456 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 00457 m_libHandle = NULL; 00458 } 00459 00460 if (threadLocalStorageHandle) 00461 #if ITT_PLATFORM==ITT_PLATFORM_WIN 00462 TlsFree (threadLocalStorageHandle); 00463 #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 00464 pthread_key_delete(threadLocalStorageHandle); 00465 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 00466 } 00467 00468 /* 00469 * This function should be called by the user for any method once. 00470 * The function will return a unique method ID, the user should maintain 00471 * the ID for each method 00472 */ 00473 ITT_EXTERN_C unsigned int JITAPI iJIT_GetNewMethodID() 00474 { 00475 static unsigned int methodID = 0x100000; 00476 00477 if (methodID == 0) 00478 return 0; /* ERROR : this is not a valid value */ 00479 00480 return methodID++; 00481 }