From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:50086) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bViTV-0000Jj-BF for qemu-devel@nongnu.org; Fri, 05 Aug 2016 12:59:59 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1bViTQ-00036D-9K for qemu-devel@nongnu.org; Fri, 05 Aug 2016 12:59:57 -0400 Received: from roura.ac.upc.edu ([147.83.33.10]:52952 helo=roura.ac.upc.es) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bViTP-000366-Po for qemu-devel@nongnu.org; Fri, 05 Aug 2016 12:59:52 -0400 From: =?utf-8?b?TGx1w61z?= Vilanova Date: Fri, 5 Aug 2016 18:59:50 +0200 Message-Id: <147041639047.2523.7352313284957186583.stgit@fimbulvetr.bsc.es> In-Reply-To: <147041636348.2523.2954972609232949598.stgit@fimbulvetr.bsc.es> References: <147041636348.2523.2954972609232949598.stgit@fimbulvetr.bsc.es> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Subject: [Qemu-devel] [PATCH 5/6] hypertrace: Add guest-side user-level library List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: Stefan Hajnoczi Provides guest library "libqemu-hypertrace-guest.a" to abstract access to the hypertrace channel. Signed-off-by: Llu=C3=ADs Vilanova --- Makefile | 6 + configure | 2=20 hypertrace/guest/user/Makefile | 28 ++++ hypertrace/guest/user/common.c | 221 +++++++++++++++++++++++++= ++++++ hypertrace/guest/user/qemu-hypertrace.h | 77 +++++++++++ 5 files changed, 333 insertions(+), 1 deletion(-) create mode 100644 hypertrace/guest/user/Makefile create mode 100644 hypertrace/guest/user/common.c create mode 100644 hypertrace/guest/user/qemu-hypertrace.h diff --git a/Makefile b/Makefile index 0d7647f..bebd6e6 100644 --- a/Makefile +++ b/Makefile @@ -459,9 +459,13 @@ ifneq (,$(findstring qemu-ga,$(TOOLS))) endif endif =20 +install-hypertrace: + $(INSTALL_DIR) "$(DESTDIR)$(includedir)" + $(INSTALL_DATA) "$(SRC_PATH)/hypertrace/guest/user/qemu-hypertrace.h" "= $(DESTDIR)$(includedir)/" + =20 install: all $(if $(BUILD_DOCS),install-doc) \ -install-datadir install-localstatedir +install-datadir install-localstatedir install-hypertrace ifneq ($(TOOLS),) $(call install-prog,$(subst qemu-ga,qemu-ga$(EXESUF),$(TOOLS)),$(DESTDI= R)$(bindir)) endif diff --git a/configure b/configure index e80fde4..076eb8b 100755 --- a/configure +++ b/configure @@ -5780,6 +5780,8 @@ if [ "$TARGET_BASE_ARCH" =3D "" ]; then fi =20 symlink "$source_path/Makefile.target" "$target_dir/Makefile" +mkdir -p $target_dir/hypertrace/guest/user +symlink $source_path/hypertrace/guest/user/Makefile $target_dir/hypertra= ce/guest/user/Makefile =20 upper() { echo "$@"| LC_ALL=3DC tr '[a-z]' '[A-Z]' diff --git a/hypertrace/guest/user/Makefile b/hypertrace/guest/user/Makef= ile new file mode 100644 index 0000000..bcc9dc9 --- /dev/null +++ b/hypertrace/guest/user/Makefile @@ -0,0 +1,28 @@ +include ../../../../config-host.mak +include ../../../config-target.mak +include $(SRC_PATH)/rules.mak + +vpath % $(SRC_PATH)/hypertrace/guest/user + +# do not use QEMU's per-host cflags when building guest code +QEMU_CFLAGS =3D -Werror -Wall + +QEMU_CFLAGS +=3D $(GLIB_CFLAGS) +QEMU_CFLAGS +=3D -I$(SRC_PATH)/include +QEMU_CFLAGS +=3D -I../../../../linux-headers +QEMU_CFLAGS +=3D -I../../../../ +QEMU_CFLAGS +=3D -I../../../ + +ifdef CONFIG_SOFTMMU +QEMU_CFLAGS +=3D -DNEED_CPU_H +QEMU_CFLAGS +=3D -I$(SRC_PATH)/target-$(TARGET_BASE_ARCH) +endif + +obj-y =3D common.o + +libqemu-hypertrace-guest.a: $(obj-y) + +all: libqemu-hypertrace-guest.a + +clean: + rm -f $(obj-y) libqemu-hypertrace-guest.a diff --git a/hypertrace/guest/user/common.c b/hypertrace/guest/user/commo= n.c new file mode 100644 index 0000000..1429b2a --- /dev/null +++ b/hypertrace/guest/user/common.c @@ -0,0 +1,221 @@ +/* + * Guest-side management of hypertrace. + * + * Copyright (C) 2016 Llu=C3=ADs Vilanova + * + * This work is licensed under the terms of the GNU GPL, version 2 or la= ter. + * See the COPYING file in the top-level directory. + */ + +#include "qemu-hypertrace.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config-host.h" +#include "config-target.h" +#if defined(CONFIG_SOFTMMU) +#include "qemu/osdep.h" +#include "hw/pci/pci.h" +#endif + + +static char *data_path =3D NULL; +static char *control_path =3D NULL; +static int data_fd =3D -1; +static int control_fd =3D -1; + +static uint64_t *data_addr =3D NULL; +static uint64_t *control_addr =3D NULL; + + +static int init_channel_file(const char *base, const char *suffix, size_= t size, + char ** path, int *fd, uint64_t **addr) +{ + *path =3D malloc(strlen(base) + strlen(suffix) + 1); + sprintf(*path, "%s%s", base, suffix); + + *fd =3D open(*path, O_RDWR); + if (*fd =3D=3D -1) { + return -1; + } + + *addr =3D mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, *fd, = 0); + if (*addr =3D=3D MAP_FAILED) { + return -1; + } + return 0; +} + +#if !defined(CONFIG_USER_ONLY) && defined(__linux__) +static int check_device_id (const char *base, const char *name, uint64_t= value) +{ + char tmp[1024]; + sprintf(tmp, "%s/%s", base, name); + + int fd =3D open(tmp, O_RDONLY); + if (fd < 0) { + return -1; + } + + char v[1024]; + ssize_t s =3D read(fd, v, sizeof(v)); + if (s < 0) { + close(fd); + return -1; + } + v[s] =3D '\0'; + + char *end; + uint64_t vv =3D strtoull(v, &end, 16); + if (*end =3D=3D '\n' && vv =3D=3D value) { + return 0; + } + else { + return -1; + } +} + +static char* find_device(void) +{ + static char tmp[1024]; + char *res =3D NULL; + + glob_t g; + if (glob("/sys/devices/pci*/*", GLOB_NOSORT, NULL, &g) !=3D 0) { + return NULL; + } + + + int i; + for (i =3D 0; i < g.gl_pathc; i++) { + char *path =3D g.gl_pathv[i]; + + if (check_device_id(path, "vendor", PCI_VENDOR_ID_REDHAT_QUMRANE= T) < 0) { + continue; + } + if (check_device_id(path, "device", PCI_DEVICE_ID_HYPERTRACE) < = 0) { + continue; + } + + sprintf(tmp, "%s", path); + res =3D tmp; + break; + } + + globfree(&g); + + return res; +} +#endif + +int qemu_hypertrace_init(const char *base) +{ +#if defined(CONFIG_USER_ONLY) + const char *control_suff =3D "-control"; + const size_t control_size =3D getpagesize() * 2; + const char *data_suff =3D "-data"; +#elif defined(__linux__) + const char *control_suff =3D "/resource0"; + const size_t control_size =3D getpagesize(); + const char *data_suff =3D "/resource1"; +#else +#error Unsupported OS +#endif + +#if defined(CONFIG_USER_ONLY) + if (base =3D=3D NULL) { + errno =3D ENOENT; + return -1; + } +#elif defined(__linux__) + if (base =3D=3D NULL) { + /* try to guess the base path */ + base =3D find_device(); + if (base =3D=3D NULL) { + errno =3D ENOENT; + return -1; + } + } +#endif + + int res; + res =3D init_channel_file(base, control_suff, control_size, + &control_path, &control_fd, &control_addr); + if (res !=3D 0) { + return res; + } + + size_t data_size =3D qemu_hypertrace_num_args() * sizeof(uint64_t); + data_size *=3D qemu_hypertrace_max_offset() + 1; + res =3D init_channel_file(base, data_suff, data_size, + &data_path, &data_fd, &data_addr); + if (res !=3D 0) { + return res; + } + return 0; +} + + +static int fini_channel(int *fd, char **path) +{ + if (*fd !=3D -1) { + if (close(*fd) =3D=3D -1) { + return -1; + } + *fd =3D -1; + } + if (*path !=3D NULL) { + free(*path); + *path =3D NULL; + } + return 0; +} + +int qemu_hypertrace_fini(void) +{ + if (fini_channel(&data_fd, &data_path) !=3D 0) { + return -1; + } + if (fini_channel(&control_fd, &control_path) !=3D 0) { + return -1; + } + return 0; +} + + +uint64_t qemu_hypertrace_num_args(void) +{ + return CONFIG_HYPERTRACE_ARGS; +} + +uint64_t qemu_hypertrace_max_offset(void) +{ + return control_addr[0]; +} + +uint64_t *qemu_hypertrace_data(uint64_t data_offset) +{ + return &data_addr[data_offset * CONFIG_HYPERTRACE_ARGS * sizeof(uint= 64_t)]; +} + +void qemu_hypertrace (uint64_t data_offset) +{ + uint64_t *ctrl; + ctrl =3D control_addr; + ctrl[1] =3D data_offset; +#if defined(CONFIG_USER_ONLY) + /* QEMU in 'user' mode uses two faulting pages to detect invocations= */ + ctrl =3D (uint64_t*)((char*)control_addr + getpagesize()); + ctrl[1] =3D data_offset; +#endif +} diff --git a/hypertrace/guest/user/qemu-hypertrace.h b/hypertrace/guest/u= ser/qemu-hypertrace.h new file mode 100644 index 0000000..ba58e49 --- /dev/null +++ b/hypertrace/guest/user/qemu-hypertrace.h @@ -0,0 +1,77 @@ +/* + * Guest-side management of hypertrace. + * + * Copyright (C) 2016 Llu=C3=ADs Vilanova + * + * This work is licensed under the terms of the GNU GPL, version 2 or la= ter. + * See the COPYING file in the top-level directory. + */ + +#include +#include + + +/** + * qemu_hypertrace_init: + * @base: Base path to the hypertrace channel. + * + * Initialize the hypertrace channel. + * + * The base path to the hypertrace channel depends on the type of QEMU t= arget: + * + * - User (single-application) + * The base path provided when starting QEMU ("-hypertrace" commandlin= e + * option). + * + * - System (OS-dependant) + * + Linux + * The base path to the hypertrace channel virtual device; on a defa= ult QEMU + * device setup for x86 this is "/sys/devices/pci0000:00/0000:00:04.= 0". If + * NULL is provided, the hypertrace device will be automatically det= ected. + * + * Returns: Zero on success. + */ +int qemu_hypertrace_init(const char *base); + +/** + * qemu_hypertrace_fini: + * + * Deinitialize the hypertrace channel. + * + * Returns: Zero on success. + */ +int qemu_hypertrace_fini(void); + +/** + * qemu_hypertrace_num_args: + * + * Number of uint64_t values read by each call to qemu_hypertrace(). + */ +uint64_t qemu_hypertrace_num_args(void); + +/** + * qemu_hypertrace_data_size: + * + * Maximum data offset value accepted by other calls. + */ +uint64_t qemu_hypertrace_max_offset(void); + +/** + * qemu_hypertrace_data: + * @data_offset: Offset in multiples of argument packs. + * + * Pointer to the start of the data channel. + */ +uint64_t *qemu_hypertrace_data(uint64_t data_offset); + +/** + * qemu_hypertrace: + * @data_offset: Offset in multiples of argument packs. + * + * Invoke the control channel. + * + * Each of the users (e.g., thread) of the hypertrace channel can use a + * different data offset to ensure they can work concurrently without us= ing + * locks (i.e., each uses a different portion of the data channel). + */ +void qemu_hypertrace(uint64_t data_offset);