Jump to content

Code-Level API Evolution

From RidgeRun Developer Wiki

🚧 Documentation is under development

The Holoscan SDK guide is currently under active development. Some sections may be incomplete or change without notice.

Questions? Contact RidgeRun or email to support@ridgerun.com.

Contents Pin





Code-Level API Evolution

After the graph and timing decisions are clear, update the operator code in small, testable changes. Start with one scalar path, confirm its output and completion behavior, then add parameters, Tensor payloads, device work, and external boundaries as the application requires.

The graph structure and timing choices pages provide the decisions used by the example below.


Porting and optimization support
For help porting your operators and checking that data formats and memory handling still match your application, contact RidgeRun.


Translate one operator at a time

Code area Migration action
Operator declaration Use Operator<Params> when the operator has typed configuration. Keep input and output payload types in the port declarations.
Port and storage setup Declare ports and capacity in setup().
Activation behavior Return a holoscan::Contract from contract() so the runtime can prepare the activation.
Work and error handling Process the selected data in compute() and return checked receive, emit, and processing errors.
Application startup Use holoscan::compile() to create an ExecutionPlan, check plan.ok(), and run the accepted plan with holoscan::run(). Keep device, model, permission, and external-peer checks at the application boundary.

A complete small example

The following program has a clock-driven scalar source and an input-driven sink. The source emits ten values, the sink prints them, and the application checks compilation before running. The public types used here are holoscan::Graph, holoscan::RealtimeClock, and holoscan::ComputeCalls. Build it with the environment described in Run SDK Examples. Its console output demonstrates data flow; it is not a performance measurement.

#include <chrono>
#include <cstdint>
#include <iostream>
#include <utility>
#include <holoscan/core/compile.hpp>
#include <holoscan/core/graph.hpp>
#include <holoscan/core/operator.hpp>
#include <holoscan/core/operator_spec.hpp>
#include <holoscan/core/run.hpp>
#include <holoscan/core/temporal_contract.hpp>
#include <holoscan/time/realtime_clock.hpp>

class MeasurementSource final : public holoscan::Operator<> {
 public:
  holoscan::Output<std::uint32_t> output;

  void setup(holoscan::OperatorSpec& spec) override {
    spec.output(output, "output").max_emits_per_compute(1U);
  }

  holoscan::Contract contract() const override {
    holoscan::Contract result;
    result.trigger(holoscan::OnClock{.period = std::chrono::milliseconds{10}})
        .complete_after(holoscan::ComputeCalls{.limit = 10U});
    return result;
  }

  holoscan::expected<void, holoscan::Error> compute(
      holoscan::ExecutionContext&) override {
    return output.emit(++next_);
  }

 private:
  std::uint32_t next_{};
};

class MeasurementSink final : public holoscan::Operator<> {
 public:
  holoscan::Input<std::uint32_t> input;

  void setup(holoscan::OperatorSpec& spec) override {
    spec.input(input, "input").queue_depth(4U);
  }

  holoscan::Contract contract() const override {
    holoscan::Contract result;
    result.trigger(holoscan::OnEach{input});
    return result;
  }

  holoscan::expected<void, holoscan::Error> compute(
      holoscan::ExecutionContext&) override {
    auto sample = input.receive();
    if (!sample) {
      return holoscan::make_unexpected(std::move(sample).error());
    }
    std::cout << sample->data << '\n';
    return {};
  }
};

int main() {
  holoscan::Graph graph{"measurement-migration"};
  auto source = graph.op<MeasurementSource>("source");
  auto sink = graph.op<MeasurementSink>("sink");
  graph.add_flow(source-&gt;output, sink-&gt;input,
                 holoscan::ConnectionOptions{.queue_depth = 4U});
  graph.set_default_clock(graph.add_clock<holoscan::RealtimeClock>("clock"));

  const holoscan::ExecutionPlan plan = holoscan::compile(graph);
  if (!plan.ok()) {
    std::cerr &lt;&lt; plan.json() &lt;&lt; '\n';
    return 1;
  }
  return holoscan::run(plan);
}

The source uses the checked Output::emit() result. A failed publication reaches the callback result. The sink checks Input::receive() before reading the value. The complete_after() rule limits successful source calls; the clock period only determines when the source becomes eligible.

Add parameters and Tensor data after the small path works

For configuration, define a parameter aggregate, use Operator<Params>, set defaults in the aggregate, and apply authoring values before compilation. Typed Parameters and Configuration covers defaults, validation, graph-side overrides, and authorized runtime updates.

For Tensor payloads, define the representation, shape, layout, memory placement, and capacity before writing the operator body. Acquire output storage, write it on the framework-provided stream, commit it, and publish the result. Tensor Contracts and Memory Types explains the data contract, and Writing Tensor Operators shows the checked operator path.

For an external peer, migrate the endpoint and payload contract after the in-process path works. External Endpoints and Endpoint Catalogs covers the boundary and Standalone ChannelRuntime Clients covers a separately launched client.

Check each boundary before scaling the port

Run the small path and check:

  • the first value and final value are produced as expected
  • the source completes at the intended point
  • a failed receive or publication is visible to the application
  • a missing or late input follows the selected temporal policy
  • a Tensor or external payload keeps its declared format and ownership

When those checks pass, continue into the relevant operator, Tensor, camera, or interprocess guide. The migration is complete when the intended behavior survives these cases, not when every old symbol has simply disappeared.


Related examples and concepts

Examples

Concepts

Official documentation

NVIDIA Holoscan SDK official documentation provides the current application and API reference.


Cookies help us deliver our services. By using our services, you agree to our use of cookies.