Improve ZSTD_get1BlockSummary
Add a faster scalar implementation of ZSTD_get1BlockSummary which removes the data dependency of the accumulators in the hot loop to leverage the superscalar potential of recent out-of-order CPUs. The new algorithm leverages SWAR (SIMD Within A Register) methodology to exploit the capabilities of 64-bit architectures. It achieves this by packing two 32-bit data elements into a single 64-bit register, enabling parallel operations on these subcomponents while ensuring that the 32-bit boundaries prevent overflow, thereby optimizing computational efficiency. Corresponding unit tests are included. Relative performance to GCC-13 using: `./fullbench -b19 -l5 enwik5` Neoverse-V2 before after GCC-13: 100.000% 290.527% GCC-14: 100.000% 291.714% GCC-15: 99.914% 291.495% Clang-18: 148.072% 264.524% Clang-19: 148.075% 264.512% Clang-20: 148.062% 264.490% Cortex-A720 before after GCC-13: 100.000% 235.261% GCC-14: 101.064% 234.903% GCC-15: 112.977% 218.547% Clang-18: 127.135% 180.359% Clang-19: 127.149% 180.297% Clang-20: 127.154% 180.260% Co-authored by, Thomas Daubney <Thomas.Daubney@arm.com>
This commit is contained in:
@@ -45,6 +45,7 @@
|
||||
#include "zstd_internal.h" /* ZSTD_WORKSPACETOOLARGE_MAXDURATION, ZSTD_WORKSPACETOOLARGE_FACTOR, KB, MB */
|
||||
#include "threading.h" /* ZSTD_pthread_create, ZSTD_pthread_join */
|
||||
#include "compress/hist.h" /* HIST_count_wksp */
|
||||
#include "compress/zstd_compress_internal.h" /* ZSTD_get1BlockSummary */
|
||||
|
||||
|
||||
/*-************************************
|
||||
@@ -769,6 +770,86 @@ static void test_blockSplitter_incompressibleExpansionProtection(unsigned testNb
|
||||
DISPLAYLEVEL(3, "OK \n");
|
||||
}
|
||||
|
||||
static unsigned test_get1BlockSummary(unsigned testNb)
|
||||
{
|
||||
static const ZSTD_Sequence nseqs[] = {
|
||||
{ 10, 2, 4, 1 },
|
||||
{ 20, 3, 5, 2 },
|
||||
{ 30, 6, 8, 3 },
|
||||
{ 40, 7, 9, 4 },
|
||||
{ 50, 10, 12, 5 },
|
||||
{ 60, 11, 13, 6 },
|
||||
{ 0, 14, 0, 7 },
|
||||
{ 70, 15, 17, 8 },
|
||||
{ 80, 16, 18, 9 },
|
||||
{ 90, 19, 21, 1 },
|
||||
{ 99, 20, 22, 2 },
|
||||
};
|
||||
static const BlockSummary blocks[] = {
|
||||
{ 7, 104, 53 },
|
||||
{ 6, 98, 51 },
|
||||
{ 5, 90, 48 },
|
||||
{ 4, 76, 42 },
|
||||
{ 3, 60, 35 },
|
||||
{ 2, 38, 25 },
|
||||
{ 1, 14, 14 },
|
||||
};
|
||||
size_t i;
|
||||
|
||||
DISPLAYLEVEL(3, "test%3u : ZSTD_get1BlockSummary with empty array : ", testNb++);
|
||||
{
|
||||
BlockSummary bs = ZSTD_get1BlockSummary(nseqs, 0);
|
||||
CHECK_EQ(bs.nbSequences, ERROR(externalSequences_invalid));
|
||||
}
|
||||
DISPLAYLEVEL(3, "OK \n");
|
||||
|
||||
DISPLAYLEVEL(3, "test%3u : ZSTD_get1BlockSummary with 1 literal only : ", testNb++);
|
||||
{
|
||||
static const ZSTD_Sequence seqs[] = { { 0, 5, 0, 0 } };
|
||||
BlockSummary bs = ZSTD_get1BlockSummary(seqs, 1);
|
||||
CHECK_EQ(bs.nbSequences, 1);
|
||||
CHECK_EQ(bs.litSize, 5);
|
||||
CHECK_EQ(bs.blockSize, 5);
|
||||
}
|
||||
DISPLAYLEVEL(3, "OK \n");
|
||||
|
||||
DISPLAYLEVEL(3, "test%3u : ZSTD_get1BlockSummary with no terminator : ", testNb++);
|
||||
{
|
||||
static const ZSTD_Sequence seqs[] = { { 10, 2, 4, 0 }, { 20, 3, 5, 0 } };
|
||||
BlockSummary bs = ZSTD_get1BlockSummary(seqs, 2);
|
||||
CHECK_EQ(bs.nbSequences, ERROR(externalSequences_invalid));
|
||||
}
|
||||
DISPLAYLEVEL(3, "OK \n");
|
||||
|
||||
DISPLAYLEVEL(3, "test%3u : ZSTD_get1BlockSummary with rep ignored : ", testNb++);
|
||||
{
|
||||
static const ZSTD_Sequence seqs[] = {
|
||||
{ 10, 2, 4, 2 },
|
||||
{ 10, 3, 5, 2 },
|
||||
{ 0, 7, 0, 3 },
|
||||
};
|
||||
BlockSummary bs = ZSTD_get1BlockSummary(seqs, 3);
|
||||
CHECK_EQ(bs.nbSequences, 3);
|
||||
CHECK_EQ(bs.litSize, 2 + 3 + 7);
|
||||
CHECK_EQ(bs.blockSize, (4 + 5) + (2 + 3 + 7));
|
||||
}
|
||||
DISPLAYLEVEL(3, "OK \n");
|
||||
|
||||
assert(COUNTOF(nseqs) > COUNTOF(blocks));
|
||||
for (i = 0; i < COUNTOF(blocks); ++i) {
|
||||
BlockSummary bs;
|
||||
DISPLAYLEVEL(3, "test%3u : ZSTD_get1BlockSummary with %u inputs : ",
|
||||
testNb++, (unsigned)(COUNTOF(nseqs) - i));
|
||||
bs = ZSTD_get1BlockSummary(nseqs + i, COUNTOF(nseqs) - i);
|
||||
CHECK_EQ(bs.nbSequences, blocks[i].nbSequences);
|
||||
CHECK_EQ(bs.litSize, blocks[i].litSize);
|
||||
CHECK_EQ(bs.blockSize, blocks[i].blockSize);
|
||||
DISPLAYLEVEL(3, "OK \n");
|
||||
}
|
||||
|
||||
return testNb;
|
||||
}
|
||||
|
||||
/* ============================================================= */
|
||||
|
||||
static int basicUnitTests(U32 const seed, double compressibility)
|
||||
@@ -4004,6 +4085,8 @@ static int basicUnitTests(U32 const seed, double compressibility)
|
||||
}
|
||||
DISPLAYLEVEL(3, "OK \n");
|
||||
|
||||
testNb = test_get1BlockSummary(testNb);
|
||||
|
||||
DISPLAYLEVEL(3, "test%3i : ZSTD_compressSequencesAndLiterals : ", testNb++);
|
||||
{
|
||||
const size_t srcSize = 497000;
|
||||
|
||||
Reference in New Issue
Block a user