Path: blob/main/contrib/llvm-project/llvm/lib/ExecutionEngine/IntelJITProfiling/jitprofiling.c
35271 views
/*===-- jitprofiling.c - JIT (Just-In-Time) Profiling API----------*- C -*-===*1*2* Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3* See https://llvm.org/LICENSE.txt for license information.4* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5*6*===----------------------------------------------------------------------===*7*8* This file provides Intel(R) Performance Analyzer JIT (Just-In-Time)9* Profiling API implementation.10*11* NOTE: This file comes in a style different from the rest of LLVM12* source base since this is a piece of code shared from Intel(R)13* products. Please do not reformat / re-style this code to make14* subsequent merges and contributions from the original source base eaiser.15*16*===----------------------------------------------------------------------===*/17#include "ittnotify_config.h"1819#if ITT_PLATFORM==ITT_PLATFORM_WIN20#include <windows.h>21#pragma optimize("", off)22#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */23#include <dlfcn.h>24#include <pthread.h>25#include <stdint.h>26#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */27#include <stdlib.h>2829#include "jitprofiling.h"3031static const char rcsid[] = "\n@(#) $Revision: 243501 $\n";3233#define DLL_ENVIRONMENT_VAR "VS_PROFILER"3435#ifndef NEW_DLL_ENVIRONMENT_VAR36#if ITT_ARCH==ITT_ARCH_IA3237#define NEW_DLL_ENVIRONMENT_VAR "INTEL_JIT_PROFILER32"38#else39#define NEW_DLL_ENVIRONMENT_VAR "INTEL_JIT_PROFILER64"40#endif41#endif /* NEW_DLL_ENVIRONMENT_VAR */4243#if ITT_PLATFORM==ITT_PLATFORM_WIN44#define DEFAULT_DLLNAME "JitPI.dll"45HINSTANCE m_libHandle = NULL;46#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */47#define DEFAULT_DLLNAME "libJitPI.so"48void* m_libHandle = NULL;49#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */5051/* default location of JIT profiling agent on Android */52#define ANDROID_JIT_AGENT_PATH "/data/intel/libittnotify.so"5354/* the function pointers */55typedef unsigned int(*TPInitialize)(void);56static TPInitialize FUNC_Initialize=NULL;5758typedef unsigned int(*TPNotify)(unsigned int, void*);59static TPNotify FUNC_NotifyEvent=NULL;6061static iJIT_IsProfilingActiveFlags executionMode = iJIT_NOTHING_RUNNING;6263/* end collector dll part. */6465/* loadiJIT_Funcs() : this function is called just in the beginning66* and is responsible to load the functions from BistroJavaCollector.dll67* result:68* on success: the functions loads, iJIT_DLL_is_missing=0, return value = 169* on failure: the functions are NULL, iJIT_DLL_is_missing=1, return value = 070*/71static int loadiJIT_Funcs(void);7273/* global representing whether the BistroJavaCollector can't be loaded */74static int iJIT_DLL_is_missing = 0;7576/* Virtual stack - the struct is used as a virtual stack for each thread.77* Every thread initializes with a stack of size INIT_TOP_STACK.78* Every method entry decreases from the current stack point,79* and when a thread stack reaches its top of stack (return from the global80* function), the top of stack and the current stack increase. Notice that81* when returning from a function the stack pointer is the address of82* the function return.83*/84#if ITT_PLATFORM==ITT_PLATFORM_WIN85static DWORD threadLocalStorageHandle = 0;86#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */87static pthread_key_t threadLocalStorageHandle = (pthread_key_t)0;88#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */8990#define INIT_TOP_Stack 100009192typedef struct93{94unsigned int TopStack;95unsigned int CurrentStack;96} ThreadStack, *pThreadStack;9798/* end of virtual stack. */99100/*101* The function for reporting virtual-machine related events to VTune.102* Note: when reporting iJVM_EVENT_TYPE_ENTER_NIDS, there is no need to fill103* in the stack_id field in the iJIT_Method_NIDS structure, as VTune fills it.104* The return value in iJVM_EVENT_TYPE_ENTER_NIDS &&105* iJVM_EVENT_TYPE_LEAVE_NIDS events will be 0 in case of failure.106* in iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED event107* it will be -1 if EventSpecificData == 0 otherwise it will be 0.108*/109110ITT_EXTERN_C int JITAPI111iJIT_NotifyEvent(iJIT_JVM_EVENT event_type, void *EventSpecificData)112{113int ReturnValue;114115/*116* This section is for debugging outside of VTune.117* It creates the environment variables that indicates call graph mode.118* If running outside of VTune remove the remark.119*120*121* static int firstTime = 1;122* char DoCallGraph[12] = "DoCallGraph";123* if (firstTime)124* {125* firstTime = 0;126* SetEnvironmentVariable( "BISTRO_COLLECTORS_DO_CALLGRAPH", DoCallGraph);127* }128*129* end of section.130*/131132/* initialization part - the functions have not been loaded yet. This part133* will load the functions, and check if we are in Call Graph mode.134* (for special treatment).135*/136if (!FUNC_NotifyEvent)137{138if (iJIT_DLL_is_missing)139return 0;140141/* load the Function from the DLL */142if (!loadiJIT_Funcs())143return 0;144145/* Call Graph initialization. */146}147148/* If the event is method entry/exit, check that in the current mode149* VTune is allowed to receive it150*/151if ((event_type == iJVM_EVENT_TYPE_ENTER_NIDS ||152event_type == iJVM_EVENT_TYPE_LEAVE_NIDS) &&153(executionMode != iJIT_CALLGRAPH_ON))154{155return 0;156}157/* This section is performed when method enter event occurs.158* It updates the virtual stack, or creates it if this is the first159* method entry in the thread. The stack pointer is decreased.160*/161if (event_type == iJVM_EVENT_TYPE_ENTER_NIDS)162{163#if ITT_PLATFORM==ITT_PLATFORM_WIN164pThreadStack threadStack =165(pThreadStack)TlsGetValue (threadLocalStorageHandle);166#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */167pThreadStack threadStack =168(pThreadStack)pthread_getspecific(threadLocalStorageHandle);169#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */170171/* check for use of reserved method IDs */172if ( ((piJIT_Method_NIDS) EventSpecificData)->method_id <= 999 )173return 0;174175if (!threadStack)176{177/* initialize the stack. */178threadStack = (pThreadStack) calloc (sizeof(ThreadStack), 1);179threadStack->TopStack = INIT_TOP_Stack;180threadStack->CurrentStack = INIT_TOP_Stack;181#if ITT_PLATFORM==ITT_PLATFORM_WIN182TlsSetValue(threadLocalStorageHandle,(void*)threadStack);183#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */184pthread_setspecific(threadLocalStorageHandle,(void*)threadStack);185#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */186}187188/* decrease the stack. */189((piJIT_Method_NIDS) EventSpecificData)->stack_id =190(threadStack->CurrentStack)--;191}192193/* This section is performed when method leave event occurs194* It updates the virtual stack.195* Increases the stack pointer.196* If the stack pointer reached the top (left the global function)197* increase the pointer and the top pointer.198*/199if (event_type == iJVM_EVENT_TYPE_LEAVE_NIDS)200{201#if ITT_PLATFORM==ITT_PLATFORM_WIN202pThreadStack threadStack =203(pThreadStack)TlsGetValue (threadLocalStorageHandle);204#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */205pThreadStack threadStack =206(pThreadStack)pthread_getspecific(threadLocalStorageHandle);207#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */208209/* check for use of reserved method IDs */210if ( ((piJIT_Method_NIDS) EventSpecificData)->method_id <= 999 )211return 0;212213if (!threadStack)214{215/* Error: first report in this thread is method exit */216exit (1);217}218219((piJIT_Method_NIDS) EventSpecificData)->stack_id =220++(threadStack->CurrentStack) + 1;221222if (((piJIT_Method_NIDS) EventSpecificData)->stack_id223> threadStack->TopStack)224((piJIT_Method_NIDS) EventSpecificData)->stack_id =225(unsigned int)-1;226}227228if (event_type == iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED)229{230/* check for use of reserved method IDs */231if ( ((piJIT_Method_Load) EventSpecificData)->method_id <= 999 )232return 0;233}234235ReturnValue = (int)FUNC_NotifyEvent(event_type, EventSpecificData);236237return ReturnValue;238}239240/* The new mode call back routine */241ITT_EXTERN_C void JITAPI242iJIT_RegisterCallbackEx(void *userdata, iJIT_ModeChangedEx243NewModeCallBackFuncEx)244{245/* is it already missing... or the load of functions from the DLL failed */246if (iJIT_DLL_is_missing || !loadiJIT_Funcs())247{248/* then do not bother with notifications */249NewModeCallBackFuncEx(userdata, iJIT_NO_NOTIFICATIONS);250/* Error: could not load JIT functions. */251return;252}253/* nothing to do with the callback */254}255256/*257* This function allows the user to query in which mode, if at all,258*VTune is running259*/260ITT_EXTERN_C iJIT_IsProfilingActiveFlags JITAPI iJIT_IsProfilingActive(void)261{262if (!iJIT_DLL_is_missing)263{264loadiJIT_Funcs();265}266267return executionMode;268}269270/* this function loads the collector dll (BistroJavaCollector)271* and the relevant functions.272* on success: all functions load, iJIT_DLL_is_missing = 0, return value = 1273* on failure: all functions are NULL, iJIT_DLL_is_missing = 1, return value = 0274*/275static int loadiJIT_Funcs(void)276{277static int bDllWasLoaded = 0;278char *dllName = (char*)rcsid; /* !! Just to avoid unused code elimination */279#if ITT_PLATFORM==ITT_PLATFORM_WIN280DWORD dNameLength = 0;281#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */282283if(bDllWasLoaded)284{285/* dll was already loaded, no need to do it for the second time */286return 1;287}288289/* Assumes that the DLL will not be found */290iJIT_DLL_is_missing = 1;291FUNC_NotifyEvent = NULL;292293if (m_libHandle)294{295#if ITT_PLATFORM==ITT_PLATFORM_WIN296FreeLibrary(m_libHandle);297#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */298dlclose(m_libHandle);299#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */300m_libHandle = NULL;301}302303/* Try to get the dll name from the environment */304#if ITT_PLATFORM==ITT_PLATFORM_WIN305dNameLength = GetEnvironmentVariableA(NEW_DLL_ENVIRONMENT_VAR, NULL, 0);306if (dNameLength)307{308DWORD envret = 0;309dllName = (char*)malloc(sizeof(char) * (dNameLength + 1));310envret = GetEnvironmentVariableA(NEW_DLL_ENVIRONMENT_VAR,311dllName, dNameLength);312if (envret)313{314/* Try to load the dll from the PATH... */315m_libHandle = LoadLibraryExA(dllName,316NULL, LOAD_WITH_ALTERED_SEARCH_PATH);317}318free(dllName);319} else {320/* Try to use old VS_PROFILER variable */321dNameLength = GetEnvironmentVariableA(DLL_ENVIRONMENT_VAR, NULL, 0);322if (dNameLength)323{324DWORD envret = 0;325dllName = (char*)malloc(sizeof(char) * (dNameLength + 1));326envret = GetEnvironmentVariableA(DLL_ENVIRONMENT_VAR,327dllName, dNameLength);328if (envret)329{330/* Try to load the dll from the PATH... */331m_libHandle = LoadLibraryA(dllName);332}333free(dllName);334}335}336#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */337dllName = getenv(NEW_DLL_ENVIRONMENT_VAR);338if (!dllName)339dllName = getenv(DLL_ENVIRONMENT_VAR);340#ifdef ANDROID341if (!dllName)342dllName = ANDROID_JIT_AGENT_PATH;343#endif344if (dllName)345{346/* Try to load the dll from the PATH... */347m_libHandle = dlopen(dllName, RTLD_LAZY);348}349#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */350351if (!m_libHandle)352{353#if ITT_PLATFORM==ITT_PLATFORM_WIN354m_libHandle = LoadLibraryA(DEFAULT_DLLNAME);355#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */356m_libHandle = dlopen(DEFAULT_DLLNAME, RTLD_LAZY);357#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */358}359360/* if the dll wasn't loaded - exit. */361if (!m_libHandle)362{363iJIT_DLL_is_missing = 1; /* don't try to initialize364* JIT agent the second time365*/366return 0;367}368369#if ITT_PLATFORM==ITT_PLATFORM_WIN370FUNC_NotifyEvent = (TPNotify)GetProcAddress(m_libHandle, "NotifyEvent");371#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */372FUNC_NotifyEvent = (TPNotify)(intptr_t)dlsym(m_libHandle, "NotifyEvent");373#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */374if (!FUNC_NotifyEvent)375{376FUNC_Initialize = NULL;377return 0;378}379380#if ITT_PLATFORM==ITT_PLATFORM_WIN381FUNC_Initialize = (TPInitialize)GetProcAddress(m_libHandle, "Initialize");382#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */383FUNC_Initialize = (TPInitialize)(intptr_t)dlsym(m_libHandle, "Initialize");384#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */385if (!FUNC_Initialize)386{387FUNC_NotifyEvent = NULL;388return 0;389}390391executionMode = (iJIT_IsProfilingActiveFlags)FUNC_Initialize();392393bDllWasLoaded = 1;394iJIT_DLL_is_missing = 0; /* DLL is ok. */395396/*397* Call Graph mode: init the thread local storage398* (need to store the virtual stack there).399*/400if ( executionMode == iJIT_CALLGRAPH_ON )401{402/* Allocate a thread local storage slot for the thread "stack" */403if (!threadLocalStorageHandle)404#if ITT_PLATFORM==ITT_PLATFORM_WIN405threadLocalStorageHandle = TlsAlloc();406#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */407pthread_key_create(&threadLocalStorageHandle, NULL);408#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */409}410411return 1;412}413414/*415* This function should be called by the user whenever a thread ends,416* to free the thread "virtual stack" storage417*/418ITT_EXTERN_C void JITAPI FinalizeThread(void)419{420if (threadLocalStorageHandle)421{422#if ITT_PLATFORM==ITT_PLATFORM_WIN423pThreadStack threadStack =424(pThreadStack)TlsGetValue (threadLocalStorageHandle);425#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */426pThreadStack threadStack =427(pThreadStack)pthread_getspecific(threadLocalStorageHandle);428#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */429if (threadStack)430{431free (threadStack);432threadStack = NULL;433#if ITT_PLATFORM==ITT_PLATFORM_WIN434TlsSetValue (threadLocalStorageHandle, threadStack);435#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */436pthread_setspecific(threadLocalStorageHandle, threadStack);437#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */438}439}440}441442/*443* This function should be called by the user when the process ends,444* to free the local storage index445*/446ITT_EXTERN_C void JITAPI FinalizeProcess(void)447{448if (m_libHandle)449{450#if ITT_PLATFORM==ITT_PLATFORM_WIN451FreeLibrary(m_libHandle);452#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */453dlclose(m_libHandle);454#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */455m_libHandle = NULL;456}457458if (threadLocalStorageHandle)459#if ITT_PLATFORM==ITT_PLATFORM_WIN460TlsFree (threadLocalStorageHandle);461#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */462pthread_key_delete(threadLocalStorageHandle);463#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */464}465466/*467* This function should be called by the user for any method once.468* The function will return a unique method ID, the user should maintain469* the ID for each method470*/471ITT_EXTERN_C unsigned int JITAPI iJIT_GetNewMethodID(void)472{473static unsigned int methodID = 0x100000;474475if (methodID == 0)476return 0; /* ERROR : this is not a valid value */477478return methodID++;479}480481482