From 213c397492bdc64cf26b2e7b3877e4a29dc9f8da Mon Sep 17 00:00:00 2001 From: Stefano Brivio Date: Mon, 28 Feb 2022 16:18:44 +0100 Subject: [PATCH] passt, pasta: Run-time selection of AVX2 build Build-time selection of AVX2 flags and routines is not practical for distributions, but limiting AVX2 usage to checksum routines with specific run-time detection doesn't allow for easy performance gains from auto-vectorisation of batched packet handling routines. For x86_64, build non-AVX2 and AVX2 binaries, and implement a simple wrapper replacing the current executable with the AVX2 build if it's available, and if AVX2 is supported by the current CPU. Signed-off-by: Stefano Brivio --- Makefile | 38 ++++++++++++++++++++++++++++---------- README.md | 28 +++++++++++----------------- arch.c | 42 ++++++++++++++++++++++++++++++++++++++++++ arch.h | 6 ++++++ hooks/pre-push | 9 --------- passt.c | 3 +++ test/build/all | 10 ---------- test/demo/passt | 2 +- test/demo/pasta | 2 +- 9 files changed, 92 insertions(+), 48 deletions(-) create mode 100644 arch.c create mode 100644 arch.h diff --git a/Makefile b/Makefile index 031b684..8387719 100644 --- a/Makefile +++ b/Makefile @@ -14,8 +14,11 @@ ifeq ($(RLIMIT_STACK_VAL),unlimited) RLIMIT_STACK_VAL := 1024 endif -AUDIT_ARCH := $(shell uname -m | tr [a-z] [A-Z]) -AUDIT_ARCH := $(shell echo $(AUDIT_ARCH) | sed 's/^ARM.*/ARM/') +# Get 'uname -m'-like architecture description for target +TARGET_ARCH := $(shell $(CC) -dumpmachine | cut -f1 -d- | tr [a-z] [A-Z]) +TARGET_ARCH := $(shell echo $(TARGET_ARCH) | sed 's/POWERPC/PPC/') + +AUDIT_ARCH := $(shell echo $(TARGET_ARCH) | sed 's/^ARM.*/ARM/') AUDIT_ARCH := $(shell echo $(AUDIT_ARCH) | sed 's/I[456]86/I386/') AUDIT_ARCH := $(shell echo $(AUDIT_ARCH) | sed 's/PPC64/PPC/') AUDIT_ARCH := $(shell echo $(AUDIT_ARCH) | sed 's/PPCLE/PPC64LE/') @@ -25,7 +28,7 @@ CFLAGS += -DPAGE_SIZE=$(shell getconf PAGE_SIZE) CFLAGS += -DNETNS_RUN_DIR=\"/run/netns\" CFLAGS += -DPASST_AUDIT_ARCH=AUDIT_ARCH_$(AUDIT_ARCH) CFLAGS += -DRLIMIT_STACK_VAL=$(RLIMIT_STACK_VAL) -CFLAGS += -DARCH=\"$(shell uname -m)\" +CFLAGS += -DARCH=\"$(TARGET_ARCH)\" # On gcc 11.2, with -O2 and -flto, tcp_hash() and siphash_20b(), if inlined, # seem to be hitting something similar to: @@ -63,10 +66,13 @@ endif prefix ?= /usr/local +ifeq ($(TARGET_ARCH),X86_64) +all: passt passt.avx2 pasta pasta.avx2 qrap +BIN := passt passt.avx2 pasta pasta.avx2 qrap +else all: passt pasta qrap - -avx2: CFLAGS += -Ofast -mavx2 -ftree-vectorize -funroll-loops -avx2: clean all +BIN := passt pasta qrap +endif static: CFLAGS += -static -DGLIBC_NO_STATIC_NSS static: clean all @@ -78,6 +84,16 @@ passt: $(filter-out qrap.c,$(wildcard *.c)) \ $(filter-out qrap.h,$(wildcard *.h)) seccomp.h $(CC) $(CFLAGS) $(filter-out qrap.c,$(wildcard *.c)) -o passt +passt.avx2: CFLAGS += -Ofast -mavx2 -ftree-vectorize -funroll-loops +passt.avx2: $(filter-out qrap.c,$(wildcard *.c)) \ + $(filter-out qrap.h,$(wildcard *.h)) seccomp.h + $(CC) $(CFLAGS) $(filter-out qrap.c,$(wildcard *.c)) -o passt.avx2 + +passt.avx2: passt + +pasta.avx2: passt.avx2 + ln -s passt.avx2 pasta.avx2 + pasta: passt ln -s passt pasta ln -s passt.1 pasta.1 @@ -88,24 +104,26 @@ qrap: qrap.c passt.h .PHONY: clean clean: - -${RM} passt *.o seccomp.h qrap pasta pasta.1 \ + -${RM} passt passt.avx2 *.o seccomp.h qrap pasta pasta.avx2 pasta.1 \ passt.tar passt.tar.gz *.deb *.rpm -install: passt pasta qrap +install: $(BIN) mkdir -p $(DESTDIR)$(prefix)/bin $(DESTDIR)$(prefix)/share/man/man1 - cp -d passt pasta qrap $(DESTDIR)$(prefix)/bin + cp -d $(BIN) $(DESTDIR)$(prefix)/bin cp -d passt.1 pasta.1 qrap.1 $(DESTDIR)$(prefix)/share/man/man1 uninstall: -${RM} $(DESTDIR)$(prefix)/bin/passt + -${RM} $(DESTDIR)$(prefix)/bin/passt.avx2 -${RM} $(DESTDIR)$(prefix)/bin/pasta + -${RM} $(DESTDIR)$(prefix)/bin/pasta.avx2 -${RM} $(DESTDIR)$(prefix)/bin/qrap -${RM} $(DESTDIR)$(prefix)/share/man/man1/passt.1 -${RM} $(DESTDIR)$(prefix)/share/man/man1/pasta.1 -${RM} $(DESTDIR)$(prefix)/share/man/man1/qrap.1 pkgs: - tar cf passt.tar -P --xform 's//\/usr\/bin\//' passt pasta qrap + tar cf passt.tar -P --xform 's//\/usr\/bin\//' $(BIN) tar rf passt.tar -P --xform 's//\/usr\/share\/man\/man1\//' \ passt.1 pasta.1 qrap.1 gzip passt.tar diff --git a/README.md b/README.md index 14e1777..4966e15 100644 --- a/README.md +++ b/README.md @@ -220,7 +220,7 @@ speeding up local connections, and usually requiring NAT. _pasta_: * Linux * ✅ starting from 4.18 kernel version * ✅ starting from 3.13 kernel version -* 🛠 build-time selection of AVX2 instructions (as much as possible) +* ✅ run-time selection of AVX2 build * ⌚ [_musl_](https://bugs.passt.top/show_bug.cgi?id=4) and [_uClibc-ng_](https://bugs.passt.top/show_bug.cgi?id=5) * ⌚ [FreeBSD](https://bugs.passt.top/show_bug.cgi?id=6), @@ -467,15 +467,12 @@ Test logs [here](/builds/latest/test/). cd passt make - * alternatively, static builds for x86_64, with or without AVX2 instructions, - as of the latest commit are also available for convenience - [here](/builds/latest/x86_64/avx2/) and - [here](/builds/latest/x86_64/). Convenience, non-official - packages for Debian (and derivatives) and RPM-based distributions are also - available there. These binaries and packages are simply built with: + * alternatively, static builds for x86_64 as of the latest commit are also + available for convenience [here](/builds/latest/x86_64/). Convenience, + non-official packages for Debian (and derivatives) and RPM-based + distributions are also available there. These binaries and packages are + simply built with: - CFLAGS="-static" make avx2 - make pkgs make static make pkgs @@ -530,15 +527,12 @@ Test logs [here](/builds/latest/test/). cd passt make - * alternatively, static builds for x86_64, with or without AVX2 instructions, - as of the latest commit are also available for convenience - [here](/builds/latest/x86_64/avx2/) and - [here](/builds/latest/x86_64/). Convenience, non-official - packages for Debian (and derivatives) and RPM-based distributions are also - available there. These binaries and packages are simply built with: + * alternatively, static builds for x86_64 as of the latest commit are also + available for convenience [here](/builds/latest/x86_64/). Convenience, + non-official packages for Debian (and derivatives) and RPM-based + distributions are also available there. These binaries and packages are + simply built with: - CFLAGS="-static" make avx2 - make pkgs make static make pkgs diff --git a/arch.c b/arch.c new file mode 100644 index 0000000..b8e1db5 --- /dev/null +++ b/arch.c @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +/* PASST - Plug A Simple Socket Transport + * for qemu/UNIX domain socket mode + * + * PASTA - Pack A Subtle Tap Abstraction + * for network namespace/tap device mode + * + * arch.c - Architecture-specific implementations + * + * Copyright (c) 2022 Red Hat GmbH + * Author: Stefano Brivio + */ + +#include +#include +#include +#include + +/** + * arch_avx2_exec() - Run AVX2 build if supported, drop suffix from argv[0] + * @argv: Arguments from command line + */ +#ifdef __x86_64__ +void arch_avx2_exec(char **argv) +{ + char *p = strstr(argv[0], ".avx2"); + + if (p) { + *p = 0; + } else if (__builtin_cpu_supports("avx2")) { + char path[PATH_MAX]; + + snprintf(path, PATH_MAX, "%s.avx2", argv[0]); + argv[0] = path; + execve(path, argv, environ); + perror("Can't run AVX2 build, using non-AVX2 version"); + } +} +#else +void arch_avx2_exec(char **argv) { (void)argv; } +#endif diff --git a/arch.h b/arch.h new file mode 100644 index 0000000..ce1c01b --- /dev/null +++ b/arch.h @@ -0,0 +1,6 @@ +/* SPDX-License-Identifier: AGPL-3.0-or-later + * Copyright (c) 2022 Red Hat GmbH + * Author: Stefano Brivio + */ + +void arch_avx2_exec(char **argv); diff --git a/hooks/pre-push b/hooks/pre-push index a3f67f4..6a9b712 100755 --- a/hooks/pre-push +++ b/hooks/pre-push @@ -58,15 +58,6 @@ ssh "${USER_HOST}" "rm -f ${BIN}/*.deb" ssh "${USER_HOST}" "rm -f ${BIN}/*.rpm" scp *.deb *.rpm "${USER_HOST}:${BIN}/" -CFLAGS="-static -DGLIBC_NO_STATIC_NSS" make avx2 -ssh "${USER_HOST}" "mkdir -p ${BIN}/avx2" -scp passt pasta qrap passt.1 pasta.1 qrap.1 "${USER_HOST}:${BIN}/avx2/" - -make pkgs -ssh "${USER_HOST}" "rm -f ${BIN}/avx2/*.deb" -ssh "${USER_HOST}" "rm -f ${BIN}/avx2/*.rpm" -scp *.deb *.rpm "${USER_HOST}:${BIN}/avx2/" - ssh "${USER_HOST}" "mv ${LATEST} ${AWAY}" ssh "${USER_HOST}" "mv ${TEMP} ${LATEST}" ssh "${USER_HOST}" "rm -rf ${AWAY}" diff --git a/passt.c b/passt.c index e7dd108..40d3e57 100644 --- a/passt.c +++ b/passt.c @@ -69,6 +69,7 @@ #include "tap.h" #include "conf.h" #include "pasta.h" +#include "arch.h" #define EPOLL_EVENTS 8 @@ -313,6 +314,8 @@ int main(int argc, char **argv) struct sigaction sa; char *log_name; + arch_avx2_exec(argv); + check_root(); drop_caps(); diff --git a/test/build/all b/test/build/all index 9aa6c61..6043793 100644 --- a/test/build/all +++ b/test/build/all @@ -40,13 +40,3 @@ host CFLAGS="-Werror" make check [ -f passt ] check [ -h pasta ] check [ -f qrap ] - -test Build AVX2 -host make clean -check ! [ -e passt ] -check ! [ -e pasta ] -check ! [ -e qrap ] -host CFLAGS="-Werror" make avx2 -check [ -f passt ] -check [ -h pasta ] -check [ -f qrap ] diff --git a/test/demo/passt b/test/demo/passt index 76aac86..8838363 100644 --- a/test/demo/passt +++ b/test/demo/passt @@ -29,7 +29,7 @@ sleep 1 say and build it. sleep 1 host cd passt -host make avx2 +host make sleep 1 nl diff --git a/test/demo/pasta b/test/demo/pasta index b2dd327..74fca85 100644 --- a/test/demo/pasta +++ b/test/demo/pasta @@ -169,7 +169,7 @@ say more in the "Performance" section below. sleep 3 ns exit passt exit -passt CFLAGS="-g" make avx2 +passt CFLAGS="-g" make sleep 2 passtb perf record -g ./pasta sleep 2