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