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