diff --git a/.gitignore b/.gitignore index 9ed22840a..e7ce99f16 100644 --- a/.gitignore +++ b/.gitignore @@ -63,3 +63,5 @@ cmake-build*/ src/examples/PodioExample/datamodel/* src/examples/PodioExample/src/* src/examples/PodioExample/podio_generated_files.cmake + +podio_build/ diff --git a/src/examples/PodioExample/DatamodelGlue.h b/src/examples/PodioExample/DatamodelGlue.h index 7dc50f646..e9307f020 100644 --- a/src/examples/PodioExample/DatamodelGlue.h +++ b/src/examples/PodioExample/DatamodelGlue.h @@ -15,7 +15,6 @@ #include #include -#if podio_VERSION < PODIO_VERSION(0, 17, 0) /// Legacy PODIO support template struct PodioTypeMap { @@ -38,7 +37,6 @@ struct PodioTypeMap { using mutable_t = MutableEventInfo; using collection_t = EventInfoCollection; }; -#endif template diff --git a/src/examples/PodioExample/PodioExample.cc b/src/examples/PodioExample/PodioExample.cc index a57b57088..05a642776 100644 --- a/src/examples/PodioExample/PodioExample.cc +++ b/src/examples/PodioExample/PodioExample.cc @@ -26,10 +26,10 @@ void create_hits_file() { eventinfos1.push_back(eventinfo1); ExampleHitCollection hits1; - hits1.push_back(ExampleHit(22, -1, -1, 0, 100)); - hits1.push_back(ExampleHit(49, 1, 1, 0, 15.5)); - hits1.push_back(ExampleHit(47, 1, 2, 0, 0.5)); - hits1.push_back(ExampleHit(42, 2, 1, 0, 4.0)); + hits1.push_back(ExampleHit(22, -1, -1, 0, 100, 0)); + hits1.push_back(ExampleHit(49, 1, 1, 0, 15.5, 0)); + hits1.push_back(ExampleHit(47, 1, 2, 0, 0.5, 0)); + hits1.push_back(ExampleHit(42, 2, 1, 0, 4.0, 0)); podio::Frame event1; event1.put(std::move(hits1), "hits"); @@ -43,10 +43,10 @@ void create_hits_file() { eventinfos2.push_back(eventinfo2); ExampleHitCollection hits2; - hits2.push_back(ExampleHit(42, 5, -5, 5, 7.6)); - hits2.push_back(ExampleHit(618, -3, -5, 1, 99.9)); - hits2.push_back(ExampleHit(27, -10, 10, 10, 22.2)); - hits2.push_back(ExampleHit(28, -9, 11, 10, 7.8)); + hits2.push_back(ExampleHit(42, 5, -5, 5, 7.6, 0)); + hits2.push_back(ExampleHit(618, -3, -5, 1, 99.9, 0)); + hits2.push_back(ExampleHit(27, -10, 10, 10, 22.2, 0)); + hits2.push_back(ExampleHit(28, -9, 11, 10, 7.8, 0)); podio::Frame event2; event2.put(std::move(hits2), "hits"); diff --git a/src/examples/PodioExample/layout.yaml b/src/examples/PodioExample/layout.yaml index 2e831d74e..9c0b65a46 100644 --- a/src/examples/PodioExample/layout.yaml +++ b/src/examples/PodioExample/layout.yaml @@ -26,6 +26,7 @@ datatypes : - double y // y-coordinate - double z // z-coordinate - double energy // measured energy deposit + - uint64_t time // ticks since start of timeframe ExampleCluster : Description : "Cluster" diff --git a/src/examples/TimesliceExample/CMakeLists.txt b/src/examples/TimesliceExample/CMakeLists.txt index 54acd64ae..13b886b0c 100644 --- a/src/examples/TimesliceExample/CMakeLists.txt +++ b/src/examples/TimesliceExample/CMakeLists.txt @@ -3,12 +3,13 @@ if (USE_PODIO) set (TimesliceExample_SOURCES TimesliceExample.cc + CollectionTabulators.cc ) add_library(TimesliceExample SHARED ${TimesliceExample_SOURCES}) - target_link_libraries(TimesliceExample jana2 podio::podio PodioExampleDatamodel PodioExampleDatamodelDict podio::podioRootIO) + target_link_libraries(TimesliceExample PodioExampleDatamodel PodioExampleDatamodelDict podio::podioRootIO) set_target_properties(TimesliceExample PROPERTIES PREFIX "" SUFFIX ".so" OUTPUT_NAME "TimesliceExample") - install(TARGETS TimesliceExample DESTINATION programs) + install(TARGETS TimesliceExample DESTINATION plugins) else() message(STATUS "Skipping examples/TimesliceExample because USE_PODIO=Off") diff --git a/src/examples/TimesliceExample/CollectionTabulators.cc b/src/examples/TimesliceExample/CollectionTabulators.cc new file mode 100644 index 000000000..3b4ee9915 --- /dev/null +++ b/src/examples/TimesliceExample/CollectionTabulators.cc @@ -0,0 +1,41 @@ + +#include "CollectionTabulators.h" + +JTablePrinter TabulateClusters(const ExampleClusterCollection* c) { + + JTablePrinter t; + t.AddColumn("clusterId"); + t.AddColumn("energy"); + t.AddColumn("hits"); + t.AddColumn("clusters"); + + for (auto cluster : *c) { + std::ostringstream oss; + for (auto hit : cluster.Hits()) { + oss << hit.id() << " "; + } + std::ostringstream oss2; + for (auto cluster : cluster.Clusters()) { + oss2 << cluster.id() << " "; + } + t | cluster.id() | cluster.energy() | oss.str() | oss2.str(); + } + return t; +} + + +JTablePrinter TabulateHits(const ExampleHitCollection* c) { + + JTablePrinter t; + t.AddColumn("hitId"); + t.AddColumn("cellId"); + t.AddColumn("x"); + t.AddColumn("y"); + t.AddColumn("energy"); + t.AddColumn("time"); + + for (auto hit : *c) { + t | hit.id() | hit.cellID() | hit.x() | hit.y() | hit.energy() | hit.time(); + } + return t; +} diff --git a/src/examples/TimesliceExample/CollectionTabulators.h b/src/examples/TimesliceExample/CollectionTabulators.h new file mode 100644 index 000000000..d8446fd62 --- /dev/null +++ b/src/examples/TimesliceExample/CollectionTabulators.h @@ -0,0 +1,10 @@ +#pragma once + +#include "DatamodelGlue.h" +#include + +JTablePrinter TabulateClusters(const ExampleClusterCollection* c); + +JTablePrinter TabulateHits(const ExampleHitCollection* c); + + diff --git a/src/examples/TimesliceExample/MyDataModel.h b/src/examples/TimesliceExample/MyDataModel.h deleted file mode 100644 index e2d710750..000000000 --- a/src/examples/TimesliceExample/MyDataModel.h +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2024, Jefferson Science Associates, LLC. -// Subject to the terms in the LICENSE file found in the top-level directory. - -#pragma once - -#include - -struct MyHit : public JObject { - int hit_id; - int energy, x, y; -}; - -struct MyCluster : public JObject { - int cluster_id; - int energy, x, y; - std::vector hits; -}; - diff --git a/src/examples/TimesliceExample/MyEventFactory.h b/src/examples/TimesliceExample/MyEventFactory.h index 37e883f4c..807877e1a 100644 --- a/src/examples/TimesliceExample/MyEventFactory.h +++ b/src/examples/TimesliceExample/MyEventFactory.h @@ -1,38 +1,39 @@ - - - // Copyright 2024, Jefferson Science Associates, LLC. // Subject to the terms in the LICENSE file found in the top-level directory. #pragma once -#include "MyDataModel.h" -#include + +#include #include -struct MyClusterFactory : public JFactoryT { +struct MyEventFactory : public JOmniFactory { - int init_call_count = 0; - int change_run_call_count = 0; - int process_call_count = 0; + PodioInput m_protoclusters_in {this, "evt_protoclusters"}; + PodioOutput m_clusters_out {this, "clusters"}; - MyClusterFactory() { + + MyEventFactory() { SetLevel(JEventLevel::Event); } - void Init() override { - ++init_call_count; + void Configure() { } - void ChangeRun(const std::shared_ptr&) override { - ++change_run_call_count; + void ChangeRun(int32_t /*run_nr*/) { } - void Process(const std::shared_ptr& event) override { - ++process_call_count; + void Execute(int32_t /*run_nr*/, uint64_t /*evt_nr*/) { + + auto cs = std::make_unique(); + + for (auto protocluster : *m_protoclusters_in()) { + auto cluster = MutableExampleCluster(protocluster.energy() + 1000); + cluster.addClusters(protocluster); + cs->push_back(cluster); + } - auto protos = event->Get("protos"); - // TODO: Output something sensible + m_clusters_out() = std::move(cs); } }; diff --git a/src/examples/TimesliceExample/MyEventProcessor.h b/src/examples/TimesliceExample/MyEventProcessor.h index b49e99541..ff6341331 100644 --- a/src/examples/TimesliceExample/MyEventProcessor.h +++ b/src/examples/TimesliceExample/MyEventProcessor.h @@ -3,32 +3,77 @@ // Subject to the terms in the LICENSE file found in the top-level directory. #pragma once -#include "MyDataModel.h" + +#include +#include +#include "CollectionTabulators.h" #include -struct ExampleEventProcessor : public JEventProcessor { +#include + + + +struct MyEventProcessor : public JEventProcessor { + + PodioInput m_ts_hits_in {this, "hits", JEventLevel::Timeslice}; + PodioInput m_ts_protoclusters_in {this, "ts_protoclusters", JEventLevel::Timeslice}; + PodioInput m_evt_protoclusters_in {this, "evt_protoclusters", JEventLevel::Event}; + PodioInput m_evt_clusters_in {this, "clusters", JEventLevel::Event}; + + Input m_evt_frame_in {this, "", JEventLevel::Event}; + Input m_ts_frame_in {this, "", JEventLevel::Timeslice}; + + std::unique_ptr m_writer = nullptr; + std::set m_seen_event_nrs; + int m_expected_timeslice_count; std::mutex m_mutex; - ExampleTimesliceProcessor() { - SetEventLevel(JEvent::Level::Event); + MyEventProcessor() { + SetLevel(JEventLevel::Event); + SetTypeName("MyEventProcessor"); + } + + void Init() { + m_writer = std::make_unique("output.root"); + m_expected_timeslice_count = GetApplication()->GetParameterValue("jana:nevents"); } void Process(const std::shared_ptr& event) { + auto ts_nr = event->GetParent(JEventLevel::Timeslice).GetEventNumber(); + m_seen_event_nrs.insert(event->GetEventNumber()); + std::lock_guard guard(m_mutex); + m_writer->writeFrame(*(m_evt_frame_in().at(0)), "events"); + if (event->GetEventIndex() == 0) { + m_writer->writeFrame(*(m_ts_frame_in().at(0)), "timeslices"); + } + + LOG_DEBUG(GetLogger()) + << "MyEventProcessor: Event " << event->GetEventNumber() << " from Timeslice " << ts_nr + << "\nTimeslice-level hits\n" + << TabulateHits(m_ts_hits_in()) + << "\nTimeslice-level protoclusters\n" + << TabulateClusters(m_ts_protoclusters_in()) + << "\nEvent-level protoclusters\n" + << TabulateClusters(m_evt_protoclusters_in()) + << "\nEvent-level clusters\n" + << TabulateClusters(m_evt_clusters_in()) + << LOG_END; + } + + void Finish() { + m_writer->finish(); + for (int tsnr=0; tsnrGet(); - // assert(outputs.size() == 4); - // assert(outputs[0]->z == 25.6f); - // assert(outputs[1]->z == 26.5f); - // assert(outputs[2]->z == 27.4f); - // assert(outputs[3]->z == 28.3f); - LOG << " Contents of event " << event->GetEventNumber() << LOG_END; - for (auto output : outputs) { - LOG << " " << output->evt << ":" << output->sub << " " << output->z << LOG_END; + if (!m_seen_event_nrs.contains(evtnr)) { + LOG << "MyEventProcessor: Missing event #" << evtnr << LOG_END; + } + } } - LOG << " DONE with contents of event " << event->GetEventNumber() << LOG_END; } }; diff --git a/src/examples/TimesliceExample/MyTimesliceFactory.h b/src/examples/TimesliceExample/MyTimesliceFactory.h index 64dc4a026..4cf4ff767 100644 --- a/src/examples/TimesliceExample/MyTimesliceFactory.h +++ b/src/examples/TimesliceExample/MyTimesliceFactory.h @@ -2,35 +2,35 @@ // Subject to the terms in the LICENSE file found in the top-level directory. #pragma once -#include "MyDataModel.h" +#include #include -#include -struct MyProtoClusterFactory : public JFactoryT { +struct MyTimesliceFactory : public JOmniFactory { - int init_call_count = 0; - int change_run_call_count = 0; - int process_call_count = 0; + PodioInput hits_in {this, "hits"}; + PodioOutput clusters_out {this, "protoclusters"}; - MyProtoClusterFactory() { + MyTimesliceFactory() { SetLevel(JEventLevel::Timeslice); } - void Init() override { - ++init_call_count; + void Configure() { } - void ChangeRun(const std::shared_ptr&) override { - ++change_run_call_count; + void ChangeRun(int32_t /*run_nr*/) { } - void Process(const std::shared_ptr& event) override { - ++process_call_count; + void Execute(int32_t /*run_nr*/, uint64_t /*evt_nr*/) { - auto protos = event->Get("protos"); - // TODO: Output something sensible + auto cs = std::make_unique(); + for (auto hit : *hits_in()) { + auto cluster = MutableExampleCluster(hit.energy()); + cluster.addHits(hit); + cs->push_back(cluster); + } + clusters_out() = std::move(cs); } }; diff --git a/src/examples/TimesliceExample/MyTimesliceSource.h b/src/examples/TimesliceExample/MyTimesliceSource.h index b0aa1b69d..d77cc70ad 100644 --- a/src/examples/TimesliceExample/MyTimesliceSource.h +++ b/src/examples/TimesliceExample/MyTimesliceSource.h @@ -2,39 +2,37 @@ // Subject to the terms in the LICENSE file found in the top-level directory. #pragma once -#include "MyDataModel.h" + +#include #include +#include "CollectionTabulators.h" struct MyTimesliceSource : public JEventSource { - MyTimesliceSource(std::string source_name, JApplication *app) : JEventSource(source_name, app) { + PodioOutput m_hits_out {this, "hits"}; + + MyTimesliceSource() { SetLevel(JEventLevel::Timeslice); + SetTypeName("MyTimesliceSource"); } - static std::string GetDescription() { return "MyTimesliceSource"; } - - std::string GetType(void) const override { return JTypeInfo::demangle(); } - void Open() override { } void GetEvent(std::shared_ptr event) override { - auto evt = event->GetEventNumber(); - std::vector inputs; - inputs.push_back(new MyInput(22,3.6,evt,0)); - inputs.push_back(new MyInput(23,3.5,evt,1)); - inputs.push_back(new MyInput(24,3.4,evt,2)); - inputs.push_back(new MyInput(25,3.3,evt,3)); - inputs.push_back(new MyInput(26,3.2,evt,4)); - event->Insert(inputs); - - auto hits = std::make_unique(); - hits.push_back(ExampleHit(22)); - hits.push_back(ExampleHit(23)); - hits.push_back(ExampleHit(24)); - event->InsertCollection(hits); - - jout << "MyTimesliceSource: Emitting " << event->GetEventNumber() << jendl; + auto ts_nr = event->GetEventNumber(); + auto hits_out = std::make_unique(); + + // ExampleHit(unsigned long long cellID, double x, double y, double z, double energy, std::uint64_t time); + hits_out->push_back(ExampleHit(ts_nr, 0, 22, 22, 22, 0)); + hits_out->push_back(ExampleHit(ts_nr, 0, 49, 49, 49, 1)); + hits_out->push_back(ExampleHit(ts_nr, 0, 7.6, 7.6, 7.6, 2)); + + LOG_DEBUG(GetLogger()) << "MyTimesliceSource: Timeslice " << event->GetEventNumber() << "\n" + << TabulateHits(hits_out.get()) + << LOG_END; + + m_hits_out() = std::move(hits_out); } }; diff --git a/src/examples/TimesliceExample/MyTimesliceUnfolder.h b/src/examples/TimesliceExample/MyTimesliceUnfolder.h index c238db7f5..0efbf2ab0 100644 --- a/src/examples/TimesliceExample/MyTimesliceUnfolder.h +++ b/src/examples/TimesliceExample/MyTimesliceUnfolder.h @@ -2,42 +2,51 @@ // Subject to the terms in the LICENSE file found in the top-level directory. #pragma once -#include "MyDataModel.h" + +#include + #include +#include "CollectionTabulators.h" + +struct MyTimesliceUnfolder : public JEventUnfolder { -struct ExampleTimesliceUnfolder : public JEventUnfolder { + PodioInput m_timeslice_clusters_in {this, "ts_protoclusters", JEventLevel::Timeslice}; + PodioOutput m_event_clusters_out {this, "evt_protoclusters"}; + + size_t next_time_bucket = 0; MyTimesliceUnfolder() { + SetTypeName(NAME_OF_THIS); SetParentLevel(JEventLevel::Timeslice); SetChildLevel(JEventLevel::Event); } - - void Preprocess(const JEvent& parent) const override { - parent->Get("protos"); - } - Result Unfold(const JEvent& parent, JEvent& child, int item) override { - auto protos = parent->Get("protos"); - - child.SetEventNumber(parent.GetEventNumber()*10 + item); - LOG << "Unfolding parent=" << parent.GetEventNumber() << ", child=" << child.GetEventNumber() << ", item=" << item << LOG_END; - - std::vector child_protos; - for (auto proto: protos) { - if (true) { - // TODO: condition - child_protos.push_back(proto); - } - } - child->Insert(child_protos, "event_protos")->SetFactoryFlag(JFactoryFlag::NOT_OBJECT_OWNER); - - if (item == 3) { - jout << "Unfold found item 3, finishing join" << jendl; - return Result::Finished; - } - return Result::KeepGoing; + + Result Unfold(const JEvent& parent, JEvent& child, int child_idx) override { + + auto timeslice_nr = parent.GetEventNumber(); + size_t event_nr = 100*timeslice_nr + child_idx; + child.SetEventNumber(event_nr); + + // For now, a one-to-one relationship between timeslices and events + + auto event_clusters_out = std::make_unique(); + event_clusters_out->setSubsetCollection(true); + event_clusters_out->push_back(m_timeslice_clusters_in()->at(child_idx)); + + LOG_DEBUG(GetLogger()) << "MyTimesliceUnfolder: Timeslice " << parent.GetEventNumber() + << ", Event " << child.GetEventNumber() + << "\nTimeslice clusters in:\n" + << TabulateClusters(m_timeslice_clusters_in()) + << "\nEvent clusters out:\n" + << TabulateClusters(event_clusters_out.get()) + << LOG_END; + + m_event_clusters_out() = std::move(event_clusters_out); + + return (child_idx == 2) ? Result::NextChildNextParent : Result::NextChildKeepParent; } -} +}; diff --git a/src/examples/TimesliceExample/TimesliceExample.cc b/src/examples/TimesliceExample/TimesliceExample.cc index b1acad9ac..4cd48b732 100644 --- a/src/examples/TimesliceExample/TimesliceExample.cc +++ b/src/examples/TimesliceExample/TimesliceExample.cc @@ -8,6 +8,8 @@ #include "MyTimesliceFactory.h" #include "MyEventFactory.h" +#include + #include @@ -16,12 +18,12 @@ void InitPlugin(JApplication *app) { InitJANAPlugin(app); - app->Add(new MyTimesliceSource("Dummy")); + app->Add(new MyTimesliceSource); app->Add(new MyTimesliceUnfolder); app->Add(new MyEventProcessor); - app->Add(new JFactoryGeneratorT()); - app->Add(new JFactoryGeneratorT()); + app->Add(new JOmniFactoryGeneratorT("protoclusterizer", {"hits"}, {"ts_protoclusters"}, app)); + app->Add(new JOmniFactoryGeneratorT("clusterizer", {"evt_protoclusters"}, {"clusters"}, app)); app->SetParameterValue("jana:extended_report", 0); } diff --git a/src/libraries/JANA/CLI/JBenchmarker.h b/src/libraries/JANA/CLI/JBenchmarker.h index f9834fc28..f2dc2d0f5 100644 --- a/src/libraries/JANA/CLI/JBenchmarker.h +++ b/src/libraries/JANA/CLI/JBenchmarker.h @@ -10,7 +10,7 @@ class JBenchmarker { JApplication* m_app; - JLogger m_logger = JLoggingService::logger("JBenchmarker"); + JLogger m_logger; size_t m_min_threads = 1; size_t m_max_threads = 0; diff --git a/src/libraries/JANA/CMakeLists.txt b/src/libraries/JANA/CMakeLists.txt index 2189cccd3..f821484fb 100644 --- a/src/libraries/JANA/CMakeLists.txt +++ b/src/libraries/JANA/CMakeLists.txt @@ -58,6 +58,7 @@ set(JANA2_SOURCES Services/JComponentManager.h Services/JGlobalRootLock.h Services/JLoggingService.h + Services/JLoggingService.cc Services/JParameterManager.cc Services/JParameterManager.h Services/JPluginLoader.cc diff --git a/src/libraries/JANA/Engine/JArrow.h b/src/libraries/JANA/Engine/JArrow.h index 26cd1d0cc..b86a434ca 100644 --- a/src/libraries/JANA/Engine/JArrow.h +++ b/src/libraries/JANA/Engine/JArrow.h @@ -39,13 +39,12 @@ class JArrow { friend class JScheduler; std::vector m_listeners; // Downstream Arrows - friend class JTopologyBuilder; - std::vector m_places; // Will eventually supplant m_listeners, m_chunksize protected: // This is usable by subclasses. - // Note that it has to be injected because JArrow doesn't know about JApplication, etc - JLogger m_logger {JLogger::Level::OFF}; + JLogger m_logger; + friend class JTopologyBuilder; + std::vector m_places; // Will eventually supplant m_listeners, m_chunksize public: bool is_parallel() { return m_is_parallel; } diff --git a/src/libraries/JANA/Engine/JArrowTopology.cc b/src/libraries/JANA/Engine/JArrowTopology.cc index d184f0ca9..e0893f7c8 100644 --- a/src/libraries/JANA/Engine/JArrowTopology.cc +++ b/src/libraries/JANA/Engine/JArrowTopology.cc @@ -19,6 +19,9 @@ JArrowTopology::~JArrowTopology() { for (auto pool : pools) { delete pool; } + if (event_pool != nullptr) { + delete event_pool; + } } diff --git a/src/libraries/JANA/Engine/JArrowTopology.h b/src/libraries/JANA/Engine/JArrowTopology.h index 622d7f4ff..5a65e5a80 100644 --- a/src/libraries/JANA/Engine/JArrowTopology.h +++ b/src/libraries/JANA/Engine/JArrowTopology.h @@ -28,7 +28,7 @@ struct JArrowTopology { // Ensure that ComponentManager stays alive at least as long as JArrowTopology does // Otherwise there is a potential use-after-free when JArrowTopology or JArrowProcessingController access components - JEventPool* event_pool; // TODO: Move into pools eventually + JEventPool* event_pool = nullptr; // TODO: Move into pools eventually JPerfMetrics metrics; std::vector arrows; diff --git a/src/libraries/JANA/Engine/JDebugProcessingController.cc b/src/libraries/JANA/Engine/JDebugProcessingController.cc index 748051db4..795d9eced 100644 --- a/src/libraries/JANA/Engine/JDebugProcessingController.cc +++ b/src/libraries/JANA/Engine/JDebugProcessingController.cc @@ -56,7 +56,6 @@ void JDebugProcessingController::run_worker() { for (JEventProcessor *proc: evt_procs) { proc->DoMap(event); - proc->DoReduce(event); } m_total_events_processed += 1; event->GetFactorySet()->Release(); @@ -72,7 +71,7 @@ void JDebugProcessingController::run_worker() { m_stop_achieved = true; bool finish_achieved = true; for (auto evt_src: evt_srces) { - finish_achieved &= (evt_src->GetStatus() == JEventSource::SourceStatus::Finished); + finish_achieved &= (evt_src->GetStatus() == JEventSource::Status::Finalized); } m_finish_achieved = finish_achieved; diff --git a/src/libraries/JANA/Engine/JEventProcessorArrow.cc b/src/libraries/JANA/Engine/JEventProcessorArrow.cc index c4590c0f8..b4428b97e 100644 --- a/src/libraries/JANA/Engine/JEventProcessorArrow.cc +++ b/src/libraries/JANA/Engine/JEventProcessorArrow.cc @@ -43,7 +43,7 @@ void JEventProcessorArrow::initialize() { LOG_DEBUG(m_logger) << "Initializing arrow '" << get_name() << "'" << LOG_END; for (auto processor : m_processors) { processor->DoInitialize(); - LOG_INFO(m_logger) << "Initialized JEventProcessor '" << processor->GetType() << "'" << LOG_END; + LOG_INFO(m_logger) << "Initialized JEventProcessor '" << processor->GetTypeName() << "'" << LOG_END; } } @@ -51,7 +51,7 @@ void JEventProcessorArrow::finalize() { LOG_DEBUG(m_logger) << "Finalizing arrow '" << get_name() << "'" << LOG_END; for (auto processor : m_processors) { processor->DoFinalize(); - LOG_INFO(m_logger) << "Finalized JEventProcessor '" << processor->GetType() << "'" << LOG_END; + LOG_INFO(m_logger) << "Finalized JEventProcessor '" << processor->GetTypeName() << "'" << LOG_END; } } diff --git a/src/libraries/JANA/Engine/JEventSourceArrow.cc b/src/libraries/JANA/Engine/JEventSourceArrow.cc index a78e8f620..8312890c0 100644 --- a/src/libraries/JANA/Engine/JEventSourceArrow.cc +++ b/src/libraries/JANA/Engine/JEventSourceArrow.cc @@ -9,7 +9,6 @@ #include -using SourceStatus = JEventSource::RETURN_STATUS; JEventSourceArrow::JEventSourceArrow(std::string name, std::vector sources, @@ -62,7 +61,7 @@ void JEventSourceArrow::finalize() { // However, we can't rely on the JEventSources turning themselves off since execution can be externally paused. // Instead we leave everything open until we finalize the whole topology, and finalize remaining event sources then. for (JEventSource* source : m_sources) { - if (source->GetStatus() == JEventSource::SourceStatus::Opened) { + if (source->GetStatus() == JEventSource::Status::Initialized) { LOG_INFO(m_logger) << "Finalizing JEventSource '" << source->GetTypeName() << "' (" << source->GetResourceName() << ")" << LOG_END; source->DoFinalize(); } diff --git a/src/libraries/JANA/Engine/JMailbox.h b/src/libraries/JANA/Engine/JMailbox.h index 521287e77..07fc5b840 100644 --- a/src/libraries/JANA/Engine/JMailbox.h +++ b/src/libraries/JANA/Engine/JMailbox.h @@ -10,6 +10,7 @@ #include #include #include +#include /// JMailbox is a threadsafe event queue designed for communication between Arrows. /// It is different from the standard data structure in the following ways: @@ -38,11 +39,15 @@ class JQueue { size_t m_capacity; size_t m_locations_count; bool m_enable_work_stealing = false; + int m_id = 0; + JLogger m_logger; public: inline size_t get_threshold() { return m_capacity; } inline size_t get_locations_count() { return m_locations_count; } inline bool is_work_stealing_enabled() { return m_enable_work_stealing; } + void set_logger(JLogger logger) { m_logger = logger; } + void set_id(int id) { m_id = id; } inline JQueue(size_t threshold, size_t locations_count, bool enable_work_stealing) @@ -288,6 +293,40 @@ class JMailbox : public JQueue { }; +template <> +inline void JMailbox*>::push_and_unreserve(std::shared_ptr** buffer, size_t count, size_t reserved_count, size_t location_id) { + + auto& mb = m_queues[location_id]; + std::lock_guard lock(mb.mutex); + assert(reserved_count <= mb.reserved_count); + assert(mb.queue.size() + count <= m_capacity); + mb.reserved_count -= reserved_count; + for (size_t i=0; iget()->GetEventNumber() << LOG_END; + mb.queue.push_back(buffer[i]); + buffer[i] = nullptr; + } +} + +template <> +inline size_t JMailbox*>::pop_and_reserve(std::shared_ptr** buffer, size_t min_requested_count, size_t max_requested_count, size_t location_id) { + + auto& mb = m_queues[location_id]; + std::lock_guard lock(mb.mutex); + + if (mb.queue.size() < min_requested_count) return 0; + + auto nitems = std::min(max_requested_count, mb.queue.size()); + mb.reserved_count += nitems; + + for (size_t i=0; iget()->GetEventNumber() << LOG_END; + mb.queue.pop_front(); + } + return nitems; +} + #endif //JANA2_JMAILBOX_H diff --git a/src/libraries/JANA/Engine/JTopologyBuilder.h b/src/libraries/JANA/Engine/JTopologyBuilder.h index d2cb0989d..c79e11b93 100644 --- a/src/libraries/JANA/Engine/JTopologyBuilder.h +++ b/src/libraries/JANA/Engine/JTopologyBuilder.h @@ -34,6 +34,8 @@ class JTopologyBuilder : public JService { int m_affinity = 0; int m_locality = 0; JLogger m_arrow_logger; + JLogger m_queue_logger; + JLogger m_builder_logger; public: @@ -132,13 +134,22 @@ class JTopologyBuilder : public JService { m_limit_total_events_in_flight); m_topology->event_pool->init(); attach_top_level(JEventLevel::Run); - LOG_DEBUG(m_arrow_logger) << "Arrow topology is:\n" << print_topology() << LOG_END; + LOG_DEBUG(m_builder_logger) << "Arrow topology is:\n" << print_topology() << LOG_END; if (m_configure_topology) { m_topology = m_configure_topology(m_topology); - LOG_DEBUG(m_arrow_logger) << "Found custom topology configurator! Modified arrow topology is: \n" << print_topology() << LOG_END; + LOG_DEBUG(m_builder_logger) << "Found custom topology configurator! Modified arrow topology is: \n" << print_topology() << LOG_END; } } + int id=0; + for (auto* queue : m_topology->queues) { + queue->set_logger(m_queue_logger); + queue->set_id(id); + id += 1; + } + for (auto* arrow : m_topology->arrows) { + arrow->set_logger(m_arrow_logger); + } return m_topology; } @@ -185,7 +196,10 @@ class JTopologyBuilder : public JService { "Records a trace of who called each factory. Reduces performance but necessary for plugins such as janadot.") ->SetIsAdvanced(true); - m_arrow_logger = sl->get()->get_logger("JArrow"); + auto m_logging_svc = sl->get(); + m_arrow_logger = m_logging_svc->get_logger("JArrow"); + m_queue_logger = m_logging_svc->get_logger("JQueue"); + m_builder_logger = m_logging_svc->get_logger("JTopologyBuilder"); }; inline std::shared_ptr create_empty() { @@ -347,12 +361,10 @@ class JTopologyBuilder : public JService { auto* src_arrow = new JEventSourceArrow("sources", sources_at_level, queue, pool_at_level); m_topology->arrows.push_back(src_arrow); src_arrow->set_chunksize(m_event_source_chunksize); - src_arrow->set_logger(m_arrow_logger); auto* proc_arrow = new JEventProcessorArrow("processors", queue, nullptr, pool_at_level); m_topology->arrows.push_back(proc_arrow); proc_arrow->set_chunksize(m_event_processor_chunksize); - proc_arrow->set_logger(m_arrow_logger); for (auto proc: procs_at_level) { proc_arrow->add_processor(proc); @@ -373,12 +385,10 @@ class JTopologyBuilder : public JService { auto *src_arrow = new JEventSourceArrow(ss.str()+"Src", sources_at_level, q1, pool_at_level); m_topology->arrows.push_back(src_arrow); src_arrow->set_chunksize(m_event_source_chunksize); - src_arrow->set_logger(m_arrow_logger); auto *map_arrow = new JEventMapArrow(ss.str()+"Map", q1, q2);; m_topology->arrows.push_back(map_arrow); map_arrow->set_chunksize(m_event_source_chunksize); - map_arrow->set_logger(m_arrow_logger); src_arrow->attach(map_arrow); // TODO: We are using q2 temporarily knowing that it will be overwritten in attach_lower_level. @@ -386,14 +396,12 @@ class JTopologyBuilder : public JService { auto *unfold_arrow = new JUnfoldArrow(ss.str()+"Unfold", unfolders_at_level[0], q2, pool_at_level, q2); m_topology->arrows.push_back(unfold_arrow); unfold_arrow->set_chunksize(m_event_source_chunksize); - unfold_arrow->set_logger(m_arrow_logger); map_arrow->attach(unfold_arrow); // child_in, child_out, parent_out auto *fold_arrow = new JFoldArrow(ss.str()+"Fold", current_level, unfolders_at_level[0]->GetChildLevel(), q2, pool_at_level, pool_at_level); // TODO: Support user-provided folders fold_arrow->set_chunksize(m_event_source_chunksize); - fold_arrow->set_logger(m_arrow_logger); bool found_sink = (procs_at_level.size() > 0); attach_lower_level(unfolders_at_level[0]->GetChildLevel(), unfold_arrow, fold_arrow, found_sink); @@ -409,7 +417,6 @@ class JTopologyBuilder : public JService { auto* proc_arrow = new JEventProcessorArrow(ss.str()+"Proc", q3, nullptr, pool_at_level); m_topology->arrows.push_back(proc_arrow); proc_arrow->set_chunksize(m_event_processor_chunksize); - proc_arrow->set_logger(m_arrow_logger); for (auto proc: procs_at_level) { proc_arrow->add_processor(proc); diff --git a/src/libraries/JANA/Engine/JUnfoldArrow.h b/src/libraries/JANA/Engine/JUnfoldArrow.h index 212f6e01d..181a2f989 100644 --- a/src/libraries/JANA/Engine/JUnfoldArrow.h +++ b/src/libraries/JANA/Engine/JUnfoldArrow.h @@ -75,10 +75,13 @@ class JUnfoldArrow : public JArrow { } success = m_child_in.pull(ci); if (! success) { + m_parent_in.push(pi); return false; } success = m_child_out.pull(co); if (! success) { + m_parent_in.push(pi); + m_child_in.push(ci); return false; } return true; @@ -92,6 +95,20 @@ class JUnfoldArrow : public JArrow { return message_count; } + + size_t get_pending() final { + size_t sum = 0; + for (PlaceRefBase* place : m_places) { + sum += place->get_pending(); + } + if (m_parent_event != nullptr) { + sum += 1; + // Handle the case of UnfoldArrow hanging on to a parent + } + return sum; + } + + void execute(JArrowMetrics& metrics, size_t location_id) final { auto start_total_time = std::chrono::steady_clock::now(); @@ -134,7 +151,7 @@ class JUnfoldArrow : public JArrow { LOG_DEBUG(m_logger) << "Unfold succeeded: Parent event = " << m_parent_event->get()->GetEventNumber() << ", child event = " << child->get()->GetEventNumber() << LOG_END; // TODO: We'll need something more complicated for the streaming join case - if (status == JEventUnfolder::Result::Finished) { + if (status == JEventUnfolder::Result::NextChildNextParent || status == JEventUnfolder::Result::KeepChildNextParent) { LOG_DEBUG(m_logger) << "Unfold finished with parent event = " << m_parent_event->get()->GetEventNumber() << LOG_END; m_ready_to_fetch_parent = true; m_parent_event->get()->Release(); diff --git a/src/libraries/JANA/JApplication.cc b/src/libraries/JANA/JApplication.cc index bd325beee..923335a1f 100644 --- a/src/libraries/JANA/JApplication.cc +++ b/src/libraries/JANA/JApplication.cc @@ -21,6 +21,21 @@ JApplication *japp = nullptr; +JApplication::JApplication(JLogger::Level verbosity) { + m_params = std::make_shared(); + m_params->SetParameter("log:global", verbosity); + m_service_locator.provide(m_params); + m_service_locator.provide(std::make_shared()); + m_service_locator.provide(std::make_shared(this)); + m_service_locator.provide(std::make_shared(this)); + m_service_locator.provide(std::make_shared()); + m_service_locator.provide(std::make_shared()); + + m_plugin_loader = m_service_locator.get(); + m_component_manager = m_service_locator.get(); + m_logger = m_service_locator.get()->get_logger("JApplication"); + m_logger.show_classname = false; +} JApplication::JApplication(JParameterManager* params) { @@ -124,7 +139,6 @@ void JApplication::Initialize() { m_params->SetDefaultParameter("jana:extended_report", m_extended_report, "Controls whether the ticker shows simple vs detailed performance metrics"); m_component_manager->initialize(); - m_component_manager->resolve_event_sources(); int engine_choice = 0; m_params->SetDefaultParameter("jana:engine", engine_choice, @@ -192,7 +206,7 @@ void JApplication::Run(bool wait_until_finished) { if (!m_draining_queues) { bool draining = true; for (auto evt_src : m_component_manager->get_evt_srces()) { - draining &= (evt_src->GetStatus() == JEventSource::SourceStatus::Finished); + draining &= (evt_src->GetStatus() == JEventSource::Status::Finalized); } m_draining_queues = draining; } diff --git a/src/libraries/JANA/JApplication.h b/src/libraries/JANA/JApplication.h index b2f6e7f47..16a76dcf2 100644 --- a/src/libraries/JANA/JApplication.h +++ b/src/libraries/JANA/JApplication.h @@ -49,6 +49,7 @@ class JApplication { enum class ExitCode {Success=0, UnhandledException, Timeout, Segfault=139}; explicit JApplication(JParameterManager* params = nullptr); + explicit JApplication(JLogger::Level verbosity); ~JApplication(); diff --git a/src/libraries/JANA/JCsvWriter.h b/src/libraries/JANA/JCsvWriter.h index f16f007c0..de6d7f677 100644 --- a/src/libraries/JANA/JCsvWriter.h +++ b/src/libraries/JANA/JCsvWriter.h @@ -78,11 +78,6 @@ class JCsvWriter : public JEventProcessor { m_dest_file.close(); } - std::string GetType() const override { - return JTypeInfo::demangle(); - } - - }; diff --git a/src/libraries/JANA/JEvent.h b/src/libraries/JANA/JEvent.h index 148dedb96..1662732d2 100644 --- a/src/libraries/JANA/JEvent.h +++ b/src/libraries/JANA/JEvent.h @@ -102,8 +102,8 @@ class JEvent : public JResettable, public std::enable_shared_from_this // PODIO #ifdef JANA2_HAVE_PODIO std::vector GetAllCollectionNames() const; - const podio::CollectionBase* GetCollectionBase(std::string name) const; - template const typename JFactoryPodioT::CollectionT* GetCollection(std::string name) const; + const podio::CollectionBase* GetCollectionBase(std::string name, bool throw_on_missing=true) const; + template const typename JFactoryPodioT::CollectionT* GetCollection(std::string name, bool throw_on_missing=true) const; template JFactoryPodioT* InsertCollection(typename JFactoryPodioT::CollectionT&& collection, std::string name); template JFactoryPodioT* InsertCollectionAlreadyInFrame(const typename JFactoryPodioT::CollectionT* collection, std::string name); #endif @@ -131,6 +131,8 @@ class JEvent : public JResettable, public std::enable_shared_from_this // Hierarchical JEventLevel GetLevel() const { return mFactorySet->GetLevel(); } void SetLevel(JEventLevel level) { mFactorySet->SetLevel(level); } + void SetEventIndex(int event_index) { mEventIndex = event_index; } + int64_t GetEventIndex() const { return mEventIndex; } const JEvent& GetParent(JEventLevel level) const { for (const auto& pair : mParents) { @@ -196,7 +198,8 @@ class JEvent : public JResettable, public std::enable_shared_from_this // Hierarchical stuff std::vector*>> mParents; - std::atomic_size_t mReferenceCount {1}; + std::atomic_int mReferenceCount {1}; + int64_t mEventIndex = -1; @@ -221,6 +224,7 @@ inline JFactoryT* JEvent::Insert(T* item, const std::string& tag) const { if (factory == nullptr) { factory = new JFactoryT; factory->SetTag(tag); + factory->SetLevel(mFactorySet->GetLevel()); mFactorySet->Add(factory); } factory->Insert(item); @@ -240,6 +244,7 @@ inline JFactoryT* JEvent::Insert(const std::vector& items, const std::str if (factory == nullptr) { factory = new JFactoryT; factory->SetTag(tag); + factory->SetLevel(mFactorySet->GetLevel()); mFactorySet->Add(factory); } for (T* item : items) { @@ -500,10 +505,15 @@ inline std::vector JEvent::GetAllCollectionNames() const { return keys; } -inline const podio::CollectionBase* JEvent::GetCollectionBase(std::string name) const { +inline const podio::CollectionBase* JEvent::GetCollectionBase(std::string name, bool throw_on_missing) const { auto it = mPodioFactories.find(name); if (it == mPodioFactories.end()) { - throw JException("No factory with tag '%s' found", name.c_str()); + if (throw_on_missing) { + throw JException("No factory with tag '%s' found", name.c_str()); + } + else { + return nullptr; + } } JFactoryPodio* factory = dynamic_cast(it->second); if (factory == nullptr) { @@ -517,8 +527,11 @@ inline const podio::CollectionBase* JEvent::GetCollectionBase(std::string name) } template -const typename JFactoryPodioT::CollectionT* JEvent::GetCollection(std::string name) const { - JFactoryT* factory = GetFactory(name, true); +const typename JFactoryPodioT::CollectionT* JEvent::GetCollection(std::string name, bool throw_on_missing) const { + JFactoryT* factory = GetFactory(name, throw_on_missing); + if (factory == nullptr) { + return nullptr; + } JFactoryPodioT* typed_factory = dynamic_cast*>(factory); if (typed_factory == nullptr) { throw JException("Factory must inherit from JFactoryPodioT in order to use JEvent::GetCollection()"); @@ -556,6 +569,7 @@ JFactoryPodioT* JEvent::InsertCollectionAlreadyInFrame(const typename JFactor if (factory == nullptr) { factory = new JFactoryPodioT(); factory->SetTag(name); + factory->SetLevel(GetLevel()); mFactorySet->Add(factory); auto it = mPodioFactories.find(name); @@ -569,7 +583,7 @@ JFactoryPodioT* JEvent::InsertCollectionAlreadyInFrame(const typename JFactor if (factory->GetStatus() == JFactory::Status::Inserted || factory->GetStatus() == JFactory::Status::Processed) { - throw JException("PODIO collections can only be inserted once, but factory already has data"); + throw JException("PODIO collections can only be inserted once, but factory with tag '%s' already has data", name.c_str()); } // There's a chance that some user already added to the event's JFactorySet a diff --git a/src/libraries/JANA/JEventProcessor.h b/src/libraries/JANA/JEventProcessor.h index e31e97c7e..fa5fa4fe2 100644 --- a/src/libraries/JANA/JEventProcessor.h +++ b/src/libraries/JANA/JEventProcessor.h @@ -5,169 +5,183 @@ #ifndef _JEventProcessor_h_ #define _JEventProcessor_h_ +#include +#include +#include #include -#include -#include -#include class JApplication; -class JEventProcessor { +class JEventProcessor : public jana::omni::JComponent, + public jana::omni::JHasRunCallbacks, + public jana::omni::JHasInputs { public: - explicit JEventProcessor(JApplication* app = nullptr) - : mApplication(app) - , m_status(Status::Unopened) - , m_event_count{0} - {} - + JEventProcessor() = default; virtual ~JEventProcessor() = default; - enum class Status { Unopened, Opened, Finished }; - - Status GetStatus() const { return m_status; } - - std::string GetPluginName() const { return m_plugin_name; } + // TODO: Deprecate + explicit JEventProcessor(JApplication* app) { + m_app = app; + } - std::string GetTypeName() const { return m_type_name; } std::string GetResourceName() const { return m_resource_name; } uint64_t GetEventCount() const { return m_event_count; }; - JApplication* GetApplication() const { return mApplication; } - bool AreEventsOrdered() const { return m_receive_events_in_order; } virtual void DoInitialize() { try { - std::call_once(m_init_flag, &JEventProcessor::Init, this); - m_status = Status::Opened; + for (auto* parameter : m_parameters) { + parameter->Configure(*(m_app->GetJParameterManager()), m_prefix); + } + for (auto* service : m_services) { + service->Init(m_app); + } + Init(); + m_status = Status::Initialized; } catch (JException& ex) { ex.plugin_name = m_plugin_name; - ex.component_name = GetType(); + ex.component_name = m_type_name; throw ex; } catch (...) { auto ex = JException("Unknown exception in JEventProcessor::Open()"); ex.nested_exception = std::current_exception(); ex.plugin_name = m_plugin_name; - ex.component_name = GetType(); + ex.component_name = m_type_name; throw ex; } } - // TODO: Improve this type signature virtual void DoMap(const std::shared_ptr& e) { + + for (auto* input : m_inputs) { + input->PrefetchCollection(*e); + } + // JExceptions with factory info will be furnished by the callee, + // so we don't need to try/catch here. + + // Also we don't have + // a Preprocess(), so we don't technically need Init() here even + + if (m_callback_style != CallbackStyle::Declarative) { + DoReduce(e); // This does all the locking! + } + } + + + virtual void DoReduce(const std::shared_ptr& e) { try { - std::call_once(m_init_flag, &JEventProcessor::DoInitialize, this); auto run_number = e->GetRunNumber(); - { - std::lock_guard lock(m_mutex); - if (m_last_run_number != run_number) { - if (m_last_run_number != -1) { - EndRun(); - } - m_last_run_number = run_number; - BeginRun(e); + std::lock_guard lock(m_mutex); + + if (m_status == Status::Uninitialized) { + DoInitialize(); + } + else if (m_status == Status::Finalized) { + throw JException("JEventProcessor: Attempted to call DoMap() after Finalize()"); + } + if (m_last_run_number != run_number) { + if (m_last_run_number != -1) { + EndRun(); + } + for (auto* resource : m_resources) { + resource->ChangeRun(e->GetRunNumber(), m_app); } + m_last_run_number = run_number; + BeginRun(e); + } + for (auto* input : m_inputs) { + input->GetCollection(*e); + } + if (m_callback_style == CallbackStyle::Declarative) { + Process(e->GetRunNumber(), e->GetEventNumber(), e->GetEventIndex()); + } + else { + Process(e); } - Process(e); m_event_count += 1; } catch (JException& ex) { ex.plugin_name = m_plugin_name; - ex.component_name = GetType(); + ex.component_name = m_type_name; throw ex; } catch (std::exception& e) { auto ex = JException(e.what()); ex.nested_exception = std::current_exception(); ex.plugin_name = m_plugin_name; - ex.component_name = GetType(); + ex.component_name = m_type_name; throw ex; } catch (...) { - auto ex = JException("Unknown exception in JEventProcessor::DoMap()"); + auto ex = JException("Unknown exception in JEventProcessor::DoReduce()"); ex.nested_exception = std::current_exception(); ex.plugin_name = m_plugin_name; - ex.component_name = GetType(); + ex.component_name = m_type_name; throw ex; } } - // Reduce does nothing in the basic version because the current API tells - // the user to lock a mutex in Process(), which takes care of it for us. - virtual void DoReduce(const std::shared_ptr&) {} - - virtual void DoFinalize() { try { std::lock_guard lock(m_mutex); - if (m_status != Status::Finished) { + if (m_status != Status::Finalized) { if (m_last_run_number != -1) { EndRun(); } Finish(); - m_status = Status::Finished; + m_status = Status::Finalized; } } catch (JException& ex) { ex.plugin_name = m_plugin_name; - ex.component_name = GetType(); + ex.component_name = m_type_name; throw ex; } catch (...) { auto ex = JException("Unknown exception in JEventProcessor::Finish()"); ex.nested_exception = std::current_exception(); ex.plugin_name = m_plugin_name; - ex.component_name = GetType(); + ex.component_name = m_type_name; throw ex; } } - // TODO: Make these protected? - /// JEventProcessor::Init, Process, and Finish are meant to be written by the user. - /// Each JEventProcessor is intended to generate one distinct output, virtual void Init() {} - virtual void BeginRun(const std::shared_ptr&) {} virtual void Process(const std::shared_ptr& /*event*/) { throw JException("Not implemented yet!"); } - virtual void EndRun() {} + + virtual void Process(int64_t /*run_nr*/, uint64_t /*event_nr*/, uint64_t /*event_idx*/) { + throw JException("Not implemented yet!"); + } + virtual void Finish() {} - // TODO: Can we please deprecate this in favor of GetTypeName? + // TODO: Deprecate virtual std::string GetType() const { return m_type_name; } - // Meant to be called by JANA - JEventLevel GetLevel() { return m_level; } - - protected: // The following are meant to be called by the user from the constructor in order to // configure their JEventProcessor instance. - /// SetTypeName is intended as a replacement to GetType(), which should be less confusing for the - /// user. It should be called from the constructor. For convenience, we provide a - /// NAME_OF_THIS macro so that the user doesn't have to type the class name as a string, which may - /// get out of sync if automatic refactoring tools are used. - - void SetTypeName(std::string type_name) { m_type_name = std::move(type_name); } - /// Resource name lets the user tell the parallelization engine to synchronize different EventProcessors /// which write to the same shared resource; e.g. if you have two EventProcessors /// which both write to a ROOT tree, they should both set the resource name 'ROOT'. On the flip side, @@ -177,47 +191,21 @@ class JEventProcessor { /// assume that you are manually synchronizing access via your own mutex, which will be safe if and only /// if you use your locks correctly, and also may result in a performance penalty. - void SetResourceName(std::string resource_name) { m_resource_name = std::move(resource_name); } + // void SetResourceName(std::string resource_name) { m_resource_name = std::move(resource_name); } /// SetEventsOrdered allows the user to tell the parallelization engine that it needs to see /// the event stream ordered by increasing event IDs. (Note that this requires all EventSources /// emit event IDs which are consecutive.) Ordering by event ID makes for cleaner output, but comes /// with a performance penalty, so it is best if this is enabled during debugging, and disabled otherwise. - void SetEventsOrdered(bool receive_events_in_order) { m_receive_events_in_order = receive_events_in_order; } - - // Meant to be called by user in constructor - void SetLevel(JEventLevel level) { m_level = level; } - + // void SetEventsOrdered(bool receive_events_in_order) { m_receive_events_in_order = receive_events_in_order; } private: - // Common to components - JEventLevel m_level = JEventLevel::Event; - JApplication* mApplication = nullptr; - Status m_status; - std::string m_plugin_name; - std::string m_type_name; - std::once_flag m_init_flag; - std::once_flag m_finish_flag; - std::mutex m_mutex; - - // JEventProcessor-specific std::string m_resource_name; - std::atomic_ullong m_event_count; - int32_t m_last_run_number = -1; + std::atomic_ullong m_event_count {0}; bool m_receive_events_in_order = false; - - /// This is called by JApplication::Add(JEventProcessor*). There - /// should be no need to call it from anywhere else. - void SetJApplication(JApplication* app) { mApplication = app; } - - friend JComponentManager; - - /// SetPluginName is called by ComponentManager and should not be exposed to the user. - void SetPluginName(std::string plugin_name) { m_plugin_name = std::move(plugin_name); }; - }; #endif // _JEventProcessor_h_ diff --git a/src/libraries/JANA/JEventSource.h b/src/libraries/JANA/JEventSource.h index 08881be00..89e15d83d 100644 --- a/src/libraries/JANA/JEventSource.h +++ b/src/libraries/JANA/JEventSource.h @@ -6,47 +6,42 @@ #ifndef _JEventSource_h_ #define _JEventSource_h_ -#include -#include -#include +#include +#include #include +#include #include -#include -#include -#include -#include class JFactoryGenerator; class JApplication; class JFactory; -class JEventSource { +class JEventSource : public jana::omni::JComponent, public jana::omni::JHasOutputs { public: - /// SourceStatus describes the current state of the EventSource - enum class SourceStatus { Unopened, Opened, Finished }; - /// ReturnStatus describes what happened the last time a GetEvent() was attempted. /// If GetEvent() reaches an error state, it should throw a JException instead. enum class ReturnStatus { Success, TryAgain, Finished }; + // TODO: Deprecate me! /// The user is supposed to _throw_ RETURN_STATUS::kNO_MORE_EVENTS or kBUSY from GetEvent() enum class RETURN_STATUS { kSUCCESS, kNO_MORE_EVENTS, kBUSY, kTRY_AGAIN, kERROR, kUNKNOWN }; // Constructor - + // TODO: Deprecate me! explicit JEventSource(std::string resource_name, JApplication* app = nullptr) - : m_application(app) - , m_status(SourceStatus::Unopened) - , m_resource_name(std::move(resource_name)) + : m_resource_name(std::move(resource_name)) , m_factory_generator(nullptr) , m_event_count{0} - {} + { + m_app = app; + } + JEventSource() = default; virtual ~JEventSource() = default; @@ -111,46 +106,72 @@ class JEventSource { // Wrappers for calling Open and GetEvent in a safe way - virtual void DoInitialize() { + virtual void DoInitialize(bool with_lock=true) { try { - std::call_once(m_init_flag, &JEventSource::Open, this); - m_status = SourceStatus::Opened; + if (with_lock) { + std::lock_guard lock(m_mutex); + if (m_status == Status::Uninitialized) { + Open(); + m_status = Status::Initialized; + } + } + else { + if (m_status == Status::Uninitialized) { + Open(); + m_status = Status::Initialized; + } + } } catch (JException& ex) { ex.plugin_name = m_plugin_name; - ex.component_name = GetType(); + ex.component_name = m_type_name; throw ex; } - catch (std::runtime_error& e){ - throw(JException(e.what())); + catch (std::exception& e){ + auto ex = JException("Exception in JEventSource::Open(): %s", e.what()); + ex.nested_exception = std::current_exception(); + ex.plugin_name = m_plugin_name; + ex.component_name = m_type_name; + throw ex; } catch (...) { auto ex = JException("Unknown exception in JEventSource::Open()"); ex.nested_exception = std::current_exception(); ex.plugin_name = m_plugin_name; - ex.component_name = GetType(); + ex.component_name = m_type_name; throw ex; } } - virtual void DoFinalize() { + virtual void DoFinalize(bool with_lock=true) { try { - std::call_once(m_close_flag, &JEventSource::Close, this); - m_status = SourceStatus::Finished; + if (with_lock) { + std::lock_guard lock(m_mutex); + Close(); + m_status = Status::Finalized; + } + else { + Close(); + m_status = Status::Finalized; + } } catch (JException& ex) { ex.plugin_name = m_plugin_name; - ex.component_name = GetType(); + ex.component_name = m_type_name; throw ex; } - catch (std::runtime_error& e){ - throw(JException(e.what())); + catch (std::exception& e){ + auto ex = JException("Exception in JEventSource::Close(): %s", e.what()); + ex.nested_exception = std::current_exception(); + ex.plugin_name = m_plugin_name; + ex.component_name = m_type_name; + throw ex; } catch (...) { auto ex = JException("Unknown exception in JEventSource::Close()"); ex.nested_exception = std::current_exception(); ex.plugin_name = m_plugin_name; - ex.component_name = GetType(); + ex.component_name = m_type_name; throw ex; } } @@ -162,11 +183,10 @@ class JEventSource { auto last_evt_nr = m_nevents + m_nskip; try { - if (m_status == SourceStatus::Unopened) { - DoInitialize(); - m_status = SourceStatus::Opened; + if (m_status == Status::Uninitialized) { + DoInitialize(false); } - if (m_status == SourceStatus::Opened) { + if (m_status == Status::Initialized) { if (m_event_count < first_evt_nr) { // Skip these events due to nskip event->SetEventNumber(m_event_count); // Default event number to event count @@ -177,13 +197,13 @@ class JEventSource { return ReturnStatus::TryAgain; // Reject this event and recycle it } else if (m_nevents != 0 && (m_event_count == last_evt_nr)) { // Declare ourselves finished due to nevents - DoFinalize(); // Close out the event source as soon as it declares itself finished + DoFinalize(false); // Close out the event source as soon as it declares itself finished return ReturnStatus::Finished; } else { // Actually emit an event. // GetEvent() expects the following things from its incoming JEvent event->SetEventNumber(m_event_count); - event->SetJApplication(m_application); + event->SetJApplication(m_app); event->SetJEventSource(this); event->SetSequential(false); event->GetJCallGraphRecorder()->Reset(); @@ -197,11 +217,14 @@ class JEventSource { } auto previous_origin = event->GetJCallGraphRecorder()->SetInsertDataOrigin( JCallGraphRecorder::ORIGIN_FROM_SOURCE); // (see note at top of JCallGraphRecorder.h) GetEvent(event); + for (auto* output : m_outputs) { + output->InsertCollection(*event); + } event->GetJCallGraphRecorder()->SetInsertDataOrigin( previous_origin ); m_event_count += 1; return ReturnStatus::Success; // Don't reject this event! } - } else if (m_status == SourceStatus::Finished) { + } else if (m_status == Status::Finalized) { return ReturnStatus::Finished; } else { throw JException("Invalid ReturnStatus"); @@ -210,7 +233,7 @@ class JEventSource { catch (RETURN_STATUS rs) { if (rs == RETURN_STATUS::kNO_MORE_EVENTS) { - DoFinalize(); + DoFinalize(false); return ReturnStatus::Finished; } else if (rs == RETURN_STATUS::kTRY_AGAIN || rs == RETURN_STATUS::kBUSY) { @@ -219,7 +242,7 @@ class JEventSource { else if (rs == RETURN_STATUS::kERROR || rs == RETURN_STATUS::kUNKNOWN) { JException ex ("JEventSource threw RETURN_STATUS::kERROR or kUNKNOWN"); ex.plugin_name = m_plugin_name; - ex.component_name = GetType(); + ex.component_name = m_type_name; throw ex; } else { @@ -228,17 +251,21 @@ class JEventSource { } catch (JException& ex) { ex.plugin_name = m_plugin_name; - ex.component_name = GetType(); + ex.component_name = m_type_name; throw ex; } - catch (std::runtime_error& e){ - throw(JException(e.what())); + catch (std::exception& e){ + auto ex = JException("Exception in JEventSource::GetEvent(): %s", e.what()); + ex.nested_exception = std::current_exception(); + ex.plugin_name = m_plugin_name; + ex.component_name = m_type_name; + throw ex; } catch (...) { auto ex = JException("Unknown exception in JEventSource::GetEvent()"); ex.nested_exception = std::current_exception(); ex.plugin_name = m_plugin_name; - ex.component_name = GetType(); + ex.component_name = m_type_name; throw ex; } } @@ -256,23 +283,20 @@ class JEventSource { // Getters and setters - - SourceStatus GetStatus() const { return m_status; } - - std::string GetPluginName() const { return m_plugin_name; } - - std::string GetTypeName() const { return m_type_name; } + + void SetResourceName(std::string resource_name) { m_resource_name = resource_name; } std::string GetResourceName() const { return m_resource_name; } uint64_t GetEventCount() const { return m_event_count; }; - JApplication* GetApplication() const { return m_application; } - + // TODO: Deprecate me virtual std::string GetType() const { return m_type_name; } + // TODO: Deprecate me std::string GetName() const { return m_resource_name; } + // TODO: Deprecate me virtual std::string GetVDescription() const { return ""; } ///< Optional for getting description via source rather than JEventSourceGenerator @@ -283,15 +307,6 @@ class JEventSource { uint64_t GetNSkip() { return m_nskip; } uint64_t GetNEvents() { return m_nevents; } - - /// SetTypeName is intended as a replacement to GetType(), which should be less confusing for the - /// user. It should be called from the constructor. For convenience, we provide a - /// NAME_OF_THIS macro so that the user doesn't have to type the class name as a string, which may - /// get out of sync if automatic refactoring tools are used. - - // Meant to be called by user - void SetTypeName(std::string type_name) { m_type_name = std::move(type_name); } - // Meant to be called by user /// SetFactoryGenerator allows us to override the set of factories. This is void SetFactoryGenerator(JFactoryGenerator* generator) { m_factory_generator = generator; } @@ -304,18 +319,6 @@ class JEventSource { /// which will hurt performance. Conceptually, FinishEvent isn't great, and so should be avoided when possible. void EnableFinishEvent() { m_enable_free_event = true; } - // Meant to be called by user in constructor - void SetLevel(JEventLevel level) { m_level = level; } - - // Meant to be called by JANA - JEventLevel GetLevel() { return m_level; } - - // Meant to be called by JANA - void SetApplication(JApplication* app) { m_application = app; } - - // Meant to be called by JANA - void SetPluginName(std::string plugin_name) { m_plugin_name = std::move(plugin_name); }; - // Meant to be called by JANA void SetNEvents(uint64_t nevents) { m_nevents = nevents; }; @@ -324,17 +327,6 @@ class JEventSource { private: - // Common to all components - JEventLevel m_level = JEventLevel::Event; - JApplication* m_application = nullptr; - std::atomic m_status; - std::string m_plugin_name; - std::string m_type_name; - std::once_flag m_init_flag; - std::once_flag m_close_flag; - std::mutex m_mutex; - - // JEventSource-specific std::string m_resource_name; JFactoryGenerator* m_factory_generator = nullptr; std::atomic_ullong m_event_count {0}; diff --git a/src/libraries/JANA/JEventUnfolder.h b/src/libraries/JANA/JEventUnfolder.h index 7224f73ef..abdfd0c13 100644 --- a/src/libraries/JANA/JEventUnfolder.h +++ b/src/libraries/JANA/JEventUnfolder.h @@ -3,29 +3,23 @@ #pragma once -#include +#include +#include +#include +#include #include -#include class JApplication; -class JEventUnfolder { +class JEventUnfolder : public jana::omni::JComponent, + public jana::omni::JHasRunCallbacks, + public jana::omni::JHasInputs, + public jana::omni::JHasOutputs { private: - // Common to components... factor this out someday - - JEventLevel m_level = JEventLevel::Event; - JApplication* m_application = nullptr; - std::string m_plugin_name; - std::string m_type_name; - std::mutex m_mutex; int32_t m_last_run_number = -1; - enum class Status { Uninitialized, Initialized, Finalized }; - Status m_status = Status::Uninitialized; - - // JEventUnfolder-specific - // + bool m_enable_simplified_callbacks = false; JEventLevel m_child_level; - int m_per_timeslice_event_count = 0; + int m_child_number = 0; bool m_call_preprocess_upstream = true; @@ -34,17 +28,19 @@ class JEventUnfolder { virtual ~JEventUnfolder() {}; - enum class Result { KeepGoing, Finished }; + enum class Result { NextChildNextParent, NextChildKeepParent, KeepChildNextParent }; virtual void Init() {}; - - virtual void ChangeRun(const JEvent&) {}; - + virtual void Preprocess(const JEvent& /*parent*/) const {}; - virtual Result Unfold(const JEvent& parent, JEvent& child, int item) = 0; + virtual Result Unfold(const JEvent& /*parent*/, JEvent& /*child*/, int /*item_nr*/) { + throw JException("Not implemented yet!"); + }; - virtual void EndRun() {}; + virtual Result Unfold(uint64_t /*parent_nr*/, uint64_t /*child_nr*/, int /*item_nr*/) { + throw JException("Not implemented yet!"); + }; virtual void Finish() {}; @@ -60,42 +56,20 @@ class JEventUnfolder { JEventLevel GetChildLevel() { return m_child_level; } - // Component setters (set by user) - - void SetTypeName(std::string type_name) { m_type_name = std::move(type_name); } - - void SetLevel(JEventLevel level) { m_level = level; } - - - // Component getters - - JEventLevel GetLevel() { return m_level; } - - JApplication* GetApplication() const { return m_application; } - - std::string GetPluginName() const { return m_plugin_name; } - - std::string GetTypeName() const { return m_type_name; } - - - private: - // Component setters (set by JANA) - - friend JComponentManager; - - friend JApplication; - - void SetApplication(JApplication* app) { m_application = app; } - - void SetPluginName(std::string plugin_name) { m_plugin_name = std::move(plugin_name); }; - - public: // Backend void DoInit() { try { std::lock_guard lock(m_mutex); + // TODO: Obtain overrides of collection names from param manager + + for (auto* parameter : m_parameters) { + parameter->Configure(*(m_app->GetJParameterManager()), m_prefix); + } + for (auto* service : m_services) { + service->Init(m_app); + } if (m_status == Status::Uninitialized) { Init(); m_status = Status::Initialized; @@ -110,7 +84,7 @@ class JEventUnfolder { throw ex; } catch (...) { - auto ex = JException("JEventUnfolder: Unknown exception in JEventUnfolder::Init()"); + auto ex = JException("JEventUnfolder: Exception in Init()"); ex.nested_exception = std::current_exception(); ex.plugin_name = m_plugin_name; ex.component_name = m_type_name; @@ -120,17 +94,25 @@ class JEventUnfolder { void DoPreprocess(const JEvent& parent) { try { - std::lock_guard lock(m_mutex); - if (m_status == Status::Initialized) { - Preprocess(parent); + { + std::lock_guard lock(m_mutex); + if (m_status != Status::Initialized) { + throw JException("JEventUnfolder: Component needs to be initialized and not finalized before Unfold can be called"); + // TODO: Consider calling Initialize(with_lock=false) like we do elsewhere + } } - else { - throw JException("JEventUnfolder: Component needs to be initialized and not finalized before Unfold can be called"); + for (auto* input : m_inputs) { + input->PrefetchCollection(parent); + } + if (m_callback_style != CallbackStyle::Declarative) { + Preprocess(parent); } } catch (JException& ex) { ex.plugin_name = m_plugin_name; - ex.component_name = m_type_name; + if (ex.component_name.empty()) { + ex.component_name = m_type_name; + } throw ex; } catch (...) { @@ -147,16 +129,45 @@ class JEventUnfolder { std::lock_guard lock(m_mutex); if (m_status == Status::Initialized) { if (!m_call_preprocess_upstream) { - Preprocess(parent); + if (!m_enable_simplified_callbacks) { + Preprocess(parent); + } } if (m_last_run_number != parent.GetRunNumber()) { - ChangeRun(parent); + for (auto* resource : m_resources) { + resource->ChangeRun(parent.GetRunNumber(), m_app); + } + if (m_callback_style == CallbackStyle::Declarative) { + ChangeRun(parent.GetRunNumber()); + } + else { + ChangeRun(parent); + } m_last_run_number = parent.GetRunNumber(); } - Result result = Unfold(parent, child, m_per_timeslice_event_count); - m_per_timeslice_event_count += 1; - if (result == Result::Finished) { - m_per_timeslice_event_count = 0; + for (auto* input : m_inputs) { + input->GetCollection(parent); + // TODO: This requires that all inputs come from the parent. + // However, eventually we will want to support inputs + // that come from the child. + } + for (auto* output : m_outputs) { + output->Reset(); + } + Result result; + child.SetEventIndex(m_child_number); + if (m_enable_simplified_callbacks) { + result = Unfold(parent.GetEventNumber(), child.GetEventNumber(), m_child_number); + } + else { + result = Unfold(parent, child, m_child_number); + } + for (auto* output : m_outputs) { + output->InsertCollection(child); + } + m_child_number += 1; + if (result == Result::NextChildNextParent || result == Result::KeepChildNextParent) { + m_child_number = 0; } return result; } @@ -166,11 +177,13 @@ class JEventUnfolder { } catch (JException& ex) { ex.plugin_name = m_plugin_name; - ex.component_name = m_type_name; + if (ex.component_name.empty()) { + ex.component_name = m_type_name; + } throw ex; } catch (...) { - auto ex = JException("Unknown exception in JEventUnfolder::DoUnfold()"); + auto ex = JException("Exception in JEventUnfolder::DoUnfold()"); ex.nested_exception = std::current_exception(); ex.plugin_name = m_plugin_name; ex.component_name = m_type_name; diff --git a/src/libraries/JANA/JFactory.cc b/src/libraries/JANA/JFactory.cc index 8d9f13635..1366d92ce 100644 --- a/src/libraries/JANA/JFactory.cc +++ b/src/libraries/JANA/JFactory.cc @@ -18,8 +18,10 @@ void JFactory::Create(const std::shared_ptr& event) { mStatus = Status::Unprocessed; } catch (JException& ex) { - ex.plugin_name = mPluginName; - ex.component_name = mFactoryName; + if (ex.plugin_name.empty()) ex.plugin_name = mPluginName; + if (ex.component_name.empty()) ex.component_name = mFactoryName; + if (ex.factory_name.empty()) ex.factory_name = mFactoryName; + if (ex.factory_tag.empty()) ex.factory_tag = mTag; throw ex; } catch (...) { @@ -27,24 +29,62 @@ void JFactory::Create(const std::shared_ptr& event) { ex.nested_exception = std::current_exception(); ex.plugin_name = mPluginName; ex.component_name = mFactoryName; + ex.factory_name = mFactoryName; + ex.factory_tag = mTag; throw ex; } } if (mStatus == Status::Unprocessed) { - if (mPreviousRunNumber == -1) { - // This is the very first run - ChangeRun(event); - BeginRun(event); - mPreviousRunNumber = run_number; - } - else if (mPreviousRunNumber != run_number) { - // This is a later run, and it has changed - EndRun(); - ChangeRun(event); - BeginRun(event); - mPreviousRunNumber = run_number; - } - Process(event); + try { + if (mPreviousRunNumber == -1) { + // This is the very first run + ChangeRun(event); + BeginRun(event); + mPreviousRunNumber = run_number; + } + else if (mPreviousRunNumber != run_number) { + // This is a later run, and it has changed + EndRun(); + ChangeRun(event); + BeginRun(event); + mPreviousRunNumber = run_number; + } + } + catch (JException& ex) { + if (ex.plugin_name.empty()) ex.plugin_name = mPluginName; + if (ex.component_name.empty()) ex.component_name = mFactoryName; + if (ex.factory_name.empty()) ex.factory_name = mFactoryName; + if (ex.factory_tag.empty()) ex.factory_tag = mTag; + throw ex; + } + catch (...) { + auto ex = JException("Unknown exception in JFactoryT::BeginRun/ChangeRun/EndRun()"); + ex.nested_exception = std::current_exception(); + ex.plugin_name = mPluginName; + ex.component_name = mFactoryName; + ex.factory_name = mFactoryName; + ex.factory_tag = mTag; + throw ex; + } + try { + Process(event); + } + catch (JException& ex) { + if (ex.plugin_name.empty()) ex.plugin_name = mPluginName; + if (ex.component_name.empty()) ex.component_name = mFactoryName; + if (ex.factory_name.empty()) ex.factory_name = mFactoryName; + if (ex.factory_tag.empty()) ex.factory_tag = mTag; + throw ex; + } + catch (...) { + auto ex = JException("Unknown exception in JFactoryT::Process()"); + ex.nested_exception = std::current_exception(); + ex.plugin_name = mPluginName; + ex.component_name = mFactoryName; + ex.factory_name = mFactoryName; + ex.factory_tag = mTag; + throw ex; + } mStatus = Status::Processed; mCreationStatus = CreationStatus::Created; } diff --git a/src/libraries/JANA/JFactorySet.cc b/src/libraries/JANA/JFactorySet.cc index 04dbe3ff1..00305788b 100644 --- a/src/libraries/JANA/JFactorySet.cc +++ b/src/libraries/JANA/JFactorySet.cc @@ -137,9 +137,7 @@ JFactory* JFactorySet::GetFactory(const std::string& object_name, const std::str std::vector JFactorySet::GetAllFactories() const { std::vector results; for (auto p : mFactories) { - if (p.second->GetLevel() == mLevel) { - results.push_back(p.second); - } + results.push_back(p.second); } return results; } @@ -229,7 +227,6 @@ std::vector JFactorySet::Summarize() const { std::vector results; for (auto& pair : mFactories) { - if (pair.second->GetLevel() != mLevel) continue; results.push_back({ .level = pair.second->GetLevel(), .plugin_name = pair.second->GetPluginName(), diff --git a/src/libraries/JANA/JFactorySet.h b/src/libraries/JANA/JFactorySet.h index e3ba8e620..8b7e290b5 100644 --- a/src/libraries/JANA/JFactorySet.h +++ b/src/libraries/JANA/JFactorySet.h @@ -59,8 +59,9 @@ JFactoryT* JFactorySet::GetFactory(const std::string& tag) const { auto typed_key = std::make_pair(std::type_index(typeid(T)), tag); auto typed_iter = mFactories.find(typed_key); if (typed_iter != std::end(mFactories)) { - if (typed_iter->second->GetLevel() != mLevel) { - throw JException("Factory belongs to a different level on the event hierarchy!"); + JEventLevel found_level = typed_iter->second->GetLevel(); + if (found_level != mLevel) { + throw JException("Factory belongs to a different level on the event hierarchy. Expected: %s, Found: %s", toString(mLevel).c_str(), toString(found_level).c_str()); } return static_cast*>(typed_iter->second); } @@ -68,8 +69,9 @@ JFactoryT* JFactorySet::GetFactory(const std::string& tag) const { auto untyped_key = std::make_pair(JTypeInfo::demangle(), tag); auto untyped_iter = mFactoriesFromString.find(untyped_key); if (untyped_iter != std::end(mFactoriesFromString)) { - if (untyped_iter->second->GetLevel() != mLevel) { - throw JException("Factory belongs to a different level on the event hierarchy!"); + JEventLevel found_level = untyped_iter->second->GetLevel(); + if (found_level != mLevel) { + throw JException("Factory belongs to a different level on the event hierarchy. Expected: %s, Found: %s", toString(mLevel).c_str(), toString(found_level).c_str()); } return static_cast*>(untyped_iter->second); } diff --git a/src/libraries/JANA/JMultifactory.h b/src/libraries/JANA/JMultifactory.h index a3fbe6c0d..893643f10 100644 --- a/src/libraries/JANA/JMultifactory.h +++ b/src/libraries/JANA/JMultifactory.h @@ -8,6 +8,8 @@ #include #include +#include +#include #ifdef JANA2_HAVE_PODIO #include @@ -57,7 +59,8 @@ class JMultifactoryHelperPodio : public JFactoryPodioT{ #endif // JANA2_HAVE_PODIO -class JMultifactory { +class JMultifactory : public jana::omni::JComponent, + public jana::omni::JHasRunCallbacks { JFactorySet mHelpers; // This has ownership UNTIL JFactorySet::Add() takes it over @@ -70,9 +73,7 @@ class JMultifactory { std::string mTag; // JMultifactories each get their own name // This can be used for parameter and collection name prefixing, though at a higher level - std::string mPluginName; // So we can propagate this to the JMultifactoryHelpers, so we can have useful error messages std::string mFactoryName; // So we can propagate this to the JMultifactoryHelpers, so we can have useful error messages - JApplication* mApp; #ifdef JANA2_HAVE_PODIO bool mNeedPodio = false; // Whether we need to retrieve the podio::Frame @@ -128,13 +129,9 @@ class JMultifactory { // This is meant to be called from JFactorySet, which will take ownership of the helpers while leaving the pointers // in place. This method is only supposed to be called by JFactorySet::Add(JMultifactory). - void SetApplication(JApplication* app) { mApp = app; } - JApplication* GetApplication() { return mApp; } - // These are set by JFactoryGeneratorT (just like JFactories) and get propagated to each of the JMultifactoryHelpers void SetTag(std::string tag) { mTag = std::move(tag); } void SetFactoryName(std::string factoryName) { mFactoryName = std::move(factoryName); } - void SetPluginName(std::string pluginName) { mPluginName = std::move(pluginName); } }; @@ -143,9 +140,11 @@ template void JMultifactory::DeclareOutput(std::string tag, bool owns_data) { JFactory* helper = new JMultifactoryHelper(this); if (!owns_data) helper->SetFactoryFlag(JFactory::JFactory_Flags_t::NOT_OBJECT_OWNER); - helper->SetPluginName(mPluginName); + helper->SetPluginName(m_plugin_name); helper->SetFactoryName(mFactoryName); helper->SetTag(std::move(tag)); + helper->SetLevel(GetLevel()); + mHelpers.SetLevel(GetLevel()); mHelpers.Add(helper); } @@ -153,7 +152,10 @@ template void JMultifactory::SetData(std::string tag, std::vector data) { JFactoryT* helper = mHelpers.GetFactory(tag); if (helper == nullptr) { - throw JException("JMultifactory: Attempting to SetData() without corresponding DeclareOutput()"); + auto ex = JException("JMultifactory: Attempting to SetData() without corresponding DeclareOutput()"); + ex.factory_name = m_type_name; + ex.factory_tag = m_prefix; + throw ex; } #ifdef JANA2_HAVE_PODIO // This may or may not be a Podio factory. We find out if it is, and if so, set the frame before calling Set(). @@ -175,8 +177,10 @@ void JMultifactory::DeclarePodioOutput(std::string tag, bool owns_data) { if (!owns_data) helper->SetSubsetCollection(true); helper->SetTag(std::move(tag)); - helper->SetPluginName(mPluginName); + helper->SetPluginName(m_plugin_name); helper->SetFactoryName(mFactoryName); + helper->SetLevel(GetLevel()); + mHelpers.SetLevel(GetLevel()); mHelpers.Add(helper); mNeedPodio = true; } @@ -185,11 +189,17 @@ template void JMultifactory::SetCollection(std::string tag, typename JFactoryPodioT::CollectionT&& collection) { JFactoryT* helper = mHelpers.GetFactory(tag); if (helper == nullptr) { - throw JException("JMultifactory: Attempting to SetData() without corresponding DeclareOutput()"); + auto ex = JException("JMultifactory: Attempting to SetData() without corresponding DeclareOutput()"); + ex.factory_name = m_type_name; + ex.factory_tag = m_prefix; + throw ex; } auto* typed = dynamic_cast*>(helper); if (typed == nullptr) { - throw JException("JMultifactory: Helper needs to be a JFactoryPodioT (this shouldn't be reachable)"); + auto ex = JException("JMultifactory: Helper needs to be a JFactoryPodioT (this shouldn't be reachable)"); + ex.factory_name = m_type_name; + ex.factory_tag = m_prefix; + throw ex; } typed->SetFrame(mPodioFrame); @@ -200,11 +210,17 @@ template void JMultifactory::SetCollection(std::string tag, std::unique_ptr::CollectionT> collection) { JFactoryT* helper = mHelpers.GetFactory(tag); if (helper == nullptr) { - throw JException("JMultifactory: Attempting to SetData() without corresponding DeclareOutput()"); + auto ex = JException("JMultifactory: Attempting to SetData() without corresponding DeclareOutput()"); + ex.factory_name = m_type_name; + ex.factory_tag = m_prefix; + throw ex; } auto* typed = dynamic_cast*>(helper); if (typed == nullptr) { - throw JException("JMultifactory: Helper needs to be a JFactoryPodioT (this shouldn't be reachable)"); + auto ex = JException("JMultifactory: Helper needs to be a JFactoryPodioT (this shouldn't be reachable)"); + ex.factory_name = m_type_name; + ex.factory_tag = m_prefix; + throw ex; } typed->SetFrame(mPodioFrame); diff --git a/src/libraries/JANA/Omni/JComponent.h b/src/libraries/JANA/Omni/JComponent.h new file mode 100644 index 000000000..e5c735257 --- /dev/null +++ b/src/libraries/JANA/Omni/JComponent.h @@ -0,0 +1,206 @@ + +// Copyright 2024, Jefferson Science Associates, LLC. +// Subject to the terms in the LICENSE file found in the top-level directory. +// Created by Nathan Brei + +#pragma once +#include + +namespace jana { +namespace omni { + + +struct JComponent { + enum class Status { Uninitialized, Initialized, Finalized }; + enum class CallbackStyle { Compatibility, Classic, Declarative }; + +protected: + + struct ParameterBase; + struct ServiceBase; + + std::vector m_parameters; + std::vector m_services; + + JEventLevel m_level = JEventLevel::Event; + CallbackStyle m_callback_style = CallbackStyle::Compatibility; + std::string m_prefix; + std::string m_plugin_name; + std::string m_type_name; + Status m_status = Status::Uninitialized; + mutable std::mutex m_mutex; + JApplication* m_app = nullptr; + JLogger m_logger; + +public: + // --------------------- + // Meant to be called by users, or alternatively from a Generator + // --------------------- + void SetLevel(JEventLevel level) { m_level = level; } + + void SetCallbackStyle(CallbackStyle style) { m_callback_style = style; } + + void SetPrefix(std::string prefix) { + m_prefix = prefix; + } + /// For convenience, we provide a NAME_OF_THIS macro so that the user doesn't have to store the type name as a string, + /// because that could get out of sync if automatic refactoring tools are used. + void SetTypeName(std::string type_name) { m_type_name = std::move(type_name); } + + JApplication* GetApplication() const { + if (m_app == nullptr) { + throw JException("JApplication pointer hasn't been provided yet! Hint: Component configuration should happen inside Init(), not in the constructor."); + } + return m_app; + } + + JLogger& GetLogger() { return m_logger; } + + + // --------------------- + // Meant to be called by JANA + // --------------------- + std::string GetPrefix() { return m_prefix; } + + JEventLevel GetLevel() { return m_level; } + + std::string GetLoggerName() const { return m_prefix.empty() ? m_type_name : m_prefix; } + + std::string GetPluginName() const { return m_plugin_name; } + + void SetPluginName(std::string plugin_name) { m_plugin_name = std::move(plugin_name); }; + + std::string GetTypeName() const { return m_type_name; } + + Status GetStatus() const { + std::lock_guard lock(m_mutex); + return m_status; + } + + void SetApplication(JApplication* app) { m_app = app; } + + void SetLogger(JLogger logger) { m_logger = logger; } + + +protected: + struct ParameterBase { + std::string m_name; + std::string m_description; + virtual void Configure(JParameterManager& parman, const std::string& prefix) = 0; + virtual void Configure(std::map fields) = 0; + }; + + struct ServiceBase { + virtual void Init(JApplication* app) = 0; + }; + + void RegisterParameter(ParameterBase* parameter) { + m_parameters.push_back(parameter); + } + + void RegisterService(ServiceBase* service) { + m_services.push_back(service); + } + +public: + + void ConfigureAllParameters(std::map fields) { + for (auto* parameter : this->m_parameters) { + parameter->Configure(fields); + } + } + +protected: + template + class ParameterRef : public ParameterBase { + + T* m_data; + + public: + ParameterRef(JComponent* owner, std::string name, T& slot, std::string description="") { + owner->RegisterParameter(this); + this->m_name = name; + this->m_description = description; + m_data = &slot; + } + + const T& operator()() { return *m_data; } + + protected: + + void Configure(JParameterManager& parman, const std::string& prefix) override { + parman.SetDefaultParameter(prefix + ":" + this->m_name, *m_data, this->m_description); + } + void Configure(std::map fields) override { + auto it = fields.find(this->m_name); + if (it != fields.end()) { + const auto& value_str = it->second; + JParameterManager::Parse(value_str, *m_data); + } + } + }; + + template + class Parameter : public ParameterBase { + + T m_data; + + public: + Parameter(JComponent* owner, std::string name, T default_value, std::string description) { + owner->RegisterParameter(this); + this->m_name = name; + this->m_description = description; + m_data = default_value; + } + + const T& operator()() { return m_data; } + + protected: + + void Configure(JParameterManager& parman, const std::string& prefix) override { + parman.SetDefaultParameter(prefix + ":" + this->m_name, m_data, this->m_description); + } + void Configure(std::map fields) override { + auto it = fields.find(this->m_name); + if (it != fields.end()) { + const auto& value_str = it->second; + JParameterManager::Parse(value_str, m_data); + } + } + }; + + + template + class Service : public ServiceBase { + + std::shared_ptr m_data; + + public: + + Service(JComponent* owner) { + owner->RegisterService(this); + } + + ServiceT& operator()() { + return *m_data; + } + + protected: + + void Init(JApplication* app) { + m_data = app->GetService(); + } + + }; + + + + +}; + + + +} // namespace omni +} // namespace jana + + diff --git a/src/libraries/JANA/Omni/JHasInputs.h b/src/libraries/JANA/Omni/JHasInputs.h new file mode 100644 index 000000000..d389e9a34 --- /dev/null +++ b/src/libraries/JANA/Omni/JHasInputs.h @@ -0,0 +1,160 @@ +// Copyright 2024, Jefferson Science Associates, LLC. +// Subject to the terms in the LICENSE file found in the top-level directory. +// Created by Nathan Brei + +#pragma once +#include + +template struct PodioTypeMap; + +namespace jana { +namespace omni { + + +struct JHasInputs { +protected: + + struct InputBase; + std::vector m_inputs; + + void RegisterInput(InputBase* input) { + m_inputs.push_back(input); + } + + struct InputBase { + std::string type_name; + JEventLevel level; + std::vector collection_names; + bool is_variadic = false; + + virtual void GetCollection(const JEvent& event) = 0; + virtual void PrefetchCollection(const JEvent& event) = 0; + }; + + template + class Input : public InputBase { + + std::vector m_data; + + public: + Input(JHasInputs* owner, std::string default_tag="", JEventLevel level=JEventLevel::None) { + owner->RegisterInput(this); + this->collection_names.push_back(default_tag); + this->type_name = JTypeInfo::demangle(); + this->level = level; + } + + const std::vector& operator()() { return m_data; } + + private: + friend class JComponentT; + + void GetCollection(const JEvent& event) { + if (this->level == event.GetLevel() || this->level == JEventLevel::None) { + m_data = event.Get(this->collection_names[0]); + } + else { + m_data = event.GetParent(level).template Get(this->collection_names[0]); + } + } + void PrefetchCollection(const JEvent& event) { + if (this->level == event.GetLevel() || this->level == JEventLevel::None) { + event.Get(this->collection_names[0]); + } + else { + event.GetParent(level).template Get(this->collection_names[0]); + } + } + }; + +#ifdef JANA2_HAVE_PODIO + template + class PodioInput : public InputBase { + + const typename PodioTypeMap::collection_t* m_data; + + public: + + PodioInput(JHasInputs* owner, std::string default_collection_name="", JEventLevel level=JEventLevel::None) { + owner->RegisterInput(this); + this->collection_names.push_back(default_collection_name); + this->type_name = JTypeInfo::demangle(); + this->level = level; + } + + const typename PodioTypeMap::collection_t* operator()() { + return m_data; + } + + void GetCollection(const JEvent& event) { + if (this->level == event.GetLevel() || this->level == JEventLevel::None) { + m_data = event.GetCollection(this->collection_names[0]); + } + else { + m_data = event.GetParent(this->level).GetCollection(this->collection_names[0]); + } + } + + void PrefetchCollection(const JEvent& event) { + if (this->level == event.GetLevel() || this->level == JEventLevel::None) { + event.GetCollection(this->collection_names[0]); + } + else { + event.GetParent(this->level).GetCollection(this->collection_names[0]); + } + } + }; + + + template + class VariadicPodioInput : public InputBase { + + std::vector::collection_t*> m_data; + + public: + + VariadicPodioInput(JHasInputs* owner, std::vector default_names={}, JEventLevel level=JEventLevel::None) { + owner->RegisterInput(this); + this->collection_names = default_names; + this->type_name = JTypeInfo::demangle(); + this->is_variadic = true; + this->level = level; + } + + const std::vector::collection_t*> operator()() { + return m_data; + } + + void GetCollection(const JEvent& event) { + m_data.clear(); + if (this->level == event.GetLevel() || this->level == JEventLevel::None) { + for (auto& coll_name : this->collection_names) { + m_data.push_back(event.GetCollection(coll_name)); + } + } + else { + for (auto& coll_name : this->collection_names) { + m_data.push_back(event.GetParent(this->level).GetCollection(this->collection_names[0])); + } + } + } + + void PrefetchCollection(const JEvent& event) { + if (this->level == event.GetLevel() || this->level == JEventLevel::None) { + for (auto& coll_name : this->collection_names) { + event.GetCollection(coll_name); + } + } + else { + for (auto& coll_name : this->collection_names) { + event.GetParent(this->level).GetCollection(this->collection_names[0]); + } + } + } + }; +#endif +}; + +} // namespace omni +} // namespace jana + diff --git a/src/libraries/JANA/Omni/JHasOutputs.h b/src/libraries/JANA/Omni/JHasOutputs.h new file mode 100644 index 000000000..eca931a18 --- /dev/null +++ b/src/libraries/JANA/Omni/JHasOutputs.h @@ -0,0 +1,122 @@ +// Copyright 2023, Jefferson Science Associates, LLC. +// Subject to the terms in the LICENSE file found in the top-level directory. +// Created by Nathan Brei + +#pragma once + +#include + +template struct PodioTypeMap; + +namespace jana { +namespace omni { + + +struct JHasOutputs { +protected: + struct OutputBase; + std::vector m_outputs; + + void RegisterOutput(OutputBase* output) { + m_outputs.push_back(output); + } + + struct OutputBase { + std::string type_name; + std::vector collection_names; + bool is_variadic = false; + + virtual void InsertCollection(JEvent& event) = 0; + virtual void Reset() = 0; + }; + + template + class Output : public OutputBase { + std::vector m_data; + + public: + Output(JHasOutputs* owner, std::string default_tag_name="") { + owner->RegisterOutput(this); + this->collection_names.push_back(default_tag_name); + this->type_name = JTypeInfo::demangle(); + } + + std::vector& operator()() { return m_data; } + + protected: + void InsertCollection(JEvent& event) override { + event.Insert(m_data, this->collection_names[0]); + } + void Reset() override { } + }; + + +#ifdef JANA2_HAVE_PODIO + template + class PodioOutput : public OutputBase { + + std::unique_ptr::collection_t> m_data; + + public: + + PodioOutput(JHasOutputs* owner, std::string default_collection_name="") { + owner->RegisterOutput(this); + this->collection_names.push_back(default_collection_name); + this->type_name = JTypeInfo::demangle(); + } + + std::unique_ptr::collection_t>& operator()() { return m_data; } + + protected: + void InsertCollection(JEvent& event) override { + event.InsertCollection(std::move(*m_data), this->collection_names[0]); + } + void Reset() override { + m_data = std::move(std::make_unique::collection_t>()); + } + }; + + + template + class VariadicPodioOutput : public OutputBase { + + std::vector::collection_t>> m_data; + + public: + + VariadicPodioOutput(JHasOutputs* owner, std::vector default_collection_names={}) { + owner->RegisterOutput(this); + this->collection_names = default_collection_names; + this->type_name = JTypeInfo::demangle(); + this->is_variadic = true; + } + + std::vector::collection_t>>& operator()() { return m_data; } + + protected: + void InsertCollection(JEvent& event) override { + if (m_data.size() != this->collection_names.size()) { + throw JException("VariadicPodioOutput InsertCollection failed: Declared %d collections, but provided %d.", this->collection_names.size(), m_data.size()); + // Otherwise this leads to a PODIO segfault + } + size_t i = 0; + for (auto& coll_name : this->collection_names) { + event.InsertCollection(std::move(*(m_data[i++])), coll_name); + } + } + + void Reset() override { + m_data.clear(); + for (auto& coll_name : this->collection_names) { + m_data.push_back(std::make_unique::collection_t>()); + } + } + }; +#endif + +}; + + + +} // namespace omni +} // namespace jana diff --git a/src/libraries/JANA/Omni/JHasRunCallbacks.h b/src/libraries/JANA/Omni/JHasRunCallbacks.h new file mode 100644 index 000000000..ab40094d3 --- /dev/null +++ b/src/libraries/JANA/Omni/JHasRunCallbacks.h @@ -0,0 +1,65 @@ +// Copyright 2024, Jefferson Science Associates, LLC. +// Subject to the terms in the LICENSE file found in the top-level directory. +// Created by Nathan Brei + +#pragma once + +#include + +namespace jana { +namespace omni { + +class JHasRunCallbacks { + +protected: + struct ResourceBase { + virtual void ChangeRun(int32_t run_nr, JApplication* app) = 0; + }; + + std::vector m_resources; + int32_t m_last_run_number = -1; + +public: + void RegisterResource(ResourceBase* resource) { + m_resources.push_back(resource); + } + + template + class Resource : public ResourceBase { + ResourceT m_data; + LambdaT m_lambda; + + public: + + Resource(JHasRunCallbacks* owner, LambdaT lambda) : m_lambda(lambda) { + owner->RegisterResource(this); + }; + + const ResourceT& operator()() { return m_data; } + + protected: + + void ChangeRun(int32_t run_nr, JApplication* app) override { + std::shared_ptr service = app->template GetService(); + m_data = m_lambda(service, run_nr); + } + }; + + // Declarative interface + virtual void ChangeRun(int32_t /*run_nr*/) {} + + // Full interface + virtual void ChangeRun(const JEvent&) {} + + // Compatibility interface + virtual void BeginRun(const std::shared_ptr&) {} + + virtual void ChangeRun(const std::shared_ptr&) {} + + virtual void EndRun() {} + +}; + +} // namespace omni +} // namespace jana + diff --git a/src/libraries/JANA/Omni/JOmniFactory.h b/src/libraries/JANA/Omni/JOmniFactory.h new file mode 100644 index 000000000..cb70d28f8 --- /dev/null +++ b/src/libraries/JANA/Omni/JOmniFactory.h @@ -0,0 +1,311 @@ +// Copyright 2023, Jefferson Science Associates, LLC. +// Subject to the terms in the LICENSE file found in the top-level directory. +// Created by Nathan Brei + +#pragma once + +/** + * Omnifactories are a lightweight layer connecting JANA to generic algorithms + * It is assumed multiple input data (controlled by input tags) + * which might be changed by user parameters. + */ + +#include +#include +#include + +#include +#include + +#include +#include + + +struct EmptyConfig {}; + +template +class JOmniFactory : public JMultifactory, public jana::omni::JHasInputs { +public: + + /// ========================= + /// Handle output collections + /// ========================= + + struct OutputBase { + std::string type_name; + std::vector collection_names; + bool is_variadic = false; + + virtual void CreateHelperFactory(JOmniFactory& fac) = 0; + virtual void SetCollection(JOmniFactory& fac) = 0; + virtual void Reset() = 0; + }; + + template + class Output : public OutputBase { + std::vector m_data; + + public: + Output(JOmniFactory* owner, std::string default_tag_name="") { + owner->RegisterOutput(this); + this->collection_names.push_back(default_tag_name); + this->type_name = JTypeInfo::demangle(); + } + + std::vector& operator()() { return m_data; } + + private: + friend class JOmniFactory; + + void CreateHelperFactory(JOmniFactory& fac) override { + fac.DeclareOutput(this->collection_names[0]); + } + + void SetCollection(JOmniFactory& fac) override { + fac.SetData(this->collection_names[0], this->m_data); + } + + void Reset() override { } + }; + + +#ifdef JANA2_HAVE_PODIO + template + class PodioOutput : public OutputBase { + + std::unique_ptr::collection_t> m_data; + + public: + + PodioOutput(JOmniFactory* owner, std::string default_collection_name="") { + owner->RegisterOutput(this); + this->collection_names.push_back(default_collection_name); + this->type_name = JTypeInfo::demangle(); + } + + std::unique_ptr::collection_t>& operator()() { return m_data; } + + private: + friend class JOmniFactory; + + void CreateHelperFactory(JOmniFactory& fac) override { + fac.DeclarePodioOutput(this->collection_names[0]); + } + + void SetCollection(JOmniFactory& fac) override { + if (m_data == nullptr) { + throw JException("JOmniFactory: SetCollection failed due to missing output collection '%s'", this->collection_names[0].c_str()); + // Otherwise this leads to a PODIO segfault + } + fac.SetCollection(this->collection_names[0], std::move(this->m_data)); + } + + void Reset() override { + m_data = std::move(std::make_unique::collection_t>()); + } + }; + + + template + class VariadicPodioOutput : public OutputBase { + + std::vector::collection_t>> m_data; + + public: + + VariadicPodioOutput(JOmniFactory* owner, std::vector default_collection_names={}) { + owner->RegisterOutput(this); + this->collection_names = default_collection_names; + this->type_name = JTypeInfo::demangle(); + this->is_variadic = true; + } + + std::vector::collection_t>>& operator()() { return m_data; } + + private: + friend class JOmniFactory; + + void CreateHelperFactory(JOmniFactory& fac) override { + for (auto& coll_name : this->collection_names) { + fac.DeclarePodioOutput(coll_name); + } + } + + void SetCollection(JOmniFactory& fac) override { + if (m_data.size() != this->collection_names.size()) { + throw JException("JOmniFactory: VariadicPodioOutput SetCollection failed: Declared %d collections, but provided %d.", this->collection_names.size(), m_data.size()); + // Otherwise this leads to a PODIO segfault + } + size_t i = 0; + for (auto& coll_name : this->collection_names) { + fac.SetCollection(coll_name, std::move(this->m_data[i++])); + } + } + + void Reset() override { + m_data.clear(); + for (auto& coll_name : this->collection_names) { + m_data.push_back(std::make_unique::collection_t>()); + } + } + }; +#endif + + void RegisterOutput(OutputBase* output) { + m_outputs.push_back(output); + } + + +public: + std::vector m_outputs; + +private: + /// Current logger + JLogger m_logger; + + /// Configuration + ConfigT m_config; + +public: + + size_t FindVariadicCollectionCount(size_t total_input_count, size_t variadic_input_count, size_t total_collection_count, bool is_input) { + + size_t variadic_collection_count = total_collection_count - (total_input_count - variadic_input_count); + + if (variadic_input_count == 0) { + // No variadic inputs: check that collection_name count matches input count exactly + if (total_input_count != total_collection_count) { + throw JException("JOmniFactory '%s': Wrong number of %s collection names: %d expected, %d found.", + m_prefix.c_str(), (is_input ? "input" : "output"), total_input_count, total_collection_count); + } + } + else { + // Variadic inputs: check that we have enough collection names for the non-variadic inputs + if (total_input_count-variadic_input_count > total_collection_count) { + throw JException("JOmniFactory '%s': Not enough %s collection names: %d needed, %d found.", + m_prefix.c_str(), (is_input ? "input" : "output"), total_input_count-variadic_input_count, total_collection_count); + } + + // Variadic inputs: check that the variadic collection names is evenly divided by the variadic input count + if (variadic_collection_count % variadic_input_count != 0) { + throw JException("JOmniFactory '%s': Wrong number of %s collection names: %d found total, but %d can't be distributed among %d variadic inputs evenly.", + m_prefix.c_str(), (is_input ? "input" : "output"), total_collection_count, variadic_collection_count, variadic_input_count); + } + } + return variadic_collection_count; + } + + inline void PreInit(std::string tag, + std::vector default_input_collection_names, + std::vector default_output_collection_names ) { + + // TODO: NWB: JMultiFactory::GetTag,SetTag are not currently usable + m_prefix = (this->GetPluginName().empty()) ? tag : this->GetPluginName() + ":" + tag; + + // Obtain collection name overrides if provided. + // Priority = [JParameterManager, JOmniFactoryGenerator] + m_app->SetDefaultParameter(m_prefix + ":InputTags", default_input_collection_names, "Input collection names"); + m_app->SetDefaultParameter(m_prefix + ":OutputTags", default_output_collection_names, "Output collection names"); + + // Figure out variadic inputs + size_t variadic_input_count = 0; + for (auto* input : m_inputs) { + if (input->is_variadic) { + variadic_input_count += 1; + } + } + size_t variadic_input_collection_count = FindVariadicCollectionCount(m_inputs.size(), variadic_input_count, default_input_collection_names.size(), true); + + // Set input collection names + size_t i = 0; + for (auto* input : m_inputs) { + input->collection_names.clear(); + if (input->is_variadic) { + for (size_t j = 0; j<(variadic_input_collection_count/variadic_input_count); ++j) { + input->collection_names.push_back(default_input_collection_names[i++]); + } + } + else { + input->collection_names.push_back(default_input_collection_names[i++]); + } + } + + // Figure out variadic outputs + size_t variadic_output_count = 0; + for (auto* output : m_outputs) { + if (output->is_variadic) { + variadic_output_count += 1; + } + } + size_t variadic_output_collection_count = FindVariadicCollectionCount(m_outputs.size(), variadic_output_count, default_output_collection_names.size(), true); + + // Set output collection names and create corresponding helper factories + i = 0; + for (auto* output : m_outputs) { + output->collection_names.clear(); + if (output->is_variadic) { + for (size_t j = 0; j<(variadic_output_collection_count/variadic_output_count); ++j) { + output->collection_names.push_back(default_output_collection_names[i++]); + } + } + else { + output->collection_names.push_back(default_output_collection_names[i++]); + } + output->CreateHelperFactory(*this); + } + + // Obtain logger + //m_logger = m_app->GetService()->logger(m_prefix); + m_logger = m_app->GetService()->get_logger(m_prefix); + + // Configure logger. Priority = [JParameterManager, system log level] + // std::string default_log_level = eicrecon::LogLevelToString(m_logger->level()); + // m_app->SetDefaultParameter(m_prefix + ":LogLevel", default_log_level, "LogLevel: trace, debug, info, warn, err, critical, off"); + // m_logger->set_level(eicrecon::ParseLogLevel(default_log_level)); + } + + void Init() override { + for (auto* parameter : m_parameters) { + parameter->Configure(*(m_app->GetJParameterManager()), m_prefix); + } + for (auto* service : m_services) { + service->Init(m_app); + } + static_cast(this)->Configure(); + } + + void BeginRun(const std::shared_ptr& event) override { + for (auto* resource : m_resources) { + resource->ChangeRun(event->GetRunNumber(), m_app); + } + static_cast(this)->ChangeRun(event->GetRunNumber()); + } + + void Process(const std::shared_ptr &event) override { + try { + for (auto* input : m_inputs) { + input->GetCollection(*event); + } + for (auto* output : m_outputs) { + output->Reset(); + } + static_cast(this)->Execute(event->GetRunNumber(), event->GetEventNumber()); + for (auto* output : m_outputs) { + output->SetCollection(*this); + } + } + catch(std::exception &e) { + throw JException(e.what()); + } + } + + using ConfigType = ConfigT; + + /// Retrieve reference to already-configured logger + //std::shared_ptr &logger() { return m_logger; } + JLogger& logger() { return m_logger; } + + /// Retrieve reference to embedded config object + ConfigT& config() { return m_config; } + +}; diff --git a/src/libraries/JANA/Omni/JOmniFactoryGeneratorT.h b/src/libraries/JANA/Omni/JOmniFactoryGeneratorT.h new file mode 100644 index 000000000..3595db8a4 --- /dev/null +++ b/src/libraries/JANA/Omni/JOmniFactoryGeneratorT.h @@ -0,0 +1,121 @@ +// Copyright 2023, Jefferson Science Associates, LLC. +// Subject to the terms in the LICENSE file found in the top-level directory. +// Created by Nathan Brei + +#pragma once + +#include +#include +#include + +template +class JOmniFactoryGeneratorT : public JFactoryGenerator { +public: + using FactoryConfigType = typename FactoryT::ConfigType; + +private: + struct TypedWiring { + std::string m_tag; + std::vector m_default_input_tags; + std::vector m_default_output_tags; + FactoryConfigType m_default_cfg; /// Must be properly copyable! + }; + + struct UntypedWiring { + std::string m_tag; + std::vector m_default_input_tags; + std::vector m_default_output_tags; + std::map m_config_params; + }; + +public: + + + explicit JOmniFactoryGeneratorT(std::string tag, + std::vector default_input_tags, + std::vector default_output_tags, + FactoryConfigType cfg, + JApplication* app) { + m_app = app; + m_wirings.push_back({.m_tag=tag, + .m_default_input_tags=default_input_tags, + .m_default_output_tags=default_output_tags, + .m_default_cfg=cfg + }); + }; + + explicit JOmniFactoryGeneratorT(std::string tag, + std::vector default_input_tags, + std::vector default_output_tags, + JApplication* app) { + m_app = app; + m_wirings.push_back({.m_tag=tag, + .m_default_input_tags=default_input_tags, + .m_default_output_tags=default_output_tags, + .m_default_cfg={} + }); + + } + + explicit JOmniFactoryGeneratorT(JApplication* app) : m_app(app) { + } + + void AddWiring(std::string tag, + std::vector default_input_tags, + std::vector default_output_tags, + FactoryConfigType cfg) { + + m_wirings.push_back({.m_tag=tag, + .m_default_input_tags=default_input_tags, + .m_default_output_tags=default_output_tags, + .m_default_cfg=cfg + }); + } + + void AddWiring(std::string tag, + std::vector default_input_tags, + std::vector default_output_tags, + std::map config_params={}) { + + // Create throwaway factory so we can populate its config using our map. + FactoryT factory; + factory.ConfigureAllParameters(config_params); + auto config = factory.config(); + + m_wirings.push_back({.m_tag=tag, + .m_default_input_tags=default_input_tags, + .m_default_output_tags=default_output_tags, + .m_default_cfg=config + }); + + } + + void GenerateFactories(JFactorySet *factory_set) override { + + for (const auto& wiring : m_wirings) { + + + FactoryT *factory = new FactoryT; + factory->SetApplication(m_app); + factory->SetPluginName(this->GetPluginName()); + factory->SetFactoryName(JTypeInfo::demangle()); + // factory->SetTag(wiring.m_tag); + // We do NOT want to do this because JMF will use the tag to suffix the collection names + // TODO: NWB: Change this in JANA + factory->config() = wiring.m_default_cfg; + + // Set up all of the wiring prereqs so that Init() can do its thing + // Specifically, it needs valid input/output tags, a valid logger, and + // valid default values in its Config object + factory->PreInit(wiring.m_tag, wiring.m_default_input_tags, wiring.m_default_output_tags); + + // Factory is ready + factory_set->Add(factory); + } + } + +private: + std::vector m_wirings; + JApplication* m_app; + +}; diff --git a/src/libraries/JANA/Services/JComponentManager.cc b/src/libraries/JANA/Services/JComponentManager.cc index 0ec70b022..888fe17fa 100644 --- a/src/libraries/JANA/Services/JComponentManager.cc +++ b/src/libraries/JANA/Services/JComponentManager.cc @@ -65,9 +65,7 @@ void JComponentManager::add(JEventSource *event_source) { void JComponentManager::add(JEventProcessor *processor) { processor->SetPluginName(m_current_plugin_name); - if (processor->GetApplication() == nullptr) { - processor->SetJApplication(m_app); - } + processor->SetApplication(m_app); m_evt_procs.push_back(processor); } @@ -92,6 +90,20 @@ void JComponentManager::initialize() { auto parms = m_app->GetJParameterManager(); parms->SetDefaultParameter("record_call_stack", m_enable_call_graph_recording, "Records a trace of who called each factory. Reduces performance but necessary for plugins such as janadot."); parms->FilterParameters(m_default_tags, "DEFTAG:"); + + resolve_event_sources(); + + auto logging_svc = m_app->GetService(); + + for (JEventSource* source : m_evt_srces) { + source->SetLogger(logging_svc->get_logger(source->GetLoggerName())); + } + for (JEventProcessor* proc : m_evt_procs) { + proc->SetLogger(logging_svc->get_logger(proc->GetLoggerName())); + } + for (JEventUnfolder* unfolder : m_unfolders) { + unfolder->SetLogger(logging_svc->get_logger(unfolder->GetLoggerName())); + } } @@ -209,16 +221,25 @@ JComponentSummary JComponentManager::get_component_summary() { // Event sources for (auto * src : m_evt_srces) { - result.event_sources.push_back({.level=src->GetLevel(), .plugin_name=src->GetPluginName(), .type_name=src->GetType(), .source_name=src->GetName()}); + result.event_sources.push_back({.level=src->GetLevel(), + .plugin_name=src->GetPluginName(), + .type_name=src->GetType(), + .source_name=src->GetName()}); } // Event processors for (auto * evt_proc : m_evt_procs) { - result.event_processors.push_back({.level=evt_proc->GetLevel(), .plugin_name = evt_proc->GetPluginName(), .type_name=evt_proc->GetTypeName()}); + result.event_processors.push_back({.level=evt_proc->GetLevel(), + .plugin_name = evt_proc->GetPluginName(), + .type_name=evt_proc->GetTypeName(), + .prefix=evt_proc->GetPrefix()}); } for (auto * unfolder : m_unfolders) { - result.event_unfolders.push_back({.level=unfolder->GetLevel(), .plugin_name = unfolder->GetPluginName(), .type_name=unfolder->GetTypeName()}); + result.event_unfolders.push_back({.level=unfolder->GetLevel(), + .plugin_name = unfolder->GetPluginName(), + .type_name=unfolder->GetTypeName(), + .prefix=unfolder->GetPrefix()}); } // Factories diff --git a/src/libraries/JANA/Services/JLoggingService.cc b/src/libraries/JANA/Services/JLoggingService.cc new file mode 100644 index 000000000..4e9283d40 --- /dev/null +++ b/src/libraries/JANA/Services/JLoggingService.cc @@ -0,0 +1,115 @@ + +// Copyright 2020, Jefferson Science Associates, LLC. +// Subject to the terms in the LICENSE file found in the top-level directory. + + +#include + +#include + + +template <> +inline void JParameterManager::Parse(const std::string& in, JLogger::Level& out) { + std::string token(in); + std::transform(in.begin(), in.end(), token.begin(), ::tolower); + if (std::strcmp(token.c_str(), "trace") == 0) { + out = JLogger::Level::TRACE; + } + else if (std::strcmp(token.c_str(), "debug") == 0) { + out = JLogger::Level::DEBUG; + } + else if (std::strcmp(token.c_str(), "info") == 0) { + out = JLogger::Level::INFO; + } + else if (std::strcmp(token.c_str(), "warn") == 0) { + out = JLogger::Level::WARN; + } + else if (std::strcmp(token.c_str(), "error") == 0) { + out = JLogger::Level::ERROR; + } + else if (std::strcmp(token.c_str(), "fatal") == 0) { + out = JLogger::Level::FATAL; + } + else { + throw JException("Unable to parse log level: '%s'. Options are: TRACE, DEBUG, INFO, WARN, ERROR, FATAL", in.c_str()); + } +} + +void JLoggingService::acquire_services(JServiceLocator* serviceLocator) { + + auto params = serviceLocator->get(); + params->SetDefaultParameter("log:global", m_global_log_level, "Default log level"); + + std::vector groups; + params->SetDefaultParameter("log:off", groups, "Comma-separated list of loggers that should be turned off completely"); + for (auto& s : groups) { + m_local_log_levels[s] = JLogger::Level::OFF; + } + groups.clear(); + params->SetDefaultParameter("log:fatal", groups, "Comma-separated list of loggers that should only print FATAL"); + for (auto& s : groups) { + m_local_log_levels[s] = JLogger::Level::FATAL; + } + groups.clear(); + params->SetDefaultParameter("log:error", groups, "Comma-separated list of loggers that should only print ERROR or higher"); + for (auto& s : groups) { + m_local_log_levels[s] = JLogger::Level::ERROR; + } + groups.clear(); + params->SetDefaultParameter("log:warn", groups, "Comma-separated list of loggers that should only print WARN or higher"); + for (auto& s : groups) { + m_local_log_levels[s] = JLogger::Level::WARN; + } + groups.clear(); + params->SetDefaultParameter("log:info", groups, "Comma-separated list of loggers that should only print INFO or higher"); + for (auto& s : groups) { + m_local_log_levels[s] = JLogger::Level::INFO; + } + groups.clear(); + params->SetDefaultParameter("log:debug", groups, "Comma-separated list of loggers that should only print DEBUG or higher"); + for (auto& s : groups) { + m_local_log_levels[s] = JLogger::Level::DEBUG; + } + groups.clear(); + params->SetDefaultParameter("log:trace", groups, "Comma-separated list of loggers that should print everything"); + for (auto& s : groups) { + m_local_log_levels[s] = JLogger::Level::TRACE; + } + // Set the log level on the parameter manager, resolving the chicken-and-egg problem. + params->SetLogger(get_logger("JParameterManager")); +} + + +void JLoggingService::set_level(JLogger::Level level) { + m_global_log_level = level; +} + + +void JLoggingService::set_level(std::string className, JLogger::Level level) { + m_local_log_levels[className] = level; +} + + +JLogger JLoggingService::get_logger() { + return JLogger(m_global_log_level); +} + + +JLogger JLoggingService::get_logger(std::string className) { + + JLogger logger; + logger.show_classname = true; + logger.className = className; + + auto search = m_local_log_levels.find(className); + if (search != m_local_log_levels.end()) { + logger.level = search->second; + } else { + logger.level = m_global_log_level; + } + return logger; +} + + + + diff --git a/src/libraries/JANA/Services/JLoggingService.h b/src/libraries/JANA/Services/JLoggingService.h index fc327b4d4..692d5b890 100644 --- a/src/libraries/JANA/Services/JLoggingService.h +++ b/src/libraries/JANA/Services/JLoggingService.h @@ -2,19 +2,12 @@ // Copyright 2020, Jefferson Science Associates, LLC. // Subject to the terms in the LICENSE file found in the top-level directory. - -#ifndef JANA_JLOGGER_H_ -#define JANA_JLOGGER_H_ +#pragma once #include #include #include -#include -#include -#include -#include -#include // Convenience macros for temporary debugging statements. #ifndef _DBG__ @@ -30,87 +23,26 @@ inline std::string ltrunc(std::string original, size_t desired_length) { return "\u2026" + original.substr(n - desired_length, desired_length - 1); } + class JLoggingService : public JService { JLogger::Level m_global_log_level = JLogger::Level::INFO; + std::map m_local_log_levels; public: - void set_level(JLogger::Level level) { m_global_log_level = level; } - - void set_level(std::string className, JLogger::Level level) { - m_local_log_levels[className] = level; - } - - void acquire_services(JServiceLocator* serviceLocator) override { - - auto params = serviceLocator->get(); - std::vector groups; - params->SetDefaultParameter("log:off", groups, "Comma-separated list of loggers that should be turned off completely"); - for (auto& s : groups) { - m_local_log_levels[s] = JLogger::Level::OFF; - } - groups.clear(); - params->SetDefaultParameter("log:fatal", groups, "Comma-separated list of loggers that should only print FATAL"); - for (auto& s : groups) { - m_local_log_levels[s] = JLogger::Level::FATAL; - } - groups.clear(); - params->SetDefaultParameter("log:error", groups, "Comma-separated list of loggers that should only print ERROR or higher"); - for (auto& s : groups) { - m_local_log_levels[s] = JLogger::Level::ERROR; - } - groups.clear(); - params->SetDefaultParameter("log:warn", groups, "Comma-separated list of loggers that should only print WARN or higher"); - for (auto& s : groups) { - m_local_log_levels[s] = JLogger::Level::WARN; - } - groups.clear(); - params->SetDefaultParameter("log:info", groups, "Comma-separated list of loggers that should only print INFO or higher"); - for (auto& s : groups) { - m_local_log_levels[s] = JLogger::Level::INFO; - } - groups.clear(); - params->SetDefaultParameter("log:debug", groups, "Comma-separated list of loggers that should only print DEBUG or higher"); - for (auto& s : groups) { - m_local_log_levels[s] = JLogger::Level::DEBUG; - } - groups.clear(); - params->SetDefaultParameter("log:trace", groups, "Comma-separated list of loggers that should print everything"); - for (auto& s : groups) { - m_local_log_levels[s] = JLogger::Level::TRACE; - } - // Set the log level on the parameter manager, resolving the chicken-and-egg problem. - params->SetLogger(get_logger("JParameterManager")); - } - - JLogger get_logger() { - return JLogger(m_global_log_level); - } - - JLogger get_logger(std::string className) { - - JLogger logger; - logger.show_classname = true; - logger.className = className; - - auto search = m_local_log_levels.find(className); - if (search != m_local_log_levels.end()) { - logger.level = search->second; - } else { - logger.level = m_global_log_level; - } - return logger; - } - - /// Deprecated - static JLogger logger(std::string /* className */) { - return JLogger(JLogger::Level::WARN); - } -}; + void acquire_services(JServiceLocator* serviceLocator) override; + + void set_level(JLogger::Level level); -#endif + void set_level(std::string className, JLogger::Level level); + + JLogger get_logger(); + + JLogger get_logger(std::string className); + +}; diff --git a/src/libraries/JANA/Services/JPluginLoader.cc b/src/libraries/JANA/Services/JPluginLoader.cc index f37997293..16554c5c1 100644 --- a/src/libraries/JANA/Services/JPluginLoader.cc +++ b/src/libraries/JANA/Services/JPluginLoader.cc @@ -137,13 +137,27 @@ void JPluginLoader::attach_plugins(JComponentManager* jcm) { paths_checked << "Loaded successfully" << std::endl; found_plugin = true; break; - } catch (...) { - paths_checked << "Loading failure: " << dlerror() << std::endl; - LOG_WARN(m_logger) << "Loading failure: " << dlerror() << LOG_END; + } + catch (JException& e) { + LOG_WARN(m_logger) << "Exception loading plugin: " << e << LOG_END; + paths_checked << "JException: " << e.GetMessage() << std::endl; continue; } + catch (std::exception& e) { + LOG_WARN(m_logger) << "Exception loading plugin: " << e.what() << LOG_END; + paths_checked << "Exception: " << e.what() << std::endl; + continue; + } + catch (...) { + LOG_WARN(m_logger) << "Unknown exception loading plugin" << LOG_END; + paths_checked << "Unknown exception" << std::endl; + continue; + } + } + else { + paths_checked << "File not found" << std::endl; + } - paths_checked << "File not found" << std::endl; LOG_DEBUG(m_logger) << "Failed to attach '" << fullpath << "'" << LOG_END; } @@ -189,7 +203,7 @@ void JPluginLoader::attach_plugin(std::string soname) { void* handle = dlopen(soname.c_str(), RTLD_LAZY | RTLD_GLOBAL | RTLD_NODELETE); if (!handle) { LOG_DEBUG(m_logger) << dlerror() << LOG_END; - throw "dlopen failed"; + throw JException("Plugin dlopen() failed: %s", dlerror()); } // Look for an InitPlugin symbol diff --git a/src/libraries/JANA/Status/JComponentSummary.cc b/src/libraries/JANA/Status/JComponentSummary.cc index 4ede844ea..6189c6554 100644 --- a/src/libraries/JANA/Status/JComponentSummary.cc +++ b/src/libraries/JANA/Status/JComponentSummary.cc @@ -10,50 +10,37 @@ std::ostream& operator<<(std::ostream& os, JComponentSummary const& cs) { os << "Component Summary" << std::endl << std::endl; - os << std::left; - os << " SOURCES" << std::endl; - JTablePrinter sourcesTable; - sourcesTable.AddColumn("Plugin"); - sourcesTable.AddColumn("Name"); - sourcesTable.AddColumn("Source"); - sourcesTable.AddColumn("Level"); + + JTablePrinter table; + table.AddColumn("Plugin"); + table.AddColumn("Type"); + table.AddColumn("Level"); + table.AddColumn("Name"); + table.AddColumn("Tag"); + for (const auto& source : cs.event_sources) { - sourcesTable | source.plugin_name | source.type_name | source.source_name | source.level; + table | source.plugin_name | "JEventSource" | source.level | source.type_name | source.source_name; } - sourcesTable.Render(os); - os << " PROCESSORS" << std::endl; - JTablePrinter procsTable; - procsTable.AddColumn("Plugin"); - procsTable.AddColumn("Name"); - procsTable.AddColumn("Level"); - for (const auto& proc : cs.event_processors) { - procsTable | proc.plugin_name | proc.type_name | proc.level; + for (const auto& unfolder : cs.event_unfolders) { + table | unfolder.plugin_name | "JEventUnfolder" | unfolder.level | unfolder.type_name | unfolder.prefix; } - procsTable.Render(os); - - if (cs.event_unfolders.size() != 0) { - os << " UNFOLDERS" << std::endl; - JTablePrinter unfoldersTable; - unfoldersTable.AddColumn("Plugin"); - unfoldersTable.AddColumn("Name"); - unfoldersTable.AddColumn("Level"); - for (const auto& unfolder : cs.event_unfolders) { - unfoldersTable | unfolder.plugin_name | unfolder.type_name | unfolder.level; - } - sourcesTable.Render(os); + + for (const auto& proc : cs.event_processors) { + table | proc.plugin_name | "JEventProcessor" | proc.level | proc.type_name | proc.prefix; } - os << " FACTORIES" << std::endl; + os << table << std::endl; JTablePrinter factoryTable; factoryTable.AddColumn("Plugin"); - factoryTable.AddColumn("Object name"); - factoryTable.AddColumn("Tag"); + factoryTable.AddColumn("Factory"); factoryTable.AddColumn("Level"); + factoryTable.AddColumn("Collection type"); + factoryTable.AddColumn("Collection tag"); for (const auto& factory : cs.factories) { - factoryTable | factory.plugin_name | factory.object_name | factory.factory_tag | factory.level; + factoryTable | factory.plugin_name | factory.factory_name | factory.level | factory.object_name | factory.factory_tag; } - factoryTable.Render(os); + os << factoryTable << std::endl; return os; } diff --git a/src/libraries/JANA/Status/JComponentSummary.h b/src/libraries/JANA/Status/JComponentSummary.h index a4f4054d5..3d52168e7 100644 --- a/src/libraries/JANA/Status/JComponentSummary.h +++ b/src/libraries/JANA/Status/JComponentSummary.h @@ -29,12 +29,14 @@ struct JEventProcessorSummary { JEventLevel level; std::string plugin_name; std::string type_name; + std::string prefix; }; struct JEventUnfolderSummary { JEventLevel level; std::string plugin_name; std::string type_name; + std::string prefix; }; struct JComponentSummary { diff --git a/src/libraries/JANA/Utils/JEventKey.h b/src/libraries/JANA/Utils/JEventKey.h new file mode 100644 index 000000000..ee3284f3c --- /dev/null +++ b/src/libraries/JANA/Utils/JEventKey.h @@ -0,0 +1,101 @@ +// Copyright 2024, Jefferson Science Associates, LLC. +// Subject to the terms in the LICENSE file found in the top-level directory. + +#pragma once +#include +#include + +class JEventKey { + struct Entry { JEventLevel level, + uint64_t absolute_number, // Starts at zero. For each event emitted at this level, increases by 1 + uint64_t relative_number, // Starts at zero. For each event emitted at this level BELONGING TO THIS PARENT, increases by 1 + uint64_t user_number } // User can set this using whatever convention they like. However it should probably increase monotonically. + // Defaults to absolute_number. + + std::vector m_entries; // store in REVERSE order: [self, parent, grandparent, ...] + int64_t m_run_number = -1; + // Set to -1 by default (we need to know when we don't have a run number so that the calibrations db can respond accordingly) + // User can set this to whatever they want + // Run number will automatically be propagated to any children + +public: + + JEventKey() { + m_entries.push_back({JEventLevel::None, 0, 0, 0}); + } + + Configure(JEventLevel level, uint64_t absolute_number) { + m_entries.clear(); + m_entries.push_back({level, absolute_number, absolute_number, absolute_number}); + } + + AddParent(const JEventKey& parent_key, uint64_t relative_number) { + if (m_entries.size() > 1) { + throw JException("Event already has a parent"); + } + for (const auto& entry : parent_key.m_entries) { + m_entries.push_back(entry); + // Store a copy of all parent entries locally so that we can more reliably detect refcount/recycling issues + // This may change as we figure out how to track non-parent ancestors and siblings + } + m_entries[0].relative_number = relative_number; + if (m_run_number == -1) { + m_run_number = parent_key.m_run_number; + } + } + + const std::vector& GetEntries() const { + return m_entries; + } + + void SetUserEventNumber(uint64_t user_number) { + // m_entries always has at least one entry + if (m_entries.size() == 0) throw JException("") + m_entries.back().user_number = user_number; + } + + void SetRunNumber(int64_t run_number) { + m_run_number = run_number; + } + + std::string toString() { + std::ostringstream ss; + ss << *this; + return ss.str(); + } + + JEventLevel GetLevel() { + return m_entries[0].level; + } + + uint64_t GetAbsoluteEventNumber() { + return m_entries[0].absolute_number; + } + + uint64_t GetRelativeEventNumber() { + return m_entries[0].relative_number; + } + + uint64_t GetUserEventNumber() { + return m_entries[0].user_number; + } +} + +inline std::ostream& operator<<(std::ostream& in, const JEventKey& key) { + // Timeslice 34.10.19 (absolute #1234, user #5678)" + in << key.GetLevel() << " "; + auto s = m_entries.size(); + for (size_t i=m_entries.size(); i>0; --i) { + in << m_entries[s-i-1].relative_number << "."; + } + in << key.GetRelativeEventNumber(); + if (key.GetRelativeEventNumber() != key.GetAbsoluteEventNumber()) { + in << "(absolute #" << key.GetAbsoluteEventNumber(); + + } + if (key.GetUserEventNumber() != key.GetAbsoluteEventNumber()) { + in << ", user #" << key.GetUserNumber(); + } + in << ")"; + return in; +} diff --git a/src/libraries/JANA/Utils/JEventLevel.h b/src/libraries/JANA/Utils/JEventLevel.h index 0867978a7..b10db525e 100644 --- a/src/libraries/JANA/Utils/JEventLevel.h +++ b/src/libraries/JANA/Utils/JEventLevel.h @@ -15,11 +15,17 @@ inline std::ostream& operator<<(std::ostream& os, JEventLevel level) { case JEventLevel::Event: os << "Event"; break; case JEventLevel::Subevent: os << "Subevent"; break; case JEventLevel::Task: os << "Task"; break; - case JEventLevel::None: os << "None"; break; + default: os << "None"; break; } return os; } +inline std::string toString(JEventLevel level) { + std::stringstream ss; + ss << level; + return ss.str(); +} + inline JEventLevel next_level(JEventLevel current_level) { switch (current_level) { @@ -30,6 +36,6 @@ inline JEventLevel next_level(JEventLevel current_level) { case JEventLevel::Event: return JEventLevel::Subevent; case JEventLevel::Subevent: return JEventLevel::Task; case JEventLevel::Task: return JEventLevel::None; - case JEventLevel::None: return JEventLevel::None; + default: return JEventLevel::None; } } diff --git a/src/libraries/JANA/Utils/JTablePrinter.cc b/src/libraries/JANA/Utils/JTablePrinter.cc index f6f590d7d..61494c60b 100644 --- a/src/libraries/JANA/Utils/JTablePrinter.cc +++ b/src/libraries/JANA/Utils/JTablePrinter.cc @@ -215,3 +215,8 @@ void JTablePrinter::Render(std::ostream& os) { } } +std::ostream& operator<<(std::ostream& os, JTablePrinter& t) { + t.Render(os); + return os; +} + diff --git a/src/libraries/JANA/Utils/JTablePrinter.h b/src/libraries/JANA/Utils/JTablePrinter.h index 6b2a8da83..925479036 100644 --- a/src/libraries/JANA/Utils/JTablePrinter.h +++ b/src/libraries/JANA/Utils/JTablePrinter.h @@ -54,6 +54,8 @@ class JTablePrinter { }; +std::ostream& operator<<(std::ostream& os, JTablePrinter& t); + template JTablePrinter& JTablePrinter::operator|(T cell) { std::ostringstream ss; diff --git a/src/plugins/JTest/JTestMain.cc b/src/plugins/JTest/JTestMain.cc index c9338e950..b19433086 100644 --- a/src/plugins/JTest/JTestMain.cc +++ b/src/plugins/JTest/JTestMain.cc @@ -18,8 +18,8 @@ extern "C"{ void InitPlugin(JApplication *app){ InitJANAPlugin(app); - app->Add(new JTestParser("dummy_source", app)); - app->Add(new JTestPlotter(app)); + app->Add(new JTestParser); + app->Add(new JTestPlotter); app->Add(new JFactoryGeneratorT()); app->Add(new JFactoryGeneratorT()); diff --git a/src/plugins/JTest/JTestParser.h b/src/plugins/JTest/JTestParser.h index 625df0195..81cb7f36c 100644 --- a/src/plugins/JTest/JTestParser.h +++ b/src/plugins/JTest/JTestParser.h @@ -28,13 +28,7 @@ class JTestParser : public JEventSource { public: - JTestParser(std::string source_name, JApplication* app) : JEventSource(source_name, app) - { - app->SetDefaultParameter("jtest:parser_ms", m_cputime_ms, "Time spent during parsing"); - app->SetDefaultParameter("jtest:parser_spread", m_cputime_spread, "Spread of time spent during parsing"); - app->SetDefaultParameter("jtest:parser_bytes", m_write_bytes, "Bytes written during parsing"); - app->SetDefaultParameter("jtest:parser_bytes_spread", m_write_spread, "Spread of bytes written during parsing"); - + JTestParser() { SetTypeName(NAME_OF_THIS); } @@ -42,6 +36,14 @@ class JTestParser : public JEventSource { return "JTest Fake Event Source"; } + void Open() { + auto app = GetApplication(); + app->SetDefaultParameter("jtest:parser_ms", m_cputime_ms, "Time spent during parsing"); + app->SetDefaultParameter("jtest:parser_spread", m_cputime_spread, "Spread of time spent during parsing"); + app->SetDefaultParameter("jtest:parser_bytes", m_write_bytes, "Bytes written during parsing"); + app->SetDefaultParameter("jtest:parser_bytes_spread", m_write_spread, "Spread of bytes written during parsing"); + } + void GetEvent(std::shared_ptr event) { if ((m_events_generated % 40) == 0) { diff --git a/src/plugins/JTest/JTestPlotter.h b/src/plugins/JTest/JTestPlotter.h index a87cb3770..ed9503a83 100644 --- a/src/plugins/JTest/JTestPlotter.h +++ b/src/plugins/JTest/JTestPlotter.h @@ -20,22 +20,19 @@ class JTestPlotter : public JEventProcessor { public: - JTestPlotter(JApplication* app) : JEventProcessor(app) { - + JTestPlotter() { SetTypeName(NAME_OF_THIS); + } + void Init() override { + auto app = GetApplication(); app->SetDefaultParameter("jtest:plotter_ms", m_cputime_ms, "Time spent during plotting"); app->SetDefaultParameter("jtest:plotter_spread", m_cputime_spread, "Spread of time spent during plotting"); app->SetDefaultParameter("jtest:plotter_bytes", m_write_bytes, "Bytes written during plotting"); app->SetDefaultParameter("jtest:plotter_bytes_spread", m_write_spread, "Spread of bytes written during plotting"); } - virtual std::string GetType() const { - return JTypeInfo::demangle(); - } - - - void Process(const std::shared_ptr& aEvent) { + void Process(const std::shared_ptr& aEvent) override { // Read the track data auto td = aEvent->GetSingle(); diff --git a/src/plugins/JTest/JTestTracker.h b/src/plugins/JTest/JTestTracker.h index 8f6240fff..1f99dc6c9 100644 --- a/src/plugins/JTest/JTestTracker.h +++ b/src/plugins/JTest/JTestTracker.h @@ -28,7 +28,6 @@ class JTestTracker : public JFactoryT { void Init() override { auto app = GetApplication(); - assert (app != nullptr); app->SetDefaultParameter("jtest:tracker_ms", m_cputime_ms, "Time spent during tracking"); app->SetDefaultParameter("jtest:tracker_spread", m_cputime_spread, "Spread of time spent during tracking"); app->SetDefaultParameter("jtest:tracker_bytes", m_write_bytes, "Bytes written during tracking"); diff --git a/src/plugins/janadot/JEventProcessorJANADOT.cc b/src/plugins/janadot/JEventProcessorJANADOT.cc index d41de314e..46ed6e99c 100644 --- a/src/plugins/janadot/JEventProcessorJANADOT.cc +++ b/src/plugins/janadot/JEventProcessorJANADOT.cc @@ -29,8 +29,14 @@ void InitPlugin(JApplication *app){ //------------------------------------------------------------------ JEventProcessorJANADOT::JEventProcessorJANADOT() { SetTypeName("JEventProcessorJANADOT"); +} + +//------------------------------------------------------------------ +// init +//------------------------------------------------------------------ +void JEventProcessorJANADOT::Init() { - auto app = japp; + auto app = GetApplication(); app->SetDefaultParameter("janadot:output_file", m_output_filename, "Output filename for call graph visualization"); app->SetDefaultParameter("janadot:weight_edges", m_weight_edges, "Use edge weight (penwidth) to represent the percent of time spent in call"); @@ -97,13 +103,6 @@ JEventProcessorJANADOT::JEventProcessorJANADOT() { }catch(...){} } -//------------------------------------------------------------------ -// init -//------------------------------------------------------------------ -void JEventProcessorJANADOT::Init() { - // Nothing to do here -} - //------------------------------------------------------------------ // BeginRun //------------------------------------------------------------------ diff --git a/src/plugins/janarate/JEventProcessorJANARATE.cc b/src/plugins/janarate/JEventProcessorJANARATE.cc index 3438913b1..185d7279e 100644 --- a/src/plugins/janarate/JEventProcessorJANARATE.cc +++ b/src/plugins/janarate/JEventProcessorJANARATE.cc @@ -40,7 +40,7 @@ void JEventProcessorJANARATE::Init(void) Ncalls = 0; prescale = 100; - mApplication->GetJParameterManager()->SetDefaultParameter( + GetApplication()->GetJParameterManager()->SetDefaultParameter( "RATE:PRESCALE", prescale, "Prescale entries in rate tree by this"); diff --git a/src/programs/unit_tests/ArrowActivationTests.cc b/src/programs/unit_tests/ArrowActivationTests.cc index 5fbb0073b..ae5f2fdc8 100644 --- a/src/programs/unit_tests/ArrowActivationTests.cc +++ b/src/programs/unit_tests/ArrowActivationTests.cc @@ -45,6 +45,9 @@ TEST_CASE("ArrowActivationTests") { topology->arrows.push_back(subtract_one); topology->arrows.push_back(sum_everything); + topology->pools.push_back(p1); + topology->pools.push_back(p2); + auto logger = JLogger(JLogger::Level::OFF); topology->m_logger = logger; emit_rand_ints->set_logger(logger); diff --git a/src/programs/unit_tests/BarrierEventTests.cc b/src/programs/unit_tests/BarrierEventTests.cc index b1c65e4c0..8dce85b45 100644 --- a/src/programs/unit_tests/BarrierEventTests.cc +++ b/src/programs/unit_tests/BarrierEventTests.cc @@ -8,8 +8,8 @@ TEST_CASE("BarrierEventTests") { SECTION("Basic Barrier") { JApplication app; - app.Add(new BarrierProcessor(&app)); - app.Add(new BarrierSource("dummy", &app)); + app.Add(new BarrierProcessor); + app.Add(new BarrierSource); app.SetParameterValue("nthreads", 4); app.SetParameterValue("jana:event_source_chunksize", 1); app.SetParameterValue("jana:event_processor_chunksize", 1); diff --git a/src/programs/unit_tests/BarrierEventTests.h b/src/programs/unit_tests/BarrierEventTests.h index 3ceabe055..09f7c2823 100644 --- a/src/programs/unit_tests/BarrierEventTests.h +++ b/src/programs/unit_tests/BarrierEventTests.h @@ -16,16 +16,6 @@ class BarrierSource : public JEventSource { int event_count=0; public: - BarrierSource(std::string source_name, JApplication *app) : JEventSource(source_name, app) - { } - - static std::string GetDescription() { - return "BarrierTests fake event source"; - } - - std::string GetType(void) const override { - return JTypeInfo::demangle(); - } void Open() override { } @@ -52,8 +42,6 @@ class BarrierSource : public JEventSource { struct BarrierProcessor : public JEventProcessor { public: - explicit BarrierProcessor(JApplication* app) : JEventProcessor(app) {} - void Process(const std::shared_ptr& event) override { if (event->GetSequential()) { diff --git a/src/programs/unit_tests/CMakeLists.txt b/src/programs/unit_tests/CMakeLists.txt index 4df2e65bd..5a97cc828 100644 --- a/src/programs/unit_tests/CMakeLists.txt +++ b/src/programs/unit_tests/CMakeLists.txt @@ -39,6 +39,7 @@ set(TEST_SOURCES ArrowTests.cc MultiLevelTopologyTests.cc UnfoldTests.cc + JComponentTests.cc ) if (${USE_PODIO}) diff --git a/src/programs/unit_tests/ExactlyOnceTests.cc b/src/programs/unit_tests/ExactlyOnceTests.cc index 4a60c1b52..6745e51a4 100644 --- a/src/programs/unit_tests/ExactlyOnceTests.cc +++ b/src/programs/unit_tests/ExactlyOnceTests.cc @@ -13,8 +13,8 @@ TEST_CASE("ExactlyOnceTests") { JApplication app; - auto source = new SimpleSource("SimpleSource", &app); - auto processor = new SimpleProcessor(&app); + auto source = new SimpleSource(); + auto processor = new SimpleProcessor(); app.Add(source); app.Add(processor); diff --git a/src/programs/unit_tests/ExactlyOnceTests.h b/src/programs/unit_tests/ExactlyOnceTests.h index d856c3cd5..282bcfa5c 100644 --- a/src/programs/unit_tests/ExactlyOnceTests.h +++ b/src/programs/unit_tests/ExactlyOnceTests.h @@ -16,16 +16,6 @@ struct SimpleSource : public JEventSource { std::atomic_int close_count {0}; std::atomic_int event_count {0}; - SimpleSource(std::string source_name, JApplication *app) : JEventSource(source_name, app) - { } - - static std::string GetDescription() { - return "ComponentTests Fake Event Source"; - } - - std::string GetType(void) const override { - return JTypeInfo::demangle(); - } void Open() override { open_count += 1; @@ -47,8 +37,6 @@ struct SimpleProcessor : public JEventProcessor { std::atomic_int init_count {0}; std::atomic_int finish_count {0}; - SimpleProcessor(JApplication* app) : JEventProcessor(app) {} - void Init() override { init_count += 1; } diff --git a/src/programs/unit_tests/JComponentTests.cc b/src/programs/unit_tests/JComponentTests.cc new file mode 100644 index 000000000..5b9a6df42 --- /dev/null +++ b/src/programs/unit_tests/JComponentTests.cc @@ -0,0 +1,181 @@ +#include + +#include +#include +#include +#include +#include + +namespace jana { + +template +MultifactoryT* RetrieveMultifactory(JFactorySet* facset, std::string output_collection_name) { + auto fac = facset->GetFactory(output_collection_name); + REQUIRE(fac != nullptr); + auto helper = dynamic_cast*>(fac); + REQUIRE(helper != nullptr); + auto multifactory = helper->GetMultifactory(); + REQUIRE(multifactory != nullptr); + auto typed = dynamic_cast(multifactory); + REQUIRE(typed != nullptr); + return typed; +} + +namespace component_unfolder_param_tests { + + +struct TestUnfolder : public JEventUnfolder { + + Parameter threshold {this, "threshold", 16.0, "The max cutoff threshold [V * A * kg^-1 * m^-2 * sec^-3]"}; + Parameter bucket_count {this, "bucket_count", 22, "The total number of buckets [dimensionless]"}; + + TestUnfolder() { + SetPrefix("my_unfolder"); + } +}; + + +TEST_CASE("JEventUnfolderParametersTests") { + JApplication app; + auto* sut = new TestUnfolder; + app.Add(sut); + + SECTION("JEventUnfolder using default parameters") { + app.Initialize(); + sut->DoInit(); + REQUIRE(sut->threshold() == 16.0); + REQUIRE(sut->bucket_count() == 22); + } + SECTION("JEventUnfolder using overridden parameters") { + app.SetParameterValue("my_unfolder:threshold", 12.0); + app.Initialize(); + sut->DoInit(); + REQUIRE(sut->threshold() == 12.0); + REQUIRE(sut->bucket_count() == 22); + } +} +} // component_unfolder_param_tests + + + + + +namespace component_processor_param_tests { + +struct TestProc : public JEventProcessor { + + Parameter threshold {this, "threshold", 16.0, "The max cutoff threshold [V * A * kg^-1 * m^-2 * sec^-3]"}; + Parameter bucket_count {this, "bucket_count", 22, "The total number of buckets [dimensionless]"}; + + TestProc() { + SetPrefix("my_proc"); + } +}; + + +TEST_CASE("JEventProcessorParametersTests") { + JApplication app; + auto* sut = new TestProc; + app.Add(sut); + + SECTION("JEventProcessor using default parameters") { + app.Initialize(); + sut->DoInitialize(); + REQUIRE(sut->threshold() == 16.0); + REQUIRE(sut->bucket_count() == 22); + } + SECTION("JEventProcessor using overridden parameters") { + app.SetParameterValue("my_proc:threshold", 12.0); + app.Initialize(); + sut->DoInitialize(); + REQUIRE(sut->threshold() == 12.0); + REQUIRE(sut->bucket_count() == 22); + } + +} + +} // namsepace component_processor_param_tests + + +namespace component_omnifactory_param_tests { + +struct MyCluster { + int x; +}; + +struct TestFac : public JOmniFactory { + + Output clusters_out {this, "clusters_out"}; + + Parameter threshold {this, "threshold", 16.0, "The max cutoff threshold [V * A * kg^-1 * m^-2 * sec^-3]"}; + Parameter bucket_count {this, "bucket_count", 22, "The total number of buckets [dimensionless]"}; + + TestFac() { + } + + void Configure() { + } + + void ChangeRun(int32_t) final { + } + + + // NOLINTNEXTLINE(bugprone-easily-swappable-parameters) + void Execute(int64_t, uint64_t) { + } +}; + + +TEST_CASE("JOmniFactoryParametersTests") { + JApplication app; + + + SECTION("JOmniFactory using default parameters") { + app.Initialize(); + JOmniFactoryGeneratorT facgen (&app); + facgen.AddWiring("ECalTestAlg", {}, {"specific_clusters_out"}); + JFactorySet facset; + facgen.GenerateFactories(&facset); + auto sut = RetrieveMultifactory(&facset, "specific_clusters_out"); + // RetrieveMultifactory() will call DoInitialize() for us + + REQUIRE(sut->threshold() == 16.0); + REQUIRE(sut->bucket_count() == 22); + } + + /* + * FIXME: In EICrecon first though + + SECTION("JOmniFactory using facgen parameters") { + app.Initialize(); + JOmniFactoryGeneratorT facgen (&app); + facgen.AddWiring("my_fac", {}, {"specific_clusters_out"}, {{"bucket_count","444"}}); + JFactorySet facset; + facgen.GenerateFactories(&facset); + auto sut = RetrieveMultifactory(&facset, "specific_clusters_out"); + // RetrieveMultifactory() will call DoInitialize() for us + + REQUIRE(sut->threshold() == 16.0); + REQUIRE(sut->bucket_count() == 444); + } + + SECTION("JOmniFactory using overridden parameters") { + app.SetParameterValue("my_fac:threshold", 12.0); + app.Initialize(); + + JOmniFactoryGeneratorT facgen (&app); + facgen.AddWiring("my_fac", {}, {"specific_clusters_out"}, {{"threshold", "55.5"}}); + JFactorySet facset; + facgen.GenerateFactories(&facset); + auto sut = RetrieveMultifactory(&facset, "specific_clusters_out"); + + REQUIRE(sut->threshold() == 12.0); + REQUIRE(sut->bucket_count() == 22); + } + + */ + +} // TEST_CASE + +} // namespace component_omnifactory_param_tests +} // namespace jana diff --git a/src/programs/unit_tests/JEventProcessorSequentialTests.cc b/src/programs/unit_tests/JEventProcessorSequentialTests.cc index 39f4aa551..8fe702bb8 100644 --- a/src/programs/unit_tests/JEventProcessorSequentialTests.cc +++ b/src/programs/unit_tests/JEventProcessorSequentialTests.cc @@ -14,9 +14,6 @@ namespace jeventprocessorsequentialtests { // Hence, we protect each Catch test with its own namespace. struct DummySource : public JEventSource { - DummySource() : JEventSource("DummySource", nullptr) { - SetTypeName("DummySource"); - } // By default, this will emit empty events with event numbers 0,1,2... void GetEvent(std::shared_ptr) override {} @@ -190,4 +187,4 @@ TEST_CASE("JEventProcessorSequentialTests") { } } -} // namespace \ No newline at end of file +} // namespace diff --git a/src/programs/unit_tests/JFactoryDefTagsTests.cc b/src/programs/unit_tests/JFactoryDefTagsTests.cc index 9cbc927c2..a18831bdf 100644 --- a/src/programs/unit_tests/JFactoryDefTagsTests.cc +++ b/src/programs/unit_tests/JFactoryDefTagsTests.cc @@ -103,7 +103,7 @@ TEST_CASE("MediumDefTags") { namespace deftagstest { struct DummySource : public JEventSource { - DummySource() : JEventSource("DummySource") { + DummySource() { SetTypeName(NAME_OF_THIS); }; @@ -144,4 +144,4 @@ TEST_CASE("LargeDefTags") { REQUIRE(proc->processed_count == 3); REQUIRE(proc->GetEventCount() == 3); REQUIRE(proc->E == 33.3); -} \ No newline at end of file +} diff --git a/src/programs/unit_tests/JFactoryTests.h b/src/programs/unit_tests/JFactoryTests.h index e07d385eb..6bc54a201 100644 --- a/src/programs/unit_tests/JFactoryTests.h +++ b/src/programs/unit_tests/JFactoryTests.h @@ -53,8 +53,6 @@ struct JFactoryTestDummyFactory : public JFactoryT { struct JFactoryTestDummySource: public JEventSource { - JFactoryTestDummySource() : JEventSource("dummy", nullptr) {} - void GetEvent(std::shared_ptr) override { }; diff --git a/src/programs/unit_tests/JParameterManagerTests.cc b/src/programs/unit_tests/JParameterManagerTests.cc index 89c3c8ea0..fbc2c6c30 100644 --- a/src/programs/unit_tests/JParameterManagerTests.cc +++ b/src/programs/unit_tests/JParameterManagerTests.cc @@ -409,8 +409,8 @@ TEST_CASE("JParameterManager_CompileTimeErrorForParseAndStringify") { int x; JParameterManager::Parse("22", x); - Mood m; // Uncomment these to test compile-time error message + //Mood m; //JParameterManager::Parse("Mediocre", m); //JParameterManager::Stringify(m); } diff --git a/src/programs/unit_tests/MultiLevelTopologyTests.cc b/src/programs/unit_tests/MultiLevelTopologyTests.cc index 3e1878b33..dfefe17dc 100644 --- a/src/programs/unit_tests/MultiLevelTopologyTests.cc +++ b/src/programs/unit_tests/MultiLevelTopologyTests.cc @@ -65,11 +65,12 @@ class Diagram { grid[r][c] = '['; grid[r][c+1] = ']'; } - +/* void add_connection(size_t start_row, size_t start_col, size_t end_row, size_t end_col) { if (start_row == end_row) { } } +*/ void print() { for (const auto& line : grid) { std::cout << line << std::endl; @@ -177,7 +178,6 @@ struct MultiLevelTopologyBuilder { // Skip lowest level if (i < 2) { // Vertical connector to split and merge - Level lower = levels[i+1]; auto split_it = arrows.find({l, ComponentType::Split}); if (split_it != arrows.end()) { std::cout << " |"; @@ -323,15 +323,6 @@ struct MultiLevelTopologyBuilder { }; -// Source Filter Map Split Merge Reduce -// -// Timeslice [] -----> [] -----> [] -----> [] [] -----> [] -// / \ -// --- --- -// / \ -// Event [] -------------------------> [] - - TEST_CASE("MultiLevelTopologyBuilderTests") { MultiLevelTopologyBuilder b; @@ -446,7 +437,7 @@ TEST_CASE("TimeslicesTests") { parms->SetParameter("jana:nevents", "5"); JApplication app(parms); - app.Add(new MyTimesliceSource("Dummy", &app)); + app.Add(new MyTimesliceSource); app.Add(new MyTimesliceUnfolder); app.Add(new MyEventProcessor); app.Add(new JFactoryGeneratorT); diff --git a/src/programs/unit_tests/MultiLevelTopologyTests.h b/src/programs/unit_tests/MultiLevelTopologyTests.h index 8fb4c8065..b36e8b73f 100644 --- a/src/programs/unit_tests/MultiLevelTopologyTests.h +++ b/src/programs/unit_tests/MultiLevelTopologyTests.h @@ -23,12 +23,10 @@ struct MyCluster : public JObject { struct MyTimesliceSource : public JEventSource { - MyTimesliceSource(std::string source_name, JApplication *app) : JEventSource(source_name, app) { + MyTimesliceSource() { SetLevel(JEventLevel::Timeslice); } - static std::string GetDescription() { return "MyTimesliceSource"; } - std::string GetType(void) const override { return JTypeInfo::demangle(); } void Open() override { } void GetEvent(std::shared_ptr event) override { @@ -54,7 +52,7 @@ struct MyTimesliceUnfolder : public JEventUnfolder { init_called_count++; }; - virtual void Preprocess(const JEvent& parent) const { + virtual void Preprocess(const JEvent& /*parent*/) const { preprocess_called_count++; // TODO: Are we going to need an omni unfolder? // TODO: Call protocluster factory @@ -69,9 +67,9 @@ struct MyTimesliceUnfolder : public JEventUnfolder { if (item == 3) { jout << "Unfold found item 3, finishing join" << jendl; // TODO: Insert protocluster into child - return Result::Finished; + return Result::NextChildNextParent; } - return Result::KeepGoing; + return Result::NextChildKeepParent; } virtual void Finish() { diff --git a/src/programs/unit_tests/NEventNSkipTests.cc b/src/programs/unit_tests/NEventNSkipTests.cc index b2e113ffd..36cbdbc1d 100644 --- a/src/programs/unit_tests/NEventNSkipTests.cc +++ b/src/programs/unit_tests/NEventNSkipTests.cc @@ -15,8 +15,6 @@ struct NEventNSkipBoundedSource : public JEventSource { std::atomic_int open_count{0}; std::atomic_int close_count{0}; - NEventNSkipBoundedSource(std::string source_name, JApplication *app) : JEventSource(source_name, app) { } - void GetEvent(std::shared_ptr) override { if (event_count >= event_bound) { throw JEventSource::RETURN_STATUS::kNO_MORE_EVENTS; @@ -39,7 +37,7 @@ struct NEventNSkipBoundedSource : public JEventSource { TEST_CASE("NEventNSkipTests") { JApplication app; - auto source = new NEventNSkipBoundedSource("BoundedSource", &app); + auto source = new NEventNSkipBoundedSource(); app.Add(source); SECTION("[1..100] @ nskip=0, nevents=0 => [1..100]") { @@ -82,9 +80,9 @@ TEST_CASE("JEventSourceArrow with multiple JEventSources") { JParameterManager* params = new JParameterManager; params->SetParameter("log:debug","JArrow,JArrowProcessingController"); JApplication app(params); - auto source1 = new NEventNSkipBoundedSource("BoundedSource1", &app); - auto source2 = new NEventNSkipBoundedSource("BoundedSource2", &app); - auto source3 = new NEventNSkipBoundedSource("BoundedSource3", &app); + auto source1 = new NEventNSkipBoundedSource(); + auto source2 = new NEventNSkipBoundedSource(); + auto source3 = new NEventNSkipBoundedSource(); app.Add(source1); app.Add(source2); app.Add(source3); @@ -100,9 +98,9 @@ TEST_CASE("JEventSourceArrow with multiple JEventSources") { app.Run(true); REQUIRE(app.GetExitCode() == (int) JApplication::ExitCode::Success); - REQUIRE(source1->GetStatus() == JEventSource::SourceStatus::Finished); - REQUIRE(source2->GetStatus() == JEventSource::SourceStatus::Finished); - REQUIRE(source3->GetStatus() == JEventSource::SourceStatus::Finished); + REQUIRE(source1->GetStatus() == JEventSource::Status::Finalized); + REQUIRE(source2->GetStatus() == JEventSource::Status::Finalized); + REQUIRE(source3->GetStatus() == JEventSource::Status::Finalized); REQUIRE(source1->open_count == 1); REQUIRE(source2->open_count == 1); REQUIRE(source3->open_count == 1); @@ -126,9 +124,9 @@ TEST_CASE("JEventSourceArrow with multiple JEventSources") { app.Run(true); REQUIRE(app.GetExitCode() == (int) JApplication::ExitCode::Success); - REQUIRE(source1->GetStatus() == JEventSource::SourceStatus::Finished); - REQUIRE(source2->GetStatus() == JEventSource::SourceStatus::Finished); - REQUIRE(source3->GetStatus() == JEventSource::SourceStatus::Finished); + REQUIRE(source1->GetStatus() == JEventSource::Status::Finalized); + REQUIRE(source2->GetStatus() == JEventSource::Status::Finalized); + REQUIRE(source3->GetStatus() == JEventSource::Status::Finalized); REQUIRE(source1->open_count == 1); REQUIRE(source2->open_count == 1); REQUIRE(source3->open_count == 1); @@ -154,9 +152,9 @@ TEST_CASE("JEventSourceArrow with multiple JEventSources") { app.Run(true); REQUIRE(app.GetExitCode() == (int) JApplication::ExitCode::Success); - REQUIRE(source1->GetStatus() == JEventSource::SourceStatus::Finished); - REQUIRE(source2->GetStatus() == JEventSource::SourceStatus::Finished); - REQUIRE(source3->GetStatus() == JEventSource::SourceStatus::Finished); + REQUIRE(source1->GetStatus() == JEventSource::Status::Finalized); + REQUIRE(source2->GetStatus() == JEventSource::Status::Finalized); + REQUIRE(source3->GetStatus() == JEventSource::Status::Finalized); REQUIRE(source1->open_count == 1); REQUIRE(source2->open_count == 1); REQUIRE(source3->open_count == 1); diff --git a/src/programs/unit_tests/PodioTests.cc b/src/programs/unit_tests/PodioTests.cc index 3ea642023..a7707d263 100644 --- a/src/programs/unit_tests/PodioTests.cc +++ b/src/programs/unit_tests/PodioTests.cc @@ -155,7 +155,7 @@ struct TestFac : public JFactoryPodioT { void Init() override { init_called = true; } - void Process(const std::shared_ptr& event) override { + void Process(const std::shared_ptr&) override { ExampleClusterCollection c; c.push_back(ExampleCluster(16.0)); SetCollection(std::move(c)); @@ -188,7 +188,7 @@ struct TestFac : public JFactoryPodioT { TestFac() { SetTag("clusters"); } - void Process(const std::shared_ptr& event) override { + void Process(const std::shared_ptr&) override { Insert(new ExampleCluster(16.0)); } }; diff --git a/src/programs/unit_tests/ScaleTests.cc b/src/programs/unit_tests/ScaleTests.cc index dcec8f052..e8e4c0381 100644 --- a/src/programs/unit_tests/ScaleTests.cc +++ b/src/programs/unit_tests/ScaleTests.cc @@ -12,7 +12,7 @@ TEST_CASE("NThreads") { // parms->SetParameter("log:debug","JScheduler,JArrowProcessingController,JWorker,JArrow"); parms->SetParameter("jana:nevents",3); JApplication app(parms); - app.Add(new scaletest::DummySource("DummySource", &app)); + app.Add(new scaletest::DummySource); SECTION("If nthreads not provided, default to 1") { app.Run(true); @@ -40,7 +40,7 @@ TEST_CASE("ScaleNWorkerUpdate") { auto params = new JParameterManager(); // params->SetParameter("log:debug", "JWorker,JArrowTopology,JScheduler,JArrow"); JApplication app(params); - app.Add(new scaletest::DummySource("DummySource", &app)); + app.Add(new scaletest::DummySource); app.Add(new scaletest::DummyProcessor); app.SetParameterValue("nthreads", 4); app.Run(false); @@ -69,7 +69,7 @@ TEST_CASE("ScaleThroughputImprovement", "[.][performance]") { // parms->SetParameter("log:info","JScheduler"); JApplication app(parms); app.SetTicker(false); - app.Add(new scaletest::DummySource("dummy", &app)); + app.Add(new scaletest::DummySource); app.Add(new scaletest::DummyProcessor); // app.SetParameterValue("benchmark:minthreads", 1); // app.SetParameterValue("benchmark:maxthreads", 5); diff --git a/src/programs/unit_tests/ScaleTests.h b/src/programs/unit_tests/ScaleTests.h index 635a4b15b..ffbda6a14 100644 --- a/src/programs/unit_tests/ScaleTests.h +++ b/src/programs/unit_tests/ScaleTests.h @@ -12,8 +12,6 @@ namespace scaletest { struct DummySource : public JEventSource { - DummySource(std::string source_name, JApplication *app ) : JEventSource(std::move(source_name), app) {} - void GetEvent(std::shared_ptr) override { consume_cpu_ms(20); std::this_thread::sleep_for(std::chrono::nanoseconds(1)); diff --git a/src/programs/unit_tests/SubeventTests.cc b/src/programs/unit_tests/SubeventTests.cc index 6a3331119..7e4f44a72 100644 --- a/src/programs/unit_tests/SubeventTests.cc +++ b/src/programs/unit_tests/SubeventTests.cc @@ -144,7 +144,6 @@ TEST_CASE("Basic subevent arrow functionality") { } struct SimpleSource : public JEventSource { - SimpleSource(std::string name) : JEventSource(name) {}; void GetEvent(std::shared_ptr event) override { std::vector inputs; inputs.push_back(new MyInput(22,3.6)); @@ -179,7 +178,7 @@ TEST_CASE("Basic subevent arrow functionality") { auto topology = app.GetService()->create_empty(); auto source_arrow = new JEventSourceArrow("simpleSource", - {new SimpleSource("simpleSource")}, + {new SimpleSource}, &events_in, topology->event_pool); auto proc_arrow = new JEventProcessorArrow("simpleProcessor", &events_out, nullptr, topology->event_pool); diff --git a/src/programs/unit_tests/TerminationTests.cc b/src/programs/unit_tests/TerminationTests.cc index dc089691b..1a4974624 100644 --- a/src/programs/unit_tests/TerminationTests.cc +++ b/src/programs/unit_tests/TerminationTests.cc @@ -17,14 +17,14 @@ TEST_CASE("TerminationTests") { auto parms = new JParameterManager; // parms->SetParameter("log:debug","JScheduler,JArrowProcessingController,JWorker,JArrow"); JApplication app(parms); - auto processor = new CountingProcessor(&app); + auto processor = new CountingProcessor(); app.Add(processor); app.SetParameterValue("jana:extended_report", 0); SECTION("Arrow engine, manual termination") { app.SetParameterValue("jana:engine", 0); - auto source = new UnboundedSource("UnboundedSource", &app); + auto source = new UnboundedSource(); app.Add(source); app.Run(false); std::this_thread::sleep_for(std::chrono::milliseconds(50)); @@ -37,7 +37,7 @@ TEST_CASE("TerminationTests") { SECTION("Arrow engine, self termination") { app.SetParameterValue("jana:engine", 0); - auto source = new BoundedSource("BoundedSource", &app); + auto source = new BoundedSource(); app.Add(source); app.Run(true); REQUIRE(source->event_count == 10); @@ -53,7 +53,7 @@ TEST_CASE("TerminationTests") { // What we really want is an Arrow that has an initialize() that we override. // However to do that, we need to extend JESA and create a custom topology. app.SetParameterValue("jana:engine", 0); - auto source = new InterruptedSource("InterruptedSource", &app); + auto source = new InterruptedSource(); app.Add(source); app.Run(true); REQUIRE(processor->processed_count == 1); // TODO: Was 0, should become zero again @@ -67,7 +67,7 @@ TEST_CASE("TerminationTests") { SECTION("Debug engine, self-termination") { app.SetParameterValue("jana:engine", 1); - auto source = new BoundedSource("BoundedSource", &app); + auto source = new BoundedSource(); app.Add(source); app.Run(true); REQUIRE(source->event_count == 10); @@ -79,7 +79,7 @@ TEST_CASE("TerminationTests") { SECTION("Debug engine, manual termination") { app.SetParameterValue("jana:engine", 1); - auto source = new UnboundedSource("UnboundedSource", &app); + auto source = new UnboundedSource(); app.Add(source); app.Run(false); std::this_thread::sleep_for(std::chrono::milliseconds(10)); diff --git a/src/programs/unit_tests/TerminationTests.h b/src/programs/unit_tests/TerminationTests.h index f6d1199dd..0ba1b7e06 100644 --- a/src/programs/unit_tests/TerminationTests.h +++ b/src/programs/unit_tests/TerminationTests.h @@ -12,9 +12,6 @@ #include "catch.hpp" struct InterruptedSource : public JEventSource { - InterruptedSource(std::string source_name, JApplication* app) : JEventSource(source_name, app) {} - static std::string GetDescription() { return "ComponentTests Fake Event Source"; } - std::string GetType(void) const override { return JTypeInfo::demangle(); } void Open() override { GetApplication()->Stop(); } void GetEvent(std::shared_ptr) override {} }; @@ -23,17 +20,6 @@ struct BoundedSource : public JEventSource { uint64_t event_count = 0; - BoundedSource(std::string source_name, JApplication *app) : JEventSource(source_name, app) - { } - - static std::string GetDescription() { - return "ComponentTests Fake Event Source"; - } - - std::string GetType(void) const override { - return JTypeInfo::demangle(); - } - void Open() override { } @@ -49,17 +35,6 @@ struct UnboundedSource : public JEventSource { uint64_t event_count = 0; - UnboundedSource(std::string source_name, JApplication *app) : JEventSource(source_name, app) - { } - - static std::string GetDescription() { - return "ComponentTests Fake Event Source"; - } - - std::string GetType(void) const override { - return JTypeInfo::demangle(); - } - void Open() override { } @@ -77,8 +52,6 @@ struct CountingProcessor : public JEventProcessor { std::atomic_int finish_call_count {0}; - CountingProcessor(JApplication* app) : JEventProcessor(app) {} - void Init() override {} void Process(const std::shared_ptr& /*event*/) override { diff --git a/src/programs/unit_tests/TimeoutTests.cc b/src/programs/unit_tests/TimeoutTests.cc index b18eb820b..273a90e11 100644 --- a/src/programs/unit_tests/TimeoutTests.cc +++ b/src/programs/unit_tests/TimeoutTests.cc @@ -19,28 +19,28 @@ TEST_CASE("TimeoutTests", "[.][performance]") { SECTION("Timeout in the event source on the first event") { - app.Add(new SourceWithTimeout("source_with_timeout", &app, 1)); + app.Add(new SourceWithTimeout(1)); app.Add(new ProcessorWithTimeout(-1)); app.Run(true); REQUIRE(app.GetExitCode() == (int) JApplication::ExitCode::Timeout); } SECTION("Timeout in the event source on the 5th event") { - app.Add(new SourceWithTimeout("source_with_timeout", &app, 5)); + app.Add(new SourceWithTimeout(5)); app.Add(new ProcessorWithTimeout(-1)); app.Run(true); REQUIRE(app.GetExitCode() == (int) JApplication::ExitCode::Timeout); } SECTION("Timeout in the event processor on the first event") { - app.Add(new SourceWithTimeout("source_with_timeout", &app, -1)); + app.Add(new SourceWithTimeout(-1)); app.Add(new ProcessorWithTimeout(1)); app.Run(true); REQUIRE(app.GetExitCode() == (int) JApplication::ExitCode::Timeout); } SECTION("Timeout in the event processor on the 5th event") { - app.Add(new SourceWithTimeout("source_with_timeout", &app, -1)); + app.Add(new SourceWithTimeout(-1)); app.Add(new ProcessorWithTimeout(5)); app.Run(true); REQUIRE(app.GetExitCode() == (int) JApplication::ExitCode::Timeout); @@ -49,7 +49,7 @@ TEST_CASE("TimeoutTests", "[.][performance]") { SECTION("A slow event source for the first event is fine") { int first_event_ms = 2000; - app.Add(new SourceWithTimeout("source_with_timeout", &app, -1, first_event_ms)); + app.Add(new SourceWithTimeout(-1, first_event_ms)); app.Add(new ProcessorWithTimeout(-1, 0)); app.Run(true); REQUIRE(app.GetExitCode() == (int) JApplication::ExitCode::Success); @@ -58,7 +58,7 @@ TEST_CASE("TimeoutTests", "[.][performance]") { SECTION("A slow event processor for the first event is fine") { int first_event_ms = 2000; - app.Add(new SourceWithTimeout("source_with_timeout", &app, -1, 0)); + app.Add(new SourceWithTimeout(-1, 0)); app.Add(new ProcessorWithTimeout(-1, first_event_ms)); app.Run(true); REQUIRE(app.GetExitCode() == (int) JApplication::ExitCode::Success); diff --git a/src/programs/unit_tests/TimeoutTests.h b/src/programs/unit_tests/TimeoutTests.h index d5bef61e5..35690f55d 100644 --- a/src/programs/unit_tests/TimeoutTests.h +++ b/src/programs/unit_tests/TimeoutTests.h @@ -15,24 +15,13 @@ struct SourceWithTimeout : public JEventSource { int first_event_delay_ms = 0; std::atomic_int event_count {0}; - SourceWithTimeout(std::string source_name, - JApplication *app, - int timeout_on_event_nr=-1, + SourceWithTimeout(int timeout_on_event_nr=-1, int first_delay_ms=0 ) - : JEventSource(std::move(source_name), app) - , timeout_on_event_nr(timeout_on_event_nr) + : timeout_on_event_nr(timeout_on_event_nr) , first_event_delay_ms(first_delay_ms) { } - static std::string GetDescription() { - return "ComponentTests Fake Event Source"; - } - - std::string GetType() const override { - return JTypeInfo::demangle(); - } - void Open() override { } diff --git a/src/programs/unit_tests/UnfoldTests.cc b/src/programs/unit_tests/UnfoldTests.cc index e8f9a4587..699feea62 100644 --- a/src/programs/unit_tests/UnfoldTests.cc +++ b/src/programs/unit_tests/UnfoldTests.cc @@ -36,7 +36,7 @@ struct TestUnfolder : public JEventUnfolder { unfolded_child_levels.push_back(child.GetLevel()); child.SetEventNumber(child_nr); LOG << "Unfolding " << parent.GetLevel() << " event " << parent.GetEventNumber() << " into " << child.GetLevel() << " " << child_nr << "; iter=" << iter << LOG_END; - return (iter == 2 ? Result::Finished : Result::KeepGoing); + return (iter == 2 ? Result::NextChildNextParent : Result::NextChildKeepParent); } }; diff --git a/src/programs/unit_tests/UserExceptionTests.cc b/src/programs/unit_tests/UserExceptionTests.cc index 860013ba7..cae310584 100644 --- a/src/programs/unit_tests/UserExceptionTests.cc +++ b/src/programs/unit_tests/UserExceptionTests.cc @@ -17,16 +17,16 @@ TEST_CASE("UserExceptionTests") { SECTION("JEventSource::Open() excepts, debug engine") { app.SetParameterValue("jana:engine", 1); - app.Add(new FlakySource("open_excepting_source", &app, true, false)); - app.Add(new FlakyProcessor(&app, false, false, false)); + app.Add(new FlakySource(true, false)); + app.Add(new FlakyProcessor(false, false, false)); REQUIRE_THROWS(app.Run(true)); } SECTION("JEventSource::GetEvent() excepts, debug engine") { app.SetParameterValue("jana:engine", 1); - app.Add(new FlakySource("open_excepting_source", &app, false, true)); - app.Add(new FlakyProcessor(&app, false, false, false)); + app.Add(new FlakySource(false, true)); + app.Add(new FlakyProcessor(false, false, false)); REQUIRE_THROWS(app.Run(true)); } @@ -34,64 +34,64 @@ TEST_CASE("UserExceptionTests") { SECTION("JEventProcessor::Init() excepts, debug engine") { app.SetParameterValue("jana:engine", 1); - app.Add(new FlakySource("open_excepting_source", &app, false, false)); - app.Add(new FlakyProcessor(&app, true, false, false)); + app.Add(new FlakySource(false, false)); + app.Add(new FlakyProcessor(true, false, false)); REQUIRE_THROWS(app.Run(true)); } SECTION("JEventProcessor::Process() excepts, debug engine") { app.SetParameterValue("jana:engine", 1); - app.Add(new FlakySource("open_excepting_source", &app, false, false)); - app.Add(new FlakyProcessor(&app, false, true, false)); + app.Add(new FlakySource(false, false)); + app.Add(new FlakyProcessor(false, true, false)); REQUIRE_THROWS(app.Run(true)); } SECTION("JEventProcessor::Finish() excepts, debug engine") { app.SetParameterValue("jana:engine", 1); - app.Add(new FlakySource("open_excepting_source", &app, false, false)); - app.Add(new FlakyProcessor(&app, false, false, true)); + app.Add(new FlakySource(false, false)); + app.Add(new FlakyProcessor(false, false, true)); REQUIRE_THROWS(app.Run(true)); } SECTION("JEventSource::Open() excepts, default engine") { app.SetParameterValue("jana:engine", 0); - app.Add(new FlakySource("open_excepting_source", &app, true, false)); - app.Add(new FlakyProcessor(&app, false, false, false)); + app.Add(new FlakySource(true, false)); + app.Add(new FlakyProcessor(false, false, false)); REQUIRE_THROWS(app.Run(true)); } SECTION("JEventSource::GetEvent() excepts, default engine") { app.SetParameterValue("jana:engine", 0); - app.Add(new FlakySource("open_excepting_source", &app, false, true)); - app.Add(new FlakyProcessor(&app, false, false, false)); + app.Add(new FlakySource(false, true)); + app.Add(new FlakyProcessor(false, false, false)); REQUIRE_THROWS(app.Run(true)); } SECTION("JEventProcessor::Init() excepts, default engine") { app.SetParameterValue("jana:engine", 0); - app.Add(new FlakySource("open_excepting_source", &app, false, false)); - app.Add(new FlakyProcessor(&app, true, false, false)); + app.Add(new FlakySource(false, false)); + app.Add(new FlakyProcessor(true, false, false)); REQUIRE_THROWS(app.Run(true)); } SECTION("JEventProcessor::Process() excepts, default engine") { app.SetParameterValue("jana:engine", 0); - app.Add(new FlakySource("open_excepting_source", &app, false, false)); - app.Add(new FlakyProcessor(&app, false, true, false)); + app.Add(new FlakySource(false, false)); + app.Add(new FlakyProcessor(false, true, false)); REQUIRE_THROWS(app.Run(true)); } SECTION("JEventProcessor::Finish() excepts, default engine") { app.SetParameterValue("jana:engine", 0); - app.Add(new FlakySource("open_excepting_source", &app, false, false)); - app.Add(new FlakyProcessor(&app, false, false, true)); + app.Add(new FlakySource(false, false)); + app.Add(new FlakyProcessor(false, false, true)); REQUIRE_THROWS(app.Run(true)); } } diff --git a/src/programs/unit_tests/UserExceptionTests.h b/src/programs/unit_tests/UserExceptionTests.h index 112e90b71..558ffaa90 100644 --- a/src/programs/unit_tests/UserExceptionTests.h +++ b/src/programs/unit_tests/UserExceptionTests.h @@ -16,14 +16,8 @@ struct FlakySource : public JEventSource { bool open_excepts, getevent_excepts; int event_count = 0; - FlakySource(std::string source_name, JApplication* app, bool open_excepts, bool getevent_excepts) - : JEventSource(source_name, app), open_excepts(open_excepts), getevent_excepts(getevent_excepts) {} - - static std::string GetDescription() { return "UnopenableEventSource"; } - - std::string GetType(void) const override { - return JTypeInfo::demangle(); - } + FlakySource(bool open_excepts, bool getevent_excepts) + : open_excepts(open_excepts), getevent_excepts(getevent_excepts) {} void Open() override { if (open_excepts) { @@ -49,9 +43,8 @@ struct FlakyProcessor : public JEventProcessor { bool init_excepts, process_excepts, finish_excepts; - FlakyProcessor(JApplication* app, bool init_excepts, bool process_excepts, bool finish_excepts) - : JEventProcessor(app) - , init_excepts(init_excepts) + FlakyProcessor(bool init_excepts, bool process_excepts, bool finish_excepts) + : init_excepts(init_excepts) , process_excepts(process_excepts) , finish_excepts(finish_excepts) {}; @@ -73,10 +66,6 @@ struct FlakyProcessor : public JEventProcessor { throw JException("Unable to finish!"); } } - - std::string GetType(void) const override { - return JTypeInfo::demangle(); - } };