The x86/ARM split asked for on macOS already exists: BitShuffleBlock.h (fbc507839) sends
the per-block transform to bitshuffle_hperf everywhere except aarch64 with NEON, where it
uses the classic bitshuffle's NEON path, and both call sites go through it. Nothing new is
needed for Apple Silicon - clang --target=arm64-apple-macos defines __aarch64__ and
__ARM_NEON exactly as aarch64 Linux does, both vendored files compile to arm64 Mach-O
objects, the seam resolves to bshuf_(un)trans_bit_elem and bshuf_using_NEON() is 1. The
header now says why the switch is a preprocessor one: a universal build compiles it once
per architecture, which a CMake-time answer cannot follow.
What had never happened is the NEON code actually running. It has now, under
qemu-aarch64 in the project's cross image: 504 blocks (elem 1/2/4/8, 8 elements up to the
128 kB block, odd multiples of 8, random and detector-like data) plus 54 whole-buffer
bitshuffle/LZ4 streams with element counts that are no multiple of 8 or of the block. The
output is byte-identical (same md5) across aarch64 NEON, aarch64 without NEON (seam falls
back to hperf's portable code), x86 hperf AVX2 via ifunc, hperf SSE2, hperf portable
fallback, and classic SSE2 / AVX2 / scalar; every implementation decodes every other.
Throughput, one thread on a loaded Zen 3, 16/32-bit, GB/s encode/decode: hperf AVX2
~9-12/~10-11, classic AVX2 ~8/~5.5-8, classic SSE2 ~4-5/~4.5-5.5, hperf portable fallback
auto-vectorised ~2.8/~5, not vectorised ~1/~1.8. Classic 128-bit SIMD beating hperf's
fallback is the x86 stand-in for the choice the seam makes on ARM; no ARM hardware was
available, so the NEON-vs-fallback ranking on a real core is still unmeasured.
The one thing that would have failed on aarch64 is the Bshuf_SSE test, which required
SSE2 outright. It now accepts NEON as well, which also makes it the check that a Mac or
DGX Spark build did not end up on the scalar path.
Not built: no CMake configure or jfjoch_test build was run on this machine (busy); the
test expression was compiled and run standalone on x86 only.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit 5957b15493dfd0cc8a18fb780a18c2573a6eccde)
590 lines
28 KiB
C++
590 lines
28 KiB
C++
// SPDX-FileCopyrightText: 2024 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
|
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
#include <catch2/catch_all.hpp>
|
|
#include <iostream>
|
|
#include <bitshuffle/bitshuffle.h>
|
|
|
|
#include "../receiver/FrameTransformation.h"
|
|
#include "../common/RawToConvertedGeometry.h"
|
|
#include "../compression/JFJochDecompress.h"
|
|
#include <random>
|
|
|
|
using namespace std::literals::chrono_literals;
|
|
|
|
inline uint32_t read_be32(const void *ptr) {
|
|
auto ptr32 = (uint32_t *) ptr;
|
|
return __builtin_bswap32(ptr32[0]);
|
|
}
|
|
|
|
inline uint64_t read_be64(const void *ptr) {
|
|
auto ptr64 = (uint64_t *) ptr;
|
|
return __builtin_bswap64(ptr64[0]);
|
|
}
|
|
|
|
// The classic bitshuffle runs behind the HDF5 filter everywhere, and on aarch64 it is also the one
|
|
// BitShuffleBlock.h picks, so a build that left it on its scalar path must not go unnoticed.
|
|
TEST_CASE("Bshuf_SIMD", "[bitshuffle]") {
|
|
REQUIRE ((bshuf_using_SSE2() == 1 || bshuf_using_NEON() == 1));
|
|
}
|
|
|
|
TEST_CASE("FrameTransformation_Raw_NoCompression" ,"") {
|
|
const uint16_t nmodules = 4;
|
|
const uint16_t ndatastreams = 2;
|
|
DiffractionExperiment experiment(DetJF(ndatastreams * nmodules, 1));
|
|
experiment.DataStreams(ndatastreams);
|
|
|
|
experiment.Raw();
|
|
experiment.Compression(CompressionAlgorithm::NO_COMPRESSION);
|
|
|
|
FrameTransformation transformation(experiment);
|
|
|
|
std::mt19937 g1(1587);
|
|
std::uniform_int_distribution<int16_t> dist;
|
|
|
|
std::vector<int16_t> input_0(nmodules*RAW_MODULE_SIZE);
|
|
for (int i = 0; i < nmodules*RAW_MODULE_SIZE; i++)
|
|
input_0[i] = dist(g1);
|
|
|
|
std::vector<int16_t> input_1(nmodules*RAW_MODULE_SIZE);
|
|
for (int i = 0; i < nmodules*RAW_MODULE_SIZE; i++)
|
|
input_1[i] = dist(g1);
|
|
|
|
for (int i = 0; i < nmodules; i++) {
|
|
REQUIRE_NOTHROW(transformation.ProcessModule(input_0.data() + i * RAW_MODULE_SIZE, i, 0));
|
|
REQUIRE_NOTHROW(transformation.ProcessModule(input_1.data() + i * RAW_MODULE_SIZE, i, 1));
|
|
}
|
|
auto image = transformation.GetCompressedImage();
|
|
REQUIRE(image.GetCompressedSize() == experiment.GetByteDepthImage() * experiment.GetPixelsNum());
|
|
auto output = (int16_t *) image.GetCompressed();
|
|
|
|
uint32_t diff_0 = 0;
|
|
uint32_t diff_1 = 0;
|
|
|
|
for (int i = 0; i < nmodules*RAW_MODULE_SIZE; i++) {
|
|
if (input_0[i] != output[i]) diff_0++;
|
|
if (input_1[i] != output[i + nmodules*RAW_MODULE_SIZE]) diff_1++;
|
|
}
|
|
REQUIRE(diff_0 == 0);
|
|
REQUIRE(diff_1 == 0);
|
|
}
|
|
|
|
TEST_CASE("FrameTransformation_Raw_NoCompression_bshuf_lz4" ,"") {
|
|
const uint16_t nmodules = 4;
|
|
const uint16_t ndatastreams = 2;
|
|
DiffractionExperiment experiment(DetJF(ndatastreams * nmodules, 1));
|
|
experiment.DataStreams(ndatastreams);
|
|
|
|
experiment.Raw();
|
|
experiment.Compression(CompressionAlgorithm::BSHUF_LZ4);
|
|
|
|
FrameTransformation transformation(experiment);
|
|
|
|
std::mt19937 g1(1587);
|
|
std::uniform_int_distribution<int16_t> dist;
|
|
|
|
std::vector<int16_t> input_0(nmodules*RAW_MODULE_SIZE);
|
|
for (int i = 0; i < nmodules*RAW_MODULE_SIZE; i++)
|
|
input_0[i] = dist(g1);
|
|
|
|
std::vector<int16_t> input_1(nmodules*RAW_MODULE_SIZE);
|
|
for (int i = 0; i < nmodules*RAW_MODULE_SIZE; i++)
|
|
input_1[i] = dist(g1);
|
|
|
|
for (int i = 0; i < nmodules; i++) {
|
|
REQUIRE_NOTHROW(transformation.ProcessModule(input_0.data() + i * RAW_MODULE_SIZE, i, 0));
|
|
REQUIRE_NOTHROW(transformation.ProcessModule(input_1.data() + i * RAW_MODULE_SIZE, i, 1));
|
|
}
|
|
|
|
auto image = transformation.GetCompressedImage();
|
|
|
|
REQUIRE(read_be64(image.GetCompressed()) == experiment.GetPixelsNum() * experiment.GetByteDepthImage());
|
|
REQUIRE(read_be32(image.GetCompressed() + 8) == JFJochBitShuffleCompressor::BlockSize(experiment.GetCompressionAlgorithm(),
|
|
experiment.GetByteDepthImage()) *
|
|
experiment.GetByteDepthImage());
|
|
|
|
std::vector<int16_t> output;
|
|
REQUIRE_NOTHROW(JFJochDecompress(output, experiment.GetCompressionAlgorithm(), image.GetCompressed(),
|
|
image.GetCompressedSize(),
|
|
experiment.GetPixelsNum()));
|
|
|
|
uint32_t diff_0 = 0;
|
|
uint32_t diff_1 = 0;
|
|
|
|
for (int i = 0; i < nmodules*RAW_MODULE_SIZE; i++) {
|
|
if (input_0[i] != output[i]) diff_0++;
|
|
if (input_1[i] != output[i + nmodules*RAW_MODULE_SIZE]) diff_1++;
|
|
}
|
|
REQUIRE(diff_0 == 0);
|
|
REQUIRE(diff_1 == 0);
|
|
}
|
|
|
|
TEST_CASE("FrameTransformation_Conversion_NoGeomTransformation_NoCompression" ,"") {
|
|
const uint16_t nmodules = 4;
|
|
const uint16_t ndatastreams = 2;
|
|
DiffractionExperiment experiment(DetJF(ndatastreams * nmodules, 1));
|
|
experiment.DataStreams(ndatastreams);
|
|
|
|
experiment.GeometryTransformation(false);
|
|
experiment.Compression(CompressionAlgorithm::NO_COMPRESSION);
|
|
|
|
FrameTransformation transformation(experiment);
|
|
|
|
std::mt19937 g1(1587);
|
|
std::uniform_int_distribution<int16_t> dist;
|
|
|
|
std::vector<int16_t> input_0(nmodules*RAW_MODULE_SIZE);
|
|
for (int i = 0; i < nmodules*RAW_MODULE_SIZE; i++)
|
|
input_0[i] = dist(g1);
|
|
|
|
std::vector<int16_t> input_1(nmodules*RAW_MODULE_SIZE);
|
|
for (int i = 0; i < nmodules*RAW_MODULE_SIZE; i++)
|
|
input_1[i] = dist(g1);
|
|
|
|
for (int i = 0; i < nmodules; i++) {
|
|
REQUIRE_NOTHROW(transformation.ProcessModule(input_0.data() + i * RAW_MODULE_SIZE, i, 0));
|
|
REQUIRE_NOTHROW(transformation.ProcessModule(input_1.data() + i * RAW_MODULE_SIZE, i, 1));
|
|
}
|
|
auto image = transformation.GetCompressedImage();
|
|
REQUIRE(image.GetCompressedSize() == experiment.GetByteDepthImage() * experiment.GetPixelsNum());
|
|
auto output = (int16_t *) image.GetCompressed();
|
|
|
|
uint32_t diff_0 = 0;
|
|
uint32_t diff_1 = 0;
|
|
|
|
for (int i = 0; i < nmodules*RAW_MODULE_SIZE; i++) {
|
|
if (input_0[i] != output[i]) diff_0++;
|
|
if (input_1[i] != output[i + nmodules*RAW_MODULE_SIZE]) diff_1++;
|
|
}
|
|
REQUIRE(diff_0 == 0);
|
|
REQUIRE(diff_1 == 0);
|
|
}
|
|
|
|
TEST_CASE("FrameTransformation_Converted_NoCompression" ,"") {
|
|
const uint16_t nmodules = 4;
|
|
const uint16_t ndatastreams = 2;
|
|
DiffractionExperiment experiment(DetJF(ndatastreams * nmodules, 2));
|
|
experiment.DataStreams(ndatastreams);
|
|
experiment.Compression(CompressionAlgorithm::NO_COMPRESSION);
|
|
|
|
FrameTransformation transformation(experiment);
|
|
|
|
std::mt19937 g1(1687);
|
|
std::uniform_int_distribution<int16_t> dist;
|
|
|
|
std::vector<int16_t> input_0(nmodules*RAW_MODULE_SIZE);
|
|
for (int i = 0; i < nmodules*RAW_MODULE_SIZE; i++)
|
|
input_0[i] = dist(g1);
|
|
|
|
std::vector<int16_t> input_1(nmodules*RAW_MODULE_SIZE);
|
|
for (int i = 0; i < nmodules*RAW_MODULE_SIZE; i++)
|
|
input_1[i] = dist(g1);
|
|
|
|
for (int i = 0; i < nmodules; i++) {
|
|
REQUIRE_NOTHROW(transformation.ProcessModule(input_0.data() + i * RAW_MODULE_SIZE, i, 0));
|
|
REQUIRE_NOTHROW(transformation.ProcessModule(input_1.data() + i * RAW_MODULE_SIZE, i, 1));
|
|
}
|
|
|
|
auto image = transformation.GetCompressedImage();
|
|
REQUIRE(image.GetCompressedSize() == experiment.GetByteDepthImage() * experiment.GetPixelsNum());
|
|
auto output = (int16_t *) image.GetCompressed();
|
|
|
|
REQUIRE(input_0[511*1024] == output[CONVERTED_MODULE_SIZE * (2 * nmodules - 2) + 0]);
|
|
REQUIRE(input_0[511*1024+256]/2 == output[CONVERTED_MODULE_SIZE * (2 * nmodules - 2) + 258]);
|
|
REQUIRE(input_0[256*1024+256]/4 == output[CONVERTED_MODULE_SIZE * (2 * nmodules - 2) + 2 * 1030 * 255 + 257]);
|
|
|
|
REQUIRE(input_0[311*1024] == output[CONVERTED_MODULE_SIZE * (2 * nmodules - 2) + 200 * 1030 * 2 + 0]);
|
|
REQUIRE(input_0[311*1024+256] / 2 == output[CONVERTED_MODULE_SIZE * (2 * nmodules - 2) + 200 * 1030 * 2 + 258]);
|
|
|
|
REQUIRE(input_0[(511+512)*1024] == output[CONVERTED_MODULE_SIZE * (2 * nmodules - 2) + 1030]);
|
|
REQUIRE(input_0[(511+512)*1024 + 800] == output[CONVERTED_MODULE_SIZE * (2 * nmodules - 2) + 1030 + 800 + 6]);
|
|
|
|
REQUIRE(input_1[511*1024] == output[CONVERTED_MODULE_SIZE * (nmodules - 2) + 0]);
|
|
REQUIRE(input_1[511*1024+256] /2 == output[CONVERTED_MODULE_SIZE * (nmodules - 2) + 258]);
|
|
|
|
REQUIRE(input_1[(311+2*512)*1024] == output[200 * 1030 * 2 + 0]);
|
|
REQUIRE(input_1[(311+2*512)*1024+512] / 2 == output[200 * 1030 * 2 + 256*2+3]);
|
|
|
|
REQUIRE(input_1[(511+512)*1024] == output[CONVERTED_MODULE_SIZE * (nmodules - 2) + 1030]);
|
|
REQUIRE(input_1[(511+512)*1024 + 800] == output[CONVERTED_MODULE_SIZE * (nmodules - 2) + 1030 + 800 + 6]);
|
|
}
|
|
|
|
TEST_CASE("FrameTransformation_Converted_bshuf_lz4" ,"") {
|
|
const uint16_t nmodules = 4;
|
|
const uint16_t ndatastreams = 2;
|
|
DiffractionExperiment experiment(DetJF(ndatastreams * nmodules, 2));
|
|
experiment.DataStreams(ndatastreams);
|
|
|
|
experiment.Compression(CompressionAlgorithm::BSHUF_LZ4);
|
|
|
|
FrameTransformation transformation(experiment);
|
|
|
|
// Predictable random number generator
|
|
std::mt19937 g1(23433);
|
|
std::uniform_int_distribution<int16_t> distribution;
|
|
|
|
std::vector<int16_t> input_0(nmodules*RAW_MODULE_SIZE);
|
|
for (int i = 0; i < nmodules*RAW_MODULE_SIZE; i++)
|
|
input_0[i] = distribution(g1);
|
|
|
|
std::vector<int16_t> input_1(nmodules*RAW_MODULE_SIZE);
|
|
for (int i = 0; i < nmodules*RAW_MODULE_SIZE; i++)
|
|
input_1[i] = distribution(g1);
|
|
|
|
std::vector<char> output_compressed(experiment.GetMaxCompressedSize());
|
|
|
|
for (int i = 0; i < nmodules; i++) {
|
|
REQUIRE_NOTHROW(transformation.ProcessModule(input_0.data() + i * RAW_MODULE_SIZE, i, 0));
|
|
REQUIRE_NOTHROW(transformation.ProcessModule(input_1.data() + i * RAW_MODULE_SIZE, i, 1));
|
|
}
|
|
|
|
auto image = transformation.GetCompressedImage();
|
|
|
|
REQUIRE(read_be64(image.GetCompressed()) == experiment.GetPixelsNum() * experiment.GetByteDepthImage());
|
|
REQUIRE(read_be32(image.GetCompressed() + 8) == JFJochBitShuffleCompressor::BlockSize(experiment.GetCompressionAlgorithm(),
|
|
experiment.GetByteDepthImage()) *
|
|
experiment.GetByteDepthImage());
|
|
|
|
std::vector<uint16_t> output;
|
|
REQUIRE_NOTHROW(JFJochDecompress(output, experiment.GetCompressionAlgorithm(), image.GetCompressed(),
|
|
image.GetCompressedSize(),
|
|
experiment.GetPixelsNum()));
|
|
|
|
REQUIRE(input_0[511*1024] == output[CONVERTED_MODULE_SIZE * (2 * nmodules - 2) + 0]);
|
|
REQUIRE(input_0[511*1024+256]/2 == output[CONVERTED_MODULE_SIZE * (2 * nmodules - 2) + 258]);
|
|
REQUIRE(input_0[256*1024+256]/4 == output[CONVERTED_MODULE_SIZE * (2 * nmodules - 2) + 2 * 1030 * 255 + 257]);
|
|
|
|
REQUIRE(input_0[311*1024] == output[CONVERTED_MODULE_SIZE * (2 * nmodules - 2) + 200 * 1030 * 2 + 0]);
|
|
REQUIRE(input_0[311*1024+256] / 2 == output[CONVERTED_MODULE_SIZE * (2 * nmodules - 2) + 200 * 1030 * 2 + 258]);
|
|
|
|
REQUIRE(input_0[(511+512)*1024] == output[CONVERTED_MODULE_SIZE * (2 * nmodules - 2) + 1030]);
|
|
REQUIRE(input_0[(511+512)*1024 + 800] == output[CONVERTED_MODULE_SIZE * (2 * nmodules - 2) + 1030 + 800 + 6]);
|
|
|
|
REQUIRE(input_1[511*1024] == output[CONVERTED_MODULE_SIZE * (nmodules - 2) + 0]);
|
|
REQUIRE(input_1[511*1024+256] /2 == output[CONVERTED_MODULE_SIZE * (nmodules - 2) + 258]);
|
|
|
|
REQUIRE(input_1[(311+2*512)*1024] == output[200 * 1030 * 2 + 0]);
|
|
REQUIRE(input_1[(311+2*512)*1024+512] / 2 == output[200 * 1030 * 2 + 256*2+3]);
|
|
|
|
REQUIRE(input_1[(511+512)*1024] == output[CONVERTED_MODULE_SIZE * (nmodules - 2) + 1030]);
|
|
REQUIRE(input_1[(511+512)*1024 + 800] == output[CONVERTED_MODULE_SIZE * (nmodules - 2) + 1030 + 800 + 6]);
|
|
}
|
|
|
|
TEST_CASE("FrameTransformation_Converted_bshuf_zstd" ,"") {
|
|
const uint16_t nmodules = 4;
|
|
const uint16_t ndatastreams = 2;
|
|
DiffractionExperiment experiment(DetJF(ndatastreams * nmodules, 2));
|
|
experiment.DataStreams(ndatastreams);
|
|
|
|
experiment.Compression(CompressionAlgorithm::BSHUF_ZSTD);
|
|
|
|
FrameTransformation transformation(experiment);
|
|
|
|
std::mt19937 g1(1987);
|
|
std::uniform_int_distribution<int16_t> dist;
|
|
|
|
std::vector<int16_t> input_0(nmodules*RAW_MODULE_SIZE);
|
|
for (int i = 0; i < nmodules*RAW_MODULE_SIZE; i++)
|
|
input_0[i] = dist(g1);
|
|
|
|
std::vector<int16_t> input_1(nmodules*RAW_MODULE_SIZE);
|
|
for (int i = 0; i < nmodules*RAW_MODULE_SIZE; i++)
|
|
input_1[i] = dist(g1);
|
|
|
|
std::vector<char> output_compressed(experiment.GetMaxCompressedSize());
|
|
|
|
for (int i = 0; i < nmodules; i++) {
|
|
REQUIRE_NOTHROW(transformation.ProcessModule(input_0.data() + i * RAW_MODULE_SIZE, i, 0));
|
|
REQUIRE_NOTHROW(transformation.ProcessModule(input_1.data() + i * RAW_MODULE_SIZE, i, 1));
|
|
}
|
|
|
|
auto image = transformation.GetCompressedImage();
|
|
|
|
REQUIRE(read_be64(image.GetCompressed()) == experiment.GetPixelsNum() * experiment.GetByteDepthImage());
|
|
REQUIRE(read_be32(image.GetCompressed() + 8) == JFJochBitShuffleCompressor::BlockSize(experiment.GetCompressionAlgorithm(),
|
|
experiment.GetByteDepthImage()) *
|
|
experiment.GetByteDepthImage());
|
|
|
|
std::vector<uint16_t> output;
|
|
REQUIRE_NOTHROW(JFJochDecompress(output, experiment.GetCompressionAlgorithm(), image.GetCompressed(),
|
|
image.GetCompressedSize(),
|
|
experiment.GetPixelsNum()));
|
|
|
|
REQUIRE(input_0[511*1024] == output[CONVERTED_MODULE_SIZE * (2 * nmodules - 2) + 0]);
|
|
REQUIRE(input_0[511*1024+256]/2 == output[CONVERTED_MODULE_SIZE * (2 * nmodules - 2) + 258]);
|
|
REQUIRE(input_0[256*1024+256]/4 == output[CONVERTED_MODULE_SIZE * (2 * nmodules - 2) + 2 * 1030 * 255 + 257]);
|
|
|
|
REQUIRE(input_0[311*1024] == output[CONVERTED_MODULE_SIZE * (2 * nmodules - 2) + 200 * 1030 * 2 + 0]);
|
|
REQUIRE(input_0[311*1024+256] / 2 == output[CONVERTED_MODULE_SIZE * (2 * nmodules - 2) + 200 * 1030 * 2 + 258]);
|
|
|
|
REQUIRE(input_0[(511+512)*1024] == output[CONVERTED_MODULE_SIZE * (2 * nmodules - 2) + 1030]);
|
|
REQUIRE(input_0[(511+512)*1024 + 800] == output[CONVERTED_MODULE_SIZE * (2 * nmodules - 2) + 1030 + 800 + 6]);
|
|
|
|
REQUIRE(input_1[511*1024] == output[CONVERTED_MODULE_SIZE * (nmodules - 2) + 0]);
|
|
REQUIRE(input_1[511*1024+256] /2 == output[CONVERTED_MODULE_SIZE * (nmodules - 2) + 258]);
|
|
|
|
REQUIRE(input_1[(311+2*512)*1024] == output[200 * 1030 * 2 + 0]);
|
|
REQUIRE(input_1[(311+2*512)*1024+512] / 2 == output[200 * 1030 * 2 + 256*2+3]);
|
|
|
|
REQUIRE(input_1[(511+512)*1024] == output[CONVERTED_MODULE_SIZE * (nmodules - 2) + 1030]);
|
|
REQUIRE(input_1[(511+512)*1024 + 800] == output[CONVERTED_MODULE_SIZE * (nmodules - 2) + 1030 + 800 + 6]);
|
|
}
|
|
|
|
TEST_CASE("FrameTransformation_Converted_bshuf_zstd_rle" ,"") {
|
|
const uint16_t nmodules = 4;
|
|
const uint16_t ndatastreams = 2;
|
|
DiffractionExperiment experiment(DetJF(ndatastreams * nmodules, 2));
|
|
experiment.DataStreams(ndatastreams);
|
|
|
|
experiment.Compression(CompressionAlgorithm::BSHUF_ZSTD_RLE);
|
|
|
|
FrameTransformation transformation(experiment);
|
|
|
|
std::mt19937 g1(1987);
|
|
std::uniform_int_distribution<int16_t> dist;
|
|
|
|
std::vector<int16_t> input_0(nmodules*RAW_MODULE_SIZE);
|
|
for (int i = 0; i < nmodules*RAW_MODULE_SIZE; i++)
|
|
input_0[i] = dist(g1);
|
|
|
|
std::vector<int16_t> input_1(nmodules*RAW_MODULE_SIZE);
|
|
for (int i = 0; i < nmodules*RAW_MODULE_SIZE; i++)
|
|
input_1[i] = dist(g1);
|
|
|
|
std::vector<char> output_compressed(experiment.GetMaxCompressedSize());
|
|
|
|
for (int i = 0; i < nmodules; i++) {
|
|
REQUIRE_NOTHROW(transformation.ProcessModule(input_0.data() + i * RAW_MODULE_SIZE, i, 0));
|
|
REQUIRE_NOTHROW(transformation.ProcessModule(input_1.data() + i * RAW_MODULE_SIZE, i, 1));
|
|
}
|
|
|
|
auto image = transformation.GetCompressedImage();
|
|
|
|
REQUIRE(read_be64(image.GetCompressed()) == experiment.GetPixelsNum() * experiment.GetByteDepthImage());
|
|
REQUIRE(read_be32(image.GetCompressed() + 8) == JFJochBitShuffleCompressor::BlockSize(experiment.GetCompressionAlgorithm(),
|
|
experiment.GetByteDepthImage()) *
|
|
experiment.GetByteDepthImage());
|
|
|
|
std::vector<uint16_t> output;
|
|
REQUIRE_NOTHROW(JFJochDecompress(output, experiment.GetCompressionAlgorithm(), image.GetCompressed(),
|
|
image.GetCompressedSize(),
|
|
experiment.GetPixelsNum()));
|
|
|
|
REQUIRE(input_0[511*1024] == output[CONVERTED_MODULE_SIZE * (2 * nmodules - 2) + 0]);
|
|
REQUIRE(input_0[511*1024+256]/2 == output[CONVERTED_MODULE_SIZE * (2 * nmodules - 2) + 258]);
|
|
REQUIRE(input_0[256*1024+256]/4 == output[CONVERTED_MODULE_SIZE * (2 * nmodules - 2) + 2 * 1030 * 255 + 257]);
|
|
|
|
REQUIRE(input_0[311*1024] == output[CONVERTED_MODULE_SIZE * (2 * nmodules - 2) + 200 * 1030 * 2 + 0]);
|
|
REQUIRE(input_0[311*1024+256] / 2 == output[CONVERTED_MODULE_SIZE * (2 * nmodules - 2) + 200 * 1030 * 2 + 258]);
|
|
|
|
REQUIRE(input_0[(511+512)*1024] == output[CONVERTED_MODULE_SIZE * (2 * nmodules - 2) + 1030]);
|
|
REQUIRE(input_0[(511+512)*1024 + 800] == output[CONVERTED_MODULE_SIZE * (2 * nmodules - 2) + 1030 + 800 + 6]);
|
|
|
|
REQUIRE(input_1[511*1024] == output[CONVERTED_MODULE_SIZE * (nmodules - 2) + 0]);
|
|
REQUIRE(input_1[511*1024+256] /2 == output[CONVERTED_MODULE_SIZE * (nmodules - 2) + 258]);
|
|
|
|
REQUIRE(input_1[(311+2*512)*1024] == output[200 * 1030 * 2 + 0]);
|
|
REQUIRE(input_1[(311+2*512)*1024+512] / 2 == output[200 * 1030 * 2 + 256*2+3]);
|
|
|
|
REQUIRE(input_1[(511+512)*1024] == output[CONVERTED_MODULE_SIZE * (nmodules - 2) + 1030]);
|
|
REQUIRE(input_1[(511+512)*1024 + 800] == output[CONVERTED_MODULE_SIZE * (nmodules - 2) + 1030 + 800 + 6]);
|
|
}
|
|
|
|
TEST_CASE("FrameTransformation_Converted_bshuf_zstd_32bit" ,"") {
|
|
const uint16_t nmodules = 4;
|
|
const uint16_t ndatastreams = 2;
|
|
DiffractionExperiment experiment(DetJF(ndatastreams * nmodules, 2));
|
|
experiment.DataStreams(ndatastreams);
|
|
|
|
experiment.Compression(CompressionAlgorithm::BSHUF_ZSTD).BitDepthImage(32);
|
|
|
|
FrameTransformation transformation(experiment);
|
|
|
|
std::mt19937 g1(1987);
|
|
std::uniform_int_distribution<int32_t> dist;
|
|
|
|
std::vector<int32_t> input_0(nmodules*RAW_MODULE_SIZE);
|
|
for (int i = 0; i < nmodules*RAW_MODULE_SIZE; i++)
|
|
input_0[i] = dist(g1);
|
|
|
|
input_0[311*1024+256] = INT32_MAX-1;
|
|
input_0[311*1024+255] = INT32_MIN;
|
|
|
|
std::vector<int32_t> input_1(nmodules*RAW_MODULE_SIZE);
|
|
for (int i = 0; i < nmodules*RAW_MODULE_SIZE; i++)
|
|
input_1[i] = dist(g1);
|
|
|
|
std::vector<char> output_compressed(experiment.GetMaxCompressedSize());
|
|
|
|
for (int i = 0; i < nmodules; i++) {
|
|
REQUIRE_NOTHROW(transformation.ProcessModule(input_0.data() + i * RAW_MODULE_SIZE, i, 0));
|
|
REQUIRE_NOTHROW(transformation.ProcessModule(input_1.data() + i * RAW_MODULE_SIZE, i, 1));
|
|
}
|
|
|
|
auto image = transformation.GetCompressedImage();
|
|
|
|
REQUIRE(read_be64(image.GetCompressed()) == experiment.GetPixelsNum() * experiment.GetByteDepthImage());
|
|
REQUIRE(read_be32(image.GetCompressed() + 8) == JFJochBitShuffleCompressor::BlockSize(experiment.GetCompressionAlgorithm(),
|
|
experiment.GetByteDepthImage()) *
|
|
experiment.GetByteDepthImage());
|
|
|
|
std::vector<uint32_t> output;
|
|
REQUIRE_NOTHROW(JFJochDecompress(output, experiment.GetCompressionAlgorithm(), image.GetCompressed(),
|
|
image.GetCompressedSize(),
|
|
experiment.GetPixelsNum()));
|
|
|
|
REQUIRE(input_0[511*1024] == output[CONVERTED_MODULE_SIZE * (2 * nmodules - 2) + 0]);
|
|
REQUIRE(input_0[511*1024+256]/2 == output[CONVERTED_MODULE_SIZE * (2 * nmodules - 2) + 258]);
|
|
REQUIRE(input_0[256*1024+256]/4 == output[CONVERTED_MODULE_SIZE * (2 * nmodules - 2) + 2 * 1030 * 255 + 257]);
|
|
|
|
REQUIRE(input_0[311*1024] == output[CONVERTED_MODULE_SIZE * (2 * nmodules - 2) + 200 * 1030 * 2 + 0]);
|
|
REQUIRE(input_0[311*1024+255] == output[CONVERTED_MODULE_SIZE * (2 * nmodules - 2) + 200 * 1030 * 2 + 255]);
|
|
REQUIRE(input_0[311*1024+256] / 2 == output[CONVERTED_MODULE_SIZE * (2 * nmodules - 2) + 200 * 1030 * 2 + 258]);
|
|
|
|
REQUIRE(input_0[(511+512)*1024] == output[CONVERTED_MODULE_SIZE * (2 * nmodules - 2) + 1030]);
|
|
REQUIRE(input_0[(511+512)*1024 + 800] == output[CONVERTED_MODULE_SIZE * (2 * nmodules - 2) + 1030 + 800 + 6]);
|
|
|
|
REQUIRE(input_1[511*1024] == output[CONVERTED_MODULE_SIZE * (nmodules - 2) + 0]);
|
|
REQUIRE(input_1[511*1024+256] /2 == output[CONVERTED_MODULE_SIZE * (nmodules - 2) + 258]);
|
|
|
|
REQUIRE(input_1[(311+2*512)*1024] == output[200 * 1030 * 2 + 0]);
|
|
REQUIRE(input_1[(311+2*512)*1024+512] / 2 == output[200 * 1030 * 2 + 256*2+3]);
|
|
|
|
REQUIRE(input_1[(511+512)*1024] == output[CONVERTED_MODULE_SIZE * (nmodules - 2) + 1030]);
|
|
REQUIRE(input_1[(511+512)*1024 + 800] == output[CONVERTED_MODULE_SIZE * (nmodules - 2) + 1030 + 800 + 6]);
|
|
}
|
|
|
|
TEST_CASE("FrameTransformation_Converted_bshuf_zstd_8bit" ,"") {
|
|
const uint16_t nmodules = 4;
|
|
const uint16_t ndatastreams = 2;
|
|
DiffractionExperiment experiment(DetJF(ndatastreams * nmodules, 2));
|
|
experiment.DataStreams(ndatastreams);
|
|
|
|
experiment.Compression(CompressionAlgorithm::BSHUF_ZSTD).BitDepthImage(8);
|
|
|
|
FrameTransformation transformation(experiment);
|
|
|
|
std::mt19937 g1(1987);
|
|
std::uniform_int_distribution<int8_t> dist;
|
|
|
|
std::vector<int8_t> input_0(nmodules*RAW_MODULE_SIZE);
|
|
for (int i = 0; i < nmodules*RAW_MODULE_SIZE; i++)
|
|
input_0[i] = dist(g1);
|
|
|
|
input_0[311*1024+256] = INT8_MAX-1;
|
|
input_0[311*1024+255] = INT8_MIN;
|
|
|
|
std::vector<int8_t> input_1(nmodules*RAW_MODULE_SIZE);
|
|
for (int i = 0; i < nmodules*RAW_MODULE_SIZE; i++)
|
|
input_1[i] = dist(g1);
|
|
|
|
std::vector<char> output_compressed(experiment.GetMaxCompressedSize());
|
|
|
|
for (int i = 0; i < nmodules; i++) {
|
|
REQUIRE_NOTHROW(transformation.ProcessModule(input_0.data() + i * RAW_MODULE_SIZE, i, 0));
|
|
REQUIRE_NOTHROW(transformation.ProcessModule(input_1.data() + i * RAW_MODULE_SIZE, i, 1));
|
|
}
|
|
|
|
auto image = transformation.GetCompressedImage();
|
|
|
|
REQUIRE(read_be64(image.GetCompressed()) == experiment.GetPixelsNum() * experiment.GetByteDepthImage());
|
|
REQUIRE(read_be32(image.GetCompressed() + 8) == JFJochBitShuffleCompressor::BlockSize(experiment.GetCompressionAlgorithm(),
|
|
experiment.GetByteDepthImage()) *
|
|
experiment.GetByteDepthImage());
|
|
|
|
std::vector<int8_t> output;
|
|
REQUIRE_NOTHROW(JFJochDecompress(output, experiment.GetCompressionAlgorithm(), image.GetCompressed(),
|
|
image.GetCompressedSize(),
|
|
experiment.GetPixelsNum()));
|
|
|
|
REQUIRE(input_0[511*1024] == output[CONVERTED_MODULE_SIZE * (2 * nmodules - 2) + 0]);
|
|
REQUIRE(input_0[511*1024+256]/2 == output[CONVERTED_MODULE_SIZE * (2 * nmodules - 2) + 258]);
|
|
REQUIRE(input_0[256*1024+256]/4 == output[CONVERTED_MODULE_SIZE * (2 * nmodules - 2) + 2 * 1030 * 255 + 257]);
|
|
|
|
REQUIRE(input_0[311*1024] == output[CONVERTED_MODULE_SIZE * (2 * nmodules - 2) + 200 * 1030 * 2 + 0]);
|
|
REQUIRE(input_0[311*1024+255] == output[CONVERTED_MODULE_SIZE * (2 * nmodules - 2) + 200 * 1030 * 2 + 255]);
|
|
REQUIRE(input_0[311*1024+256] / 2 == output[CONVERTED_MODULE_SIZE * (2 * nmodules - 2) + 200 * 1030 * 2 + 258]);
|
|
|
|
REQUIRE(input_0[(511+512)*1024] == output[CONVERTED_MODULE_SIZE * (2 * nmodules - 2) + 1030]);
|
|
REQUIRE(input_0[(511+512)*1024 + 800] == output[CONVERTED_MODULE_SIZE * (2 * nmodules - 2) + 1030 + 800 + 6]);
|
|
|
|
REQUIRE(input_1[511*1024] == output[CONVERTED_MODULE_SIZE * (nmodules - 2) + 0]);
|
|
REQUIRE(input_1[511*1024+256] /2 == output[CONVERTED_MODULE_SIZE * (nmodules - 2) + 258]);
|
|
|
|
REQUIRE(input_1[(311+2*512)*1024] == output[200 * 1030 * 2 + 0]);
|
|
REQUIRE(input_1[(311+2*512)*1024+512] / 2 == output[200 * 1030 * 2 + 256*2+3]);
|
|
|
|
REQUIRE(input_1[(511+512)*1024] == output[CONVERTED_MODULE_SIZE * (nmodules - 2) + 1030]);
|
|
REQUIRE(input_1[(511+512)*1024 + 800] == output[CONVERTED_MODULE_SIZE * (nmodules - 2) + 1030 + 800 + 6]);
|
|
}
|
|
|
|
TEST_CASE("FrameTransformation_Converted_bshuf_zstd_unsigned_16bit" ,"") {
|
|
const uint16_t nmodules = 4;
|
|
const uint16_t ndatastreams = 2;
|
|
DiffractionExperiment experiment(DetJF(ndatastreams * nmodules, 2));
|
|
experiment.DataStreams(ndatastreams);
|
|
|
|
experiment.Compression(CompressionAlgorithm::BSHUF_ZSTD).PixelSigned(false);
|
|
|
|
REQUIRE(!experiment.IsPixelSigned());
|
|
REQUIRE(experiment.GetByteDepthImage() == 2);
|
|
|
|
FrameTransformation transformation(experiment);
|
|
|
|
std::mt19937 g1(1987);
|
|
std::uniform_int_distribution<uint16_t> dist(0, UINT16_MAX - 2);
|
|
|
|
std::vector<uint16_t> input_0(nmodules*RAW_MODULE_SIZE);
|
|
for (int i = 0; i < nmodules*RAW_MODULE_SIZE; i++)
|
|
input_0[i] = dist(g1);
|
|
|
|
input_0[311*1024+256] = UINT16_MAX - 2;
|
|
input_0[311*1024+255] = UINT16_MAX - 1;
|
|
input_0[255*1024] = UINT16_MAX - 1;
|
|
|
|
std::vector<uint16_t> input_1(nmodules*RAW_MODULE_SIZE);
|
|
for (int i = 0; i < nmodules*RAW_MODULE_SIZE; i++)
|
|
input_1[i] = dist(g1);
|
|
|
|
std::vector<char> output_compressed(experiment.GetMaxCompressedSize());
|
|
|
|
for (int i = 0; i < nmodules; i++) {
|
|
REQUIRE_NOTHROW(transformation.ProcessModule(input_0.data() + i * RAW_MODULE_SIZE, i, 0));
|
|
REQUIRE_NOTHROW(transformation.ProcessModule(input_1.data() + i * RAW_MODULE_SIZE, i, 1));
|
|
}
|
|
|
|
auto image = transformation.GetCompressedImage();
|
|
|
|
REQUIRE(read_be64(image.GetCompressed()) == experiment.GetPixelsNum() * experiment.GetByteDepthImage());
|
|
REQUIRE(read_be32(image.GetCompressed() + 8) == JFJochBitShuffleCompressor::BlockSize(experiment.GetCompressionAlgorithm(),
|
|
experiment.GetByteDepthImage()) *
|
|
experiment.GetByteDepthImage());
|
|
|
|
std::vector<uint16_t> output;
|
|
REQUIRE_NOTHROW(JFJochDecompress(output, experiment.GetCompressionAlgorithm(), image.GetCompressed(),
|
|
image.GetCompressedSize(),
|
|
experiment.GetPixelsNum()));
|
|
|
|
REQUIRE(input_0[511*1024] == output[CONVERTED_MODULE_SIZE * (2 * nmodules - 2) + 0]);
|
|
REQUIRE(input_0[511*1024+256]/2 == output[CONVERTED_MODULE_SIZE * (2 * nmodules - 2) + 258]);
|
|
REQUIRE(input_0[256*1024+256]/4 == output[CONVERTED_MODULE_SIZE * (2 * nmodules - 2) + 2 * 1030 * 255 + 257]);
|
|
|
|
REQUIRE(input_0[311*1024] == output[CONVERTED_MODULE_SIZE * (2 * nmodules - 2) + 200 * 1030 * 2 + 0]);
|
|
REQUIRE(input_0[311*1024+255] == output[CONVERTED_MODULE_SIZE * (2 * nmodules - 2) + 200 * 1030 * 2 + 255]);
|
|
REQUIRE(input_0[311*1024+255] == output[CONVERTED_MODULE_SIZE * (2 * nmodules - 2) + 200 * 1030 * 2 + 256]);
|
|
REQUIRE(input_0[311*1024+256] / 2 == output[CONVERTED_MODULE_SIZE * (2 * nmodules - 2) + 200 * 1030 * 2 + 258]);
|
|
REQUIRE(input_0[255*1024] == output[CONVERTED_MODULE_SIZE * (2 * nmodules - 2) + 257 * 1030 * 2 + 0]);
|
|
|
|
REQUIRE(input_0[(511+512)*1024] == output[CONVERTED_MODULE_SIZE * (2 * nmodules - 2) + 1030]);
|
|
REQUIRE(input_0[(511+512)*1024 + 800] == output[CONVERTED_MODULE_SIZE * (2 * nmodules - 2) + 1030 + 800 + 6]);
|
|
|
|
REQUIRE(input_1[511*1024] == output[CONVERTED_MODULE_SIZE * (nmodules - 2) + 0]);
|
|
REQUIRE(input_1[511*1024+256] /2 == output[CONVERTED_MODULE_SIZE * (nmodules - 2) + 258]);
|
|
|
|
REQUIRE(input_1[(311+2*512)*1024] == output[200 * 1030 * 2 + 0]);
|
|
REQUIRE(input_1[(311+2*512)*1024+512] / 2 == output[200 * 1030 * 2 + 256*2+3]);
|
|
|
|
REQUIRE(input_1[(511+512)*1024] == output[CONVERTED_MODULE_SIZE * (nmodules - 2) + 1030]);
|
|
REQUIRE(input_1[(511+512)*1024 + 800] == output[CONVERTED_MODULE_SIZE * (nmodules - 2) + 1030 + 800 + 6]);
|
|
}
|