Home | History | Annotate | Download | only in vtune
      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 
     72 static 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"
     86 HINSTANCE m_libHandle = NULL;
     87 #else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
     88 #define DEFAULT_DLLNAME			"libJitPI.so"
     89 void* 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 */
     96 typedef unsigned int(*TPInitialize)(void);
     97 static TPInitialize FUNC_Initialize=NULL;
     98 
     99 typedef unsigned int(*TPNotify)(unsigned int, void*);
    100 static TPNotify FUNC_NotifyEvent=NULL;
    101 
    102 static 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 */
    112 static int loadiJIT_Funcs(void);
    113 
    114 /* global representing whether the BistroJavaCollector can't be loaded */
    115 static 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
    125 static DWORD threadLocalStorageHandle = 0;
    126 #else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
    127 static pthread_key_t threadLocalStorageHandle = (pthread_key_t)0;
    128 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
    129 
    130 #define INIT_TOP_Stack 10000
    131 
    132 typedef 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 
    151 ITT_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 
    271 ITT_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 */
    286 ITT_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 */
    300 static 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 */
    439 ITT_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 */
    465 ITT_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 */
    490 ITT_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