mirror of
https://github.com/RPCS3/llvm.git
synced 2024-11-23 19:59:48 +00:00
Add profiling support for Intel Parallel Amplifier XE (VTune) for JITted code in LLVM.
Also refactor the existing OProfile profiling code to reuse the same interfaces with the VTune profiling code. In addition, unit tests for the profiling interfaces were added. This patch was prepared by Andrew Kaylor and Daniel Malea, and reviewed in the llvm-commits list by Jim Grosbach git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@152620 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
c007ba86f3
commit
61b1851a20
@ -156,6 +156,44 @@ else()
|
||||
option(LLVM_ENABLE_ASSERTIONS "Enable assertions" ON)
|
||||
endif()
|
||||
|
||||
option(LLVM_USE_INTEL_JITEVENTS
|
||||
"Use Intel JIT API to inform Intel(R) VTune(TM) Amplifier XE 2011 about JIT code"
|
||||
OFF)
|
||||
|
||||
if( LLVM_USE_INTEL_JITEVENTS )
|
||||
# Verify we are on a supported platform
|
||||
if( CMAKE_SYSTEM_NAME MATCHES "Windows" OR CMAKE_SYSTEM_NAME MATCHES "Linux" )
|
||||
# Directory where Intel Parallel Amplifier XE 2011 is installed.
|
||||
if ( WIN32 )
|
||||
set(LLVM_INTEL_JITEVENTS_DIR $ENV{VTUNE_AMPLIFIER_XE_2011_DIR})
|
||||
else ( WIN32 )
|
||||
set(LLVM_INTEL_JITEVENTS_DIR "/opt/intel/vtune_amplifier_xe_2011")
|
||||
endif ( WIN32 )
|
||||
|
||||
# Set include and library search paths for Intel JIT Events API
|
||||
set(LLVM_INTEL_JITEVENTS_INCDIR "${LLVM_INTEL_JITEVENTS_DIR}/include")
|
||||
|
||||
if ( CMAKE_SIZEOF_VOID_P EQUAL 8 )
|
||||
set(LLVM_INTEL_JITEVENTS_LIBDIR "${LLVM_INTEL_JITEVENTS_DIR}/lib64")
|
||||
else ( CMAKE_SIZEOF_VOID_P EQUAL 8 )
|
||||
set(LLVM_INTEL_JITEVENTS_LIBDIR "${LLVM_INTEL_JITEVENTS_DIR}/lib32")
|
||||
endif ( CMAKE_SIZEOF_VOID_P EQUAL 8 )
|
||||
else()
|
||||
message(FATAL_ERROR
|
||||
"Intel JIT API support is available on Linux and Windows only.")
|
||||
endif()
|
||||
endif( LLVM_USE_INTEL_JITEVENTS )
|
||||
|
||||
option(LLVM_USE_OPROFILE
|
||||
"Use opagent JIT interface to inform OProfile about JIT code" OFF)
|
||||
|
||||
# If enabled, ierify we are on a platform that supports oprofile.
|
||||
if( LLVM_USE_OPROFILE )
|
||||
if( NOT CMAKE_SYSTEM_NAME MATCHES "Linux" )
|
||||
message(FATAL_ERROR "OProfile support is available on Linux only.")
|
||||
endif( NOT CMAKE_SYSTEM_NAME MATCHES "Linux" )
|
||||
endif( LLVM_USE_OPROFILE )
|
||||
|
||||
# Define an option controlling whether we should build for 32-bit on 64-bit
|
||||
# platforms, where supported.
|
||||
if( CMAKE_SIZEOF_VOID_P EQUAL 8 AND NOT WIN32 )
|
||||
|
@ -343,3 +343,11 @@ LLVM_HAS_POLLY = @LLVM_HAS_POLLY@
|
||||
# Flags supported by the linker.
|
||||
# bfd ld / gold --version-script=file
|
||||
HAVE_LINK_VERSION_SCRIPT = @HAVE_LINK_VERSION_SCRIPT@
|
||||
|
||||
# Flags to control building support for Intel JIT Events API
|
||||
USE_INTEL_JITEVENTS := @USE_INTEL_JITEVENTS@
|
||||
INTEL_JITEVENTS_INCDIR := @INTEL_JITEVENTS_INCDIR@
|
||||
INTEL_JITEVENTS_LIBDIR := @INTEL_JITEVENTS_LIBDIR@
|
||||
|
||||
# Flags to control building support for OProfile JIT API
|
||||
USE_OPROFILE := @USE_OPROFILE@
|
||||
|
@ -1183,29 +1183,83 @@ AC_ARG_WITH(oprofile,
|
||||
*) llvm_cv_oppath="${withval}/lib/oprofile"
|
||||
CPPFLAGS="-I${withval}/include";;
|
||||
esac
|
||||
if test -n "$llvm_cv_oppath" ; then
|
||||
LIBS="$LIBS -L${llvm_cv_oppath} -Wl,-rpath,${llvm_cv_oppath}"
|
||||
dnl Work around http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=537744:
|
||||
dnl libbfd is not included properly in libopagent in some Debian
|
||||
dnl versions. If libbfd isn't found at all, we assume opagent works
|
||||
dnl anyway.
|
||||
AC_SEARCH_LIBS(bfd_init, bfd, [], [])
|
||||
AC_SEARCH_LIBS(op_open_agent, opagent, [], [
|
||||
echo "Error! You need to have libopagent around."
|
||||
exit -1
|
||||
])
|
||||
AC_CHECK_HEADER([opagent.h], [], [
|
||||
echo "Error! You need to have opagent.h around."
|
||||
exit -1
|
||||
])
|
||||
fi
|
||||
case $llvm_cv_os_type in
|
||||
Linux)
|
||||
if test -n "$llvm_cv_oppath" ; then
|
||||
LIBS="$LIBS -lopagent -L${llvm_cv_oppath} -Wl,-rpath,${llvm_cv_oppath}"
|
||||
dnl Work around http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=537744:
|
||||
dnl libbfd is not included properly in libopagent in some Debian
|
||||
dnl versions. If libbfd isn't found at all, we assume opagent works
|
||||
dnl anyway.
|
||||
AC_SEARCH_LIBS(bfd_init, bfd, [], [])
|
||||
AC_SEARCH_LIBS(op_open_agent, opagent, [], [
|
||||
echo "Error! You need to have libopagent around."
|
||||
exit -1
|
||||
])
|
||||
AC_CHECK_HEADER([opagent.h], [], [
|
||||
echo "Error! You need to have opagent.h around."
|
||||
exit -1
|
||||
])
|
||||
fi ;;
|
||||
*)
|
||||
AC_MSG_ERROR([OProfile support is available on Linux only.]) ;;
|
||||
esac
|
||||
],
|
||||
[
|
||||
AC_SUBST(USE_OPROFILE, [0])
|
||||
])
|
||||
AC_DEFINE_UNQUOTED([USE_OPROFILE],$USE_OPROFILE,
|
||||
AC_DEFINE_UNQUOTED([LLVM_USE_OPROFILE],$USE_OPROFILE,
|
||||
[Define if we have the oprofile JIT-support library])
|
||||
|
||||
dnl Enable support for Intel JIT Events API.
|
||||
AC_ARG_WITH(intel-jitevents,
|
||||
AS_HELP_STRING([--with-intel-jitevents=<vtune-amplifier-dir>],
|
||||
[Specify location of run-time support library for Intel JIT API (default=/opt/intel/vtune_amplifier_xe_2011)]),
|
||||
[
|
||||
case $llvm_cv_os_type in
|
||||
Linux|Win32|Cygwin|MingW) ;;
|
||||
*)
|
||||
AC_MSG_ERROR([
|
||||
Intel JIT API support is available on Linux and Windows only."]) ;;
|
||||
esac
|
||||
|
||||
AC_SUBST(USE_INTEL_JITEVENTS, [1])
|
||||
case "$llvm_cv_target_arch" in
|
||||
x86) llvm_intel_jitevents_archdir="lib32";;
|
||||
x86_64) llvm_intel_jitevents_archdir="lib64";;
|
||||
*) echo "Target architecture $llvm_cv_target_arch does not support Intel JIT Events API"
|
||||
exit -1;;
|
||||
esac
|
||||
INTEL_JITEVENTS_INCDIR="/opt/intel/vtune_amplifier_xe_2011/include"
|
||||
INTEL_JITEVENTS_LIBDIR="/opt/intel/vtune_amplifier_xe_2011/$llvm_intel_jitevents_archdir"
|
||||
case "$withval" in
|
||||
/* | [[A-Za-z]]:[[\\/]]*) INTEL_JITEVENTS_INCDIR=$withval/include
|
||||
INTEL_JITEVENTS_LIBDIR=$withval/$llvm_intel_jitevents_archdir ;;
|
||||
*) ;;
|
||||
esac
|
||||
|
||||
AC_SUBST(INTEL_JITEVENTS_INCDIR)
|
||||
AC_SUBST(INTEL_JITEVENTS_LIBDIR)
|
||||
|
||||
LIBS="$LIBS -L${INTEL_JITEVENTS_LIBDIR}"
|
||||
CPPFLAGS="$CPPFLAGS -I$INTEL_JITEVENTS_INCDIR"
|
||||
|
||||
AC_SEARCH_LIBS(iJIT_IsProfilingActive, jitprofiling, [], [
|
||||
echo "Error! Cannot find libjitprofiling.a. Please check path specified in flag --with-intel-jitevents"
|
||||
exit -1
|
||||
])
|
||||
AC_CHECK_HEADER([jitprofiling.h], [], [
|
||||
echo "Error! Cannot find jitprofiling.h. Please check path specified in flag --with-intel-jitevents"
|
||||
exit -1
|
||||
])
|
||||
|
||||
],
|
||||
[
|
||||
AC_SUBST(USE_INTEL_JITEVENTS, [0])
|
||||
])
|
||||
AC_DEFINE_UNQUOTED([LLVM_USE_INTEL_JITEVENTS],$USE_INTEL_JITEVENTS,
|
||||
[Define if we have the Intel JIT API runtime support library])
|
||||
|
||||
dnl===-----------------------------------------------------------------------===
|
||||
dnl===
|
||||
dnl=== SECTION 6: Check for header files
|
||||
|
363
configure
vendored
363
configure
vendored
@ -766,6 +766,9 @@ NO_MISSING_FIELD_INITIALIZERS
|
||||
COVERED_SWITCH_DEFAULT
|
||||
USE_UDIS86
|
||||
USE_OPROFILE
|
||||
USE_INTEL_JITEVENTS
|
||||
INTEL_JITEVENTS_INCDIR
|
||||
INTEL_JITEVENTS_LIBDIR
|
||||
HAVE_PTHREAD
|
||||
HUGE_VAL_SANITY
|
||||
MMAP_FILE
|
||||
@ -1451,6 +1454,10 @@ Optional Packages:
|
||||
--with-udis86=<path> Use udis86 external x86 disassembler library
|
||||
--with-oprofile=<prefix>
|
||||
Tell OProfile >= 0.9.4 how to symbolize JIT output
|
||||
--with-intel-jitevents=<vtune-amplifier-dir>
|
||||
Specify location of run-time support library for
|
||||
Intel JIT API
|
||||
(default=/opt/intel/vtune_amplifier_xe_2011)
|
||||
|
||||
Some influential environment variables:
|
||||
CC C compiler command
|
||||
@ -10395,7 +10402,7 @@ else
|
||||
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
|
||||
lt_status=$lt_dlunknown
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 10398 "configure"
|
||||
#line 10405 "configure"
|
||||
#include "confdefs.h"
|
||||
|
||||
#if HAVE_DLFCN_H
|
||||
@ -13260,9 +13267,11 @@ if test "${with_oprofile+set}" = set; then
|
||||
*) llvm_cv_oppath="${withval}/lib/oprofile"
|
||||
CPPFLAGS="-I${withval}/include";;
|
||||
esac
|
||||
if test -n "$llvm_cv_oppath" ; then
|
||||
LIBS="$LIBS -L${llvm_cv_oppath} -Wl,-rpath,${llvm_cv_oppath}"
|
||||
{ echo "$as_me:$LINENO: checking for library containing bfd_init" >&5
|
||||
case $llvm_cv_os_type in
|
||||
Linux)
|
||||
if test -n "$llvm_cv_oppath" ; then
|
||||
LIBS="$LIBS -lopagent -L${llvm_cv_oppath} -Wl,-rpath,${llvm_cv_oppath}"
|
||||
{ echo "$as_me:$LINENO: checking for library containing bfd_init" >&5
|
||||
echo $ECHO_N "checking for library containing bfd_init... $ECHO_C" >&6; }
|
||||
if test "${ac_cv_search_bfd_init+set}" = set; then
|
||||
echo $ECHO_N "(cached) $ECHO_C" >&6
|
||||
@ -13361,7 +13370,7 @@ if test "$ac_res" != no; then
|
||||
|
||||
fi
|
||||
|
||||
{ echo "$as_me:$LINENO: checking for library containing op_open_agent" >&5
|
||||
{ echo "$as_me:$LINENO: checking for library containing op_open_agent" >&5
|
||||
echo $ECHO_N "checking for library containing op_open_agent... $ECHO_C" >&6; }
|
||||
if test "${ac_cv_search_op_open_agent+set}" = set; then
|
||||
echo $ECHO_N "(cached) $ECHO_C" >&6
|
||||
@ -13460,12 +13469,12 @@ if test "$ac_res" != no; then
|
||||
|
||||
else
|
||||
|
||||
echo "Error! You need to have libopagent around."
|
||||
exit -1
|
||||
echo "Error! You need to have libopagent around."
|
||||
exit -1
|
||||
|
||||
fi
|
||||
|
||||
if test "${ac_cv_header_opagent_h+set}" = set; then
|
||||
if test "${ac_cv_header_opagent_h+set}" = set; then
|
||||
{ echo "$as_me:$LINENO: checking for opagent.h" >&5
|
||||
echo $ECHO_N "checking for opagent.h... $ECHO_C" >&6; }
|
||||
if test "${ac_cv_header_opagent_h+set}" = set; then
|
||||
@ -13623,13 +13632,18 @@ if test $ac_cv_header_opagent_h = yes; then
|
||||
:
|
||||
else
|
||||
|
||||
echo "Error! You need to have opagent.h around."
|
||||
exit -1
|
||||
echo "Error! You need to have opagent.h around."
|
||||
exit -1
|
||||
|
||||
fi
|
||||
|
||||
|
||||
fi
|
||||
fi ;;
|
||||
*)
|
||||
{ { echo "$as_me:$LINENO: error: OProfile support is available on Linux only." >&5
|
||||
echo "$as_me: error: OProfile support is available on Linux only." >&2;}
|
||||
{ (exit 1); exit 1; }; } ;;
|
||||
esac
|
||||
|
||||
else
|
||||
|
||||
@ -13640,7 +13654,327 @@ fi
|
||||
|
||||
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define USE_OPROFILE $USE_OPROFILE
|
||||
#define LLVM_USE_OPROFILE $USE_OPROFILE
|
||||
_ACEOF
|
||||
|
||||
|
||||
|
||||
# Check whether --with-intel-jitevents was given.
|
||||
if test "${with_intel_jitevents+set}" = set; then
|
||||
withval=$with_intel_jitevents;
|
||||
case $llvm_cv_os_type in
|
||||
Linux|Win32|Cygwin|MingW) ;;
|
||||
*)
|
||||
{ { echo "$as_me:$LINENO: error:
|
||||
Intel JIT API support is available on Linux and Windows only.\"" >&5
|
||||
echo "$as_me: error:
|
||||
Intel JIT API support is available on Linux and Windows only.\"" >&2;}
|
||||
{ (exit 1); exit 1; }; } ;;
|
||||
esac
|
||||
|
||||
USE_INTEL_JITEVENTS=1
|
||||
|
||||
case "$llvm_cv_target_arch" in
|
||||
x86) llvm_intel_jitevents_archdir="lib32";;
|
||||
x86_64) llvm_intel_jitevents_archdir="lib64";;
|
||||
*) echo "Target architecture $llvm_cv_target_arch does not support Intel JIT Events API"
|
||||
exit -1;;
|
||||
esac
|
||||
INTEL_JITEVENTS_INCDIR="/opt/intel/vtune_amplifier_xe_2011/include"
|
||||
INTEL_JITEVENTS_LIBDIR="/opt/intel/vtune_amplifier_xe_2011/$llvm_intel_jitevents_archdir"
|
||||
case "$withval" in
|
||||
/* | [A-Za-z]:[\\/]*) INTEL_JITEVENTS_INCDIR=$withval/include
|
||||
INTEL_JITEVENTS_LIBDIR=$withval/$llvm_intel_jitevents_archdir ;;
|
||||
*) ;;
|
||||
|
||||
esac
|
||||
|
||||
|
||||
|
||||
|
||||
LIBS="$LIBS -L${INTEL_JITEVENTS_LIBDIR}"
|
||||
CPPFLAGS="$CPPFLAGS -I$INTEL_JITEVENTS_INCDIR"
|
||||
|
||||
{ echo "$as_me:$LINENO: checking for library containing iJIT_IsProfilingActive" >&5
|
||||
echo $ECHO_N "checking for library containing iJIT_IsProfilingActive... $ECHO_C" >&6; }
|
||||
if test "${ac_cv_search_iJIT_IsProfilingActive+set}" = set; then
|
||||
echo $ECHO_N "(cached) $ECHO_C" >&6
|
||||
else
|
||||
ac_func_search_save_LIBS=$LIBS
|
||||
cat >conftest.$ac_ext <<_ACEOF
|
||||
/* confdefs.h. */
|
||||
_ACEOF
|
||||
cat confdefs.h >>conftest.$ac_ext
|
||||
cat >>conftest.$ac_ext <<_ACEOF
|
||||
/* end confdefs.h. */
|
||||
|
||||
/* Override any GCC internal prototype to avoid an error.
|
||||
Use char because int might match the return type of a GCC
|
||||
builtin and then its argument prototype would still apply. */
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
char iJIT_IsProfilingActive ();
|
||||
int
|
||||
main ()
|
||||
{
|
||||
return iJIT_IsProfilingActive ();
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
for ac_lib in '' jitprofiling; do
|
||||
if test -z "$ac_lib"; then
|
||||
ac_res="none required"
|
||||
else
|
||||
ac_res=-l$ac_lib
|
||||
LIBS="-l$ac_lib $ac_func_search_save_LIBS"
|
||||
fi
|
||||
rm -f conftest.$ac_objext conftest$ac_exeext
|
||||
if { (ac_try="$ac_link"
|
||||
case "(($ac_try" in
|
||||
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
|
||||
*) ac_try_echo=$ac_try;;
|
||||
esac
|
||||
eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
|
||||
(eval "$ac_link") 2>conftest.er1
|
||||
ac_status=$?
|
||||
grep -v '^ *+' conftest.er1 >conftest.err
|
||||
rm -f conftest.er1
|
||||
cat conftest.err >&5
|
||||
echo "$as_me:$LINENO: \$? = $ac_status" >&5
|
||||
(exit $ac_status); } &&
|
||||
{ ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
|
||||
{ (case "(($ac_try" in
|
||||
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
|
||||
*) ac_try_echo=$ac_try;;
|
||||
esac
|
||||
eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
|
||||
(eval "$ac_try") 2>&5
|
||||
ac_status=$?
|
||||
echo "$as_me:$LINENO: \$? = $ac_status" >&5
|
||||
(exit $ac_status); }; } &&
|
||||
{ ac_try='test -s conftest$ac_exeext'
|
||||
{ (case "(($ac_try" in
|
||||
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
|
||||
*) ac_try_echo=$ac_try;;
|
||||
esac
|
||||
eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
|
||||
(eval "$ac_try") 2>&5
|
||||
ac_status=$?
|
||||
echo "$as_me:$LINENO: \$? = $ac_status" >&5
|
||||
(exit $ac_status); }; }; then
|
||||
ac_cv_search_iJIT_IsProfilingActive=$ac_res
|
||||
else
|
||||
echo "$as_me: failed program was:" >&5
|
||||
sed 's/^/| /' conftest.$ac_ext >&5
|
||||
|
||||
|
||||
fi
|
||||
|
||||
rm -f core conftest.err conftest.$ac_objext \
|
||||
conftest$ac_exeext
|
||||
if test "${ac_cv_search_iJIT_IsProfilingActive+set}" = set; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
if test "${ac_cv_search_iJIT_IsProfilingActive+set}" = set; then
|
||||
:
|
||||
else
|
||||
ac_cv_search_iJIT_IsProfilingActive=no
|
||||
fi
|
||||
rm conftest.$ac_ext
|
||||
LIBS=$ac_func_search_save_LIBS
|
||||
fi
|
||||
{ echo "$as_me:$LINENO: result: $ac_cv_search_iJIT_IsProfilingActive" >&5
|
||||
echo "${ECHO_T}$ac_cv_search_iJIT_IsProfilingActive" >&6; }
|
||||
ac_res=$ac_cv_search_iJIT_IsProfilingActive
|
||||
if test "$ac_res" != no; then
|
||||
test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
|
||||
|
||||
else
|
||||
|
||||
echo "Error! Cannot find libjitprofiling.a. Please check path specified in flag --with-intel-jitevents"
|
||||
exit -1
|
||||
|
||||
fi
|
||||
|
||||
if test "${ac_cv_header_jitprofiling_h+set}" = set; then
|
||||
{ echo "$as_me:$LINENO: checking for jitprofiling.h" >&5
|
||||
echo $ECHO_N "checking for jitprofiling.h... $ECHO_C" >&6; }
|
||||
if test "${ac_cv_header_jitprofiling_h+set}" = set; then
|
||||
echo $ECHO_N "(cached) $ECHO_C" >&6
|
||||
fi
|
||||
{ echo "$as_me:$LINENO: result: $ac_cv_header_jitprofiling_h" >&5
|
||||
echo "${ECHO_T}$ac_cv_header_jitprofiling_h" >&6; }
|
||||
else
|
||||
# Is the header compilable?
|
||||
{ echo "$as_me:$LINENO: checking jitprofiling.h usability" >&5
|
||||
echo $ECHO_N "checking jitprofiling.h usability... $ECHO_C" >&6; }
|
||||
cat >conftest.$ac_ext <<_ACEOF
|
||||
/* confdefs.h. */
|
||||
_ACEOF
|
||||
cat confdefs.h >>conftest.$ac_ext
|
||||
cat >>conftest.$ac_ext <<_ACEOF
|
||||
/* end confdefs.h. */
|
||||
$ac_includes_default
|
||||
#include <jitprofiling.h>
|
||||
_ACEOF
|
||||
rm -f conftest.$ac_objext
|
||||
if { (ac_try="$ac_compile"
|
||||
case "(($ac_try" in
|
||||
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
|
||||
*) ac_try_echo=$ac_try;;
|
||||
esac
|
||||
eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
|
||||
(eval "$ac_compile") 2>conftest.er1
|
||||
ac_status=$?
|
||||
grep -v '^ *+' conftest.er1 >conftest.err
|
||||
rm -f conftest.er1
|
||||
cat conftest.err >&5
|
||||
echo "$as_me:$LINENO: \$? = $ac_status" >&5
|
||||
(exit $ac_status); } &&
|
||||
{ ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
|
||||
{ (case "(($ac_try" in
|
||||
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
|
||||
*) ac_try_echo=$ac_try;;
|
||||
esac
|
||||
eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
|
||||
(eval "$ac_try") 2>&5
|
||||
ac_status=$?
|
||||
echo "$as_me:$LINENO: \$? = $ac_status" >&5
|
||||
(exit $ac_status); }; } &&
|
||||
{ ac_try='test -s conftest.$ac_objext'
|
||||
{ (case "(($ac_try" in
|
||||
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
|
||||
*) ac_try_echo=$ac_try;;
|
||||
esac
|
||||
eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
|
||||
(eval "$ac_try") 2>&5
|
||||
ac_status=$?
|
||||
echo "$as_me:$LINENO: \$? = $ac_status" >&5
|
||||
(exit $ac_status); }; }; then
|
||||
ac_header_compiler=yes
|
||||
else
|
||||
echo "$as_me: failed program was:" >&5
|
||||
sed 's/^/| /' conftest.$ac_ext >&5
|
||||
|
||||
ac_header_compiler=no
|
||||
fi
|
||||
|
||||
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
||||
{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
|
||||
echo "${ECHO_T}$ac_header_compiler" >&6; }
|
||||
|
||||
# Is the header present?
|
||||
{ echo "$as_me:$LINENO: checking jitprofiling.h presence" >&5
|
||||
echo $ECHO_N "checking jitprofiling.h presence... $ECHO_C" >&6; }
|
||||
cat >conftest.$ac_ext <<_ACEOF
|
||||
/* confdefs.h. */
|
||||
_ACEOF
|
||||
cat confdefs.h >>conftest.$ac_ext
|
||||
cat >>conftest.$ac_ext <<_ACEOF
|
||||
/* end confdefs.h. */
|
||||
#include <jitprofiling.h>
|
||||
_ACEOF
|
||||
if { (ac_try="$ac_cpp conftest.$ac_ext"
|
||||
case "(($ac_try" in
|
||||
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
|
||||
*) ac_try_echo=$ac_try;;
|
||||
esac
|
||||
eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
|
||||
(eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
|
||||
ac_status=$?
|
||||
grep -v '^ *+' conftest.er1 >conftest.err
|
||||
rm -f conftest.er1
|
||||
cat conftest.err >&5
|
||||
echo "$as_me:$LINENO: \$? = $ac_status" >&5
|
||||
(exit $ac_status); } >/dev/null; then
|
||||
if test -s conftest.err; then
|
||||
ac_cpp_err=$ac_c_preproc_warn_flag
|
||||
ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
|
||||
else
|
||||
ac_cpp_err=
|
||||
fi
|
||||
else
|
||||
ac_cpp_err=yes
|
||||
fi
|
||||
if test -z "$ac_cpp_err"; then
|
||||
ac_header_preproc=yes
|
||||
else
|
||||
echo "$as_me: failed program was:" >&5
|
||||
sed 's/^/| /' conftest.$ac_ext >&5
|
||||
|
||||
ac_header_preproc=no
|
||||
fi
|
||||
|
||||
rm -f conftest.err conftest.$ac_ext
|
||||
{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
|
||||
echo "${ECHO_T}$ac_header_preproc" >&6; }
|
||||
|
||||
# So? What about this header?
|
||||
case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
|
||||
yes:no: )
|
||||
{ echo "$as_me:$LINENO: WARNING: jitprofiling.h: accepted by the compiler, rejected by the preprocessor!" >&5
|
||||
echo "$as_me: WARNING: jitprofiling.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
|
||||
{ echo "$as_me:$LINENO: WARNING: jitprofiling.h: proceeding with the compiler's result" >&5
|
||||
echo "$as_me: WARNING: jitprofiling.h: proceeding with the compiler's result" >&2;}
|
||||
ac_header_preproc=yes
|
||||
;;
|
||||
no:yes:* )
|
||||
{ echo "$as_me:$LINENO: WARNING: jitprofiling.h: present but cannot be compiled" >&5
|
||||
echo "$as_me: WARNING: jitprofiling.h: present but cannot be compiled" >&2;}
|
||||
{ echo "$as_me:$LINENO: WARNING: jitprofiling.h: check for missing prerequisite headers?" >&5
|
||||
echo "$as_me: WARNING: jitprofiling.h: check for missing prerequisite headers?" >&2;}
|
||||
{ echo "$as_me:$LINENO: WARNING: jitprofiling.h: see the Autoconf documentation" >&5
|
||||
echo "$as_me: WARNING: jitprofiling.h: see the Autoconf documentation" >&2;}
|
||||
{ echo "$as_me:$LINENO: WARNING: jitprofiling.h: section \"Present But Cannot Be Compiled\"" >&5
|
||||
echo "$as_me: WARNING: jitprofiling.h: section \"Present But Cannot Be Compiled\"" >&2;}
|
||||
{ echo "$as_me:$LINENO: WARNING: jitprofiling.h: proceeding with the preprocessor's result" >&5
|
||||
echo "$as_me: WARNING: jitprofiling.h: proceeding with the preprocessor's result" >&2;}
|
||||
{ echo "$as_me:$LINENO: WARNING: jitprofiling.h: in the future, the compiler will take precedence" >&5
|
||||
echo "$as_me: WARNING: jitprofiling.h: in the future, the compiler will take precedence" >&2;}
|
||||
( cat <<\_ASBOX
|
||||
## ------------------------------------ ##
|
||||
## Report this to http://llvm.org/bugs/ ##
|
||||
## ------------------------------------ ##
|
||||
_ASBOX
|
||||
) | sed "s/^/$as_me: WARNING: /" >&2
|
||||
;;
|
||||
esac
|
||||
{ echo "$as_me:$LINENO: checking for jitprofiling.h" >&5
|
||||
echo $ECHO_N "checking for jitprofiling.h... $ECHO_C" >&6; }
|
||||
if test "${ac_cv_header_jitprofiling_h+set}" = set; then
|
||||
echo $ECHO_N "(cached) $ECHO_C" >&6
|
||||
else
|
||||
ac_cv_header_jitprofiling_h=$ac_header_preproc
|
||||
fi
|
||||
{ echo "$as_me:$LINENO: result: $ac_cv_header_jitprofiling_h" >&5
|
||||
echo "${ECHO_T}$ac_cv_header_jitprofiling_h" >&6; }
|
||||
|
||||
fi
|
||||
if test $ac_cv_header_jitprofiling_h = yes; then
|
||||
:
|
||||
else
|
||||
|
||||
echo "Error! Cannot find jitprofiling.h. Please check path specified in flag --with-intel-jitevents"
|
||||
exit -1
|
||||
|
||||
fi
|
||||
|
||||
|
||||
|
||||
|
||||
else
|
||||
|
||||
USE_INTEL_JITEVENTS=0
|
||||
|
||||
|
||||
fi
|
||||
|
||||
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define LLVM_USE_INTEL_JITEVENTS $USE_INTEL_JITEVENTS
|
||||
_ACEOF
|
||||
|
||||
|
||||
@ -21913,6 +22247,9 @@ NO_MISSING_FIELD_INITIALIZERS!$NO_MISSING_FIELD_INITIALIZERS$ac_delim
|
||||
COVERED_SWITCH_DEFAULT!$COVERED_SWITCH_DEFAULT$ac_delim
|
||||
USE_UDIS86!$USE_UDIS86$ac_delim
|
||||
USE_OPROFILE!$USE_OPROFILE$ac_delim
|
||||
USE_INTEL_JITEVENTS!$USE_INTEL_JITEVENTS$ac_delim
|
||||
INTEL_JITEVENTS_INCDIR!$INTEL_JITEVENTS_INCDIR$ac_delim
|
||||
INTEL_JITEVENTS_LIBDIR!$INTEL_JITEVENTS_LIBDIR$ac_delim
|
||||
HAVE_PTHREAD!$HAVE_PTHREAD$ac_delim
|
||||
HUGE_VAL_SANITY!$HUGE_VAL_SANITY$ac_delim
|
||||
MMAP_FILE!$MMAP_FILE$ac_delim
|
||||
@ -21938,7 +22275,7 @@ LIBOBJS!$LIBOBJS$ac_delim
|
||||
LTLIBOBJS!$LTLIBOBJS$ac_delim
|
||||
_ACEOF
|
||||
|
||||
if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 90; then
|
||||
if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 93; then
|
||||
break
|
||||
elif $ac_last_try; then
|
||||
{ { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
|
||||
|
@ -357,6 +357,19 @@
|
||||
<dd>Path to Clang's source directory. Defaults to tools/clang.
|
||||
Clang will not be built when it is empty or it does not point valid
|
||||
path.</dd>
|
||||
|
||||
<dt><b>LLVM_USE_OPROFILE</b>:BOOL</dt>
|
||||
<dd> Enable building OProfile JIT support. Defaults to OFF</dd>
|
||||
|
||||
<dt><b>LLVM_USE_INTEL_JITEVENTS</b>:BOOL</dt>
|
||||
<dd> Enable building support for Intel JIT Events API. Defaults to OFF</dd>
|
||||
|
||||
<dt><b>LLVM_INTEL_JITEVENTS_DIR</b>:PATH</dt>
|
||||
<dd> Path to installation of Intel(R) VTune(TM) Amplifier XE 2011,
|
||||
used to locate the <tt>jitprofiling</tt> library. Default =
|
||||
<tt>%VTUNE_AMPLIFIER_XE_2011_DIR%</tt> (Windows)
|
||||
| <tt>/opt/intel/vtune_amplifier_xe_2011</tt> (Linux) </dd>
|
||||
|
||||
</dl>
|
||||
|
||||
</div>
|
||||
|
@ -677,9 +677,6 @@
|
||||
/* Define to 1 if your <sys/time.h> declares `struct tm'. */
|
||||
#undef TM_IN_SYS_TIME
|
||||
|
||||
/* Define if we have the oprofile JIT-support library */
|
||||
#undef USE_OPROFILE
|
||||
|
||||
/* Define if use udis86 library */
|
||||
#undef USE_UDIS86
|
||||
|
||||
@ -716,4 +713,10 @@
|
||||
/* Added by Kevin -- Maximum path length */
|
||||
#cmakedefine MAXPATHLEN ${MAXPATHLEN}
|
||||
|
||||
/* Support for Intel JIT Events API is enabled */
|
||||
#cmakedefine LLVM_USE_INTEL_JITEVENTS 1
|
||||
|
||||
/* Support for OProfile JIT API is enabled */
|
||||
#cmakedefine LLVM_USE_OPROFILE 1
|
||||
|
||||
#endif
|
||||
|
@ -615,6 +615,12 @@
|
||||
/* Installation prefix directory */
|
||||
#undef LLVM_PREFIX
|
||||
|
||||
/* Define if we have the Intel JIT API runtime support library */
|
||||
#undef LLVM_USE_INTEL_JITEVENTS
|
||||
|
||||
/* Define if we have the oprofile JIT-support library */
|
||||
#undef LLVM_USE_OPROFILE
|
||||
|
||||
/* Major version of the LLVM API */
|
||||
#undef LLVM_VERSION_MAJOR
|
||||
|
||||
@ -675,9 +681,6 @@
|
||||
/* Define to 1 if your <sys/time.h> declares `struct tm'. */
|
||||
#undef TM_IN_SYS_TIME
|
||||
|
||||
/* Define if we have the oprofile JIT-support library */
|
||||
#undef USE_OPROFILE
|
||||
|
||||
/* Define if use udis86 library */
|
||||
#undef USE_UDIS86
|
||||
|
||||
|
102
include/llvm/ExecutionEngine/IntelJITEventsWrapper.h
Normal file
102
include/llvm/ExecutionEngine/IntelJITEventsWrapper.h
Normal file
@ -0,0 +1,102 @@
|
||||
//===-- IntelJITEventsWrapper.h - Intel JIT Events API Wrapper --*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines a wrapper for the Intel JIT Events API. It allows for the
|
||||
// implementation of the jitprofiling library to be swapped with an alternative
|
||||
// implementation (for testing). To include this file, you must have the
|
||||
// jitprofiling.h header available; it is available in Intel(R) VTune(TM)
|
||||
// Amplifier XE 2011.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef INTEL_JIT_EVENTS_WRAPPER_H
|
||||
#define INTEL_JIT_EVENTS_WRAPPER_H
|
||||
|
||||
#include <jitprofiling.h>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class IntelJITEventsWrapper {
|
||||
// Function pointer types for testing implementation of Intel jitprofiling
|
||||
// library
|
||||
typedef int (*NotifyEventPtr)(iJIT_JVM_EVENT, void*);
|
||||
typedef void (*RegisterCallbackExPtr)(void *, iJIT_ModeChangedEx );
|
||||
typedef iJIT_IsProfilingActiveFlags (*IsProfilingActivePtr)(void);
|
||||
typedef void (*FinalizeThreadPtr)(void);
|
||||
typedef void (*FinalizeProcessPtr)(void);
|
||||
typedef unsigned int (*GetNewMethodIDPtr)(void);
|
||||
|
||||
NotifyEventPtr NotifyEventFunc;
|
||||
RegisterCallbackExPtr RegisterCallbackExFunc;
|
||||
IsProfilingActivePtr IsProfilingActiveFunc;
|
||||
FinalizeThreadPtr FinalizeThreadFunc;
|
||||
FinalizeProcessPtr FinalizeProcessFunc;
|
||||
GetNewMethodIDPtr GetNewMethodIDFunc;
|
||||
|
||||
public:
|
||||
bool isAmplifierRunning() {
|
||||
return iJIT_IsProfilingActive() == iJIT_SAMPLING_ON;
|
||||
}
|
||||
|
||||
IntelJITEventsWrapper()
|
||||
: NotifyEventFunc(::iJIT_NotifyEvent),
|
||||
RegisterCallbackExFunc(::iJIT_RegisterCallbackEx),
|
||||
IsProfilingActiveFunc(::iJIT_IsProfilingActive),
|
||||
FinalizeThreadFunc(::FinalizeThread),
|
||||
FinalizeProcessFunc(::FinalizeProcess),
|
||||
GetNewMethodIDFunc(::iJIT_GetNewMethodID) {
|
||||
}
|
||||
|
||||
IntelJITEventsWrapper(NotifyEventPtr NotifyEventImpl,
|
||||
RegisterCallbackExPtr RegisterCallbackExImpl,
|
||||
IsProfilingActivePtr IsProfilingActiveImpl,
|
||||
FinalizeThreadPtr FinalizeThreadImpl,
|
||||
FinalizeProcessPtr FinalizeProcessImpl,
|
||||
GetNewMethodIDPtr GetNewMethodIDImpl)
|
||||
: NotifyEventFunc(NotifyEventImpl),
|
||||
RegisterCallbackExFunc(RegisterCallbackExImpl),
|
||||
IsProfilingActiveFunc(IsProfilingActiveImpl),
|
||||
FinalizeThreadFunc(FinalizeThreadImpl),
|
||||
FinalizeProcessFunc(FinalizeProcessImpl),
|
||||
GetNewMethodIDFunc(GetNewMethodIDImpl) {
|
||||
}
|
||||
|
||||
// Sends an event anncouncing that a function has been emitted
|
||||
// return values are event-specific. See Intel documentation for details.
|
||||
int iJIT_NotifyEvent(iJIT_JVM_EVENT EventType, void *EventSpecificData) {
|
||||
if (!NotifyEventFunc)
|
||||
return -1;
|
||||
return NotifyEventFunc(EventType, EventSpecificData);
|
||||
}
|
||||
|
||||
// Registers a callback function to receive notice of profiling state changes
|
||||
void iJIT_RegisterCallbackEx(void *UserData,
|
||||
iJIT_ModeChangedEx NewModeCallBackFuncEx) {
|
||||
if (RegisterCallbackExFunc)
|
||||
RegisterCallbackExFunc(UserData, NewModeCallBackFuncEx);
|
||||
}
|
||||
|
||||
// Returns the current profiler mode
|
||||
iJIT_IsProfilingActiveFlags iJIT_IsProfilingActive(void) {
|
||||
if (!IsProfilingActiveFunc)
|
||||
return iJIT_NOTHING_RUNNING;
|
||||
return IsProfilingActiveFunc();
|
||||
}
|
||||
|
||||
// Generates a locally unique method ID for use in code registration
|
||||
unsigned int iJIT_GetNewMethodID(void) {
|
||||
if (!GetNewMethodIDFunc)
|
||||
return -1;
|
||||
return GetNewMethodIDFunc();
|
||||
}
|
||||
};
|
||||
|
||||
} //namespace llvm
|
||||
|
||||
#endif //INTEL_JIT_EVENTS_WRAPPER_H
|
@ -15,6 +15,7 @@
|
||||
#ifndef LLVM_EXECUTION_ENGINE_JIT_EVENTLISTENER_H
|
||||
#define LLVM_EXECUTION_ENGINE_JIT_EVENTLISTENER_H
|
||||
|
||||
#include "llvm/Config/config.h"
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include "llvm/Support/DebugLoc.h"
|
||||
|
||||
@ -23,6 +24,8 @@
|
||||
namespace llvm {
|
||||
class Function;
|
||||
class MachineFunction;
|
||||
class OProfileWrapper;
|
||||
class IntelJITEventsWrapper;
|
||||
|
||||
/// JITEvent_EmittedFunctionDetails - Helper struct for containing information
|
||||
/// about a generated machine code function.
|
||||
@ -72,11 +75,42 @@ public:
|
||||
/// to NotifyFunctionEmitted may have been destroyed by the time of the
|
||||
/// matching NotifyFreeingMachineCode call.
|
||||
virtual void NotifyFreeingMachineCode(void *) {}
|
||||
};
|
||||
|
||||
// This returns NULL if support isn't available.
|
||||
JITEventListener *createOProfileJITEventListener();
|
||||
#if LLVM_USE_INTEL_JITEVENTS
|
||||
// Construct an IntelJITEventListener
|
||||
static JITEventListener *createIntelJITEventListener();
|
||||
|
||||
// Construct an IntelJITEventListener with a test Intel JIT API implementation
|
||||
static JITEventListener *createIntelJITEventListener(
|
||||
IntelJITEventsWrapper* AlternativeImpl);
|
||||
#else
|
||||
static JITEventListener *createIntelJITEventListener() { return 0; }
|
||||
|
||||
static JITEventListener *createIntelJITEventListener(
|
||||
IntelJITEventsWrapper* AlternativeImpl) {
|
||||
return 0;
|
||||
}
|
||||
#endif // USE_INTEL_JITEVENTS
|
||||
|
||||
#if LLVM_USE_OPROFILE
|
||||
// Construct an OProfileJITEventListener
|
||||
static JITEventListener *createOProfileJITEventListener();
|
||||
|
||||
// Construct an OProfileJITEventListener with a test opagent implementation
|
||||
static JITEventListener *createOProfileJITEventListener(
|
||||
OProfileWrapper* AlternativeImpl);
|
||||
#else
|
||||
|
||||
static JITEventListener *createOProfileJITEventListener() { return 0; }
|
||||
|
||||
static JITEventListener *createOProfileJITEventListener(
|
||||
OProfileWrapper* AlternativeImpl) {
|
||||
return 0;
|
||||
}
|
||||
#endif // USE_OPROFILE
|
||||
|
||||
};
|
||||
|
||||
} // end namespace llvm.
|
||||
|
||||
#endif
|
||||
#endif // defined LLVM_EXECUTION_ENGINE_JIT_EVENTLISTENER_H
|
||||
|
124
include/llvm/ExecutionEngine/OProfileWrapper.h
Normal file
124
include/llvm/ExecutionEngine/OProfileWrapper.h
Normal file
@ -0,0 +1,124 @@
|
||||
//===-- OProfileWrapper.h - OProfile JIT API Wrapper ------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// This file defines a OProfileWrapper object that detects if the oprofile
|
||||
// daemon is running, and provides wrappers for opagent functions used to
|
||||
// communicate with the oprofile JIT interface. The dynamic library libopagent
|
||||
// does not need to be linked directly as this object lazily loads the library
|
||||
// when the first op_ function is called.
|
||||
//
|
||||
// See http://oprofile.sourceforge.net/doc/devel/jit-interface.html for the
|
||||
// definition of the interface.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef OPROFILE_WRAPPER_H
|
||||
#define OPROFILE_WRAPPER_H
|
||||
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include <opagent.h>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
|
||||
class OProfileWrapper {
|
||||
typedef op_agent_t (*op_open_agent_ptr_t)();
|
||||
typedef int (*op_close_agent_ptr_t)(op_agent_t);
|
||||
typedef int (*op_write_native_code_ptr_t)(op_agent_t,
|
||||
const char*,
|
||||
uint64_t,
|
||||
void const*,
|
||||
const unsigned int);
|
||||
typedef int (*op_write_debug_line_info_ptr_t)(op_agent_t,
|
||||
void const*,
|
||||
size_t,
|
||||
struct debug_line_info const*);
|
||||
typedef int (*op_unload_native_code_ptr_t)(op_agent_t, uint64_t);
|
||||
|
||||
// Also used for op_minor_version function which has the same signature
|
||||
typedef int (*op_major_version_ptr_t)(void);
|
||||
|
||||
// This is not a part of the opagent API, but is useful nonetheless
|
||||
typedef bool (*IsOProfileRunningPtrT)(void);
|
||||
|
||||
|
||||
op_agent_t Agent;
|
||||
op_open_agent_ptr_t OpenAgentFunc;
|
||||
op_close_agent_ptr_t CloseAgentFunc;
|
||||
op_write_native_code_ptr_t WriteNativeCodeFunc;
|
||||
op_write_debug_line_info_ptr_t WriteDebugLineInfoFunc;
|
||||
op_unload_native_code_ptr_t UnloadNativeCodeFunc;
|
||||
op_major_version_ptr_t MajorVersionFunc;
|
||||
op_major_version_ptr_t MinorVersionFunc;
|
||||
IsOProfileRunningPtrT IsOProfileRunningFunc;
|
||||
|
||||
bool Initialized;
|
||||
|
||||
public:
|
||||
OProfileWrapper();
|
||||
|
||||
// For testing with a mock opagent implementation, skips the dynamic load and
|
||||
// the function resolution.
|
||||
OProfileWrapper(op_open_agent_ptr_t OpenAgentImpl,
|
||||
op_close_agent_ptr_t CloseAgentImpl,
|
||||
op_write_native_code_ptr_t WriteNativeCodeImpl,
|
||||
op_write_debug_line_info_ptr_t WriteDebugLineInfoImpl,
|
||||
op_unload_native_code_ptr_t UnloadNativeCodeImpl,
|
||||
op_major_version_ptr_t MajorVersionImpl,
|
||||
op_major_version_ptr_t MinorVersionImpl,
|
||||
IsOProfileRunningPtrT MockIsOProfileRunningImpl = 0)
|
||||
: OpenAgentFunc(OpenAgentImpl),
|
||||
CloseAgentFunc(CloseAgentImpl),
|
||||
WriteNativeCodeFunc(WriteNativeCodeImpl),
|
||||
WriteDebugLineInfoFunc(WriteDebugLineInfoImpl),
|
||||
UnloadNativeCodeFunc(UnloadNativeCodeImpl),
|
||||
MajorVersionFunc(MajorVersionImpl),
|
||||
MinorVersionFunc(MinorVersionImpl),
|
||||
IsOProfileRunningFunc(MockIsOProfileRunningImpl),
|
||||
Initialized(true)
|
||||
{
|
||||
}
|
||||
|
||||
// Calls op_open_agent in the oprofile JIT library and saves the returned
|
||||
// op_agent_t handle internally so it can be used when calling all the other
|
||||
// op_* functions. Callers of this class do not need to keep track of
|
||||
// op_agent_t objects.
|
||||
bool op_open_agent();
|
||||
|
||||
int op_close_agent();
|
||||
int op_write_native_code(const char* name,
|
||||
uint64_t addr,
|
||||
void const* code,
|
||||
const unsigned int size);
|
||||
int op_write_debug_line_info(void const* code,
|
||||
size_t num_entries,
|
||||
struct debug_line_info const* info);
|
||||
int op_unload_native_code(uint64_t addr);
|
||||
int op_major_version(void);
|
||||
int op_minor_version(void);
|
||||
|
||||
// Returns true if the oprofiled process is running, the opagent library is
|
||||
// loaded and a connection to the agent has been established, and false
|
||||
// otherwise.
|
||||
bool isAgentAvailable();
|
||||
|
||||
private:
|
||||
// Loads the libopagent library and initializes this wrapper if the oprofile
|
||||
// daemon is running
|
||||
bool initialize();
|
||||
|
||||
// Searches /proc for the oprofile daemon and returns true if the process if
|
||||
// found, or false otherwise.
|
||||
bool checkForOProfileProcEntry();
|
||||
|
||||
bool isOProfileRunning();
|
||||
};
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
#endif //OPROFILE_WRAPPER_H
|
@ -1,3 +1,5 @@
|
||||
|
||||
|
||||
add_llvm_library(LLVMExecutionEngine
|
||||
ExecutionEngine.cpp
|
||||
ExecutionEngineBindings.cpp
|
||||
@ -8,3 +10,11 @@ add_subdirectory(Interpreter)
|
||||
add_subdirectory(JIT)
|
||||
add_subdirectory(MCJIT)
|
||||
add_subdirectory(RuntimeDyld)
|
||||
|
||||
if( LLVM_USE_OPROFILE )
|
||||
add_subdirectory(OProfileJIT)
|
||||
endif( LLVM_USE_OPROFILE )
|
||||
|
||||
if( LLVM_USE_INTEL_JITEVENTS )
|
||||
add_subdirectory(IntelJITEvents)
|
||||
endif( LLVM_USE_INTEL_JITEVENTS )
|
||||
|
67
lib/ExecutionEngine/EventListenerCommon.h
Normal file
67
lib/ExecutionEngine/EventListenerCommon.h
Normal file
@ -0,0 +1,67 @@
|
||||
//===-- JIT.h - Abstract Execution Engine Interface -------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Common functionality for JITEventListener implementations
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef EVENT_LISTENER_COMMON_H
|
||||
#define EVENT_LISTENER_COMMON_H
|
||||
|
||||
#include "llvm/Metadata.h"
|
||||
#include "llvm/Analysis/DebugInfo.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/Support/ValueHandle.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
namespace jitprofiling {
|
||||
|
||||
class FilenameCache {
|
||||
// Holds the filename of each Scope, so that we can pass a null-terminated
|
||||
// string into oprofile. Use an AssertingVH rather than a ValueMap because we
|
||||
// shouldn't be modifying any MDNodes while this map is alive.
|
||||
DenseMap<AssertingVH<MDNode>, std::string> Filenames;
|
||||
DenseMap<AssertingVH<MDNode>, std::string> Paths;
|
||||
|
||||
public:
|
||||
const char *getFilename(MDNode *Scope) {
|
||||
std::string &Filename = Filenames[Scope];
|
||||
if (Filename.empty()) {
|
||||
DIScope DIScope(Scope);
|
||||
Filename = DIScope.getFilename();
|
||||
}
|
||||
return Filename.c_str();
|
||||
}
|
||||
|
||||
const char *getFullPath(MDNode *Scope) {
|
||||
std::string &P = Paths[Scope];
|
||||
if (P.empty()) {
|
||||
DIScope DIScope(Scope);
|
||||
StringRef DirName = DIScope.getDirectory();
|
||||
StringRef FileName = DIScope.getFilename();
|
||||
SmallString<256> FullPath;
|
||||
if (DirName != "." && DirName != "") {
|
||||
FullPath = DirName;
|
||||
}
|
||||
if (FileName != "") {
|
||||
sys::path::append(FullPath, FileName);
|
||||
}
|
||||
P = FullPath.str();
|
||||
}
|
||||
return P.c_str();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace jitprofiling
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
#endif //EVENT_LISTENER_COMMON_H
|
11
lib/ExecutionEngine/IntelJITEvents/CMakeLists.txt
Normal file
11
lib/ExecutionEngine/IntelJITEvents/CMakeLists.txt
Normal file
@ -0,0 +1,11 @@
|
||||
|
||||
include_directories( ${LLVM_INTEL_JITEVENTS_INCDIR} ${CMAKE_CURRENT_SOURCE_DIR}/.. )
|
||||
|
||||
set(system_libs
|
||||
${system_libs}
|
||||
jitprofiling
|
||||
)
|
||||
|
||||
add_llvm_library(LLVMIntelJITEvents
|
||||
IntelJITEventListener.cpp
|
||||
)
|
183
lib/ExecutionEngine/IntelJITEvents/IntelJITEventListener.cpp
Normal file
183
lib/ExecutionEngine/IntelJITEvents/IntelJITEventListener.cpp
Normal file
@ -0,0 +1,183 @@
|
||||
//===-- IntelJITEventListener.cpp - Tell Intel profiler about JITed code --===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines a JITEventListener object to tell Intel(R) VTune(TM)
|
||||
// Amplifier XE 2011 about JITted functions.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Config/config.h"
|
||||
#include "llvm/ExecutionEngine/JITEventListener.h"
|
||||
|
||||
#define DEBUG_TYPE "amplifier-jit-event-listener"
|
||||
#include "llvm/Function.h"
|
||||
#include "llvm/Metadata.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
#include "llvm/Analysis/DebugInfo.h"
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
#include "llvm/ExecutionEngine/IntelJITEventsWrapper.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Support/Errno.h"
|
||||
#include "llvm/Support/ValueHandle.h"
|
||||
#include "EventListenerCommon.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::jitprofiling;
|
||||
|
||||
namespace {
|
||||
|
||||
class IntelJITEventListener : public JITEventListener {
|
||||
typedef DenseMap<void*, unsigned int> MethodIDMap;
|
||||
|
||||
IntelJITEventsWrapper& Wrapper;
|
||||
MethodIDMap MethodIDs;
|
||||
FilenameCache Filenames;
|
||||
|
||||
public:
|
||||
IntelJITEventListener(IntelJITEventsWrapper& libraryWrapper)
|
||||
: Wrapper(libraryWrapper) {
|
||||
}
|
||||
|
||||
~IntelJITEventListener() {
|
||||
}
|
||||
|
||||
virtual void NotifyFunctionEmitted(const Function &F,
|
||||
void *FnStart, size_t FnSize,
|
||||
const EmittedFunctionDetails &Details);
|
||||
|
||||
virtual void NotifyFreeingMachineCode(void *OldPtr);
|
||||
};
|
||||
|
||||
static LineNumberInfo LineStartToIntelJITFormat(
|
||||
uintptr_t StartAddress,
|
||||
uintptr_t Address,
|
||||
DebugLoc Loc) {
|
||||
LineNumberInfo Result;
|
||||
|
||||
Result.Offset = Address - StartAddress;
|
||||
Result.LineNumber = Loc.getLine();
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
static iJIT_Method_Load FunctionDescToIntelJITFormat(
|
||||
IntelJITEventsWrapper& Wrapper,
|
||||
const char* FnName,
|
||||
uintptr_t FnStart,
|
||||
size_t FnSize) {
|
||||
iJIT_Method_Load Result;
|
||||
memset(&Result, 0, sizeof(iJIT_Method_Load));
|
||||
|
||||
Result.method_id = Wrapper.iJIT_GetNewMethodID();
|
||||
Result.method_name = const_cast<char*>(FnName);
|
||||
Result.method_load_address = reinterpret_cast<void*>(FnStart);
|
||||
Result.method_size = FnSize;
|
||||
|
||||
Result.class_id = 0;
|
||||
Result.class_file_name = NULL;
|
||||
Result.user_data = NULL;
|
||||
Result.user_data_size = 0;
|
||||
Result.env = iJDE_JittingAPI;
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
// Adds the just-emitted function to the symbol table.
|
||||
void IntelJITEventListener::NotifyFunctionEmitted(
|
||||
const Function &F, void *FnStart, size_t FnSize,
|
||||
const EmittedFunctionDetails &Details) {
|
||||
iJIT_Method_Load FunctionMessage = FunctionDescToIntelJITFormat(Wrapper,
|
||||
F.getName().data(),
|
||||
reinterpret_cast<uint64_t>(FnStart),
|
||||
FnSize);
|
||||
|
||||
std::vector<LineNumberInfo> LineInfo;
|
||||
|
||||
if (!Details.LineStarts.empty()) {
|
||||
// Now convert the line number information from the address/DebugLoc
|
||||
// format in Details to the offset/lineno in Intel JIT API format.
|
||||
|
||||
LineInfo.reserve(Details.LineStarts.size() + 1);
|
||||
|
||||
DebugLoc FirstLoc = Details.LineStarts[0].Loc;
|
||||
assert(!FirstLoc.isUnknown()
|
||||
&& "LineStarts should not contain unknown DebugLocs");
|
||||
|
||||
MDNode *FirstLocScope = FirstLoc.getScope(F.getContext());
|
||||
DISubprogram FunctionDI = getDISubprogram(FirstLocScope);
|
||||
if (FunctionDI.Verify()) {
|
||||
FunctionMessage.source_file_name = const_cast<char*>(
|
||||
Filenames.getFullPath(FirstLocScope));
|
||||
|
||||
LineNumberInfo FirstLine;
|
||||
FirstLine.Offset = 0;
|
||||
FirstLine.LineNumber = FunctionDI.getLineNumber();
|
||||
LineInfo.push_back(FirstLine);
|
||||
}
|
||||
|
||||
for (std::vector<EmittedFunctionDetails::LineStart>::const_iterator I =
|
||||
Details.LineStarts.begin(), E = Details.LineStarts.end();
|
||||
I != E; ++I) {
|
||||
// This implementation ignores the DebugLoc filename because the Intel
|
||||
// JIT API does not support multiple source files associated with a single
|
||||
// JIT function
|
||||
LineInfo.push_back(LineStartToIntelJITFormat(
|
||||
reinterpret_cast<uintptr_t>(FnStart),
|
||||
I->Address,
|
||||
I->Loc));
|
||||
|
||||
// If we have no file name yet for the function, use the filename from
|
||||
// the first instruction that has one
|
||||
if (FunctionMessage.source_file_name == 0) {
|
||||
MDNode *scope = I->Loc.getScope(
|
||||
Details.MF->getFunction()->getContext());
|
||||
FunctionMessage.source_file_name = const_cast<char*>(
|
||||
Filenames.getFullPath(scope));
|
||||
}
|
||||
}
|
||||
|
||||
FunctionMessage.line_number_size = LineInfo.size();
|
||||
FunctionMessage.line_number_table = &*LineInfo.begin();
|
||||
} else {
|
||||
FunctionMessage.line_number_size = 0;
|
||||
FunctionMessage.line_number_table = 0;
|
||||
}
|
||||
|
||||
Wrapper.iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED,
|
||||
&FunctionMessage);
|
||||
MethodIDs[FnStart] = FunctionMessage.method_id;
|
||||
}
|
||||
|
||||
void IntelJITEventListener::NotifyFreeingMachineCode(void *FnStart) {
|
||||
MethodIDMap::iterator I = MethodIDs.find(FnStart);
|
||||
if (I != MethodIDs.end()) {
|
||||
Wrapper.iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_UNLOAD_START, &I->second);
|
||||
MethodIDs.erase(I);
|
||||
}
|
||||
}
|
||||
|
||||
} // anonymous namespace.
|
||||
|
||||
namespace llvm {
|
||||
JITEventListener *JITEventListener::createIntelJITEventListener() {
|
||||
static OwningPtr<IntelJITEventsWrapper> JITProfilingWrapper(
|
||||
new IntelJITEventsWrapper);
|
||||
return new IntelJITEventListener(*JITProfilingWrapper);
|
||||
}
|
||||
|
||||
// for testing
|
||||
JITEventListener *JITEventListener::createIntelJITEventListener(
|
||||
IntelJITEventsWrapper* TestImpl) {
|
||||
return new IntelJITEventListener(*TestImpl);
|
||||
}
|
||||
|
||||
} // namespace llvm
|
||||
|
23
lib/ExecutionEngine/IntelJITEvents/LLVMBuild.txt
Normal file
23
lib/ExecutionEngine/IntelJITEvents/LLVMBuild.txt
Normal file
@ -0,0 +1,23 @@
|
||||
;===- ./lib/ExecutionEngine/JITProfileAmplifier/LLVMBuild.txt --*- Conf -*--===;
|
||||
;
|
||||
; The LLVM Compiler Infrastructure
|
||||
;
|
||||
; This file is distributed under the University of Illinois Open Source
|
||||
; License. See LICENSE.TXT for details.
|
||||
;
|
||||
;===------------------------------------------------------------------------===;
|
||||
;
|
||||
; This is an LLVMBuild description file for the components in this subdirectory.
|
||||
;
|
||||
; For more information on the LLVMBuild system, please see:
|
||||
;
|
||||
; http://llvm.org/docs/LLVMBuild.html
|
||||
;
|
||||
;===------------------------------------------------------------------------===;
|
||||
|
||||
[common]
|
||||
|
||||
[component_0]
|
||||
type = Library
|
||||
name = IntelJITEvents
|
||||
parent = ExecutionEngine
|
17
lib/ExecutionEngine/IntelJITEvents/Makefile
Normal file
17
lib/ExecutionEngine/IntelJITEvents/Makefile
Normal file
@ -0,0 +1,17 @@
|
||||
##===- lib/ExecutionEngine/JITProfile/Makefile -------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
LEVEL = ../../..
|
||||
LIBRARYNAME = LLVMIntelJITEvents
|
||||
|
||||
include $(LEVEL)/Makefile.config
|
||||
|
||||
SOURCES := IntelJITEventListener.cpp
|
||||
CPPFLAGS += -I$(INTEL_JITEVENTS_INCDIR) -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/..
|
||||
|
||||
include $(LLVM_SRC_ROOT)/Makefile.rules
|
@ -7,5 +7,4 @@ add_llvm_library(LLVMJIT
|
||||
JITDwarfEmitter.cpp
|
||||
JITEmitter.cpp
|
||||
JITMemoryManager.cpp
|
||||
OProfileJITEventListener.cpp
|
||||
)
|
||||
|
@ -16,7 +16,7 @@
|
||||
;===------------------------------------------------------------------------===;
|
||||
|
||||
[common]
|
||||
subdirectories = Interpreter JIT MCJIT RuntimeDyld
|
||||
subdirectories = Interpreter JIT MCJIT RuntimeDyld IntelJITEvents OProfileJIT
|
||||
|
||||
[component_0]
|
||||
type = Library
|
||||
|
@ -8,6 +8,17 @@
|
||||
##===----------------------------------------------------------------------===##
|
||||
LEVEL = ../..
|
||||
LIBRARYNAME = LLVMExecutionEngine
|
||||
|
||||
include $(LEVEL)/Makefile.config
|
||||
|
||||
PARALLEL_DIRS = Interpreter JIT MCJIT RuntimeDyld
|
||||
|
||||
include $(LEVEL)/Makefile.common
|
||||
ifeq ($(USE_INTEL_JITEVENTS), 1)
|
||||
PARALLEL_DIRS += IntelJITEvents
|
||||
endif
|
||||
|
||||
ifeq ($(USE_OPROFILE), 1)
|
||||
PARALLEL_DIRS += OProfileJIT
|
||||
endif
|
||||
|
||||
include $(LLVM_SRC_ROOT)/Makefile.rules
|
||||
|
7
lib/ExecutionEngine/OProfileJIT/CMakeLists.txt
Normal file
7
lib/ExecutionEngine/OProfileJIT/CMakeLists.txt
Normal file
@ -0,0 +1,7 @@
|
||||
|
||||
include_directories( ${LLVM_OPROFILE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/.. )
|
||||
|
||||
add_llvm_library(LLVMOProfileJIT
|
||||
OProfileJITEventListener.cpp
|
||||
OProfileWrapper.cpp
|
||||
)
|
23
lib/ExecutionEngine/OProfileJIT/LLVMBuild.txt
Normal file
23
lib/ExecutionEngine/OProfileJIT/LLVMBuild.txt
Normal file
@ -0,0 +1,23 @@
|
||||
;===- ./lib/ExecutionEngine/OProfileJIT/LLVMBuild.txt ----------*- Conf -*--===;
|
||||
;
|
||||
; The LLVM Compiler Infrastructure
|
||||
;
|
||||
; This file is distributed under the University of Illinois Open Source
|
||||
; License. See LICENSE.TXT for details.
|
||||
;
|
||||
;===------------------------------------------------------------------------===;
|
||||
;
|
||||
; This is an LLVMBuild description file for the components in this subdirectory.
|
||||
;
|
||||
; For more information on the LLVMBuild system, please see:
|
||||
;
|
||||
; http://llvm.org/docs/LLVMBuild.html
|
||||
;
|
||||
;===------------------------------------------------------------------------===;
|
||||
|
||||
[common]
|
||||
|
||||
[component_0]
|
||||
type = Library
|
||||
name = OProfileJIT
|
||||
parent = ExecutionEngine
|
18
lib/ExecutionEngine/OProfileJIT/Makefile
Normal file
18
lib/ExecutionEngine/OProfileJIT/Makefile
Normal file
@ -0,0 +1,18 @@
|
||||
##===- lib/ExecutionEngine/OProfileJIT/Makefile ------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
LEVEL = ../../..
|
||||
LIBRARYNAME = LLVMOProfileJIT
|
||||
|
||||
include $(LEVEL)/Makefile.config
|
||||
|
||||
SOURCES += OProfileJITEventListener.cpp \
|
||||
OProfileWrapper.cpp
|
||||
CPPFLAGS += -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/..
|
||||
|
||||
include $(LLVM_SRC_ROOT)/Makefile.rules
|
@ -7,51 +7,55 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines a JITEventListener object that calls into OProfile to tell
|
||||
// it about JITted functions. For now, we only record function names and sizes,
|
||||
// but eventually we'll also record line number information.
|
||||
//
|
||||
// See http://oprofile.sourceforge.net/doc/devel/jit-interface.html for the
|
||||
// definition of the interface we're using.
|
||||
// This file defines a JITEventListener object that uses OProfileWrapper to tell
|
||||
// oprofile about JITted functions, including source line information.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Config/config.h"
|
||||
#include "llvm/ExecutionEngine/JITEventListener.h"
|
||||
|
||||
#define DEBUG_TYPE "oprofile-jit-event-listener"
|
||||
#include "llvm/Function.h"
|
||||
#include "llvm/Metadata.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
#include "llvm/Analysis/DebugInfo.h"
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
#include "llvm/ExecutionEngine/JITEventListener.h"
|
||||
#include "llvm/ExecutionEngine/OProfileWrapper.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/ValueHandle.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Support/Errno.h"
|
||||
#include "llvm/Config/config.h"
|
||||
#include <stddef.h>
|
||||
#include "EventListenerCommon.h"
|
||||
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
#if USE_OPROFILE
|
||||
|
||||
#include <opagent.h>
|
||||
using namespace llvm::jitprofiling;
|
||||
|
||||
namespace {
|
||||
|
||||
class OProfileJITEventListener : public JITEventListener {
|
||||
op_agent_t Agent;
|
||||
OProfileWrapper& Wrapper;
|
||||
|
||||
void initialize();
|
||||
|
||||
public:
|
||||
OProfileJITEventListener();
|
||||
OProfileJITEventListener(OProfileWrapper& LibraryWrapper)
|
||||
: Wrapper(LibraryWrapper) {
|
||||
initialize();
|
||||
}
|
||||
|
||||
~OProfileJITEventListener();
|
||||
|
||||
virtual void NotifyFunctionEmitted(const Function &F,
|
||||
void *FnStart, size_t FnSize,
|
||||
const EmittedFunctionDetails &Details);
|
||||
void *FnStart, size_t FnSize,
|
||||
const JITEvent_EmittedFunctionDetails &Details);
|
||||
|
||||
virtual void NotifyFreeingMachineCode(void *OldPtr);
|
||||
};
|
||||
|
||||
OProfileJITEventListener::OProfileJITEventListener()
|
||||
: Agent(op_open_agent()) {
|
||||
if (Agent == NULL) {
|
||||
void OProfileJITEventListener::initialize() {
|
||||
if (!Wrapper.op_open_agent()) {
|
||||
const std::string err_str = sys::StrError();
|
||||
DEBUG(dbgs() << "Failed to connect to OProfile agent: " << err_str << "\n");
|
||||
} else {
|
||||
@ -60,8 +64,8 @@ OProfileJITEventListener::OProfileJITEventListener()
|
||||
}
|
||||
|
||||
OProfileJITEventListener::~OProfileJITEventListener() {
|
||||
if (Agent != NULL) {
|
||||
if (op_close_agent(Agent) == -1) {
|
||||
if (Wrapper.isAgentAvailable()) {
|
||||
if (Wrapper.op_close_agent() == -1) {
|
||||
const std::string err_str = sys::StrError();
|
||||
DEBUG(dbgs() << "Failed to disconnect from OProfile agent: "
|
||||
<< err_str << "\n");
|
||||
@ -71,22 +75,6 @@ OProfileJITEventListener::~OProfileJITEventListener() {
|
||||
}
|
||||
}
|
||||
|
||||
class FilenameCache {
|
||||
// Holds the filename of each Scope, so that we can pass a null-terminated
|
||||
// string into oprofile. Use an AssertingVH rather than a ValueMap because we
|
||||
// shouldn't be modifying any MDNodes while this map is alive.
|
||||
DenseMap<AssertingVH<MDNode>, std::string> Filenames;
|
||||
|
||||
public:
|
||||
const char *getFilename(MDNode *Scope) {
|
||||
std::string &Filename = Filenames[Scope];
|
||||
if (Filename.empty()) {
|
||||
Filename = DIScope(Scope).getFilename();
|
||||
}
|
||||
return Filename.c_str();
|
||||
}
|
||||
};
|
||||
|
||||
static debug_line_info LineStartToOProfileFormat(
|
||||
const MachineFunction &MF, FilenameCache &Filenames,
|
||||
uintptr_t Address, DebugLoc Loc) {
|
||||
@ -103,9 +91,9 @@ static debug_line_info LineStartToOProfileFormat(
|
||||
// Adds the just-emitted function to the symbol table.
|
||||
void OProfileJITEventListener::NotifyFunctionEmitted(
|
||||
const Function &F, void *FnStart, size_t FnSize,
|
||||
const EmittedFunctionDetails &Details) {
|
||||
const JITEvent_EmittedFunctionDetails &Details) {
|
||||
assert(F.hasName() && FnStart != 0 && "Bad symbol to add");
|
||||
if (op_write_native_code(Agent, F.getName().data(),
|
||||
if (Wrapper.op_write_native_code(F.getName().data(),
|
||||
reinterpret_cast<uint64_t>(FnStart),
|
||||
FnStart, FnSize) == -1) {
|
||||
DEBUG(dbgs() << "Failed to tell OProfile about native function "
|
||||
@ -151,8 +139,8 @@ void OProfileJITEventListener::NotifyFunctionEmitted(
|
||||
// line info's address to include the start of the function.
|
||||
LineInfo[0].vma = reinterpret_cast<uintptr_t>(FnStart);
|
||||
|
||||
if (op_write_debug_line_info(Agent, FnStart,
|
||||
LineInfo.size(), &*LineInfo.begin()) == -1) {
|
||||
if (Wrapper.op_write_debug_line_info(FnStart, LineInfo.size(),
|
||||
&*LineInfo.begin()) == -1) {
|
||||
DEBUG(dbgs()
|
||||
<< "Failed to tell OProfile about line numbers for native function "
|
||||
<< F.getName() << " at ["
|
||||
@ -164,7 +152,7 @@ void OProfileJITEventListener::NotifyFunctionEmitted(
|
||||
// Removes the being-deleted function from the symbol table.
|
||||
void OProfileJITEventListener::NotifyFreeingMachineCode(void *FnStart) {
|
||||
assert(FnStart && "Invalid function pointer");
|
||||
if (op_unload_native_code(Agent, reinterpret_cast<uint64_t>(FnStart)) == -1) {
|
||||
if (Wrapper.op_unload_native_code(reinterpret_cast<uint64_t>(FnStart)) == -1) {
|
||||
DEBUG(dbgs()
|
||||
<< "Failed to tell OProfile about unload of native function at "
|
||||
<< FnStart << "\n");
|
||||
@ -174,19 +162,16 @@ void OProfileJITEventListener::NotifyFreeingMachineCode(void *FnStart) {
|
||||
} // anonymous namespace.
|
||||
|
||||
namespace llvm {
|
||||
JITEventListener *createOProfileJITEventListener() {
|
||||
return new OProfileJITEventListener;
|
||||
}
|
||||
JITEventListener *JITEventListener::createOProfileJITEventListener() {
|
||||
static OwningPtr<OProfileWrapper> JITProfilingWrapper(new OProfileWrapper);
|
||||
return new OProfileJITEventListener(*JITProfilingWrapper);
|
||||
}
|
||||
|
||||
#else // USE_OPROFILE
|
||||
|
||||
namespace llvm {
|
||||
// By defining this to return NULL, we can let clients call it unconditionally,
|
||||
// even if they haven't configured with the OProfile libraries.
|
||||
JITEventListener *createOProfileJITEventListener() {
|
||||
return NULL;
|
||||
// for testing
|
||||
JITEventListener *JITEventListener::createOProfileJITEventListener(
|
||||
OProfileWrapper* TestImpl) {
|
||||
return new OProfileJITEventListener(*TestImpl);
|
||||
}
|
||||
} // namespace llvm
|
||||
|
||||
#endif // USE_OPROFILE
|
||||
} // namespace llvm
|
||||
|
263
lib/ExecutionEngine/OProfileJIT/OProfileWrapper.cpp
Normal file
263
lib/ExecutionEngine/OProfileJIT/OProfileWrapper.cpp
Normal file
@ -0,0 +1,263 @@
|
||||
//===-- OProfileWrapper.cpp - OProfile JIT API Wrapper implementation -----===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the interface in OProfileWrapper.h. It is responsible
|
||||
// for loading the opagent dynamic library when the first call to an op_
|
||||
// function occurs.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/ExecutionEngine/OProfileWrapper.h"
|
||||
|
||||
#define DEBUG_TYPE "oprofile-wrapper"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Support/DynamicLibrary.h"
|
||||
#include "llvm/Support/Mutex.h"
|
||||
#include "llvm/Support/MutexGuard.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <cstring>
|
||||
#include <stddef.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
namespace {
|
||||
|
||||
// Global mutex to ensure a single thread initializes oprofile agent.
|
||||
llvm::sys::Mutex OProfileInitializationMutex;
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
namespace llvm {
|
||||
|
||||
OProfileWrapper::OProfileWrapper()
|
||||
: Agent(0),
|
||||
OpenAgentFunc(0),
|
||||
CloseAgentFunc(0),
|
||||
WriteNativeCodeFunc(0),
|
||||
WriteDebugLineInfoFunc(0),
|
||||
UnloadNativeCodeFunc(0),
|
||||
MajorVersionFunc(0),
|
||||
MinorVersionFunc(0),
|
||||
IsOProfileRunningFunc(0),
|
||||
Initialized(false) {
|
||||
}
|
||||
|
||||
bool OProfileWrapper::initialize() {
|
||||
using namespace llvm;
|
||||
using namespace llvm::sys;
|
||||
|
||||
MutexGuard Guard(OProfileInitializationMutex);
|
||||
|
||||
if (Initialized)
|
||||
return OpenAgentFunc != 0;
|
||||
|
||||
Initialized = true;
|
||||
|
||||
// If the oprofile daemon is not running, don't load the opagent library
|
||||
if (!isOProfileRunning()) {
|
||||
DEBUG(dbgs() << "OProfile daemon is not detected.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string error;
|
||||
if(!DynamicLibrary::LoadLibraryPermanently("libopagent.so", &error)) {
|
||||
DEBUG(dbgs()
|
||||
<< "OProfile connector library libopagent.so could not be loaded: "
|
||||
<< error << "\n");
|
||||
}
|
||||
|
||||
// Get the addresses of the opagent functions
|
||||
OpenAgentFunc = (op_open_agent_ptr_t)(intptr_t)
|
||||
DynamicLibrary::SearchForAddressOfSymbol("op_open_agent");
|
||||
CloseAgentFunc = (op_close_agent_ptr_t)(intptr_t)
|
||||
DynamicLibrary::SearchForAddressOfSymbol("op_close_agent");
|
||||
WriteNativeCodeFunc = (op_write_native_code_ptr_t)(intptr_t)
|
||||
DynamicLibrary::SearchForAddressOfSymbol("op_write_native_code");
|
||||
WriteDebugLineInfoFunc = (op_write_debug_line_info_ptr_t)(intptr_t)
|
||||
DynamicLibrary::SearchForAddressOfSymbol("op_write_debug_line_info");
|
||||
UnloadNativeCodeFunc = (op_unload_native_code_ptr_t)(intptr_t)
|
||||
DynamicLibrary::SearchForAddressOfSymbol("op_unload_native_code");
|
||||
MajorVersionFunc = (op_major_version_ptr_t)(intptr_t)
|
||||
DynamicLibrary::SearchForAddressOfSymbol("op_major_version");
|
||||
MinorVersionFunc = (op_major_version_ptr_t)(intptr_t)
|
||||
DynamicLibrary::SearchForAddressOfSymbol("op_minor_version");
|
||||
|
||||
// With missing functions, we can do nothing
|
||||
if (!OpenAgentFunc
|
||||
|| !CloseAgentFunc
|
||||
|| !WriteNativeCodeFunc
|
||||
|| !WriteDebugLineInfoFunc
|
||||
|| !UnloadNativeCodeFunc) {
|
||||
OpenAgentFunc = 0;
|
||||
CloseAgentFunc = 0;
|
||||
WriteNativeCodeFunc = 0;
|
||||
WriteDebugLineInfoFunc = 0;
|
||||
UnloadNativeCodeFunc = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OProfileWrapper::isOProfileRunning() {
|
||||
if (IsOProfileRunningFunc != 0)
|
||||
return IsOProfileRunningFunc();
|
||||
return checkForOProfileProcEntry();
|
||||
}
|
||||
|
||||
bool OProfileWrapper::checkForOProfileProcEntry() {
|
||||
DIR* ProcDir;
|
||||
|
||||
ProcDir = opendir("/proc");
|
||||
if (!ProcDir)
|
||||
return false;
|
||||
|
||||
// Walk the /proc tree looking for the oprofile daemon
|
||||
struct dirent* Entry;
|
||||
while (0 != (Entry = readdir(ProcDir))) {
|
||||
if (Entry->d_type == DT_DIR) {
|
||||
// Build a path from the current entry name
|
||||
SmallString<256> CmdLineFName;
|
||||
raw_svector_ostream(CmdLineFName) << "/proc/" << Entry->d_name
|
||||
<< "/cmdline";
|
||||
|
||||
// Open the cmdline file
|
||||
int CmdLineFD = open(CmdLineFName.c_str(), S_IRUSR);
|
||||
if (CmdLineFD != -1) {
|
||||
char ExeName[PATH_MAX+1];
|
||||
char* BaseName = 0;
|
||||
|
||||
// Read the cmdline file
|
||||
ssize_t NumRead = read(CmdLineFD, ExeName, PATH_MAX+1);
|
||||
close(CmdLineFD);
|
||||
ssize_t Idx = 0;
|
||||
|
||||
// Find the terminator for the first string
|
||||
while (Idx < NumRead-1 && ExeName[Idx] != 0) {
|
||||
Idx++;
|
||||
}
|
||||
|
||||
// Go back to the last non-null character
|
||||
Idx--;
|
||||
|
||||
// Find the last path separator in the first string
|
||||
while (Idx > 0) {
|
||||
if (ExeName[Idx] == '/') {
|
||||
BaseName = ExeName + Idx + 1;
|
||||
break;
|
||||
}
|
||||
Idx--;
|
||||
}
|
||||
|
||||
// Test this to see if it is the oprofile daemon
|
||||
if (BaseName != 0 && !strcmp("oprofiled", BaseName)) {
|
||||
// If it is, we're done
|
||||
closedir(ProcDir);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We've looked through all the files and didn't find the daemon
|
||||
closedir(ProcDir);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool OProfileWrapper::op_open_agent() {
|
||||
if (!Initialized)
|
||||
initialize();
|
||||
|
||||
if (OpenAgentFunc != 0) {
|
||||
Agent = OpenAgentFunc();
|
||||
return Agent != 0;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int OProfileWrapper::op_close_agent() {
|
||||
if (!Initialized)
|
||||
initialize();
|
||||
|
||||
int ret = -1;
|
||||
if (Agent && CloseAgentFunc) {
|
||||
ret = CloseAgentFunc(Agent);
|
||||
if (ret == 0) {
|
||||
Agent = 0;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool OProfileWrapper::isAgentAvailable() {
|
||||
return Agent != 0;
|
||||
}
|
||||
|
||||
int OProfileWrapper::op_write_native_code(const char* Name,
|
||||
uint64_t Addr,
|
||||
void const* Code,
|
||||
const unsigned int Size) {
|
||||
if (!Initialized)
|
||||
initialize();
|
||||
|
||||
if (Agent && WriteNativeCodeFunc)
|
||||
return WriteNativeCodeFunc(Agent, Name, Addr, Code, Size);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int OProfileWrapper::op_write_debug_line_info(
|
||||
void const* Code,
|
||||
size_t NumEntries,
|
||||
struct debug_line_info const* Info) {
|
||||
if (!Initialized)
|
||||
initialize();
|
||||
|
||||
if (Agent && WriteDebugLineInfoFunc)
|
||||
return WriteDebugLineInfoFunc(Agent, Code, NumEntries, Info);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int OProfileWrapper::op_major_version() {
|
||||
if (!Initialized)
|
||||
initialize();
|
||||
|
||||
if (Agent && MajorVersionFunc)
|
||||
return MajorVersionFunc();
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int OProfileWrapper::op_minor_version() {
|
||||
if (!Initialized)
|
||||
initialize();
|
||||
|
||||
if (Agent && MinorVersionFunc)
|
||||
return MinorVersionFunc();
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int OProfileWrapper::op_unload_native_code(uint64_t Addr) {
|
||||
if (!Initialized)
|
||||
initialize();
|
||||
|
||||
if (Agent && UnloadNativeCodeFunc)
|
||||
return UnloadNativeCodeFunc(Agent, Addr);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
} // namespace llvm
|
@ -1,5 +1,22 @@
|
||||
|
||||
link_directories( ${LLVM_INTEL_JITEVENTS_LIBDIR} )
|
||||
|
||||
set(LLVM_LINK_COMPONENTS mcjit jit interpreter nativecodegen bitreader asmparser selectiondag)
|
||||
|
||||
if( LLVM_USE_OPROFILE )
|
||||
set(LLVM_LINK_COMPONENTS
|
||||
${LLVM_LINK_COMPONENTS}
|
||||
OProfileJIT
|
||||
)
|
||||
endif( LLVM_USE_OPROFILE )
|
||||
|
||||
if( LLVM_USE_INTEL_JITEVENTS )
|
||||
set(LLVM_LINK_COMPONENTS
|
||||
${LLVM_LINK_COMPONENTS}
|
||||
IntelJITEvents
|
||||
)
|
||||
endif( LLVM_USE_INTEL_JITEVENTS )
|
||||
|
||||
add_llvm_tool(lli
|
||||
lli.cpp
|
||||
)
|
||||
|
@ -9,6 +9,21 @@
|
||||
|
||||
LEVEL := ../..
|
||||
TOOLNAME := lli
|
||||
|
||||
include $(LEVEL)/Makefile.config
|
||||
|
||||
LINK_COMPONENTS := mcjit jit interpreter nativecodegen bitreader asmparser selectiondag
|
||||
|
||||
include $(LEVEL)/Makefile.common
|
||||
# If Intel JIT Events support is confiured, link against the LLVM Intel JIT
|
||||
# Events interface library
|
||||
ifeq ($(USE_INTEL_JITEVENTS), 1)
|
||||
LINK_COMPONENTS += inteljitevents
|
||||
endif
|
||||
|
||||
# If oprofile support is confiured, link against the LLVM oprofile interface
|
||||
# library
|
||||
ifeq ($(USE_OPROFILE), 1)
|
||||
LINK_COMPONENTS += oprofilejit
|
||||
endif
|
||||
|
||||
include $(LLVM_SRC_ROOT)/Makefile.rules
|
||||
|
@ -238,7 +238,12 @@ int main(int argc, char **argv, char * const *envp) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
EE->RegisterJITEventListener(createOProfileJITEventListener());
|
||||
// The following functions have no effect if their respective profiling
|
||||
// support wasn't enabled in the build configuration.
|
||||
EE->RegisterJITEventListener(
|
||||
JITEventListener::createOProfileJITEventListener());
|
||||
EE->RegisterJITEventListener(
|
||||
JITEventListener::createIntelJITEventListener());
|
||||
|
||||
EE->DisableLazyCompilation(NoLazyCompilation);
|
||||
|
||||
|
@ -83,12 +83,36 @@ add_llvm_unittest(Analysis
|
||||
Analysis/ScalarEvolutionTest.cpp
|
||||
)
|
||||
|
||||
if( LLVM_USE_INTEL_JITEVENTS )
|
||||
include_directories( ${LLVM_INTEL_JITEVENTS_INCDIR} )
|
||||
link_directories( ${LLVM_INTEL_JITEVENTS_LIBDIR} )
|
||||
set(ProfileTestSources
|
||||
ExecutionEngine/IntelJITEventListenerTest.cpp
|
||||
)
|
||||
set(LLVM_LINK_COMPONENTS
|
||||
${LLVM_LINK_COMPONENTS}
|
||||
IntelJITEvents
|
||||
)
|
||||
endif( LLVM_USE_INTEL_JITEVENTS )
|
||||
|
||||
if( LLVM_USE_OPROFILE )
|
||||
set(ProfileTestSources
|
||||
${ProfileTestSources}
|
||||
ExecutionEngine/OProfileJITEventListenerTest.cpp
|
||||
)
|
||||
set(LLVM_LINK_COMPONENTS
|
||||
${LLVM_LINK_COMPONENTS}
|
||||
OProfileJIT
|
||||
)
|
||||
endif( LLVM_USE_OPROFILE )
|
||||
|
||||
add_llvm_unittest(ExecutionEngine
|
||||
ExecutionEngine/ExecutionEngineTest.cpp
|
||||
ExecutionEngine/JITEventListenerTest.cpp
|
||||
${ProfileTestSources}
|
||||
)
|
||||
|
||||
set(JITTestsSources
|
||||
ExecutionEngine/JIT/JITEventListenerTest.cpp
|
||||
ExecutionEngine/JIT/JITMemoryManagerTest.cpp
|
||||
ExecutionEngine/JIT/JITTest.cpp
|
||||
ExecutionEngine/JIT/MultiJITTest.cpp
|
||||
|
110
unittests/ExecutionEngine/IntelJITEventListenerTest.cpp
Normal file
110
unittests/ExecutionEngine/IntelJITEventListenerTest.cpp
Normal file
@ -0,0 +1,110 @@
|
||||
//===- JITEventListenerTest.cpp - Tests for Intel JITEventListener --------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "JITEventListenerTestCommon.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
#include "llvm/ExecutionEngine/IntelJITEventsWrapper.h"
|
||||
|
||||
#include <map>
|
||||
#include <list>
|
||||
|
||||
namespace {
|
||||
|
||||
// map of function ("method") IDs to source locations
|
||||
NativeCodeMap ReportedDebugFuncs;
|
||||
|
||||
} // namespace
|
||||
|
||||
/// Mock implementaion of Intel JIT API jitprofiling library
|
||||
namespace test_jitprofiling {
|
||||
|
||||
int NotifyEvent(iJIT_JVM_EVENT EventType, void *EventSpecificData) {
|
||||
switch (EventType) {
|
||||
case iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED: {
|
||||
EXPECT_TRUE(0 != EventSpecificData);
|
||||
iJIT_Method_Load* msg = static_cast<iJIT_Method_Load*>(EventSpecificData);
|
||||
|
||||
ReportedDebugFuncs[msg->method_id];
|
||||
|
||||
for(unsigned int i = 0; i < msg->line_number_size; ++i) {
|
||||
EXPECT_TRUE(0 != msg->line_number_table);
|
||||
std::pair<std::string, unsigned int> loc(
|
||||
std::string(msg->source_file_name),
|
||||
msg->line_number_table[i].LineNumber);
|
||||
ReportedDebugFuncs[msg->method_id].push_back(loc);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case iJVM_EVENT_TYPE_METHOD_UNLOAD_START: {
|
||||
EXPECT_TRUE(0 != EventSpecificData);
|
||||
unsigned int UnloadId
|
||||
= *reinterpret_cast<unsigned int*>(EventSpecificData);
|
||||
EXPECT_TRUE(1 == ReportedDebugFuncs.erase(UnloadId));
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
iJIT_IsProfilingActiveFlags IsProfilingActive(void) {
|
||||
// for testing, pretend we have an Intel Parallel Amplifier XE 2011
|
||||
// instance attached
|
||||
return iJIT_SAMPLING_ON;
|
||||
}
|
||||
|
||||
unsigned int GetNewMethodID(void) {
|
||||
static unsigned int id = 0;
|
||||
return ++id;
|
||||
}
|
||||
|
||||
} //namespace test_jitprofiling
|
||||
|
||||
class IntelJITEventListenerTest
|
||||
: public JITEventListenerTestBase<IntelJITEventsWrapper> {
|
||||
public:
|
||||
IntelJITEventListenerTest()
|
||||
: JITEventListenerTestBase<IntelJITEventsWrapper>(
|
||||
new IntelJITEventsWrapper(test_jitprofiling::NotifyEvent, 0,
|
||||
test_jitprofiling::IsProfilingActive, 0, 0,
|
||||
test_jitprofiling::GetNewMethodID))
|
||||
{
|
||||
EXPECT_TRUE(0 != MockWrapper);
|
||||
|
||||
Listener.reset(JITEventListener::createIntelJITEventListener(
|
||||
MockWrapper.get()));
|
||||
EXPECT_TRUE(0 != Listener);
|
||||
EE->RegisterJITEventListener(Listener.get());
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(IntelJITEventListenerTest, NoDebugInfo) {
|
||||
TestNoDebugInfo(ReportedDebugFuncs);
|
||||
}
|
||||
|
||||
TEST_F(IntelJITEventListenerTest, SingleLine) {
|
||||
TestSingleLine(ReportedDebugFuncs);
|
||||
}
|
||||
|
||||
TEST_F(IntelJITEventListenerTest, MultipleLines) {
|
||||
TestMultipleLines(ReportedDebugFuncs);
|
||||
}
|
||||
|
||||
// This testcase is disabled because the Intel JIT API does not support a single
|
||||
// JITted function with source lines associated with multiple files
|
||||
/*
|
||||
TEST_F(IntelJITEventListenerTest, MultipleFiles) {
|
||||
TestMultipleFiles(ReportedDebugFuncs);
|
||||
}
|
||||
*/
|
||||
|
||||
testing::Environment* const jit_env =
|
||||
testing::AddGlobalTestEnvironment(new JITEnvironment);
|
@ -1,238 +0,0 @@
|
||||
//===- JITEventListenerTest.cpp - Unit tests for JITEventListeners --------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/ExecutionEngine/JITEventListener.h"
|
||||
|
||||
#include "llvm/LLVMContext.h"
|
||||
#include "llvm/Instructions.h"
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
#include "llvm/CodeGen/MachineCodeInfo.h"
|
||||
#include "llvm/ExecutionEngine/JIT.h"
|
||||
#include "llvm/Support/TypeBuilder.h"
|
||||
#include "llvm/Support/TargetSelect.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include <vector>
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
int dummy;
|
||||
|
||||
namespace {
|
||||
|
||||
struct FunctionEmittedEvent {
|
||||
// Indices are local to the RecordingJITEventListener, since the
|
||||
// JITEventListener interface makes no guarantees about the order of
|
||||
// calls between Listeners.
|
||||
unsigned Index;
|
||||
const Function *F;
|
||||
void *Code;
|
||||
size_t Size;
|
||||
JITEvent_EmittedFunctionDetails Details;
|
||||
};
|
||||
struct FunctionFreedEvent {
|
||||
unsigned Index;
|
||||
void *Code;
|
||||
};
|
||||
|
||||
struct RecordingJITEventListener : public JITEventListener {
|
||||
std::vector<FunctionEmittedEvent> EmittedEvents;
|
||||
std::vector<FunctionFreedEvent> FreedEvents;
|
||||
|
||||
unsigned NextIndex;
|
||||
|
||||
RecordingJITEventListener() : NextIndex(0) {}
|
||||
|
||||
virtual void NotifyFunctionEmitted(const Function &F,
|
||||
void *Code, size_t Size,
|
||||
const EmittedFunctionDetails &Details) {
|
||||
FunctionEmittedEvent Event = {NextIndex++, &F, Code, Size, Details};
|
||||
EmittedEvents.push_back(Event);
|
||||
}
|
||||
|
||||
virtual void NotifyFreeingMachineCode(void *OldPtr) {
|
||||
FunctionFreedEvent Event = {NextIndex++, OldPtr};
|
||||
FreedEvents.push_back(Event);
|
||||
}
|
||||
};
|
||||
|
||||
class JITEventListenerTest : public testing::Test {
|
||||
protected:
|
||||
JITEventListenerTest()
|
||||
: M(new Module("module", getGlobalContext())),
|
||||
EE(EngineBuilder(M)
|
||||
.setEngineKind(EngineKind::JIT)
|
||||
.create()) {
|
||||
}
|
||||
|
||||
Module *M;
|
||||
const OwningPtr<ExecutionEngine> EE;
|
||||
};
|
||||
|
||||
Function *buildFunction(Module *M) {
|
||||
Function *Result = Function::Create(
|
||||
TypeBuilder<int32_t(int32_t), false>::get(getGlobalContext()),
|
||||
GlobalValue::ExternalLinkage, "id", M);
|
||||
Value *Arg = Result->arg_begin();
|
||||
BasicBlock *BB = BasicBlock::Create(M->getContext(), "entry", Result);
|
||||
ReturnInst::Create(M->getContext(), Arg, BB);
|
||||
return Result;
|
||||
}
|
||||
|
||||
// Tests that a single JITEventListener follows JIT events accurately.
|
||||
TEST_F(JITEventListenerTest, Simple) {
|
||||
RecordingJITEventListener Listener;
|
||||
EE->RegisterJITEventListener(&Listener);
|
||||
Function *F1 = buildFunction(M);
|
||||
Function *F2 = buildFunction(M);
|
||||
|
||||
void *F1_addr = EE->getPointerToFunction(F1);
|
||||
void *F2_addr = EE->getPointerToFunction(F2);
|
||||
EE->getPointerToFunction(F1); // Should do nothing.
|
||||
EE->freeMachineCodeForFunction(F1);
|
||||
EE->freeMachineCodeForFunction(F2);
|
||||
|
||||
ASSERT_EQ(2U, Listener.EmittedEvents.size());
|
||||
ASSERT_EQ(2U, Listener.FreedEvents.size());
|
||||
|
||||
EXPECT_EQ(0U, Listener.EmittedEvents[0].Index);
|
||||
EXPECT_EQ(F1, Listener.EmittedEvents[0].F);
|
||||
EXPECT_EQ(F1_addr, Listener.EmittedEvents[0].Code);
|
||||
EXPECT_LT(0U, Listener.EmittedEvents[0].Size)
|
||||
<< "We don't know how big the function will be, but it had better"
|
||||
<< " contain some bytes.";
|
||||
|
||||
EXPECT_EQ(1U, Listener.EmittedEvents[1].Index);
|
||||
EXPECT_EQ(F2, Listener.EmittedEvents[1].F);
|
||||
EXPECT_EQ(F2_addr, Listener.EmittedEvents[1].Code);
|
||||
EXPECT_LT(0U, Listener.EmittedEvents[1].Size)
|
||||
<< "We don't know how big the function will be, but it had better"
|
||||
<< " contain some bytes.";
|
||||
|
||||
EXPECT_EQ(2U, Listener.FreedEvents[0].Index);
|
||||
EXPECT_EQ(F1_addr, Listener.FreedEvents[0].Code);
|
||||
|
||||
EXPECT_EQ(3U, Listener.FreedEvents[1].Index);
|
||||
EXPECT_EQ(F2_addr, Listener.FreedEvents[1].Code);
|
||||
|
||||
F1->eraseFromParent();
|
||||
F2->eraseFromParent();
|
||||
}
|
||||
|
||||
// Tests that a single JITEventListener follows JIT events accurately.
|
||||
TEST_F(JITEventListenerTest, MultipleListenersDontInterfere) {
|
||||
RecordingJITEventListener Listener1;
|
||||
RecordingJITEventListener Listener2;
|
||||
RecordingJITEventListener Listener3;
|
||||
Function *F1 = buildFunction(M);
|
||||
Function *F2 = buildFunction(M);
|
||||
|
||||
EE->RegisterJITEventListener(&Listener1);
|
||||
EE->RegisterJITEventListener(&Listener2);
|
||||
void *F1_addr = EE->getPointerToFunction(F1);
|
||||
EE->RegisterJITEventListener(&Listener3);
|
||||
EE->UnregisterJITEventListener(&Listener1);
|
||||
void *F2_addr = EE->getPointerToFunction(F2);
|
||||
EE->UnregisterJITEventListener(&Listener2);
|
||||
EE->UnregisterJITEventListener(&Listener3);
|
||||
EE->freeMachineCodeForFunction(F1);
|
||||
EE->RegisterJITEventListener(&Listener2);
|
||||
EE->RegisterJITEventListener(&Listener3);
|
||||
EE->RegisterJITEventListener(&Listener1);
|
||||
EE->freeMachineCodeForFunction(F2);
|
||||
EE->UnregisterJITEventListener(&Listener1);
|
||||
EE->UnregisterJITEventListener(&Listener2);
|
||||
EE->UnregisterJITEventListener(&Listener3);
|
||||
|
||||
// Listener 1.
|
||||
ASSERT_EQ(1U, Listener1.EmittedEvents.size());
|
||||
ASSERT_EQ(1U, Listener1.FreedEvents.size());
|
||||
|
||||
EXPECT_EQ(0U, Listener1.EmittedEvents[0].Index);
|
||||
EXPECT_EQ(F1, Listener1.EmittedEvents[0].F);
|
||||
EXPECT_EQ(F1_addr, Listener1.EmittedEvents[0].Code);
|
||||
EXPECT_LT(0U, Listener1.EmittedEvents[0].Size)
|
||||
<< "We don't know how big the function will be, but it had better"
|
||||
<< " contain some bytes.";
|
||||
|
||||
EXPECT_EQ(1U, Listener1.FreedEvents[0].Index);
|
||||
EXPECT_EQ(F2_addr, Listener1.FreedEvents[0].Code);
|
||||
|
||||
// Listener 2.
|
||||
ASSERT_EQ(2U, Listener2.EmittedEvents.size());
|
||||
ASSERT_EQ(1U, Listener2.FreedEvents.size());
|
||||
|
||||
EXPECT_EQ(0U, Listener2.EmittedEvents[0].Index);
|
||||
EXPECT_EQ(F1, Listener2.EmittedEvents[0].F);
|
||||
EXPECT_EQ(F1_addr, Listener2.EmittedEvents[0].Code);
|
||||
EXPECT_LT(0U, Listener2.EmittedEvents[0].Size)
|
||||
<< "We don't know how big the function will be, but it had better"
|
||||
<< " contain some bytes.";
|
||||
|
||||
EXPECT_EQ(1U, Listener2.EmittedEvents[1].Index);
|
||||
EXPECT_EQ(F2, Listener2.EmittedEvents[1].F);
|
||||
EXPECT_EQ(F2_addr, Listener2.EmittedEvents[1].Code);
|
||||
EXPECT_LT(0U, Listener2.EmittedEvents[1].Size)
|
||||
<< "We don't know how big the function will be, but it had better"
|
||||
<< " contain some bytes.";
|
||||
|
||||
EXPECT_EQ(2U, Listener2.FreedEvents[0].Index);
|
||||
EXPECT_EQ(F2_addr, Listener2.FreedEvents[0].Code);
|
||||
|
||||
// Listener 3.
|
||||
ASSERT_EQ(1U, Listener3.EmittedEvents.size());
|
||||
ASSERT_EQ(1U, Listener3.FreedEvents.size());
|
||||
|
||||
EXPECT_EQ(0U, Listener3.EmittedEvents[0].Index);
|
||||
EXPECT_EQ(F2, Listener3.EmittedEvents[0].F);
|
||||
EXPECT_EQ(F2_addr, Listener3.EmittedEvents[0].Code);
|
||||
EXPECT_LT(0U, Listener3.EmittedEvents[0].Size)
|
||||
<< "We don't know how big the function will be, but it had better"
|
||||
<< " contain some bytes.";
|
||||
|
||||
EXPECT_EQ(1U, Listener3.FreedEvents[0].Index);
|
||||
EXPECT_EQ(F2_addr, Listener3.FreedEvents[0].Code);
|
||||
|
||||
F1->eraseFromParent();
|
||||
F2->eraseFromParent();
|
||||
}
|
||||
|
||||
TEST_F(JITEventListenerTest, MatchesMachineCodeInfo) {
|
||||
RecordingJITEventListener Listener;
|
||||
MachineCodeInfo MCI;
|
||||
Function *F = buildFunction(M);
|
||||
|
||||
EE->RegisterJITEventListener(&Listener);
|
||||
EE->runJITOnFunction(F, &MCI);
|
||||
void *F_addr = EE->getPointerToFunction(F);
|
||||
EE->freeMachineCodeForFunction(F);
|
||||
|
||||
ASSERT_EQ(1U, Listener.EmittedEvents.size());
|
||||
ASSERT_EQ(1U, Listener.FreedEvents.size());
|
||||
|
||||
EXPECT_EQ(0U, Listener.EmittedEvents[0].Index);
|
||||
EXPECT_EQ(F, Listener.EmittedEvents[0].F);
|
||||
EXPECT_EQ(F_addr, Listener.EmittedEvents[0].Code);
|
||||
EXPECT_EQ(MCI.address(), Listener.EmittedEvents[0].Code);
|
||||
EXPECT_EQ(MCI.size(), Listener.EmittedEvents[0].Size);
|
||||
|
||||
EXPECT_EQ(1U, Listener.FreedEvents[0].Index);
|
||||
EXPECT_EQ(F_addr, Listener.FreedEvents[0].Code);
|
||||
}
|
||||
|
||||
class JITEnvironment : public testing::Environment {
|
||||
virtual void SetUp() {
|
||||
// Required to create a JIT.
|
||||
InitializeNativeTarget();
|
||||
}
|
||||
};
|
||||
testing::Environment* const jit_env =
|
||||
testing::AddGlobalTestEnvironment(new JITEnvironment);
|
||||
|
||||
} // anonymous namespace
|
238
unittests/ExecutionEngine/JITEventListenerTest.cpp
Normal file
238
unittests/ExecutionEngine/JITEventListenerTest.cpp
Normal file
@ -0,0 +1,238 @@
|
||||
//===- JITEventListenerTest.cpp - Unit tests for JITEventListeners --------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/ExecutionEngine/JITEventListener.h"
|
||||
|
||||
#include "llvm/LLVMContext.h"
|
||||
#include "llvm/Instructions.h"
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
#include "llvm/CodeGen/MachineCodeInfo.h"
|
||||
#include "llvm/ExecutionEngine/JIT.h"
|
||||
#include "llvm/Support/TypeBuilder.h"
|
||||
#include "llvm/Support/TargetSelect.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include <vector>
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
int dummy;
|
||||
|
||||
namespace {
|
||||
|
||||
struct FunctionEmittedEvent {
|
||||
// Indices are local to the RecordingJITEventListener, since the
|
||||
// JITEventListener interface makes no guarantees about the order of
|
||||
// calls between Listeners.
|
||||
unsigned Index;
|
||||
const Function *F;
|
||||
void *Code;
|
||||
size_t Size;
|
||||
JITEvent_EmittedFunctionDetails Details;
|
||||
};
|
||||
struct FunctionFreedEvent {
|
||||
unsigned Index;
|
||||
void *Code;
|
||||
};
|
||||
|
||||
struct RecordingJITEventListener : public JITEventListener {
|
||||
std::vector<FunctionEmittedEvent> EmittedEvents;
|
||||
std::vector<FunctionFreedEvent> FreedEvents;
|
||||
|
||||
unsigned NextIndex;
|
||||
|
||||
RecordingJITEventListener() : NextIndex(0) {}
|
||||
|
||||
virtual void NotifyFunctionEmitted(const Function &F,
|
||||
void *Code, size_t Size,
|
||||
const EmittedFunctionDetails &Details) {
|
||||
FunctionEmittedEvent Event = {NextIndex++, &F, Code, Size, Details};
|
||||
EmittedEvents.push_back(Event);
|
||||
}
|
||||
|
||||
virtual void NotifyFreeingMachineCode(void *OldPtr) {
|
||||
FunctionFreedEvent Event = {NextIndex++, OldPtr};
|
||||
FreedEvents.push_back(Event);
|
||||
}
|
||||
};
|
||||
|
||||
class JITEventListenerTest : public testing::Test {
|
||||
protected:
|
||||
JITEventListenerTest()
|
||||
: M(new Module("module", getGlobalContext())),
|
||||
EE(EngineBuilder(M)
|
||||
.setEngineKind(EngineKind::JIT)
|
||||
.create()) {
|
||||
}
|
||||
|
||||
Module *M;
|
||||
const OwningPtr<ExecutionEngine> EE;
|
||||
};
|
||||
|
||||
Function *buildFunction(Module *M) {
|
||||
Function *Result = Function::Create(
|
||||
TypeBuilder<int32_t(int32_t), false>::get(getGlobalContext()),
|
||||
GlobalValue::ExternalLinkage, "id", M);
|
||||
Value *Arg = Result->arg_begin();
|
||||
BasicBlock *BB = BasicBlock::Create(M->getContext(), "entry", Result);
|
||||
ReturnInst::Create(M->getContext(), Arg, BB);
|
||||
return Result;
|
||||
}
|
||||
|
||||
// Tests that a single JITEventListener follows JIT events accurately.
|
||||
TEST_F(JITEventListenerTest, Simple) {
|
||||
RecordingJITEventListener Listener;
|
||||
EE->RegisterJITEventListener(&Listener);
|
||||
Function *F1 = buildFunction(M);
|
||||
Function *F2 = buildFunction(M);
|
||||
|
||||
void *F1_addr = EE->getPointerToFunction(F1);
|
||||
void *F2_addr = EE->getPointerToFunction(F2);
|
||||
EE->getPointerToFunction(F1); // Should do nothing.
|
||||
EE->freeMachineCodeForFunction(F1);
|
||||
EE->freeMachineCodeForFunction(F2);
|
||||
|
||||
ASSERT_EQ(2U, Listener.EmittedEvents.size());
|
||||
ASSERT_EQ(2U, Listener.FreedEvents.size());
|
||||
|
||||
EXPECT_EQ(0U, Listener.EmittedEvents[0].Index);
|
||||
EXPECT_EQ(F1, Listener.EmittedEvents[0].F);
|
||||
EXPECT_EQ(F1_addr, Listener.EmittedEvents[0].Code);
|
||||
EXPECT_LT(0U, Listener.EmittedEvents[0].Size)
|
||||
<< "We don't know how big the function will be, but it had better"
|
||||
<< " contain some bytes.";
|
||||
|
||||
EXPECT_EQ(1U, Listener.EmittedEvents[1].Index);
|
||||
EXPECT_EQ(F2, Listener.EmittedEvents[1].F);
|
||||
EXPECT_EQ(F2_addr, Listener.EmittedEvents[1].Code);
|
||||
EXPECT_LT(0U, Listener.EmittedEvents[1].Size)
|
||||
<< "We don't know how big the function will be, but it had better"
|
||||
<< " contain some bytes.";
|
||||
|
||||
EXPECT_EQ(2U, Listener.FreedEvents[0].Index);
|
||||
EXPECT_EQ(F1_addr, Listener.FreedEvents[0].Code);
|
||||
|
||||
EXPECT_EQ(3U, Listener.FreedEvents[1].Index);
|
||||
EXPECT_EQ(F2_addr, Listener.FreedEvents[1].Code);
|
||||
|
||||
F1->eraseFromParent();
|
||||
F2->eraseFromParent();
|
||||
}
|
||||
|
||||
// Tests that a single JITEventListener follows JIT events accurately.
|
||||
TEST_F(JITEventListenerTest, MultipleListenersDontInterfere) {
|
||||
RecordingJITEventListener Listener1;
|
||||
RecordingJITEventListener Listener2;
|
||||
RecordingJITEventListener Listener3;
|
||||
Function *F1 = buildFunction(M);
|
||||
Function *F2 = buildFunction(M);
|
||||
|
||||
EE->RegisterJITEventListener(&Listener1);
|
||||
EE->RegisterJITEventListener(&Listener2);
|
||||
void *F1_addr = EE->getPointerToFunction(F1);
|
||||
EE->RegisterJITEventListener(&Listener3);
|
||||
EE->UnregisterJITEventListener(&Listener1);
|
||||
void *F2_addr = EE->getPointerToFunction(F2);
|
||||
EE->UnregisterJITEventListener(&Listener2);
|
||||
EE->UnregisterJITEventListener(&Listener3);
|
||||
EE->freeMachineCodeForFunction(F1);
|
||||
EE->RegisterJITEventListener(&Listener2);
|
||||
EE->RegisterJITEventListener(&Listener3);
|
||||
EE->RegisterJITEventListener(&Listener1);
|
||||
EE->freeMachineCodeForFunction(F2);
|
||||
EE->UnregisterJITEventListener(&Listener1);
|
||||
EE->UnregisterJITEventListener(&Listener2);
|
||||
EE->UnregisterJITEventListener(&Listener3);
|
||||
|
||||
// Listener 1.
|
||||
ASSERT_EQ(1U, Listener1.EmittedEvents.size());
|
||||
ASSERT_EQ(1U, Listener1.FreedEvents.size());
|
||||
|
||||
EXPECT_EQ(0U, Listener1.EmittedEvents[0].Index);
|
||||
EXPECT_EQ(F1, Listener1.EmittedEvents[0].F);
|
||||
EXPECT_EQ(F1_addr, Listener1.EmittedEvents[0].Code);
|
||||
EXPECT_LT(0U, Listener1.EmittedEvents[0].Size)
|
||||
<< "We don't know how big the function will be, but it had better"
|
||||
<< " contain some bytes.";
|
||||
|
||||
EXPECT_EQ(1U, Listener1.FreedEvents[0].Index);
|
||||
EXPECT_EQ(F2_addr, Listener1.FreedEvents[0].Code);
|
||||
|
||||
// Listener 2.
|
||||
ASSERT_EQ(2U, Listener2.EmittedEvents.size());
|
||||
ASSERT_EQ(1U, Listener2.FreedEvents.size());
|
||||
|
||||
EXPECT_EQ(0U, Listener2.EmittedEvents[0].Index);
|
||||
EXPECT_EQ(F1, Listener2.EmittedEvents[0].F);
|
||||
EXPECT_EQ(F1_addr, Listener2.EmittedEvents[0].Code);
|
||||
EXPECT_LT(0U, Listener2.EmittedEvents[0].Size)
|
||||
<< "We don't know how big the function will be, but it had better"
|
||||
<< " contain some bytes.";
|
||||
|
||||
EXPECT_EQ(1U, Listener2.EmittedEvents[1].Index);
|
||||
EXPECT_EQ(F2, Listener2.EmittedEvents[1].F);
|
||||
EXPECT_EQ(F2_addr, Listener2.EmittedEvents[1].Code);
|
||||
EXPECT_LT(0U, Listener2.EmittedEvents[1].Size)
|
||||
<< "We don't know how big the function will be, but it had better"
|
||||
<< " contain some bytes.";
|
||||
|
||||
EXPECT_EQ(2U, Listener2.FreedEvents[0].Index);
|
||||
EXPECT_EQ(F2_addr, Listener2.FreedEvents[0].Code);
|
||||
|
||||
// Listener 3.
|
||||
ASSERT_EQ(1U, Listener3.EmittedEvents.size());
|
||||
ASSERT_EQ(1U, Listener3.FreedEvents.size());
|
||||
|
||||
EXPECT_EQ(0U, Listener3.EmittedEvents[0].Index);
|
||||
EXPECT_EQ(F2, Listener3.EmittedEvents[0].F);
|
||||
EXPECT_EQ(F2_addr, Listener3.EmittedEvents[0].Code);
|
||||
EXPECT_LT(0U, Listener3.EmittedEvents[0].Size)
|
||||
<< "We don't know how big the function will be, but it had better"
|
||||
<< " contain some bytes.";
|
||||
|
||||
EXPECT_EQ(1U, Listener3.FreedEvents[0].Index);
|
||||
EXPECT_EQ(F2_addr, Listener3.FreedEvents[0].Code);
|
||||
|
||||
F1->eraseFromParent();
|
||||
F2->eraseFromParent();
|
||||
}
|
||||
|
||||
TEST_F(JITEventListenerTest, MatchesMachineCodeInfo) {
|
||||
RecordingJITEventListener Listener;
|
||||
MachineCodeInfo MCI;
|
||||
Function *F = buildFunction(M);
|
||||
|
||||
EE->RegisterJITEventListener(&Listener);
|
||||
EE->runJITOnFunction(F, &MCI);
|
||||
void *F_addr = EE->getPointerToFunction(F);
|
||||
EE->freeMachineCodeForFunction(F);
|
||||
|
||||
ASSERT_EQ(1U, Listener.EmittedEvents.size());
|
||||
ASSERT_EQ(1U, Listener.FreedEvents.size());
|
||||
|
||||
EXPECT_EQ(0U, Listener.EmittedEvents[0].Index);
|
||||
EXPECT_EQ(F, Listener.EmittedEvents[0].F);
|
||||
EXPECT_EQ(F_addr, Listener.EmittedEvents[0].Code);
|
||||
EXPECT_EQ(MCI.address(), Listener.EmittedEvents[0].Code);
|
||||
EXPECT_EQ(MCI.size(), Listener.EmittedEvents[0].Size);
|
||||
|
||||
EXPECT_EQ(1U, Listener.FreedEvents[0].Index);
|
||||
EXPECT_EQ(F_addr, Listener.FreedEvents[0].Code);
|
||||
}
|
||||
|
||||
class JITEnvironment : public testing::Environment {
|
||||
virtual void SetUp() {
|
||||
// Required to create a JIT.
|
||||
InitializeNativeTarget();
|
||||
}
|
||||
};
|
||||
testing::Environment* const jit_env =
|
||||
testing::AddGlobalTestEnvironment(new JITEnvironment);
|
||||
|
||||
} // anonymous namespace
|
209
unittests/ExecutionEngine/JITEventListenerTestCommon.h
Normal file
209
unittests/ExecutionEngine/JITEventListenerTestCommon.h
Normal file
@ -0,0 +1,209 @@
|
||||
//===- JITEventListenerTestCommon.h - Helper for JITEventListener tests ------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===-------------------------------------------------------------------------------===//
|
||||
|
||||
#ifndef JIT_EVENT_LISTENER_TEST_COMMON_H
|
||||
#define JIT_EVENT_LISTENER_TEST_COMMON_H
|
||||
|
||||
#include "llvm/Analysis/DIBuilder.h"
|
||||
#include "llvm/Analysis/DebugInfo.h"
|
||||
#include "llvm/CodeGen/MachineCodeInfo.h"
|
||||
#include "llvm/Config/config.h"
|
||||
#include "llvm/ExecutionEngine/JIT.h"
|
||||
#include "llvm/ExecutionEngine/JITEventListener.h"
|
||||
#include "llvm/Instructions.h"
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/Support/IRBuilder.h"
|
||||
#include "llvm/Support/Dwarf.h"
|
||||
#include "llvm/Support/TypeBuilder.h"
|
||||
#include "llvm/Support/TargetSelect.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
typedef std::vector<std::pair<std::string, unsigned int> > SourceLocations;
|
||||
typedef std::map<uint64_t, SourceLocations> NativeCodeMap;
|
||||
|
||||
class JITEnvironment : public testing::Environment {
|
||||
virtual void SetUp() {
|
||||
// Required to create a JIT.
|
||||
llvm::InitializeNativeTarget();
|
||||
}
|
||||
};
|
||||
|
||||
inline unsigned int getLine() {
|
||||
return 12;
|
||||
}
|
||||
|
||||
inline unsigned int getCol() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline const char* getFilename() {
|
||||
return "mock_source_file.cpp";
|
||||
}
|
||||
|
||||
// Test fixture shared by tests for listener implementations
|
||||
template<typename WrapperT>
|
||||
class JITEventListenerTestBase : public testing::Test {
|
||||
protected:
|
||||
llvm::OwningPtr<WrapperT> MockWrapper;
|
||||
llvm::OwningPtr<llvm::JITEventListener> Listener;
|
||||
|
||||
public:
|
||||
llvm::Module* M;
|
||||
llvm::MDNode* Scope;
|
||||
llvm::ExecutionEngine* EE;
|
||||
llvm::DIBuilder* DebugBuilder;
|
||||
llvm::IRBuilder<> Builder;
|
||||
|
||||
JITEventListenerTestBase(WrapperT* w)
|
||||
: MockWrapper(w)
|
||||
, M(new llvm::Module("module", llvm::getGlobalContext()))
|
||||
, EE(llvm::EngineBuilder(M)
|
||||
.setEngineKind(llvm::EngineKind::JIT)
|
||||
.setOptLevel(llvm::CodeGenOpt::None)
|
||||
.create())
|
||||
, DebugBuilder(new llvm::DIBuilder(*M))
|
||||
, Builder(llvm::getGlobalContext())
|
||||
{
|
||||
DebugBuilder->createCompileUnit(llvm::dwarf::DW_LANG_C_plus_plus,
|
||||
"JIT",
|
||||
"JIT",
|
||||
"JIT",
|
||||
true,
|
||||
"",
|
||||
1);
|
||||
|
||||
Scope = DebugBuilder->createFile(getFilename(), ".");
|
||||
}
|
||||
|
||||
llvm::Function *buildFunction(const SourceLocations& DebugLocations) {
|
||||
using namespace llvm;
|
||||
|
||||
LLVMContext& GlobalContext = getGlobalContext();
|
||||
|
||||
SourceLocations::const_iterator CurrentDebugLocation
|
||||
= DebugLocations.begin();
|
||||
|
||||
if (CurrentDebugLocation != DebugLocations.end()) {
|
||||
DebugLoc DebugLocation = DebugLoc::get(getLine(), getCol(),
|
||||
DebugBuilder->createFile(CurrentDebugLocation->first, "."));
|
||||
Builder.SetCurrentDebugLocation(DebugLocation);
|
||||
CurrentDebugLocation++;
|
||||
}
|
||||
|
||||
Function *Result = Function::Create(
|
||||
TypeBuilder<int32_t(int32_t), false>::get(GlobalContext),
|
||||
GlobalValue::ExternalLinkage, "id", M);
|
||||
Value *Arg = Result->arg_begin();
|
||||
BasicBlock *BB = BasicBlock::Create(M->getContext(), "entry", Result);
|
||||
Builder.SetInsertPoint(BB);
|
||||
Value* one = ConstantInt::get(GlobalContext, APInt(32, 1));
|
||||
for(; CurrentDebugLocation != DebugLocations.end();
|
||||
++CurrentDebugLocation) {
|
||||
Arg = Builder.CreateMul(Arg, Builder.CreateAdd(Arg, one));
|
||||
Builder.SetCurrentDebugLocation(
|
||||
DebugLoc::get(CurrentDebugLocation->second, 0,
|
||||
DebugBuilder->createFile(CurrentDebugLocation->first, ".")));
|
||||
}
|
||||
Builder.CreateRet(Arg);
|
||||
return Result;
|
||||
}
|
||||
|
||||
void TestNoDebugInfo(NativeCodeMap& ReportedDebugFuncs) {
|
||||
SourceLocations DebugLocations;
|
||||
llvm::Function* f = buildFunction(DebugLocations);
|
||||
EXPECT_TRUE(0 != f);
|
||||
|
||||
//Cause JITting and callbacks to our listener
|
||||
EXPECT_TRUE(0 != EE->getPointerToFunction(f));
|
||||
EXPECT_TRUE(1 == ReportedDebugFuncs.size());
|
||||
|
||||
EE->freeMachineCodeForFunction(f);
|
||||
EXPECT_TRUE(ReportedDebugFuncs.size() == 0);
|
||||
}
|
||||
|
||||
void TestSingleLine(NativeCodeMap& ReportedDebugFuncs) {
|
||||
SourceLocations DebugLocations;
|
||||
DebugLocations.push_back(std::make_pair(std::string(getFilename()),
|
||||
getLine()));
|
||||
llvm::Function* f = buildFunction(DebugLocations);
|
||||
EXPECT_TRUE(0 != f);
|
||||
|
||||
EXPECT_TRUE(0 != EE->getPointerToFunction(f));
|
||||
EXPECT_TRUE(1 == ReportedDebugFuncs.size());
|
||||
EXPECT_STREQ(ReportedDebugFuncs.begin()->second.begin()->first.c_str(),
|
||||
getFilename());
|
||||
EXPECT_EQ(ReportedDebugFuncs.begin()->second.begin()->second, getLine());
|
||||
|
||||
EE->freeMachineCodeForFunction(f);
|
||||
EXPECT_TRUE(ReportedDebugFuncs.size() == 0);
|
||||
}
|
||||
|
||||
void TestMultipleLines(NativeCodeMap& ReportedDebugFuncs) {
|
||||
using namespace std;
|
||||
|
||||
SourceLocations DebugLocations;
|
||||
unsigned int c = 5;
|
||||
for(unsigned int i = 0; i < c; ++i) {
|
||||
DebugLocations.push_back(make_pair(string(getFilename()), getLine() + i));
|
||||
}
|
||||
|
||||
llvm::Function* f = buildFunction(DebugLocations);
|
||||
EXPECT_TRUE(0 != f);
|
||||
|
||||
EXPECT_TRUE(0 != EE->getPointerToFunction(f));
|
||||
EXPECT_TRUE(1 == ReportedDebugFuncs.size());
|
||||
SourceLocations& FunctionInfo = ReportedDebugFuncs.begin()->second;
|
||||
EXPECT_EQ(c, FunctionInfo.size());
|
||||
|
||||
int VerifyCount = 0;
|
||||
for(SourceLocations::iterator i = FunctionInfo.begin();
|
||||
i != FunctionInfo.end();
|
||||
++i) {
|
||||
EXPECT_STREQ(i->first.c_str(), getFilename());
|
||||
EXPECT_EQ(i->second, getLine() + VerifyCount);
|
||||
VerifyCount++;
|
||||
}
|
||||
|
||||
EE->freeMachineCodeForFunction(f);
|
||||
EXPECT_TRUE(ReportedDebugFuncs.size() == 0);
|
||||
}
|
||||
|
||||
void TestMultipleFiles(NativeCodeMap& ReportedDebugFuncs) {
|
||||
|
||||
std::string secondFilename("another_file.cpp");
|
||||
|
||||
SourceLocations DebugLocations;
|
||||
DebugLocations.push_back(std::make_pair(std::string(getFilename()),
|
||||
getLine()));
|
||||
DebugLocations.push_back(std::make_pair(secondFilename, getLine()));
|
||||
llvm::Function* f = buildFunction(DebugLocations);
|
||||
EXPECT_TRUE(0 != f);
|
||||
|
||||
EXPECT_TRUE(0 != EE->getPointerToFunction(f));
|
||||
EXPECT_TRUE(1 == ReportedDebugFuncs.size());
|
||||
SourceLocations& FunctionInfo = ReportedDebugFuncs.begin()->second;
|
||||
EXPECT_TRUE(2 == FunctionInfo.size());
|
||||
|
||||
EXPECT_STREQ(FunctionInfo.at(0).first.c_str(), getFilename());
|
||||
EXPECT_STREQ(FunctionInfo.at(1).first.c_str(), secondFilename.c_str());
|
||||
|
||||
EXPECT_EQ(FunctionInfo.at(0).second, getLine());
|
||||
EXPECT_EQ(FunctionInfo.at(1).second, getLine());
|
||||
|
||||
EE->freeMachineCodeForFunction(f);
|
||||
EXPECT_TRUE(ReportedDebugFuncs.size() == 0);
|
||||
}
|
||||
};
|
||||
|
||||
#endif //JIT_EVENT_LISTENER_TEST_COMMON_H
|
@ -13,6 +13,29 @@ LINK_COMPONENTS := engine interpreter
|
||||
|
||||
include $(LEVEL)/Makefile.config
|
||||
|
||||
SOURCES := ExecutionEngineTest.cpp \
|
||||
JITEventListenerTest.cpp
|
||||
|
||||
ifeq ($(USE_INTEL_JITEVENTS), 1)
|
||||
# Build the Intel JIT Events interface tests
|
||||
SOURCES += IntelJITEventListenerTest.cpp
|
||||
|
||||
# Add the Intel JIT Events include directory
|
||||
CPPFLAGS += -I$(INTEL_JITEVENTS_INCDIR)
|
||||
|
||||
# Link against the LLVM Intel JIT Evens interface library
|
||||
LINK_COMPONENTS += inteljitevents
|
||||
endif
|
||||
|
||||
ifeq ($(USE_OPROFILE), 1)
|
||||
# Build the OProfile JIT interface tests
|
||||
SOURCES += OProfileJITEventListenerTest.cpp
|
||||
|
||||
# Link against the LLVM oprofile interface library
|
||||
LINK_COMPONENTS += oprofilejit
|
||||
endif
|
||||
|
||||
|
||||
PARALLEL_DIRS = JIT
|
||||
|
||||
include $(LLVM_SRC_ROOT)/unittests/Makefile.unittest
|
||||
|
166
unittests/ExecutionEngine/OProfileJITEventListenerTest.cpp
Normal file
166
unittests/ExecutionEngine/OProfileJITEventListenerTest.cpp
Normal file
@ -0,0 +1,166 @@
|
||||
//===- OProfileJITEventListenerTest.cpp - Unit tests for OProfileJITEventsListener --------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===--------------------------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/ExecutionEngine/JITEventListener.h"
|
||||
#include "llvm/ExecutionEngine/OProfileWrapper.h"
|
||||
#include "JITEventListenerTestCommon.h"
|
||||
|
||||
#include <map>
|
||||
#include <list>
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
|
||||
struct OprofileNativeFunction {
|
||||
const char* Name;
|
||||
uint64_t Addr;
|
||||
const void* CodePtr;
|
||||
unsigned int CodeSize;
|
||||
|
||||
OprofileNativeFunction(const char* name,
|
||||
uint64_t addr,
|
||||
const void* code,
|
||||
unsigned int size)
|
||||
: Name(name)
|
||||
, Addr(addr)
|
||||
, CodePtr(code)
|
||||
, CodeSize(size) {
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::list<OprofileNativeFunction> NativeFunctionList;
|
||||
typedef std::list<debug_line_info> NativeDebugList;
|
||||
NativeFunctionList NativeFunctions;
|
||||
|
||||
NativeCodeMap ReportedDebugFuncs;
|
||||
|
||||
} // namespace
|
||||
|
||||
/// Mock implementaion of opagent library
|
||||
namespace test_opagent {
|
||||
|
||||
op_agent_t globalAgent = reinterpret_cast<op_agent_t>(42);
|
||||
|
||||
op_agent_t open_agent()
|
||||
{
|
||||
// return non-null op_agent_t
|
||||
return globalAgent;
|
||||
}
|
||||
|
||||
int close_agent(op_agent_t agent)
|
||||
{
|
||||
EXPECT_EQ(globalAgent, agent);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int write_native_code(op_agent_t agent,
|
||||
const char* name,
|
||||
uint64_t addr,
|
||||
void const* code,
|
||||
unsigned int size)
|
||||
{
|
||||
EXPECT_EQ(globalAgent, agent);
|
||||
OprofileNativeFunction func(name, addr, code, size);
|
||||
NativeFunctions.push_back(func);
|
||||
|
||||
// Verify no other registration has take place for the same address
|
||||
EXPECT_TRUE(ReportedDebugFuncs.find(addr) == ReportedDebugFuncs.end());
|
||||
|
||||
ReportedDebugFuncs[addr];
|
||||
return 0;
|
||||
}
|
||||
|
||||
int write_debug_line_info(op_agent_t agent,
|
||||
void const* code,
|
||||
size_t num_entries,
|
||||
struct debug_line_info const* info)
|
||||
{
|
||||
EXPECT_EQ(globalAgent, agent);
|
||||
|
||||
//verify code has been loaded first
|
||||
uint64_t addr = reinterpret_cast<uint64_t>(code);
|
||||
NativeCodeMap::iterator i = ReportedDebugFuncs.find(addr);
|
||||
EXPECT_TRUE(i != ReportedDebugFuncs.end());
|
||||
|
||||
NativeDebugList NativeInfo(info, info + num_entries);
|
||||
|
||||
SourceLocations locs;
|
||||
for(NativeDebugList::iterator i = NativeInfo.begin();
|
||||
i != NativeInfo.end();
|
||||
++i) {
|
||||
locs.push_back(std::make_pair(std::string(i->filename), i->lineno));
|
||||
}
|
||||
ReportedDebugFuncs[addr] = locs;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int unload_native_code(op_agent_t agent, uint64_t addr) {
|
||||
EXPECT_EQ(globalAgent, agent);
|
||||
|
||||
//verify that something for the given JIT addr has been loaded first
|
||||
NativeCodeMap::iterator i = ReportedDebugFuncs.find(addr);
|
||||
EXPECT_TRUE(i != ReportedDebugFuncs.end());
|
||||
ReportedDebugFuncs.erase(i);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int version() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool is_oprofile_running() {
|
||||
return true;
|
||||
}
|
||||
|
||||
} //namespace test_opagent
|
||||
|
||||
class OProfileJITEventListenerTest
|
||||
: public JITEventListenerTestBase<OProfileWrapper>
|
||||
{
|
||||
public:
|
||||
OProfileJITEventListenerTest()
|
||||
: JITEventListenerTestBase<OProfileWrapper>(
|
||||
new OProfileWrapper(test_opagent::open_agent,
|
||||
test_opagent::close_agent,
|
||||
test_opagent::write_native_code,
|
||||
test_opagent::write_debug_line_info,
|
||||
test_opagent::unload_native_code,
|
||||
test_opagent::version,
|
||||
test_opagent::version,
|
||||
test_opagent::is_oprofile_running))
|
||||
{
|
||||
EXPECT_TRUE(0 != MockWrapper);
|
||||
|
||||
Listener.reset(JITEventListener::createOProfileJITEventListener(
|
||||
MockWrapper.get()));
|
||||
EXPECT_TRUE(0 != Listener);
|
||||
EE->RegisterJITEventListener(Listener.get());
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(OProfileJITEventListenerTest, NoDebugInfo) {
|
||||
TestNoDebugInfo(ReportedDebugFuncs);
|
||||
}
|
||||
|
||||
TEST_F(OProfileJITEventListenerTest, SingleLine) {
|
||||
TestSingleLine(ReportedDebugFuncs);
|
||||
}
|
||||
|
||||
TEST_F(OProfileJITEventListenerTest, MultipleLines) {
|
||||
TestMultipleLines(ReportedDebugFuncs);
|
||||
}
|
||||
|
||||
TEST_F(OProfileJITEventListenerTest, MultipleFiles) {
|
||||
TestMultipleFiles(ReportedDebugFuncs);
|
||||
}
|
||||
|
||||
testing::Environment* const jit_env =
|
||||
testing::AddGlobalTestEnvironment(new JITEnvironment);
|
Loading…
Reference in New Issue
Block a user