Mika Lindqvist [Sun, 13 Mar 2022 15:12:42 +0000 (17:12 +0200)]
Allow bypassing runtime feature check of TZCNT instructions.
* This avoids conditional branch when it's known at build time that TZCNT instructions are always supported
Adam Stylinski [Mon, 21 Feb 2022 21:52:17 +0000 (16:52 -0500)]
Speed up chunkcopy and memset
This was found to have a significant impact on a highly compressible PNG
for both the encode and decode. Some deltas show performance improving
as much as 60%+.
For the scenarios where the "dist" is not an even modulus of our chunk
size, we simply repeat the bytes as many times as possible into our
vector registers. We then copy the entire vector and then advance the
quotient of our chunksize divided by our dist value.
If dist happens to be 1, there's no reason to not just call memset from
libc (this is likely to be just as fast if not faster).
Adam Stylinski [Mon, 24 Jan 2022 04:32:46 +0000 (23:32 -0500)]
Improve SSE2 slide hash performance
At least on pre-nehalem CPUs, we get a > 50% improvement. This is
mostly due to the fact that we're opportunistically doing aligned loads
instead of unaligned loads. This is something that is very likely to be
possible, given that the deflate stream initialization uses the zalloc
function, which most libraries don't override. Our allocator aligns to
64 byte boundaries, meaning we can do aligned loads on even AVX512 for
the zstream->prev and zstream->head pointers. However, only pre-nehalem
CPUs _actually_ benefit from explicitly aligned load instructions.
The other thing being done here is we're unrolling the loop by a factor
of 2 so that we can get a tiny bit more ILP. This improved performance
by another 5%-7% gain.
Ilya Leoshkevich [Tue, 15 Mar 2022 12:09:04 +0000 (08:09 -0400)]
IBM Z: Delete stale self-hosted builder containers
Due to things like power outage ExecStop may not run, resulting in a
stale actions-runner container. This would prevent ExecStart from
succeeding, so try deleting such stale containers in ExecStartPre.
Adam Stylinski [Mon, 21 Feb 2022 05:17:07 +0000 (00:17 -0500)]
Adding some application-specific benchmarks
So far there's only added png encode and decode with predictably
compressible bytes. This gives us a rough idea of more holistic
impacts of performance improvements (and regressions).
An interesting thing found with this, when compared with stock zlib,
we're slower for png decoding at levels 8 & 9. When we are slower, we
are spending a fair amount of time in the chunk copy function. This
probably merits a closer look.
This code creates optionally an alternative benchmark binary that links
with an alternative static zlib implementation. This can be used to
quickly compare between different forks.
Adam Stylinski [Tue, 8 Feb 2022 22:09:30 +0000 (17:09 -0500)]
Use pclmulqdq accelerated CRC for exported function
We were already using this internally for our CRC calculations, however
the exported function to CRC checksum any arbitrary stream of bytes was
still using a generic C based version that leveraged tables. This
function is now called when len is at least 64 bytes.
Adam Stylinski [Sat, 12 Feb 2022 15:26:50 +0000 (10:26 -0500)]
Improved adler32 NEON performance by 30-47%
We unlocked some ILP by allowing for independent sums in the loop and
reducing these sums outside of the loop. Additionally, the multiplication
by 32 (now 64) is moved outside of this loop. Similar to the chromium
implementation, this code does straight 8 bit -> 16 bit additions and defers
the fused multiply accumulate outside of the loop. However, by unrolling by
another factor of 2, the code is measurably faster. The code does fused multiply
accmulates back to as many scratch registers we have room for in order to maximize
ILP for the 16 integer FMAs that need to occur. The compiler seems to order them
such that the destination register is the same register as the previous instruction,
so perhaps it's not actually able to overlap or maybe the -A73's pipeline is reordering
these instructions, anyway.
On the Odroid-N2, the Cortex-A73 cores are ~30-44% faster on the adler32 benchmark,
and the Cortex-A53 cores are anywhere from 34-47% faster.
Adam Stylinski [Wed, 16 Feb 2022 14:42:40 +0000 (09:42 -0500)]
Unlocked more ILP in SSE variant of adler checksum
This helps uarchs such as sandybridge more than Yorkfield, but there
were some measurable gains on a Core 2 Quad Q9650 as well. We can sum
to two separate vs2 variables and add them back together at the end,
allowing for some overlapping multiply-adds. This was only about a 9-12%
gain on the Q9650 but it nearly doubled performance on cascade lake and
is likely to have appreciable gains on everything in between those two.
Adam Stylinski [Sat, 5 Feb 2022 21:15:46 +0000 (16:15 -0500)]
Improve sse41 adler32 performance
Rather than doing opportunistic aligned loads, we can do scalar
unaligned loads into our two halves of the checksum until we hit
alignment. Then, we can subtract from the max number of sums for the
first run through the loop.
This allows us to force aligned loads for unaligned buffers (likely a
common case for arbitrary runs of memory). This is not meaningful after
Nehalem but pre-Nehalem architectures it makes a substantial difference
to performance and is more foolproof than hoping for an aligned buffer.
Improvement is around 44-50% for unaligned worst case scenarios.
Adam Stylinski [Mon, 21 Feb 2022 21:46:18 +0000 (16:46 -0500)]
Prevent stale stub functions from being called in deflate_slow
Just in case this is the very first call to longest match, we should
instead assign the function pointer instead of the function itself. This
way, by the time it leaves the stub, the function pointer gets
reassigned. This was found incidentally while debugging something else.
Adam Stylinski [Sun, 23 Jan 2022 03:49:04 +0000 (22:49 -0500)]
Write an SSE2 optimized compare256
The SSE4 variant uses the unfortunate string comparison instructions from
SSE4.2 which not only don't work on as many CPUs but, are often slower
than the SSE2 counterparts except in very specific circumstances.
This version should be ~2x faster than unaligned_64 for larger strings
and about half the performance of AVX2 comparisons on identical
hardware.
This version is meant to supplement pre AVX hardware. Because of this,
we're performing 1 extra load + compare at the beginning. In the event
that we're doing a full 256 byte comparison (completely equal strings),
this will result in 2 extra SIMD comparisons if the inputs are unaligned.
Given that the loads will be absorbed by L1, this isn't super likely to
be a giant penalty but for something like a core-i first or second gen,
where unaligned loads aren't nearly as expensive, this going to be
_marginally_ slower in the worst case. This allows us to have half the
loads be aligned, so that the compiler can elide the load and compare by
using a register relative pcmpeqb.
Only define CPU variants that require deflate_state when deflate.h has previously been included. This allows us to include cpu_features.h without including zlib.h or name mangling.
Adam Stylinski [Thu, 3 Feb 2022 23:23:45 +0000 (18:23 -0500)]
Obtained more ILP with VMX by breaking a data dependency
By unrolling and finding the equivalent recurrence relation here, we can
do more independent sums, maximizing ILP. For when the data size fits
into cache, we get a sizable return. For when we don't, it's minor but
still measurable.
Adam Stylinski [Fri, 28 Jan 2022 15:00:07 +0000 (10:00 -0500)]
More than double adler32 performance with altivec
Bits of low hanging and high hanging fruit in this round of
optimization. Altivec has a sum characters into 4 lanes of integers
instructions (intrinsic vec_sum4s) that seems basically made for this
algorithm. Additionally, there's a similar multiply-accumulate routine
that takes two character vectors for input and outputs a vector of 4
ints for their respective adjacent sums. This alone was a good amount
of the performance gains.
Additionally, the shifting by 4 was still done in the loop when it was
easy to roll outside of the loop and do only once. This removed some
latency for a dependent operand to be ready. We also unrolled the loop
with independent sums, though, this only seems to help for much larger
input sizes.
Additionally, we reduced feeding the two 16 bit halves of the sum simply
by packing them into an aligned allocation in the stack next to each
other. Then, when loaded, we permute and shift the values to two
separate vector registers from the same input registers. The separation
of these scalars probably could have been done in vector registers
through some tricks but we need them in scalar GPRs anyhow every time
they leave the loop so it was naturally better to keep those separate
before hitting the vectorized code.
For the horizontal addition, the code was modified to use a sequence of
shifts and adds to produce a vector sum in the first lane. Then, the
much cheaper vec_ste was used to store the value into a general purpose
register rather than vec_extract.
Lastly, instead of doing the relatively expensive modulus in GPRs after
we perform the scalar operations to align all of the loads in the loop,
we can instead reduce "n" here for the first round to be n minus the
alignment offset.
[ARM] rename cmake/configure macros check_{acle,neon}_intrinsics to check_{acle,neon}_compiler_flag
* Currently these macros only check that the compiler flag(s) are supported, not that the compiler supports the actual intrinsics
Michael Hirsch [Tue, 25 Jan 2022 00:22:01 +0000 (19:22 -0500)]
Intel compilers: update deprecated -wn to -Wall style
This removes warnings on every single target like:
icx: command line warning #10430: Unsupported command line options encountered
These options as listed are not supported.
For more information, use '-qnextgen-diag'.
option list:
-w3
Signed-off-by: Michael Hirsch <michael@scivision.dev>
Adam Stylinski [Tue, 25 Jan 2022 05:16:37 +0000 (00:16 -0500)]
Make cmake and configure release flags consistent
CMake sufficiently appends -DNDEBUG to the preprocessor macros when not
compiling with debug symbols. This turns off debug level assertions and
has some other side effects. As such, we should equally append this
define to the configure scripts' CFLAGS.