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);
59 static TPInitialize FUNC_Initialize=NULL;
60
61 typedef unsigned int(*TPNotify)(unsigned int, void*);
62 static TPNotify FUNC_NotifyEvent=NULL;
63
64 static iJIT_IsProfilingActiveFlags executionMode = iJIT_NOTHING_RUNNING;
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;
99 } ThreadStack, *pThreadStack;
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
iJIT_NotifyEvent(iJIT_JVM_EVENT event_type,void * EventSpecificData)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) &&
156 (executionMode != iJIT_CALLGRAPH_ON))
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
iJIT_RegisterCallbackEx(void * userdata,iJIT_ModeChangedEx NewModeCallBackFuncEx)245 iJIT_RegisterCallbackEx(void *userdata, iJIT_ModeChangedEx
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 */
iJIT_IsProfilingActive()263 ITT_EXTERN_C iJIT_IsProfilingActiveFlags JITAPI iJIT_IsProfilingActive()
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 */
loadiJIT_Funcs()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
394 executionMode = (iJIT_IsProfilingActiveFlags)FUNC_Initialize();
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 */
403 if ( executionMode == iJIT_CALLGRAPH_ON )
404 {
405 /* Allocate a thread local storage slot for the thread "stack" */
406 if (!threadLocalStorageHandle)
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 */
FinalizeThread()421 ITT_EXTERN_C void JITAPI FinalizeThread()
422 {
423 if (threadLocalStorageHandle)
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 */
FinalizeProcess()449 ITT_EXTERN_C void JITAPI FinalizeProcess()
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
461 if (threadLocalStorageHandle)
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 */
iJIT_GetNewMethodID()474 ITT_EXTERN_C unsigned int JITAPI iJIT_GetNewMethodID()
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 }
483