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
34static 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"
48HINSTANCE m_libHandle = NULL;
49#else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
50#define DEFAULT_DLLNAME                 "libJitPI.so"
51void* 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 */
58typedef unsigned int(*TPInitialize)(void);
59static TPInitialize FUNC_Initialize=NULL;
60
61typedef unsigned int(*TPNotify)(unsigned int, void*);
62static TPNotify FUNC_NotifyEvent=NULL;
63
64static 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 */
74static int loadiJIT_Funcs(void);
75
76/* global representing whether the BistroJavaCollector can't be loaded */
77static 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
88static DWORD threadLocalStorageHandle = 0;
89#else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
90static pthread_key_t threadLocalStorageHandle = (pthread_key_t)0;
91#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
92
93#define INIT_TOP_Stack 10000
94
95typedef 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
113ITT_EXTERN_C int JITAPI
114iJIT_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 */
244ITT_EXTERN_C void JITAPI
245iJIT_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 */
263ITT_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 */
278static 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 */
421ITT_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*/
449ITT_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 */
474ITT_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