Class Application

class Application : public holoscan::Fragment

Application class.

An application acquires and processes streaming data. An application is a collection of fragments where each fragment can be allocated to execute on a physical node of a Holoscan cluster.

Public Functions

explicit Application(const std::vector<std::string> &argv = {})

Construct a new Application object.

This constructor parses the command line for flags that are recognized by App Driver/Worker, and removes all recognized flags so users can use the remaining flags for their own purposes.

The command line arguments are retrieved from /proc/self/cmdline so that the single-fragment application works as expected without any command line arguments.

The arguments after processing arguments are stored in the argv_ member variable and the reference to the vector of arguments can be accessed through the argv() method.

Parameters
~Application() override = default
template<typename FragmentT = Fragment, typename StringT, typename ...ArgsT, typename = std::enable_if_t<std::is_constructible_v<std::string, StringT>>>
inline std::shared_ptr<Fragment> make_fragment(const StringT &name, ArgsT&&... args)

Create a new fragment.

Template Parameters
Parameters
Returns
template<typename FragmentT, typename ...ArgsT>
inline std::shared_ptr<FragmentT> make_fragment(ArgsT&&... args)

Create a new fragment.

Template Parameters
Parameters
Returns
std::string &description()

Get the application description.

Returns
Application &description(const std::string &desc) &

Set the application description.

Parameters
Returns
Application &&description(const std::string &desc) &&

Set the application description.

Parameters
Returns
std::string &version()

Get the application version.

Returns
Application &version(const std::string &version) &

Set the application version.

Parameters
Returns
Application &&version(const std::string &version) &&

Set the application version.

Parameters
Returns
std::vector<std::string> &argv()

Get the reference to the command line arguments after processing flags.

The returned vector includes the executable name as the first element.

Returns
CLIOptions &options()

Get the reference to the CLI options.

Returns
FragmentGraph &fragment_graph()

Get the fragment connection graph.

When two operators are connected through add_flow(Fragment, Fragment), the fragment connection graph is automatically updated. The fragment connection graph is used to assign transmitters and receivers to the corresponding Operator instances in the fragment so that the application can be executed in a distributed manner.

Returns
virtual void add_fragment(const std::shared_ptr<Fragment> &frag)

Add a fragment to the graph.

The information of the fragment is stored in the Graph object. If the fragment is already added, this method does nothing.

Parameters
virtual void add_flow(const std::shared_ptr<Fragment> &upstream_frag, const std::shared_ptr<Fragment> &downstream_frag, std::set<std::pair<std::string, std::string>> port_pairs)

Add a flow between two fragments.

It takes two fragments and a vector of string pairs as arguments. The vector of string pairs is used to connect the output ports of the first fragment to the input ports of the second fragment. The input and output ports of the operators are specified as a string in the format of <operator name>.<port name>. If the operator has only one input or output port, the port name can be omitted.

In the above example, the output port of the blur_image operator in fragment1 is connected to the input port of the sharpen_image operator in fragment2. Since blur_image and sharpen_image operators have only one output/input port, the port names are omitted.

The information about the flow (edge) is stored in the Graph object and can be accessed through the fragment_graph() method.

If the upstream fragment or the downstream fragment is not in the graph, it will be added to the graph.

Parameters
virtual void run() override
virtual std::future<void> run_async() override

Initialize the graph and run the graph asynchronously.

This method calls compose() to compose the graph, and runs the graph asynchronously.

Returns
virtual void add_flow(const std::shared_ptr<Operator> &upstream_op, const std::shared_ptr<Operator> &downstream_op)

Add a flow between two operators.

An output port of the upstream operator is connected to an input port of the downstream operator. The information about the flow (edge) is stored in the Graph object.

If the upstream operator or the downstream operator is not in the graph, it will be added to the graph.

If there are multiple output ports in the upstream operator or multiple input ports in the downstream operator, it shows an error message.

Parameters
virtual void add_flow(const std::shared_ptr<Operator> &upstream_op, const std::shared_ptr<Operator> &downstream_op, std::set<std::pair<std::string, std::string>> port_pairs)

Add a flow between two operators.

An output port of the upstream operator is connected to an input port of the downstream operator. The information about the flow (edge) is stored in the Graph object.

If the upstream operator or the downstream operator is not in the graph, it will be added to the graph.

In port_pairs, an empty port name (“”) can be used for specifying a port name if the operator has only one input/output port.

If a non-existent port name is specified in port_pairs, it first checks if there is a parameter with the same name but with a type of std::vector<holoscan::IOSpec*> in the downstream operator. If there is such a parameter (e.g., receivers), it creates a new input port with a specific label (<parameter name>:<index>. e.g., receivers:0), otherwise it shows an error message.

For example, if a parameter receivers want to have an arbitrary number of receivers,

Instead of creating a fixed number of input ports (e.g., source_video and tensor) and assigning them to the parameter (receivers): You can skip the creation of input ports and assign them to the parameter (receivers) as follows: This makes the following code possible in the Application’s compose() method: Instead of: By using the parameter (receivers) with std::vector<holoscan::IOSpec*> type, the framework creates input ports (receivers:0 and receivers:1) implicitly and connects them (and adds the references of the input ports to the receivers vector).

Parameters

Protected Functions

AppDriver &driver()

Get the application driver.

Returns
AppWorker &worker()

Get the application worker.

Returns
void process_arguments()

Protected Attributes

std::string app_description_ = {}
std::string app_version_ = {"0.0.0"}
CLIParser cli_parser_
std::vector<std::string> argv_
std::unique_ptr<FragmentGraph> fragment_graph_
std::shared_ptr<AppDriver> app_driver_
std::shared_ptr<AppWorker> app_worker_

Protected Static Functions

static expected<SchedulerType, ErrorCode> get_distributed_app_scheduler_env()
static expected<bool, ErrorCode> get_stop_on_deadlock_env()
static expected<int64_t, ErrorCode> get_stop_on_deadlock_timeout_env()
static expected<int64_t, ErrorCode> get_max_duration_ms_env()
static expected<double, ErrorCode> get_check_recession_period_ms_env()
static void set_scheduler_for_fragments(std::vector<FragmentNodeType> &target_fragments)

Set the scheduler for fragments object.

Set scheduler for each fragment to use multi-thread scheduler by default because UCXTransmitter/UCXReceiver doesn’t work with GreedyScheduler with the following graph.

With the following graph connections, due to how UCXTransmitter/UCXReceiver works, UCX connections between op1 and op3 and between op2 and op3 are not established (resulting in a deadlock).

  • op1.out -> op3.in1

  • op2.out -> op3.in2

Parameters

Friends

friend class AppDriver
friend class AppWorker

© Copyright 2022-2023, NVIDIA. Last updated on Sep 13, 2023.