From d74c9694fa7c5a9a533f066cd734d7046d652429 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Wed, 3 Dec 2025 16:31:20 +0100 Subject: [PATCH] jfjoch_broker: Add option to HTTP profiling --- broker/JFJochBrokerHttp.cpp | 52 +++++++++++++++---- broker/JFJochBrokerHttp.h | 8 ++- broker/gen/model/Jfjoch_settings.cpp | 31 ++++++++++- broker/gen/model/Jfjoch_settings.h | 9 ++++ broker/jfjoch_api.yaml | 4 ++ broker/jfjoch_broker.cpp | 4 +- broker/redoc-static.html | 2 +- docs/python_client/docs/JfjochSettings.md | 1 + .../src/openapi/models/jfjoch_settings.ts | 4 ++ 9 files changed, 101 insertions(+), 14 deletions(-) diff --git a/broker/JFJochBrokerHttp.cpp b/broker/JFJochBrokerHttp.cpp index a5bc603e..5a2ecf36 100644 --- a/broker/JFJochBrokerHttp.cpp +++ b/broker/JFJochBrokerHttp.cpp @@ -10,10 +10,12 @@ #include "../preview/JFJochTIFF.h" JFJochBrokerHttp::JFJochBrokerHttp(const DiffractionExperiment &experiment, - const SpotFindingSettings& spot_finding_settings, - std::shared_ptr &rtr) - : DefaultApi(rtr), - state_machine(experiment, services, logger, spot_finding_settings) { + const SpotFindingSettings &spot_finding_settings, + std::shared_ptr &rtr, + bool profiling) + : DefaultApi(rtr), + http_profiling(profiling), + state_machine(experiment, services, logger, spot_finding_settings) { Pistache::Rest::Routes::Get(*rtr, "/", Pistache::Rest::Routes::bind(&JFJochBrokerHttp::GetStaticFile, this)); Pistache::Rest::Routes::Get(*rtr, "/frontend", Pistache::Rest::Routes::bind(&JFJochBrokerHttp::GetStaticFile, this)); Pistache::Rest::Routes::Get(*rtr, "/frontend/*", Pistache::Rest::Routes::bind(&JFJochBrokerHttp::GetStaticFile, this)); @@ -55,7 +57,9 @@ void JFJochBrokerHttp::start_post(const org::openapitools::server::model::Datase } void JFJochBrokerHttp::status_get(Pistache::Http::ResponseWriter &response) { + const auto start = std::chrono::steady_clock::now(); ProcessOutput(Convert(state_machine.GetStatus()), response); + LogRequestDuration("status_get", start); } @@ -460,15 +464,20 @@ void JFJochBrokerHttp::image_buffer_clear_post(Pistache::Http::ResponseWriter &r void JFJochBrokerHttp::image_buffer_image_cbor_get(const std::optional &imageNumber, Pistache::Http::ResponseWriter &response) { + const auto start = std::chrono::steady_clock::now(); + std::vector tmp_vector; state_machine.GetImageFromBuffer(tmp_vector, imageNumber.value_or(-1)); std::string s = std::string((char *) tmp_vector.data(), tmp_vector.size()); - if (!s.empty()) + if (!s.empty()) { + LogRequestDuration("image_buffer_image_cbor_get", start); response.send(Pistache::Http::Code::Ok, s, Pistache::Http::Mime::MediaType::fromString("application/cbor")); - else + } else { + LogRequestDuration("image_buffer_image_cbor_get (not found)", start); response.send(Pistache::Http::Code::Not_Found); + } } void JFJochBrokerHttp::image_buffer_image_jpeg_get(const std::optional &id, @@ -482,6 +491,8 @@ void JFJochBrokerHttp::image_buffer_image_jpeg_get(const std::optional const std::optional &color, const std::optional &showResEst, Pistache::Http::ResponseWriter &response) { + const auto start = std::chrono::steady_clock::now(); + int64_t image_id = id.value_or(ImageBuffer::MaxImage); PreviewImageSettings settings{}; @@ -501,10 +512,13 @@ void JFJochBrokerHttp::image_buffer_image_jpeg_get(const std::optional settings.show_beam_center = showBeamCenter.value_or(true); settings.format = PreviewImageFormat::JPEG; std::string s = state_machine.GetPreviewJPEG(settings, image_id); - if (!s.empty()) + if (!s.empty()) { + LogRequestDuration("image_buffer_image_jpeg_get", start); response.send(Pistache::Http::Code::Ok, s, Pistache::Http::Mime::MediaType::fromString("image/jpeg")); - else + } else { + LogRequestDuration("image_buffer_image_jpeg_get (not found)", start); response.send(Pistache::Http::Code::Not_Found); + } } void @@ -521,15 +535,20 @@ JFJochBrokerHttp::image_buffer_image_tiff_get(const std::optional &id, } void JFJochBrokerHttp::image_buffer_start_cbor_get(Pistache::Http::ResponseWriter &response) { + const auto start = std::chrono::steady_clock::now(); + std::vector tmp_vector; state_machine.GetStartMessageFromBuffer(tmp_vector); std::string s = std::string((char *) tmp_vector.data(), tmp_vector.size()); - if (!s.empty()) + if (!s.empty()) { + LogRequestDuration("image_buffer_start_cbor_get", start); response.send(Pistache::Http::Code::Ok, s, Pistache::Http::Mime::MediaType::fromString("application/cbor")); - else + } else { + LogRequestDuration("image_buffer_start_cbor_get (not found)", start); response.send(Pistache::Http::Code::Not_Found); + } } void JFJochBrokerHttp::image_buffer_status_get(Pistache::Http::ResponseWriter &response) { @@ -551,6 +570,8 @@ void JFJochBrokerHttp::preview_plot_get(const std::optional &type, const std::optional &compression, const std::optional &fill, const std::optional &experimentalCoord, const std::optional &azintUnit, Pistache::Http::ResponseWriter &response) { + const auto start = std::chrono::steady_clock::now(); + PlotAzintUnit unit = PlotAzintUnit::Q_recipA; if (azintUnit.has_value()) { if (azintUnit == "Q_recipA" || azintUnit == "q_recipa") @@ -576,9 +597,12 @@ void JFJochBrokerHttp::preview_plot_get(const std::optional &type, req.binning = binning.value(); } auto plot = state_machine.GetPlots(req); + + LogRequestDuration("preview_plot_get", start); ProcessOutput(Convert(plot), response, compression.value_or(false)); } + void JFJochBrokerHttp::config_indexing_get(Pistache::Http::ResponseWriter &response) { ProcessOutput(Convert(state_machine.GetIndexingSettings()), response); } @@ -605,3 +629,11 @@ void JFJochBrokerHttp::config_dark_mask_put(const org::openapitools::server::mod void JFJochBrokerHttp::config_dark_mask_get(Pistache::Http::ResponseWriter &response) { ProcessOutput(Convert(state_machine.GetDarkMaskSettings()), response); } + +void JFJochBrokerHttp::LogRequestDuration(const char *operation, + const std::chrono::steady_clock::time_point &start) noexcept { + using namespace std::chrono; + const auto elapsed_ms = duration_cast(steady_clock::now() - start).count(); + if (http_profiling) + logger.Info("HTTP {} completed in {} ms", operation, static_cast(elapsed_ms)); +} diff --git a/broker/JFJochBrokerHttp.h b/broker/JFJochBrokerHttp.h index ca8bfd96..29b1ede7 100644 --- a/broker/JFJochBrokerHttp.h +++ b/broker/JFJochBrokerHttp.h @@ -19,6 +19,8 @@ class JFJochBrokerHttp : public org::openapitools::server::api::DefaultApi { Logger logger{"JFJochBroker"}; JFJochServices services {logger}; + bool http_profiling = false; + void config_image_format_get(Pistache::Http::ResponseWriter &response) override; void config_image_format_put(const org::openapitools::server::model::Image_format_settings &imageFormatSettings, @@ -183,7 +185,8 @@ class JFJochBrokerHttp : public org::openapitools::server::api::DefaultApi { public: JFJochBrokerHttp(const DiffractionExperiment& experiment, const SpotFindingSettings &spot_finding_settings, - std::shared_ptr &rtr); + std::shared_ptr &rtr, + bool profiling = false); void AddDetectorSetup(const DetectorSetup &setup); JFJochServices& Services(); @@ -197,6 +200,9 @@ private: void config_file_writer_put(const org::openapitools::server::model::File_writer_settings &fileWriterSettings, Pistache::Http::ResponseWriter &response) override; + + void LogRequestDuration(const char *operation, + const std::chrono::steady_clock::time_point &start) noexcept; }; diff --git a/broker/gen/model/Jfjoch_settings.cpp b/broker/gen/model/Jfjoch_settings.cpp index f14cc01d..0771db5b 100644 --- a/broker/gen/model/Jfjoch_settings.cpp +++ b/broker/gen/model/Jfjoch_settings.cpp @@ -33,6 +33,8 @@ Jfjoch_settings::Jfjoch_settings() m_Image_buffer_MiBIsSet = false; m_Verbose = false; m_VerboseIsSet = false; + m_Http_profile = false; + m_Http_profileIsSet = false; m_Receiver_threads = 64; m_Receiver_threadsIsSet = false; m_Numa_policy = ""; @@ -121,7 +123,7 @@ bool Jfjoch_settings::validate(std::stringstream& msg, const std::string& pathPr } } - + if (receiverThreadsIsSet()) { const int32_t& value = m_Receiver_threads; @@ -183,6 +185,9 @@ bool Jfjoch_settings::operator==(const Jfjoch_settings& rhs) const ((!verboseIsSet() && !rhs.verboseIsSet()) || (verboseIsSet() && rhs.verboseIsSet() && isVerbose() == rhs.isVerbose())) && + ((!httpProfileIsSet() && !rhs.httpProfileIsSet()) || (httpProfileIsSet() && rhs.httpProfileIsSet() && isHttpProfile() == rhs.isHttpProfile())) && + + ((!receiverThreadsIsSet() && !rhs.receiverThreadsIsSet()) || (receiverThreadsIsSet() && rhs.receiverThreadsIsSet() && getReceiverThreads() == rhs.getReceiverThreads())) && @@ -241,6 +246,8 @@ void to_json(nlohmann::json& j, const Jfjoch_settings& o) j["image_buffer_MiB"] = o.m_Image_buffer_MiB; if(o.verboseIsSet()) j["verbose"] = o.m_Verbose; + if(o.httpProfileIsSet()) + j["http_profile"] = o.m_Http_profile; if(o.receiverThreadsIsSet()) j["receiver_threads"] = o.m_Receiver_threads; if(o.numaPolicyIsSet()) @@ -313,6 +320,11 @@ void from_json(const nlohmann::json& j, Jfjoch_settings& o) j.at("verbose").get_to(o.m_Verbose); o.m_VerboseIsSet = true; } + if(j.find("http_profile") != j.end()) + { + j.at("http_profile").get_to(o.m_Http_profile); + o.m_Http_profileIsSet = true; + } if(j.find("receiver_threads") != j.end()) { j.at("receiver_threads").get_to(o.m_Receiver_threads); @@ -531,6 +543,23 @@ void Jfjoch_settings::unsetVerbose() { m_VerboseIsSet = false; } +bool Jfjoch_settings::isHttpProfile() const +{ + return m_Http_profile; +} +void Jfjoch_settings::setHttpProfile(bool const value) +{ + m_Http_profile = value; + m_Http_profileIsSet = true; +} +bool Jfjoch_settings::httpProfileIsSet() const +{ + return m_Http_profileIsSet; +} +void Jfjoch_settings::unsetHttp_profile() +{ + m_Http_profileIsSet = false; +} int32_t Jfjoch_settings::getReceiverThreads() const { return m_Receiver_threads; diff --git a/broker/gen/model/Jfjoch_settings.h b/broker/gen/model/Jfjoch_settings.h index e9ca44d3..221936df 100644 --- a/broker/gen/model/Jfjoch_settings.h +++ b/broker/gen/model/Jfjoch_settings.h @@ -150,6 +150,13 @@ public: bool verboseIsSet() const; void unsetVerbose(); /// + /// Print profiling information for HTTP requests + /// + bool isHttpProfile() const; + void setHttpProfile(bool const value); + bool httpProfileIsSet() const; + void unsetHttp_profile(); + /// /// Number of threads used by the receiver /// int32_t getReceiverThreads() const; @@ -234,6 +241,8 @@ protected: bool m_Image_buffer_MiBIsSet; bool m_Verbose; bool m_VerboseIsSet; + bool m_Http_profile; + bool m_Http_profileIsSet; int32_t m_Receiver_threads; bool m_Receiver_threadsIsSet; std::string m_Numa_policy; diff --git a/broker/jfjoch_api.yaml b/broker/jfjoch_api.yaml index 7b9c4d08..3d19d1b7 100644 --- a/broker/jfjoch_api.yaml +++ b/broker/jfjoch_api.yaml @@ -2116,6 +2116,10 @@ components: type: boolean default: false description: Print extra debug information + http_profile: + type: boolean + default: false + description: Print profiling information for HTTP requests receiver_threads: type: integer minimum: 1 diff --git a/broker/jfjoch_broker.cpp b/broker/jfjoch_broker.cpp index 90d84809..5352bb80 100644 --- a/broker/jfjoch_broker.cpp +++ b/broker/jfjoch_broker.cpp @@ -129,7 +129,9 @@ int main (int argc, char **argv) { std::vector sigs{SIGQUIT, SIGINT, SIGTERM, SIGHUP}; setUpUnixSignals(sigs); - JFJochBrokerHttp broker(experiment, spot_finding_settings, router); + JFJochBrokerHttp broker(experiment, spot_finding_settings, router, + settings.isHttpProfile()); + broker.FrontendDirectory(settings.getFrontendDirectory()); for (const auto &d: det_setup) diff --git a/broker/redoc-static.html b/broker/redoc-static.html index 6188457e..c54d966a 100644 --- a/broker/redoc-static.html +++ b/broker/redoc-static.html @@ -1405,7 +1405,7 @@ then image might be replaced in the buffer between calling /images and /image.cb " class="sc-eVqvcJ sc-fszimp kIppRw drqpJr">

Test Jungfraujoch system

http://localhost:5232/version