From f85b87bfd25e91c7b1bca379f5ebdfddac86928f Mon Sep 17 00:00:00 2001 From: leonarski_f Date: Thu, 23 May 2024 22:58:52 +0200 Subject: [PATCH] PreviewImage: remove mutex --- preview/PreviewImage.cpp | 209 ++++++++++++++++------------- preview/PreviewImage.h | 19 +-- receiver/JFJochReceiver.cpp | 20 +-- receiver/JFJochReceiver.h | 9 +- receiver/JFJochReceiverPlots.h | 1 - receiver/JFJochReceiverService.cpp | 19 +-- receiver/JFJochReceiverService.h | 3 + tests/JPEGTest.cpp | 26 +++- tests/TIFFTest.cpp | 10 +- tools/jfjoch_spot_finding_test.cpp | 4 +- 10 files changed, 181 insertions(+), 139 deletions(-) diff --git a/preview/PreviewImage.cpp b/preview/PreviewImage.cpp index bfd40dba..0f5f53c9 100644 --- a/preview/PreviewImage.cpp +++ b/preview/PreviewImage.cpp @@ -31,28 +31,7 @@ constexpr const static rgb plotly[] = {{0x1f, 0x77, 0xb4}, constexpr const static rgb indigo = {.r = 0x3f, .g = 0x51, .b = 0xb5}; constexpr const static rgb gray = {.r = 0xbe, .g = 0xbe, .b = 0xbe}; -PreviewImage::PreviewImage(const DiffractionExperiment &in_experiment) : - experiment(in_experiment), - initialized(false), - xpixel(experiment.GetXPixelsNum()), - ypixel(experiment.GetYPixelsNum()), - beam_x(experiment.GetBeamX_pxl()), - beam_y(experiment.GetBeamY_pxl()), - pixel_depth_bytes(experiment.GetPixelDepth()), - pixel_is_signed(experiment.IsPixelSigned()), - uncompressed_image(experiment.GetPixelsNum() * experiment.GetPixelDepth()), - roi_map(experiment.ROI()), - counter(experiment.GetPreviewPeriod()) {} - -void PreviewImage::UpdateImage(const void *in_uncompressed_image, - const std::vector &in_spots) { - if (counter.GeneratePreview()) { - std::unique_lock ul(m); - initialized = true; - memcpy(uncompressed_image.data(), in_uncompressed_image, xpixel * ypixel * pixel_depth_bytes); - spots = in_spots; - } -} +PreviewImage::PreviewImage(std::chrono::microseconds period) : counter(period) {} void colormap(std::vector& ret, float v, size_t pixel) { if ((v < 0.0) || (v > 1.0)) { @@ -106,55 +85,6 @@ std::vector GenerateRGB(const T* value, size_t npixel, uint32_t s return ret; } -std::string PreviewImage::GenerateJPEG(const PreviewJPEGSettings &settings) const { - std::vector v; - { - // JPEG compression is outside the critical loop protected by m - std::unique_lock ul(m); - - if (!initialized) - return {}; - - if (!pixel_is_signed) { - if (pixel_depth_bytes == 2) - v = GenerateRGB((uint16_t *) uncompressed_image.data(), xpixel * ypixel, - settings.saturation_value, UINT16_MAX); - else - v = GenerateRGB((uint32_t *) uncompressed_image.data(), xpixel * ypixel, - settings.saturation_value, UINT32_MAX); - } else { - if (pixel_depth_bytes == 2) - v = GenerateRGB((int16_t *) uncompressed_image.data(), xpixel * ypixel, - settings.saturation_value, INT16_MIN); - else - v = GenerateRGB((int32_t *) uncompressed_image.data(), xpixel * ypixel, - settings.saturation_value, INT32_MIN); - } - if (settings.show_spots) - AddSpots(v); - } - - if (settings.show_roi) - AddROI(v); - - if (settings.resolution_ring) - AddResolutionRing(v, settings.resolution_ring.value()); - - AddBeamCenter(v); - - return WriteJPEGToMem(v, xpixel, ypixel, settings.jpeg_quality); -} - -std::string PreviewImage::GenerateTIFF() const { - std::unique_lock ul(m); - if (!initialized) - return {}; - - std::string s = WriteTIFFToString(const_cast(uncompressed_image.data()), - xpixel, ypixel, pixel_depth_bytes, pixel_is_signed); - return s; -} - template std::vector GenerateDioptasPreview(const void* input, size_t xpixel, size_t ypixel, T special_value) { auto input_ptr = (T *) input; @@ -174,26 +104,6 @@ std::vector GenerateDioptasPreview(const void* input, size_t xpixel, s return vec; } -std::string PreviewImage::GenerateTIFFDioptas() const { - std::unique_lock ul(m); - if (!initialized) - return {}; - - std::vector vec; - if (pixel_is_signed) { - if (pixel_depth_bytes == 2) - vec = GenerateDioptasPreview(uncompressed_image.data(), xpixel, ypixel, INT16_MIN); - else - vec = GenerateDioptasPreview(uncompressed_image.data(), xpixel, ypixel, INT32_MIN); - } else { - if (pixel_depth_bytes == 2) - vec = GenerateDioptasPreview(uncompressed_image.data(), xpixel, ypixel, UINT16_MAX); - else - vec = GenerateDioptasPreview(uncompressed_image.data(), xpixel, ypixel, UINT32_MAX); - } - return WriteTIFFToString(vec.data(), xpixel, ypixel, 2, false); -} - void PreviewImage::AddBeamCenter(std::vector &rgb_image) const { size_t beam_x_int = std::lround(beam_x); size_t beam_y_int = std::lround(beam_y); @@ -230,7 +140,7 @@ void PreviewImage::AddSpots(std::vector &rgb_image) const { void PreviewImage::AddROI(std::vector &rgb_image) const { int64_t roi_counter = 0; - for (const auto &box: roi_map.GetROIBox()) { + for (const auto &box: experiment.ROI().GetROIBox()) { int rectangle_width = 5; for (auto x = box.GetXMin() - rectangle_width; x <= box.GetXMax() + rectangle_width; x++) { @@ -249,7 +159,7 @@ void PreviewImage::AddROI(std::vector &rgb_image) const { roi_counter++; } - for (const auto &circle: roi_map.GetROICircle()) { + for (const auto &circle: experiment.ROI().GetROICircle()) { int width = 5; for (int64_t y = std::floor(circle.GetY() - circle.GetRadius_pxl() - width); @@ -281,3 +191,116 @@ void PreviewImage::AddResolutionRing(std::vector &rgb_image, float d) c } } } + +void PreviewImage::Configure(const DiffractionExperiment &in_experiment) { + std::unique_lock ul(m); + + experiment = in_experiment; + initialized = false; + xpixel = experiment.GetXPixelsNum(); + ypixel = experiment.GetYPixelsNum(); + beam_x = experiment.GetBeamX_pxl(); + beam_y = experiment.GetBeamY_pxl(); + pixel_depth_bytes = experiment.GetPixelDepth(); + pixel_is_signed = experiment.IsPixelSigned(); + uncompressed_image.resize(experiment.GetPixelsNum() * experiment.GetPixelDepth()); + memset(uncompressed_image.data(), 0, experiment.GetPixelsNum() * experiment.GetPixelDepth()); +} + +void PreviewImage::Configure() { + std::unique_lock ul(m); + + initialized = false; + xpixel = 0; + ypixel = 0; +} + +void PreviewImage::UpdateImage(const void *in_uncompressed_image, + const std::vector &in_spots) { + if (counter.GeneratePreview()) { + std::unique_lock ul(m); + + if (xpixel * ypixel == 0) + throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Preview not configured"); + + initialized = true; + memcpy(uncompressed_image.data(), in_uncompressed_image, xpixel * ypixel * pixel_depth_bytes); + spots = in_spots; + } +} + +std::string PreviewImage::GenerateJPEG(const PreviewJPEGSettings &settings) const { + std::vector v; + size_t local_xpixel; + size_t local_ypixel; + + { + // JPEG compression is outside the critical loop protected by m + std::unique_lock ul(m); + + local_xpixel = xpixel; + local_ypixel = ypixel; + + if (!initialized) + return {}; + + if (!pixel_is_signed) { + if (pixel_depth_bytes == 2) + v = GenerateRGB((uint16_t *) uncompressed_image.data(), xpixel * ypixel, + settings.saturation_value, UINT16_MAX); + else + v = GenerateRGB((uint32_t *) uncompressed_image.data(), xpixel * ypixel, + settings.saturation_value, UINT32_MAX); + } else { + if (pixel_depth_bytes == 2) + v = GenerateRGB((int16_t *) uncompressed_image.data(), xpixel * ypixel, + settings.saturation_value, INT16_MIN); + else + v = GenerateRGB((int32_t *) uncompressed_image.data(), xpixel * ypixel, + settings.saturation_value, INT32_MIN); + } + if (settings.show_spots) + AddSpots(v); + + if (settings.show_roi) + AddROI(v); + + if (settings.resolution_ring) + AddResolutionRing(v, settings.resolution_ring.value()); + + AddBeamCenter(v); + } + + return WriteJPEGToMem(v, local_xpixel, local_ypixel, settings.jpeg_quality); +} + + +std::string PreviewImage::GenerateTIFF() const { + std::unique_lock ul(m); + if (!initialized) + return {}; + + std::string s = WriteTIFFToString(const_cast(uncompressed_image.data()), + xpixel, ypixel, pixel_depth_bytes, pixel_is_signed); + return s; +} + +std::string PreviewImage::GenerateTIFFDioptas() const { + std::unique_lock ul(m); + if (!initialized) + return {}; + + std::vector vec; + if (pixel_is_signed) { + if (pixel_depth_bytes == 2) + vec = GenerateDioptasPreview(uncompressed_image.data(), xpixel, ypixel, INT16_MIN); + else + vec = GenerateDioptasPreview(uncompressed_image.data(), xpixel, ypixel, INT32_MIN); + } else { + if (pixel_depth_bytes == 2) + vec = GenerateDioptasPreview(uncompressed_image.data(), xpixel, ypixel, UINT16_MAX); + else + vec = GenerateDioptasPreview(uncompressed_image.data(), xpixel, ypixel, UINT32_MAX); + } + return WriteTIFFToString(vec.data(), xpixel, ypixel, 2, false); +} diff --git a/preview/PreviewImage.h b/preview/PreviewImage.h index e84e8ed9..47aa3c44 100644 --- a/preview/PreviewImage.h +++ b/preview/PreviewImage.h @@ -29,16 +29,15 @@ class PreviewImage { mutable std::mutex m; DiffractionExperiment experiment; - bool initialized; - const ROIMap roi_map; + bool initialized = false; std::vector uncompressed_image; std::vector spots; - size_t xpixel; - size_t ypixel; - size_t pixel_depth_bytes; - bool pixel_is_signed; - float beam_x; - float beam_y; + size_t xpixel = 0; + size_t ypixel = 0; + size_t pixel_depth_bytes = 2; + bool pixel_is_signed = false; + float beam_x = 0; + float beam_y = 0; void AddResolutionRing(std::vector &rgb_image, float d) const; void AddBeamCenter(std::vector &rgb_image) const; @@ -52,7 +51,9 @@ class PreviewImage { void beam_center_mark(std::vector& ret, int64_t xpixel, int64_t ypixel) const; public: - explicit PreviewImage(const DiffractionExperiment& experiment); + explicit PreviewImage(std::chrono::microseconds period = std::chrono::seconds(1)); + void Configure(const DiffractionExperiment& experiment); + void Configure(); void UpdateImage(const void *uncompressed_image, const std::vector &spots); [[nodiscard]] std::string GenerateJPEG(const PreviewJPEGSettings& settings) const; [[nodiscard]] std::string GenerateTIFF() const; diff --git a/receiver/JFJochReceiver.cpp b/receiver/JFJochReceiver.cpp index 3c70c033..b6703138 100644 --- a/receiver/JFJochReceiver.cpp +++ b/receiver/JFJochReceiver.cpp @@ -17,6 +17,8 @@ JFJochReceiver::JFJochReceiver(const DiffractionExperiment& in_experiment, Logger &in_logger, int64_t in_forward_and_sum_nthreads, const NUMAHWPolicy &in_numa_policy, const SpotFindingSettings &in_spot_finding_settings, + PreviewImage &in_preview_image, + PreviewImage &in_preview_image_indexed, SendBuffer &buf) : experiment(in_experiment), calibration(nullptr), @@ -33,8 +35,8 @@ JFJochReceiver::JFJochReceiver(const DiffractionExperiment& in_experiment, az_int_mapping(experiment), plots(experiment, az_int_mapping), spot_finding_settings(in_spot_finding_settings), - preview_image(experiment), - preview_image_indexed(experiment), + preview_image(in_preview_image), + preview_image_indexed(in_preview_image_indexed), serialmx_filter(experiment) { if (experiment.GetDetectorSetup().GetDetectorType() == DetectorType::JUNGFRAU) @@ -573,20 +575,6 @@ JFJochReceiverStatus JFJochReceiver::GetStatus() const { return ret; } -std::string JFJochReceiver::GetTIFF(bool calibration_run) const { - if (calibration_run) - return preview_image.GenerateTIFFDioptas(); - else - return preview_image.GenerateTIFF(); -} - -std::string JFJochReceiver::GetJPEG(const PreviewJPEGSettings &settings) const { - if (settings.show_indexed) - return preview_image_indexed.GenerateJPEG(settings); - else - return preview_image.GenerateJPEG(settings); -} - void JFJochReceiver::GetXFELEventCode(std::vector &v) const { if (experiment.IsPulsedSource()) plots.GetXFELEventCode(v); diff --git a/receiver/JFJochReceiver.h b/receiver/JFJochReceiver.h index bb66f35e..857089be 100644 --- a/receiver/JFJochReceiver.h +++ b/receiver/JFJochReceiver.h @@ -108,8 +108,8 @@ class JFJochReceiver { NUMAHWPolicy numa_policy; - PreviewImage preview_image; - PreviewImage preview_image_indexed; + PreviewImage &preview_image; + PreviewImage &preview_image_indexed; LossyFilter serialmx_filter; @@ -131,6 +131,8 @@ public: Logger &logger, int64_t forward_and_sum_nthreads, const NUMAHWPolicy &numa_policy, const SpotFindingSettings &spot_finding_settings, + PreviewImage &preview_image, + PreviewImage &preview_image_indexed, SendBuffer &buffer); ~JFJochReceiver(); JFJochReceiver(const JFJochReceiver &other) = delete; @@ -148,9 +150,6 @@ public: MultiLinePlot GetPlots(const PlotRequest& request); - std::string GetTIFF(bool calibration) const; - std::string GetJPEG(const PreviewJPEGSettings &settings) const; - void GetXFELEventCode(std::vector &v) const; void GetXFELPulseID(std::vector &v) const; }; diff --git a/receiver/JFJochReceiverPlots.h b/receiver/JFJochReceiverPlots.h index 07fa17fe..9edf8571 100644 --- a/receiver/JFJochReceiverPlots.h +++ b/receiver/JFJochReceiverPlots.h @@ -25,7 +25,6 @@ class JFJochReceiverPlots { StatusVector receiver_delay; StatusVector receiver_free_send_buf; StatusVector image_collection_efficiency; - StatusVector unit_cell[6]; SetAverage indexing_solution_per_time_point; std::map>> roi_sum; diff --git a/receiver/JFJochReceiverService.cpp b/receiver/JFJochReceiverService.cpp index 4522d744..d5e4653d 100644 --- a/receiver/JFJochReceiverService.cpp +++ b/receiver/JFJochReceiverService.cpp @@ -51,12 +51,17 @@ void JFJochReceiverService::Start(const DiffractionExperiment &experiment, const throw JFJochException(JFJochExceptionCategory::WrongDAQState, "Receiver not idle, cannot start"); try { + preview_image.Configure(experiment); + preview_image_indexed.Configure(experiment); + // Thanks to properties of unique_ptr, starting new measurement will call destructor of JFJochReceiver, which will // ensure that everything was rolled back receiver = std::make_unique(experiment, calibration, aq_devices, image_pusher, logger, nthreads, numa_policy, spot_finding_settings, + preview_image, + preview_image_indexed, buffer); try { // Don't want to stop @@ -128,19 +133,17 @@ std::vector JFJochReceiverService::GetNetworkConfig( } std::string JFJochReceiverService::GetTIFF(bool calibration) const { - std::unique_lock ul(state_mutex); - if (receiver) - return receiver->GetTIFF(calibration); + if (calibration) + return preview_image.GenerateTIFFDioptas(); else - return ""; + return preview_image.GenerateTIFF(); } std::string JFJochReceiverService::GetJPEG(const PreviewJPEGSettings &settings) const { - std::unique_lock ul(state_mutex); - if (receiver) - return receiver->GetJPEG(settings); + if (settings.show_indexed) + return preview_image_indexed.GenerateJPEG(settings); else - return ""; + return preview_image.GenerateJPEG(settings); } void JFJochReceiverService::LoadInternalGeneratorImage(const DiffractionExperiment &experiment, diff --git a/receiver/JFJochReceiverService.h b/receiver/JFJochReceiverService.h index d636b0ad..f74b34e2 100644 --- a/receiver/JFJochReceiverService.h +++ b/receiver/JFJochReceiverService.h @@ -25,6 +25,9 @@ class JFJochReceiverService { std::future measurement; void FinalizeMeasurement(); SpotFindingSettings spot_finding_settings; + + PreviewImage preview_image; + PreviewImage preview_image_indexed; public: JFJochReceiverService(AcquisitionDeviceGroup &aq_devices, Logger &logger, diff --git a/tests/JPEGTest.cpp b/tests/JPEGTest.cpp index 9eea75f0..5c10cd82 100644 --- a/tests/JPEGTest.cpp +++ b/tests/JPEGTest.cpp @@ -24,7 +24,19 @@ TEST_CASE("JPEGTest","[JPEG]") { f.write(s.data(), s.size()); } +TEST_CASE("PreviewImage_NotConfigured","[JPEG]") { + std::vector image_conv_2(67878); + std::vector spots; + + PreviewImage image; + REQUIRE_THROWS(image.UpdateImage(image_conv_2.data(), spots)); + REQUIRE(image.GenerateJPEG(PreviewJPEGSettings()).empty()); +} + + TEST_CASE("PreviewImage_GenerateJPEG","[JPEG]") { + RegisterHDF5Filter(); + DiffractionExperiment experiment(DetectorGeometry(8,2,8,36)); experiment.ImagesPerTrigger(5).NumTriggers(1).UseInternalPacketGenerator(true) .FilePrefix("lyso_test_min_pix_2").ConversionOnFPGA(false) @@ -57,7 +69,8 @@ TEST_CASE("PreviewImage_GenerateJPEG","[JPEG]") { {.x = 800, .y = 1000, .indexed = false}, {.x = 1200, .y = 500, .indexed = true} }; - PreviewImage image(experiment); + PreviewImage image; + image.Configure(experiment); PreviewJPEGSettings preview_settings{ .saturation_value = 5, @@ -69,7 +82,6 @@ TEST_CASE("PreviewImage_GenerateJPEG","[JPEG]") { image.UpdateImage(image_conv_2.data(), spots); - std::string s; REQUIRE_NOTHROW(s = image.GenerateJPEG(preview_settings)); std::ofstream f("lyso_diff.jpeg", std::ios::binary); @@ -77,6 +89,8 @@ TEST_CASE("PreviewImage_GenerateJPEG","[JPEG]") { } TEST_CASE("PreviewImage_GenerateJPEG_ROI","[JPEG]") { + RegisterHDF5Filter(); + DiffractionExperiment experiment(DetectorGeometry(8,2,8,36)); experiment.ImagesPerTrigger(5).NumTriggers(1).UseInternalPacketGenerator(true) .FilePrefix("lyso_test_min_pix_2").ConversionOnFPGA(false) @@ -111,7 +125,8 @@ TEST_CASE("PreviewImage_GenerateJPEG_ROI","[JPEG]") { {.x = 800, .y = 1000, .indexed = false}, {.x = 1200, .y = 500, .indexed = true} }; - PreviewImage image(experiment); + PreviewImage image; + image.Configure(experiment); image.UpdateImage(image_conv_2.data(), spots); PreviewJPEGSettings preview_settings{ @@ -128,6 +143,8 @@ TEST_CASE("PreviewImage_GenerateJPEG_ROI","[JPEG]") { } TEST_CASE("PreviewImage_GenerateJPEG_resolution","[JPEG]") { + RegisterHDF5Filter(); + DiffractionExperiment experiment(DetectorGeometry(8,2,8,36)); experiment.ImagesPerTrigger(5).NumTriggers(1).UseInternalPacketGenerator(true) .FilePrefix("lyso_test_min_pix_2").ConversionOnFPGA(false) @@ -153,7 +170,8 @@ TEST_CASE("PreviewImage_GenerateJPEG_resolution","[JPEG]") { RawToConvertedGeometry(experiment, image_conv_2.data(), image_raw_geom.data()); std::vector spots = {}; - PreviewImage image(experiment); + PreviewImage image; + image.Configure(experiment); image.UpdateImage(image_conv_2.data(), spots); PreviewJPEGSettings preview_settings{ diff --git a/tests/TIFFTest.cpp b/tests/TIFFTest.cpp index 2122f21c..826fda59 100644 --- a/tests/TIFFTest.cpp +++ b/tests/TIFFTest.cpp @@ -33,6 +33,8 @@ TEST_CASE("TIFFTest_File_signed","[TIFF]") { } TEST_CASE("PreviewImage_GenerateTIFF","[TIFF]") { + RegisterHDF5Filter(); + DiffractionExperiment experiment(DetectorGeometry(8,2,8,36)); experiment.ImagesPerTrigger(5).NumTriggers(1).UseInternalPacketGenerator(true) .FilePrefix("lyso_test_min_pix_2").ConversionOnFPGA(false) @@ -58,7 +60,8 @@ TEST_CASE("PreviewImage_GenerateTIFF","[TIFF]") { RawToConvertedGeometry(experiment, image_conv_2.data(), image_raw_geom.data()); std::vector spots; - PreviewImage image(experiment); + PreviewImage image; + image.Configure(experiment); image.UpdateImage(image_conv_2.data(), spots); std::string s; @@ -69,6 +72,8 @@ TEST_CASE("PreviewImage_GenerateTIFF","[TIFF]") { TEST_CASE("PreviewImage_GenerateTIFFDioptas","[TIFF]") { + RegisterHDF5Filter(); + DiffractionExperiment experiment(DetectorGeometry(8,2,8,36)); experiment.ImagesPerTrigger(5).NumTriggers(1).UseInternalPacketGenerator(true) .FilePrefix("lyso_test_min_pix_2").ConversionOnFPGA(false) @@ -94,7 +99,8 @@ TEST_CASE("PreviewImage_GenerateTIFFDioptas","[TIFF]") { RawToConvertedGeometry(experiment, image_conv_2.data(), image_raw_geom.data()); std::vector spots; - PreviewImage image(experiment); + PreviewImage image; + image.Configure(experiment); image.UpdateImage(image_conv_2.data(), spots); std::string s; diff --git a/tools/jfjoch_spot_finding_test.cpp b/tools/jfjoch_spot_finding_test.cpp index e77e011e..4c05a098 100644 --- a/tools/jfjoch_spot_finding_test.cpp +++ b/tools/jfjoch_spot_finding_test.cpp @@ -209,7 +209,9 @@ int main(int argc, char **argv) { MXAnalyzer analyzer(x); - PreviewImage preview(x); + PreviewImage preview; + preview.Configure(x); + uint64_t indexed_images = 0; LossyFilter filter(x);