LLVM  14.0.0git
jitprofiling.c
Go to the documentation of this file.
1 /*===-- jitprofiling.c - JIT (Just-In-Time) Profiling API----------*- C -*-===*
2  *
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
6  *
7  *===----------------------------------------------------------------------===*
8  *
9  * This file provides Intel(R) Performance Analyzer JIT (Just-In-Time)
10  * Profiling API implementation.
11  *
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.
16  *
17  *===----------------------------------------------------------------------===*/
18 #include "ittnotify_config.h"
19 
20 #if ITT_PLATFORM==ITT_PLATFORM_WIN
21 #include <windows.h>
22 #pragma optimize("", off)
23 #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
24 #include <dlfcn.h>
25 #include <pthread.h>
26 #include <stdint.h>
27 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
28 #include <stdlib.h>
29 
30 #include "jitprofiling.h"
31 
32 static const char rcsid[] = "\n@(#) $Revision: 243501 $\n";
33 
34 #define DLL_ENVIRONMENT_VAR "VS_PROFILER"
35 
36 #ifndef NEW_DLL_ENVIRONMENT_VAR
37 #if ITT_ARCH==ITT_ARCH_IA32
38 #define NEW_DLL_ENVIRONMENT_VAR "INTEL_JIT_PROFILER32"
39 #else
40 #define NEW_DLL_ENVIRONMENT_VAR "INTEL_JIT_PROFILER64"
41 #endif
42 #endif /* NEW_DLL_ENVIRONMENT_VAR */
43 
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 */
51 
52 /* default location of JIT profiling agent on Android */
53 #define ANDROID_JIT_AGENT_PATH "/data/intel/libittnotify.so"
54 
55 /* the function pointers */
56 typedef unsigned int(*TPInitialize)(void);
58 
59 typedef unsigned int(*TPNotify)(unsigned int, void*);
61 
63 
64 /* end collector dll part. */
65 
66 /* loadiJIT_Funcs() : this function is called just in the beginning
67  * and is responsible to load the functions from BistroJavaCollector.dll
68  * result:
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
71  */
72 static int loadiJIT_Funcs(void);
73 
74 /* global representing whether the BistroJavaCollector can't be loaded */
75 static int iJIT_DLL_is_missing = 0;
76 
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.
84 */
85 #if ITT_PLATFORM==ITT_PLATFORM_WIN
87 #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
88 static pthread_key_t threadLocalStorageHandle = (pthread_key_t)0;
89 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
90 
91 #define INIT_TOP_Stack 10000
92 
93 typedef struct
94 {
95  unsigned int TopStack;
96  unsigned int CurrentStack;
98 
99 /* end of virtual stack. */
100 
101 /*
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.
109 */
110 
111 ITT_EXTERN_C int JITAPI
112 iJIT_NotifyEvent(iJIT_JVM_EVENT event_type, void *EventSpecificData)
113 {
114  int ReturnValue;
115 
116  /*
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.
120  *
121  *
122  * static int firstTime = 1;
123  * char DoCallGraph[12] = "DoCallGraph";
124  * if (firstTime)
125  * {
126  * firstTime = 0;
127  * SetEnvironmentVariable( "BISTRO_COLLECTORS_DO_CALLGRAPH", DoCallGraph);
128  * }
129  *
130  * end of section.
131  */
132 
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).
136  */
137  if (!FUNC_NotifyEvent)
138  {
139  if (iJIT_DLL_is_missing)
140  return 0;
141 
142  /* load the Function from the DLL */
143  if (!loadiJIT_Funcs())
144  return 0;
145 
146  /* Call Graph initialization. */
147  }
148 
149  /* If the event is method entry/exit, check that in the current mode
150  * VTune is allowed to receive it
151  */
152  if ((event_type == iJVM_EVENT_TYPE_ENTER_NIDS ||
153  event_type == iJVM_EVENT_TYPE_LEAVE_NIDS) &&
155  {
156  return 0;
157  }
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.
161  */
162  if (event_type == iJVM_EVENT_TYPE_ENTER_NIDS)
163  {
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 */
171 
172  /* check for use of reserved method IDs */
173  if ( ((piJIT_Method_NIDS) EventSpecificData)->method_id <= 999 )
174  return 0;
175 
176  if (!threadStack)
177  {
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 */
187  }
188 
189  /* decrease the stack. */
190  ((piJIT_Method_NIDS) EventSpecificData)->stack_id =
191  (threadStack->CurrentStack)--;
192  }
193 
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.
199  */
200  if (event_type == iJVM_EVENT_TYPE_LEAVE_NIDS)
201  {
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 */
209 
210  /* check for use of reserved method IDs */
211  if ( ((piJIT_Method_NIDS) EventSpecificData)->method_id <= 999 )
212  return 0;
213 
214  if (!threadStack)
215  {
216  /* Error: first report in this thread is method exit */
217  exit (1);
218  }
219 
220  ((piJIT_Method_NIDS) EventSpecificData)->stack_id =
221  ++(threadStack->CurrentStack) + 1;
222 
223  if (((piJIT_Method_NIDS) EventSpecificData)->stack_id
224  > threadStack->TopStack)
225  ((piJIT_Method_NIDS) EventSpecificData)->stack_id =
226  (unsigned int)-1;
227  }
228 
229  if (event_type == iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED)
230  {
231  /* check for use of reserved method IDs */
232  if ( ((piJIT_Method_Load) EventSpecificData)->method_id <= 999 )
233  return 0;
234  }
235 
236  ReturnValue = (int)FUNC_NotifyEvent(event_type, EventSpecificData);
237 
238  return ReturnValue;
239 }
240 
241 /* The new mode call back routine */
242 ITT_EXTERN_C void JITAPI
244  NewModeCallBackFuncEx)
245 {
246  /* is it already missing... or the load of functions from the DLL failed */
248  {
249  /* then do not bother with notifications */
250  NewModeCallBackFuncEx(userdata, iJIT_NO_NOTIFICATIONS);
251  /* Error: could not load JIT functions. */
252  return;
253  }
254  /* nothing to do with the callback */
255 }
256 
257 /*
258  * This function allows the user to query in which mode, if at all,
259  *VTune is running
260  */
262 {
263  if (!iJIT_DLL_is_missing)
264  {
265  loadiJIT_Funcs();
266  }
267 
268  return executionMode;
269 }
270 
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
275  */
276 static int loadiJIT_Funcs()
277 {
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 */
283 
284  if(bDllWasLoaded)
285  {
286  /* dll was already loaded, no need to do it for the second time */
287  return 1;
288  }
289 
290  /* Assumes that the DLL will not be found */
292  FUNC_NotifyEvent = NULL;
293 
294  if (m_libHandle)
295  {
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 */
301  m_libHandle = NULL;
302  }
303 
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);
307  if (dNameLength)
308  {
309  DWORD envret = 0;
310  dllName = (char*)malloc(sizeof(char) * (dNameLength + 1));
311  envret = GetEnvironmentVariableA(NEW_DLL_ENVIRONMENT_VAR,
312  dllName, dNameLength);
313  if (envret)
314  {
315  /* Try to load the dll from the PATH... */
316  m_libHandle = LoadLibraryExA(dllName,
317  NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
318  }
319  free(dllName);
320  } else {
321  /* Try to use old VS_PROFILER variable */
322  dNameLength = GetEnvironmentVariableA(DLL_ENVIRONMENT_VAR, NULL, 0);
323  if (dNameLength)
324  {
325  DWORD envret = 0;
326  dllName = (char*)malloc(sizeof(char) * (dNameLength + 1));
327  envret = GetEnvironmentVariableA(DLL_ENVIRONMENT_VAR,
328  dllName, dNameLength);
329  if (envret)
330  {
331  /* Try to load the dll from the PATH... */
332  m_libHandle = LoadLibraryA(dllName);
333  }
334  free(dllName);
335  }
336  }
337 #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
338  dllName = getenv(NEW_DLL_ENVIRONMENT_VAR);
339  if (!dllName)
340  dllName = getenv(DLL_ENVIRONMENT_VAR);
341 #ifdef ANDROID
342  if (!dllName)
343  dllName = ANDROID_JIT_AGENT_PATH;
344 #endif
345  if (dllName)
346  {
347  /* Try to load the dll from the PATH... */
348  m_libHandle = dlopen(dllName, RTLD_LAZY);
349  }
350 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
351 
352  if (!m_libHandle)
353  {
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 */
359  }
360 
361  /* if the dll wasn't loaded - exit. */
362  if (!m_libHandle)
363  {
364  iJIT_DLL_is_missing = 1; /* don't try to initialize
365  * JIT agent the second time
366  */
367  return 0;
368  }
369 
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)
376  {
377  FUNC_Initialize = NULL;
378  return 0;
379  }
380 
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)
387  {
388  FUNC_NotifyEvent = NULL;
389  return 0;
390  }
391 
393 
394  bDllWasLoaded = 1;
395  iJIT_DLL_is_missing = 0; /* DLL is ok. */
396 
397  /*
398  * Call Graph mode: init the thread local storage
399  * (need to store the virtual stack there).
400  */
402  {
403  /* Allocate a thread local storage slot for the thread "stack" */
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 */
410  }
411 
412  return 1;
413 }
414 
415 /*
416  * This function should be called by the user whenever a thread ends,
417  * to free the thread "virtual stack" storage
418  */
420 {
422  {
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 */
430  if (threadStack)
431  {
432  free (threadStack);
433  threadStack = NULL;
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 */
439  }
440  }
441 }
442 
443 /*
444  * This function should be called by the user when the process ends,
445  * to free the local storage index
446 */
448 {
449  if (m_libHandle)
450  {
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 */
456  m_libHandle = NULL;
457  }
458 
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 */
465 }
466 
467 /*
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
471  */
473 {
474  static unsigned int methodID = 0x100000;
475 
476  if (methodID == 0)
477  return 0; /* ERROR : this is not a valid value */
478 
479  return methodID++;
480 }
ANDROID_JIT_AGENT_PATH
#define ANDROID_JIT_AGENT_PATH
Definition: jitprofiling.c:53
FinalizeProcess
ITT_EXTERN_C void JITAPI FinalizeProcess()
Definition: jitprofiling.c:447
ThreadStack::TopStack
unsigned int TopStack
Definition: jitprofiling.c:95
_iJIT_Method_NIDS
Definition: jitprofiling.h:148
iJVM_EVENT_TYPE_LEAVE_NIDS
@ iJVM_EVENT_TYPE_LEAVE_NIDS
Definition: jitprofiling.h:62
intptr_t
iJIT_IsProfilingActive
ITT_EXTERN_C iJIT_IsProfilingActiveFlags JITAPI iJIT_IsProfilingActive()
Definition: jitprofiling.c:261
jitprofiling.h
FUNC_NotifyEvent
static TPNotify FUNC_NotifyEvent
Definition: jitprofiling.c:60
iJIT_CALLGRAPH_ON
@ iJIT_CALLGRAPH_ON
Definition: jitprofiling.h:114
iJIT_GetNewMethodID
ITT_EXTERN_C unsigned int JITAPI iJIT_GetNewMethodID()
Definition: jitprofiling.c:472
JITAPI
#define JITAPI
Definition: jitprofiling.h:235
ThreadStack
Definition: jitprofiling.c:93
iJIT_JVM_EVENT
enum iJIT_jvm_event iJIT_JVM_EVENT
DEFAULT_DLLNAME
#define DEFAULT_DLLNAME
Definition: jitprofiling.c:45
pThreadStack
struct ThreadStack * pThreadStack
threadLocalStorageHandle
static DWORD threadLocalStorageHandle
Definition: jitprofiling.c:86
piJIT_Method_NIDS
struct _iJIT_Method_NIDS * piJIT_Method_NIDS
iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED
@ iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED
Definition: jitprofiling.h:42
int
Clang compiles this i1 i64 store i64 i64 store i64 i64 store i64 i64 store i64 align Which gets codegen d xmm0 movaps rbp movaps rbp movaps rbp movaps rbp rbp rbp rbp rbp It would be better to have movq s of instead of the movaps s LLVM produces ret int
Definition: README.txt:536
m_libHandle
HINSTANCE m_libHandle
Definition: jitprofiling.c:46
DLL_ENVIRONMENT_VAR
#define DLL_ENVIRONMENT_VAR
Definition: jitprofiling.c:34
iJIT_NO_NOTIFICATIONS
@ iJIT_NO_NOTIFICATIONS
Definition: jitprofiling.h:68
ittnotify_config.h
iJIT_ModeChangedEx
void(* iJIT_ModeChangedEx)(void *UserData, iJIT_ModeFlags Flags)
Definition: jitprofiling.h:238
_iJIT_Method_Load
Definition: jitprofiling.h:174
ITT_EXTERN_C
#define ITT_EXTERN_C
Definition: ittnotify_config.h:149
ThreadStack::CurrentStack
unsigned int CurrentStack
Definition: jitprofiling.c:96
iJIT_NOTHING_RUNNING
@ iJIT_NOTHING_RUNNING
Definition: jitprofiling.h:106
llvm::AMDGPU::SDWA::DWORD
@ DWORD
Definition: SIDefines.h:653
INIT_TOP_Stack
#define INIT_TOP_Stack
Definition: jitprofiling.c:91
iJVM_EVENT_TYPE_ENTER_NIDS
@ iJVM_EVENT_TYPE_ENTER_NIDS
Definition: jitprofiling.h:56
TPInitialize
unsigned int(* TPInitialize)(void)
Definition: jitprofiling.c:56
FUNC_Initialize
static TPInitialize FUNC_Initialize
Definition: jitprofiling.c:57
FinalizeThread
ITT_EXTERN_C void JITAPI FinalizeThread()
Definition: jitprofiling.c:419
iJIT_NotifyEvent
ITT_EXTERN_C int JITAPI iJIT_NotifyEvent(iJIT_JVM_EVENT event_type, void *EventSpecificData)
Definition: jitprofiling.c:112
rcsid
static const char rcsid[]
Definition: jitprofiling.c:32
executionMode
static iJIT_IsProfilingActiveFlags executionMode
Definition: jitprofiling.c:62
TPNotify
unsigned int(* TPNotify)(unsigned int, void *)
Definition: jitprofiling.c:59
NEW_DLL_ENVIRONMENT_VAR
#define NEW_DLL_ENVIRONMENT_VAR
Definition: jitprofiling.c:40
loadiJIT_Funcs
static int loadiJIT_Funcs(void)
Definition: jitprofiling.c:276
exit
declare void exit(i32) noreturn nounwind This compiles into
Definition: README.txt:1072
iJIT_DLL_is_missing
static int iJIT_DLL_is_missing
Definition: jitprofiling.c:75
iJIT_IsProfilingActiveFlags
enum _iJIT_IsProfilingActiveFlags iJIT_IsProfilingActiveFlags
iJIT_RegisterCallbackEx
ITT_EXTERN_C void JITAPI iJIT_RegisterCallbackEx(void *userdata, iJIT_ModeChangedEx NewModeCallBackFuncEx)
Definition: jitprofiling.c:243