image_preprocessing: inline the buffer accessors
Build Packages / build:viewer-tgz:cpu (push) Successful in 7m6s
Build Packages / build:viewer-tgz:cuda (push) Successful in 8m15s
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 13m41s
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 13m53s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 14m15s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 14m27s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 14m44s
Build Packages / build:rpm (rocky9_sls9) (push) Successful in 13m6s
Build Packages / build:rpm (rocky8) (push) Successful in 12m1s
Build Packages / XDS test (durin plugin) (push) Successful in 6m58s
Build Packages / Generate python client (push) Successful in 35s
Build Packages / Build documentation (push) Successful in 1m3s
Build Packages / Create release (push) Skipped
Build Packages / build:rpm (ubuntu2404) (push) Successful in 12m41s
Build Packages / build:rpm (rocky9) (push) Successful in 14m0s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 13m59s
Build Packages / DIALS test (push) Successful in 13m49s
Build Packages / XDS test (neggia plugin) (push) Successful in 8m38s
Build Packages / XDS test (JFJoch plugin) (push) Successful in 9m20s
Build Packages / Unit tests (push) Successful in 1h1m46s
Build Packages / build:windows:nocuda (push) Failing after 2s
Build Packages / build:windows:cuda (push) Failing after 2s
Build Packages / build:viewer-tgz:cpu (push) Successful in 7m6s
Build Packages / build:viewer-tgz:cuda (push) Successful in 8m15s
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 13m41s
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 13m53s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 14m15s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 14m27s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 14m44s
Build Packages / build:rpm (rocky9_sls9) (push) Successful in 13m6s
Build Packages / build:rpm (rocky8) (push) Successful in 12m1s
Build Packages / XDS test (durin plugin) (push) Successful in 6m58s
Build Packages / Generate python client (push) Successful in 35s
Build Packages / Build documentation (push) Successful in 1m3s
Build Packages / Create release (push) Skipped
Build Packages / build:rpm (ubuntu2404) (push) Successful in 12m41s
Build Packages / build:rpm (rocky9) (push) Successful in 14m0s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 13m59s
Build Packages / DIALS test (push) Successful in 13m49s
Build Packages / XDS test (neggia plugin) (push) Successful in 8m38s
Build Packages / XDS test (JFJoch plugin) (push) Successful in 9m20s
Build Packages / Unit tests (push) Successful in 1h1m46s
Build Packages / build:windows:nocuda (push) Failing after 2s
Build Packages / build:windows:cuda (push) Failing after 2s
operator[], size(), data() and getBuffer() are one-line accessors that were defined in the .cpp. The build sets no link-time optimisation, so out of line each of them is a real call - once per pixel, from the CPU preprocessor, the CPU azimuthal integrator and the CPU spot finder - and they stop those loops vectorising at all. They show up in a profile directly: about six per cent of a whole azimuthal-integration-only run is spent in the call overhead of two accessors that do nothing but index a vector. Moving them into the header retires 30% fewer instructions on that run and takes the per-image CPU cost on a GPU-less pass from 34.6 to 24.2 ms, with the output bit for bit unchanged - same observation count, same cell, same merge statistics. It is worth nothing on the GPU path, where the image stays on the device, and everything on the paths that have no GPU to fall back on. This also explains a measurement that had been blamed on the pixel mask being a vector<bool>: a microbenchmark of that loop indexed a raw pointer and came out far faster than the same loop in the binary, and the difference was this call, not the mask. Measured properly the mask costs about 14% single-threaded rather than the 41% claimed, and at the thread counts this actually runs at the bit mask is FASTER than the byte mask it was proposed to become, because it moves eight times less traffic and the loop is bandwidth bound. That change should not be made. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -14,15 +14,19 @@ public:
|
||||
explicit ImagePreprocessorBuffer(size_t npixels);
|
||||
virtual ~ImagePreprocessorBuffer() = default;
|
||||
|
||||
// Standard CPU operation
|
||||
std::vector<int32_t> &getBuffer();
|
||||
const std::vector<int32_t> &getBuffer() const;
|
||||
int32_t &operator[](size_t i);
|
||||
const int32_t &operator[](size_t i) const;
|
||||
size_t size() const;
|
||||
// Standard CPU operation. Defined here rather than in the .cpp: these are called once per pixel by
|
||||
// the CPU preprocessor, the CPU azimuthal integrator and the CPU spot finder, and the build has no
|
||||
// link-time optimisation - so out of line they are a real call per pixel, and they stop the callers
|
||||
// vectorising at all. Inlining them costs about a third of the per-image CPU work on every path
|
||||
// that does not have a GPU, and leaves the results bit-identical.
|
||||
std::vector<int32_t> &getBuffer() { return buffer; }
|
||||
const std::vector<int32_t> &getBuffer() const { return buffer; }
|
||||
int32_t &operator[](size_t i) { return buffer[i]; }
|
||||
const int32_t &operator[](size_t i) const { return buffer[i]; }
|
||||
size_t size() const { return buffer.size(); }
|
||||
|
||||
int32_t *data();
|
||||
const int32_t *data() const;
|
||||
int32_t *data() { return buffer.data(); }
|
||||
const int32_t *data() const { return buffer.data(); }
|
||||
|
||||
// GPU operations (overriden in ImagePreprocessorBufferGPU
|
||||
virtual int32_t *getGPUBuffer();
|
||||
|
||||
Reference in New Issue
Block a user