blob: 7b507de864cde2ed6b1b804cb8aee865218c9aa6 [file] [log] [blame]
Andrew Kaylor770b97b2012-09-28 17:35:20 +00001/*===-- 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 *
Andrew Kaylor3c9019d2012-10-10 01:48:52 +000013 * 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 *
Andrew Kaylor770b97b2012-09-28 17:35:20 +000018 *===----------------------------------------------------------------------===*/
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#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
28#include <malloc.h>
29#include <stdlib.h>
30
31#include "jitprofiling.h"
32
33static 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"
47HINSTANCE m_libHandle = NULL;
48#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
49#define DEFAULT_DLLNAME "libJitPI.so"
50void* 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 */
57typedef unsigned int(*TPInitialize)(void);
58static TPInitialize FUNC_Initialize=NULL;
59
60typedef unsigned int(*TPNotify)(unsigned int, void*);
61static TPNotify FUNC_NotifyEvent=NULL;
62
63static iJIT_IsProfilingActiveFlags executionMode = iJIT_NOTHING_RUNNING;
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 */
73static int loadiJIT_Funcs(void);
74
75/* global representing whether the BistroJavaCollector can't be loaded */
76static 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
87static DWORD threadLocalStorageHandle = 0;
88#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
89static pthread_key_t threadLocalStorageHandle = (pthread_key_t)0;
90#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
91
92#define INIT_TOP_Stack 10000
93
94typedef struct
95{
96 unsigned int TopStack;
97 unsigned int CurrentStack;
98} ThreadStack, *pThreadStack;
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
112ITT_EXTERN_C int JITAPI
113iJIT_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) &&
155 (executionMode != iJIT_CALLGRAPH_ON))
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 */
243ITT_EXTERN_C void JITAPI
244iJIT_RegisterCallbackEx(void *userdata, iJIT_ModeChangedEx
245 NewModeCallBackFuncEx)
246{
247 /* is it already missing... or the load of functions from the DLL failed */
248 if (iJIT_DLL_is_missing || !loadiJIT_Funcs())
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 */
262ITT_EXTERN_C iJIT_IsProfilingActiveFlags JITAPI iJIT_IsProfilingActive()
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 */
277static 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 */
292 iJIT_DLL_is_missing = 1;
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)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)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
393 executionMode = (iJIT_IsProfilingActiveFlags)FUNC_Initialize();
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 */
402 if ( executionMode == iJIT_CALLGRAPH_ON )
403 {
404 /* Allocate a thread local storage slot for the thread "stack" */
405 if (!threadLocalStorageHandle)
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 */
420ITT_EXTERN_C void JITAPI FinalizeThread()
421{
422 if (threadLocalStorageHandle)
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*/
448ITT_EXTERN_C void JITAPI FinalizeProcess()
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
460 if (threadLocalStorageHandle)
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 */
473ITT_EXTERN_C unsigned int JITAPI iJIT_GetNewMethodID()
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}