1 /*===-- jitprofiling.c - JIT (Just-In-Time) Profiling API----------*- C -*-===*
3 * Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 * See https://llvm.org/LICENSE.txt for license information.
5 * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 *===----------------------------------------------------------------------===*
9 * This file provides Intel(R) Performance Analyzer JIT (Just-In-Time)
10 * Profiling API implementation.
12 * NOTE: This file comes in a style different from the rest of LLVM
13 * source base since this is a piece of code shared from Intel(R)
14 * products. Please do not reformat / re-style this code to make
15 * subsequent merges and contributions from the original source base eaiser.
17 *===----------------------------------------------------------------------===*/
18 #include "ittnotify_config.h"
20 #if ITT_PLATFORM==ITT_PLATFORM_WIN
22 #pragma optimize("", off)
23 #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
27 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
30 #include "jitprofiling.h"
32 static const char rcsid
[] = "\n@(#) $Revision: 243501 $\n";
34 #define DLL_ENVIRONMENT_VAR "VS_PROFILER"
36 #ifndef NEW_DLL_ENVIRONMENT_VAR
37 #if ITT_ARCH==ITT_ARCH_IA32
38 #define NEW_DLL_ENVIRONMENT_VAR "INTEL_JIT_PROFILER32"
40 #define NEW_DLL_ENVIRONMENT_VAR "INTEL_JIT_PROFILER64"
42 #endif /* NEW_DLL_ENVIRONMENT_VAR */
44 #if ITT_PLATFORM==ITT_PLATFORM_WIN
45 #define DEFAULT_DLLNAME "JitPI.dll"
46 HINSTANCE m_libHandle
= NULL
;
47 #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
48 #define DEFAULT_DLLNAME "libJitPI.so"
49 void* m_libHandle
= NULL
;
50 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
52 /* default location of JIT profiling agent on Android */
53 #define ANDROID_JIT_AGENT_PATH "/data/intel/libittnotify.so"
55 /* the function pointers */
56 typedef unsigned int(*TPInitialize
)(void);
57 static TPInitialize FUNC_Initialize
=NULL
;
59 typedef unsigned int(*TPNotify
)(unsigned int, void*);
60 static TPNotify FUNC_NotifyEvent
=NULL
;
62 static iJIT_IsProfilingActiveFlags executionMode
= iJIT_NOTHING_RUNNING
;
64 /* end collector dll part. */
66 /* loadiJIT_Funcs() : this function is called just in the beginning
67 * and is responsible to load the functions from BistroJavaCollector.dll
69 * on success: the functions loads, iJIT_DLL_is_missing=0, return value = 1
70 * on failure: the functions are NULL, iJIT_DLL_is_missing=1, return value = 0
72 static int loadiJIT_Funcs(void);
74 /* global representing whether the BistroJavaCollector can't be loaded */
75 static int iJIT_DLL_is_missing
= 0;
77 /* Virtual stack - the struct is used as a virtual stack for each thread.
78 * Every thread initializes with a stack of size INIT_TOP_STACK.
79 * Every method entry decreases from the current stack point,
80 * and when a thread stack reaches its top of stack (return from the global
81 * function), the top of stack and the current stack increase. Notice that
82 * when returning from a function the stack pointer is the address of
83 * the function return.
85 #if ITT_PLATFORM==ITT_PLATFORM_WIN
86 static DWORD threadLocalStorageHandle
= 0;
87 #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
88 static pthread_key_t threadLocalStorageHandle
= (pthread_key_t
)0;
89 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
91 #define INIT_TOP_Stack 10000
95 unsigned int TopStack
;
96 unsigned int CurrentStack
;
97 } ThreadStack
, *pThreadStack
;
99 /* end of virtual stack. */
102 * The function for reporting virtual-machine related events to VTune.
103 * Note: when reporting iJVM_EVENT_TYPE_ENTER_NIDS, there is no need to fill
104 * in the stack_id field in the iJIT_Method_NIDS structure, as VTune fills it.
105 * The return value in iJVM_EVENT_TYPE_ENTER_NIDS &&
106 * iJVM_EVENT_TYPE_LEAVE_NIDS events will be 0 in case of failure.
107 * in iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED event
108 * it will be -1 if EventSpecificData == 0 otherwise it will be 0.
111 ITT_EXTERN_C
int JITAPI
112 iJIT_NotifyEvent(iJIT_JVM_EVENT event_type
, void *EventSpecificData
)
117 * This section is for debugging outside of VTune.
118 * It creates the environment variables that indicates call graph mode.
119 * If running outside of VTune remove the remark.
122 * static int firstTime = 1;
123 * char DoCallGraph[12] = "DoCallGraph";
127 * SetEnvironmentVariable( "BISTRO_COLLECTORS_DO_CALLGRAPH", DoCallGraph);
133 /* initialization part - the functions have not been loaded yet. This part
134 * will load the functions, and check if we are in Call Graph mode.
135 * (for special treatment).
137 if (!FUNC_NotifyEvent
)
139 if (iJIT_DLL_is_missing
)
142 /* load the Function from the DLL */
143 if (!loadiJIT_Funcs())
146 /* Call Graph initialization. */
149 /* If the event is method entry/exit, check that in the current mode
150 * VTune is allowed to receive it
152 if ((event_type
== iJVM_EVENT_TYPE_ENTER_NIDS
||
153 event_type
== iJVM_EVENT_TYPE_LEAVE_NIDS
) &&
154 (executionMode
!= iJIT_CALLGRAPH_ON
))
158 /* This section is performed when method enter event occurs.
159 * It updates the virtual stack, or creates it if this is the first
160 * method entry in the thread. The stack pointer is decreased.
162 if (event_type
== iJVM_EVENT_TYPE_ENTER_NIDS
)
164 #if ITT_PLATFORM==ITT_PLATFORM_WIN
165 pThreadStack threadStack
=
166 (pThreadStack
)TlsGetValue (threadLocalStorageHandle
);
167 #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
168 pThreadStack threadStack
=
169 (pThreadStack
)pthread_getspecific(threadLocalStorageHandle
);
170 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
172 /* check for use of reserved method IDs */
173 if ( ((piJIT_Method_NIDS
) EventSpecificData
)->method_id
<= 999 )
178 /* initialize the stack. */
179 threadStack
= (pThreadStack
) calloc (sizeof(ThreadStack
), 1);
180 threadStack
->TopStack
= INIT_TOP_Stack
;
181 threadStack
->CurrentStack
= INIT_TOP_Stack
;
182 #if ITT_PLATFORM==ITT_PLATFORM_WIN
183 TlsSetValue(threadLocalStorageHandle
,(void*)threadStack
);
184 #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
185 pthread_setspecific(threadLocalStorageHandle
,(void*)threadStack
);
186 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
189 /* decrease the stack. */
190 ((piJIT_Method_NIDS
) EventSpecificData
)->stack_id
=
191 (threadStack
->CurrentStack
)--;
194 /* This section is performed when method leave event occurs
195 * It updates the virtual stack.
196 * Increases the stack pointer.
197 * If the stack pointer reached the top (left the global function)
198 * increase the pointer and the top pointer.
200 if (event_type
== iJVM_EVENT_TYPE_LEAVE_NIDS
)
202 #if ITT_PLATFORM==ITT_PLATFORM_WIN
203 pThreadStack threadStack
=
204 (pThreadStack
)TlsGetValue (threadLocalStorageHandle
);
205 #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
206 pThreadStack threadStack
=
207 (pThreadStack
)pthread_getspecific(threadLocalStorageHandle
);
208 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
210 /* check for use of reserved method IDs */
211 if ( ((piJIT_Method_NIDS
) EventSpecificData
)->method_id
<= 999 )
216 /* Error: first report in this thread is method exit */
220 ((piJIT_Method_NIDS
) EventSpecificData
)->stack_id
=
221 ++(threadStack
->CurrentStack
) + 1;
223 if (((piJIT_Method_NIDS
) EventSpecificData
)->stack_id
224 > threadStack
->TopStack
)
225 ((piJIT_Method_NIDS
) EventSpecificData
)->stack_id
=
229 if (event_type
== iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED
)
231 /* check for use of reserved method IDs */
232 if ( ((piJIT_Method_Load
) EventSpecificData
)->method_id
<= 999 )
236 ReturnValue
= (int)FUNC_NotifyEvent(event_type
, EventSpecificData
);
241 /* The new mode call back routine */
242 ITT_EXTERN_C
void JITAPI
243 iJIT_RegisterCallbackEx(void *userdata
, iJIT_ModeChangedEx
244 NewModeCallBackFuncEx
)
246 /* is it already missing... or the load of functions from the DLL failed */
247 if (iJIT_DLL_is_missing
|| !loadiJIT_Funcs())
249 /* then do not bother with notifications */
250 NewModeCallBackFuncEx(userdata
, iJIT_NO_NOTIFICATIONS
);
251 /* Error: could not load JIT functions. */
254 /* nothing to do with the callback */
258 * This function allows the user to query in which mode, if at all,
261 ITT_EXTERN_C iJIT_IsProfilingActiveFlags JITAPI
iJIT_IsProfilingActive()
263 if (!iJIT_DLL_is_missing
)
268 return executionMode
;
271 /* this function loads the collector dll (BistroJavaCollector)
272 * and the relevant functions.
273 * on success: all functions load, iJIT_DLL_is_missing = 0, return value = 1
274 * on failure: all functions are NULL, iJIT_DLL_is_missing = 1, return value = 0
276 static int loadiJIT_Funcs()
278 static int bDllWasLoaded
= 0;
279 char *dllName
= (char*)rcsid
; /* !! Just to avoid unused code elimination */
280 #if ITT_PLATFORM==ITT_PLATFORM_WIN
281 DWORD dNameLength
= 0;
282 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
286 /* dll was already loaded, no need to do it for the second time */
290 /* Assumes that the DLL will not be found */
291 iJIT_DLL_is_missing
= 1;
292 FUNC_NotifyEvent
= NULL
;
296 #if ITT_PLATFORM==ITT_PLATFORM_WIN
297 FreeLibrary(m_libHandle
);
298 #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
299 dlclose(m_libHandle
);
300 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
304 /* Try to get the dll name from the environment */
305 #if ITT_PLATFORM==ITT_PLATFORM_WIN
306 dNameLength
= GetEnvironmentVariableA(NEW_DLL_ENVIRONMENT_VAR
, NULL
, 0);
310 dllName
= (char*)malloc(sizeof(char) * (dNameLength
+ 1));
311 envret
= GetEnvironmentVariableA(NEW_DLL_ENVIRONMENT_VAR
,
312 dllName
, dNameLength
);
315 /* Try to load the dll from the PATH... */
316 m_libHandle
= LoadLibraryExA(dllName
,
317 NULL
, LOAD_WITH_ALTERED_SEARCH_PATH
);
321 /* Try to use old VS_PROFILER variable */
322 dNameLength
= GetEnvironmentVariableA(DLL_ENVIRONMENT_VAR
, NULL
, 0);
326 dllName
= (char*)malloc(sizeof(char) * (dNameLength
+ 1));
327 envret
= GetEnvironmentVariableA(DLL_ENVIRONMENT_VAR
,
328 dllName
, dNameLength
);
331 /* Try to load the dll from the PATH... */
332 m_libHandle
= LoadLibraryA(dllName
);
337 #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
338 dllName
= getenv(NEW_DLL_ENVIRONMENT_VAR
);
340 dllName
= getenv(DLL_ENVIRONMENT_VAR
);
343 dllName
= ANDROID_JIT_AGENT_PATH
;
347 /* Try to load the dll from the PATH... */
348 m_libHandle
= dlopen(dllName
, RTLD_LAZY
);
350 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
354 #if ITT_PLATFORM==ITT_PLATFORM_WIN
355 m_libHandle
= LoadLibraryA(DEFAULT_DLLNAME
);
356 #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
357 m_libHandle
= dlopen(DEFAULT_DLLNAME
, RTLD_LAZY
);
358 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
361 /* if the dll wasn't loaded - exit. */
364 iJIT_DLL_is_missing
= 1; /* don't try to initialize
365 * JIT agent the second time
370 #if ITT_PLATFORM==ITT_PLATFORM_WIN
371 FUNC_NotifyEvent
= (TPNotify
)GetProcAddress(m_libHandle
, "NotifyEvent");
372 #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
373 FUNC_NotifyEvent
= (TPNotify
)(intptr_t)dlsym(m_libHandle
, "NotifyEvent");
374 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
375 if (!FUNC_NotifyEvent
)
377 FUNC_Initialize
= NULL
;
381 #if ITT_PLATFORM==ITT_PLATFORM_WIN
382 FUNC_Initialize
= (TPInitialize
)GetProcAddress(m_libHandle
, "Initialize");
383 #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
384 FUNC_Initialize
= (TPInitialize
)(intptr_t)dlsym(m_libHandle
, "Initialize");
385 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
386 if (!FUNC_Initialize
)
388 FUNC_NotifyEvent
= NULL
;
392 executionMode
= (iJIT_IsProfilingActiveFlags
)FUNC_Initialize();
395 iJIT_DLL_is_missing
= 0; /* DLL is ok. */
398 * Call Graph mode: init the thread local storage
399 * (need to store the virtual stack there).
401 if ( executionMode
== iJIT_CALLGRAPH_ON
)
403 /* Allocate a thread local storage slot for the thread "stack" */
404 if (!threadLocalStorageHandle
)
405 #if ITT_PLATFORM==ITT_PLATFORM_WIN
406 threadLocalStorageHandle
= TlsAlloc();
407 #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
408 pthread_key_create(&threadLocalStorageHandle
, NULL
);
409 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
416 * This function should be called by the user whenever a thread ends,
417 * to free the thread "virtual stack" storage
419 ITT_EXTERN_C
void JITAPI
FinalizeThread()
421 if (threadLocalStorageHandle
)
423 #if ITT_PLATFORM==ITT_PLATFORM_WIN
424 pThreadStack threadStack
=
425 (pThreadStack
)TlsGetValue (threadLocalStorageHandle
);
426 #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
427 pThreadStack threadStack
=
428 (pThreadStack
)pthread_getspecific(threadLocalStorageHandle
);
429 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
434 #if ITT_PLATFORM==ITT_PLATFORM_WIN
435 TlsSetValue (threadLocalStorageHandle
, threadStack
);
436 #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
437 pthread_setspecific(threadLocalStorageHandle
, threadStack
);
438 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
444 * This function should be called by the user when the process ends,
445 * to free the local storage index
447 ITT_EXTERN_C
void JITAPI
FinalizeProcess()
451 #if ITT_PLATFORM==ITT_PLATFORM_WIN
452 FreeLibrary(m_libHandle
);
453 #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
454 dlclose(m_libHandle
);
455 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
459 if (threadLocalStorageHandle
)
460 #if ITT_PLATFORM==ITT_PLATFORM_WIN
461 TlsFree (threadLocalStorageHandle
);
462 #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
463 pthread_key_delete(threadLocalStorageHandle
);
464 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
468 * This function should be called by the user for any method once.
469 * The function will return a unique method ID, the user should maintain
470 * the ID for each method
472 ITT_EXTERN_C
unsigned int JITAPI
iJIT_GetNewMethodID()
474 static unsigned int methodID
= 0x100000;
477 return 0; /* ERROR : this is not a valid value */