Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial version of Action Plan implementation #289

Merged
merged 16 commits into from
Aug 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ daq_protobuf_codegen( opmon/*.proto )

##############################################################################
# Main library
daq_add_library(DAQModule*.cpp ConfigurationManager.cpp ModuleConfiguration.cpp
daq_add_library(Application.cpp DAQModule.cpp DAQModuleManager.cpp ConfigurationManager.cpp ModuleConfiguration.cpp
LINK_LIBRARIES ${APPFWK_DEPENDENCIES})

##############################################################################
Expand Down
72 changes: 72 additions & 0 deletions docs/ActionPlans.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# Action Plans

## Overview

An ActionPlan defines a series of ActionSteps, each one consisting of a set of DAQModule classes to run the command on. Each ActionPlan is associated with a FSMCommand object, and is run by the appliction when it recieves the corresponding command. If a command is received and no ActionPlan is defined, the application currently runs a "dummy" ActionPlan consisting of a single step where registered Actions matching the command name are all run in parallel.

## Defining an ActionPlan

ActionPlans are defined in configuration using these objects:

```XML
<class name="ActionPlan" description="A set of parallel steps for an application to carry out a command">
<relationship name="fsm" class-type="FSMCommand" low-cc="one" high-cc="one" is-composite="no" is-exclusive="no" is-dependent="no"/>
<relationship name="steps" class-type="ActionStep" low-cc="zero" high-cc="many" is-composite="no" is-exclusive="no" is-dependent="no" ordered="yes"/>
</class>

<class name="ActionStep">
<attribute name="module" type="class" is-multi-value="yes"/>
</class>
```

1. ActionPlan relates a set of ActionSteps to a FSMCommand instance.
1. ActionStep lists the module types to run in parallel at a given point in the sequence

ActionPlans are validated by the application to ensure that every module type has registered methods corresponding to the command linked to the ActionPlan.

### Example test/config/appfwk.data.xml

The DAQModuleManager_test unit test defines several ActionPlans used within the test. For example, the "do_stuff" action:

```XML

<obj class="FSMCommand" id="stuff">
<attr name="cmd" type="string" val="stuff"/>
<attr name="optional" type="bool" val="0"/>
</obj>

<obj class="ActionPlan" id="stuff">
<rel name="fsm" class="FSMCommand" id="stuff"/>
<rel name="steps">
<ref class="ActionStep" id="stuff_step_1"/>
</rel>
</obj>

<obj class="ActionStep" id="stuff_step_1">
<attr name="modules" type="class">
<data val="DummyModule"/>
</attr>
</obj>

```

The ActionPlans are associated with the Application instance as follows:

```XML
<obj class="DaqApplication" id="TestApp">
<attr name="application_name" type="string" val="daq_application"/>
<rel name="runs_on" class="VirtualHost" id="vlocalhost"/>
<rel name="modules">
<ref class="DummyModule" id="dummy_module_0"/>
</rel>
<rel name="action_plans">
<ref class="ActionPlan" id="stuff"/>
<ref class="ActionPlan" id="bad_stuff"/>
</rel>
</obj>
```

## Notes

* DAQModules register their action methods in the same way as before, however the specification of valid states for an action has been removed
* ActionSteps target module types, with the assumption that if multiple modules of the same class are present within an application, they will all run their defined action methods in unison (or at least within the same parallel processing step)
2 changes: 1 addition & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ appfwk consists of a generic DAQ application (`daq_application`) which can be co

appfwk provides the scaffolding on which all DUNE DAQ software processes can be developed. The running DAQ typically consists of multiple distinct processes assigned various tasks: filtering data, requesting it, saving it to storage, etc. There are many different types of process, some of which may not even have been conceived of yet, and it would be cumbersome to recompile multiple different types of process across many packages every time one wanted to change the behavior of the DAQ. To solve this problem, the approach that's been taken is to have a standard DUNE DAQ software process [`daq_application`](Daq-Application.md) which can be configured at runtime by Run Control in order to perform some particular function in the DAQ.

`daq_application` is designed as a flexible container of "DAQ modules" (units of code designed to perform specific tasks) and "connections" (designed to move data between DAQ modules that can be in the same or in different DAQ applications). These specific tasks can vary widely; they include [producing fake data for testing purposes](https://github.com/DUNE-DAQ/readoutmodules/blob/develop/plugins/FakeCardReader.hpp), [putting data into long term storage](https://github.com/DUNE-DAQ/dfmodules/blob/develop/plugins/DataWriterModule.hpp), and so forth. DAQ modules will typically execute user-defined functions when receiving standard transitions from Run Control: "conf", "start", etc. appfwk provides the `DAQModule` base class which users should derive their DAQ module class from in their own packages.
`daq_application` is designed as a flexible container of "DAQ modules" (units of code designed to perform specific tasks) and "connections" (designed to move data between DAQ modules that can be in the same or in different DAQ applications). These specific tasks can vary widely; they include [producing fake data for testing purposes](https://github.com/DUNE-DAQ/readoutmodules/blob/develop/plugins/FakeCardReader.hpp), [putting data into long term storage](https://github.com/DUNE-DAQ/dfmodules/blob/develop/plugins/DataWriterModule.hpp), and so forth. DAQ modules will typically execute user-defined functions when receiving standard transitions from Run Control: "conf", "start", etc. appfwk provides the `DAQModule` base class which users should derive their DAQ module class from in their own packages. Read more about ActionPlans [here](ActionPlans.md).

![daq_application](https://github.com/DUNE-DAQ/appfwk/raw/develop/docs/Application.png)

Expand Down
23 changes: 11 additions & 12 deletions include/appfwk/DAQModule.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,12 +137,13 @@ ERS_DECLARE_ISSUE_BASE(appfwk, ///< Namespace
/**
* @brief The MissingConnection DAQModule ERS Issue
*/
ERS_DECLARE_ISSUE_BASE(appfwk, ///< Namespace
MissingConnection, ///< Type of the Issue
appfwk::GeneralDAQModuleIssue, ///< Base class of the Issue
"Required Connection Not Found. Type: " << type << ", direction: " << direction, ///< Log Message from the issue
((std::string)name), ///< Base class attributes
((std::string)type)((std::string)direction) ///< Attribute of this class
ERS_DECLARE_ISSUE_BASE(appfwk, ///< Namespace
MissingConnection, ///< Type of the Issue
appfwk::GeneralDAQModuleIssue, ///< Base class of the Issue
"Required Connection Not Found. Type: " << type << ", direction: "
<< direction, ///< Log Message from the issue
((std::string)name), ///< Base class attributes
((std::string)type)((std::string)direction) ///< Attribute of this class
)

// Re-enable coverage collection LCOV_EXCL_STOP
Expand Down Expand Up @@ -197,29 +198,27 @@ namespace appfwk {
* Non-accepted commands or failure should return an ERS exception
* indicating this result.
*/
void execute_command(const std::string& name, const std::string& state, const data_t& data = {});
void execute_command(const std::string& name, const data_t& data = {});

std::vector<std::string> get_commands() const;

bool has_command(const std::string& name, const std::string& state) const;
bool has_command(const std::string& name) const;

protected:
/**
* @brief Registers a mdoule command under the name `cmd`.
* Returns whether the command was inserted (false meaning that command `cmd` already exists)
*/
template<typename Child>
void register_command(const std::string& name,
void (Child::*f)(const data_t&),
const std::set<std::string>& valid_states = std::set<std::string>{ "ANY" });
void register_command(const std::string& name, void (Child::*f)(const data_t&));

DAQModule(DAQModule const&) = delete;
DAQModule(DAQModule&&) = delete;
DAQModule& operator=(DAQModule const&) = delete;
DAQModule& operator=(DAQModule&&) = delete;

private:
using CommandMap_t = std::map<std::string, std::pair<std::set<std::string>, std::function<void(const data_t&)>>>;
using CommandMap_t = std::map<std::string, std::function<void(const data_t&)>>;
CommandMap_t m_commands;
};

Expand Down
13 changes: 9 additions & 4 deletions include/appfwk/ModuleConfiguration.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#define APPFWK_INCLUDE_MODULECONFIGURATION_HPP_

#include "appfwk/ConfigurationManager.hpp"
#include "confmodel/ActionPlan.hpp"
#include "confmodel/DaqModule.hpp"
#include "iomanager/IOManager.hpp"
#include "conffwk/Configuration.hpp"
Expand All @@ -26,10 +27,10 @@ ERS_DECLARE_ISSUE(appfwk,
"Application contains a resource " << res << " that is not a DaqModule", ///< Message
((std::string)res) ///< Message parameters
)
ERS_DECLARE_ISSUE(appfwk, ///< Namespace
NotADaqApplication, ///< Issue class name
ERS_DECLARE_ISSUE(appfwk, ///< Namespace
NotADaqApplication, ///< Issue class name
"Application " << app << " is neither a DaqApplication nor a SmartDaqApplication ", ///< Message
((std::string)app) ///< Message parameters
((std::string)app) ///< Message parameters
)

namespace confmodel {
Expand All @@ -41,10 +42,11 @@ namespace appfwk {

class ModuleConfiguration
{
std::shared_ptr<ConfigurationManager> m_config_mgr;
std::unordered_map<std::string, const dunedaq::confmodel::ActionPlan*> m_action_plans;
std::vector<const dunedaq::confmodel::DaqModule*> m_modules;
iomanager::Queues_t m_queues;
iomanager::Connections_t m_networkconnections;
std::shared_ptr<ConfigurationManager> m_config_mgr;

public:
explicit ModuleConfiguration(std::shared_ptr<ConfigurationManager> mgr);
Expand All @@ -53,6 +55,9 @@ class ModuleConfiguration
const iomanager::Connections_t& networkconnections() { return m_networkconnections; }
const std::vector<const confmodel::DaqModule*>& modules() { return m_modules; }

const std::unordered_map<std::string, const dunedaq::confmodel::ActionPlan*>& action_plans() { return m_action_plans; }
const dunedaq::confmodel::ActionPlan* action_plan(std::string cmd) const;

std::shared_ptr<ConfigurationManager> configuration_manager() { return m_config_mgr; }

template<typename T>
Expand Down
5 changes: 2 additions & 3 deletions include/appfwk/detail/DAQModule.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,11 @@ namespace dunedaq::appfwk {
template<typename Child>
void
DAQModule::register_command(const std::string& cmd_name,
void (Child::*f)(const data_t&),
const std::set<std::string>& states)
void (Child::*f)(const data_t&))
{
using namespace std::placeholders;

bool done = m_commands.emplace(cmd_name, std::make_pair(states, std::bind(f, dynamic_cast<Child*>(this), _1))).second;
bool done = m_commands.emplace(cmd_name, std::bind(f, dynamic_cast<Child*>(this), _1)).second;
if (!done) {
// Throw here
throw CommandRegistrationFailed(ERS_HERE, get_name(), cmd_name);
Expand Down
4 changes: 3 additions & 1 deletion src/detail/Application.hxx → src/Application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
* received with this code.
*/

#include "Application.hpp"

#include "appfwk/Issues.hpp"
#include "appfwk/opmon/application.pb.h"
#include "appfwk/cmd/Nljs.hpp"
Expand Down Expand Up @@ -109,7 +111,7 @@ Application::execute(const dataobj_t& cmd_data)
}

try {
m_mod_mgr.execute(get_state(), cmdname, rc_cmd.data);
m_mod_mgr.execute(cmdname, rc_cmd.data);
m_busy.store(false);
if (rc_cmd.exit_state != "ANY")
set_state(rc_cmd.exit_state);
Expand Down
2 changes: 0 additions & 2 deletions src/Application.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,4 @@ class Application
} // namespace appfwk
} // namespace dunedaq

#include "detail/Application.hxx"

#endif // APPFWK_INCLUDE_APPFWK_APPLICATION_HPP_
14 changes: 3 additions & 11 deletions src/DAQModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,11 @@
namespace dunedaq::appfwk {

void
DAQModule::execute_command(const std::string& cmd_name, const std::string& state, const data_t& data)
DAQModule::execute_command(const std::string& cmd_name, const data_t& data)
{
if (auto cmd = m_commands.find(cmd_name); cmd != m_commands.end()) {
if (cmd->second.first.find("ANY") != cmd->second.first.end() ||
(cmd->second.first.find(state) != cmd->second.first.end())) {
std::invoke(cmd->second.second, data);
std::invoke(cmd->second, data);
return;
}
throw InvalidState(ERS_HERE, get_name(), cmd_name, state);
}
throw UnknownCommand(ERS_HERE, get_name(), cmd_name);
}
Expand All @@ -38,14 +34,10 @@ DAQModule::get_commands() const
}

bool
DAQModule::has_command(const std::string& cmd_name, const std::string& state) const
DAQModule::has_command(const std::string& cmd_name) const
{
if (auto cmd = m_commands.find(cmd_name); cmd != m_commands.end()) {
if (cmd->second.first.find("ANY") != cmd->second.first.end() ||
(cmd->second.first.find(state) != cmd->second.first.end())) {
return true;
}
ers::warning(InvalidState(ERS_HERE, get_name(), cmd_name, state));
}
return false;
}
Expand Down
Loading
Loading