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 <sbrivio@redhat.com>
This commit is contained in:
Stefano Brivio 2022-02-28 16:18:44 +01:00
parent deca1ebe50
commit 213c397492
9 changed files with 92 additions and 48 deletions

View file

@ -14,8 +14,11 @@ ifeq ($(RLIMIT_STACK_VAL),unlimited)
RLIMIT_STACK_VAL := 1024 RLIMIT_STACK_VAL := 1024
endif endif
AUDIT_ARCH := $(shell uname -m | tr [a-z] [A-Z]) # Get 'uname -m'-like architecture description for target
AUDIT_ARCH := $(shell echo $(AUDIT_ARCH) | sed 's/^ARM.*/ARM/') 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/I[456]86/I386/')
AUDIT_ARCH := $(shell echo $(AUDIT_ARCH) | sed 's/PPC64/PPC/') AUDIT_ARCH := $(shell echo $(AUDIT_ARCH) | sed 's/PPC64/PPC/')
AUDIT_ARCH := $(shell echo $(AUDIT_ARCH) | sed 's/PPCLE/PPC64LE/') 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 += -DNETNS_RUN_DIR=\"/run/netns\"
CFLAGS += -DPASST_AUDIT_ARCH=AUDIT_ARCH_$(AUDIT_ARCH) CFLAGS += -DPASST_AUDIT_ARCH=AUDIT_ARCH_$(AUDIT_ARCH)
CFLAGS += -DRLIMIT_STACK_VAL=$(RLIMIT_STACK_VAL) 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, # On gcc 11.2, with -O2 and -flto, tcp_hash() and siphash_20b(), if inlined,
# seem to be hitting something similar to: # seem to be hitting something similar to:
@ -63,10 +66,13 @@ endif
prefix ?= /usr/local 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 all: passt pasta qrap
BIN := passt pasta qrap
avx2: CFLAGS += -Ofast -mavx2 -ftree-vectorize -funroll-loops endif
avx2: clean all
static: CFLAGS += -static -DGLIBC_NO_STATIC_NSS static: CFLAGS += -static -DGLIBC_NO_STATIC_NSS
static: clean all static: clean all
@ -78,6 +84,16 @@ passt: $(filter-out qrap.c,$(wildcard *.c)) \
$(filter-out qrap.h,$(wildcard *.h)) seccomp.h $(filter-out qrap.h,$(wildcard *.h)) seccomp.h
$(CC) $(CFLAGS) $(filter-out qrap.c,$(wildcard *.c)) -o passt $(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 pasta: passt
ln -s passt pasta ln -s passt pasta
ln -s passt.1 pasta.1 ln -s passt.1 pasta.1
@ -88,24 +104,26 @@ qrap: qrap.c passt.h
.PHONY: clean .PHONY: clean
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 passt.tar passt.tar.gz *.deb *.rpm
install: passt pasta qrap install: $(BIN)
mkdir -p $(DESTDIR)$(prefix)/bin $(DESTDIR)$(prefix)/share/man/man1 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 cp -d passt.1 pasta.1 qrap.1 $(DESTDIR)$(prefix)/share/man/man1
uninstall: uninstall:
-${RM} $(DESTDIR)$(prefix)/bin/passt -${RM} $(DESTDIR)$(prefix)/bin/passt
-${RM} $(DESTDIR)$(prefix)/bin/passt.avx2
-${RM} $(DESTDIR)$(prefix)/bin/pasta -${RM} $(DESTDIR)$(prefix)/bin/pasta
-${RM} $(DESTDIR)$(prefix)/bin/pasta.avx2
-${RM} $(DESTDIR)$(prefix)/bin/qrap -${RM} $(DESTDIR)$(prefix)/bin/qrap
-${RM} $(DESTDIR)$(prefix)/share/man/man1/passt.1 -${RM} $(DESTDIR)$(prefix)/share/man/man1/passt.1
-${RM} $(DESTDIR)$(prefix)/share/man/man1/pasta.1 -${RM} $(DESTDIR)$(prefix)/share/man/man1/pasta.1
-${RM} $(DESTDIR)$(prefix)/share/man/man1/qrap.1 -${RM} $(DESTDIR)$(prefix)/share/man/man1/qrap.1
pkgs: 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\//' \ tar rf passt.tar -P --xform 's//\/usr\/share\/man\/man1\//' \
passt.1 pasta.1 qrap.1 passt.1 pasta.1 qrap.1
gzip passt.tar gzip passt.tar

View file

@ -220,7 +220,7 @@ speeding up local connections, and usually requiring NAT. _pasta_:
* Linux * Linux
* ✅ starting from 4.18 kernel version * ✅ starting from 4.18 kernel version
* ✅ starting from 3.13 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 * ⌚ [_musl_](https://bugs.passt.top/show_bug.cgi?id=4) and
[_uClibc-ng_](https://bugs.passt.top/show_bug.cgi?id=5) [_uClibc-ng_](https://bugs.passt.top/show_bug.cgi?id=5)
* ⌚ [FreeBSD](https://bugs.passt.top/show_bug.cgi?id=6), * ⌚ [FreeBSD](https://bugs.passt.top/show_bug.cgi?id=6),
@ -467,15 +467,12 @@ Test logs [here](/builds/latest/test/).
cd passt cd passt
make make
* alternatively, static builds for x86_64, with or without AVX2 instructions, * alternatively, static builds for x86_64 as of the latest commit are also
as of the latest commit are also available for convenience available for convenience [here](/builds/latest/x86_64/). Convenience,
[here](/builds/latest/x86_64/avx2/) and non-official packages for Debian (and derivatives) and RPM-based
[here](/builds/latest/x86_64/). Convenience, non-official distributions are also available there. These binaries and packages are
packages for Debian (and derivatives) and RPM-based distributions are also simply built with:
available there. These binaries and packages are simply built with:
CFLAGS="-static" make avx2
make pkgs
make static make static
make pkgs make pkgs
@ -530,15 +527,12 @@ Test logs [here](/builds/latest/test/).
cd passt cd passt
make make
* alternatively, static builds for x86_64, with or without AVX2 instructions, * alternatively, static builds for x86_64 as of the latest commit are also
as of the latest commit are also available for convenience available for convenience [here](/builds/latest/x86_64/). Convenience,
[here](/builds/latest/x86_64/avx2/) and non-official packages for Debian (and derivatives) and RPM-based
[here](/builds/latest/x86_64/). Convenience, non-official distributions are also available there. These binaries and packages are
packages for Debian (and derivatives) and RPM-based distributions are also simply built with:
available there. These binaries and packages are simply built with:
CFLAGS="-static" make avx2
make pkgs
make static make static
make pkgs make pkgs

42
arch.c Normal file
View file

@ -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@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

6
arch.h Normal file
View file

@ -0,0 +1,6 @@
/* SPDX-License-Identifier: AGPL-3.0-or-later
* Copyright (c) 2022 Red Hat GmbH
* Author: Stefano Brivio <sbrivio@redhat.com>
*/
void arch_avx2_exec(char **argv);

View file

@ -58,15 +58,6 @@ ssh "${USER_HOST}" "rm -f ${BIN}/*.deb"
ssh "${USER_HOST}" "rm -f ${BIN}/*.rpm" ssh "${USER_HOST}" "rm -f ${BIN}/*.rpm"
scp *.deb *.rpm "${USER_HOST}:${BIN}/" 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 ${LATEST} ${AWAY}"
ssh "${USER_HOST}" "mv ${TEMP} ${LATEST}" ssh "${USER_HOST}" "mv ${TEMP} ${LATEST}"
ssh "${USER_HOST}" "rm -rf ${AWAY}" ssh "${USER_HOST}" "rm -rf ${AWAY}"

View file

@ -69,6 +69,7 @@
#include "tap.h" #include "tap.h"
#include "conf.h" #include "conf.h"
#include "pasta.h" #include "pasta.h"
#include "arch.h"
#define EPOLL_EVENTS 8 #define EPOLL_EVENTS 8
@ -313,6 +314,8 @@ int main(int argc, char **argv)
struct sigaction sa; struct sigaction sa;
char *log_name; char *log_name;
arch_avx2_exec(argv);
check_root(); check_root();
drop_caps(); drop_caps();

View file

@ -40,13 +40,3 @@ host CFLAGS="-Werror" make
check [ -f passt ] check [ -f passt ]
check [ -h pasta ] check [ -h pasta ]
check [ -f qrap ] 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 ]

View file

@ -29,7 +29,7 @@ sleep 1
say and build it. say and build it.
sleep 1 sleep 1
host cd passt host cd passt
host make avx2 host make
sleep 1 sleep 1
nl nl

View file

@ -169,7 +169,7 @@ say more in the "Performance" section below.
sleep 3 sleep 3
ns exit ns exit
passt exit passt exit
passt CFLAGS="-g" make avx2 passt CFLAGS="-g" make
sleep 2 sleep 2
passtb perf record -g ./pasta passtb perf record -g ./pasta
sleep 2 sleep 2