1/*
2  This file is provided under a dual BSD/GPLv2 license.  When using or
3  redistributing this file, you may do so under either license.
4
5  GPL LICENSE SUMMARY
6
7  Copyright(c) 2005-2012 Intel Corporation. All rights reserved.
8
9  This program is free software; you can redistribute it and/or modify
10  it under the terms of version 2 of the GNU General Public License as
11  published by the Free Software Foundation.
12
13  This program is distributed in the hope that it will be useful, but
14  WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  General Public License for more details.
17
18  You should have received a copy of the GNU General Public License
19  along with this program; if not, write to the Free Software
20  Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
21  The full GNU General Public License is included in this distribution
22  in the file called LICENSE.GPL.
23
24  Contact Information:
25  http://software.intel.com/en-us/articles/intel-vtune-amplifier-xe/
26
27  BSD LICENSE
28
29  Copyright(c) 2005-2012 Intel Corporation. All rights reserved.
30  All rights reserved.
31
32  Redistribution and use in source and binary forms, with or without
33  modification, are permitted provided that the following conditions
34  are met:
35
36    * Redistributions of source code must retain the above copyright
37      notice, this list of conditions and the following disclaimer.
38    * Redistributions in binary form must reproduce the above copyright
39      notice, this list of conditions and the following disclaimer in
40      the documentation and/or other materials provided with the
41      distribution.
42    * Neither the name of Intel Corporation nor the names of its
43      contributors may be used to endorse or promote products derived
44      from this software without specific prior written permission.
45
46  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
47  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
48  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
49  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
50  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
51  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
52  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
53  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
54  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
55  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
56  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
57*/
58#include "ittnotify_config.h"
59
60#if ITT_PLATFORM==ITT_PLATFORM_WIN
61#include <windows.h>
62#pragma optimize("", off)
63#else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
64#include <pthread.h>
65#include <dlfcn.h>
66#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
67#include <malloc.h>
68#include <stdlib.h>
69
70#include "jitprofiling.h"
71
72static const char rcsid[] = "\n@(#) $Revision: 234474 $\n";
73
74#define DLL_ENVIRONMENT_VAR		"VS_PROFILER"
75
76#ifndef NEW_DLL_ENVIRONMENT_VAR
77#if ITT_ARCH==ITT_ARCH_IA32
78#define NEW_DLL_ENVIRONMENT_VAR		"INTEL_JIT_PROFILER32"
79#else
80#define NEW_DLL_ENVIRONMENT_VAR		"INTEL_JIT_PROFILER64"
81#endif
82#endif /* NEW_DLL_ENVIRONMENT_VAR */
83
84#if ITT_PLATFORM==ITT_PLATFORM_WIN
85#define DEFAULT_DLLNAME			"JitPI.dll"
86HINSTANCE m_libHandle = NULL;
87#else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
88#define DEFAULT_DLLNAME			"libJitPI.so"
89void* m_libHandle = NULL;
90#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
91
92/* default location of JIT profiling agent on Android */
93#define ANDROID_JIT_AGENT_PATH  "/data/intel/libittnotify.so"
94
95/* the function pointers */
96typedef unsigned int(*TPInitialize)(void);
97static TPInitialize FUNC_Initialize=NULL;
98
99typedef unsigned int(*TPNotify)(unsigned int, void*);
100static TPNotify FUNC_NotifyEvent=NULL;
101
102static iJIT_IsProfilingActiveFlags executionMode = iJIT_NOTHING_RUNNING;
103
104/* end collector dll part. */
105
106/* loadiJIT_Funcs() : this function is called just in the beginning and is responsible
107** to load the functions from BistroJavaCollector.dll
108** result:
109**		on success: the functions loads,    iJIT_DLL_is_missing=0, return value = 1.
110**		on failure: the functions are NULL, iJIT_DLL_is_missing=1, return value = 0.
111*/
112static int loadiJIT_Funcs(void);
113
114/* global representing whether the BistroJavaCollector can't be loaded */
115static int iJIT_DLL_is_missing = 0;
116
117/* Virtual stack - the struct is used as a virtual stack for each thread.
118** Every thread initializes with a stack of size INIT_TOP_STACK.
119** Every method entry decreases from the current stack point,
120** and when a thread stack reaches its top of stack (return from the global function),
121** the top of stack and the current stack increase. Notice that when returning from a function
122** the stack pointer is the address of the function return.
123*/
124#if ITT_PLATFORM==ITT_PLATFORM_WIN
125static DWORD threadLocalStorageHandle = 0;
126#else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
127static pthread_key_t threadLocalStorageHandle = (pthread_key_t)0;
128#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
129
130#define INIT_TOP_Stack 10000
131
132typedef struct
133{
134    unsigned int TopStack;
135    unsigned int CurrentStack;
136} ThreadStack, *pThreadStack;
137
138/* end of virtual stack. */
139
140/*
141** The function for reporting virtual-machine related events to VTune.
142** Note: when reporting iJVM_EVENT_TYPE_ENTER_NIDS, there is no need to fill in the stack_id
143** field in the iJIT_Method_NIDS structure, as VTune fills it.
144**
145** The return value in iJVM_EVENT_TYPE_ENTER_NIDS && iJVM_EVENT_TYPE_LEAVE_NIDS events
146** will be 0 in case of failure.
147** in iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED event it will be -1 if EventSpecificData == 0
148** otherwise it will be 0.
149*/
150
151ITT_EXTERN_C int JITAPI iJIT_NotifyEvent(iJIT_JVM_EVENT event_type, void *EventSpecificData)
152{
153    int ReturnValue;
154
155    /*******************************************************************************
156    ** This section is for debugging outside of VTune.
157    ** It creates the environment variables that indicates call graph mode.
158    ** If running outside of VTune remove the remark.
159    **
160
161      static int firstTime = 1;
162      char DoCallGraph[12] = "DoCallGraph";
163      if (firstTime)
164      {
165      firstTime = 0;
166      SetEnvironmentVariable( "BISTRO_COLLECTORS_DO_CALLGRAPH", DoCallGraph);
167      }
168
169    ** end of section.
170    *******************************************************************************/
171
172    /* initialization part - the functions have not been loaded yet. This part
173    **		will load the functions, and check if we are in Call Graph mode.
174    **		(for special treatment).
175    */
176    if (!FUNC_NotifyEvent)
177    {
178        if (iJIT_DLL_is_missing)
179            return 0;
180
181        // load the Function from the DLL
182        if (!loadiJIT_Funcs())
183            return 0;
184
185        /* Call Graph initialization. */
186    }
187
188    /* If the event is method entry/exit, check that in the current mode
189    ** VTune is allowed to receive it
190    */
191    if ((event_type == iJVM_EVENT_TYPE_ENTER_NIDS || event_type == iJVM_EVENT_TYPE_LEAVE_NIDS) &&
192        (executionMode != iJIT_CALLGRAPH_ON))
193    {
194        return 0;
195    }
196    /* This section is performed when method enter event occurs.
197    ** It updates the virtual stack, or creates it if this is the first
198    ** method entry in the thread. The stack pointer is decreased.
199    */
200    if (event_type == iJVM_EVENT_TYPE_ENTER_NIDS)
201    {
202#if ITT_PLATFORM==ITT_PLATFORM_WIN
203        pThreadStack threadStack = (pThreadStack)TlsGetValue (threadLocalStorageHandle);
204#else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
205        pThreadStack threadStack = (pThreadStack)pthread_getspecific(threadLocalStorageHandle);
206#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
207
208        // check for use of reserved method IDs
209        if ( ((piJIT_Method_NIDS) EventSpecificData)->method_id <= 999 )
210            return 0;
211
212        if (!threadStack)
213        {
214            // initialize the stack.
215            threadStack = (pThreadStack) calloc (sizeof(ThreadStack), 1);
216            threadStack->TopStack = INIT_TOP_Stack;
217            threadStack->CurrentStack = INIT_TOP_Stack;
218#if ITT_PLATFORM==ITT_PLATFORM_WIN
219            TlsSetValue(threadLocalStorageHandle,(void*)threadStack);
220#else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
221            pthread_setspecific(threadLocalStorageHandle,(void*)threadStack);
222#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
223        }
224
225        // decrease the stack.
226        ((piJIT_Method_NIDS) EventSpecificData)->stack_id = (threadStack->CurrentStack)--;
227    }
228
229    /* This section is performed when method leave event occurs
230    ** It updates the virtual stack.
231    **		Increases the stack pointer.
232    **		If the stack pointer reached the top (left the global function)
233    **			increase the pointer and the top pointer.
234    */
235    if (event_type == iJVM_EVENT_TYPE_LEAVE_NIDS)
236    {
237#if ITT_PLATFORM==ITT_PLATFORM_WIN
238        pThreadStack threadStack = (pThreadStack)TlsGetValue (threadLocalStorageHandle);
239#else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
240        pThreadStack threadStack = (pThreadStack)pthread_getspecific(threadLocalStorageHandle);
241#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
242
243        // check for use of reserved method IDs
244        if ( ((piJIT_Method_NIDS) EventSpecificData)->method_id <= 999 )
245            return 0;
246
247        if (!threadStack)
248        {
249            /* Error: first report in this thread is method exit */
250            exit (1);
251        }
252
253        ((piJIT_Method_NIDS) EventSpecificData)->stack_id = ++(threadStack->CurrentStack) + 1;
254
255        if (((piJIT_Method_NIDS) EventSpecificData)->stack_id > threadStack->TopStack)
256            ((piJIT_Method_NIDS) EventSpecificData)->stack_id = (unsigned int)-1;
257    }
258
259    if (event_type == iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED)
260    {
261        // check for use of reserved method IDs
262        if ( ((piJIT_Method_Load) EventSpecificData)->method_id <= 999 )
263            return 0;
264    }
265
266    ReturnValue = (int)FUNC_NotifyEvent(event_type, EventSpecificData);
267
268    return ReturnValue;
269}
270
271ITT_EXTERN_C void JITAPI iJIT_RegisterCallbackEx(void *userdata, iJIT_ModeChangedEx NewModeCallBackFuncEx) // The new mode call back routine
272{
273    // is it already missing... or the load of functions from the DLL failed
274    if (iJIT_DLL_is_missing || !loadiJIT_Funcs())
275    {
276        NewModeCallBackFuncEx(userdata, iJIT_NO_NOTIFICATIONS);  // then do not bother with notifications
277        /* Error: could not load JIT functions. */
278        return;
279    }
280    // nothing to do with the callback
281}
282
283/*
284** This function allows the user to query in which mode, if at all, VTune is running
285*/
286ITT_EXTERN_C iJIT_IsProfilingActiveFlags JITAPI iJIT_IsProfilingActive()
287{
288    if (!iJIT_DLL_is_missing)
289    {
290        loadiJIT_Funcs();
291    }
292
293    return executionMode;
294}
295#include <stdio.h>
296/* this function loads the collector dll (BistroJavaCollector) and the relevant functions.
297** on success: all functions load,     iJIT_DLL_is_missing = 0, return value = 1.
298** on failure: all functions are NULL, iJIT_DLL_is_missing = 1, return value = 0.
299*/
300static int loadiJIT_Funcs()
301{
302    static int bDllWasLoaded = 0;
303    char *dllName = (char*)rcsid; // !!! Just to avoid unused code elimination !!!
304#if ITT_PLATFORM==ITT_PLATFORM_WIN
305    DWORD dNameLength = 0;
306#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
307
308    if(bDllWasLoaded)
309    {// dll was already loaded, no need to do it for the second time
310        return 1;
311    }
312
313    // Assumes that the DLL will not be found
314    iJIT_DLL_is_missing = 1;
315    FUNC_NotifyEvent = NULL;
316
317    if (m_libHandle)
318    {
319#if ITT_PLATFORM==ITT_PLATFORM_WIN
320        FreeLibrary(m_libHandle);
321#else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
322        dlclose(m_libHandle);
323#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
324        m_libHandle = NULL;
325    }
326
327    // try to get the dll name from the environment
328#if ITT_PLATFORM==ITT_PLATFORM_WIN
329    dNameLength = GetEnvironmentVariableA(NEW_DLL_ENVIRONMENT_VAR, NULL, 0);
330    if (dNameLength)
331    {
332        DWORD envret = 0;
333        dllName = (char*)malloc(sizeof(char) * (dNameLength + 1));
334        envret = GetEnvironmentVariableA(NEW_DLL_ENVIRONMENT_VAR, dllName, dNameLength);
335        if (envret)
336        {
337            // Try to load the dll from the PATH...
338            m_libHandle = LoadLibraryExA(dllName, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
339        }
340        free(dllName);
341    } else {
342        // Try to use old VS_PROFILER variable
343        dNameLength = GetEnvironmentVariableA(DLL_ENVIRONMENT_VAR, NULL, 0);
344        if (dNameLength)
345        {
346            DWORD envret = 0;
347            dllName = (char*)malloc(sizeof(char) * (dNameLength + 1));
348            envret = GetEnvironmentVariableA(DLL_ENVIRONMENT_VAR, dllName, dNameLength);
349            if (envret)
350            {
351                // Try to load the dll from the PATH...
352                m_libHandle = LoadLibraryA(dllName);
353            }
354            free(dllName);
355        }
356    }
357#else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
358    dllName = getenv(NEW_DLL_ENVIRONMENT_VAR);
359    if (!dllName) {
360        dllName = getenv(DLL_ENVIRONMENT_VAR);
361    }
362#ifdef ANDROID
363    if (!dllName)
364        dllName = ANDROID_JIT_AGENT_PATH;
365#endif
366    if (dllName)
367    {
368        // Try to load the dll from the PATH...
369        m_libHandle = dlopen(dllName, RTLD_LAZY);
370    }
371#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
372
373    if (!m_libHandle)
374    {
375#if ITT_PLATFORM==ITT_PLATFORM_WIN
376        m_libHandle = LoadLibraryA(DEFAULT_DLLNAME);
377#else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
378        m_libHandle = dlopen(DEFAULT_DLLNAME, RTLD_LAZY);
379#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
380    }
381
382    // if the dll wasn't loaded - exit.
383    if (!m_libHandle)
384    {
385        iJIT_DLL_is_missing = 1; // don't try to initialize JIT agent the second time
386        return 0;
387    }
388#if ITT_PLATFORM==ITT_PLATFORM_WIN
389    FUNC_NotifyEvent = (TPNotify)GetProcAddress(m_libHandle, "NotifyEvent");
390#else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
391    FUNC_NotifyEvent = reinterpret_cast<TPNotify>(reinterpret_cast<intptr_t>(dlsym(m_libHandle, "NotifyEvent")));
392#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
393    if (!FUNC_NotifyEvent)
394    {
395        FUNC_Initialize = NULL;
396        return 0;
397    }
398
399#if ITT_PLATFORM==ITT_PLATFORM_WIN
400    FUNC_Initialize = (TPInitialize)GetProcAddress(m_libHandle, "Initialize");
401#else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
402    FUNC_Initialize = reinterpret_cast<TPInitialize>(reinterpret_cast<intptr_t>(dlsym(m_libHandle, "Initialize")));
403#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
404    if (!FUNC_Initialize)
405    {
406        FUNC_NotifyEvent = NULL;
407        return 0;
408    }
409
410    executionMode = (iJIT_IsProfilingActiveFlags)FUNC_Initialize();
411    if (executionMode != iJIT_SAMPLING_ON)
412      executionMode = iJIT_SAMPLING_ON;
413
414    bDllWasLoaded = 1;
415    iJIT_DLL_is_missing = 0; // DLL is ok.
416
417    /*
418    ** Call Graph mode: init the thread local storage
419    ** (need to store the virtual stack there).
420    */
421    if ( executionMode == iJIT_CALLGRAPH_ON )
422    {
423        // Allocate a thread local storage slot for the thread "stack"
424        if (!threadLocalStorageHandle)
425#if ITT_PLATFORM==ITT_PLATFORM_WIN
426            threadLocalStorageHandle = TlsAlloc();
427#else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
428        pthread_key_create(&threadLocalStorageHandle, NULL);
429#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
430    }
431
432    return 1;
433}
434
435/*
436** This function should be called by the user whenever a thread ends, to free the thread
437** "virtual stack" storage
438*/
439ITT_EXTERN_C void JITAPI FinalizeThread()
440{
441    if (threadLocalStorageHandle)
442    {
443#if ITT_PLATFORM==ITT_PLATFORM_WIN
444        pThreadStack threadStack = (pThreadStack)TlsGetValue (threadLocalStorageHandle);
445#else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
446        pThreadStack threadStack = (pThreadStack)pthread_getspecific(threadLocalStorageHandle);
447#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
448        if (threadStack)
449        {
450            free (threadStack);
451            threadStack = NULL;
452#if ITT_PLATFORM==ITT_PLATFORM_WIN
453            TlsSetValue (threadLocalStorageHandle, threadStack);
454#else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
455            pthread_setspecific(threadLocalStorageHandle, threadStack);
456#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
457        }
458    }
459}
460
461/*
462** This function should be called by the user when the process ends, to free the local
463** storage index
464*/
465ITT_EXTERN_C void JITAPI FinalizeProcess()
466{
467    if (m_libHandle)
468    {
469#if ITT_PLATFORM==ITT_PLATFORM_WIN
470        FreeLibrary(m_libHandle);
471#else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
472        dlclose(m_libHandle);
473#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
474        m_libHandle = NULL;
475    }
476
477    if (threadLocalStorageHandle)
478#if ITT_PLATFORM==ITT_PLATFORM_WIN
479        TlsFree (threadLocalStorageHandle);
480#else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
481    pthread_key_delete(threadLocalStorageHandle);
482#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
483}
484
485/*
486** This function should be called by the user for any method once.
487** The function will return a unique method ID, the user should maintain the ID for each
488** method
489*/
490ITT_EXTERN_C unsigned int JITAPI iJIT_GetNewMethodID()
491{
492    static unsigned int methodID = 0x100000;
493
494    if (methodID == 0)
495        return 0;	// ERROR : this is not a valid value
496
497    return methodID++;
498}
499
500