membarrier: add --enable-membarrier

Actually enable the global memory barriers if supported by the OS.
Because only recent versions of Linux include the support, they
are disabled by default. Note that it also has to be disabled
for QEMU to run under Wine.

Before this patch, rcutorture reports 85 ns/read for my machine,
after the patch it reports 12.5 ns/read. On the other hand updates
go from 50 *micro*seconds to 20 *milli*seconds.

Backports commit a40161cbe9ccbcbab798c3e4d257c4bba99d153a from qemu
This commit is contained in:
Paolo Bonzini 2018-03-17 19:30:33 -04:00 committed by Lioncash
parent 67cb6d16ff
commit 7b52aa7987
No known key found for this signature in database
GPG key ID: 4E3C3CC1031BA9C7
4 changed files with 100 additions and 0 deletions

40
qemu/configure vendored
View file

@ -175,6 +175,7 @@ solaris="no"
softmmu="yes"
pie=""
tcg="yes"
membarrier=""
cpuid_h="no"
avx2_opt="no"
@ -562,6 +563,10 @@ for opt do
;;
--disable-stack-protector) stack_protector="no"
;;
--disable-membarrier) membarrier="no"
;;
--enable-membarrier) membarrier="yes"
;;
*)
echo "ERROR: unknown option $opt"
echo "Try '$0 --help' for more information"
@ -1181,6 +1186,37 @@ if compile_prog "" "" ; then
vector16=yes
fi
##########################################
# check for usable membarrier system call
if test "$membarrier" = "yes"; then
have_membarrier=no
if test "$mingw32" = "yes" ; then
have_membarrier=yes
elif test "$linux" = "yes" ; then
cat > $TMPC << EOF
#include <linux/membarrier.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <stdlib.h>
int main(void) {
syscall(__NR_membarrier, MEMBARRIER_CMD_QUERY, 0);
syscall(__NR_membarrier, MEMBARRIER_CMD_SHARED, 0);
exit(0);
}
EOF
if compile_prog "" "" ; then
have_membarrier=yes
fi
fi
if test "$have_membarrier" = "no"; then
feature_not_found "membarrier" "membarrier system call not available"
fi
else
# Do not enable it by default even for Mingw32, because it doesn't
# work on Wine.
membarrier=no
fi
#########################################
# See if 128-bit atomic operations are supported.
@ -1323,6 +1359,7 @@ if test -n "$sparc_cpu"; then
echo "Target Sparc Arch $sparc_cpu"
fi
echo "PIE $pie"
echo "membarrier $membarrier"
echo "TCG support $tcg"
if test "$tcg" = "yes" ; then
echo "TCG debug enabled $debug_tcg"
@ -1408,6 +1445,9 @@ fi
if test "$bswap_h" = "yes" ; then
echo "CONFIG_MACHINE_BSWAP_H=y" >> $config_host_mak
fi
if test "$membarrier" = "yes" ; then
echo "CONFIG_MEMBARRIER=y" >> $config_host_mak
fi
if test "$tcg" = "yes"; then
echo "CONFIG_TCG=y" >> $config_host_mak
if test "$tcg_interpreter" = "yes" ; then

View file

@ -9,9 +9,19 @@
#ifndef QEMU_SYS_MEMBARRIER_H
#define QEMU_SYS_MEMBARRIER_H 1
#ifdef CONFIG_MEMBARRIER
/* Only block reordering at the compiler level in the performance-critical
* side. The slow side forces processor-level ordering on all other cores
* through a system call.
*/
extern void smp_mb_global_init(void);
extern void smp_mb_global(void);
#define smp_mb_placeholder() barrier()
#else
/* Keep it simple, execute a real memory barrier on both sides. */
static inline void smp_mb_global_init(void) {}
#define smp_mb_global() smp_mb()
#define smp_mb_placeholder() smp_mb()
#endif
#endif

View file

@ -11,3 +11,4 @@ util-obj-y += host-utils.o
util-obj-y += getauxval.o
util-obj-y += log.o
util-obj-y += range.o
util-obj-$(CONFIG_MEMBARRIER) += sys_membarrier.o

View file

@ -0,0 +1,49 @@
/*
* Process-global memory barriers
*
* Copyright (c) 2018 Red Hat, Inc.
*
* Author: Paolo Bonzini <pbonzini@redhat.com>
*/
#include <qemu/osdep.h>
#include <qemu/sys_membarrier.h>
#ifdef CONFIG_LINUX
#include <linux/membarrier.h>
#include <sys/syscall.h>
static int
membarrier(int cmd, int flags)
{
return syscall(__NR_membarrier, cmd, flags);
}
#endif
void smp_mb_global(void)
{
#if defined CONFIG_WIN32
FlushProcessWriteBuffers();
#elif defined CONFIG_LINUX
membarrier(MEMBARRIER_CMD_SHARED, 0);
#else
#error --enable-membarrier is not supported on this operating system.
#endif
}
void smp_mb_global_init(void)
{
#ifdef CONFIG_LINUX
int ret = membarrier(MEMBARRIER_CMD_QUERY, 0);
if (ret < 0) {
//error_report("This QEMU binary requires the membarrier system call.");
//error_report("Please upgrade your system to a newer version of Linux");
exit(1);
}
if (!(ret & MEMBARRIER_CMD_SHARED)) {
//error_report("This QEMU binary requires MEMBARRIER_CMD_SHARED support.");
//error_report("Please upgrade your system to a newer version of Linux");
exit(1);
}
#endif
}