From 732fc5686257b5adfbfde8ab8f6d11ba547114df Mon Sep 17 00:00:00 2001 From: YanzhaoW Date: Tue, 21 Nov 2023 23:57:03 +0100 Subject: [PATCH] create R3B::UcesbSource2 --- .gitignore | 3 + r3bsource/CMakeLists.txt | 5 + r3bsource/base/R3BReader.h | 15 ++ r3bsource/base/R3BUcesbSource2.cxx | 218 ++++++++++++++++++++ r3bsource/base/R3BUcesbSource2.h | 152 ++++++++++++++ r3bsource/base/utils/R3BUcesbDecl.h | 152 ++++++++++++++ r3bsource/base/utils/R3BUcesbLauncher.cxx | 198 ++++++++++++++++++ r3bsource/base/utils/R3BUcesbLauncher.h | 42 ++++ r3bsource/base/utils/R3BUcesbMappingFlag.h | 144 +++++++++++++ r3bsource/base/utils/R3BUcesbStructInfo.cxx | 93 +++++++++ r3bsource/base/utils/R3BUcesbStructInfo.h | 42 ++++ 11 files changed, 1064 insertions(+) create mode 100644 r3bsource/base/R3BUcesbSource2.cxx create mode 100644 r3bsource/base/R3BUcesbSource2.h create mode 100644 r3bsource/base/utils/R3BUcesbDecl.h create mode 100644 r3bsource/base/utils/R3BUcesbLauncher.cxx create mode 100644 r3bsource/base/utils/R3BUcesbLauncher.h create mode 100644 r3bsource/base/utils/R3BUcesbMappingFlag.h create mode 100644 r3bsource/base/utils/R3BUcesbStructInfo.cxx create mode 100644 r3bsource/base/utils/R3BUcesbStructInfo.h diff --git a/.gitignore b/.gitignore index 56a00ddae..b9eba70b1 100644 --- a/.gitignore +++ b/.gitignore @@ -62,5 +62,8 @@ input/ build-r3broot.sh cmake-build-debug/ +#conan: +CMakeUserPresets.json + # Local configuration c3w.conf diff --git a/r3bsource/CMakeLists.txt b/r3bsource/CMakeLists.txt index 4627594e4..5fab376c2 100644 --- a/r3bsource/CMakeLists.txt +++ b/r3bsource/CMakeLists.txt @@ -25,6 +25,7 @@ set(INCLUDE_DIRECTORIES #put here all directories where header files are located ${R3BROOT_SOURCE_DIR}/r3bsource ${R3BROOT_SOURCE_DIR}/r3bsource/base +${R3BROOT_SOURCE_DIR}/r3bsource/base/utils ${R3BROOT_SOURCE_DIR}/r3bsource/wr ${R3BROOT_SOURCE_DIR}/r3bsource/trloii ${R3BROOT_SOURCE_DIR}/r3bsource/beammonitor @@ -91,7 +92,10 @@ include_directories(SYSTEM ${SYSTEM_INCLUDE_DIRECTORIES}) link_directories( ${LINK_DIRECTORIES}) set(SRCS +./base/utils/R3BUcesbLauncher.cxx +./base/utils/R3BUcesbStructInfo.cxx ./base/R3BUcesbSource.cxx +./base/R3BUcesbSource2.cxx ./base/R3BReader.cxx ./base/R3BUnpackReader.cxx ./wr/R3BWhiterabbitMasterReader.cxx @@ -237,3 +241,4 @@ set(DEPENDENCIES set(LIBRARY_NAME R3Bsource) GENERATE_LIBRARY() +target_include_directories(R3Bsource PUBLIC neuland base base/utils trloii wr ${SYSTEM_INCLUDE_DIRECTORIES}) diff --git a/r3bsource/base/R3BReader.h b/r3bsource/base/R3BReader.h index 4c73d3709..4aea2f537 100644 --- a/r3bsource/base/R3BReader.h +++ b/r3bsource/base/R3BReader.h @@ -16,6 +16,7 @@ #include "TNamed.h" #include "TString.h" +#include extern "C" { @@ -30,6 +31,14 @@ class R3BReader : public TNamed public: R3BReader(TString const&); virtual ~R3BReader(); + [[nodiscard]] virtual bool MismappedItemRequired(std::string_view /*item_name*/) const { return false; } + bool AllowExtraCondition(R3B::UcesbMap map_flag, R3B::UcesbMap success_condition) + { + return (map_flag & ~(success_condition | extra_conditions_)) == R3B::UcesbMap::zero; + } + + void SetExtraConditions(R3B::UcesbMap conditions) { extra_conditions_ = conditions; } + void AddExtraConditions(R3B::UcesbMap conditions) { extra_conditions_ |= conditions; } /* Setup structure information */ virtual Bool_t Init(ext_data_struct_info*) = 0; @@ -41,6 +50,12 @@ class R3BReader : public TNamed virtual void Reset() = 0; /* Return actual name of the reader */ + // actions when closed + virtual void Close(){}; + + private: + R3B::UcesbMap extra_conditions_ = R3B::UcesbMap::zero; + public: ClassDef(R3BReader, 0); }; diff --git a/r3bsource/base/R3BUcesbSource2.cxx b/r3bsource/base/R3BUcesbSource2.cxx new file mode 100644 index 000000000..df378c322 --- /dev/null +++ b/r3bsource/base/R3BUcesbSource2.cxx @@ -0,0 +1,218 @@ +/****************************************************************************** + * Copyright (C) 2019 GSI Helmholtzzentrum für Schwerionenforschung GmbH * + * Copyright (C) 2019-2023 Members of R3B Collaboration * + * * + * This software is distributed under the terms of the * + * GNU General Public Licence (GPL) version 3, * + * copied verbatim in the file "LICENSE". * + * * + * In applying this license GSI does not waive the privileges and immunities * + * granted to it by virtue of its status as an Intergovernmental Organization * + * or submit itself to any jurisdiction. * + ******************************************************************************/ + +#include "R3BUcesbSource2.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace R3B +{ + UcesbSource::UcesbSource(std::string_view lmdfile_name, + std::string_view ntuple_options, + std::string_view ucesb_path, + EventStructType* event_struct, + size_t event_struct_size) + : event_struct_size_{ event_struct_size } + , event_struct_{ event_struct } + , lmdfile_name_{ lmdfile_name } + , ntuple_options_{ ntuple_options } + , ucesb_path_{ ucesb_path } + { + } + + bool UcesbSource::Init() + { + init_runID(); + init_ucesb(); + return true; + } + + UcesbSource::~UcesbSource() { ucesb_server_launcher_.Close(); } + + void UcesbSource::init_ucesb() + { + auto command_string = fmt::format("{0} {1} --ntuple={2},STRUCT,-", ucesb_path_, lmdfile_name_, ntuple_options_); + if (max_event_num_ > 0) + { + command_string = fmt::format("{} --max-events={}", command_string, max_event_num_); + } + R3BLOG(info, fmt::format("Calling ucesb with command: {}", command_string)); + + ucesb_server_launcher_.Launch(std::move(command_string)); + } + + bool UcesbSource::InitUnpackers() + { + if (auto* frm = FairRootManager::Instance(); frm != nullptr) + { + R3BLOG(debug, "Checking the register of R3BEventHeader"); + if (event_header_ = dynamic_cast(frm->GetObject("EventHeader.")); event_header_ == nullptr) + { + throw R3B::runtime_error("EventHeader. was not defined properly!"); + } + } + R3BLOG(debug, "EventHeader. was defined properly"); + + init_readers(); + setup_ucesb(); + + return true; + } + + void UcesbSource::setup_ucesb() + { + // TODO: convert to std::bitset + // could be initialzed in type UcesbMap. But C++ doesn't allow static cast of enum class pointer to its + // underlying type + auto is_struct_map_success = uint32_t{}; + if (ucesb_client_.setup( + nullptr, 0, ucesb_client_struct_info_.Get(), &is_struct_map_success, event_struct_size_) == 0) + { + ucesb_client_struct_info_.CheckStructMapping(this); + } + else + { + R3BLOG(error, "ext_data_clnt::setup() failed"); + const auto* msg = (ucesb_client_.last_error() == nullptr) ? UCESB_NULL_STR_MSG : ucesb_client_.last_error(); + throw R3B::runtime_error(fmt::format("UCESB error: {}", msg)); + } + } + + int UcesbSource::ReadEvent(unsigned int /*eventID*/) + { + auto ret_val = ucesb_client_.fetch_event(event_struct_, event_struct_size_); + if (ret_val > 0) + { + ForEachReader([](auto& reader) { reader->R3BRead(); }); + } + else if (ret_val == 0) + { + R3BLOG(info, "Reached the maximal event num on the ucesb server."); + // ending event loop here + return 1; + } + else + { + R3BLOG(error, "ext_data_clnt::fetch_event() failed"); + const auto* msg = (ucesb_client_.last_error() == nullptr) ? UCESB_NULL_STR_MSG : ucesb_client_.last_error(); + throw R3B::runtime_error(fmt::format("UCESB error: {}", msg)); + } + + return 0; + } + + void print_uint32_with_size(const uint32_t* data, ssize_t size) + { + // TODO: use ranges library instead of reinterpret_cast + constexpr auto column_size = 8; + using SubDataType = const std::array; + + auto data_span = std::span(reinterpret_cast(data), size / column_size); + R3BLOG(info, "Raw data:"); + auto index = uint32_t{}; + for (const auto& row_data : data_span) + { + fmt::print("RAW{0:04x}: {1:08x}\n", index, fmt::join(row_data, " ")); + index += column_size; + } + } + + void UcesbSource::print_raw_data() + { + // TODO: what's the best way to deal with this void** monstrosity + const void* raw_data = nullptr; + ssize_t raw_data_size = 0; + auto ret_val = ucesb_client_.get_raw_data(&raw_data, &raw_data_size); + + if (ret_val == 0) + { + if (raw_data != nullptr) + { + const auto* data = reinterpret_cast(raw_data); + print_uint32_with_size(data, raw_data_size); + } + } + else + { + R3BLOG(error, "ext_data_clnt::get_raw_data()"); + throw R3B::runtime_error("Failed to get raw data."); + } + } + + void UcesbSource::init_runID() + { + auto* run = FairRun::Instance(); + if (run == nullptr) + { + throw R3B::runtime_error("FairRun is not available!"); + } + + if (run_id_ != 0) + { + R3BLOG(info, fmt::format("Setting the run ID of the FairRun to be {} from FairSource", run_id_)); + run->SetRunId(run_id_); + } + else if (auto run_id = run->GetRunId(); run_id != 0) + { + R3BLOG(info, fmt::format("Setting the run ID of the FairSource to be {} from FairRun", run_id)); + run_id_ = run_id; + } + else + { + R3BLOG(warn, "Run ID of neither FairRun nor FairSource is set!"); + } + } + + void UcesbSource::FillEventHeader(FairEventHeader* feh) { feh->SetRunId(run_id_); } + + int UcesbSource::CheckMaxEventNo(int EvtEnd) + { + max_event_num_ = (EvtEnd == 0) ? max_event_num_ : EvtEnd; + return static_cast(max_event_num_); + } + + // readers looping methods: + void UcesbSource::init_readers() + { + ForEachReader( + [this](auto& reader) + { + if (not reader->Init(ucesb_client_struct_info_.Get())) + { + const auto* msg = + (ucesb_client_.last_error() == nullptr) ? UCESB_NULL_STR_MSG : ucesb_client_.last_error(); + throw R3B::runtime_error(fmt::format("UCESB error: {}", msg)); + } + }); + } + + bool UcesbSource::ReInitUnpackers() + { + ForEachReader( + [](auto& reader) + { + if (!reader->ReInit()) + { + throw R3B::runtime_error("ReInit of a reader failed."); + } + }); + return true; + } +} // namespace R3B diff --git a/r3bsource/base/R3BUcesbSource2.h b/r3bsource/base/R3BUcesbSource2.h new file mode 100644 index 000000000..d067563ae --- /dev/null +++ b/r3bsource/base/R3BUcesbSource2.h @@ -0,0 +1,152 @@ +#pragma once + +/****************************************************************************** + * Copyright (C) 2019 GSI Helmholtzzentrum für Schwerionenforschung GmbH * + * Copyright (C) 2019-2023 Members of R3B Collaboration * + * * + * This software is distributed under the terms of the * + * GNU General Public Licence (GPL) version 3, * + * copied verbatim in the file "LICENSE". * + * * + * In applying this license GSI does not waive the privileges and immunities * + * granted to it by virtue of its status as an Intergovernmental Organization * + * or submit itself to any jurisdiction. * + ******************************************************************************/ + +#include "R3BReader.h" +#include +#include +#include +#include +#include + +struct EXT_STR_h101_t; +using EventStructType = EXT_STR_h101_t; + +namespace R3B +{ + class UcesbSource : public FairSource + { + public: + UcesbSource() = default; + UcesbSource(std::string_view lmdfile_name, + std::string_view ntuple_options, + std::string_view ucesb_path, + EventStructType* event_struct, + size_t event_struct_size); + // rule of five: + ~UcesbSource() override; + UcesbSource(const UcesbSource&) = delete; + UcesbSource(UcesbSource&&) = delete; + UcesbSource& operator=(const UcesbSource&) = delete; + UcesbSource& operator=(UcesbSource&&) = delete; + + // setters: + void SetMaxEvents(unsigned int max_event_num) { max_event_num_ = max_event_num; } + void SetLMDFileName(std::string_view lmdfile_name) { lmdfile_name_ = lmdfile_name; } + void SetNTupleOptions(std::string_view ntuple_options) { ntuple_options_ = ntuple_options; } + void SetUcesbPath(std::string_view ucesb_path) { ucesb_path_ = ucesb_path; } + void SetEventStructSize(size_t event_size) { event_struct_size_ = event_size; } + // non-owning + void SetEventStruct(EventStructType* event_struct) { event_struct_ = event_struct; } + void SetRawDataPrint(bool print_raw_data) { has_raw_data_printing_ = print_raw_data; } + void SetRunID(unsigned int run_id) { run_id_ = run_id; } + void AllowExtraMap(UcesbMap flag) { ucesb_client_struct_info_.SetExtraMapFlags(flag); } + + template + auto AddReader(std::unique_ptr reader) -> ReaderType*; + template + auto AddReader(Args&&... args) -> ReaderType*; + // TODO: C++20 concepts + template + void ForEachReader(UnaryOp&& opt); + + template + auto FindReaderIf(Predicate&& pred) -> R3BReader*; + + // deprecate the old API because of bad memory managerment + [[deprecated("Please use smart pointer method to add a reader")]] auto* AddReader(R3BReader* a_reader) + { + return AddReader(std::unique_ptr(a_reader)); + } + + private: + bool has_raw_data_printing_ = false; + unsigned int run_id_ = 0; + unsigned int max_event_num_ = 0; + size_t event_struct_size_ = 0; + EventStructType* event_struct_ = nullptr; // non-owning + R3BEventHeader* event_header_ = nullptr; // non-owning + std::vector> readers_; + std::string lmdfile_name_; + std::string ntuple_options_; + std::string ucesb_path_; + + ext_data_clnt ucesb_client_; + UcesbStructInfo ucesb_client_struct_info_; + UcesbServerLauncher ucesb_server_launcher_ = UcesbServerLauncher{ &ucesb_client_ }; + + // private non-virtual methods: + + void init_runID(); + void init_ucesb(); + void init_ucesb_bp(); + void init_readers(); + void setup_ucesb(); + void print_raw_data(); + + // private virtual methods: + bool Init() override; + bool InitUnpackers() override; + bool ReInitUnpackers() override; + void Close() override {} + void SetParUnpackers() override + { + ForEachReader([](auto& reader) { reader->SetParContainers(); }); + } + void Reset() override + { + ForEachReader([](auto& reader) { reader->Reset(); }); + } + void FillEventHeader(FairEventHeader* feh) override; + int ReadEvent(unsigned int eventID = 0) override; + int CheckMaxEventNo(int EvtEnd = 0) override; + bool SpecifyRunId() override { return true; } + Source_Type GetSourceType() override { return kONLINE; } + + public: + ClassDefInlineOverride(R3B::UcesbSource, 1); + }; + + template + auto UcesbSource::AddReader(std::unique_ptr reader) -> ReaderType* + { + auto& reader_ref = readers_.emplace_back(std::move(reader)); + return static_cast(reader_ref.get()); + } + + template + auto UcesbSource::AddReader(Args&&... args) -> ReaderType* + { + static_assert(std::is_base_of_v, "The reader type must be derived from R3BReader!"); + return AddReader(std::make_unique(std::forward(args)...)); + } + + template + void UcesbSource::ForEachReader(UnaryOp&& opt) + { + for (auto& reader : readers_) + { + opt(reader); + } + } + + template + auto UcesbSource::FindReaderIf(Predicate&& pred) -> R3BReader* + { + auto res = std::find_if(readers_.begin(), readers_.end(), [&pred](auto& reader) { return pred(reader.get()); }); + return (res == readers_.end()) ? nullptr : res->get(); + } +} // namespace R3B + +using R3BUcesbSource2 = R3B::UcesbSource; diff --git a/r3bsource/base/utils/R3BUcesbDecl.h b/r3bsource/base/utils/R3BUcesbDecl.h new file mode 100644 index 000000000..c15fe35c2 --- /dev/null +++ b/r3bsource/base/utils/R3BUcesbDecl.h @@ -0,0 +1,152 @@ +#pragma once +/****************************************************************************** + * Copyright (C) 2019 GSI Helmholtzzentrum für Schwerionenforschung GmbH * + * Copyright (C) 2019-2023 Members of R3B Collaboration * + * * + * This software is distributed under the terms of the * + * GNU General Public Licence (GPL) version 3, * + * copied verbatim in the file "LICENSE". * + * * + * In applying this license GSI does not waive the privileges and immunities * + * granted to it by virtue of its status as an Intergovernmental Organization * + * or submit itself to any jurisdiction. * + ******************************************************************************/ + +// This header file can totally be avoided if, for some reasons, Ucesb client code base didn't hide these declarations +// in SOURCE file. + +#include +#include + +constexpr auto EXT_DATA_STATE_INIT = 0; +constexpr auto EXT_DATA_STATE_OPEN = 1; +constexpr auto EXT_DATA_STATE_OPEN_OUT = 2; +constexpr auto EXT_DATA_STATE_PARSED_HEADERS = 3; +constexpr auto EXT_DATA_STATE_SETUP_READ = 4; +constexpr auto EXT_DATA_STATE_SETUP_WRITE = 5; + +struct ext_data_structure_item +{ + uint32_t _offset; /* Not used within STRUCT_WRITER itself. */ + uint32_t _length; /* not needed, info only */ + const char* _block; /* not needed, info only */ + + const char* _var_name; + uint32_t _var_array_len; + const char* _var_ctrl_name; + uint32_t _var_type; + uint32_t _limit_min; + uint32_t _limit_max; + + uint32_t _map_success; + +#if STRUCT_WRITER + uint32_t _ctrl_offset; +#endif + /* Used for remapping. */ + struct ext_data_structure_item* _ctrl_item; + struct ext_data_structure_item* _next_off_item; + /* Temporary used while creating remap list. */ + struct ext_data_structure_item* _match_item; + struct ext_data_structure_item* _child_item; +}; + +struct ext_data_structure_info +{ + struct ext_data_structure_item* _items; + + /* Used while returning items for ext_data_struct_info_map_success(). */ + struct ext_data_structure_item* _ret_item; + int _ret_for_server; + + struct ext_data_structure_info* _server_struct_info; + + uint32_t _map_success; + + const char* _last_error; +}; + +struct ext_data_client_struct +{ + const char* _id; + + /* Todo: the following controls _raw_ptr in ext_data_client. With + * several structures...? + */ + uint32_t _max_raw_words; + + uint32_t _orig_xor_sum_msg; + size_t _orig_struct_size; + void* _orig_array; /* for mapping */ + + uint32_t _orig_max_pack_items; + uint32_t _orig_static_pack_items; + + uint32_t* _orig_pack_list; + uint32_t* _orig_pack_list_end; + + size_t _dest_struct_size; + + uint32_t _dest_max_pack_items; + uint32_t _dest_static_pack_items; + + uint32_t* _dest_pack_list; + uint32_t* _dest_pack_list_end; + + uint32_t* _dest_reverse_pack; + + uint32_t* _map_list; + uint32_t* _map_list_end; + + struct ext_data_structure_info* _struct_info_msg; +}; + +struct ext_data_client +{ + int _fd; + int _fd_close; /* If using STDIN, we are not to close it, so -1. */ + + char* _buf; + size_t _buf_alloc; + size_t _buf_used; + size_t _buf_filled; + + uint32_t* _raw_ptr; /* This is not allocated; just used. */ + uint32_t _raw_words; + uint32_t* _raw_swapped; + + struct ext_data_client_struct* _structures; + int _num_structures; + + uint32_t _sort_u32_words; + + const char* _last_error; + + int _state; + + int _fetched_event; +}; + +/* Layout of the structure information generated. + */ + +struct ext_data_structure_layout_item +{ + uint32_t _offset; + uint32_t _size; + uint32_t _xor; + const char* _name; +}; + +struct ext_data_structure_layout +{ + uint32_t _magic; + uint32_t _size_info; + uint32_t _size_struct; + uint32_t _size_struct_onion; + uint32_t _pack_list_items; + + uint32_t _num_items; + // NOLINTNEXTLINE + struct ext_data_structure_layout_item _items[1]; /* more than 1 for parts */ +}; diff --git a/r3bsource/base/utils/R3BUcesbLauncher.cxx b/r3bsource/base/utils/R3BUcesbLauncher.cxx new file mode 100644 index 000000000..0336571e2 --- /dev/null +++ b/r3bsource/base/utils/R3BUcesbLauncher.cxx @@ -0,0 +1,198 @@ +/****************************************************************************** + * Copyright (C) 2019 GSI Helmholtzzentrum für Schwerionenforschung GmbH * + * Copyright (C) 2019-2023 Members of R3B Collaboration * + * * + * This software is distributed under the terms of the * + * GNU General Public Licence (GPL) version 3, * + * copied verbatim in the file "LICENSE". * + * * + * In applying this license GSI does not waive the privileges and immunities * + * granted to it by virtue of its status as an Intergovernmental Organization * + * or submit itself to any jurisdiction. * + ******************************************************************************/ + +#include "R3BUcesbLauncher.h" +#include +#include +#include +#include +#include +#include + +#include + +constexpr auto CHILD_CLOSE_WAITING_TIME = std::chrono::seconds(5); + +namespace fs = std::filesystem; +namespace +{ + struct ResolveResult + { + std::string executable; + std::vector options; + std::vector lmds; + std::vector others; + }; + + bool Check_exist(std::string_view exe) + { + auto exe_path = fs::path{ exe }; + return fs::exists(exe_path) || fs::is_symlink(exe_path); + } + + // TODO: C++23 insert range + template + void Append_elements(std::vector& base, std::vector to_append) + { + base.reserve(base.size() + to_append.size()); + for (auto& ele : to_append) + { + base.emplace_back(std::move(ele)); + } + } + + auto get_regex_filelist(std::string filename_regex) -> std::vector + { + auto wildcard_path = fs::path{ filename_regex }; + auto parent_folder = wildcard_path.parent_path(); + if (not fs::exists(parent_folder)) + { + R3BLOG(error, fmt::format("Cannot get the parent folder of the regex path {}", filename_regex)); + return {}; + } + // const auto regex_string = std::regex_replace(wildcard_path.filename().string(), std::regex{ "\\*" }, ".*"); + const auto regex_string = wildcard_path.filename().string(); + auto filelist = std::vector{}; + for (const auto& dir_entry : fs::directory_iterator(parent_folder)) + { + if (std::regex_match(dir_entry.path().filename().string(), std::regex{ regex_string })) + { + filelist.emplace_back(fs::absolute(dir_entry.path())); + } + } + if (filelist.empty()) + { + R3BLOG(error, fmt::format(R"(Cannot find any files with regex "{}")", regex_string)); + } + return filelist; + } + + void Append_lmds(std::vector& lmds, std::string filename_regex) + { + // expand filenames on regex + Append_elements(lmds, get_regex_filelist(std::move(filename_regex))); + } + + auto parse_splits(std::vector splits) -> ResolveResult + { + auto result = ResolveResult{}; + + auto option_regex = std::regex{ "^--[0-9A-z,=\\-]+" }; + auto lmd_regex = std::regex{ "^.*\\.lmd$" }; + + for (auto& split_item : splits) + { + if (std::regex_match(split_item, option_regex)) + { + result.options.emplace_back(std::move(split_item)); + } + else if (std::regex_match(split_item, lmd_regex)) + { + Append_lmds(result.lmds, std::move(split_item)); + } + else if (Check_exist(split_item)) + { + // it must be an executable then + if (not result.executable.empty()) + { + R3BLOG(info, fmt::format("Ucesb Executable has been set to \"{}\" ", result.executable)); + R3BLOG(error, fmt::format("Found another executable \"{}\" but only one is allowed!", split_item)); + continue; + } + result.executable = std::move(split_item); + } + else + { + // In other cases, let ucesb deal with this + result.others.emplace_back(std::move(split_item)); + } + } + return result; + } + + void lmd_filenames_sorting(std::vector& filenames) + { + // simple lexicographically sorting + std::sort(filenames.begin(), filenames.end()); + } + + auto resolve_exe_options_lmd(std::string cmd) -> ResolveResult + { + if (cmd.empty()) + { + throw R3B::logic_error("Ucesb command string is empty!"); + } + R3BLOG(debug, fmt::format("Resolving string command: {}", cmd)); + boost::trim(cmd); + auto splits = std::vector{}; + auto executable = std::string{}; + auto options = std::vector{}; + auto lmds = std::vector{}; + boost::split(splits, cmd, boost::is_any_of(" "), boost::token_compress_on); + if (splits.empty()) + { + throw R3B::runtime_error(fmt::format("Get 0 element from splitting string {}", cmd)); + } + auto results = parse_splits(std::move(splits)); + lmd_filenames_sorting(results.lmds); + + return results; + } +} // namespace + +namespace R3B +{ + void UcesbServerLauncher::Launch(std::string command_string) + { + auto launch_strings = resolve_exe_options_lmd(std::move(command_string)); + auto launch_args = std::vector{}; + Append_elements(launch_args, std::move(launch_strings.options)); + Append_elements(launch_args, std::move(launch_strings.lmds)); + Append_elements(launch_args, std::move(launch_strings.others)); + + R3BLOG(debug, + fmt::format("Ucesb command after resolving wildcard filename: \n {} {}", + launch_strings.executable, + fmt::join(launch_args, " "))); + + ucesb_server_ = std::make_unique( + launch_strings.executable, boost::process::args(launch_args), boost::process::std_out > server_pipe_); + if (auto is_status_ok = client_->connect(server_pipe_.native_source()); not is_status_ok) + { + R3BLOG(error, "ext_data_clnt::connect() failed"); + const auto* msg = (client_->last_error() == nullptr) ? UCESB_NULL_STR_MSG : client_->last_error(); + throw R3B::runtime_error(fmt::format("UCESB error: {}", msg)); + } + } + + void UcesbServerLauncher::Setup(ext_data_struct_info& struct_info, size_t event_struct_size) {} + + void UcesbServerLauncher::Close() + { + if (auto ret_val = client_->close(); ret_val != 0) + { + throw R3B::runtime_error("ext_data_clnt::close() failed"); + } + auto err_code = std::error_code{}; + if (not ucesb_server_->wait_for(CHILD_CLOSE_WAITING_TIME, err_code)) + { + R3BLOG(warn, fmt::format("Failed to close Ucesb server! Error code: {}", err_code)); + ucesb_server_->terminate(err_code); + R3BLOG(warn, "Killing Ucesb server"); + } + else + { + R3BLOG(info, "Ucesb server is closed successfully"); + } + } +} // namespace R3B diff --git a/r3bsource/base/utils/R3BUcesbLauncher.h b/r3bsource/base/utils/R3BUcesbLauncher.h new file mode 100644 index 000000000..1d7ebf065 --- /dev/null +++ b/r3bsource/base/utils/R3BUcesbLauncher.h @@ -0,0 +1,42 @@ +#pragma once + +/****************************************************************************** + * Copyright (C) 2019 GSI Helmholtzzentrum für Schwerionenforschung GmbH * + * Copyright (C) 2019-2023 Members of R3B Collaboration * + * * + * This software is distributed under the terms of the * + * GNU General Public Licence (GPL) version 3, * + * copied verbatim in the file "LICENSE". * + * * + * In applying this license GSI does not waive the privileges and immunities * + * granted to it by virtue of its status as an Intergovernmental Organization * + * or submit itself to any jurisdiction. * + ******************************************************************************/ +#include +#include +#include + +constexpr auto UCESB_NULL_STR_MSG = "Can't retrieve error message as last_error returns nullptr!"; + +namespace R3B +{ + + class UcesbServerLauncher + { + public: + explicit UcesbServerLauncher(ext_data_clnt* client) + : client_{ client } + { + } + void Launch(std::string command_string); + void Setup(ext_data_struct_info& struct_info, size_t event_struct_size); + void Close(); + + private: + ext_data_clnt* client_ = nullptr; + std::unique_ptr ucesb_server_; + boost::asio::io_service ios_; + boost::process::async_pipe server_pipe_{ ios_ }; + }; + +} // namespace R3B diff --git a/r3bsource/base/utils/R3BUcesbMappingFlag.h b/r3bsource/base/utils/R3BUcesbMappingFlag.h new file mode 100644 index 000000000..d6f1bda72 --- /dev/null +++ b/r3bsource/base/utils/R3BUcesbMappingFlag.h @@ -0,0 +1,144 @@ +#pragma once +/****************************************************************************** + * Copyright (C) 2019 GSI Helmholtzzentrum für Schwerionenforschung GmbH * + * Copyright (C) 2019-2023 Members of R3B Collaboration * + * * + * This software is distributed under the terms of the * + * GNU General Public Licence (GPL) version 3, * + * copied verbatim in the file "LICENSE". * + * * + * In applying this license GSI does not waive the privileges and immunities * + * granted to it by virtue of its status as an Intergovernmental Organization * + * or submit itself to any jurisdiction. * + ******************************************************************************/ + +#include +#include +#include +#include + +constexpr auto UCESB_MAP_BITSIZE = 32; + +namespace R3B +{ + + enum class UcesbMap : uint32_t + { + zero = 0x0000U, + match = EXT_DATA_ITEM_MAP_MATCH, + no_dest = EXT_DATA_ITEM_MAP_NO_DEST, + not_found = EXT_DATA_ITEM_MAP_NOT_FOUND, + type_mismatch = EXT_DATA_ITEM_MAP_TYPE_MISMATCH, + ctrl_mismatch = EXT_DATA_ITEM_MAP_CTRL_MISMATCH, + array_fewer = EXT_DATA_ITEM_MAP_ARRAY_FEWER, + array_more = EXT_DATA_ITEM_MAP_ARRAY_MORE, + not_done = EXT_DATA_ITEM_MAP_NOT_DONE, + ok = EXT_DATA_ITEM_MAP_OK, + ok_no_dest = EXT_DATA_ITEM_MAP_OK_NO_DEST, + }; + + using UcesbMapUType = std::underlying_type::type; + + inline auto operator|(const UcesbMap& left, const UcesbMap& right) -> UcesbMap + { + auto res = static_cast(left) | static_cast(right); + return static_cast(res); + } + inline void operator|=(UcesbMap& left, const UcesbMap& right) { left = left | right; } + + inline auto operator&(const UcesbMap& left, const UcesbMap& right) -> UcesbMap + { + auto res = static_cast(left) & static_cast(right); + return static_cast(res); + } + + inline void operator&=(UcesbMap& left, const UcesbMap& right) { left = left & right; } + + inline auto operator~(const UcesbMap& map) -> UcesbMap + { + return static_cast(~(static_cast(map))); + } + + inline auto operator<<(std::ostream& ostream, const UcesbMap& map) -> std::ostream& + { + ostream << std::bitset(static_cast(map)); + return ostream; + } + + inline auto UcesbMap2String(UcesbMap map) -> std::string + { + switch (map) + { + case UcesbMap::zero: + return std::string{ "zero" }; + case UcesbMap::match: + return std::string{ "match" }; + case UcesbMap::no_dest: + return std::string{ "no_dest" }; + case UcesbMap::not_found: + return std::string{ "not_found" }; + case UcesbMap::type_mismatch: + return std::string{ "type_mismatch" }; + case UcesbMap::ctrl_mismatch: + return std::string{ "ctrl_mismatch" }; + case UcesbMap::array_fewer: + return std::string{ "array_fewer" }; + case UcesbMap::array_more: + return std::string{ "array_more" }; + case UcesbMap::not_done: + return std::string{ "not_done" }; + case UcesbMap::ok: + return std::string{ "ok" }; + case UcesbMap::ok_no_dest: + return std::string{ "ok_no_dest" }; + default: + return fmt::format("", std::bitset(static_cast(map)).to_string()); + } + } +} // namespace R3B + +template <> +class fmt::formatter +{ + public: + constexpr auto parse(format_parse_context& ctx) + { + if (ctx.begin() == ctx.end()) + { + return ctx.end(); + } + const auto* specifier_iter = ctx.begin(); + if (*specifier_iter == 's' or *specifier_iter == 'b') + { + presentation_ = *specifier_iter; + ++specifier_iter; // NOLINT + } + + if (specifier_iter == ctx.end()) + { + throw format_error("UcesbMap format failed: missing right curly bracket!"); + } + + if (*specifier_iter != '}') + { + throw format_error("UcesbMap format failed: only one speicifier is allowed"); + } + return specifier_iter; + } + + template + constexpr auto format(const R3B::UcesbMap& flag, FmtContent& ctn) const + { + switch (presentation_) + { + default: + case 's': + return format_to(ctn.out(), "{}", R3B::UcesbMap2String(flag)); + case 'b': + return format_to(ctn.out(), "0x{:b}", static_cast(flag)); + } + } + + private: + char presentation_ = 's'; +}; diff --git a/r3bsource/base/utils/R3BUcesbStructInfo.cxx b/r3bsource/base/utils/R3BUcesbStructInfo.cxx new file mode 100644 index 000000000..e88d155bd --- /dev/null +++ b/r3bsource/base/utils/R3BUcesbStructInfo.cxx @@ -0,0 +1,93 @@ +/****************************************************************************** + * Copyright (C) 2019 GSI Helmholtzzentrum für Schwerionenforschung GmbH * + * Copyright (C) 2019-2023 Members of R3B Collaboration * + * * + * This software is distributed under the terms of the * + * GNU General Public Licence (GPL) version 3, * + * copied verbatim in the file "LICENSE". * + * * + * In applying this license GSI does not waive the privileges and immunities * + * granted to it by virtue of its status as an Intergovernmental Organization * + * or submit itself to any jurisdiction. * + ******************************************************************************/ + +#include "R3BUcesbStructInfo.h" +#include "R3BUcesbDecl.h" +#include +#include +#include + +namespace R3B +{ + // return pointer of the reader if it requires the item. If not required, return nullptr + inline auto check_struct_item_requried(std::string_view item_name, UcesbSource* source) -> R3BReader* + { + return source->FindReaderIf([item_name](R3BReader* reader) + { return reader->MismappedItemRequired(item_name); }); + } + + bool UcesbStructInfo::check_struct_item(ext_data_structure_item* item, UcesbSource* source) + { + auto map_flag = static_cast(item->_map_success); + auto is_match_ok = ((map_flag & ~(map_success_conditions_)) == UcesbMap::zero); + if (is_match_ok) + { + return true; + } + auto* required_reader = check_struct_item_requried(item->_var_name, source); + if (required_reader == nullptr || required_reader->AllowExtraCondition(map_flag, map_success_conditions_)) + { + // no reader requries this item or reader accepts extra flag + return true; + } + + R3BLOG(error, + fmt::format("Failed to map the item {} required from {} due to the map flag: {}", + item->_var_name, + required_reader->GetName(), + map_flag)); + return false; + } + + void UcesbStructInfo::CheckStructMapping(UcesbSource* source) + { + auto* struct_info = static_cast(struct_info_); + auto is_checking_ok = true; + for (auto* item = struct_info->_items; item != nullptr; item = item->_next_off_item) + { + is_checking_ok &= check_struct_item(item, source); + } + + if (not is_checking_ok) + { + terminate(); + } + } + + void UcesbStructInfo::terminate() + { + R3BLOG(error, "ext_data_clnt::setup() failed to map all items:"); + + if (fair::Logger::GetConsoleSeverity() < fair::Severity::info) + { + ext_data_struct_info_print_map_success(static_cast(struct_info_), + stderr, + static_cast(map_success_conditions_)); + } + throw R3B::runtime_error("ext_data_clnt::setup() mapping failure may cause unexpected analysis results " + "due to missing data members. Unpacker needs fixing.\n\n\n"); + } + + // void UcesbStructInfo::check_struct_info_mapping_old(const UcesbMap& is_map_success) + // { + // if ((is_map_success & ~(map_success_conditions_)) != UcesbMap::zero) + // { + // R3BLOG(error, "ext_data_clnt::setup() failed to map all items:"); + // ext_data_struct_info_print_map_success(static_cast(ucesb_client_struct_info_), + // stderr, + // static_cast(map_success_conditions_)); + // throw R3B::runtime_error("ext_data_clnt::setup() mapping failure may cause unexpected analysis results " + // "due to missing data members. Unpacker needs fixing."); + // } + // } +} // namespace R3B diff --git a/r3bsource/base/utils/R3BUcesbStructInfo.h b/r3bsource/base/utils/R3BUcesbStructInfo.h new file mode 100644 index 000000000..e57d5d23e --- /dev/null +++ b/r3bsource/base/utils/R3BUcesbStructInfo.h @@ -0,0 +1,42 @@ +#pragma once + +/****************************************************************************** + * Copyright (C) 2019 GSI Helmholtzzentrum für Schwerionenforschung GmbH * + * Copyright (C) 2019-2023 Members of R3B Collaboration * + * * + * This software is distributed under the terms of the * + * GNU General Public Licence (GPL) version 3, * + * copied verbatim in the file "LICENSE". * + * * + * In applying this license GSI does not waive the privileges and immunities * + * granted to it by virtue of its status as an Intergovernmental Organization * + * or submit itself to any jurisdiction. * + ******************************************************************************/ + +#include "R3BUcesbMappingFlag.h" +#include +#include +#include + +struct ext_data_structure_item; +namespace R3B +{ + class UcesbSource; + class UcesbStructInfo + { + public: + UcesbStructInfo() = default; + auto Get() -> ext_data_struct_info* { return &struct_info_; } + void CheckStructMapping(UcesbSource* source); + void SetExtraMapFlags(UcesbMap extr_flag) { map_success_conditions_ |= extr_flag; } + void SetMapSuccessCondition(UcesbMap condition) { map_success_conditions_ = condition; } + + private: + void terminate(); + bool check_struct_item(ext_data_structure_item* item, UcesbSource* source); + ext_data_struct_info struct_info_; + UcesbMap map_success_conditions_ = UcesbMap::ok; + + // void check_struct_info_mapping_old(const UcesbMap& is_map_success); + }; +} // namespace R3B