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