Upstream-Status: Backport From ca6d916a6f8f0f8abbb4c9b6a97dd1a1615bb124 Mon Sep 17 00:00:00 2001 From: Maynard Johnson Date: Wed, 5 Dec 2012 10:16:35 -0600 Subject: [PATCH] Fix up configure to handle architectures that do not implement perf_event_open This patch fixes the following problems: 1) The configure script allows the user to pass a location to kernel headers (via --with-kernel option) such that, even if the running kernel does not have perf_events support, it may be possible to build operf (e.g., in cross-compile environments). But the message 'This kernel does not have perf_events support; falling back to legacy oprofile' was being displayed inappropriately in such cases. This patch changes the configure script so that the "falling back to legacy oprofile" message will only be displayed if we're running on a kernel that does not have perf_events support AND the user did not pass specify the "--with-kernel" option. 2) Some architectures don't even implement the perf_event_open syscall, so the configure script must do more than checking kernel version and whether or not perf_event.h is present in order to decide if perf_events is supported. This patch provides that extra capability. These problems were reported by Tony Jones . Signed-off-by: Maynard Johnson --- configure.ac | 74 +++++++++++++++++++++++++++++----------- utils/op_perf_events_checker.c | 6 ++-- 2 files changed, 58 insertions(+), 22 deletions(-) diff --git a/configure.ac b/configure.ac index 5c3d13d..89336ee 100644 --- a/configure.ac +++ b/configure.ac @@ -70,34 +70,66 @@ KERNELDIR=$withval) dnl Check kernel version for perf_events supported -AC_MSG_CHECKING([kernel version supports perf_events]) if test "$KERNELDIR" != ""; then KINC="$KERNELDIR/include" -fi -AX_KERNEL_VERSION(2, 6, 31, <=, kernel_has_perf_events_support="yes", -kernel_has_perf_events_support="no") - -if test "$kernel_has_perf_events_support" = "no"; then - AC_MSG_RESULT([This kernel does not have perf_events support; falling back to legacy oprofile]) + PERF_EVENT_FLAGS=" -I$KERNELDIR/include" + AC_SUBST(PERF_EVENT_FLAGS) + PERF_EVENT_H="$KERNELDIR/include/linux/perf_event.h" else - AC_MSG_RESULT([This kernel has perf_events support]) + PERF_EVENT_H="/usr/include/linux/perf_event.h" fi -if test "$KERNELDIR" == ""; then - PERF_EVENT_H="/usr/include/linux/perf_event.h" +PERF_EVENT_H_EXISTS="no" +kernel_may_have_perf_events_support="no" +AX_KERNEL_VERSION(2, 6, 31, <=, kernel_may_have_perf_events_support="yes", +kernel_has_perf_events_support="no") + +dnl The AX_KERNEL_VERSION macro may return kernel_may_have_perf_events_support="yes", +dnl indicating a partial answer. Some architectures do not implement the Performance +dnl Events Kernel Subsystem even with kernel versions > 2.6.31 -- i.e., not even +dnl implementing the perf_event_open syscall to return ENOSYS. So the check below +dnl will identify and handle such situations. + +if test "$kernel_may_have_perf_events_support" = "yes"; then + AC_CHECK_HEADER($PERF_EVENT_H,PERF_EVENT_H_EXISTS="yes") + AC_MSG_CHECKING([kernel supports perf_events]) + if test "$PERF_EVENT_H_EXISTS" = "yes"; then + rm -f test-for-PERF_EVENT_OPEN + AC_LANG_CONFTEST( + [AC_LANG_PROGRAM([[#include + #include + #include + #include + ]], + [[struct perf_event_attr attr; + pid_t pid; + memset(&attr, 0, sizeof(attr)); + attr.size = sizeof(attr); + attr.sample_type = PERF_SAMPLE_IP; + pid = getpid(); + syscall(__NR_perf_event_open, &attr, pid, 0, -1, 0); + ]]) + ]) + $CC conftest.$ac_ext $CFLAGS $LDFLAGS $LIBS $PERF_EVENT_FLAGS -o test-for-PERF_EVENT_OPEN > /dev/null 2>&1 + if test -f test-for-PERF_EVENT_OPEN; then + kernel_has_perf_events_support="yes" + AC_MSG_RESULT(yes) + else + AC_MSG_RESULT(no) + kernel_has_perf_events_support="no" + fi + else + AC_MSG_RESULT(unknown -- perf_event.h not found) + fi else - PERF_EVENT_H="$KERNELDIR/include/linux/perf_event.h" + AC_MSG_RESULT(kernel supports perf_events... no) + kernel_has_perf_events_support="no" fi -AC_CHECK_HEADER($PERF_EVENT_H,PERF_EVENT_H_EXISTS="yes") -AM_CONDITIONAL(BUILD_FOR_PERF_EVENT, test -n "$PERF_EVENT_H_EXISTS") -if test "$PERF_EVENT_H_EXISTS" = "yes"; then - HAVE_PERF_EVENTS='1' - if test "$KERNELDIR" != ""; then - PERF_EVENT_FLAGS=" -I$KERNELDIR/include" - AC_SUBST(PERF_EVENT_FLAGS) - fi +AM_CONDITIONAL(BUILD_FOR_PERF_EVENT, test "$kernel_has_perf_events_support" = "yes") +if test "$kernel_has_perf_events_support" = "yes"; then + HAVE_PERF_EVENTS='1' AC_MSG_CHECKING([whether PERF_RECORD_MISC_GUEST_KERNEL is defined in perf_event.h]) rm -f test-for-PERF_GUEST AC_LANG_CONFTEST( @@ -117,7 +149,9 @@ if test "$PERF_EVENT_H_EXISTS" = "yes"; then rm -f test-for-PERF_GUEST* else HAVE_PERF_EVENTS='0' + AC_MSG_RESULT([No perf_events support available; falling back to legacy oprofile]) fi + AC_DEFINE_UNQUOTED(HAVE_PERF_EVENTS, $HAVE_PERF_EVENTS, [Kernel support for perf_events exists]) if test "$HAVE_PERF_EVENTS" = "1"; then @@ -433,7 +467,7 @@ elif test "`getent passwd oprofile 2>/dev/null`" == "" || \ fi fi -if test "$PERF_EVENT_H_EXISTS" != "yes" && test "$kernel_has_perf_events_support" = "yes"; then +if test "$PERF_EVENT_H_EXISTS" != "yes" && test "$kernel_may_have_perf_events_support" = "yes"; then echo "Warning: perf_event.h not found. Either install the kernel headers package or" echo "use the --with-kernel option if you want the non-root, single application" echo "profiling support provided by operf." diff --git a/utils/op_perf_events_checker.c b/utils/op_perf_events_checker.c index 519cafa..74a410e 100644 --- a/utils/op_perf_events_checker.c +++ b/utils/op_perf_events_checker.c @@ -49,8 +49,10 @@ int main(int argc, char **argv) } #if HAVE_PERF_EVENTS - /* If perf_events syscall is not implemented, the syscall below will fail - * with ENOSYS (38). If implemented, but the processor type on which this + /* Even if the perf_event_open syscall is implemented, the architecture may still + * not provide a full implementation of the perf_events subsystem, in which case, + * the syscall below will fail with ENOSYS (38). If the perf_events subsystem is + * implemented for the architecture, but the processor type on which this * program is running is not supported by perf_events, the syscall returns * ENOENT (2). */ -- 1.7.9.7