1 /*===-- jitprofiling.c - JIT (Just-In-Time) Profiling API----------*- C -*-===*
3 * The LLVM Compiler Infrastructure
5 * This file is distributed under the University of Illinois Open Source
6 * License. See LICENSE.TXT for details.
8 *===----------------------------------------------------------------------===*
10 * This file provides Intel(R) Performance Analyzer JIT (Just-In-Time)
11 * Profiling API implementation.
13 *===----------------------------------------------------------------------===*/
14 #include "ittnotify_config.h"
16 #if ITT_PLATFORM==ITT_PLATFORM_WIN
18 #pragma optimize("", off)
19 #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
22 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
26 #include "jitprofiling.h"
28 static const char rcsid[] = "\n@(#) $Revision: 243501 $\n";
30 #define DLL_ENVIRONMENT_VAR "VS_PROFILER"
32 #ifndef NEW_DLL_ENVIRONMENT_VAR
33 #if ITT_ARCH==ITT_ARCH_IA32
34 #define NEW_DLL_ENVIRONMENT_VAR "INTEL_JIT_PROFILER32"
36 #define NEW_DLL_ENVIRONMENT_VAR "INTEL_JIT_PROFILER64"
38 #endif /* NEW_DLL_ENVIRONMENT_VAR */
40 #if ITT_PLATFORM==ITT_PLATFORM_WIN
41 #define DEFAULT_DLLNAME "JitPI.dll"
42 HINSTANCE m_libHandle = NULL;
43 #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
44 #define DEFAULT_DLLNAME "libJitPI.so"
45 void* m_libHandle = NULL;
46 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
48 /* default location of JIT profiling agent on Android */
49 #define ANDROID_JIT_AGENT_PATH "/data/intel/libittnotify.so"
51 /* the function pointers */
52 typedef unsigned int(*TPInitialize)(void);
53 static TPInitialize FUNC_Initialize=NULL;
55 typedef unsigned int(*TPNotify)(unsigned int, void*);
56 static TPNotify FUNC_NotifyEvent=NULL;
58 static iJIT_IsProfilingActiveFlags executionMode = iJIT_NOTHING_RUNNING;
60 /* end collector dll part. */
62 /* loadiJIT_Funcs() : this function is called just in the beginning
63 * and is responsible to load the functions from BistroJavaCollector.dll
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
68 static int loadiJIT_Funcs(void);
70 /* global representing whether the BistroJavaCollector can't be loaded */
71 static int iJIT_DLL_is_missing = 0;
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.
81 #if ITT_PLATFORM==ITT_PLATFORM_WIN
82 static DWORD threadLocalStorageHandle = 0;
83 #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
84 static pthread_key_t threadLocalStorageHandle = (pthread_key_t)0;
85 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
87 #define INIT_TOP_Stack 10000
91 unsigned int TopStack;
92 unsigned int CurrentStack;
93 } ThreadStack, *pThreadStack;
95 /* end of virtual stack. */
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.
107 ITT_EXTERN_C int JITAPI
108 iJIT_NotifyEvent(iJIT_JVM_EVENT event_type, void *EventSpecificData)
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.
118 * static int firstTime = 1;
119 * char DoCallGraph[12] = "DoCallGraph";
123 * SetEnvironmentVariable( "BISTRO_COLLECTORS_DO_CALLGRAPH", DoCallGraph);
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).
133 if (!FUNC_NotifyEvent)
135 if (iJIT_DLL_is_missing)
138 /* load the Function from the DLL */
139 if (!loadiJIT_Funcs())
142 /* Call Graph initialization. */
145 /* If the event is method entry/exit, check that in the current mode
146 * VTune is allowed to receive it
148 if ((event_type == iJVM_EVENT_TYPE_ENTER_NIDS ||
149 event_type == iJVM_EVENT_TYPE_LEAVE_NIDS) &&
150 (executionMode != iJIT_CALLGRAPH_ON))
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.
158 if (event_type == iJVM_EVENT_TYPE_ENTER_NIDS)
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 */
168 /* check for use of reserved method IDs */
169 if ( ((piJIT_Method_NIDS) EventSpecificData)->method_id <= 999 )
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 */
185 /* decrease the stack. */
186 ((piJIT_Method_NIDS) EventSpecificData)->stack_id =
187 (threadStack->CurrentStack)--;
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.
196 if (event_type == iJVM_EVENT_TYPE_LEAVE_NIDS)
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 */
206 /* check for use of reserved method IDs */
207 if ( ((piJIT_Method_NIDS) EventSpecificData)->method_id <= 999 )
212 /* Error: first report in this thread is method exit */
216 ((piJIT_Method_NIDS) EventSpecificData)->stack_id =
217 ++(threadStack->CurrentStack) + 1;
219 if (((piJIT_Method_NIDS) EventSpecificData)->stack_id
220 > threadStack->TopStack)
221 ((piJIT_Method_NIDS) EventSpecificData)->stack_id =
225 if (event_type == iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED)
227 /* check for use of reserved method IDs */
228 if ( ((piJIT_Method_Load) EventSpecificData)->method_id <= 999 )
232 ReturnValue = (int)FUNC_NotifyEvent(event_type, EventSpecificData);
237 /* The new mode call back routine */
238 ITT_EXTERN_C void JITAPI
239 iJIT_RegisterCallbackEx(void *userdata, iJIT_ModeChangedEx
240 NewModeCallBackFuncEx)
242 /* is it already missing... or the load of functions from the DLL failed */
243 if (iJIT_DLL_is_missing || !loadiJIT_Funcs())
245 /* then do not bother with notifications */
246 NewModeCallBackFuncEx(userdata, iJIT_NO_NOTIFICATIONS);
247 /* Error: could not load JIT functions. */
250 /* nothing to do with the callback */
254 * This function allows the user to query in which mode, if at all,
257 ITT_EXTERN_C iJIT_IsProfilingActiveFlags JITAPI iJIT_IsProfilingActive()
259 if (!iJIT_DLL_is_missing)
264 return executionMode;
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
272 static int loadiJIT_Funcs()
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 */
282 /* dll was already loaded, no need to do it for the second time */
286 /* Assumes that the DLL will not be found */
287 iJIT_DLL_is_missing = 1;
288 FUNC_NotifyEvent = NULL;
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 */
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);
306 dllName = (char*)malloc(sizeof(char) * (dNameLength + 1));
307 envret = GetEnvironmentVariableA(NEW_DLL_ENVIRONMENT_VAR,
308 dllName, dNameLength);
311 /* Try to load the dll from the PATH... */
312 m_libHandle = LoadLibraryExA(dllName,
313 NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
317 /* Try to use old VS_PROFILER variable */
318 dNameLength = GetEnvironmentVariableA(DLL_ENVIRONMENT_VAR, NULL, 0);
322 dllName = (char*)malloc(sizeof(char) * (dNameLength + 1));
323 envret = GetEnvironmentVariableA(DLL_ENVIRONMENT_VAR,
324 dllName, dNameLength);
327 /* Try to load the dll from the PATH... */
328 m_libHandle = LoadLibraryA(dllName);
333 #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
334 dllName = getenv(NEW_DLL_ENVIRONMENT_VAR);
336 dllName = getenv(DLL_ENVIRONMENT_VAR);
339 dllName = ANDROID_JIT_AGENT_PATH;
343 /* Try to load the dll from the PATH... */
344 m_libHandle = dlopen(dllName, RTLD_LAZY);
346 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
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 */
357 /* if the dll wasn't loaded - exit. */
360 iJIT_DLL_is_missing = 1; /* don't try to initialize
361 * JIT agent the second time
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)
373 FUNC_Initialize = NULL;
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)
384 FUNC_NotifyEvent = NULL;
388 executionMode = (iJIT_IsProfilingActiveFlags)FUNC_Initialize();
391 iJIT_DLL_is_missing = 0; /* DLL is ok. */
394 * Call Graph mode: init the thread local storage
395 * (need to store the virtual stack there).
397 if ( executionMode == iJIT_CALLGRAPH_ON )
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 */
412 * This function should be called by the user whenever a thread ends,
413 * to free the thread "virtual stack" storage
415 ITT_EXTERN_C void JITAPI FinalizeThread()
417 if (threadLocalStorageHandle)
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 */
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 */
440 * This function should be called by the user when the process ends,
441 * to free the local storage index
443 ITT_EXTERN_C void JITAPI FinalizeProcess()
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 */
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 */
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
468 ITT_EXTERN_C unsigned int JITAPI iJIT_GetNewMethodID()
470 static unsigned int methodID = 0x100000;
473 return 0; /* ERROR : this is not a valid value */