The improved performance from Program Steppings

Quxlang is introducing a new feature called program steppings. Program steppings allow portable Quxlang to beat Clang and GCC C++ in performance.

While both Clang and QXC (the official Quxlang compiler) use LLVM as their backend, C++ compilers like GCC and Clang have a major limitation, they cannot easily produce binaries that are both portable and high performance.

While we can produce binaries that target x64, there are many different x64 processors, which support different features like SSE4, AVX, and AVX512. For example, AMD Ryzen 7000 and 9000 series processors support the AVX512 instructions, but the AMD Ryzen 5000 series processors do not.

To get the maximum performance out of a C++ binary, the usual option in C++ is to set -march=value, this enables instructions that correspond to different CPU features. But the big downside of this is that the resulting program cannot run on older CPUs. This means that a portable binary in C++ is usually compiled for a certain baseline, which limits the performance of the binary. Generally, you have a choice, using a baseline like -march=x86-64-v1 or -march=x86-64-v2 where it will work with most CPUs, or using an option like x86-64-v3 which works with more recent CPUs but will refuse to run on older processors, or even x86-64-v4 which only works on the most recent CPUs from Intel and AMD. Given that -march=x86-64-v1 is the most compatible, that is the default choice of Clang (excluding distro patches). But there is a downside, because on CPUs that support it, using x86-64-v4 will provide better performance.

Quxlang solves this by compiling the whole program after the main function at multiple stepping levels. When the program starts, the runtime uses feature detection to decide what the highest supported stepping level is, then selects a compiled procedure for the main function that corresponds to the highest supported stepping to execute.

A simple integer blur benchmark shows that Quxlang defeats GCC -O2 if the architecture level is not upgraded beyond the default:

Implementation Run 1 Run 2 Run 3 Median
C++ GCC 13.3 -O2 488.1 ms 392.8 ms 384.8 ms 392.8 ms
Quxlang Release 351.3 ms 323.8 ms 259.5 ms 323.8 ms

Quxlang’s median time was approximately 17.6% lower, equivalent to about 1.21× the throughput. Of course, GCC can easily match Quxlang’s performance using a flag like -march=native. But the produced binary would not be capable of running on older CPUs. This wasn’t an extensive benchmark, but the runs were interleaved and the improvement is obvious.

While GCC does have function multi-versioning as a compiler extension, it is not automatically implemented program-wide. In contrast, Quxlang steppings provide an enabled-by-default program-wide optimization that also doesn’t require a runtime dispatch on function entry. Quxlang provides a portable solution that works across Windows, MacOS, Linux, and across all supported CPU architectures.

The downside of steppings is that they do increase the binary size, but an intelligent operating system doesn’t need to load unused steppings from disk. Steppings can be customized from the Quxlang build file, and will be enabled by default in higher optimization Release level presets.

Leave a comment