miniCBF: write the decoded pixels past the cache
Nothing on the host reads a decoded image back: it is DMAed to the GPU, or a CPU engine walks it once and drops it. An ordinary store pays for that twice - it reads every cache line before overwriting it, and it evicts 72 MB of live cache to make room - and the decode is bound by exactly that traffic, which is why neither an eight-pixel-at-a-time scalar loop nor an SSE2 prefix sum moved it at all. Storing the pixels non-temporally takes an 18 Mpx frame from 27 ms to 11 ms, and 240 frames from six sweeps decode byte for byte as before. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+33
-1
@@ -13,6 +13,11 @@
|
||||
#include <regex>
|
||||
#include <stdexcept>
|
||||
|
||||
#if defined(__SSE2__) || defined(_M_X64) || defined(_M_AMD64)
|
||||
# include <emmintrin.h>
|
||||
# define MINICBF_STREAM_STORE 1
|
||||
#endif
|
||||
|
||||
#include "../common/JFJochException.h"
|
||||
|
||||
namespace minicbf {
|
||||
@@ -295,6 +300,30 @@ Header ParseHeader(const char *data, size_t size) {
|
||||
return h;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// Nothing on this side reads the decoded image back: it goes to the GPU by DMA, or a CPU engine
|
||||
// walks it once and drops it. An ordinary store therefore pays twice over - it reads every cache
|
||||
// line before overwriting it, and it evicts 72 MB of live cache to make room - so the pixels go
|
||||
// straight past the cache. Measured on an 18 Mpx frame: 27 ms of ordinary stores against 11 ms of
|
||||
// these. The bytes written are the same either way; the fence is what makes them visible to the
|
||||
// copy that follows.
|
||||
void StorePixel(int32_t *out, int32_t value) {
|
||||
#ifdef MINICBF_STREAM_STORE
|
||||
_mm_stream_si32(out, value);
|
||||
#else
|
||||
*out = value;
|
||||
#endif
|
||||
}
|
||||
|
||||
void StoreFence() {
|
||||
#ifdef MINICBF_STREAM_STORE
|
||||
_mm_sfence();
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// The x-CBF_BYTE_OFFSET scheme: a running value, each pixel stored as a delta in the smallest
|
||||
// container that holds it, escaping to the next size with that container's most negative value.
|
||||
// Following Bernstein & Hammersley (2006) Int. Tables Cryst. G, 37-43
|
||||
@@ -329,9 +358,12 @@ void DecodeByteOffset(const uint8_t *data, size_t size, int32_t *out, size_t n_p
|
||||
}
|
||||
|
||||
value += delta;
|
||||
out[written++] = static_cast<int32_t>(value);
|
||||
StorePixel(out + written, static_cast<int32_t>(value));
|
||||
written++;
|
||||
}
|
||||
|
||||
StoreFence();
|
||||
|
||||
if (written != n_pixels)
|
||||
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
|
||||
"miniCBF byte-offset stream ended after " + std::to_string(written)
|
||||
|
||||
Reference in New Issue
Block a user