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 <sbrivio(a)redhat.com>
---
v2: Add arch.c and arch.h to commit
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 <sbrivio(a)redhat.com>
+ */
+
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+/**
+ * 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 <sbrivio(a)redhat.com>
+ */
+
+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
--
2.34.1