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 *===----------------------------------------------------------------------===*/
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}
477