From ff223331555d421d0fd4edd2dc1a9ff778d7e17a Mon Sep 17 00:00:00 2001 From: Wendell Hom Date: Mon, 1 Jul 2024 15:55:14 -0700 Subject: [PATCH] Holoscan SDK v2.2.0 Release Co-authored-by: Cristiana Dinea Co-authored-by: Gigon Bae Co-authored-by: Gregory Lee Co-authored-by: Julien Jomier Co-authored-by: Shekhar Dwivedi Co-authored-by: Tom Birdsong Co-authored-by: Victor Chang Co-authored-by: Wendell Hom --- .github/ISSUE_TEMPLATE/bug_report.md | 32 + .github/ISSUE_TEMPLATE/feature_request.md | 20 + .../ISSUE_TEMPLATE/questions-and-support.md | 17 + .gitignore | 3 + .vscode/launch.json | 95 ++- CODE_OF_CONDUCT | 4 + CONTRIBUTING.md | 67 +- DEVELOP.md | 2 +- README.md | 6 + VERSION | 2 +- docs/api/holoscan_cpp_api.md | 2 +- docs/components/conditions.md | 10 + docs/conf.py | 32 +- docs/holoscan_create_app.md | 152 ++++- docs/holoscan_create_operator.md | 44 +- ...oloscan_create_operator_python_bindings.md | 9 +- docs/holoscan_packager.md | 31 + .../holoscan_tensor_interoperability.png | Bin 440439 -> 168737 bytes docs/inference.md | 6 + docs/sdk_installation.md | 6 +- examples/CMakeLists.txt | 1 + examples/README.md | 4 + examples/conditions/CMakeLists.txt | 4 +- .../expiring_message/CMakeLists.txt | 25 + .../conditions/expiring_message/README.md | 51 ++ .../expiring_message/cpp/CMakeLists.min.txt | 46 ++ .../expiring_message/cpp/CMakeLists.txt | 79 +++ .../cpp/ping_expiring_message.cpp | 126 ++++ .../cpp/ping_expiring_message.yaml | 18 + .../expiring_message/python/CMakeLists.txt | 42 ++ .../python/ping_expiring_message.py | 126 ++++ examples/holoviz/cpp/holoviz_geometry.cpp | 8 +- .../cpp/import_gxf_components.cpp | 3 +- examples/multi_branch_pipeline/README.md | 2 +- examples/multithread/README.md | 4 +- examples/multithread/cpp/multithread.cpp | 5 +- .../ping_distributed/cpp/ping_distributed.cpp | 11 +- examples/python_decorator/CMakeLists.txt | 43 ++ examples/python_decorator/README.md | 41 ++ examples/python_decorator/video_replayer.py | 92 +++ examples/resources/CMakeLists.txt | 3 +- examples/resources/native/CMakeLists.txt | 25 + examples/resources/native/README.md | 47 ++ .../resources/native/cpp/CMakeLists.min.txt | 46 ++ examples/resources/native/cpp/CMakeLists.txt | 70 +++ .../resources/native/cpp/native_resource.cpp | 32 +- .../resources/native/python/CMakeLists.txt | 45 ++ .../native/python/native_resource.py | 80 +++ examples/v4l2_camera/cpp/v4l2_camera.cpp | 6 +- include/holoscan/core/application.hpp | 6 +- include/holoscan/core/codec_registry.hpp | 4 +- include/holoscan/core/component_spec-inl.hpp | 4 +- include/holoscan/core/condition.hpp | 26 + .../core/conditions/gxf/expiring_message.hpp | 108 ++++ .../core/conditions/gxf/message_available.hpp | 2 +- include/holoscan/core/config.hpp | 7 +- include/holoscan/core/domain/tensor.hpp | 2 +- include/holoscan/core/endpoint.hpp | 4 +- include/holoscan/core/execution_context.hpp | 2 + include/holoscan/core/executor.hpp | 4 + .../core/executors/gxf/gxf_executor.hpp | 5 +- include/holoscan/core/fragment.hpp | 34 +- include/holoscan/core/graph.hpp | 6 +- include/holoscan/core/gxf/entity.hpp | 5 +- include/holoscan/core/gxf/gxf_component.hpp | 3 +- .../core/gxf/gxf_execution_context.hpp | 1 + include/holoscan/core/gxf/gxf_io_context.hpp | 3 +- include/holoscan/core/io_context.hpp | 81 +-- include/holoscan/core/io_spec.hpp | 10 +- .../resources/gxf/gxf_component_resource.hpp | 2 +- .../core/services/common/virtual_operator.hpp | 4 +- .../core/system/gpu_resource_monitor.hpp | 6 +- include/holoscan/holoscan.hpp | 9 +- .../operators/aja_source/aja_source.hpp | 4 +- .../bayer_demosaic/bayer_demosaic.hpp | 11 +- .../holoscan/operators/holoviz/holoviz.hpp | 6 +- .../operators/inference/inference.hpp | 7 +- .../segmentation_postprocessor.hpp | 5 +- .../v4l2_video_capture/v4l2_video_capture.hpp | 9 +- .../video_stream_recorder.hpp | 2 +- modules/holoinfer/src/include/holoinfer.hpp | 5 +- .../src/include/holoinfer_buffer.hpp | 26 +- .../src/include/holoinfer_constants.hpp | 6 +- modules/holoinfer/src/infer/onnx/core.cpp | 24 +- modules/holoinfer/src/infer/torch/core.cpp | 16 +- modules/holoinfer/src/infer/trt/core.cpp | 8 +- .../holoinfer/src/manager/infer_manager.cpp | 50 +- .../holoinfer/src/manager/infer_manager.hpp | 5 +- modules/holoinfer/src/params/infer_param.hpp | 2 +- python/holoscan/CMakeLists.txt | 13 +- python/holoscan/__init__.py | 8 +- .../holoscan/cli/common/artifact_sources.py | 2 +- python/holoscan/conditions/CMakeLists.txt | 1 + python/holoscan/conditions/__init__.py | 3 + python/holoscan/conditions/conditions.cpp | 2 + python/holoscan/conditions/count.cpp | 2 +- .../holoscan/conditions/expiring_message.cpp | 157 +++++ .../conditions/expiring_message_pydoc.hpp | 95 +++ python/holoscan/core/__init__.py | 28 +- python/holoscan/core/component.cpp | 99 +-- python/holoscan/core/component.hpp | 89 +++ python/holoscan/core/component_pydoc.hpp | 10 +- python/holoscan/core/condition.cpp | 7 +- .../core/emitter_receiver_registry.hpp | 22 +- python/holoscan/core/emitter_receivers.hpp | 44 +- python/holoscan/core/execution_context.cpp | 3 +- python/holoscan/core/fragment.cpp | 6 +- python/holoscan/core/gil_guarded_pyobject.hpp | 24 +- python/holoscan/core/io_context.cpp | 29 +- python/holoscan/core/io_context.hpp | 3 +- python/holoscan/core/io_spec.cpp | 26 +- python/holoscan/core/kwarg_handling.cpp | 21 +- python/holoscan/core/operator.cpp | 17 +- python/holoscan/core/operator_pydoc.hpp | 14 + python/holoscan/core/resource.cpp | 35 +- python/holoscan/core/resource_pydoc.hpp | 7 + python/holoscan/core/tensor.cpp | 12 +- python/holoscan/decorator.py | 577 ++++++++++++++++++ .../operators/aja_source/aja_source.cpp | 55 +- .../bayer_demosaic/bayer_demosaic.cpp | 2 +- .../operators/gxf_codelet/gxf_codelet.cpp | 2 +- .../operators/inference/inference.cpp | 19 +- python/holoscan/operators/inference/pydoc.hpp | 2 + python/holoscan/operators/operator_util.hpp | 6 +- python/holoscan/resources/__init__.py | 2 +- .../resources/gxf_component_resource.cpp | 2 +- python/tests/system/test_decorator_apps.py | 179 ++++++ python/tests/unit/test_conditions.py | 37 ++ python/tests/unit/test_core.py | 111 +++- python/tests/unit/test_decorator.py | 346 +++++++++++ python/tests/unit/test_gxf.py | 14 +- python/tests/unit/test_network_context.py | 7 +- python/tests/unit/test_operators_native.py | 23 + python/tests/unit/test_resources.py | 80 ++- python/tests/unit/test_schedulers.py | 15 +- src/CMakeLists.txt | 1 + src/common/logger/spdlog_logger.cpp | 5 +- src/core/app_driver.cpp | 30 +- src/core/app_worker.cpp | 16 +- src/core/application.cpp | 7 +- src/core/cli_parser.cpp | 5 +- src/core/condition.cpp | 27 +- src/core/conditions/gxf/asynchronous.cpp | 8 +- src/core/conditions/gxf/expiring_message.cpp | 96 +++ src/core/dataflow_tracker.cpp | 19 +- src/core/executors/gxf/gxf_executor.cpp | 82 ++- src/core/fragment.cpp | 40 +- src/core/gxf/gxf_condition.cpp | 6 + src/core/gxf/gxf_execution_context.cpp | 4 +- src/core/gxf/gxf_extension_manager.cpp | 4 +- src/core/gxf/gxf_io_context.cpp | 21 +- src/core/gxf/gxf_resource.cpp | 9 +- src/core/messagelabel.cpp | 8 +- src/core/operator.cpp | 4 +- .../gxf/annotated_double_buffer_receiver.cpp | 2 +- src/core/resources/gxf/dfft_collector.cpp | 9 +- src/core/schedulers/gxf/greedy_scheduler.cpp | 2 +- src/core/services/app_driver/client.cpp | 9 +- src/core/services/app_driver/service_impl.cpp | 5 +- src/core/services/app_worker/client.cpp | 4 +- src/core/signal_handler.cpp | 8 +- src/core/system/cpu_resource_monitor.cpp | 14 +- src/core/system/gpu_resource_monitor.cpp | 14 +- src/logger/logger.cpp | 5 +- src/operators/aja_source/aja_source.cpp | 2 +- .../bayer_demosaic/bayer_demosaic.cpp | 7 + .../format_converter/format_converter.cpp | 14 +- src/operators/inference/inference.cpp | 17 +- .../inference_processor.cpp | 5 +- .../v4l2_video_capture/v4l2_video_capture.cpp | 10 +- .../video_stream_recorder.cpp | 11 +- src/utils/cuda_stream_handler.cpp | 4 +- src/utils/holoinfer_utils.cpp | 12 +- tests/CMakeLists.txt | 9 +- tests/core/application.cpp | 10 +- tests/core/arg.cpp | 34 +- tests/core/argument_setter.cpp | 8 +- tests/core/condition.cpp | 31 +- tests/core/condition_classes.cpp | 17 +- tests/core/dataflow_tracker.cpp | 4 +- tests/core/fragment.cpp | 27 +- tests/core/resource.cpp | 32 +- tests/data/loading_gxf_extension.yaml | 19 + tests/holoinfer/inference/test_core.cpp | 6 +- tests/holoinfer/inference/test_core.hpp | 1 + tests/operators/operator_classes.cpp | 4 +- .../test_postprocessor.cpp | 60 +- tests/system/distributed/distributed_app.cpp | 3 +- .../ucx_message_serialization_ping_app.cpp | 4 +- tests/system/loading_gxf_extension.cpp | 175 ++++++ 190 files changed, 4695 insertions(+), 702 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md create mode 100644 .github/ISSUE_TEMPLATE/questions-and-support.md create mode 100644 CODE_OF_CONDUCT create mode 100644 examples/conditions/expiring_message/CMakeLists.txt create mode 100644 examples/conditions/expiring_message/README.md create mode 100644 examples/conditions/expiring_message/cpp/CMakeLists.min.txt create mode 100644 examples/conditions/expiring_message/cpp/CMakeLists.txt create mode 100644 examples/conditions/expiring_message/cpp/ping_expiring_message.cpp create mode 100644 examples/conditions/expiring_message/cpp/ping_expiring_message.yaml create mode 100644 examples/conditions/expiring_message/python/CMakeLists.txt create mode 100644 examples/conditions/expiring_message/python/ping_expiring_message.py create mode 100644 examples/python_decorator/CMakeLists.txt create mode 100644 examples/python_decorator/README.md create mode 100644 examples/python_decorator/video_replayer.py create mode 100644 examples/resources/native/CMakeLists.txt create mode 100644 examples/resources/native/README.md create mode 100644 examples/resources/native/cpp/CMakeLists.min.txt create mode 100644 examples/resources/native/cpp/CMakeLists.txt rename tests/system/native_resource_minimal_app.cpp => examples/resources/native/cpp/native_resource.cpp (74%) create mode 100644 examples/resources/native/python/CMakeLists.txt create mode 100644 examples/resources/native/python/native_resource.py create mode 100644 include/holoscan/core/conditions/gxf/expiring_message.hpp create mode 100644 python/holoscan/conditions/expiring_message.cpp create mode 100644 python/holoscan/conditions/expiring_message_pydoc.hpp create mode 100644 python/holoscan/core/component.hpp create mode 100644 python/holoscan/decorator.py create mode 100644 python/tests/system/test_decorator_apps.py create mode 100644 python/tests/unit/test_decorator.py create mode 100644 src/core/conditions/gxf/expiring_message.cpp create mode 100644 tests/data/loading_gxf_extension.yaml create mode 100644 tests/system/loading_gxf_extension.cpp diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000..d41c6a3e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,32 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: bug, help wanted +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Platform Information (please complete the following information):** + - Holoscan SDK Version [e.g. 2.1.0] +- Architecture: [x86_64, arm64] + - OS: [Ubuntu, RHEL, IGX SW OS] + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 00000000..dcb4a88a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: enhancement, help wanted +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/ISSUE_TEMPLATE/questions-and-support.md b/.github/ISSUE_TEMPLATE/questions-and-support.md new file mode 100644 index 00000000..66def445 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/questions-and-support.md @@ -0,0 +1,17 @@ +--- +name: Questions and Support +about: Request information on Holoscan SDK features and best practices +title: '' +labels: help wanted +assignees: '' + +--- + +## Please describe your question +Ask about Holoscan SDK features or best practices. For example, "Does Holoscan SDK support v4l2 compatible cameras?" +  +## Please specify what Holoscan SDK version you are using +latest + +## Please add any details about your platform or use case +For instance, "IGX devkit" diff --git a/.gitignore b/.gitignore index b8d8ffb8..598a012d 100644 --- a/.gitignore +++ b/.gitignore @@ -53,6 +53,9 @@ _deps runtime_docker/install runtime_docker/*.txt +# file autogenerated by setuptools_scm +_version.py + # PyInstaller # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. diff --git a/.vscode/launch.json b/.vscode/launch.json index 3724ee49..2977a916 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -157,7 +157,7 @@ ] }, { - "name": "(gdb) examples/conditions/asynchronous/cpp/ping_async", + "name": "(gdb) examples/conditions/asynchronous/cpp", "type": "cppdbg", "request": "launch", "program": "${command:cmake.buildDirectory}/examples/conditions/asynchronous/cpp/ping_async", @@ -184,7 +184,98 @@ ] }, { - "name": "(gdb) examples/conditions/periodic/cpp/periodic_ping", + "name": "(gdb) examples/conditions/asynchronous/python", + "type": "cppdbg", + "request": "launch", + "program": "/usr/bin/bash", + "args": [ + "${workspaceFolder}/${env:HOLOSCAN_PUBLIC_FOLDER}/.vscode/debug_python", + "${workspaceFolder}/${env:HOLOSCAN_PUBLIC_FOLDER}/examples/conditions/asynchronous/python/ping_async.py", + ], + "stopAtEntry": false, + "cwd": "${command:cmake.buildDirectory}", + "environment": [ + { + "name": "HOLOSCAN_LOG_LEVEL", + "value": "DEBUG" + }, + { + "name": "PYTHONPATH", + "value": "${command:cmake.buildDirectory}/python/lib" + }, + ], + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ] + }, + { + "name": "(gdb) examples/conditions/expiring_message/cpp", + "type": "cppdbg", + "request": "launch", + "program": "${command:cmake.buildDirectory}/examples/conditions/expiring_message/cpp/ping_expiring_message", + "args": [], + "stopAtEntry": false, + "cwd": "${command:cmake.buildDirectory}", + "environment": [ + { + "name": "HOLOSCAN_LOG_LEVEL", + "value": "INFO" + }, + { + "name": "HOLOSCAN_LOG_FORMAT", + "value": "long" + }, + ], + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ] + }, + { + "name": "(gdb) examples/conditions/expiring_message/python", + "type": "cppdbg", + "request": "launch", + "program": "/usr/bin/bash", + "args": [ + "${workspaceFolder}/${env:HOLOSCAN_PUBLIC_FOLDER}/.vscode/debug_python", + "${workspaceFolder}/${env:HOLOSCAN_PUBLIC_FOLDER}/examples/conditions/expiring_message/python/ping_expiring_message.py", + ], + "stopAtEntry": false, + "cwd": "${command:cmake.buildDirectory}", + "environment": [ + { + "name": "HOLOSCAN_LOG_LEVEL", + "value": "INFO" + }, + { + "name": "HOLOSCAN_LOG_FORMAT", + "value": "long" + }, + { + "name": "PYTHONPATH", + "value": "${command:cmake.buildDirectory}/python/lib" + }, + ], + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ] + }, + { + "name": "(gdb) examples/conditions/periodic/cpp", "type": "cppdbg", "request": "launch", "program": "${command:cmake.buildDirectory}/examples/conditions/periodic/cpp/periodic_ping", diff --git a/CODE_OF_CONDUCT b/CODE_OF_CONDUCT new file mode 100644 index 00000000..27995902 --- /dev/null +++ b/CODE_OF_CONDUCT @@ -0,0 +1,4 @@ +We observe the [RAPIDS Contributor Covenant Code of Conduct](https://docs.rapids.ai/resources/conduct/) +to foster a positive Holoscan community. + +Please report any instances of conduct violations to holoscan-conduct@nvidia.com. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index cd278284..b57125f2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,3 +1,66 @@ -The Holoscan SDK is released on GitHub to better support the community and facilitate feedback. +# Contribute to Holoscan SDK -If you find any issues with the SDK please report them using GitHub [Issues](https://github.com/nvidia-holoscan/holoscan-sdk/issues). +Welcome to Holoscan SDK! We're glad that you're considering contributing to the platform. + +Holoscan SDK is released on GitHub as open source software to better support the community and facilitate feedback. By +contributing you agree to follow our [code of conduct](./CODE_OF_CONDUCT). + +## Reporting Feedback + +Community feedback helps us improve the Holoscan SDK platform to better meet user needs. We use GitHub [Issues](https://github.com/nvidia-holoscan/holoscan-sdk/issues) to track feedback and problems over time, as well as to provide +limited support to Holoscan SDK users. + +Consider reviewing existing issues or opening a new issue if you: +- Have a question about using a Holoscan SDK feature +- Notice errors or unexpected behavior coming from Holoscan SDK +- Have an idea for a change that might benefit other users + +When reporting an error, please include relevant details that will help our team investigate the issue. Details might include: +- A summary of the problem +- The behavior you have observed +- The behavior you expected +- Details about your PC, including the architecture (x86_64 or arm64) and GPU +- The version of Holoscan SDK where you observed the problem +- Any relevant logs or images to help investigate the issue + +You can also refer to the Holoscan SDK [NVIDIA Developer Forums](https://forums.developer.nvidia.com/c/healthcare/holoscan-sdk/) for support questions and community discussions. + +## Suggesting Changes + +Users are welcome to suggest code changes to Holoscan SDK in the form of [Issues](https://github.com/nvidia-holoscan/holoscan-sdk/issues) or [Pull Requests](https://github.com/nvidia-holoscan/holoscan-sdk/pulls). + +### Issues + +Please open a new [issue](https://github.com/nvidia-holoscan/holoscan-sdk/issues) if you'd like to request a new feature +or propose a feature design. You can tag a specific community maintainer in your post with "@", or we'll update +when we've had a chance to review your post. + +### Pull Requests + +While we primarily develop Holoscan SDK internally, we also accept external contributions that help move the platform +forward. We typically favor contributions that aim to fix an existing issue or improve documentation, but we'll also integrate new features +and enhancements when they're aligned with the Holoscan SDK vision. Please check in with the development team to propose your idea before spending time working on new features. This will help prevent duplicate effort and avoid spending time on features that would be unlikely to be merged. We'll typically refer new operators for contribution +to the downstream [HoloHub](https://github.com/nvidia-holoscan/holohub) community project. + +You might contribute to Holoscan to help us address fixes earlier in our development cycle, or to suggest improvements to Holoscan SDK that you believe would broadly benefit the Holoscan community. + +Holoscan SDK follows a monthly release process that includes internal quality assurance. To add a fix or feature, +we request that you [fork](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/fork-a-repo) Holoscan SDK, develop in a branch, and submit your change as a [pull request](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request) against the latest Holoscan SDK release commit. If we accept your submission after external discussion, we will integrate those changes within our internal development and credit you in Git commit history. Any changes that we accept from community contributions will undergo quality assurance testing before they are included in the next Holoscan SDK release. + +**Note**: We recommend that new GitHub users read GitHub's [Getting Started](https://docs.github.com/en/get-started/start-your-journey) guide before opening their first pull request. + +## Tracking Development + +We take all community feedback into consideration. If we don't believe a proposed change aligns with our direction +for Holoscan SDK, or if we don't expect we can prioritize a task within a reasonable timeframe, we'll let you +know by appropriately labeling or closing the issue or pull request with an explanatory comment. + +For items that we do plan to pursue or integrate, we use +[GitHub Milestones](https://github.com/nvidia-holoscan/holoscan-sdk/milestones) +to communicate our release planning. We will add community issues and pull requests to the approximate monthly release +milestone when we expect to pursue that development. Issues that we mark as "needs triage" are not part of a milestone +and will be revisited once each month to determine our priorities. + +## Additional Information + +Please refer to the project [README](/README.md) document for additional developer information. Happy coding! diff --git a/DEVELOP.md b/DEVELOP.md index df13cc4d..b4eab4d0 100644 --- a/DEVELOP.md +++ b/DEVELOP.md @@ -84,7 +84,7 @@ To build the Holoscan SDK on a local environment, the following versions of dev | CUDA | 12.2 | Core SDK | base | | gRPC | 1.54.2 | Core SDK | grpc-builder | | UCX | 1.15.0 | Core SDK | ucx-builder | -| GXF | 3.1 | Core SDK | gxf-downloader | +| GXF | 4.0 | Core SDK | gxf-downloader | | MOFED | 23.07 | ConnectX | mofed-installer | | TensorRT | 8.6.1 | Inference operator | base | | ONNX Runtime | 1.15.1 | Inference operator | onnxruntime-downloader | diff --git a/README.md b/README.md index 2ff38d1c..085eeb8e 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,12 @@ We appreciate community discussion and feedback in support of Holoscan platform - Direct questions to the [NVIDIA Support Forum](https://forums.developer.nvidia.com/c/healthcare/holoscan-sdk/320/all). - Enter SDK issues on the [SDK GitHub Issues board](https://github.com/nvidia-holoscan/holoscan-sdk/issues). +## Contributing to Holoscan SDK + +Holoscan SDK is developed internally and released as open source software. We welcome community contributions +and may include them in Holoscan SDK releases at our discretion. Please refer to the Holoscan SDK +[Contributing Guide](/CONTRIBUTING.md) for more information. + ## Additional Notes ### Relation to NVIDIA Clara diff --git a/VERSION b/VERSION index 50aea0e7..e3a4f193 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.1.0 \ No newline at end of file +2.2.0 \ No newline at end of file diff --git a/docs/api/holoscan_cpp_api.md b/docs/api/holoscan_cpp_api.md index 019004d6..66910916 100644 --- a/docs/api/holoscan_cpp_api.md +++ b/docs/api/holoscan_cpp_api.md @@ -189,7 +189,7 @@ - {ref}`exhale_class_classholoscan_1_1Tensor` - {ref}`exhale_class_classholoscan_1_1TensorMap` -- {ref}`exhale_struct_structholoscan_1_1DLManagedTensorCtx` +- {ref}`exhale_struct_structholoscan_1_1DLManagedTensorContext` - {ref}`exhale_class_classholoscan_1_1DLManagedMemoryBuffer` ##### Functions diff --git a/docs/components/conditions.md b/docs/components/conditions.md index 03aea753..11fa57e4 100644 --- a/docs/components/conditions.md +++ b/docs/components/conditions.md @@ -20,6 +20,7 @@ The following table shows various states of the scheduling status of an operator By default, operators are always `READY`, meaning they are scheduled to continuously execute their `compute()` method. To change that behavior, some condition classes can be passed to the constructor of an operator. There are various conditions currently supported in the Holoscan SDK: - MessageAvailableCondition +- ExpiringMessageAvailableCondition - DownstreamMessageAffordableCondition - CountCondition - BooleanCondition @@ -46,6 +47,14 @@ An optional parameter for this condition is `front_stage_max_size`, the maximum If this parameter is set, the condition will only allow execution if the number of messages in the queue does not exceed this count. It can be used for operators which do not consume all messages from the queue. +## ExpiringMessageAvailableCondition + +An operator associated with `ExpiringMessageAvailableCondition` ({cpp:class}`C++ `/{py:class}`Python `) is executed when the first message received in the associated queue is expiring or when there are enough messages in the queue. +This condition is associated with a specific input or output port of an operator through the `condition()` method on the return value (IOSpec) of the OperatorSpec's `input()` or `output()` method. + +The parameters ``max_batch_size`` and ``max_delay_ns`` dictate the maximum number of messages to be batched together and the maximum delay from first message to wait before executing the entity respectively. +Please note that `ExpiringMessageAvailableCondition` requires that the input messages sent to any port using this condition must contain a timestamp. This means that the upstream operator has to emit using a timestamp . + ## DownstreamMessageAffordableCondition The `DownstreamMessageAffordableCondition` ({cpp:class}`C++ `/{py:class}`Python `) condition specifies that an operator shall be executed if the input port of the downstream operator for a given output port can accept new messages. @@ -57,6 +66,7 @@ The minimum number of messages that permits the execution of the operator is spe An operator associated with `CountCondition` ({cpp:class}`C++ `/{py:class}`Python `) is executed for a specific number of times specified using its `count` parameter. The scheduling status of the operator associated with this condition can either be in `READY` or `NEVER` state. The scheduling status reaches the `NEVER` state when the operator has been executed `count` number of times. +The `count` parameter can be set to a negative value to indicate that the operator should be executed an infinite number of times (default: `1`). ## BooleanCondition diff --git a/docs/conf.py b/docs/conf.py index c684f39c..1602440e 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,24 +1,24 @@ """ - SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. - SPDX-License-Identifier: Apache-2.0 +SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +SPDX-License-Identifier: Apache-2.0 - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 +http://www.apache.org/licenses/LICENSE-2.0 - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. - Configuration file for the Sphinx documentation builder. +Configuration file for the Sphinx documentation builder. - This file only contains a selection of the most common options. For a full - list see the documentation: - https://www.sphinx-doc.org/en/master/usage/configuration.html +This file only contains a selection of the most common options. For a full +list see the documentation: +https://www.sphinx-doc.org/en/master/usage/configuration.html """ # noqa: E501 import os import textwrap @@ -82,7 +82,7 @@ numfig = True # -- Options for graphviz output --------------------------------------------- -graphviz_output_format = "svg" +graphviz_output_format = "png" # -- Options for HTML output ------------------------------------------------- diff --git a/docs/holoscan_create_app.md b/docs/holoscan_create_app.md index 161775b1..7070805b 100644 --- a/docs/holoscan_create_app.md +++ b/docs/holoscan_create_app.md @@ -292,6 +292,8 @@ load_extensions(context, exts) To be discoverable, paths to these shared libraries need to either be absolute, relative to your working directory, installed in the `lib/gxf_extensions` folder of the holoscan package, or listed under the `HOLOSCAN_LIB_PATH` or `LD_LIBRARY_PATH` environment variables. ::: +Please see other examples in the [system tests](https://github.com/nvidia-holoscan/holoscan-sdk/blob/main/tests/system/loading_gxf_extension.cpp) in the Holoscan SDK repository. + (configuring-app-operators)= ### Configuring operators @@ -510,6 +512,149 @@ def compose(self): ``` ```` + +(configuring-app-operator-native-resources)= + +#### Native resource creation + +The resources bundled with the SDK are wrapping an underlying GXF component. However, it is also possible to define a "native" resource without any need to create and wrap an underlying GXF component. Such a resource can also be passed conditionally to an operator in the same way as the resources created in the previous section. + +For example: + +`````{tab-set} +````{tab-item} C++ +To create a native resource, implement a class that inherits from {cpp:class}`Resource ` + +```{code-block} cpp +namespace holoscan { + +class MyNativeResource : public holoscan::Resource { + public: + HOLOSCAN_RESOURCE_FORWARD_ARGS_SUPER(MyNativeResource, Resource) + + MyNativeResource() = default; + + // add any desired parameters in the setup method + // (a single string parameter is shown here for illustration) + void setup(ComponentSpec& spec) override { + spec.param(message_, "message", "Message string", "Message String", std::string("test message")); + } + + // add any user-defined methods (these could be called from an Operator's compute method) + std::string message() { return message_.get(); } + + private: + Parameter message_; +}; +} // namespace: holoscan +``` + +The `setup` method can be used to define any parameters needed by the resource. + +This resource can be used with a C++ operator, just like any other resource. For example, an operator could have a parameter holding a shared pointer to `MyNativeResource` as below. + +```{code-block} cpp +private: + +class MyOperator : public holoscan::Operator { + public: + HOLOSCAN_OPERATOR_FORWARD_ARGS(MyOperator) + + MyOperator() = default; + + void setup(OperatorSpec& spec) override { + spec.param(message_resource_, "message_resource", "message resource", + "resource printing a message"); + } + + void compute(InputContext&, OutputContext& op_output, ExecutionContext&) override { + HOLOSCAN_LOG_TRACE("MyOp::compute()"); + + // get a resource based on its name (this assumes the app author named the resource "message_resource") + auto res = resource("message_resource"); + if (!res) { + throw std::runtime_error("resource named 'message_resource' not found!"); + } + + // call a method on the retrieved resource class + auto message = res->message(); + + }; + +private: + Parameter message_resource_; +} +``` +The `compute` method above demonstrates how the templated `resource` method can be used to retrieve a resource. + + +and the resource could be created and passed via a named argument in the usual way +```{code-block} cpp + +// example code for within Application::compose (or Fragment::compose) + + auto message_resource = make_resource( + "message_resource", holoscan::Arg("message", "hello world"); + + auto my_op = std::make_operator( + "my_op", holoscan::Arg("message_resource", message_resource)); +``` + +As with GXF-based resources, it is also possible to pass a native resource as a positional argument to the operator constructor. + +For a concreate example of native resource use in a real application, see the [volume_rendering_xr application](https://github.com/nvidia-holoscan/holohub/blob/main/applications/volume_rendering_xr/main.cpp) on Holohub. This application uses a native [XrSession resource](https://github.com/nvidia-holoscan/holohub/blob/main/operators/XrFrameOp/xr_session.hpp) type which corresponds to a single OpenXR session. This single "session" resource can then be shared by both the `XrBeginFrameOp` and `XrEndFrameOp` operators. + +```` +````{tab-item} Python +To create a native resource, implement a class that inherits from {py:class}`Resource `. + +```{code-block} python +class MyNativeResource(Resource): + def __init__(self, fragment, message="test message", *args, **kwargs): + self.message = message + super().__init__(fragment, *args, **kwargs) + + # Could optionally define Parameter as in C++ via spec.param as below. + # Here, we chose instead to pass message as an argument to __init__ above. + # def setup(self, spec: ComponentSpec): + # spec.param("message", "test message") + + # define a custom method + def message(self): + return self.message +``` + +The below shows how some custom operator could use such a resource in its compute method + +```{code-block} python +class MyOperator(Operator): + def compute(self, op_input, op_output, context): + resource = self.resource("message_resource") + if resource is None: + raise ValueError("expected message resource not found") + assert isinstance(resource, MyNativeResource) + + print(f"message = {resource.message()") +``` + +where this native resource could have been created and passed positionally to `MyOperator` as follows + +```{code-block} python + +# example code within Application.compose (or Fragment.compose) + + message_resource = MyNativeResource( + fragment=self, message="hello world", name="message_resource") + + # pass the native resource as a positional argument to MyOperator + my_op = MyOperator(fragment=self, message_resource) +``` +```` +````` + +There is a minimal example of native resource use in the [examples/native](https://github.com/nvidia-holoscan/holoscan-sdk/blob/main/examples/native/) folder. + + (configuring-app-scheduler)= ### Configuring the scheduler @@ -518,14 +663,16 @@ The [scheduler](./components/schedulers.md) controls how the application schedul The default scheduler is a single-threaded [`GreedyScheduler`](./components/schedulers.md#greedy-scheduler). An application can be configured to use a different scheduler `Scheduler` ({cpp:class}`C++ `/{py:class}`Python `) or change the parameters from the default scheduler, using the `scheduler()` function ({cpp:func}`C++ `/{py:func}`Python `). -For example, if an application needs to run multiple operators in parallel, the [`MultiThreadScheduler`](./components/schedulers.md#multithreadscheduler) or [`EventBasedScheduler`](./components/schedulers.md#eventbasedscheduler) can instead be used. The difference between the two is that the MultiThreadScheduler is based on actively polling operators to determine if they are ready to execute, while the EventBasedScheduler will instead wait for an event indicating that an operator is ready to execute. +For example, if an application needs to run multiple operators in parallel, the [`MultiThreadScheduler`](./components/schedulers.md#multithread-scheduler) or [`EventBasedScheduler`](./components/schedulers.md#event-based-scheduler) can instead be used. The difference between the two is that the MultiThreadScheduler is based on actively polling operators to determine if they are ready to execute, while the EventBasedScheduler will instead wait for an event indicating that an operator is ready to execute. The code snippet belows shows how to set and configure a non-default scheduler: `````{tab-set} ````{tab-item} C++ + - We create an instance of a {ref}`holoscan::Scheduler ` derived class by using the {cpp:func}`~holoscan::Fragment::make_scheduler` function. Like operators, parameters can come from explicit {cpp:class}`~holoscan::Arg`s or {cpp:class}`~holoscan::ArgList`, or from a YAML configuration. - The {cpp:func}`~holoscan::Fragment::scheduler` method assigns the scheduler to be used by the application. + ```{code-block} cpp :emphasize-lines: 2-7 :name: holoscan-config-scheduler-cpp @@ -539,10 +686,13 @@ auto scheduler = app->make_scheduler( app->scheduler(scheduler); app->run(); ``` + ```` + ````{tab-item} Python - We create an instance of a `Scheduler` class in the {py:mod}`~holoscan.schedulers` module. Like operators, parameters can come from an explicit {py:class}`~holoscan.core.Arg` or {py:class}`~holoscan.core.ArgList`, or from a YAML configuration. - The {py:func}`~holoscan.core.Fragment.scheduler` method assigns the scheduler to be used by the application. + ```{code-block} python :emphasize-lines: 2-8 :name: holoscan-config-scheduler-python diff --git a/docs/holoscan_create_operator.md b/docs/holoscan_create_operator.md index ca5473c8..517c6fe0 100644 --- a/docs/holoscan_create_operator.md +++ b/docs/holoscan_create_operator.md @@ -419,7 +419,7 @@ class PingRxOp : public holoscan::ops::GXFOperator { The Holoscan SDK provides built-in data types called **{ref}`Domain Objects`**, defined in the `include/holoscan/core/domain` directory. For example, the {cpp:class}`holoscan::Tensor` is a Domain Object class that is used to represent a multi-dimensional array of data, which can be used directly by `OperatorSpec`, `InputContext`, and `OutputContext`. :::{tip} -This {cpp:class}`holoscan::Tensor` class is a wrapper around the {cpp:class}`~holoscan::DLManagedTensorCtx` struct holding a [DLManagedTensor](https://dmlc.github.io/dlpack/latest/c_api.html#_CPPv415DLManagedTensor) object. As such, it provides a primary interface to access Tensor data and is interoperable with other frameworks that support the [DLPack interface](https://dmlc.github.io/dlpack/latest/). +This {cpp:class}`holoscan::Tensor` class is a wrapper around the {cpp:class}`~holoscan::DLManagedTensorContext` struct holding a [DLManagedTensor](https://dmlc.github.io/dlpack/latest/c_api.html#c.DLManagedTensor) object. As such, it provides a primary interface to access Tensor data and is interoperable with other frameworks that support the [DLPack interface](https://dmlc.github.io/dlpack/latest/). ::: :::{warning} @@ -800,9 +800,17 @@ There are no differences in CMake between using a GXF operator and [using a nati ### Interoperability between GXF and native C++ operators To support sending or receiving tensors to and from operators (both GXF and native C++ operators), the Holoscan SDK provides the C++ classes below: -- A class template called {cpp:class}`holoscan::MyMap` which inherits from `std::unordered_map>`. The template parameter `T` can be any type, and it is used to specify the type of the `std::shared_ptr` objects stored in the map. -- -A {cpp:class}`holoscan::TensorMap` class defined as a specialization of `holoscan::Map` for the {cpp:class}`holoscan::Tensor` type. +- A class template called {cpp:class}`holoscan::Map` which inherits from `std::unordered_map>`. The template parameter `T` can be any type, and it is used to specify the type of the `std::shared_ptr` objects stored in the map. +- A {cpp:class}`holoscan::TensorMap` class defined as a specialization of `holoscan::Map` for the {cpp:class}`holoscan::Tensor` type. + +When a message with a {cpp:class}`holoscan::TensorMap` is emitted from a native C++ operator, +the message object is always converted to a {cpp:class}`holoscan::gxf::Entity` object and sent to the +downstream operator. + +Then, if the sent GXF Entity object holds only Tensor object(s) as its components, the downstream operator can receive the message data as a {cpp:class}`holoscan::TensorMap` object instead of a {cpp:class}`holoscan::gxf::Entity` object. + +[{numref}`fig-holoscan-tensor-interoperability`](fig-holoscan-tensor-interoperability) shows the relationship between the {cpp:class}`holoscan::gxf::Entity` and {cpp:class}`nvidia::gxf:Entity` classes and the relationship +between the {cpp:class}`holoscan::Tensor` and {cpp:class}`nvidia::gxf::Tensor` classes. :::{figure-md} fig-holoscan-tensor-interoperability :align: center @@ -813,18 +821,27 @@ A {cpp:class}`holoscan::TensorMap` class defined as a specialization of `holosca Supporting Tensor Interoperability ::: -Consider the following example, where `GXFSendTensorOp` and `GXFReceiveTensorOp` are GXF operators, and where `ProcessTensorOp` is a C++ native operator: +Both {cpp:class}`holoscan::gxf::Tensor` and {cpp:class}`nvidia::gxf::Tensor` are interoperable with each other because they are wrappers around the same underlying {cpp:class}`~holoscan::DLManagedTensorContext` struct holding a [DLManagedTensor](https://dmlc.github.io/dlpack/latest/c_api.html#c.DLManagedTensor) object. + +The `holoscan::TensorMap` class is used to store multiple tensors in a map, where each tensor is associated with a unique key. The `holoscan::TensorMap` class is used to pass multiple tensors between operators, and it is used in the same way as a `std::unordered_map>` object. + +Since both {cpp:class}`holoscan::TensorMap` and {cpp:class}`holoscan::gxf::Entity` objects hold tensors which are interoperable, the message data between GXF and native C++ operators are also interoperable. + +[{numref}`fig-tensor-interop-between-cpp-native-op-and-gxf-op`](fig-tensor-interop-between-cpp-native-op-and-gxf-op) illustrates the use of the `holoscan::TensorMap` class to pass multiple tensors between operators. The `GXFSendTensorOp` operator sends a `nvidia::gxf::Entity` object (containing a `nvidia::gxf::Tensor` object as a GXF component named "tensor") to the `ProcessTensorOp` operator, which processes the tensors and then forwards the processed tensors to the `GXFReceiveTensorOp` operator. + +Consider the following example, where `GXFSendTensorOp` and `GXFReceiveTensorOp` are GXF operators, and where `ProcessTensorOp` is a Holoscan native operator in C++: ```{digraph} interop +:name: fig-tensor-interop-between-cpp-native-op-and-gxf-op :align: center :caption: The tensor interoperability between C++ native operator and GXF operator rankdir="LR" node [shape=record]; - source [label="GXFSendTensorOp| |signal(out) : Tensor"]; + source [label="GXFSendTensorOp| |signal(out) : gxf::Entity"]; process [label="ProcessTensorOp| [in]in : TensorMap | out(out) : TensorMap "]; - sink [label="GXFReceiveTensorOp| [in]signal : Tensor | "]; + sink [label="GXFReceiveTensorOp| [in]signal : gxf::Entity | "]; source->process [label="signal...in"] process->sink [label="out...signal"] @@ -835,14 +852,14 @@ The following code shows how to implement `ProcessTensorOp`'s `compute()` method ```{code-block} cpp :caption: examples/tensor_interop/cpp/tensor_interop.cpp :linenos: true -:lineno-start: 81 -:emphasize-lines: 4,6,20,21,24 +:lineno-start: 86 +:emphasize-lines: 4,6,8,12,17,22,23,26 -void compute(InputContext& op_input, OutputContext& op_output, + void compute(InputContext& op_input, OutputContext& op_output, ExecutionContext& context) override { // The type of `in_message` is 'holoscan::TensorMap'. auto in_message = op_input.receive("in").value(); - // the type of out_message is TensorMap + // The type of out_message is TensorMap TensorMap out_message; for (auto& [key, tensor] : in_message) { // Process with 'tensor' here. @@ -1488,3 +1505,8 @@ This would define To learn more about overriding connectors and/or conditions there is a [multi_branch_pipeline](https://github.com/nvidia-holoscan/holoscan-sdk/blob/main/examples/multi_branch_pipeline) example which overrides default conditions to allow two branches of a pipeline to run at different frame rates. There is also an example of increasing the queue sizes available in [this Python queue policy test application](https://github.com/nvidia-holoscan/holoscan-sdk/blob/main/python/tests/system/test_application_with_repeated_emit_on_same_port.py). +### Using the Holoscan SDK with Other Libraries + +The Holoscan SDK enables seamless integration with various powerful, GPU-accelerated libraries to build efficient, high-performance pipelines. + +Please refer to the [Best Practices to Integrate External Libraries into Holoscan Pipelines](https://github.com/nvidia-holoscan/holohub/blob/main/tutorials/integrate_external_libs_into_pipeline/README.md) tutorial in the [HoloHub](https://github.com/nvidia-holoscan/holohub) repository for detailed examples and more information on Holoscan's tensor interoperability and handling CUDA libraries in the pipeline. This includes [CUDA Python](https://github.com/NVIDIA/cuda-python), [CuPy](https://cupy.dev/), [MatX](https://github.com/NVIDIA/MatX) for C++, [cuCIM](https://github.com/rapidsai/cucim), [CV-CUDA](https://github.com/CVCUDA/CV-CUDA), and [OpenCV](https://opencv.org/) for integration into Holoscan applications. diff --git a/docs/holoscan_create_operator_python_bindings.md b/docs/holoscan_create_operator_python_bindings.md index d9a02204..176cdb85 100644 --- a/docs/holoscan_create_operator_python_bindings.md +++ b/docs/holoscan_create_operator_python_bindings.md @@ -418,10 +418,11 @@ namespace holoscan { */ template <> struct emitter_receiver> { - static void emit(py::object& data, const std::string& name, PyOutputContext& op_output) { + static void emit(py::object& data, const std::string& name, PyOutputContext& op_output, + const int64_t acq_timestamp = -1) { auto input_spec = data.cast>(); py::gil_scoped_release release; - op_output.emit>(input_spec, name.c_str()); + op_output.emit>(input_spec, name.c_str(), acq_timestamp); return; } @@ -494,7 +495,7 @@ When creating Python bindings for an Operator on Holohub, the [pybind11_add_holo For types for which Pybind11's default casting between C++ and Python is adequate, it is not necessary to explicitly define the `emitter_receiver` class as shown in step 1. This is true because there are a couple of [default implementations](https://github.com/nvidia-holoscan/holoscan-sdk/blob/v2.1.0/python/holoscan/core/emitter_receiver_registry.hpp) for `emitter_receiver` and `emitter_receiver>` that already cover common cases. The default emitter_receiver works for the `std::vector` type shown above, which is why the code shown for illustration there is [not found within the operator's bindings](https://github.com/nvidia-holoscan/holoscan-sdk/blob/main/python/holoscan/operators/holoviz/holoviz.cpp). In that case one could immediately implement `register_types` from step 2 without having to explicitly create an `emitter_receiver` class. -An example where the default `emitter_receiver` would not work is the custom one defined by the SDK for `pybind11::dict`. In this case, to provide convenient emit of multiple tensors via passing a `dict[holoscan::Tensor]` to `op_output.emit` we have special handling of Python dictionaries. The dictionary is inspected and if all keys are strings and all values are tensor-like objects, a single C++ `nvidia::gxf::Entity` containing all of the tensors as an `nvidia::gxf::Tensor` is emitted. If the dictionary is not a tensor map, then it is just emitted as a shared pointer to the Python dict object. The `emitter_receiver` implementations used for the core SDK are defined in [emitter_receivers.hpp](https://github.com/nvidia-holoscan/holoscan-sdk/blob/v2.1.0/python/holoscan/core/emitter_receivers.hpp). These can serve as a reference when creating new ones for additional types. +An example where the default `emitter_receiver` would not work is the custom one defined by the SDK for `pybind11::dict`. In this case, to provide convenient emit of multiple tensors via passing a `dict[holoscan::Tensor]` to `op_output.emit` we have special handling of Python dictionaries. The dictionary is inspected and if all keys are strings and all values are tensor-like objects, a single C++ `nvidia::gxf::Entity` containing all of the tensors as an `nvidia::gxf::Tensor` is emitted. If the dictionary is not a tensor map, then it is just emitted as a shared pointer to the Python dict object. The `emitter_receiver` implementations used for the core SDK are defined in [emitter_receivers.hpp](https://github.com/nvidia-holoscan/holoscan-sdk/blob/v2.2.0/python/holoscan/core/emitter_receivers.hpp). These can serve as a reference when creating new ones for additional types. #### Runtime behavior of emit and receive @@ -523,7 +524,7 @@ Only types registered with the SDK can be specified by name in this third argume #### Table of types registered by the core SDK -The list of types that are registered with the SDK's `EmitterReceiverRegistry` are given in the table below. +The list of types that are registered with the SDK's `EmitterReceiverRegistry` are given in the table below. C++ Type | name in the EmitterReceiverRegistry -------------------------------------------------------|------------------------------------------- diff --git a/docs/holoscan_packager.md b/docs/holoscan_packager.md index 23ca55f1..06192ce1 100644 --- a/docs/holoscan_packager.md +++ b/docs/holoscan_packager.md @@ -95,6 +95,8 @@ The NGC container has the CLI installed already, no additional steps are require :::{tip} The packager feature is also illustrated in the [cli_packager](https://github.com/nvidia-holoscan/holoscan-sdk/tree/main/examples/cli_packager) and [video_replayer_distributed]() examples. + +Additional arguments are required when launching the container to enable the packaging of Holoscan applications inside the NGC Holoscan container. Please see the [NGC Holoscan container](https://catalog.ngc.nvidia.com/orgs/nvidia/teams/clara-holoscan/containers/holoscan) page for additional details. ::: 1. Ensure to use the [HAP environment variables](./cli/hap.md#table-of-environment-variables) wherever possible when accessing data. For example: @@ -225,6 +227,35 @@ The packager feature is also illustrated in the [cli_packager](https://github.co holoscan package --platform x64-workstation --tag my-awesome-app --config /path/to/my/awesome/application/config.yaml /path/to/my/awesome/application/ ``` +### Common Issues When Using Holoscan Packager + +#### DNS Name Resolution Error + +The Holoscan Packager may be unable to resolve hostnames in specific networking environments and may show errors similar to the following: + +``` +curl: (6) Could not resolve host: github.com. +Failed to establish a new connection:: [Errno -3] Temporary failure in name solution... +``` + +To resolve these errors, edit the `/etc/docker/daemon.json` file to include `dns` and `dns-serach` fields as follows: + +```json +{ + "default-runtime": "nvidia", + "runtimes": { + "nvidia": { + "args": [], + "path": "nvidia-container-runtime" + } + }, + "dns": ["IP-1", "IP-n"], + "dns-search": ["DNS-SERVER-1", "DNS-SERVER-n"] +} +``` + +You may need to consult your IT team and replace `IP-x` and `DNS-SERVER-x` with the provided values. + ## Run a packaged application The packaged Holoscan application container image can run with the [Holoscan App Runner](./cli/run.md): diff --git a/docs/images/holoscan_tensor_interoperability.png b/docs/images/holoscan_tensor_interoperability.png index 8f7f8ed11b8f30a3d1499244580653501eeee9af..7ec577fa28f09bfcc232cb5631828422d47093e3 100644 GIT binary patch literal 168737 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

()Ff(T0~A{Ttp3jv`~V5H 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

  • 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 fj3m*)rG9wKmfJbANX? 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 literal 440439 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

    _9&v#YT@H0e*T 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

    &zKUD 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

    }_RO9Yl5Da=NV4}{S=nT-Y|6;aUeEbb_y7OaT8( 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 diff --git a/docs/inference.md b/docs/inference.md index 00765f09..2f92697b 100644 --- a/docs/inference.md +++ b/docs/inference.md @@ -93,6 +93,12 @@ Required parameters and related features available with the Holoscan Inference M - If the `temporal_map` is absent in the parameter set, all models are inferred for all the frames. - All models are not mandatory in the `temporal_map`. The missing models are inferred per frame. - Temporal map based inferencing is supported for all backends. + - `activation_map`: Dynamic inferencing can be enabled with this parameter. It is populated in the parameter set and is updated at runtime. + - Each entry in `activation_map` has a unique keyword representing the model (same as used in `model_path_map` and `pre_processor_map`), and activation state as the value. Activation state represents whether the model will be used for inferencing or not on a given frame. Any model(s) with a value of 1 will be active and will be used for inference, and any model(s) with a value of 0 will not run. The activation map must be initialized in the parameter set for all the models that need to be activated or deactivated dynamically. + - When the activation state is 0 for a particular model in the `activation_map`, the inference operator will not launch the inference for the model and will emits the last inferred result for the model. + - If the `activation_map` is absent in the parameter set, all of the models are inferred for all frames. + - All models are not mandatory in the `activation_map`. The missing models are active on every frame. + - Activation map based dynamic inferencing is supported for all backends. - `backend_map`: Multiple backends can be used in the same application with this parameter. - Each entry in `backend_map` has a unique keyword representing the model (same as used in `model_path_map`), and the `backend` as the value. - A sample backend_map is shown below. In the example, model_1 uses the `tensorRT` backend, and model 2 and model 3 uses the `torch` backend for inference. diff --git a/docs/sdk_installation.md b/docs/sdk_installation.md index 95ee5d58..916b10ca 100644 --- a/docs/sdk_installation.md +++ b/docs/sdk_installation.md @@ -17,7 +17,7 @@ Set up your developer kit: Developer Kit | User Guide | OS | GPU Mode ------------- | ---------- | --- | --- -[NVIDIA IGX Orin][igx] | [Guide][igx-guide] | [IGX Software][igx-sw] 1.0 DP | iGPU **or*** dGPU +[NVIDIA IGX Orin][igx] | [Guide][igx-guide] | [IGX Software][igx-sw] 1.0 Production Release | iGPU **or*** dGPU [NVIDIA Jetson AGX Orin and Orin Nano][jetson-orin] | [Guide][jetson-guide] | [JetPack][jp] 6.0 | iGPU [NVIDIA Clara AGX][clara-agx]
    _Only supporting the NGC container_ | [Guide][clara-guide] | [HoloPack][sdkm] 1.2 | iGPU **or*** dGPU @@ -81,11 +81,11 @@ We provide multiple ways to install and run the Holoscan SDK: ````{tab-item} NGC Container - **dGPU** (x86_64, IGX Orin dGPU, Clara AGX dGPU, GH200) ```bash - docker pull nvcr.io/nvidia/clara-holoscan/holoscan:v1.0.3-dgpu + docker pull nvcr.io/nvidia/clara-holoscan/holoscan:v2.2.0-dgpu ``` - **iGPU** (Jetson, IGX Orin iGPU, Clara AGX iGPU) ```bash - docker pull nvcr.io/nvidia/clara-holoscan/holoscan:v1.0.3-igpu + docker pull nvcr.io/nvidia/clara-holoscan/holoscan:v2.2.0-igpu ``` See details and usage instructions on [NGC][container]. ```` diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index e77b9b86..0405ee9f 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -33,6 +33,7 @@ add_subdirectory(ping_custom_op) add_subdirectory(ping_multi_port) add_subdirectory(ping_distributed) add_subdirectory(ping_vector) +add_subdirectory(python_decorator) add_subdirectory(resources) add_subdirectory(tensor_interop) add_subdirectory(v4l2_camera) diff --git a/examples/README.md b/examples/README.md index 2845b78d..ca235981 100644 --- a/examples/README.md +++ b/examples/README.md @@ -72,6 +72,10 @@ The following examples illustrate the use of specific resource classes that can * [**Clock**](resources/clock): demonstrate assignment of a user-configured clock to the Holoscan SDK scheduler and how its runtime methods can be accessed from an operator's compute method. +## Decorator-based Python API + +* [**Python Functions as Operators**](python_decorator): demonstrates how to use a decorator to convert a Python function into an Operator. + ## Visualization * [**Holoviz**](holoviz): display overlays of various geometric primitives diff --git a/examples/conditions/CMakeLists.txt b/examples/conditions/CMakeLists.txt index bfdf68ba..bc240d35 100644 --- a/examples/conditions/CMakeLists.txt +++ b/examples/conditions/CMakeLists.txt @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,4 +14,6 @@ # limitations under the License. add_subdirectory(asynchronous) +add_subdirectory(expiring_message) add_subdirectory(periodic) + diff --git a/examples/conditions/expiring_message/CMakeLists.txt b/examples/conditions/expiring_message/CMakeLists.txt new file mode 100644 index 00000000..91b8d28e --- /dev/null +++ b/examples/conditions/expiring_message/CMakeLists.txt @@ -0,0 +1,25 @@ +# SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +add_subdirectory(cpp) +add_subdirectory(python) + +file(RELATIVE_PATH app_relative_dest_path ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}) + +install( + FILES README.md + DESTINATION "${app_relative_dest_path}" + COMPONENT "holoscan-examples" +) diff --git a/examples/conditions/expiring_message/README.md b/examples/conditions/expiring_message/README.md new file mode 100644 index 00000000..1a8882a5 --- /dev/null +++ b/examples/conditions/expiring_message/README.md @@ -0,0 +1,51 @@ +# Holoscan::ExpiringMessageAvailableCondition + +This example demonstrates how to use Holoscan::ExpiringMessageAvailableCondition. + +*Visit the [SDK User Guide](https://docs.nvidia.com/holoscan/sdk-user-guide/components/conditions.html) to learn more about the ExpiringMessageAvailable Condition.* + +## C++ API + +This example has two operators involved: + 1. a transmitter that a transmitter, set to transmit a string message `Periodic ping...` on port `out`. This operator is configured to be executed 8 times each subsequent message is sent only after a period of 10 milliseconds has elapsed. + 2. a receiver that waits for a 5 messages to be batched together to call compute. If 5 messages have not arrived by a specified interval of 1 second, compute will be called at that time. + +Note that the `ExpiringMessageAvailableCondition` added to the input port of the receive operator requires that the message sent by the output port of the transmit operator attaches a timestamp. This timestamp is needed to be able to enforce the `max_delay_ns` timeout interval used by the condition. + + +### Build instructions + +Built with the SDK, see instructions from the top level README. + +### Run instructions + +First, go in your `build` or `install` directory (automatically done by `./run launch`). + +Then, run: +```bash +./examples/conditions/expiring_message/cpp/ping_expiring_message +``` + +## Python API + +This example demonstrates the use of ExpiringMessageAvailableCondition using python API. This is a simple ping application with two operators connected using add_flow(). + +There are two operators involved in this example: + 1. a transmitter that on each tick, transmits an integer to the "out" port. This operator is configured to be executed 8 times each subsequent message is sent only after a period of 10 milliseconds has elapsed. + 3. a receiver that will wait for 5 messages from the "in" port before it will call compute. If 5 messages have not arrived by the specified interval of 1 second, compute will be called at that time. + +Note that the `ExpiringMessageAvailableCondition` added to the input port of the receive operator requires that the message sent by the output port of the transmit operator attaches a timestamp. This timestamp is needed to be able to enforce the `max_delay_ns` timeout interval used by the condition. + +### Build instructions + +Built with the SDK, see instructions from the top level README. + +### Run instructions + +First, go in your `build` or `install` directory (automatically done by `./run launch`). + +Then, run the following command. + +```bash +python3 ./examples/conditions/expiring_message/python/ping_expiring_message.py +``` diff --git a/examples/conditions/expiring_message/cpp/CMakeLists.min.txt b/examples/conditions/expiring_message/cpp/CMakeLists.min.txt new file mode 100644 index 00000000..b37d3562 --- /dev/null +++ b/examples/conditions/expiring_message/cpp/CMakeLists.min.txt @@ -0,0 +1,46 @@ +# SPDX-FileCopyrightText: Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the \"License\"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an \"AS IS\" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +cmake_minimum_required(VERSION 3.20) +project(ping_expiring_message CXX) + +# Finds the package holoscan +find_package(holoscan REQUIRED CONFIG + PATHS "/opt/nvidia/holoscan" "/workspace/holoscan-sdk/install") + +add_executable(ping_expiring_message + ping_expiring_message.cpp +) + +target_link_libraries(ping_expiring_message + PRIVATE + holoscan::core +) + +# Copy config file to the build tree +add_custom_target(ping_expiring_message_yaml + COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/ping_expiring_message.yaml" ${CMAKE_CURRENT_BINARY_DIR} +) +add_dependencies(ping_expiring_message ping_expiring_message_yaml) + +# Testing +if(BUILD_TESTING) + add_test(NAME EXAMPLE_CPP_PING_EXPIRING_MESSAGE_TEST + COMMAND ping_expiring_message + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + ) + set_tests_properties(EXAMPLE_CPP_PING_EXPIRING_MESSAGE_TEST PROPERTIES + PASS_REGULAR_EXPRESSION "Rx message received: Expiring message ping") +endif() diff --git a/examples/conditions/expiring_message/cpp/CMakeLists.txt b/examples/conditions/expiring_message/cpp/CMakeLists.txt new file mode 100644 index 00000000..553a0e36 --- /dev/null +++ b/examples/conditions/expiring_message/cpp/CMakeLists.txt @@ -0,0 +1,79 @@ +# SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Create examples +add_executable(ping_expiring_message + ping_expiring_message.cpp +) +target_link_libraries(ping_expiring_message + PRIVATE + holoscan::core +) + +# Copy config file to the build tree +add_custom_target(ping_expiring_message_yaml + COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/ping_expiring_message.yaml" ${CMAKE_CURRENT_BINARY_DIR} + DEPENDS "ping_expiring_message.yaml" + BYPRODUCTS "ping_expiring_message.yaml" +) +add_dependencies(ping_expiring_message ping_expiring_message_yaml) + +# Install examples + +# Set the install RPATH based on the location of the Holoscan SDK libraries +# The GXF extensions are loaded by the GXF libraries - no need to include here +file(RELATIVE_PATH install_lib_relative_path ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/${HOLOSCAN_INSTALL_LIB_DIR}) +set_target_properties(ping_expiring_message PROPERTIES INSTALL_RPATH "\$ORIGIN/${install_lib_relative_path}") + +# Install following the relative folder path +file(RELATIVE_PATH app_relative_dest_path ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}) + +if(HOLOSCAN_INSTALL_EXAMPLE_SOURCE) +# Install the source +install(FILES ping_expiring_message.cpp + DESTINATION "${app_relative_dest_path}" + COMPONENT holoscan-examples +) + +# Install the minimal CMakeLists.txt file +install(FILES CMakeLists.min.txt + RENAME "CMakeLists.txt" + DESTINATION "${app_relative_dest_path}" + COMPONENT holoscan-examples +) +endif() + +# Install the compiled example +install(TARGETS ping_expiring_message + DESTINATION "${app_relative_dest_path}" + COMPONENT holoscan-examples +) + +# Install the configuration file +install(FILES + "${CMAKE_CURRENT_SOURCE_DIR}/ping_expiring_message.yaml" + DESTINATION "${app_relative_dest_path}" + COMPONENT holoscan-examples +) + +# Testing +if(HOLOSCAN_BUILD_TESTS) + add_test(NAME EXAMPLE_CPP_PING_EXPIRING_MESSAGE_TEST + COMMAND ping_expiring_message + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + ) + set_tests_properties(EXAMPLE_CPP_PING_EXPIRING_MESSAGE_TEST PROPERTIES + PASS_REGULAR_EXPRESSION "Rx message received: ExpiringMessageAvailable ping: 8") +endif() diff --git a/examples/conditions/expiring_message/cpp/ping_expiring_message.cpp b/examples/conditions/expiring_message/cpp/ping_expiring_message.cpp new file mode 100644 index 00000000..e1ee40c6 --- /dev/null +++ b/examples/conditions/expiring_message/cpp/ping_expiring_message.cpp @@ -0,0 +1,126 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include "holoscan/holoscan.hpp" +#include "holoscan/core/conditions/gxf/expiring_message.hpp" + +namespace holoscan::ops { + +class PingTxOp : public Operator { + public: + HOLOSCAN_OPERATOR_FORWARD_ARGS(PingTxOp) + + PingTxOp() = default; + + void setup(OperatorSpec& spec) override { spec.output>("out"); } + + void compute(InputContext&, OutputContext& op_output, ExecutionContext&) override { + auto value = + std::make_shared(fmt::format("ExpiringMessageAvailable ping: {}", index_)); + ++index_; + + // retrieve the scheduler used for this application via it's fragment + auto scheduler = fragment_->scheduler(); + // To get the clock we currently have to cast the scheduler to gxf::GXFScheduler. + // TODO: Refactor C++ lib so the clock method is on Scheduler rather than GXFScheduler. + // That would allow us to avoid this dynamic_pointer_cast, but might require adding + // renaming Clock->GXFClock and then adding a new holoscan::Clock independent of GXF. + auto gxf_scheduler = std::dynamic_pointer_cast(scheduler); + auto clock = gxf_scheduler->clock(); + auto timestamp = clock->timestamp(); + + // emitting a timestamp is necessary for this port to be connected to an input port that is + // using a ExpiringMessageAvailableCondition + op_output.emit(value, "out", timestamp); + }; + + private: + int index_ = 1; +}; + +class PingRxOp : public Operator { + public: + HOLOSCAN_OPERATOR_FORWARD_ARGS(PingRxOp) + + PingRxOp() = default; + + void setup(OperatorSpec& spec) override { + ArgList expiring_message_arglist{Arg("max_batch_size", static_cast(5)), + Arg("max_delay_ns", static_cast(1'000'000'000))}; + spec.input>("in") + .connector(IOSpec::ConnectorType::kDoubleBuffer, + Arg("capacity", static_cast(5)), + Arg("policy", static_cast(1))) + .condition(ConditionType::kExpiringMessageAvailable, expiring_message_arglist); + } + + void compute(InputContext& op_input, OutputContext&, ExecutionContext&) override { + auto in_value = op_input.receive>("in"); + + HOLOSCAN_LOG_INFO("PingRxOp::compute() called"); + + while (in_value) { + auto message = in_value.value(); + if (message) { + HOLOSCAN_LOG_INFO("Rx message received: {}", message->c_str()); + } else { + HOLOSCAN_LOG_INFO("Rx message received: nullptr"); + } + in_value = op_input.receive>("in"); + } + }; +}; + +} // namespace holoscan::ops + +class App : public holoscan::Application { + public: + void compose() override { + using namespace holoscan; + using namespace std::chrono_literals; + // Configure the operators. Here we use CountCondition to terminate + // execution after a specific number of messages have been sent. + // PeriodicCondition is used so that each subsequent message is + // sent only after a period of 10 milliseconds has elapsed. + auto tx = make_operator( + "tx", + make_condition("count-condition", 8), + make_condition("periodic-condition", 0.01s)); + + auto rx = make_operator("rx"); + + add_flow(tx, rx); + } +}; + +int main(int argc, char** argv) { + auto app = holoscan::make_application(); + + // Get the configuration + auto config_path = std::filesystem::canonical(argv[0]).parent_path(); + config_path /= std::filesystem::path("ping_expiring_message.yaml"); + app->config(config_path); + auto& tracker = app->track(0, 0, 0); + tracker.enable_logging(); + app->run(); + tracker.print(); + return 0; +} diff --git a/examples/conditions/expiring_message/cpp/ping_expiring_message.yaml b/examples/conditions/expiring_message/cpp/ping_expiring_message.yaml new file mode 100644 index 00000000..8469d54d --- /dev/null +++ b/examples/conditions/expiring_message/cpp/ping_expiring_message.yaml @@ -0,0 +1,18 @@ +%YAML 1.2 +# SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +--- +extensions: + - libgxf_std.so diff --git a/examples/conditions/expiring_message/python/CMakeLists.txt b/examples/conditions/expiring_message/python/CMakeLists.txt new file mode 100644 index 00000000..279cec97 --- /dev/null +++ b/examples/conditions/expiring_message/python/CMakeLists.txt @@ -0,0 +1,42 @@ +# SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Get relative folder path for the app +file(RELATIVE_PATH app_relative_dest_path ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}) + +# Copy native operator ping application +add_custom_target(python_ping_expiring_message ALL + COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/ping_expiring_message.py" ${CMAKE_CURRENT_BINARY_DIR} + DEPENDS "ping_expiring_message.py" + BYPRODUCTS "ping_expiring_message,py" +) + +# Install the app +install(FILES + "${CMAKE_CURRENT_SOURCE_DIR}/ping_expiring_message.py" + DESTINATION "${app_relative_dest_path}" + COMPONENT "holoscan-examples" +) + +# Testing +if(HOLOSCAN_BUILD_TESTS) + add_test(NAME EXAMPLE_PYTHON_PING_EXPIRING_MESSAGE + COMMAND python3 ping_expiring_message.py + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + ) + set_tests_properties(EXAMPLE_PYTHON_PING_EXPIRING_MESSAGE PROPERTIES + PASS_REGULAR_EXPRESSION "ExpiringMessageAvailable ping: 8" + ) +endif() \ No newline at end of file diff --git a/examples/conditions/expiring_message/python/ping_expiring_message.py b/examples/conditions/expiring_message/python/ping_expiring_message.py new file mode 100644 index 00000000..fbdb091e --- /dev/null +++ b/examples/conditions/expiring_message/python/ping_expiring_message.py @@ -0,0 +1,126 @@ +""" + SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + SPDX-License-Identifier: Apache-2.0 + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +""" # noqa: E501 + +from holoscan.conditions import CountCondition, PeriodicCondition +from holoscan.core import Application, ConditionType, IOSpec, Operator, OperatorSpec +from holoscan.schedulers import GreedyScheduler + + +class PingTxOp(Operator): + """Simple transmitter operator. + + On each tick, it transmits an integer to the "out" port. + + **==Named Outputs==** + + out : int + An index value that increments by one on each call to `compute`. The starting value is + 1. + """ + + def __init__(self, fragment, *args, **kwargs): + self.index = 1 + # Need to call the base class constructor last + super().__init__(fragment, *args, **kwargs) + + def setup(self, spec: OperatorSpec): + spec.output("out") + + def compute(self, op_input, op_output, context): + # we can retrieve the scheduler used for this application via it's fragment + scheduler = self.fragment.scheduler() + + # The scheduler's clock is available as a parameter. + # The clock object has methods to retrieve timestamps. + + # To get the clock we currently have to set the scheduler manually in the main method. + # TODO: Refactor C++ lib so the clock method is on Scheduler rather than GXFScheduler. # noqa: E501, FIX002 + # That would allow us to access 'clock' attribute without manually setting scheduler, + # but might require adding renaming Clock->GXFClock and then adding + # a new holoscan::Clock independent of GXF. + clock = scheduler.clock + + print(f"Sending message: {self.index}") + + # Note that we must set acq_timestamp so that the timestamp required by + # the ExpiringMessageAvailableCondition on the downstream operator will + # be found. + op_output.emit(self.index, "out", acq_timestamp=clock.timestamp()) + self.index += 1 + + +class PingRxOp(Operator): + """Simple receiver operator. + + This is an example of a native operator with one input port. + On each tick, it receives up to 5 batches of messages from the "in" port. + If 5 messages are not received within 1 second, the operator will be triggered to process. + + **==Named Inputs==** + + in : any + A received value. + """ + + def __init__(self, fragment, *args, **kwargs): + # Need to call the base class constructor last + super().__init__(fragment, *args, **kwargs) + + def setup(self, spec: OperatorSpec): + spec.input("in").connector( + IOSpec.ConnectorType.DOUBLE_BUFFER, + capacity=5, + policy=1, + ).condition( + # Set the enum value corresponding to ExpiringMessageAvailableCondition + ConditionType.EXPIRING_MESSAGE_AVAILABLE, + max_batch_size=5, + max_delay_ns=1_000_000_000, + ) + + def compute(self, op_input, op_output, context): + message = op_input.receive("in") + print("PingRxOp.compute() called") + while message: + print(f"ExpiringMessageAvailable ping: {message}") + message = op_input.receive("in") + + +# Now define a simple application using the operators defined above + + +class MyPingApp(Application): + def compose(self): + # Configure the operators. Here we use CountCondition to terminate + # execution after a specific number of messages have been sent. + # PeriodicCondition is used so that each subsequent message is + # sent only after a period of 10 milliseconds has elapsed. + tx = PingTxOp(self, CountCondition(self, 8), PeriodicCondition(self, 10_000_000), name="tx") + rx = PingRxOp(self, name="rx") + + # Connect the operators into the workflow: tx -> rx + self.add_flow(tx, rx) + + +def main(): + app = MyPingApp() + app.scheduler(GreedyScheduler(fragment=app, name="greedy")) + app.run() + + +if __name__ == "__main__": + main() diff --git a/examples/holoviz/cpp/holoviz_geometry.cpp b/examples/holoviz/cpp/holoviz_geometry.cpp index 1eb86c2e..53fa7df9 100644 --- a/examples/holoviz/cpp/holoviz_geometry.cpp +++ b/examples/holoviz/cpp/holoviz_geometry.cpp @@ -307,10 +307,8 @@ class HolovizGeometryApp : public holoscan::Application { label_coords_spec.text_ = {"label_1", "label_2"}; label_coords_spec.priority_ = priority++; - auto visualizer = make_operator("holoviz", - Arg("width", 854u), - Arg("height", 480u), - Arg("tensors", input_spec)); + auto visualizer = make_operator( + "holoviz", Arg("width", 854u), Arg("height", 480u), Arg("tensors", input_spec)); // Define the workflow: source -> holoviz add_flow(source, visualizer, {{"outputs", "receivers"}}); @@ -326,7 +324,7 @@ int main(int argc, char** argv) { // Parse args struct option long_options[] = { {"help", no_argument, 0, 'h'}, {"count", required_argument, 0, 'c'}, {0, 0, 0, 0}}; - uint64_t count; + uint64_t count = 0; while (true) { int option_index = 0; const int c = getopt_long(argc, argv, "hc:", long_options, &option_index); diff --git a/examples/import_gxf_components/cpp/import_gxf_components.cpp b/examples/import_gxf_components/cpp/import_gxf_components.cpp index f7e58116..0e6f6b4e 100644 --- a/examples/import_gxf_components/cpp/import_gxf_components.cpp +++ b/examples/import_gxf_components/cpp/import_gxf_components.cpp @@ -31,7 +31,8 @@ #include "./receive_tensor_gxf.hpp" #include "./send_tensor_gxf.hpp" -#include "holoscan/core/resources/gxf/gxf_component_resource.hpp" +// Include the following header files to use GXFCodeletOp and HOLOSCAN_WRAP_GXF_CODELET_AS_OPERATOR +// macro. #include "holoscan/operators/gxf_codelet/gxf_codelet.hpp" #ifdef CUDA_TRY diff --git a/examples/multi_branch_pipeline/README.md b/examples/multi_branch_pipeline/README.md index ef0557b4..32fec735 100644 --- a/examples/multi_branch_pipeline/README.md +++ b/examples/multi_branch_pipeline/README.md @@ -49,7 +49,7 @@ For the C++ application, the scheduler to be used can be set via the `scheduler` ## Python API -- `multi_branch_pipeline.py`: This example is the same as described for the C++ application above. The primary difference is that instead of using a YAML file for the configuration variables, all values are set via the command line. Call the script below with the `--help` option to get a full description of the command line parameters. By default a polling-based multithread scheduler will be used, but if `--event-based` is specified, the event-based multithread scheduler will be used instead. +- `multi_branch_pipeline.py`: This example is the same as described for the C++ application above. The primary difference is that instead of using a YAML file for the configuration variables, all values are set via the command line. Call the script below with the `--help` option to get a full description of the command line parameters. By default a polling-based multithread scheduler will be used, but if `--event_based` is specified, the event-based multithread scheduler will be used instead. ### Build instructions diff --git a/examples/multithread/README.md b/examples/multithread/README.md index 364a3d98..437f6d98 100644 --- a/examples/multithread/README.md +++ b/examples/multithread/README.md @@ -36,7 +36,7 @@ For the C++ application, the scheduler to be used can be set via the `scheduler` ## Python API -- `multithread.py`: This example demonstrates how to configure and use a multi-threaded scheduler instead of the default single-threaded one. It involves three operators as described for the C++ API example described above. The primary difference is that instead of using a YAML file for the configuration variables, all values are set via the command line. Call the script below with the `--help` option to get a full description of the command line parameters. By default a polling-based multithread scheduler will be used, but if `--event-based` is specified, the event-based multithread scheduler will be used instead. +- `multithread.py`: This example demonstrates how to configure and use a multi-threaded scheduler instead of the default single-threaded one. It involves three operators as described for the C++ API example described above. The primary difference is that instead of using a YAML file for the configuration variables, all values are set via the command line. Call the script below with the `--help` option to get a full description of the command line parameters. By default a polling-based multithread scheduler will be used, but if `--event_based` is specified, the event-based multithread scheduler will be used instead. ### Build instructions @@ -49,5 +49,5 @@ First, go in your `build` or `install` directory (automatically done by `./run l Then, run the app with the options of your choice. For example, to use 8 worker threads to run 32 delay operators with delays ranging linearly from 0.2 to (0.2 + 0.05 * 31), one would set: ```bash -python3 ./examples/multithread/python/multithread.py --threads 8 --num_delay_ops 32 --delay 0.2 --delay_step 0.05 --event-based +python3 ./examples/multithread/python/multithread.py --threads 8 --num_delay_ops 32 --delay 0.2 --delay_step 0.05 --event_based ``` diff --git a/examples/multithread/cpp/multithread.cpp b/examples/multithread/cpp/multithread.cpp index 802f89fa..30de54a4 100644 --- a/examples/multithread/cpp/multithread.cpp +++ b/examples/multithread/cpp/multithread.cpp @@ -20,6 +20,7 @@ #include #include +#include #include #include "holoscan/holoscan.hpp" @@ -75,7 +76,7 @@ class DelayOp : public Operator { } if (!silent) { HOLOSCAN_LOG_INFO("{}: sending new value ({})", name(), new_value); } op_output.emit(new_value, "out_val"); - op_output.emit(nm, "out_name"); + op_output.emit(std::move(nm), "out_name"); }; private: @@ -134,7 +135,7 @@ class App : public holoscan::Application { auto rx = make_operator("rx", silent_); for (int i = 0; i < num_delays_; ++i) { std::string delay_name = fmt::format("mx{}", i); - auto del_op = make_operator(delay_name, + auto del_op = make_operator(std::move(delay_name), Arg{"delay", delay_ + delay_step_ * i}, Arg{"increment", i}, Arg{"silent", silent_}); diff --git a/examples/ping_distributed/cpp/ping_distributed.cpp b/examples/ping_distributed/cpp/ping_distributed.cpp index dc87b5ab..0e4e7ab7 100644 --- a/examples/ping_distributed/cpp/ping_distributed.cpp +++ b/examples/ping_distributed/cpp/ping_distributed.cpp @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -115,7 +115,7 @@ std::optional get_boolean_arg(std::vector args, const std::st std::optional get_int32_arg(std::vector args, const std::string& name) { auto loc = std::find(args.begin(), args.end(), name); - if ((loc != std::end(args)) && (loc++ != std::end(args))) { + if ((loc != std::end(args)) && (++loc != std::end(args))) { try { return std::stoi(*loc); } catch (std::exception& e) { @@ -125,10 +125,9 @@ std::optional get_int32_arg(std::vector args, const std::s } return {}; } - std::optional get_int64_arg(std::vector args, const std::string& name) { auto loc = std::find(args.begin(), args.end(), name); - if ((loc != std::end(args)) && (loc++ != std::end(args))) { + if ((loc != std::end(args)) && (++loc != std::end(args))) { try { return std::stoll(*loc); } catch (std::exception& e) { @@ -141,7 +140,7 @@ std::optional get_int64_arg(std::vector args, const std::s std::optional get_str_arg(std::vector args, const std::string& name) { auto loc = std::find(args.begin(), args.end(), name); - if ((loc != std::end(args)) && (loc++ != std::end(args))) { return *loc; } + if ((loc != std::end(args)) && (++loc != std::end(args))) { return *loc; } return {}; } @@ -165,7 +164,7 @@ int main() { auto app = holoscan::make_application(); // Parse args that are defined for all applications. - auto& remaining_args = app->argv(); + std::vector& remaining_args = app->argv(); // Parse any additional supported arguments bool tensor_on_gpu = get_boolean_arg(remaining_args, "--gpu").value_or(false); diff --git a/examples/python_decorator/CMakeLists.txt b/examples/python_decorator/CMakeLists.txt new file mode 100644 index 00000000..e663d25a --- /dev/null +++ b/examples/python_decorator/CMakeLists.txt @@ -0,0 +1,43 @@ +# SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Get relative folder path for the app +file(RELATIVE_PATH app_relative_dest_path ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}) + +# Copy video_replayer application file +add_custom_target(python_decorator_example ALL + COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/video_replayer.py" ${CMAKE_CURRENT_BINARY_DIR} + DEPENDS "video_replayer.py" + BYPRODUCTS "video_replayer.py" +) + +# Install the app +install(FILES + "${CMAKE_CURRENT_SOURCE_DIR}/video_replayer.py" + DESTINATION "${app_relative_dest_path}" + COMPONENT "holoscan-examples" +) + +# Testing +if(HOLOSCAN_BUILD_TESTS) + add_test(NAME EXAMPLE_PYTHON_DECORATOR_INTEROP_TEST + COMMAND python3 video_replayer.py + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + ) + set_tests_properties(EXAMPLE_PYTHON_DECORATOR_INTEROP_TEST PROPERTIES + DEPENDS "video_replayer.py" + PASS_REGULAR_EXPRESSION "Reach end of file or playback count reaches to the limit. Stop ticking." + ) +endif() diff --git a/examples/python_decorator/README.md b/examples/python_decorator/README.md new file mode 100644 index 00000000..d015d01f --- /dev/null +++ b/examples/python_decorator/README.md @@ -0,0 +1,41 @@ +# Using a Function Decorator to Build Python Operators + +This is an example of mixed use of native Python operators and wrapped C++ operators. In this example, instead of explicitly creating a Python operator from inheriting from `holoscan.core.Operator`, we instead demonstrate how `holoscan.core.decorator` can be used to decorator an existing function, turning it into an Operator. + +## Data + +The following dataset is used by this example: +[📦️ (NGC) Sample RacerX Video Data](https://catalog.ngc.nvidia.com/orgs/nvidia/teams/clara-holoscan/resources/holoscan_racerx_video/files?version=20231009). + +## Python Run instructions + +* **using python wheel**: + ```bash + # [Prerequisite] Download NGC dataset above to `DATA_DIR` + export HOLOSCAN_INPUT_PATH= + # [Prerequisite] Download example .py file below to `APP_DIR` + # [Optional] Start the virtualenv where holoscan is installed + python3 /video_replayer.py + ``` +* **using deb package install**: + ```bash + sudo /opt/nvidia/holoscan/examples/download_example_data + export HOLOSCAN_INPUT_PATH=/opt/nvidia/holoscan/data + export PYTHONPATH=/opt/nvidia/holoscan/python/lib + python3 /opt/nvidia/holoscan/examples/python_decorator/video_replayer.py + ``` +* **from NGC container**: + ```bash + python3 /opt/nvidia/holoscan/examples/python_decorator/video_replayer.py + ``` +* **source (dev container)**: + ```bash + ./run launch # optional: append `install` for install tree + python3 ./examples/python_decorator/video_replayer.py + ``` +* **source (local env)**: + ```bash + export PYTHONPATH=${BUILD_OR_INSTALL_DIR}/python/lib + export HOLOSCAN_INPUT_PATH=${SRC_DIR}/data + python3 ${BUILD_OR_INSTALL_DIR}/examples/python_decorator/video_replayer.py + ``` diff --git a/examples/python_decorator/video_replayer.py b/examples/python_decorator/video_replayer.py new file mode 100644 index 00000000..0ef77c20 --- /dev/null +++ b/examples/python_decorator/video_replayer.py @@ -0,0 +1,92 @@ +""" + SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + SPDX-License-Identifier: Apache-2.0 + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +""" # noqa: E501 + +import os + +from holoscan.core import Application +from holoscan.decorator import Input, Output, create_op +from holoscan.operators import HolovizOp, VideoStreamReplayerOp + +sample_data_path = os.environ.get("HOLOSCAN_INPUT_PATH", "../data") + + +@create_op( + inputs="tensor", + outputs="out_tensor", +) +def invert(tensor): + tensor = 255 - tensor + return tensor + + +@create_op(inputs=Input("in", arg_map="tensor"), outputs=Output("out", tensor_names=("frame",))) +def tensor_info(tensor): + print(f"tensor from 'in' port: shape = {tensor.shape}, " f"dtype = {tensor.dtype.name}") + return tensor + + +class VideoReplayerApp(Application): + """Example of an application that uses the operators defined above. + + This application has the following operators: + + - VideoStreamReplayerOp + - HolovizOp + + The VideoStreamReplayerOp reads a video file and sends the frames to the HolovizOp. + The HolovizOp displays the frames. + """ + + def compose(self): + video_dir = os.path.join(sample_data_path, "racerx") + if not os.path.exists(video_dir): + raise ValueError(f"Could not find video data: {video_dir=}") + + # Define the replayer and holoviz operators + replayer = VideoStreamReplayerOp( + self, + name="replayer", + directory=video_dir, + basename="racerx", + frame_rate=0, # as specified in timestamps + repeat=False, # default: false + realtime=True, # default: true + count=40, # default: 0 (no frame count restriction) + ) + invert_op = invert(self, name="image_invert") + info_op = tensor_info(self, name="tensor_info") + visualizer = HolovizOp( + self, + name="holoviz", + width=854, + height=480, + # name="frame" to match Output argument to create_op for tensor_info + tensors=[dict(name="frame", type="color", opacity=1.0, priority=0)], + ) + # Define the workflow + self.add_flow(replayer, invert_op, {("output", "tensor")}) + self.add_flow(invert_op, info_op, {("out_tensor", "in")}) + self.add_flow(info_op, visualizer, {("out", "receivers")}) + + +def main(): + app = VideoReplayerApp() + app.run() + + +if __name__ == "__main__": + main() diff --git a/examples/resources/CMakeLists.txt b/examples/resources/CMakeLists.txt index 07c05014..01485913 100644 --- a/examples/resources/CMakeLists.txt +++ b/examples/resources/CMakeLists.txt @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,3 +14,4 @@ # limitations under the License. add_subdirectory(clock) +add_subdirectory(native) diff --git a/examples/resources/native/CMakeLists.txt b/examples/resources/native/CMakeLists.txt new file mode 100644 index 00000000..91b8d28e --- /dev/null +++ b/examples/resources/native/CMakeLists.txt @@ -0,0 +1,25 @@ +# SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +add_subdirectory(cpp) +add_subdirectory(python) + +file(RELATIVE_PATH app_relative_dest_path ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}) + +install( + FILES README.md + DESTINATION "${app_relative_dest_path}" + COMPONENT "holoscan-examples" +) diff --git a/examples/resources/native/README.md b/examples/resources/native/README.md new file mode 100644 index 00000000..24cbff8f --- /dev/null +++ b/examples/resources/native/README.md @@ -0,0 +1,47 @@ +# Native Resource Example +`` +This example demonstrates how a C++ `holoscan::Resource` (or Python `holoscan.core.Resource`) can be created without wrapping an underlying GXF Component. + +## C++ Run instructions + +* **using deb package install or NGC container**: + ```bash + /opt/nvidia/holoscan/examples/resources/native/cpp/native_resource + ``` +* **source (dev container)**: + ```bash + ./run launch # optional: append `install` for install tree + ./examples/resources/native/cpp/native_resource + ``` +* **source (local env)**: + ```bash + ${BUILD_OR_INSTALL_DIR}/examples/resources/native/cpp/native_resource + ``` + +## Python Run instructions + +* **using python wheel**: + ```bash + # [Prerequisite] Download example .py file below to `APP_DIR` + # [Optional] Start the virtualenv where holoscan is installed + python3 /native_resource.py + ``` +* **using deb package install**: + ```bash + export PYTHONPATH=/opt/nvidia/holoscan/python/lib + python3 /opt/nvidia/holoscan/examples/resources/native/python/native_resource.py + ``` +* **from NGC container**: + ```bash + python3 /opt/nvidia/holoscan/examples/resources/native/python/native_resource.py + ``` +* **source (dev container)**: + ```bash + ./run launch # optional: append `install` for install tree + python3 ./examples/resources/native/python/native_resource.py + ``` +* **source (local env)**: + ```bash + export PYTHONPATH=${BUILD_OR_INSTALL_DIR}/python/lib + python3 ${BUILD_OR_INSTALL_DIR}/examples/resources/native/python/native_resource.py + ``` diff --git a/examples/resources/native/cpp/CMakeLists.min.txt b/examples/resources/native/cpp/CMakeLists.min.txt new file mode 100644 index 00000000..41867a23 --- /dev/null +++ b/examples/resources/native/cpp/CMakeLists.min.txt @@ -0,0 +1,46 @@ +# SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the \"License\"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an \"AS IS\" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +cmake_minimum_required(VERSION 3.20) +project(holoscan_native_resource CXX) + +# Finds the package holoscan +find_package(holoscan REQUIRED CONFIG + PATHS "/opt/nvidia/holoscan" "/workspace/holoscan-sdk/install") + +add_executable(native_resource + native_resource.cpp +) + +target_link_libraries(native_resource + PRIVATE + holoscan::core +) + +# Testing +if(BUILD_TESTING) + add_test(NAME EXAMPLE_RESOURCES_CPP_NATIVE_RESOURCE_TEST + COMMAND native_resource + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + ) + set_tests_properties( + EXAMPLE_RESOURCES_CPP_NATIVE_RESOURCE_TEST PROPERTIES + PASS_REGULAR_EXPRESSION "string_native_resource.string_param: test_string" + PASS_REGULAR_EXPRESSION "hardcoded_native_resource.string_param: hardcoded_string" + PASS_REGULAR_EXPRESSION "empty_native_resource.string_param: ''" + FAIL_REGULAR_EXPRESSION "error" + FAIL_REGULAR_EXPRESSION "Exception occurred" + ) +endif() diff --git a/examples/resources/native/cpp/CMakeLists.txt b/examples/resources/native/cpp/CMakeLists.txt new file mode 100644 index 00000000..8ef384d7 --- /dev/null +++ b/examples/resources/native/cpp/CMakeLists.txt @@ -0,0 +1,70 @@ +# SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Create examples +add_executable(native_resource + native_resource.cpp +) +target_link_libraries(native_resource + PUBLIC + holoscan::core +) + +# Install examples + +# Set the install RPATH based on the location of the Holoscan SDK libraries +# The GXF extensions are loaded by the GXF libraries - no need to include here +file(RELATIVE_PATH install_lib_relative_path ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/${HOLOSCAN_INSTALL_LIB_DIR}) +set_target_properties(native_resource PROPERTIES INSTALL_RPATH "\$ORIGIN/${install_lib_relative_path}") + +# Install following the relative folder path +file(RELATIVE_PATH app_relative_dest_path ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}) + +if(HOLOSCAN_INSTALL_EXAMPLE_SOURCE) +# Install the source +install(FILES native_resource.cpp + DESTINATION "${app_relative_dest_path}" + COMPONENT holoscan-examples +) + +# Install the minimal CMakeLists.txt file +install(FILES CMakeLists.min.txt + RENAME "CMakeLists.txt" + DESTINATION "${app_relative_dest_path}" + COMPONENT holoscan-examples +) +endif() + +# Install the compiled example +install(TARGETS native_resource + DESTINATION "${app_relative_dest_path}" + COMPONENT holoscan-examples +) + +# Testing +if(HOLOSCAN_BUILD_TESTS) + add_test(NAME EXAMPLE_RESOURCES_CPP_NATIVE_RESOURCE_TEST + COMMAND native_resource + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + ) + set_tests_properties( + EXAMPLE_RESOURCES_CPP_NATIVE_RESOURCE_TEST PROPERTIES + PASS_REGULAR_EXPRESSION "string_native_resource.string_param: test_string" + PASS_REGULAR_EXPRESSION "hardcoded_native_resource.string_param: hardcoded_string" + PASS_REGULAR_EXPRESSION "empty_native_resource.string_param: ''" + FAIL_REGULAR_EXPRESSION "error" + FAIL_REGULAR_EXPRESSION "Exception occurred" + ) +endif() diff --git a/tests/system/native_resource_minimal_app.cpp b/examples/resources/native/cpp/native_resource.cpp similarity index 74% rename from tests/system/native_resource_minimal_app.cpp rename to examples/resources/native/cpp/native_resource.cpp index 30e42682..720a4dcf 100644 --- a/tests/system/native_resource_minimal_app.cpp +++ b/examples/resources/native/cpp/native_resource.cpp @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,16 +15,11 @@ * limitations under the License. */ -#include - +#include #include #include -#include "../config.hpp" - -static HoloscanTestConfig test_config; - namespace holoscan { class MinimalNativeResource : public holoscan::Resource { @@ -88,26 +83,11 @@ class MinimalNativeResourceApp : public holoscan::Application { } }; -TEST(MinimalNativeResourceApp, TestMinimalNativeResourceApp) { - auto app = make_application(); - - const std::string config_file = test_config.get_test_data_file("minimal.yaml"); - app->config(config_file); - - // capture output so that we can check that the expected value is present - testing::internal::CaptureStderr(); +} // namespace holoscan +int main(int argc, char** argv) { + auto app = holoscan::make_application(); app->run(); - std::string log_output = testing::internal::GetCapturedStderr(); - EXPECT_TRUE(log_output.find("string_native_resource.string_param: test_string") != - std::string::npos) - << log_output; - EXPECT_TRUE(log_output.find("hardcoded_native_resource.string_param: hardcoded_string") != - std::string::npos) - << log_output; - EXPECT_TRUE(log_output.find("empty_native_resource.string_param: ''") != std::string::npos) - << log_output; + return 0; } - -} // namespace holoscan diff --git a/examples/resources/native/python/CMakeLists.txt b/examples/resources/native/python/CMakeLists.txt new file mode 100644 index 00000000..210c2956 --- /dev/null +++ b/examples/resources/native/python/CMakeLists.txt @@ -0,0 +1,45 @@ +# SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Get relative folder path for the app +file(RELATIVE_PATH app_relative_dest_path ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}) + +# Copy native operator ping application +add_custom_target(python_native_resource ALL + COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/native_resource.py" ${CMAKE_CURRENT_BINARY_DIR} + DEPENDS "native_resource.py" + BYPRODUCTS "native_resource.py" +) + +# Install the app +install(FILES + "${CMAKE_CURRENT_SOURCE_DIR}/native_resource.py" + DESTINATION "${app_relative_dest_path}" + COMPONENT "holoscan-examples" +) + +# Testing +if(HOLOSCAN_BUILD_TESTS) + add_test(NAME EXAMPLE_RESOURCES_PYTHON_NATIVE_RESOURCE_TEST + COMMAND python3 native_resource.py + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + ) + set_tests_properties(EXAMPLE_RESOURCES_PYTHON_NATIVE_RESOURCE_TEST PROPERTIES + PASS_REGULAR_EXPRESSION "native resource setup method called" + PASS_REGULAR_EXPRESSION "MinimalOp compute method called" + FAIL_REGULAR_EXPRESSION "error" + FAIL_REGULAR_EXPRESSION "Exception occurred" + ) +endif() diff --git a/examples/resources/native/python/native_resource.py b/examples/resources/native/python/native_resource.py new file mode 100644 index 00000000..adae6a80 --- /dev/null +++ b/examples/resources/native/python/native_resource.py @@ -0,0 +1,80 @@ +""" + SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + SPDX-License-Identifier: Apache-2.0 + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +""" # noqa: E501 + +from holoscan.conditions import CountCondition +from holoscan.core import Application, ComponentSpec, Operator, Resource + + +class NativeResource(Resource): + def __init__(self, fragment, msg="test", *args, **kwargs): + self.msg = msg + super().__init__(fragment, *args, **kwargs) + + def setup(self, spec: ComponentSpec): + print("** native resource setup method called **") + + def get_message(self): + return self.msg + + +class MinimalOp(Operator): + def __init__(self, *args, expected_message="test", **kwargs): + self.expected_message = expected_message + # Need to call the base class constructor last + super().__init__(*args, **kwargs) + + def compute(self, op_input, op_output, context): + print("** MinimalOp compute method called **") + resource = self.resource("msg_resource") + assert isinstance(resource, NativeResource) + + # can call a custom method implemented for the resource + msg = resource.get_message() + assert msg == self.expected_message + + # test case when no resource with the specified name exists + nonexistent_resource = self.resource("nonexistent") + assert nonexistent_resource is None + + # test retrieving all resources + resources = self.resources + assert isinstance(resources, dict) + assert len(resources) == 1 + assert isinstance(resources["msg_resource"], NativeResource) + + +class MinimalNativeResourceApp(Application): + def compose(self): + msg = "native resource message" + native_resource = NativeResource(self, msg=msg, name="msg_resource") + mx = MinimalOp( + self, + CountCondition(self, 1), + native_resource, + expected_message=msg, + name="mx", + ) + self.add_operator(mx) + + +def main(): + app = MinimalNativeResourceApp() + app.run() + + +if __name__ == "__main__": + main() diff --git a/examples/v4l2_camera/cpp/v4l2_camera.cpp b/examples/v4l2_camera/cpp/v4l2_camera.cpp index e2773d6d..c4f396b2 100644 --- a/examples/v4l2_camera/cpp/v4l2_camera.cpp +++ b/examples/v4l2_camera/cpp/v4l2_camera.cpp @@ -43,9 +43,9 @@ class App : public holoscan::Application { if (key_exists(from_config("source"), "width") && key_exists(from_config("source"), "height")) { // width and height given, use BlockMemoryPool (better latency) - const int width = from_config("source.width").as(); - const int height = from_config("source.height").as(); - const int n_channels = 4; + const uint64_t width = from_config("source.width").as(); + const uint64_t height = from_config("source.height").as(); + const uint8_t n_channels = 4; uint64_t block_size = width * height * n_channels; auto allocator = make_resource("pool", 0, block_size, 1); diff --git a/include/holoscan/core/application.hpp b/include/holoscan/core/application.hpp index 4be1ace5..f0a83d7c 100644 --- a/include/holoscan/core/application.hpp +++ b/include/holoscan/core/application.hpp @@ -28,12 +28,14 @@ #include "./fragment.hpp" -#include "./app_driver.hpp" #include "./app_worker.hpp" #include "./cli_parser.hpp" namespace holoscan { +// forward declaration +class AppDriver; + /** * @brief Utility function to create an application. * @@ -343,7 +345,7 @@ class Application : public Fragment { CLIParser cli_parser_; ///< The command line parser. std::vector argv_; ///< The command line arguments after processing flags. - std::unique_ptr fragment_graph_; ///< The fragment connection graph. + std::shared_ptr fragment_graph_; ///< The fragment connection graph. std::shared_ptr app_driver_; ///< The application driver. std::shared_ptr app_worker_; ///< The application worker. diff --git a/include/holoscan/core/codec_registry.hpp b/include/holoscan/core/codec_registry.hpp index 905a5108..7cfdb209 100644 --- a/include/holoscan/core/codec_registry.hpp +++ b/include/holoscan/core/codec_registry.hpp @@ -257,7 +257,7 @@ class CodecRegistry { * @param overwrite if true, any existing codec with matching codec_name will be overwritten. */ template - void add_codec(std::pair codec, const std::string& codec_name, + void add_codec(std::pair& codec, const std::string& codec_name, bool overwrite = true) { auto index = std::type_index(typeid(typeT)); add_codec(index, codec, codec_name, overwrite); @@ -271,7 +271,7 @@ class CodecRegistry { * @param codec_name the name of the codec to add. * @param overwrite if true, any existing codec with matching codec_name will be overwritten. */ - void add_codec(const std::type_index& index, std::pair codec, + void add_codec(const std::type_index& index, std::pair& codec, const std::string& codec_name, bool overwrite = true) { auto name_search = name_to_index_map_.find(codec_name); if (name_search != name_to_index_map_.end()) { diff --git a/include/holoscan/core/component_spec-inl.hpp b/include/holoscan/core/component_spec-inl.hpp index 718501d9..bcd9bcf5 100644 --- a/include/holoscan/core/component_spec-inl.hpp +++ b/include/holoscan/core/component_spec-inl.hpp @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: Copyright (c) 2022-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,8 +21,6 @@ #include #include -#include "./component_spec.hpp" - #include "./argument_setter.hpp" #include "./executors/gxf/gxf_parameter_adaptor.hpp" diff --git a/include/holoscan/core/condition.hpp b/include/holoscan/core/condition.hpp index a9567843..accc6ba2 100644 --- a/include/holoscan/core/condition.hpp +++ b/include/holoscan/core/condition.hpp @@ -98,6 +98,7 @@ namespace holoscan { // Forward declarations class Operator; +class Resource; // Note: Update `IOSpec::to_yaml_node()` if you add new condition types enum class ConditionType { @@ -109,6 +110,7 @@ enum class ConditionType { kBoolean, ///< nvidia::gxf::BooleanSchedulingTerm kPeriodic, ///< nvidia::gxf::PeriodicSchedulingTerm kAsynchronous, ///< nvidia::gxf::AsynchronousSchedulingTerm + kExpiringMessageAvailable, ///< nvidia::gxf::ExpiringMessageAvailableSchedulingTerm }; /** @@ -196,6 +198,27 @@ class Condition : public Component { using Component::add_arg; + /** + * @brief Add a resource to the condition. + * + * @param arg The resource to add. + */ + void add_arg(const std::shared_ptr& arg); + + /** + * @brief Add a resource to the condition. + * + * @param arg The resource to add. + */ + void add_arg(std::shared_ptr&& arg); + + /** + * @brief Get the resources of the condition. + * + * @return The resources of the condition. + */ + std::unordered_map>& resources() { return resources_; } + /** * @brief Define the condition specification. * @@ -217,6 +240,9 @@ class Condition : public Component { using Component::reset_graph_entities; bool is_initialized_ = false; ///< Whether the condition is initialized. + + std::unordered_map> + resources_; ///< The resources used by the condition. }; } // namespace holoscan diff --git a/include/holoscan/core/conditions/gxf/expiring_message.hpp b/include/holoscan/core/conditions/gxf/expiring_message.hpp new file mode 100644 index 00000000..467bb212 --- /dev/null +++ b/include/holoscan/core/conditions/gxf/expiring_message.hpp @@ -0,0 +1,108 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef HOLOSCAN_CORE_CONDITIONS_GXF_EXPIRING_MESSAGE_HPP +#define HOLOSCAN_CORE_CONDITIONS_GXF_EXPIRING_MESSAGE_HPP + +#include + +#include "../../gxf/gxf_condition.hpp" +#include "../../resources/gxf/clock.hpp" +#include "../../resources/gxf/realtime_clock.hpp" + +namespace holoscan { + +class ExpiringMessageAvailableCondition : public gxf::GXFCondition { + public: + HOLOSCAN_CONDITION_FORWARD_ARGS_SUPER(ExpiringMessageAvailableCondition, GXFCondition) + + ExpiringMessageAvailableCondition() = default; + + explicit ExpiringMessageAvailableCondition(int64_t max_batch_size) + : max_batch_size_(max_batch_size) {} + + ExpiringMessageAvailableCondition(int64_t max_batch_size, int64_t max_delay_ns) + : max_batch_size_(max_batch_size), max_delay_ns_(max_delay_ns) {} + + template + explicit ExpiringMessageAvailableCondition(int64_t max_batch_size, + std::chrono::duration max_delay) + : max_batch_size_(max_batch_size) { + max_delay_ns_ = std::chrono::duration_cast(max_delay).count(); + } + + const char* gxf_typename() const override { + return "nvidia::gxf::ExpiringMessageAvailableSchedulingTerm"; + } + + void receiver(std::shared_ptr receiver) { receiver_ = receiver; } + std::shared_ptr receiver() { return receiver_.get(); } + + void setup(ComponentSpec& spec) override; + + void initialize() override; + + void max_batch_size(int64_t max_batch_size); + int64_t max_batch_size() { return max_batch_size_; } + + /** + * @brief Set max delay. + * + * Note that calling this method doesn't affect the behavior of the condition once the condition + * is initialized. + * + * @param max_delay_ns The integer representing max delay in nanoseconds. + */ + void max_delay(int64_t max_delay_ns); + + /** + * @brief Set max delay. + * + * Note that calling this method doesn't affect the behavior of the condition once the + * condition is initialized. + * + * @param max_delay_duration The max delay of type `std::chrono::duration`. + */ + template + void max_delay(std::chrono::duration max_delay_duration) { + int64_t max_delay_ns = + std::chrono::duration_cast(max_delay_duration).count(); + max_delay(max_delay_ns); + } + + /** + * @brief Get max delay in nano seconds. + * + * @return The minimum time which needs to elapse between two executions (in nano seconds) + */ + int64_t max_delay_ns(); + + nvidia::gxf::ExpiringMessageAvailableSchedulingTerm* get() const; + + // TODO(GXF4): Expected setReceiver(Handle value) + + private: + // TODO(GXF4): this is now a std::set> receivers_ + Parameter> receiver_; + Parameter max_batch_size_; + Parameter max_delay_ns_; + Parameter> clock_; +}; + +} // namespace holoscan + +#endif /* HOLOSCAN_CORE_CONDITIONS_GXF_EXPIRING_MESSAGE_HPP */ diff --git a/include/holoscan/core/conditions/gxf/message_available.hpp b/include/holoscan/core/conditions/gxf/message_available.hpp index 1ea924fb..2126eb0b 100644 --- a/include/holoscan/core/conditions/gxf/message_available.hpp +++ b/include/holoscan/core/conditions/gxf/message_available.hpp @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/include/holoscan/core/config.hpp b/include/holoscan/core/config.hpp index 08b9957d..8c355ff9 100644 --- a/include/holoscan/core/config.hpp +++ b/include/holoscan/core/config.hpp @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -48,9 +48,12 @@ class Config { HOLOSCAN_LOG_WARN("Config file '{}' doesn't exist", config_file); } } - virtual ~Config() = default; + // Delete the copy constructor and assignment operator to prevent copying. + Config(const Config&) = delete; + Config& operator=(const Config&) = delete; + /** * @brief Get the path to the configuration file. * diff --git a/include/holoscan/core/domain/tensor.hpp b/include/holoscan/core/domain/tensor.hpp index 7abe0d9f..706c6e95 100644 --- a/include/holoscan/core/domain/tensor.hpp +++ b/include/holoscan/core/domain/tensor.hpp @@ -43,7 +43,7 @@ using DLManagedMemoryBuffer = nvidia::gxf::DLManagedMemoryBuffer; * * The Tensor class is a wrapper around the DLManagedTensorContext struct that holds the * DLManagedTensor object. - * (https://dmlc.github.io/dlpack/latest/c_api.html#_CPPv415DLManagedTensor). + * (https://dmlc.github.io/dlpack/latest/c_api.html#c.DLManagedTensor). * * This class provides a primary interface to access Tensor data and is interoperable with other * frameworks that support DLManagedTensor. diff --git a/include/holoscan/core/endpoint.hpp b/include/holoscan/core/endpoint.hpp index ec3585b3..dcadc01c 100644 --- a/include/holoscan/core/endpoint.hpp +++ b/include/holoscan/core/endpoint.hpp @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: Copyright (c) 2022-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -119,7 +119,7 @@ class Endpoint : public Resource { } private: - nvidia::gxf::Endpoint* gxf_endpoint_; + nvidia::gxf::Endpoint* gxf_endpoint_ = nullptr; }; } // namespace holoscan diff --git a/include/holoscan/core/execution_context.hpp b/include/holoscan/core/execution_context.hpp index 11221ec3..9f362261 100644 --- a/include/holoscan/core/execution_context.hpp +++ b/include/holoscan/core/execution_context.hpp @@ -35,6 +35,8 @@ class ExecutionContext { */ ExecutionContext() = default; + virtual ~ExecutionContext() = default; + /** * @brief Get the input context. * diff --git a/include/holoscan/core/executor.hpp b/include/holoscan/core/executor.hpp index 9fe75006..8be0c761 100644 --- a/include/holoscan/core/executor.hpp +++ b/include/holoscan/core/executor.hpp @@ -51,6 +51,10 @@ class Executor { explicit Executor(Fragment* fragment) : fragment_(fragment) {} virtual ~Executor() = default; + // Delete the copy constructor and assignment operator to prevent copying. + Executor(const Executor&) = delete; + Executor& operator=(const Executor&) = delete; + /** * @brief Run the graph. * diff --git a/include/holoscan/core/executors/gxf/gxf_executor.hpp b/include/holoscan/core/executors/gxf/gxf_executor.hpp index 803c4c7b..73153d75 100644 --- a/include/holoscan/core/executors/gxf/gxf_executor.hpp +++ b/include/holoscan/core/executors/gxf/gxf_executor.hpp @@ -89,7 +89,7 @@ class GXFExecutor : public holoscan::Executor { /** * @brief Set the context. * - * For GXF, GXFExtensionManager(gxf_extension_manager_) is initialized with the context. + * For GXF, GXFExtensionManager(extension_manager_) is initialized with the context. * * @param context The context. */ @@ -220,11 +220,8 @@ class GXFExecutor : public holoscan::Executor { ///< initializing a new operator if this is 0. gxf_uid_t op_cid_ = 0; ///< The GXF component ID of the operator. Create new component for ///< initializing a new operator if this is 0. - std::shared_ptr gxf_extension_manager_; ///< The GXF extension manager. nvidia::gxf::Extension* gxf_holoscan_extension_ = nullptr; ///< The GXF holoscan extension. - /// The flag to indicate whether the extensions are loaded. - bool is_extensions_loaded_ = false; /// The flag to indicate whether the GXF graph is initialized. bool is_gxf_graph_initialized_ = false; /// The flag to indicate whether the GXF graph is activated. diff --git a/include/holoscan/core/fragment.hpp b/include/holoscan/core/fragment.hpp index abd11ae7..a2e465ec 100644 --- a/include/holoscan/core/fragment.hpp +++ b/include/holoscan/core/fragment.hpp @@ -188,6 +188,13 @@ class Fragment { */ Config& config(); + /** + * @brief Get the shared pointer to the configuration of the fragment. + * + * @return The shared pointer to the configuration of the fragment. + */ + std::shared_ptr config_shared(); + /** * @brief Get the graph of the fragment. * @@ -195,6 +202,13 @@ class Fragment { */ OperatorGraph& graph(); + /** + * @brief Get the shared pointer to the graph of the fragment. + * + * @return The shared pointer to the graph of the fragment. + */ + std::shared_ptr graph_shared(); + /** * @brief Get the executor of the fragment. * @@ -202,6 +216,13 @@ class Fragment { */ Executor& executor(); + /** + * @brief Get the shared pointer to the executor of the fragment. + * + * @return The shared pointer to the executor of the fragment. + */ + std::shared_ptr executor_shared(); + /** * @brief Get the scheduler used by the executor * @@ -656,8 +677,8 @@ class Fragment { } template - std::unique_ptr make_graph() { - return std::make_unique(); + std::shared_ptr make_graph() { + return std::make_shared(); } template @@ -666,20 +687,23 @@ class Fragment { } template - std::unique_ptr make_executor(ArgsT&&... args) { - return std::make_unique(std::forward(args)...); + std::shared_ptr make_executor(ArgsT&&... args) { + return std::make_shared(std::forward(args)...); } /// Cleanup helper that will by called by GXFExecutor prior to GxfContextDestroy. void reset_graph_entities(); + /// Load the GXF extensions specified in the configuration. + void load_extensions_from_config(); + // Note: Maintain the order of declarations (executor_ and graph_) to ensure proper destruction // of the executor's context. std::string name_; ///< The name of the fragment. Application* app_ = nullptr; ///< The application that this fragment belongs to. std::shared_ptr config_; ///< The configuration of the fragment. std::shared_ptr executor_; ///< The executor for the fragment. - std::unique_ptr graph_; ///< The graph of the fragment. + std::shared_ptr graph_; ///< The graph of the fragment. std::shared_ptr scheduler_; ///< The scheduler used by the executor std::shared_ptr network_context_; ///< The network_context used by the executor std::shared_ptr data_flow_tracker_; ///< The DataFlowTracker for the fragment diff --git a/include/holoscan/core/graph.hpp b/include/holoscan/core/graph.hpp index ca5da60d..b883766a 100644 --- a/include/holoscan/core/graph.hpp +++ b/include/holoscan/core/graph.hpp @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: Copyright (c) 2022-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -61,6 +61,10 @@ class Graph { Graph() = default; virtual ~Graph() = default; + // Delete the copy constructor and assignment operator to prevent copying. + Graph(const Graph&) = delete; + Graph& operator=(const Graph&) = delete; + /** * @brief Add the node to the graph. * diff --git a/include/holoscan/core/gxf/entity.hpp b/include/holoscan/core/gxf/entity.hpp index 7bb0e9db..5646914e 100644 --- a/include/holoscan/core/gxf/entity.hpp +++ b/include/holoscan/core/gxf/entity.hpp @@ -19,6 +19,7 @@ #define HOLOSCAN_CORE_GXF_ENTITY_HPP #include +#include // Entity definition // Since it has code that causes a warning as an error, we disable it here. @@ -47,7 +48,7 @@ class Entity : public nvidia::gxf::Entity { public: Entity() = default; explicit Entity(const nvidia::gxf::Entity& other) : nvidia::gxf::Entity(other) {} - explicit Entity(nvidia::gxf::Entity&& other) : nvidia::gxf::Entity(other) {} + explicit Entity(nvidia::gxf::Entity&& other) : nvidia::gxf::Entity(std::move(other)) {} // Creates a new entity static Entity New(ExecutionContext* context); @@ -122,7 +123,7 @@ class Entity : public nvidia::gxf::Entity { auto handle = nvidia::gxf::Handle::Create(context(), cid); nvidia::gxf::Tensor* tensor_ptr = handle->get(); - // Copy the member data (std::shared_ptr) from the Tensor to the + // Copy the member data (std::shared_ptr) from the Tensor to the // nvidia::gxf::Tensor *tensor_ptr = nvidia::gxf::Tensor(data->dl_ctx()); } diff --git a/include/holoscan/core/gxf/gxf_component.hpp b/include/holoscan/core/gxf/gxf_component.hpp index 2763c247..18f964ed 100644 --- a/include/holoscan/core/gxf/gxf_component.hpp +++ b/include/holoscan/core/gxf/gxf_component.hpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include "../parameter.hpp" @@ -55,7 +56,7 @@ class GXFComponent { std::shared_ptr gxf_graph_entity() { return gxf_graph_entity_; } void gxf_graph_entity(std::shared_ptr graph_entity) { - gxf_graph_entity_ = graph_entity; + gxf_graph_entity_ = std::move(graph_entity); } void* gxf_cptr() { return gxf_cptr_; } diff --git a/include/holoscan/core/gxf/gxf_execution_context.hpp b/include/holoscan/core/gxf/gxf_execution_context.hpp index 99cc919c..6fac2020 100644 --- a/include/holoscan/core/gxf/gxf_execution_context.hpp +++ b/include/holoscan/core/gxf/gxf_execution_context.hpp @@ -52,6 +52,7 @@ class GXFExecutionContext : public holoscan::ExecutionContext { GXFExecutionContext(gxf_context_t context, std::shared_ptr gxf_input_context, std::shared_ptr gxf_output_context); + ~GXFExecutionContext() override = default; /** * @brief Get the GXF input context. * diff --git a/include/holoscan/core/gxf/gxf_io_context.hpp b/include/holoscan/core/gxf/gxf_io_context.hpp index 3963f188..ea98f64a 100644 --- a/include/holoscan/core/gxf/gxf_io_context.hpp +++ b/include/holoscan/core/gxf/gxf_io_context.hpp @@ -97,7 +97,8 @@ class GXFOutputContext : public OutputContext { protected: void emit_impl(std::any data, const char* name = nullptr, - OutputType out_type = OutputType::kSharedPointer) override; + OutputType out_type = OutputType::kSharedPointer, + const int64_t acq_timestamp = -1) override; }; } // namespace holoscan::gxf diff --git a/include/holoscan/core/io_context.hpp b/include/holoscan/core/io_context.hpp index 030d7004..59920f6b 100644 --- a/include/holoscan/core/io_context.hpp +++ b/include/holoscan/core/io_context.hpp @@ -39,6 +39,10 @@ namespace holoscan { +// To indicate that data is not available for the input port +struct NoMessageType {}; +constexpr NoMessageType kNoReceivedMessage; + static inline std::string get_well_formed_name( const char* name, const std::unordered_map>& io_list) { std::string well_formed_name; @@ -293,29 +297,13 @@ class InputContext { // If it is not a vector then try to get the input directly and convert for respective data // type for an input auto value = receive_impl(name); - // If the received data is nullptr, then check whether nullptr or empty holoscan::gxf::Entity - // can be sent - if (value.type() == typeid(nullptr_t)) { - HOLOSCAN_LOG_DEBUG("nullptr is received from the input port with name '{}'", name); - // If it is a shared pointer, or raw pointer then return nullptr because it might be a valid - // nullptr - if constexpr (holoscan::is_shared_ptr_v) { - return nullptr; - } else if constexpr (std::is_pointer_v) { - return nullptr; - } - // If it's holoscan::gxf::Entity then return an error message - if constexpr (is_one_of_derived_v) { - auto error_message = fmt::format( - "Null received in place of nvidia::gxf::Entity or derived type for input {}", name); - return make_unexpected( - holoscan::RuntimeError(holoscan::ErrorCode::kReceiveError, error_message.c_str())); - } else if constexpr (is_one_of_derived_v) { - auto error_message = fmt::format( - "Null received in place of holoscan::TensorMap or derived type for input {}", name); - return make_unexpected( - holoscan::RuntimeError(holoscan::ErrorCode::kReceiveError, error_message.c_str())); - } + // If no message is received, return an error message + if (value.type() == typeid(NoMessageType)) { + HOLOSCAN_LOG_DEBUG("No message is received from the input port with name '{}'", name); + auto error_message = + fmt::format("No message is received from the input port with name '{}'", name); + return make_unexpected( + holoscan::RuntimeError(holoscan::ErrorCode::kReceiveError, error_message.c_str())); } try { // Check if the types of value and DataT are the same or not @@ -323,6 +311,17 @@ class InputContext { DataT return_value = std::any_cast(value); return return_value; } catch (const std::bad_any_cast& e) { + // If the received data is nullptr, check whether the sent value was nullptr + if (value.type() == typeid(nullptr_t)) { + HOLOSCAN_LOG_DEBUG("nullptr is received from the input port with name '{}'", name); + // If it is a shared pointer or raw pointer, then return nullptr + if constexpr (holoscan::is_shared_ptr_v) { + return nullptr; + } else if constexpr (std::is_pointer_v) { + return nullptr; + } + } + // If it is of the type of holoscan::gxf::Entity then show a specific error message if constexpr (is_one_of_derived_v) { auto error_message = fmt::format( @@ -504,11 +503,14 @@ class OutputContext { * @tparam DataT The type of the data to send. * @param data The shared pointer to the data. * @param name The name of the output port. + * @param acq_timestamp The time when the message is acquired. For instance, this would generally + * be the timestamp of the camera when it captures an image. */ template >> - void emit(std::shared_ptr& data, const char* name = nullptr) { - emit_impl(data, name); + void emit(std::shared_ptr& data, const char* name = nullptr, + const int64_t acq_timestamp = -1) { + emit_impl(data, name, OutputType::kSharedPointer, acq_timestamp); } /** @@ -559,17 +561,19 @@ class OutputContext { * @tparam DataT The type of the data to send. It should be `holoscan::gxf::Entity`. * @param data The entity object to send (`holoscan::gxf::Entity`). * @param name The name of the output port. + * @param acq_timestamp The time when the message is acquired. For instance, this would generally + * be the timestamp of the camera when it captures an image. */ template >> - void emit(DataT& data, const char* name = nullptr) { + void emit(DataT& data, const char* name = nullptr, const int64_t acq_timestamp = -1) { // if it is the same as nvidia::gxf::Entity then just pass it to emit_impl if constexpr (holoscan::is_one_of_v) { - emit_impl(data, name, OutputType::kGXFEntity); + emit_impl(data, name, OutputType::kGXFEntity, acq_timestamp); } else { // Convert it to nvidia::gxf::Entity and then pass it to emit_impl // Otherwise, we will lose the type information and cannot cast appropriately in emit_impl - emit_impl(nvidia::gxf::Entity(data), name, OutputType::kGXFEntity); + emit_impl(nvidia::gxf::Entity(data), name, OutputType::kGXFEntity, acq_timestamp); } } @@ -621,17 +625,20 @@ class OutputContext { * (std::shared_ptr) or the GXF Entity (holoscan::gxf::Entity) type. * @param data The entity object to send (as `std::any`). * @param name The name of the output port. + * @param acq_timestamp The time when the message is acquired. For instance, this would generally + * be the timestamp of the camera when it captures an image. */ template >> - void emit(DataT data, const char* name = nullptr) { - emit_impl(data, name, OutputType::kAny); + void emit(DataT data, const char* name = nullptr, const int64_t acq_timestamp = -1) { + emit_impl(std::move(data), name, OutputType::kAny, acq_timestamp); } - void emit(holoscan::TensorMap& data, const char* name = nullptr) { + void emit(holoscan::TensorMap& data, const char* name = nullptr, + const int64_t acq_timestamp = -1) { auto out_message = holoscan::gxf::Entity::New(execution_context_); for (auto& [key, tensor] : data) { out_message.add(tensor, key.c_str()); } - emit(out_message, name); + emit(out_message, name, acq_timestamp); } protected: @@ -645,12 +652,10 @@ class OutputContext { * @param name The name of the output port. * @param out_type The type of the message data. */ - virtual void emit_impl(std::any data, const char* name = nullptr, - OutputType out_type = OutputType::kSharedPointer) { - (void)data; - (void)name; - (void)out_type; - } + virtual void emit_impl([[maybe_unused]] std::any data, + [[maybe_unused]] const char* name = nullptr, + [[maybe_unused]] OutputType out_type = OutputType::kSharedPointer, + [[maybe_unused]] const int64_t acq_timestamp = -1) {} ExecutionContext* execution_context_ = nullptr; ///< The execution context that is associated with. diff --git a/include/holoscan/core/io_spec.hpp b/include/holoscan/core/io_spec.hpp index b0cfb171..087cdeae 100644 --- a/include/holoscan/core/io_spec.hpp +++ b/include/holoscan/core/io_spec.hpp @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: Copyright (c) 2022-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -35,6 +35,7 @@ #include "./conditions/gxf/downstream_affordable.hpp" #include "./conditions/gxf/periodic.hpp" #include "./conditions/gxf/message_available.hpp" +#include "./conditions/gxf/expiring_message.hpp" #include "./resources/gxf/double_buffer_receiver.hpp" #include "./resources/gxf/double_buffer_transmitter.hpp" #include "./resources/gxf/ucx_receiver.hpp" @@ -172,6 +173,11 @@ class IOSpec { conditions_.emplace_back( type, std::make_shared(std::forward(args)...)); break; + case ConditionType::kExpiringMessageAvailable: + conditions_.emplace_back( + type, + std::make_shared(std::forward(args)...)); + break; case ConditionType::kDownstreamMessageAffordable: conditions_.emplace_back( type, @@ -199,7 +205,7 @@ class IOSpec { * * @param connector The connector (transmitter or receiver) of this input/output. */ - void connector(std::shared_ptr connector) { connector_ = connector; } + void connector(std::shared_ptr connector) { connector_ = std::move(connector); } /** * @brief Add a connector (receiver/transmitter) to this input/output. diff --git a/include/holoscan/core/resources/gxf/gxf_component_resource.hpp b/include/holoscan/core/resources/gxf/gxf_component_resource.hpp index a545584a..603a0fe9 100644 --- a/include/holoscan/core/resources/gxf/gxf_component_resource.hpp +++ b/include/holoscan/core/resources/gxf/gxf_component_resource.hpp @@ -74,7 +74,7 @@ namespace holoscan { explicit class_name(ArgT&& arg, ArgsT&&... args) \ : ::holoscan::GXFComponentResource(gxf_typename, std::forward(arg), \ std::forward(args)...) {} \ - class_name() = default; \ + class_name() : ::holoscan::GXFComponentResource(gxf_typename) {} \ }; /** diff --git a/include/holoscan/core/services/common/virtual_operator.hpp b/include/holoscan/core/services/common/virtual_operator.hpp index 4cdd616d..5ae7af8d 100644 --- a/include/holoscan/core/services/common/virtual_operator.hpp +++ b/include/holoscan/core/services/common/virtual_operator.hpp @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -42,7 +42,7 @@ class VirtualOperator : public holoscan::Operator { template >> VirtualOperator(StringT port_name, IOSpec::ConnectorType connector_type, ArgList arg_list) - : port_name_(port_name), connector_type_(connector_type), arg_list_(arg_list) { + : port_name_(std::move(port_name)), connector_type_(connector_type), arg_list_(arg_list) { operator_type_ = OperatorType::kVirtual; } diff --git a/include/holoscan/core/system/gpu_resource_monitor.hpp b/include/holoscan/core/system/gpu_resource_monitor.hpp index 2ef6ee7b..e5186a80 100644 --- a/include/holoscan/core/system/gpu_resource_monitor.hpp +++ b/include/holoscan/core/system/gpu_resource_monitor.hpp @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -231,8 +231,8 @@ class GPUResourceMonitor { bool init_nvml(); bool init_cuda_runtime(); - void shutdown_nvml(); - void shutdown_cuda_runtime(); + void shutdown_nvml() noexcept; + void shutdown_cuda_runtime() noexcept; void* handle_ = nullptr; ///< The handle of the GPU resource monitor void* cuda_handle_ = nullptr; ///< The handle of the CUDA Runtime library diff --git a/include/holoscan/holoscan.hpp b/include/holoscan/holoscan.hpp index 2042e645..d1a1d13c 100644 --- a/include/holoscan/holoscan.hpp +++ b/include/holoscan/holoscan.hpp @@ -51,23 +51,24 @@ #include "./core/network_contexts/gxf/ucx_context.hpp" // Resources -#include "./core/resources/gxf/clock.hpp" #include "./core/resources/gxf/block_memory_pool.hpp" -#include "./core/resources/gxf/manual_clock.hpp" +#include "./core/resources/gxf/clock.hpp" +#include "./core/resources/gxf/cuda_stream_pool.hpp" #include "./core/resources/gxf/double_buffer_receiver.hpp" #include "./core/resources/gxf/double_buffer_transmitter.hpp" +#include "./core/resources/gxf/gxf_component_resource.hpp" +#include "./core/resources/gxf/manual_clock.hpp" #include "./core/resources/gxf/realtime_clock.hpp" -#include "./core/resources/gxf/cuda_stream_pool.hpp" #include "./core/resources/gxf/serialization_buffer.hpp" #include "./core/resources/gxf/std_component_serializer.hpp" #include "./core/resources/gxf/std_entity_serializer.hpp" -#include "./core/resources/gxf/unbounded_allocator.hpp" #include "./core/resources/gxf/ucx_component_serializer.hpp" #include "./core/resources/gxf/ucx_entity_serializer.hpp" #include "./core/resources/gxf/ucx_holoscan_component_serializer.hpp" #include "./core/resources/gxf/ucx_receiver.hpp" #include "./core/resources/gxf/ucx_serialization_buffer.hpp" #include "./core/resources/gxf/ucx_transmitter.hpp" +#include "./core/resources/gxf/unbounded_allocator.hpp" // Schedulers #include "./core/schedulers/gxf/event_based_scheduler.hpp" diff --git a/include/holoscan/operators/aja_source/aja_source.hpp b/include/holoscan/operators/aja_source/aja_source.hpp index bb0ee972..25ae4968 100644 --- a/include/holoscan/operators/aja_source/aja_source.hpp +++ b/include/holoscan/operators/aja_source/aja_source.hpp @@ -112,8 +112,8 @@ class AJASourceOp : public holoscan::Operator { // internal state CNTV2Card device_; - NTV2DeviceID device_id_; - NTV2VideoFormat video_format_; + NTV2DeviceID device_id_ = DEVICE_ID_NOTFOUND; + NTV2VideoFormat video_format_ = NTV2_FORMAT_1080p_6000_A; NTV2PixelFormat pixel_format_ = NTV2_FBF_ABGR; bool use_tsi_ = false; bool is_kona_hdmi_ = false; diff --git a/include/holoscan/operators/bayer_demosaic/bayer_demosaic.hpp b/include/holoscan/operators/bayer_demosaic/bayer_demosaic.hpp index c969d33f..49519e0a 100644 --- a/include/holoscan/operators/bayer_demosaic/bayer_demosaic.hpp +++ b/include/holoscan/operators/bayer_demosaic/bayer_demosaic.hpp @@ -15,8 +15,8 @@ * limitations under the License. */ -#ifndef HOLOSCAN_OPERATORS_BAYER_DEMOSAIC_HPP -#define HOLOSCAN_OPERATORS_BAYER_DEMOSAIC_HPP +#ifndef HOLOSCAN_OPERATORS_BAYER_DEMOSAIC_BAYER_DEMOSAIC_HPP +#define HOLOSCAN_OPERATORS_BAYER_DEMOSAIC_BAYER_DEMOSAIC_HPP #include @@ -123,8 +123,9 @@ class BayerDemosaicOp : public holoscan::Operator { NppStreamContext npp_stream_ctx_{}; - NppiInterpolationMode npp_bayer_interp_mode_; - NppiBayerGridPosition npp_bayer_grid_pos_; + // defaults here will be overridden later by parameter defaults in setup method + NppiInterpolationMode npp_bayer_interp_mode_ = NPPI_INTER_UNDEFINED; + NppiBayerGridPosition npp_bayer_grid_pos_ = NPPI_BAYER_GBRG; nvidia::gxf::MemoryBuffer device_scratch_buffer_; @@ -133,4 +134,4 @@ class BayerDemosaicOp : public holoscan::Operator { } // namespace holoscan::ops -#endif /* HOLOSCAN_OPERATORS_BAYER_DEMOSAIC_HPP */ +#endif /* HOLOSCAN_OPERATORS_BAYER_DEMOSAIC_BAYER_DEMOSAIC_HPP */ diff --git a/include/holoscan/operators/holoviz/holoviz.hpp b/include/holoscan/operators/holoviz/holoviz.hpp index 91ae2dea..4d00b022 100644 --- a/include/holoscan/operators/holoviz/holoviz.hpp +++ b/include/holoscan/operators/holoviz/holoviz.hpp @@ -498,9 +498,9 @@ class HolovizOp : public Operator { std::vector lut_; std::vector initial_input_spec_; CudaStreamHandler cuda_stream_handler_; - bool render_buffer_input_enabled_; - bool render_buffer_output_enabled_; - bool camera_pose_output_enabled_; + bool render_buffer_input_enabled_ = false; + bool render_buffer_output_enabled_ = false; + bool camera_pose_output_enabled_ = false; bool is_first_tick_ = true; std::array camera_eye_cur_; //< current camera eye position diff --git a/include/holoscan/operators/inference/inference.hpp b/include/holoscan/operators/inference/inference.hpp index c1c0246b..e87d60ab 100644 --- a/include/holoscan/operators/inference/inference.hpp +++ b/include/holoscan/operators/inference/inference.hpp @@ -69,8 +69,10 @@ namespace holoscan::ops { * - **pre_processor_map**: Pre processed data to model map. * - **device_map**: Mapping of model (`DataMap`) to GPU ID for inference. Optional. * - **backend_map**: Mapping of model (`DataMap`) to backend type for inference. - * - **temporal_map**: Mapping of model (`DataMap`) to a frame delay for model inference. Optional. * Backend options: `"trt"` or `"torch"`. Optional. + * - **temporal_map**: Mapping of model (`DataMap`) to a frame delay for model inference. Optional. + * - **activation_map**: Mapping of model (`DataMap`) to a activation state for model inference. + * Optional. * - **in_tensor_names**: Input tensors (`std::vector`). Optional. * - **out_tensor_names**: Output tensors (`std::vector`). Optional. * - **infer_on_cpu**: Whether to run the computation on the CPU instead of GPU. Optional @@ -151,6 +153,9 @@ class InferenceOp : public holoscan::Operator { /// @brief Map with key as model name and value as frame delay for model inference Parameter temporal_map_; + /// @brief Map with key as model name and value as an activation state for model inference + Parameter activation_map_; + /// @brief Input tensor names Parameter> in_tensor_names_; diff --git a/include/holoscan/operators/segmentation_postprocessor/segmentation_postprocessor.hpp b/include/holoscan/operators/segmentation_postprocessor/segmentation_postprocessor.hpp index 6ed17971..e0a6a1db 100644 --- a/include/holoscan/operators/segmentation_postprocessor/segmentation_postprocessor.hpp +++ b/include/holoscan/operators/segmentation_postprocessor/segmentation_postprocessor.hpp @@ -77,8 +77,9 @@ class SegmentationPostprocessorOp : public Operator { ExecutionContext& context) override; private: - NetworkOutputType network_output_type_value_; - DataFormat data_format_value_; + // Defaults set here will be overridden by parameters defined in the setup method + NetworkOutputType network_output_type_value_ = NetworkOutputType::kSoftmax; + DataFormat data_format_value_ = DataFormat::kHWC; Parameter in_; Parameter out_; diff --git a/include/holoscan/operators/v4l2_video_capture/v4l2_video_capture.hpp b/include/holoscan/operators/v4l2_video_capture/v4l2_video_capture.hpp index 0df55093..f51ac0fa 100644 --- a/include/holoscan/operators/v4l2_video_capture/v4l2_video_capture.hpp +++ b/include/holoscan/operators/v4l2_video_capture/v4l2_video_capture.hpp @@ -89,6 +89,7 @@ namespace holoscan::ops { * int64_t row_stride = (row_bytes % 256 == 0) ? row_bytes : ((row_bytes / 256 + 1) * 256); * return height_even * row_stride; * } + * ``` */ class V4L2VideoCaptureOp : public Operator { public: @@ -133,12 +134,12 @@ class V4L2VideoCaptureOp : public Operator { void* ptr; size_t length; }; - Buffer* buffers_; + Buffer* buffers_ = nullptr; int fd_ = -1; - uint32_t width_use_; - uint32_t height_use_; - uint32_t pixel_format_use_; + uint32_t width_use_{0}; + uint32_t height_use_{0}; + uint32_t pixel_format_use_{V4L2_PIX_FMT_RGBA32}; }; } // namespace holoscan::ops diff --git a/include/holoscan/operators/video_stream_recorder/video_stream_recorder.hpp b/include/holoscan/operators/video_stream_recorder/video_stream_recorder.hpp index 2287d3b5..b7e5d220 100644 --- a/include/holoscan/operators/video_stream_recorder/video_stream_recorder.hpp +++ b/include/holoscan/operators/video_stream_recorder/video_stream_recorder.hpp @@ -75,7 +75,7 @@ class VideoStreamRecorderOp : public holoscan::Operator { // File stream for binary data nvidia::gxf::FileStream binary_file_stream_; // Offset into binary file - size_t binary_file_offset_; + size_t binary_file_offset_{0}; }; } // namespace holoscan::ops diff --git a/modules/holoinfer/src/include/holoinfer.hpp b/modules/holoinfer/src/include/holoinfer.hpp index 8a0be6dd..4f05e5b3 100644 --- a/modules/holoinfer/src/include/holoinfer.hpp +++ b/modules/holoinfer/src/include/holoinfer.hpp @@ -48,12 +48,11 @@ class _HOLOSCAN_EXTERNAL_API_ InferContext { * Executes the inference * Toolkit supports one input per model, in float32 type * - * @param preprocess_data_map Map of model names as key mapped to the preprocessed input data - * @param output_data_map Map of tensor names as key mapped to the inferred data + * @param inference_specs Pointer to inference specifications * * @return InferStatus with appropriate holoinfer_code and message. */ - InferStatus execute_inference(DataMap& preprocess_data_map, DataMap& output_data_map); + InferStatus execute_inference(std::shared_ptr& inference_specs); /** * Gets output dimension per model diff --git a/modules/holoinfer/src/include/holoinfer_buffer.hpp b/modules/holoinfer/src/include/holoinfer_buffer.hpp index 3909aeb5..adfd8565 100644 --- a/modules/holoinfer/src/include/holoinfer_buffer.hpp +++ b/modules/holoinfer/src/include/holoinfer_buffer.hpp @@ -207,6 +207,7 @@ struct InferenceSpecs { * @param inference_map Map with model name as key, output tensor names in vector form as value * @param device_map Map with model name as key, GPU ID for inference as value * @param temporal_map Map with model name as key, frame number to skip for inference as value + * @param activation_map Map with key as model name and activation state for inference as value * @param is_engine_path Input path to model is trt engine * @param oncpu Perform inference on CPU * @param parallel_proc Perform parallel inference of multiple models @@ -217,8 +218,9 @@ struct InferenceSpecs { InferenceSpecs(const std::string& backend, const Mappings& backend_map, const Mappings& model_path_map, const MultiMappings& pre_processor_map, const MultiMappings& inference_map, const Mappings& device_map, - const Mappings& temporal_map, bool is_engine_path, bool oncpu, bool parallel_proc, - bool use_fp16, bool cuda_buffer_in, bool cuda_buffer_out) + const Mappings& temporal_map, const Mappings& activation_map, bool is_engine_path, + bool oncpu, bool parallel_proc, bool use_fp16, bool cuda_buffer_in, + bool cuda_buffer_out) : backend_type_(backend), backend_map_(backend_map), model_path_map_(model_path_map), @@ -226,6 +228,7 @@ struct InferenceSpecs { inference_map_(inference_map), device_map_(device_map), temporal_map_(temporal_map), + activation_map_(activation_map), is_engine_path_(is_engine_path), oncuda_(!oncpu), parallel_processing_(parallel_proc), @@ -257,6 +260,22 @@ struct InferenceSpecs { */ Mappings get_temporal_map() const { return temporal_map_; } + /** + * @brief Get the Activation map + * @return Mappings data + */ + Mappings get_activation_map() const { return activation_map_; } + + /** + * @brief Set the Activation map + * @param activation_map Map that will be used to update the activation_map_ of specs. + */ + void set_activation_map(const Mappings& activation_map) { + for (const auto& [key, value] : activation_map) { + if (activation_map_.find(key) != activation_map.end()) { activation_map_.at(key) = value; } + } + } + /// @brief Backend type (for all models) std::string backend_type_{""}; @@ -278,6 +297,9 @@ struct InferenceSpecs { /// @brief Map with key as model name and frame number to skip for inference as value Mappings temporal_map_; + /// @brief Map with key as model name and activation state for inference as value + Mappings activation_map_; + /// @brief Flag showing if input model path is path to engine files bool is_engine_path_ = false; diff --git a/modules/holoinfer/src/include/holoinfer_constants.hpp b/modules/holoinfer/src/include/holoinfer_constants.hpp index c5bf73ee..ed5fda55 100644 --- a/modules/holoinfer/src/include/holoinfer_constants.hpp +++ b/modules/holoinfer/src/include/holoinfer_constants.hpp @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: Copyright (c) 2022-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -69,6 +69,10 @@ class _HOLOSCAN_EXTERNAL_API_ InferStatus { void set_message(const std::string& _m) { _message = _m; } void display_message() const { switch (_code) { + case holoinfer_code::H_WARNING: { + HOLOSCAN_LOG_WARN(_message); + break; + } case holoinfer_code::H_SUCCESS: default: { HOLOSCAN_LOG_INFO(_message); diff --git a/modules/holoinfer/src/infer/onnx/core.cpp b/modules/holoinfer/src/infer/onnx/core.cpp index 28a76937..4e18715f 100644 --- a/modules/holoinfer/src/infer/onnx/core.cpp +++ b/modules/holoinfer/src/infer/onnx/core.cpp @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: Copyright (c) 2022-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -138,6 +138,10 @@ holoinfer_datatype OnnxInferImpl::get_holoinfer_datatype(ONNXTensorElementDataTy return holoinfer_datatype::h_Int8; case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT32: return holoinfer_datatype::h_Int32; + case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT64: + return holoinfer_datatype::h_Int64; + case ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT8: + return holoinfer_datatype::h_UInt8; default: return holoinfer_datatype::h_Unsupported; } @@ -244,7 +248,14 @@ Ort::Value OnnxInferImpl::create_tensor(const std::shared_ptr& input return create_tensor_core(input_buffer, dims, memory_info_); case holoinfer_datatype::h_Int32: return create_tensor_core(input_buffer, dims, memory_info_); + case holoinfer_datatype::h_Int64: + return create_tensor_core(input_buffer, dims, memory_info_); + case holoinfer_datatype::h_UInt8: + return create_tensor_core(input_buffer, dims, memory_info_); default: { + HOLOSCAN_LOG_INFO( + "Onnxruntime backend is supported with following data types: float, int8, int32, int64, " + "uint8"); HOLOSCAN_LOG_ERROR("Unsupported datatype in Onnx backend tensor creation."); return Ort::Value(nullptr); } @@ -268,8 +279,17 @@ void OnnxInferImpl::transfer_to_output(std::vector>& case holoinfer_datatype::h_Int32: transfer_to_host(output_buffer[index], output_tensors_[index], output_tensor_size); break; + case holoinfer_datatype::h_Int64: + transfer_to_host(output_buffer[index], output_tensors_[index], output_tensor_size); + break; + case holoinfer_datatype::h_UInt8: + transfer_to_host(output_buffer[index], output_tensors_[index], output_tensor_size); + break; default: - throw std::runtime_error("Unsupported datatype"); + HOLOSCAN_LOG_INFO( + "Onnxruntime backend is supported with following data types: float, int8, int32, int64, " + "uint8"); + throw std::runtime_error("Unsupported datatype in output transfer with onnxrt backend."); } } diff --git a/modules/holoinfer/src/infer/torch/core.cpp b/modules/holoinfer/src/infer/torch/core.cpp index 083f4c53..fee5395e 100644 --- a/modules/holoinfer/src/infer/torch/core.cpp +++ b/modules/holoinfer/src/infer/torch/core.cpp @@ -161,10 +161,15 @@ torch::Tensor TorchInferImpl::create_tensor(const std::shared_ptr& i case holoinfer_datatype::h_Int32: return create_tensor_core( input_buffer, dims, torch::kI32, infer_device_, input_device_, cstream); + case holoinfer_datatype::h_Int64: + return create_tensor_core( + input_buffer, dims, torch::kI64, infer_device_, input_device_, cstream); case holoinfer_datatype::h_UInt8: return create_tensor_core( input_buffer, dims, torch::kUInt8, infer_device_, input_device_, cstream); default: { + HOLOSCAN_LOG_INFO( + "Torch backend is supported with following data types: float, int8, int32, int64, uint8"); HOLOSCAN_LOG_ERROR("Unsupported datatype in Torch backend tensor creation."); return torch::empty({0}); } @@ -281,7 +286,16 @@ InferStatus TorchInferImpl::transfer_to_output( infer_device_, output_device_, cstream); + case holoinfer_datatype::h_UInt8: + return transfer_from_tensor(output_buffer[index], + out_torch_tensor, + output_dims_[index], + infer_device_, + output_device_, + cstream); default: + HOLOSCAN_LOG_INFO( + "Torch backend is supported with following data types: float, int8, int32, int64, uint8"); return InferStatus(holoinfer_code::H_ERROR, "Unsupported datatype for transfer."); } } @@ -541,7 +555,7 @@ InferStatus TorchInfer::do_inference(const std::vectoroutput_tensors_[a]; - auto status = impl_->transfer_to_output(output_buffer, current_tensor, a); + auto status = impl_->transfer_to_output(output_buffer, std::move(current_tensor), a); HOLOSCAN_LOG_ERROR("Transfer of Tensor {} failed in inferece core.", impl_->output_names_[a]); return status; diff --git a/modules/holoinfer/src/infer/trt/core.cpp b/modules/holoinfer/src/infer/trt/core.cpp index 72c86bab..5e3e91c8 100644 --- a/modules/holoinfer/src/infer/trt/core.cpp +++ b/modules/holoinfer/src/infer/trt/core.cpp @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: Copyright (c) 2022-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -165,7 +165,12 @@ bool TrtInfer::initialize_parameters() { holoinfer_type = holoinfer_datatype::h_Int8; break; } + case nvinfer1::DataType::kUINT8: { + holoinfer_type = holoinfer_datatype::h_UInt8; + break; + } default: { + HOLOSCAN_LOG_INFO("TensorRT backend supports float, int8, int32, uint8 data types."); HOLOSCAN_LOG_ERROR("Data type not supported."); return false; } @@ -199,6 +204,7 @@ bool TrtInfer::initialize_parameters() { } } break; default: { + HOLOSCAN_LOG_INFO("All tensors must have dimension size between 2 and 4."); throw std::runtime_error("Dimension size not supported: " + std::to_string(dims.nbDims)); } diff --git a/modules/holoinfer/src/manager/infer_manager.cpp b/modules/holoinfer/src/manager/infer_manager.cpp index 273014bd..1b297eb9 100644 --- a/modules/holoinfer/src/manager/infer_manager.cpp +++ b/modules/holoinfer/src/manager/infer_manager.cpp @@ -227,9 +227,7 @@ InferStatus ManagerInfer::set_inference_params(std::shared_ptr& switch (current_backend) { case holoinfer_backend::h_trt: { if (inference_specs->use_fp16_ && inference_specs->is_engine_path_) { - status.set_message( - "WARNING: Engine files are the input, fp16 check/conversion is ignored"); - status.display_message(); + HOLOSCAN_LOG_WARN("Engine files are the input, fp16 check/conversion is ignored"); } if (!inference_specs->oncuda_) { status.set_message("ERROR: TRT backend supports inference on GPU only"); @@ -320,6 +318,7 @@ InferStatus ManagerInfer::set_inference_params(std::shared_ptr& if (!new_torch_infer) { HOLOSCAN_LOG_ERROR(dlerror()); status.set_message("Torch context setup failure."); + dlclose(handle); return status; } dlclose(handle); @@ -681,10 +680,20 @@ InferStatus ManagerInfer::run_core_inference(const std::string& model_name, return InferStatus(); } -InferStatus ManagerInfer::execute_inference(DataMap& permodel_preprocess_data, - DataMap& permodel_output_data) { +InferStatus ManagerInfer::execute_inference(std::shared_ptr& inference_specs) { InferStatus status = InferStatus(); + auto permodel_preprocess_data = inference_specs->data_per_tensor_; + auto permodel_output_data = inference_specs->output_per_model_; + + if (permodel_preprocess_data.size() == 0) { + status.set_code(holoinfer_code::H_ERROR); + status.set_message("Inference manager, Error: Data map empty for inferencing"); + return status; + } + + auto activation_map = inference_specs->get_activation_map(); + if (frame_counter_++ == UINT_MAX - 1) { frame_counter_ = 0; } if (infer_param_.size() == 0) { @@ -701,8 +710,28 @@ InferStatus ManagerInfer::execute_inference(DataMap& permodel_preprocess_data, std::map> inference_futures; s_time = std::chrono::steady_clock::now(); for (const auto& [model_instance, _] : infer_param_) { + bool process_model = true; + + if (activation_map.find(model_instance) != activation_map.end()) { + try { + auto activation_value = std::stoul(activation_map.at(model_instance)); + HOLOSCAN_LOG_INFO("Activation value: {} for Model: {}", activation_value, model_instance); + if (activation_value > 1) { + HOLOSCAN_LOG_WARN("Activation map can have either a value of 0 or 1 for a model."); + HOLOSCAN_LOG_WARN("Activation map value is ignored for model {}", model_instance); + } + if (activation_value == 0) { process_model = false; } + } catch (std::invalid_argument const& ex) { + HOLOSCAN_LOG_WARN("Invalid argument in activation map: {}", ex.what()); + HOLOSCAN_LOG_WARN("Activation map value is ignored for model {}", model_instance); + } catch (std::out_of_range const& ex) { + HOLOSCAN_LOG_WARN("Invalid range in activation map: {}", ex.what()); + HOLOSCAN_LOG_WARN("Activation map value is ignored for model {}", model_instance); + } + } + auto temporal_id = infer_param_.at(model_instance)->get_temporal_id(); - if (frame_counter_ % temporal_id == 0) { + if (process_model && (frame_counter_ % temporal_id == 0)) { if (!parallel_processing_) { InferStatus infer_status = run_core_inference(model_instance, permodel_preprocess_data, permodel_output_data); @@ -769,7 +798,7 @@ InferContext::InferContext() { } catch (const std::bad_alloc&) { throw; } } -InferStatus InferContext::execute_inference(DataMap& data_map, DataMap& output_data_map) { +InferStatus InferContext::execute_inference(std::shared_ptr& inference_specs) { InferStatus status = InferStatus(); if (g_managers.find(unique_id_) == g_managers.end()) { @@ -781,12 +810,7 @@ InferStatus InferContext::execute_inference(DataMap& data_map, DataMap& output_d try { g_manager = g_managers.at(unique_id_); - if (data_map.size() == 0) { - status.set_code(holoinfer_code::H_ERROR); - status.set_message("Inference manager, Error: Data map empty for inferencing"); - return status; - } - status = g_manager->execute_inference(data_map, output_data_map); + status = g_manager->execute_inference(inference_specs); } catch (const std::exception& e) { status.set_code(holoinfer_code::H_ERROR); status.set_message(std::string("Inference manager, Error in inference setup: ") + e.what()); diff --git a/modules/holoinfer/src/manager/infer_manager.hpp b/modules/holoinfer/src/manager/infer_manager.hpp index a78944bd..0ee3cce0 100644 --- a/modules/holoinfer/src/manager/infer_manager.hpp +++ b/modules/holoinfer/src/manager/infer_manager.hpp @@ -71,12 +71,11 @@ class ManagerInfer { /** * @brief Prepares and launches single/multiple inference * - * @param preprocess_data_map Input DataMap with model name as key and DataBuffer as value - * @param output_data_map Output DataMap with tensor name as key and DataBuffer as value + * @param inference_specs specifications for inference * * @return InferStatus with appropriate code and message */ - InferStatus execute_inference(DataMap& preprocess_data_map, DataMap& output_data_map); + InferStatus execute_inference(std::shared_ptr& inference_specs); /** * @brief Executes Core inference for a particular model and generates inferred data diff --git a/modules/holoinfer/src/params/infer_param.hpp b/modules/holoinfer/src/params/infer_param.hpp index ecfb4df1..75ec2a74 100644 --- a/modules/holoinfer/src/params/infer_param.hpp +++ b/modules/holoinfer/src/params/infer_param.hpp @@ -48,7 +48,7 @@ class Params { std::string model_file_path_; std::string instance_name_; int device_id_; - unsigned int temporal_id_; + unsigned int temporal_id_ = 0; std::vector in_tensor_names_; std::vector out_tensor_names_; }; diff --git a/python/holoscan/CMakeLists.txt b/python/holoscan/CMakeLists.txt index d0db6904..3fa6bc2c 100644 --- a/python/holoscan/CMakeLists.txt +++ b/python/holoscan/CMakeLists.txt @@ -87,6 +87,15 @@ add_custom_target(holoscan-python-pyinit ) add_dependencies(holoscan-python holoscan-python-pyinit) +# custom target for top-level decorator.py file is copied +set(CMAKE_PYBIND11_DECORATORS_PY_FILE ${CMAKE_CURRENT_LIST_DIR}/decorator.py) +add_custom_target(holoscan-python-decorator + COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_PYBIND11_DECORATORS_PY_FILE}" "${HOLOSCAN_PYTHON_MODULE_BINARY_DIR}/" + DEPENDS "${CMAKE_PYBIND11_DECORATORS_PY_FILE}" +) +add_dependencies(holoscan-python holoscan-python-decorator) + + # copy Holoscan Python CLI module set(HOLOSCAN_PYTHON_CLI_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/cli) add_custom_target(holoscan-python-cli @@ -99,10 +108,6 @@ add_dependencies(holoscan-python holoscan-python-cli) add_subdirectory(cli) add_subdirectory(conditions) add_subdirectory(core) -target_link_libraries(core_python - PRIVATE holoscan::core - PRIVATE AJA::ajantv2 # need this to parse NTV2Channel enum from kwargs -) add_subdirectory(executors) add_subdirectory(graphs) add_subdirectory(gxf) diff --git a/python/holoscan/__init__.py b/python/holoscan/__init__.py index 0b2763e7..e89865ee 100644 --- a/python/holoscan/__init__.py +++ b/python/holoscan/__init__.py @@ -18,7 +18,12 @@ # We import cli, core and gxf to make sure they're available before other modules that rely on them from . import cli, core, gxf -__all__ = ["as_tensor", "cli", "core", "gxf"] +try: + from ._version import __version__ +except ImportError: + __version__ = "unknown version" + +__all__ = ["__version__", "as_tensor", "cli", "core", "gxf"] def as_tensor(obj): @@ -92,6 +97,7 @@ def as_tensor(obj): # Other modules are exposed to the public API but will only be lazily loaded _EXTRA_MODULES = [ "conditions", + "decorator", "executors", "graphs", "logger", diff --git a/python/holoscan/cli/common/artifact_sources.py b/python/holoscan/cli/common/artifact_sources.py index 1ee53986..fb7232bf 100644 --- a/python/holoscan/cli/common/artifact_sources.py +++ b/python/holoscan/cli/common/artifact_sources.py @@ -39,7 +39,7 @@ class ArtifactSources: def __init__(self) -> None: self._logger = logging.getLogger("common") - self._supported_holoscan_versions = ["2.0.0", "2.1.0"] + self._supported_holoscan_versions = ["2.0.0", "2.1.0", "2.2.0"] @property def holoscan_versions(self) -> List[str]: diff --git a/python/holoscan/conditions/CMakeLists.txt b/python/holoscan/conditions/CMakeLists.txt index f0b6dbd3..b799cffe 100644 --- a/python/holoscan/conditions/CMakeLists.txt +++ b/python/holoscan/conditions/CMakeLists.txt @@ -20,5 +20,6 @@ holoscan_pybind11_module(conditions count.cpp downstream_message_affordable.cpp message_available.cpp + expiring_message.cpp periodic.cpp ) diff --git a/python/holoscan/conditions/__init__.py b/python/holoscan/conditions/__init__.py index e974bab2..69f6f4d3 100644 --- a/python/holoscan/conditions/__init__.py +++ b/python/holoscan/conditions/__init__.py @@ -20,6 +20,7 @@ holoscan.conditions.BooleanCondition holoscan.conditions.CountCondition holoscan.conditions.DownstreamMessageAffordableCondition + holoscan.conditions.ExpiringMessageAvailableCondition holoscan.conditions.MessageAvailableCondition holoscan.conditions.PeriodicCondition """ @@ -30,6 +31,7 @@ BooleanCondition, CountCondition, DownstreamMessageAffordableCondition, + ExpiringMessageAvailableCondition, MessageAvailableCondition, PeriodicCondition, ) @@ -40,6 +42,7 @@ "BooleanCondition", "CountCondition", "DownstreamMessageAffordableCondition", + "ExpiringMessageAvailableCondition", "MessageAvailableCondition", "PeriodicCondition", ] diff --git a/python/holoscan/conditions/conditions.cpp b/python/holoscan/conditions/conditions.cpp index 4f911798..3b620c08 100644 --- a/python/holoscan/conditions/conditions.cpp +++ b/python/holoscan/conditions/conditions.cpp @@ -30,6 +30,7 @@ void init_count(py::module_&); void init_periodic(py::module_&); void init_downstream_message_affordable(py::module_&); void init_message_available(py::module_&); +void init_expiring_message_available(py::module_&); PYBIND11_MODULE(_conditions, m) { m.doc() = R"pbdoc( @@ -44,5 +45,6 @@ PYBIND11_MODULE(_conditions, m) { init_periodic(m); init_downstream_message_affordable(m); init_message_available(m); + init_expiring_message_available(m); } // PYBIND11_MODULE } // namespace holoscan diff --git a/python/holoscan/conditions/count.cpp b/python/holoscan/conditions/count.cpp index 900fbdad..cc24f07c 100644 --- a/python/holoscan/conditions/count.cpp +++ b/python/holoscan/conditions/count.cpp @@ -66,7 +66,7 @@ class PyCountCondition : public CountCondition { void init_count(py::module_& m) { py::class_>( m, "CountCondition", doc::CountCondition::doc_CountCondition) - .def(py::init(), + .def(py::init(), "fragment"_a, "count"_a = 1L, "name"_a = "noname_count_condition"s, diff --git a/python/holoscan/conditions/expiring_message.cpp b/python/holoscan/conditions/expiring_message.cpp new file mode 100644 index 00000000..fbce4109 --- /dev/null +++ b/python/holoscan/conditions/expiring_message.cpp @@ -0,0 +1,157 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include +#include +#include +#include + +#include "./expiring_message_pydoc.hpp" +#include "holoscan/core/component_spec.hpp" +#include "holoscan/core/conditions/gxf/expiring_message.hpp" +#include "holoscan/core/fragment.hpp" +#include "holoscan/core/gxf/gxf_resource.hpp" +#include "holoscan/core/resources/gxf/realtime_clock.hpp" + +using std::string_literals::operator""s; +using pybind11::literals::operator""_a; + +#define STRINGIFY(x) #x +#define MACRO_STRINGIFY(x) STRINGIFY(x) + +namespace py = pybind11; + +namespace holoscan { + +/* Trampoline classes for handling Python kwargs + * + * These add a constructor that takes a Fragment for which to initialize the condition. + * The explicit parameter list and default arguments take care of providing a Pythonic + * kwarg-based interface with appropriate default values matching the condition's + * default parameters in the C++ API `setup` method. + * + * The sequence of events in this constructor is based on Fragment::make_condition + */ + +class PyExpiringMessageAvailableCondition : public ExpiringMessageAvailableCondition { + public: + /* Inherit the constructors */ + using ExpiringMessageAvailableCondition::ExpiringMessageAvailableCondition; + + // Define a constructor that fully initializes the object. + PyExpiringMessageAvailableCondition( + Fragment* fragment, + // std::shared_ptr receiver, + int64_t max_batch_size, int64_t max_delay_ns, std::shared_ptr clock = nullptr, + const std::string& name = "noname_expiring_message_available_condition") + : ExpiringMessageAvailableCondition(max_batch_size, max_delay_ns) { + name_ = name; + fragment_ = fragment; + if (clock) { + this->add_arg(Arg{"clock", clock}); + } else { + this->add_arg(Arg{"clock", fragment_->make_resource("realtime_clock")}); + } + spec_ = std::make_shared(fragment); + // receiver = receiver; // e.g. DoubleBufferReceiver + setup(*spec_.get()); + } + + template + PyExpiringMessageAvailableCondition( + Fragment* fragment, + // std::shared_ptr receiver, + int64_t max_batch_size, std::chrono::duration recess_period_duration, + std::shared_ptr clock = nullptr, + const std::string& name = "noname_expiring_message_available_condition") + : ExpiringMessageAvailableCondition(max_batch_size, recess_period_duration) { + name_ = name; + fragment_ = fragment; + if (clock) { + this->add_arg(Arg{"clock", clock}); + } else { + this->add_arg(Arg{"clock", fragment_->make_resource("realtime_clock")}); + } + spec_ = std::make_shared(fragment); + // receiver = receiver; // e.g. DoubleBufferReceiver + setup(*spec_.get()); + } +}; + +void init_expiring_message_available(py::module_& m) { + py::class_>( + m, + "ExpiringMessageAvailableCondition", + doc::ExpiringMessageAvailableCondition::doc_ExpiringMessageAvailableCondition) + // TODO: sphinx API doc build complains if more than one ExpiringMessageAvailableCondition + // init method has a docstring specified. For now just set the docstring for the + // overload using datetime.timedelta for the max_delay. + .def(py::init, const std::string&>(), + "fragment"_a, + "max_batch_size"_a, + "max_delay_ns"_a, + "clock"_a = py::none(), + "name"_a = "noname_expiring_message_available_condition"s, + doc::ExpiringMessageAvailableCondition::doc_ExpiringMessageAvailableCondition) + .def(py::init, + const std::string&>(), + "fragment"_a, + "max_batch_size"_a, + "max_delay_ns"_a, + "clock"_a = py::none(), + "name"_a = "noname_expiring_message_available_condition"s, + doc::ExpiringMessageAvailableCondition::doc_ExpiringMessageAvailableCondition) + .def_property_readonly("gxf_typename", + &ExpiringMessageAvailableCondition::gxf_typename, + doc::ExpiringMessageAvailableCondition::doc_gxf_typename) + .def_property("receiver", + py::overload_cast<>(&ExpiringMessageAvailableCondition::receiver), + py::overload_cast>( + &ExpiringMessageAvailableCondition::receiver), + doc::ExpiringMessageAvailableCondition::doc_receiver) + .def_property("max_batch_size", + py::overload_cast<>(&ExpiringMessageAvailableCondition::max_batch_size), + py::overload_cast(&ExpiringMessageAvailableCondition::max_batch_size), + doc::ExpiringMessageAvailableCondition::doc_max_batch_size) + .def("max_delay", + static_cast( + &ExpiringMessageAvailableCondition::max_delay), + doc::ExpiringMessageAvailableCondition::doc_max_delay) + .def("max_delay", + static_cast( + &ExpiringMessageAvailableCondition::max_delay), + doc::ExpiringMessageAvailableCondition::doc_max_delay) + .def("max_delay_ns", + &ExpiringMessageAvailableCondition::max_delay_ns, + doc::ExpiringMessageAvailableCondition::doc_max_delay_ns) + .def("setup", + &ExpiringMessageAvailableCondition::setup, + doc::ExpiringMessageAvailableCondition::doc_setup) + .def("initialize", + &ExpiringMessageAvailableCondition::initialize, + doc::ExpiringMessageAvailableCondition::doc_initialize); +} +} // namespace holoscan diff --git a/python/holoscan/conditions/expiring_message_pydoc.hpp b/python/holoscan/conditions/expiring_message_pydoc.hpp new file mode 100644 index 00000000..db977ab1 --- /dev/null +++ b/python/holoscan/conditions/expiring_message_pydoc.hpp @@ -0,0 +1,95 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PYHOLOSCAN_CONDITIONS_EXPIRINGMESSAGE_AVAILABLE_PYDOC_HPP +#define PYHOLOSCAN_CONDITIONS_EXPIRINGMESSAGE_AVAILABLE_PYDOC_HPP + +#include + +#include "../macros.hpp" + +namespace holoscan::doc { + +namespace ExpiringMessageAvailableCondition { + +PYDOC(ExpiringMessageAvailableCondition, R"doc( +Condition that tries to wait for specified number of messages in receiver. +When the first message in the queue mature after specified delay since arrival it would fire +regardless. + +Parameters +---------- +fragment : holoscan.core.Fragment + The fragment the condition will be associated with +max_batch_size : int + The maximum number of messages to be batched together. +max_delay_ns: int + Maximum delay in nano seconds. + The maximum delay from first message to wait before submitting workload anyway. +clock : holoscan.resources.Clock or None, optional + The clock used by the scheduler to define the flow of time. If None, a default-constructed + `holoscan.resources.RealtimeClock` will be used. +name : str, optional + The name of the condition. +)doc") + +PYDOC(gxf_typename, R"doc( +The GXF type name of the condition. + +Returns +------- +str + The GXF type name of the condition +)doc") + +PYDOC(setup, R"doc( +Define the component specification. + +Parameters +---------- +spec : holoscan.core.ComponentSpec + Component specification associated with the condition. +)doc") + +PYDOC(receiver, R"doc( +The receiver associated with the condition. +)doc") + +PYDOC(max_batch_size, R"doc( +The maximum number of messages to be batched together. +)doc") + +PYDOC(max_delay, R"doc( +The maximum delay from first message to wait before submitting workload anyway. +)doc") + +PYDOC(max_delay_ns, R"doc( +The maximum delay from first message to wait before submitting workload anyway. +)doc") + +PYDOC(initialize, R"doc( +Initialize the condition + +This method is called only once when the condition is created for the first +time, and uses a light-weight initialization. +)doc") + +} // namespace ExpiringMessageAvailableCondition + +} // namespace holoscan::doc + +#endif /* PYHOLOSCAN_CONDITIONS_MESSAGE_AVAILABLE_PYDOC_HPP */ diff --git a/python/holoscan/core/__init__.py b/python/holoscan/core/__init__.py index 8c1e3e9b..64eb18f5 100644 --- a/python/holoscan/core/__init__.py +++ b/python/holoscan/core/__init__.py @@ -90,8 +90,8 @@ from ._core import PyRegistryContext as _RegistryContext from ._core import PyOperatorSpec as OperatorSpec from ._core import PyTensor as Tensor +from ._core import Resource as _Resource from ._core import ( - Resource, Scheduler, arg_to_py_object, arglist_to_kwargs, @@ -303,6 +303,32 @@ def stop(self): Operator.__init__.__doc__ = _Operator.__init__.__doc__ +class Resource(_Resource): + def __init__(self, fragment, *args, **kwargs): + if not isinstance(fragment, _Fragment): + raise ValueError( + "The first argument to an Resource's constructor must be the Fragment " + "(Application) to which it belongs." + ) + # It is recommended to not use super() + # (https://pybind11.readthedocs.io/en/stable/advanced/classes.html#overriding-virtual-functions-in-python) + _Resource.__init__(self, self, fragment, *args, **kwargs) + # Create a PyComponentSpec object and pass it to the C++ API + spec = ComponentSpec(fragment=self.fragment, component=self) + self.spec = spec + # Call setup method in PyResource class + self.setup(spec) + + def setup(self, spec: ComponentSpec): + """Default implementation of setup method.""" + pass + + +# copy docstrings defined in core_pydoc.hpp +Resource.__doc__ = _Resource.__doc__ +Resource.__init__.__doc__ = _Resource.__init__.__doc__ + + class Tracker: """Context manager to add data flow tracking to an application.""" diff --git a/python/holoscan/core/component.cpp b/python/holoscan/core/component.cpp index c05b28f7..5db222ca 100644 --- a/python/holoscan/core/component.cpp +++ b/python/holoscan/core/component.cpp @@ -18,10 +18,12 @@ #include #include +#include #include #include -#include +#include +#include "component.hpp" #include "component_pydoc.hpp" #include "holoscan/core/arg.hpp" #include "holoscan/core/component.hpp" @@ -33,78 +35,33 @@ namespace py = pybind11; namespace holoscan { -class PyComponentSpec : public ComponentSpec { - public: - /* Inherit the constructors */ - using ComponentSpec::ComponentSpec; - - // Override the constructor to get the py::object for the Python class - explicit PyComponentSpec(Fragment* fragment = nullptr, py::object op = py::none()) - : ComponentSpec(fragment), py_op_(op) {} - - // TOIMPROVE: Should we parse headline and description from kwargs or just - // add them to the function signature? - void py_param(const std::string& name, const py::object& default_value, const ParameterFlag& flag, - const py::kwargs& kwargs) { - using std::string_literals::operator""s; - - bool is_receivers = false; - std::string headline{""s}; - std::string description{""s}; - for (const auto& [name, value] : kwargs) { - std::string param_name = name.cast(); - if (param_name == "headline") { - headline = value.cast(); - } else if (param_name == "description") { - description = value.cast(); - } else { - throw std::runtime_error("unsupported kwarg: "s + param_name); - } +// TOIMPROVE: Should we parse headline and description from kwargs or just +// add them to the function signature? +void PyComponentSpec::py_param(const std::string& name, const py::object& default_value, + const ParameterFlag& flag, const py::kwargs& kwargs) { + using std::string_literals::operator""s; + + bool is_receivers = false; + std::string headline{""s}; + std::string description{""s}; + for (const auto& [nm, value] : kwargs) { + std::string param_name = nm.cast(); + if (param_name == "headline") { + headline = value.cast(); + } else if (param_name == "description") { + description = value.cast(); + } else { + throw std::runtime_error("unsupported kwarg: "s + param_name); } - - // Create parameter object - py_params_.emplace_back(py_op()); - - // Register parameter - auto& parameter = py_params_.back(); - param(parameter, name.c_str(), headline.c_str(), description.c_str(), default_value, flag); - } - - py::object py_op() const { return py_op_; } - - std::list>& py_params() { return py_params_; } - - private: - py::object py_op_ = py::none(); - // NOTE: we use std::list instead of std::vector because we register the address of Parameter - // object to the GXF framework. The address of a std::vector element may change when the vector is - // resized. - std::list> py_params_; -}; - -class PyComponentBase : public ComponentBase { - public: - /* Inherit the constructors */ - using ComponentBase::ComponentBase; - - /* Trampolines (need one for each virtual function) */ - void initialize() override { - /* , , , */ - PYBIND11_OVERRIDE(void, ComponentBase, initialize); } -}; -class PyComponent : public Component { - public: - /* Inherit the constructors */ - using Component::Component; + // Create parameter object + py_params_.emplace_back(py_component()); - /* Trampolines (need one for each virtual function) */ - void initialize() override { - /* , , , */ - PYBIND11_OVERRIDE(void, Component, initialize); - } -}; + // Register parameter + auto& parameter = py_params_.back(); + param(parameter, name.c_str(), headline.c_str(), description.c_str(), default_value, flag); +} void init_component(py::module_& m) { py::class_>( @@ -128,10 +85,10 @@ void init_component(py::module_& m) { .value("DYNAMIC", ParameterFlag::kDynamic); py::class_>( - m, "PyComponentSpec", R"doc(Operator specification class.)doc") + m, "PyComponentSpec", R"doc(Component specification class.)doc") .def(py::init(), "fragment"_a, - "op"_a = py::none(), + "component"_a = py::none(), doc::ComponentSpec::doc_ComponentSpec) .def("param", &PyComponentSpec::py_param, diff --git a/python/holoscan/core/component.hpp b/python/holoscan/core/component.hpp new file mode 100644 index 00000000..e0695a30 --- /dev/null +++ b/python/holoscan/core/component.hpp @@ -0,0 +1,89 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PYHOLOSCAN_CORE_COMPONENT_HPP +#define PYHOLOSCAN_CORE_COMPONENT_HPP + +#include + +#include +#include +#include + +#include "holoscan/core/component.hpp" +#include "holoscan/core/component_spec.hpp" +#include "holoscan/core/fragment.hpp" +#include "holoscan/core/parameter.hpp" +#include "io_context.hpp" + +namespace py = pybind11; + +namespace holoscan { + +void init_component(py::module_&); + +class PyComponentSpec : public ComponentSpec { + public: + /* Inherit the constructors */ + using ComponentSpec::ComponentSpec; + + // Override the constructor to get the py::object for the Python class + explicit PyComponentSpec(Fragment* fragment = nullptr, py::object component = py::none()) + : ComponentSpec(fragment), py_component_(component) {} + + void py_param(const std::string& name, const py::object& default_value, const ParameterFlag& flag, + const py::kwargs& kwargs); + + py::object py_component() const { return py_component_; } + + std::list>& py_params() { return py_params_; } + + private: + py::object py_component_ = py::none(); + // NOTE: we use std::list instead of std::vector because we register the address of Parameter + // object to the GXF framework. The address of a std::vector element may change when the vector is + // resized. + std::list> py_params_; +}; + +class PyComponentBase : public ComponentBase { + public: + /* Inherit the constructors */ + using ComponentBase::ComponentBase; + + /* Trampolines (need one for each virtual function) */ + void initialize() override { + /* , , , */ + PYBIND11_OVERRIDE(void, ComponentBase, initialize); + } +}; + +class PyComponent : public Component { + public: + /* Inherit the constructors */ + using Component::Component; + + /* Trampolines (need one for each virtual function) */ + void initialize() override { + /* , , , */ + PYBIND11_OVERRIDE(void, Component, initialize); + } +}; + +} // namespace holoscan + +#endif /* PYHOLOSCAN_CORE_COMPONENT_HPP */ diff --git a/python/holoscan/core/component_pydoc.hpp b/python/holoscan/core/component_pydoc.hpp index a4c04018..7b545c1b 100644 --- a/python/holoscan/core/component_pydoc.hpp +++ b/python/holoscan/core/component_pydoc.hpp @@ -99,14 +99,12 @@ flag: holoscan.core.ParameterFlag, optional Notes ----- -This method is intended to be called within the `setup` method of an Operator. +This method is intended to be called within the `setup` method of a Component, Condition or +Resource. -In general, for native Python operators, it is not necessary to call `param` to register a -parameter with the class. Instead, one can just directly add parameters to the Python operator +In general, for native Python resources, it is not necessary to call `param` to register a +parameter with the class. Instead, one can just directly add parameters to the Python resource class (e.g. For example, directly assigning ``self.param_name = value`` in __init__.py). - -The one case which cannot be implemented without a call to `param` is adding a multi-receiver port -to an operator via a parameter with ``kind="receivers"`` set. )doc") } // namespace ComponentSpec diff --git a/python/holoscan/core/condition.cpp b/python/holoscan/core/condition.cpp index 6e982570..da00914f 100644 --- a/python/holoscan/core/condition.cpp +++ b/python/holoscan/core/condition.cpp @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -98,7 +98,10 @@ void init_condition(py::module_& m) { .value("MESSAGE_AVAILABLE", ConditionType::kMessageAvailable) .value("DOWNSTREAM_MESSAGE_AFFORDABLE", ConditionType::kDownstreamMessageAffordable) .value("COUNT", ConditionType::kCount) - .value("BOOLEAN", ConditionType::kBoolean); + .value("BOOLEAN", ConditionType::kBoolean) + .value("PERIODIC", ConditionType::kPeriodic) + .value("ASYNCHRONOUS", ConditionType::kAsynchronous) + .value("EXPIRING_MESSAGE_AVAILABLE", ConditionType::kExpiringMessageAvailable); py::class_>( m, "Condition", doc::Condition::doc_Condition) diff --git a/python/holoscan/core/emitter_receiver_registry.hpp b/python/holoscan/core/emitter_receiver_registry.hpp index 51b0a29b..e4699f8c 100644 --- a/python/holoscan/core/emitter_receiver_registry.hpp +++ b/python/holoscan/core/emitter_receiver_registry.hpp @@ -50,10 +50,11 @@ namespace holoscan { */ template struct emitter_receiver { - static void emit(py::object& data, const std::string& name, PyOutputContext& op_output) { + static void emit(py::object& data, const std::string& name, PyOutputContext& op_output, + const int64_t acq_timestamp = -1) { auto cpp_type = data.cast(); py::gil_scoped_release release; - op_output.emit(cpp_type, name.c_str()); + op_output.emit(std::move(cpp_type), name.c_str(), acq_timestamp); return; } @@ -67,10 +68,11 @@ struct emitter_receiver { */ template struct emitter_receiver> { - static void emit(py::object& data, const std::string& name, PyOutputContext& op_output) { + static void emit(py::object& data, const std::string& name, PyOutputContext& op_output, + const int64_t acq_timestamp = -1) { auto cpp_obj = std::make_shared(data.cast()); py::gil_scoped_release release; - op_output.emit>(cpp_obj, name.c_str()); + op_output.emit>(std::move(cpp_obj), name.c_str(), acq_timestamp); return; } static py::object receive(std::any result, const std::string& name, PyInputContext& op_input) { @@ -90,7 +92,8 @@ class EmitterReceiverRegistry { /** * @brief Function type for emitting a data type */ - using EmitFunc = std::function; + using EmitFunc = std::function; /** * @brief Function type for receiving a data type @@ -105,7 +108,8 @@ class EmitterReceiverRegistry { inline static EmitFunc none_emit = []([[maybe_unused]] py::object& data, [[maybe_unused]] const std::string& name, - [[maybe_unused]] PyOutputContext& op_output) -> void { + [[maybe_unused]] PyOutputContext& op_output, + [[maybe_unused]] const int64_t acq_timestamp = -1) -> void { HOLOSCAN_LOG_ERROR( "Unable to emit message (op: '{}', port: '{}')", op_output.op()->name(), name); return; @@ -138,13 +142,15 @@ class EmitterReceiverRegistry { * @param data The Python object corresponding to the data of typeT. * @param name The name of the entity emitted. * @param op_output The PyOutputContext used to emit the data. + * @param acq_timestamp The acquisition timestamp of the data. */ template - static void emit(py::object& data, const std::string& name, PyOutputContext& op_output) { + static void emit(py::object& data, const std::string& name, PyOutputContext& op_output, + const int64_t acq_timestamp = -1) { auto& instance = get_instance(); const std::type_index index = std::type_index(typeid(typeT)); const EmitFunc& func = instance.get_emitter(index); - return func(data, name, op_output); + return func(data, name, op_output, acq_timestamp); } /** diff --git a/python/holoscan/core/emitter_receivers.hpp b/python/holoscan/core/emitter_receivers.hpp index 84324e74..b570996b 100644 --- a/python/holoscan/core/emitter_receivers.hpp +++ b/python/holoscan/core/emitter_receivers.hpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include "../gxf/entity.hpp" @@ -158,10 +159,11 @@ py::object gxf_entity_to_py_object(holoscan::gxf::Entity in_entity) { */ template <> struct emitter_receiver { - static void emit(py::object& data, const std::string& name, PyOutputContext& op_output) { + static void emit(py::object& data, const std::string& name, PyOutputContext& op_output, + const int64_t acq_timestamp = -1) { py::gil_scoped_release release; auto entity = gxf::Entity(static_cast(data.cast())); - op_output.emit(entity, name.c_str()); + op_output.emit(entity, name.c_str(), acq_timestamp); return; } static py::object receive(std::any result, const std::string& name, PyInputContext& op_input) { @@ -179,14 +181,15 @@ struct emitter_receiver { */ template <> struct emitter_receiver { - static void emit(py::object& data, const std::string& name, PyOutputContext& op_output) { + static void emit(py::object& data, const std::string& name, PyOutputContext& op_output, + const int64_t acq_timestamp = -1) { // unused (emit type is holoscan::PyEntity, not holoscan::gxf:Entity) return; } static py::object receive(std::any result, const std::string& name, PyInputContext& op_input) { auto in_entity = std::any_cast(result); - return gxf_entity_to_py_object(in_entity); + return gxf_entity_to_py_object(std::move(in_entity)); } }; @@ -209,7 +212,8 @@ struct emitter_receiver { */ template <> struct emitter_receiver { - static void emit(py::object& data, const std::string& name, PyOutputContext& op_output) { + static void emit(py::object& data, const std::string& name, PyOutputContext& op_output, + const int64_t acq_timestamp = -1) { HOLOSCAN_LOG_DEBUG("py_emit: tensor-like over UCX connector"); // For tensor-like data, we should create an entity and transmit using the holoscan::Tensor // serializer. cloudpickle fails to serialize PyTensor and we want to avoid using it anyways @@ -237,7 +241,7 @@ struct emitter_receiver { py_entity.py_add(py_tensor_obj, "#holoscan: tensor"); } py::gil_scoped_release release2; - op_output.emit(py_entity, name.c_str()); + op_output.emit(py_entity, name.c_str(), acq_timestamp); return; } static py::object receive(std::any result, const std::string& name, PyInputContext& op_input) { @@ -255,7 +259,8 @@ struct emitter_receiver { */ template <> struct emitter_receiver { - static void emit(py::object& data, const std::string& name, PyOutputContext& op_output) { + static void emit(py::object& data, const std::string& name, PyOutputContext& op_output, + const int64_t acq_timestamp = -1) { bool is_tensormap = true; auto dict_obj = data.cast(); @@ -285,14 +290,15 @@ struct emitter_receiver { py_entity.py_add(py_tensor_obj, key.c_str()); } py::gil_scoped_release release2; - op_output.emit(py_entity, name.c_str()); + op_output.emit(py_entity, name.c_str(), acq_timestamp); return; } else { // If the dict is not a TensorMap, pass it as a Python object HOLOSCAN_LOG_DEBUG("py_emit: dict, but not a tensormap"); auto data_ptr = std::make_shared(data); py::gil_scoped_release release; - op_output.emit>(data_ptr, name.c_str()); + op_output.emit>( + std::move(data_ptr), name.c_str(), acq_timestamp); return; } } @@ -309,11 +315,13 @@ struct emitter_receiver { */ template <> struct emitter_receiver> { - static void emit(py::object& data, const std::string& name, PyOutputContext& op_output) { + static void emit(py::object& data, const std::string& name, PyOutputContext& op_output, + const int64_t acq_timestamp = -1) { // Emit everything else as a Python object. auto data_ptr = std::make_shared(data); py::gil_scoped_release release; - op_output.emit>(data_ptr, name.c_str()); + op_output.emit>( + std::move(data_ptr), name.c_str(), acq_timestamp); return; } @@ -330,14 +338,15 @@ struct emitter_receiver> { */ template <> struct emitter_receiver { - static void emit(py::object& data, const std::string& name, PyOutputContext& op_output) { + static void emit(py::object& data, const std::string& name, PyOutputContext& op_output, + const int64_t acq_timestamp = -1) { // use cloudpickle to serialize as a string py::module_ cloudpickle = py::module_::import("cloudpickle"); py::bytes serialized = cloudpickle.attr("dumps")(data); py::gil_scoped_release release; - auto serialized_str = serialized.cast(); - CloudPickleSerializedObject serialized_obj{serialized_str}; - op_output.emit(serialized_obj, name.c_str()); + CloudPickleSerializedObject serialized_obj{serialized.cast()}; + op_output.emit( + std::move(serialized_obj), name.c_str(), acq_timestamp); return; } @@ -356,8 +365,9 @@ struct emitter_receiver { */ template <> struct emitter_receiver { - static void emit(py::object& data, const std::string& name, PyOutputContext& op_output) { - op_output.emit(nullptr, name.c_str()); + static void emit(py::object& data, const std::string& name, PyOutputContext& op_output, + const int64_t acq_timestamp = -1) { + op_output.emit(nullptr, name.c_str(), acq_timestamp); return; } static py::object receive(std::any result, const std::string& name, PyInputContext& op_input) { diff --git a/python/holoscan/core/execution_context.cpp b/python/holoscan/core/execution_context.cpp index 7c5770cd..224b178b 100644 --- a/python/holoscan/core/execution_context.cpp +++ b/python/holoscan/core/execution_context.cpp @@ -20,6 +20,7 @@ #include #include +#include #include "execution_context_pydoc.hpp" #include "holoscan/core/execution_context.hpp" @@ -45,7 +46,7 @@ PyExecutionContext::PyExecutionContext(gxf_context_t context, std::shared_ptr& py_output_context, py::object op) : gxf::GXFExecutionContext(context, py_input_context, py_output_context), - py_op_(op), + py_op_(std::move(op)), py_input_context_(py_input_context), py_output_context_(py_output_context) {} diff --git a/python/holoscan/core/fragment.cpp b/python/holoscan/core/fragment.cpp index 40668149..e6fca4dc 100644 --- a/python/holoscan/core/fragment.cpp +++ b/python/holoscan/core/fragment.cpp @@ -76,10 +76,10 @@ void init_fragment(py::module_& m) { "prefix"_a = "", doc::Fragment::doc_config_kwargs) .def("config", py::overload_cast&>(&Fragment::config)) - .def("config", py::overload_cast<>(&Fragment::config)) + .def("config", &Fragment::config_shared) .def("config_keys", &Fragment::config_keys, doc::Fragment::doc_config_keys) - .def_property_readonly("graph", &Fragment::graph, doc::Fragment::doc_graph) - .def_property_readonly("executor", &Fragment::executor, doc::Fragment::doc_executor) + .def_property_readonly("graph", &Fragment::graph_shared, doc::Fragment::doc_graph) + .def_property_readonly("executor", &Fragment::executor_shared, doc::Fragment::doc_executor) .def( "from_config", [](Fragment& fragment, const std::string& key) { diff --git a/python/holoscan/core/gil_guarded_pyobject.hpp b/python/holoscan/core/gil_guarded_pyobject.hpp index 3dd75695..5c968e56 100644 --- a/python/holoscan/core/gil_guarded_pyobject.hpp +++ b/python/holoscan/core/gil_guarded_pyobject.hpp @@ -20,6 +20,8 @@ #include +#include + namespace py = pybind11; namespace holoscan { @@ -45,9 +47,25 @@ class GILGuardedPyObject { ~GILGuardedPyObject() { // Acquire GIL before destroying the PyObject - py::gil_scoped_acquire scope_guard; - py::handle handle = obj_.release(); - if (handle) { handle.dec_ref(); } + try { + py::gil_scoped_acquire scope_guard; + py::handle handle = obj_.release(); + if (handle) { handle.dec_ref(); } + } catch (py::error_already_set& eas) { + // Discard any Python error using Python APIs + // https://pybind11.readthedocs.io/en/stable/advanced/exceptions.html#handling-unraisable-exceptions + try { + // ignore potential runtime_error from release() call internal to discard_as_unraisable + eas.discard_as_unraisable(__func__); + } catch (...) {} + } catch (const std::exception& e) { + // catch and print info on any C++ exception raised in the destructor + try { + HOLOSCAN_LOG_ERROR("error in ~GILGuardedPyObject: {}", e.what()); + } catch (...) { + // ignore any fmt::format exception thrown by HOLOSCAN_LOG_ERROR + } + } } private: diff --git a/python/holoscan/core/io_context.cpp b/python/holoscan/core/io_context.cpp index 9c6ff5d9..2c32e7b0 100644 --- a/python/holoscan/core/io_context.cpp +++ b/python/holoscan/core/io_context.cpp @@ -152,7 +152,7 @@ py::object PyInputContext::py_receive(const std::string& name) { } else { auto maybe_result = receive(name.c_str()); if (!maybe_result.has_value()) { - HOLOSCAN_LOG_ERROR("Unable to receive input (std::any) with name '{}'", name); + HOLOSCAN_LOG_DEBUG("Unable to receive input (std::any) with name '{}'", name); return py::none(); } auto result = maybe_result.value(); @@ -164,7 +164,7 @@ py::object PyInputContext::py_receive(const std::string& name) { } void PyOutputContext::py_emit(py::object& data, const std::string& name, - const std::string& emitter_name) { + const std::string& emitter_name, int64_t acq_timestamp) { // Note:: Issue 4206197 // In the UcxTransmitter::sync_io_abi(), while popping an entity from the queue, // Runtime::GxfEntityRefCountDec() on the entity can be called (which locks 'ref_count_mutex_'). @@ -188,7 +188,7 @@ void PyOutputContext::py_emit(py::object& data, const std::string& name, if (!emitter_name.empty()) { HOLOSCAN_LOG_DEBUG("py_emit: emitting a {}", emitter_name); const auto& emit_func = registry.get_emitter(emitter_name); - emit_func(data, name, *this); + emit_func(data, name, *this, acq_timestamp); return; } @@ -196,7 +196,7 @@ void PyOutputContext::py_emit(py::object& data, const std::string& name, if (py::isinstance(data)) { HOLOSCAN_LOG_DEBUG("py_emit: emitting a holoscan::PyEntity"); const auto& emit_func = registry.get_emitter(typeid(holoscan::PyEntity)); - emit_func(data, name, *this); + emit_func(data, name, *this, acq_timestamp); return; } @@ -211,7 +211,7 @@ void PyOutputContext::py_emit(py::object& data, const std::string& name, "py_emit: emitting a std::vector object"); const auto& emit_func = registry.get_emitter(typeid(std::vector)); - emit_func(data, name, *this); + emit_func(data, name, *this, acq_timestamp); return; } } @@ -220,7 +220,7 @@ void PyOutputContext::py_emit(py::object& data, const std::string& name, // handle pybind11::dict separately from other Python types for special TensorMap treatment if (py::isinstance(data)) { const auto& emit_func = registry.get_emitter(typeid(pybind11::dict)); - emit_func(data, name, *this); + emit_func(data, name, *this, acq_timestamp); return; } @@ -259,7 +259,7 @@ void PyOutputContext::py_emit(py::object& data, const std::string& name, if (is_distributed_app && is_tensor_like(data)) { HOLOSCAN_LOG_DEBUG("py_emit: emitting a tensor-like object over a UCX connector"); const auto& emit_func = registry.get_emitter(typeid(holoscan::Tensor)); - emit_func(data, name, *this); + emit_func(data, name, *this, acq_timestamp); return; } @@ -271,7 +271,7 @@ void PyOutputContext::py_emit(py::object& data, const std::string& name, // broadcast codelet was inserted. HOLOSCAN_LOG_DEBUG("py_emit: emitting a std::shared_ptr"); const auto& emit_func = registry.get_emitter(typeid(std::shared_ptr)); - emit_func(data, name, *this); + emit_func(data, name, *this, acq_timestamp); return; } @@ -303,7 +303,12 @@ void init_io_context(py::module_& m) { py::class_>( m, "PyOutputContext", R"doc(Output context class.)doc") - .def("emit", &PyOutputContext::py_emit, "data"_a, "name"_a, "emitter_name"_a = ""); + .def("emit", + &PyOutputContext::py_emit, + "data"_a, + "name"_a, + "emitter_name"_a = "", + "acq_timestamp"_a = -1); // register a cloudpickle-based serializer for Python objects register_py_object_codec(); @@ -352,11 +357,13 @@ void init_io_context(py::module_& m) { PyInputContext::PyInputContext(ExecutionContext* execution_context, Operator* op, std::unordered_map>& inputs, py::object py_op) - : gxf::GXFInputContext::GXFInputContext(execution_context, op, inputs), py_op_(py_op) {} + : gxf::GXFInputContext::GXFInputContext(execution_context, op, inputs), + py_op_(std::move(py_op)) {} PyOutputContext::PyOutputContext(ExecutionContext* execution_context, Operator* op, std::unordered_map>& outputs, py::object py_op) - : gxf::GXFOutputContext::GXFOutputContext(execution_context, op, outputs), py_op_(py_op) {} + : gxf::GXFOutputContext::GXFOutputContext(execution_context, op, outputs), + py_op_(std::move(py_op)) {} } // namespace holoscan diff --git a/python/holoscan/core/io_context.hpp b/python/holoscan/core/io_context.hpp index f72d490b..db6f2ff4 100644 --- a/python/holoscan/core/io_context.hpp +++ b/python/holoscan/core/io_context.hpp @@ -66,7 +66,8 @@ class PyOutputContext : public gxf::GXFOutputContext { std::unordered_map>& outputs, py::object py_op); - void py_emit(py::object& data, const std::string& name, const std::string& emitter_name = ""); + void py_emit(py::object& data, const std::string& name, const std::string& emitter_name = "", + const int64_t acq_timestamp = -1); private: py::object py_op_ = py::none(); diff --git a/python/holoscan/core/io_spec.cpp b/python/holoscan/core/io_spec.cpp index 5d92068e..6e4e4a0c 100644 --- a/python/holoscan/core/io_spec.cpp +++ b/python/holoscan/core/io_spec.cpp @@ -22,6 +22,7 @@ #include #include +#include #include "holoscan/core/condition.hpp" #include "holoscan/core/io_spec.hpp" @@ -56,31 +57,38 @@ void init_io_spec(py::module_& m) { "name"_a, "io_type"_a, doc::IOSpec::doc_IOSpec) - .def_property_readonly("name", &IOSpec::name, doc::IOSpec::doc_name) + .def_property_readonly( + "name", &IOSpec::name, doc::IOSpec::doc_name, py::return_value_policy::reference_internal) .def_property_readonly("io_type", &IOSpec::io_type, doc::IOSpec::doc_io_type) .def_property_readonly( "connector_type", &IOSpec::connector_type, doc::IOSpec::doc_connector_type) - .def_property_readonly("conditions", &IOSpec::conditions, doc::IOSpec::doc_conditions) + .def_property_readonly("conditions", + &IOSpec::conditions, + doc::IOSpec::doc_conditions, + py::return_value_policy::reference_internal) .def( "condition", - [](IOSpec& io_spec, const ConditionType& kind, const py::kwargs& kwargs) { + // Note: The return type needs to be specified explicitly because pybind11 can't deduce it + [](IOSpec& io_spec, const ConditionType& kind, const py::kwargs& kwargs) -> IOSpec& { return io_spec.condition(kind, kwargs_to_arglist(kwargs)); }, - doc::IOSpec::doc_condition) + doc::IOSpec::doc_condition, + py::return_value_policy::reference_internal) // TODO: sphinx API doc build complains if more than one connector // method has a docstring specified. For now just set the docstring for the // first overload only and add information about the rest in the Notes section. .def( "connector", - [](IOSpec& io_spec, const IOSpec::ConnectorType& kind, const py::kwargs& kwargs) { - return io_spec.connector(kind, kwargs_to_arglist(kwargs)); - }, - doc::IOSpec::doc_connector) + // Note: The return type needs to be specified explicitly because pybind11 can't deduce it + [](IOSpec& io_spec, const IOSpec::ConnectorType& kind, const py::kwargs& kwargs) + -> IOSpec& { return io_spec.connector(kind, kwargs_to_arglist(kwargs)); }, + doc::IOSpec::doc_connector, + py::return_value_policy::reference_internal) // using lambdas for overloaded connector methods because py::overload_cast didn't work .def("connector", [](IOSpec& io_spec) { return io_spec.connector(); }) .def("connector", [](IOSpec& io_spec, std::shared_ptr connector) { - return io_spec.connector(connector); + return io_spec.connector(std::move(connector)); }) .def("__repr__", // use py::object and obj.cast to avoid a segfault if object has not been initialized diff --git a/python/holoscan/core/kwarg_handling.cpp b/python/holoscan/core/kwarg_handling.cpp index e7271461..0232a34c 100644 --- a/python/holoscan/core/kwarg_handling.cpp +++ b/python/holoscan/core/kwarg_handling.cpp @@ -29,7 +29,6 @@ #include "holoscan/core/condition.hpp" #include "holoscan/core/io_spec.hpp" #include "holoscan/core/resource.hpp" -#include "holoscan/operators/aja_source/ntv2channel.hpp" #include "kwarg_handling.hpp" #include "kwarg_handling_pydoc.hpp" @@ -106,7 +105,7 @@ void set_vector_arg_via_numpy_array(const py::array& obj, Arg& out) { out = yaml_node; } else if (obj.attr("ndim").cast() == 2) { YAML::Node yaml_node = YAML::Load("[]"); // Create an empty sequence - for (auto item : obj) { + for (const auto& item : obj) { YAML::Node inner_yaml_node = YAML::Load("[]"); // Create an empty sequence for (const auto& inner_item : item) { inner_yaml_node.push_back(cast_to_yaml_node(inner_item)); @@ -131,10 +130,10 @@ void set_vector_arg_via_py_sequence(const py::sequence& seq, Arg& out) { // Handle list of list and other sequence of sequence types. std::vector> v; v.reserve(static_cast(py::len(seq))); - for (auto item : seq) { + for (const auto& item : seq) { std::vector vv; vv.reserve(static_cast(py::len(item))); - for (auto inner_item : item) { vv.push_back(inner_item.cast()); } + for (const auto& inner_item : item) { vv.push_back(inner_item.cast()); } v.push_back(vv); } out = v; @@ -143,7 +142,7 @@ void set_vector_arg_via_py_sequence(const py::sequence& seq, Arg& out) { std::vector v; size_t length = py::len(seq); v.reserve(length); - for (auto item : seq) v.push_back(item.cast()); + for (const auto& item : seq) v.push_back(item.cast()); out = v; } } else { @@ -151,7 +150,7 @@ void set_vector_arg_via_py_sequence(const py::sequence& seq, Arg& out) { if (py::isinstance(first_item) && !py::isinstance(first_item)) { // Handle list of list and other sequence of sequence types. YAML::Node yaml_node = YAML::Load("[]"); // Create an empty sequence - for (auto item : seq) { + for (const auto& item : seq) { YAML::Node inner_yaml_node = YAML::Load("[]"); // Create an empty sequence for (const auto& inner_item : item) { inner_yaml_node.push_back(cast_to_yaml_node(inner_item)); @@ -266,11 +265,11 @@ py::object vector_arg_to_py_object(Arg& arg) { py::object yaml_node_to_py_object(YAML::Node node) { if (node.IsSequence()) { py::list list; - for (auto item : node) { list.append(yaml_node_to_py_object(item)); } + for (const auto& item : node) { list.append(yaml_node_to_py_object(item)); } return list; } else if (node.IsMap()) { py::dict dict; - for (auto item : node) { + for (const auto& item : node) { dict[py::str(item.first.as())] = yaml_node_to_py_object(item.second); } return dict; @@ -294,10 +293,6 @@ py::object yaml_node_to_py_object(YAML::Node node) { } // Check if it is a string. { - // special case for string -> AJASourceOp NTV2Channel enum - NTV2Channel aja_t; - if (YAML::convert::decode(node, aja_t)) { return py::cast(aja_t); } - std::string t; if (YAML::convert::decode(node, t)) { return py::str(t); } } @@ -428,7 +423,7 @@ ArgList kwargs_to_arglist(const py::kwargs& kwargs) { // There is currently no option to choose conversion to kArray instead of kNative. ArgList arglist; if (kwargs) { - for (auto& [name, handle] : kwargs) { + for (const auto& [name, handle] : kwargs) { arglist.add(py_object_to_arg(handle.cast(), name.cast())); } /// .. do something with kwargs diff --git a/python/holoscan/core/operator.cpp b/python/holoscan/core/operator.cpp index efb34d3e..e417139a 100644 --- a/python/holoscan/core/operator.cpp +++ b/python/holoscan/core/operator.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include "gil_guarded_pyobject.hpp" @@ -124,6 +125,16 @@ void init_operator(py::module_& m) { .def_property_readonly("resources", &Operator::resources, doc::Operator::doc_resources) .def_property_readonly( "operator_type", &Operator::operator_type, doc::Operator::doc_operator_type) + .def( + "resource", + [](Operator& op, const py::str& name) -> std::optional { + auto resources = op.resources(); + auto res = resources.find(name); + if (res == resources.end()) { return py::none(); } + return py::cast(res->second); + }, + "name"_a, + doc::Operator::doc_resource) .def("add_arg", py::overload_cast(&Operator::add_arg), "arg"_a, @@ -182,7 +193,7 @@ void init_operator(py::module_& m) { } PyOperatorSpec::PyOperatorSpec(Fragment* fragment, py::object op) - : OperatorSpec(fragment), py_op_(op) {} + : OperatorSpec(fragment), py_op_(std::move(op)) {} void PyOperatorSpec::py_param(const std::string& name, const py::object& default_value, const ParameterFlag& flag, const py::kwargs& kwargs) { @@ -191,8 +202,8 @@ void PyOperatorSpec::py_param(const std::string& name, const py::object& default bool is_receivers = false; std::string headline{""s}; std::string description{""s}; - for (const auto& [name, value] : kwargs) { - std::string param_name = name.cast(); + for (const auto& [kw_name, value] : kwargs) { + std::string param_name = kw_name.cast(); if (param_name == "headline") { headline = value.cast(); } else if (param_name == "description") { diff --git a/python/holoscan/core/operator_pydoc.hpp b/python/holoscan/core/operator_pydoc.hpp index 4706d8b3..aaee65f0 100644 --- a/python/holoscan/core/operator_pydoc.hpp +++ b/python/holoscan/core/operator_pydoc.hpp @@ -189,6 +189,20 @@ PYDOC(resources, R"doc( Resources associated with the operator. )doc") +PYDOC(resource, R"doc( +Resources associated with the operator. + +Parameters +---------- +name : str +The name of the resource to retrieve + +Returns +------- +holoscan.core.Resource or None + The resource with the given name. If no resource with the given name is found, None is returned. +)doc") + PYDOC(add_arg_Arg, R"doc( Add an argument to the component. )doc") diff --git a/python/holoscan/core/resource.cpp b/python/holoscan/core/resource.cpp index 61426008..0d744162 100644 --- a/python/holoscan/core/resource.cpp +++ b/python/holoscan/core/resource.cpp @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,6 +21,7 @@ #include #include +#include "component.hpp" #include "holoscan/core/arg.hpp" #include "holoscan/core/component.hpp" #include "holoscan/core/component_spec.hpp" @@ -42,9 +43,14 @@ class PyResource : public Resource { // Define a kwargs-based constructor that can create an ArgList // for passing on to the variadic-template based constructor. - PyResource(const py::args& args, const py::kwargs& kwargs) : Resource() { + PyResource(py::object resource, Fragment* fragment, const py::args& args, + const py::kwargs& kwargs) + : Resource() { using std::string_literals::operator""s; + py_resource_ = resource; + fragment_ = fragment; + int n_fragments = 0; for (auto& item : args) { py::object arg_value = item.cast(); @@ -81,6 +87,12 @@ class PyResource : public Resource { } } + // Override spec() method + std::shared_ptr py_shared_spec() { + auto spec_ptr = spec_shared(); + return std::static_pointer_cast(spec_ptr); + } + /* Trampolines (need one for each virtual function) */ void initialize() override { /* , , , */ @@ -90,12 +102,19 @@ class PyResource : public Resource { /* , , , */ PYBIND11_OVERRIDE(void, Resource, setup, spec); } + + private: + py::object py_resource_ = py::none(); }; void init_resource(py::module_& m) { - py::class_>( - m, "Resource", doc::Resource::doc_Resource) - .def(py::init(), doc::Resource::doc_Resource_args_kwargs) + // note: added py::dynamic_attr() to allow dynamically adding attributes in a Python subclass + py::class_> resource_class( + m, "Resource", py::dynamic_attr(), doc::Resource::doc_Resource_args_kwargs); + + resource_class + .def(py::init(), + doc::Resource::doc_Resource_args_kwargs) .def_property("name", py::overload_cast<>(&Resource::name, py::const_), (Resource & (Resource::*)(const std::string&)&)&Resource::name, @@ -110,6 +129,8 @@ void init_resource(py::module_& m) { &Resource::initialize, doc::Resource::doc_initialize) // note: virtual function .def_property_readonly("description", &Resource::description, doc::Resource::doc_description) + .def_property_readonly( + "resource_type", &Resource::resource_type, doc::Resource::doc_resource_type) .def( "__repr__", [](const py::object& obj) { @@ -119,6 +140,10 @@ void init_resource(py::module_& m) { return std::string(""); }, R"doc(Return repr(self).)doc"); + + py::enum_(resource_class, "ResourceType") + .value("NATIVE", Resource::ResourceType::kNative) + .value("GXF", Resource::ResourceType::kGXF); } } // namespace holoscan diff --git a/python/holoscan/core/resource_pydoc.hpp b/python/holoscan/core/resource_pydoc.hpp index c259d520..8edaf080 100644 --- a/python/holoscan/core/resource_pydoc.hpp +++ b/python/holoscan/core/resource_pydoc.hpp @@ -95,6 +95,13 @@ PYDOC(description, R"doc( YAML formatted string describing the resource. )doc") +PYDOC(resource_type, R"doc( +Resource type. + +`holoscan.core.Resource.ResourceType` enum representing the type of +the operator. The two types currently implemented are NATIVE and GXF. +)doc") + } // namespace Resource } // namespace holoscan::doc diff --git a/python/holoscan/core/tensor.cpp b/python/holoscan/core/tensor.cpp index 9eb79fd1..9e7e403d 100644 --- a/python/holoscan/core/tensor.cpp +++ b/python/holoscan/core/tensor.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include "dl_converter.hpp" @@ -212,7 +213,9 @@ LazyDLManagedTensorDeleter::LazyDLManagedTensorDeleter() { } LazyDLManagedTensorDeleter::~LazyDLManagedTensorDeleter() { - release(); + try { + release(); + } catch (const std::exception& e) {} // ignore potential fmt::v8::format_error } void LazyDLManagedTensorDeleter::add(DLManagedTensor* dl_managed_tensor_ptr) { @@ -283,7 +286,10 @@ void LazyDLManagedTensorDeleter::release() { std::this_thread::yield(); } HOLOSCAN_LOG_DEBUG("LazyDLManagedTensorDeleter thread stopped"); - s_stop = false; + { + std::lock_guard lock(s_mutex); + s_stop = false; + } } } @@ -594,7 +600,7 @@ py::capsule PyTensor::dlpack(const py::object& obj, py::object stream) { // Do not copy 'obj' or a shared pointer here in the lambda expression's initializer, otherwise // the refcount of it will be increased by 1 and prevent the object from being destructed. Use a // raw pointer here instead. - return py_dlpack(tensor.get(), stream); + return py_dlpack(tensor.get(), std::move(stream)); } py::tuple PyTensor::dlpack_device(const py::object& obj) { diff --git a/python/holoscan/decorator.py b/python/holoscan/decorator.py new file mode 100644 index 00000000..f16e61fa --- /dev/null +++ b/python/holoscan/decorator.py @@ -0,0 +1,577 @@ +""" + SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + SPDX-License-Identifier: Apache-2.0 + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +""" # noqa: E501 + +import ast +import inspect +import textwrap +from dataclasses import dataclass, field + +# Need Python 3.9 to use builtin tuple and dict directly instead of typing.Tuple, typing.Dict +from typing import Any, Dict, Optional, Tuple, Union + +import cupy as cp +import numpy as np + +from holoscan.conditions import BooleanCondition, CountCondition +from holoscan.core import ( + Condition, + ConditionType, + Fragment, + IOSpec, + Operator, + OperatorSpec, + Resource, +) +from holoscan.core._core import Fragment as FragmentBase +from holoscan.core._core import Tensor as TensorBase + +__all__ = ["Input", "Output", "create_op"] + + +def _is_tensor_like(obj): + if ( + (hasattr(obj, "__dlpack__") and hasattr(obj, "__dlpack_device__")) + or hasattr(obj, "__cuda_array_interface__") + or hasattr(obj, "__array_interface__") + ): + return True + return False + + +def _as_python_tensor(tensor): + if hasattr(tensor, "__array_interface__") or ( + hasattr(tensor, "__dlpack_device__") and tensor.__dlpack_device__()[0] == 1 + ): + return np.asarray(tensor) + else: + return cp.asarray(tensor) + + +@dataclass +class Input: + """Class for specifying an input port and how the received value maps to a function's arguments. + + Parameters + ---------- + name : str + The name of the input port. + arg_map: str or dict[str, str] + If `arg_map` is a str, the Python object received by the input port is passed to the + function argument specified by `arg_map`. If `arg_map` is a dict, the input is assumed to be + a TensorMap (dictionary of tensors). In this case the keys of the dict are the tensor names + and the values are the names of the function arguments that the tensors map to. + condition_type : holoscan.core.ConditionType, optional + The condition type for the input port. + condition_kwargs : dict[str, Any], optional + The keywords passed onto the condition specified by `condition_type`. + connector_type : holoscan.core.IOSpec.ConnectorType, optional + The connector type for the input port. + connector_kwargs : dict[str, Any], optional + The keywords passed onto the connector specified by `connector_type`. + """ + + name: str + arg_map: Optional[Union[str, dict[str, str]]] = () + condition_type: Optional[ConditionType] = None + condition_kwargs: Dict[str, Any] = field(default_factory=dict) + connector_type: Optional[IOSpec.ConnectorType] = None + connector_kwargs: Dict[str, Any] = field(default_factory=dict) + + def create_input(self, spec: OperatorSpec) -> IOSpec: + iospec = spec.input(self.name) + if self.condition_type is not None: + iospec = iospec.condition(self.condition_type, **self.condition_kwargs) + if self.connector_type is not None: + iospec = iospec.connector(self.connector_type, **self.connector_kwargs) + + +@dataclass +class Output: + """Class for specifying an output port and how the received value maps to a function's + arguments. + + Parameters + ---------- + name : str + The name of the input port. + tensor_names: tuple(str) or None + If None, whatever Python object the func outputs is emitted on the output port. If a tuple + of strings is provided it is assumed that the func returns a dictionary of tensors. The + names in the tuple specify which tensors in the dict will be transmitted on the output + port. There is no need to specify `tensor_names` if all tensors in a dict returned by the + function are to be transmitted. + condition_type : holoscan.core.ConditionType, optional + The condition type for the input port. + condition_kwargs : dict[str, Any], optional + The keywords passed onto the condition specified by `condition_type`. + connector_type : holoscan.core.IOSpec.ConnectorType, optional + The connector type for the input port. + connector_kwargs : dict[str, Any], optional + The keywords passed onto the connector specified by `connector_type`. + """ + + name: str + tensor_names: Optional[Tuple[str]] = () + condition_type: Optional[ConditionType] = None + condition_kwargs: Dict[str, Any] = field(default_factory=dict) + connector_type: Optional[IOSpec.ConnectorType] = None + connector_kwargs: Dict[str, Any] = field(default_factory=dict) + + def create_output(self, spec: OperatorSpec) -> IOSpec: + iospec = spec.output(self.name) + if self.condition_type is not None: + iospec = iospec.condition(self.condition_type, **self.condition_kwargs) + if self.connector_type is not None: + iospec = iospec.connector(self.connector_type, **self.connector_kwargs) + + +def _as_input(input_: Union[str, Input]): + """Cast str to Output object.""" + if isinstance(input_, str): + return Input(input_, arg_map=input_) + elif not isinstance(input_, Input): + return ValueError("`inputs` must be a single port name or Input object or a tuple of these") + return input_ + + +def _as_output(output: Union[str, Output]): + """Cast str to Output object.""" + if isinstance(output, str): + return Output(output) + elif not isinstance(output, Output): + return ValueError( + "`outputs` must be a single port name or Output object or a tuple of these" + ) + return output + + +def _has_function_returns_value(func): + """Check if the provided function has any return statements returning a value.""" + + class ReturnVisitor(ast.NodeVisitor): + def __init__(self): + self.returns_value = False + + def visit_Return(self, node): # noqa: N802 + # check if the return statement has a value + if node.value is not None: + self.returns_value = True + return + + self.generic_visit(node) + + def visit_ClassDef(self, node): # noqa: N802 + return + + def visit_FunctionDef(self, node): # noqa: N802 + return + + def visit_AsyncFunctionDef(self, node): # noqa: N802 + return + + def visit(self, node): + if self.returns_value: + return + super().visit(node) + + # parse the source code into an AST + source_code = inspect.getsource(func) + # deindent the text if it is indented + source_code = textwrap.dedent(source_code) + tree = ast.parse(source_code) + # initialize the visitor + visitor = ReturnVisitor() + # walk the AST + for node in ast.walk(tree): + if isinstance(node, ast.FunctionDef) and node.name == func.__name__: + visitor.generic_visit(node) + break + return visitor.returns_value + + +def create_op( + function_or_class=None, + inputs: Union[str, Input, Tuple[Union[str, Input]]] = (), + outputs: Union[str, Output, Tuple[Union[str, Output]]] = (), + cast_tensors=True, +): + """Decorator for creating an operator from a function or a class. + + When the decorator is used on a class, the class must have a `__call__` method that will be + used as the operator function. + + inputs : str, Input, or Tuple[str | Input], optional + If a str is provided, it is assumed to be the name of the input port and that the function + has a variable matching that port name to which the object received on the port will be + connected. If the port name does not match the name of the variable in the function + signature, or if there are multiple tensors to be mapped to multiple objects, use an Input + argument. A tuple of str or Input objects can be provided to specify multiple input ports. + The default of an empty tuple corresponds to no input ports. + outputs : str, Output, or Tuple[str | Output], optional + If a str is provided, any value returned by the function will be emitted on an output port + of that name. Otherwise, an Output object can be provided in the case that the function + returns multiple outputs that should be split across multiple ports. + cast_tensors : bool, optional + If True, automatically cast any tensor-like input to a NumPy or CuPy array (for host and + device tensors, respectively). If set to False, these will be left as `holoscan.Tensor` and + the user will have to cast to the desired type within the body of the decorated function or + class. + + Notes + ----- + Another case where using `Input` or `Output` objects is necessary is if the user wishes to + override the default connector or condition types for the port. + """ + # used to store the class object if the decorator is used on a class + class_obj = None + # used to determine if the decorator was used without args + is_without_args = function_or_class is not None + + # convert scalars to tuple + if isinstance(inputs, (str, Input)): + inputs = (inputs,) + # convert any str in the tuple to an Input object + inputs = tuple(_as_input(i) for i in inputs) + + if isinstance(outputs, (str, Output)): + outputs = (outputs,) + # convert any str in the tuple to an Output object + outputs = tuple(_as_output(o) for o in outputs) + + if not isinstance(outputs, tuple): + raise ValueError( + "`outputs` must be a single port name or Output object or a tuple of these" + ) + + def decorator(func_or_cls): + nonlocal function_or_class, class_obj + + def make_class(*args, **kwargs): + if "fragment" in kwargs: + fragment = kwargs.pop("fragment") + elif len(args) and isinstance(args[0], FragmentBase): + fragment, args = args[0], args[1:] + else: + raise ValueError( + "fragment must be provided via kwarg or as the first positional argument" + ) + + # frame = inspect.currentframe() + # args_names, _, _, locals_dict = inspect.getargvalues(frame) + # print(f"{args_names=}, {locals_dict=}") + + class DynamicOp(Operator): + def __init__( + self, + fragment: FragmentBase, + *args, + inputs, + outputs, + cast_tensors=cast_tensors, + **kwargs, + ): + self.func = func_or_cls + self.input_objs = inputs + self.output_objs = outputs + self.is_generator = inspect.isgeneratorfunction(self.func) + self.gen_obj = None + self.cast_tensors = cast_tensors + + # remove conditions and resources from *args + condition_args = tuple(a for a in args if isinstance(a, Condition)) + resource_args = tuple(a for a in args if isinstance(a, Resource)) + args = tuple(a for a in args if not isinstance(a, (Condition, Resource))) + self.func_args = args + + # add a boolean condition to prevent triggering if the function is a generator + # and the iteration is complete + if self.is_generator: + condition_args = condition_args + ( + BooleanCondition(fragment, name="_generator_func"), + ) + + # set name kwarg to self.func.__name__ if not provided + name = kwargs.pop("name", self.func.__name__) + + argspec = inspect.getfullargspec(self.func) + + # remove self from argspec.args if the decorator is used on a class + if class_obj: + argspec = argspec._replace(args=argspec.args[1:]) + self.class_obj = class_obj + + self.func_argspec = argspec + + # populate inputs and outputs with defaults if decorator was used without args + if is_without_args: + self.input_objs = tuple(Input(name, arg_map=name) for name in argspec.args) + # configure the output port if the function contains return statements + # (in this case, the port name will be left empty) + if _has_function_returns_value(function_or_class): + self.output_objs = tuple((Output(""),)) + + # populate all arguments not provided with defaults + if argspec.kwonlydefaults is not None: + for k in argspec.kwonlyargs: + if k not in kwargs and k in argspec.kwonlydefaults: + kwargs[k] = argspec.kwonlydefaults[k] + + # store a list of what ports map to what function arguments + self.input_mappings = {} + for input_obj in self.input_objs: + # store what argument(s) this input maps to + self.input_mappings[input_obj.name] = input_obj.arg_map + + # sets self.dynamic_kwargs and self.fixed_kwargs + self._set_fixed_and_dynamic_kwargs(kwargs) + + # get the type annotations dict for the function (not currently used) + # self.func_annotations = inspect.get_annotations(self.func) + self.func_annotations = self.func.__annotations__ + + super().__init__(fragment, *condition_args, *resource_args, name=name) + + def _set_fixed_and_dynamic_kwargs(self, kwargs): + """Split provided kwargs into those which are "fixed" and those which are + "dynamic". + + Here "dynamic" refers to function arguments that are obtained from input + ports. The keys for self.dynamic_kwargs are determined here, but the values + are initialized to None. Actual values get set during each `compute` call. + + "fixed" refers to other keyword arguments to the function that don't change + across calls. + """ + self.dynamic_kwargs = {} + for input_map in self.input_mappings.values(): + if isinstance(input_map, str): + self._add_dynamic_arg(input_map, kwargs) + elif isinstance(input_map, dict): + for arg_name in input_map.values(): + self._add_dynamic_arg(arg_name, kwargs) + self.fixed_kwargs = kwargs + + # store any positional args with specified defaults in fixed_kwargs instead + argspec = self.func_argspec + if argspec.defaults is not None: + n_default_positional = len(argspec.defaults) + if n_default_positional > 0: + self.func_args = self.func_args[:-n_default_positional] + n_required_positional = len(argspec.args) - len(argspec.defaults) + for k, v in zip(argspec.args[n_required_positional:], argspec.defaults): + # don't overwrite any kwargs that were provided + if k not in self.fixed_kwargs: + self.fixed_kwargs[k] = v + + # Now that all args with defaults are in self.fixed_kwargs we can check if any + # of the required arguments were not specified + required_args = set(argspec.args) | set(argspec.kwonlyargs) + if argspec.kwonlydefaults is not None: + required_args -= set(argspec.kwonlydefaults.keys()) + for arg in required_args: + if arg not in self.fixed_kwargs and arg not in self.dynamic_kwargs: + raise ValueError(f"required argument, '{arg}', has not been specified") + + def _add_dynamic_arg(self, arg_name, kwargs): + """helper function for _set_fixed_and_dynamic_kwargs""" + if arg_name in self.dynamic_kwargs: + raise ValueError( + "duplicate specification of mapping to function kwarg: '{arg_name}'" + ) + self.dynamic_kwargs[arg_name] = None + try: + kwargs.pop(arg_name) + except KeyError as e: + argspec = self.func_argspec + if arg_name not in argspec.kwonlyargs + argspec.args: + msg = ( + f"Provided func does not have an arg or kwarg named '{arg_name}'." + " The provided wrapped function has" + f" positional args: {argspec.args}" + f" and keyword-only args: {argspec.kwonlyargs}" + ) + raise KeyError(msg) from e + return + + # # not used by the Application, but can be useful to test the call + # def __call__(self, *args, **kwargs): + # print(f"{self.msg=}") + # return self.func(*self.func_args, *args, **self.fixed_kwargs, **kwargs) + + def setup(self, spec: OperatorSpec): + for input_obj in self.input_objs: + input_obj.create_input(spec) + + self.output_tensor_map = {} + for output_obj in self.output_objs: + output_obj.create_output(spec) + self.output_tensor_map[output_obj.name] = output_obj.tensor_names + + def compute(self, op_input, op_output, context): + for port_name, arg_map in self.input_mappings.items(): + print(f"input {port_name=}, {arg_map=}") + msg = op_input.receive(port_name) + if isinstance(arg_map, str): + # print(f"{msg=}") + if isinstance(msg, dict): + try: + # try tensor based on matching name + msg = msg[arg_map] + except KeyError as e: + # use tensor regardless of name if only one is present + tensors = tuple( + v for k, v in msg.items() if isinstance(v, TensorBase) + ) + if len(tensors) == 1: + msg = tensors[0] + elif len(tensors) > 1: + raise ValueError( + "More than one tensor found in port, but none has " + f"name {arg_map}" + ) from e + + # cast holoscan.Tensor to cp.asarray(Tensor) here or require the user + # to do it in the provided func? + if self.cast_tensors and isinstance(msg, TensorBase): + msg = _as_python_tensor(msg) + + self.dynamic_kwargs[arg_map] = msg + elif isinstance(arg_map, dict): + for tensor_name, arg_name in arg_map.items(): + try: + val = msg[tensor_name] + except KeyError as e: + raise KeyError( + f"key with name '{tensor_name}' not found in input dict" + ) from e + if self.cast_tensors and isinstance(val, TensorBase): + val = _as_python_tensor(val) + self.dynamic_kwargs[arg_name] = val + + if self.is_generator: + if self.gen_obj is None: + out = self.func( + *self.func_args, **self.fixed_kwargs, **self.dynamic_kwargs + ) + self.gen_obj = out + try: + out = next(self.gen_obj) + except StopIteration: + # disable the condition to prevent further calls + self.conditions["_generator_func"].disable_tick() + return + else: + out = self.func(*self.func_args, **self.fixed_kwargs, **self.dynamic_kwargs) + + for port_name, tensor_names in self.output_tensor_map.items(): + if tensor_names is None or len(tensor_names) == 0: + if _is_tensor_like(out): + # emit as dict of tensor-like objects + out = {"": out} + op_output.emit(out, port_name) + elif len(tensor_names) == 1: + name = tensor_names[0] + if _is_tensor_like(out): + # emit as dict of tensor-like objects + out = {name: out} + op_output.emit(out, port_name) + else: + if name not in out: + raise ValueError( + f"tensor with name '{name}' not found in function output" + ) + op_output.emit({name: out[name]}, port_name) + else: + out_tensors = {} + for name in tensor_names: + if name not in out: + raise ValueError( + f"tensor with name '{name}' not found in function output" + ) + out_tensors[name] = out[name] + # print(f"outputting tensors named: {tuple(out_tensors.keys())} on + # port {port_name}") + # print(f"tensormap emit of {out_tensors=}") + op_output.emit(out_tensors, port_name) + + op = DynamicOp(fragment, *args, inputs=inputs, outputs=outputs, **kwargs) + + def _to_camel_case(name): + """Convert name to camel case""" + parts = name.split("_") + return "".join(p.capitalize() for p in parts) + + # manually update instead of using functools.update_wrapper(op, func_or_cls) because: + # - don't want to overwrite __doc__ with func.__doc__ + # - want to use name instead of func.__name__ + if class_obj: + class_name = class_obj.__class__.__name__ + op.__name__ = class_name + "Op" if not class_name.endswith("Op") else class_name + else: + op.__name__ = _to_camel_case(func_or_cls.__name__) + "Op" + op.__qualname__ = op.__name__ + op.__module__ = func_or_cls.__module__ + return op + + def init_class(*args, **kwargs): + nonlocal class_obj, function_or_class + # create an instance of the class (using function_or_class as the class) + class_obj = function_or_class(*args, **kwargs) + # use the class's __call__ method as the operator function + if not callable(class_obj): + raise ValueError( + f"{function_or_class} must have a __call__ method to be used as an operator" + ) + function_or_class = class_obj.__call__ + return decorator(function_or_class) + + if func_or_cls is None: + return decorator + + # check if the decorator was used on a class first + if inspect.isclass(func_or_cls): # if isinstance(func_or_cls, type): + function_or_class = func_or_cls + return init_class + + if callable(func_or_cls): + return make_class + + raise Exception(f"Invalid usage of decorator for {func_or_cls}") + + return decorator(function_or_class) + + +""" +Remove example code from below this point +""" + +if False: + f = Fragment() + + @create_op( + inputs=Input("image", arg_map={"tensor": "image"}), + outputs="out", + ) + def scale_image(image: cp.ndarray, *, value: float = 1.0): + """Operator that scales an image by a specified value""" + return image * value + + # ScaleOp operator with non-default value + scale_op = scale_image(f, CountCondition(f, count=10), value=5.0, name="scale") + + assert scale_op.__name__ == "ScaleImageOp" + assert scale_op.name == "scale" diff --git a/python/holoscan/operators/aja_source/aja_source.cpp b/python/holoscan/operators/aja_source/aja_source.cpp index 5b278cdc..d5a6a5be 100644 --- a/python/holoscan/operators/aja_source/aja_source.cpp +++ b/python/holoscan/operators/aja_source/aja_source.cpp @@ -16,10 +16,13 @@ */ #include +#include #include #include #include +#include +#include #include "../operator_util.hpp" #include "./pydoc.hpp" @@ -39,6 +42,29 @@ namespace py = pybind11; namespace holoscan::ops { +namespace { + +static std::unordered_map const NTV2ChannelMapping = { + {"NTV2_CHANNEL1", NTV2Channel::NTV2_CHANNEL1}, + {"NTV2_CHANNEL2", NTV2Channel::NTV2_CHANNEL2}, + {"NTV2_CHANNEL3", NTV2Channel::NTV2_CHANNEL3}, + {"NTV2_CHANNEL4", NTV2Channel::NTV2_CHANNEL4}, + {"NTV2_CHANNEL5", NTV2Channel::NTV2_CHANNEL5}, + {"NTV2_CHANNEL6", NTV2Channel::NTV2_CHANNEL6}, + {"NTV2_CHANNEL7", NTV2Channel::NTV2_CHANNEL7}, + {"NTV2_CHANNEL8", NTV2Channel::NTV2_CHANNEL8}}; + +static NTV2Channel ToNTV2Channel(const std::string& value) { + auto it = NTV2ChannelMapping.find(value); + if (it != NTV2ChannelMapping.end()) { + return it->second; + } else { + return NTV2Channel::NTV2_CHANNEL_INVALID; + } +} + +} // namespace + /* Trampoline class for handling Python kwargs * * These add a constructor that takes a Fragment for which to initialize the operator. @@ -55,22 +81,31 @@ class PyAJASourceOp : public AJASourceOp { using AJASourceOp::AJASourceOp; // Define a constructor that fully initializes the object. - PyAJASourceOp(Fragment* fragment, const py::args& args, const std::string& device = "0"s, - NTV2Channel channel = NTV2Channel::NTV2_CHANNEL1, uint32_t width = 1920, - uint32_t height = 1080, uint32_t framerate = 60, bool rdma = false, - bool enable_overlay = false, - NTV2Channel overlay_channel = NTV2Channel::NTV2_CHANNEL2, bool overlay_rdma = true, - const std::string& name = "aja_source") + PyAJASourceOp( + Fragment* fragment, const py::args& args, const std::string& device = "0"s, + const std::variant channel = NTV2Channel::NTV2_CHANNEL1, + uint32_t width = 1920, uint32_t height = 1080, uint32_t framerate = 60, bool rdma = false, + bool enable_overlay = false, + const std::variant overlay_channel = NTV2Channel::NTV2_CHANNEL2, + bool overlay_rdma = true, const std::string& name = "aja_source") : AJASourceOp(ArgList{Arg{"device", device}, - Arg{"channel", channel}, Arg{"width", width}, Arg{"height", height}, Arg{"framerate", framerate}, Arg{"rdma", rdma}, Arg{"enable_overlay", enable_overlay}, - Arg{"overlay_channel", overlay_channel}, Arg{"overlay_rdma", overlay_rdma}}) { add_positional_condition_and_resource_args(this, args); + if (std::holds_alternative(channel)) { + this->add_arg(Arg("channel", ToNTV2Channel(std::get(channel)))); + } else { + this->add_arg(Arg("channel", std::get(channel))); + } + if (std::holds_alternative(overlay_channel)) { + this->add_arg(Arg("overlay_channel", ToNTV2Channel(std::get(overlay_channel)))); + } else { + this->add_arg(Arg("overlay_channel", std::get(overlay_channel))); + } name_ = name; fragment_ = fragment; spec_ = std::make_shared(fragment); @@ -104,13 +139,13 @@ PYBIND11_MODULE(_aja_source, m) { .def(py::init, uint32_t, uint32_t, uint32_t, bool, bool, - NTV2Channel, + const std::variant, bool, const std::string&>(), "fragment"_a, diff --git a/python/holoscan/operators/bayer_demosaic/bayer_demosaic.cpp b/python/holoscan/operators/bayer_demosaic/bayer_demosaic.cpp index d36c8604..e5694eb6 100644 --- a/python/holoscan/operators/bayer_demosaic/bayer_demosaic.cpp +++ b/python/holoscan/operators/bayer_demosaic/bayer_demosaic.cpp @@ -89,7 +89,7 @@ PYBIND11_MODULE(_bayer_demosaic, m) { py::class_>( m, "BayerDemosaicOp", doc::BayerDemosaicOp::doc_BayerDemosaicOp) - .def(py::init<>(), doc::BayerDemosaicOp::doc_BayerDemosaicOp) + .def(py::init<>()) .def(py::init, diff --git a/python/holoscan/operators/gxf_codelet/gxf_codelet.cpp b/python/holoscan/operators/gxf_codelet/gxf_codelet.cpp index 728f57f3..beea2253 100644 --- a/python/holoscan/operators/gxf_codelet/gxf_codelet.cpp +++ b/python/holoscan/operators/gxf_codelet/gxf_codelet.cpp @@ -100,7 +100,7 @@ PYBIND11_MODULE(_gxf_codelet, m) { py::class_>( m, "GXFCodeletOp", doc::GXFCodeletOp::doc_GXFCodeletOp) - .def(py::init<>(), doc::GXFCodeletOp::doc_GXFCodeletOp) + .def(py::init<>()) .def(py::init& in_tensor_names, const std::vector& out_tensor_names, bool infer_on_cpu = false, @@ -130,10 +131,19 @@ class PyInferenceOp : public InferenceOp { } py::dict temporal_map_infer = temporal_map.cast(); - for (auto& [key, value] : temporal_map_infer) { temporal_map_infer[key] = py::str(value); } + for (auto& [key, value] : temporal_map_infer) { + if (!py::isinstance(value)) { temporal_map_infer[key] = py::str(value); } + } + + py::dict activation_map_infer = activation_map.cast(); + for (auto& [key, value] : activation_map_infer) { + if (!py::isinstance(value)) { activation_map_infer[key] = py::str(value); } + } py::dict device_map_infer = device_map.cast(); - for (auto& [key, value] : device_map_infer) { device_map_infer[key] = py::str(value); } + for (auto& [key, value] : device_map_infer) { + if (!py::isinstance(value)) { device_map_infer[key] = py::str(value); } + } // convert from Python dict to InferenceOp::DataVecMap auto inference_map_datavecmap = _dict_to_inference_datavecmap(inference_map_dict); @@ -148,6 +158,9 @@ class PyInferenceOp : public InferenceOp { auto temporal_datamap = _dict_to_inference_datamap(temporal_map_infer); this->add_arg(Arg("temporal_map", temporal_datamap)); + auto activation_datamap = _dict_to_inference_datamap(activation_map_infer); + this->add_arg(Arg("activation_map", activation_datamap)); + auto backend_datamap = _dict_to_inference_datamap(backend_map.cast()); this->add_arg(Arg("backend_map", backend_datamap)); @@ -183,6 +196,7 @@ PYBIND11_MODULE(_inference, m) { py::dict, py::dict, py::dict, + py::dict, const std::vector&, const std::vector&, bool, @@ -202,6 +216,7 @@ PYBIND11_MODULE(_inference, m) { "pre_processor_map"_a, "device_map"_a = py::dict(), "temporal_map"_a = py::dict(), + "activation_map"_a = py::dict(), "backend_map"_a = py::dict(), "in_tensor_names"_a = std::vector{}, "out_tensor_names"_a = std::vector{}, diff --git a/python/holoscan/operators/inference/pydoc.hpp b/python/holoscan/operators/inference/pydoc.hpp index b26ab665..4455bd12 100644 --- a/python/holoscan/operators/inference/pydoc.hpp +++ b/python/holoscan/operators/inference/pydoc.hpp @@ -73,6 +73,8 @@ device_map : dict[str, int], optional Mapping of model to GPU ID for inference. temporal_map : dict[str, int], optional Mapping of model to frame delay for inference. +activation_map : dict[str, int], optional + Mapping of model to activation state for inference. backend_map : dict[str, str], optional Mapping of model to backend type for inference. Backend options: ``"trt"`` or ``"torch"`` in_tensor_names : sequence of str, optional diff --git a/python/holoscan/operators/operator_util.hpp b/python/holoscan/operators/operator_util.hpp index 8033d33b..9db7711c 100644 --- a/python/holoscan/operators/operator_util.hpp +++ b/python/holoscan/operators/operator_util.hpp @@ -156,10 +156,10 @@ void set_vector_arg_via_py_sequence(const py::sequence& seq, Arg& out) { // Handle list of list and other sequence of sequence types. std::vector> v; v.reserve(static_cast(py::len(seq))); - for (auto item : seq) { + for (const auto& item : seq) { std::vector vv; vv.reserve(static_cast(py::len(item))); - for (auto inner_item : item) { vv.push_back(inner_item.cast()); } + for (const auto& inner_item : item) { vv.push_back(inner_item.cast()); } v.push_back(vv); } out = v; @@ -176,7 +176,7 @@ void set_vector_arg_via_py_sequence(const py::sequence& seq, Arg& out) { if (py::isinstance(first_item) && !py::isinstance(first_item)) { // Handle list of list and other sequence of sequence types. YAML::Node yaml_node = YAML::Load("[]"); // Create an empty sequence - for (auto item : seq) { + for (const auto& item : seq) { YAML::Node inner_yaml_node = YAML::Load("[]"); // Create an empty sequence for (const auto& inner_item : item) { inner_yaml_node.push_back(cast_to_yaml_node(inner_item)); diff --git a/python/holoscan/resources/__init__.py b/python/holoscan/resources/__init__.py index ef7a900d..137e5cde 100644 --- a/python/holoscan/resources/__init__.py +++ b/python/holoscan/resources/__init__.py @@ -119,7 +119,7 @@ def __init__(self, fragment, *args, **kwargs): # (https://pybind11.readthedocs.io/en/stable/advanced/classes.html#overriding-virtual-functions-in-python) _GXFComponentResource.__init__(self, self, fragment, *args, **kwargs) # Create a PyGXFComponentResourceSpec object and pass it to the C++ API - spec = ComponentSpec(fragment=self.fragment, op=self) + spec = ComponentSpec(fragment=self.fragment, component=self) self.spec = spec # Call setup method in the derived class self.setup(spec) diff --git a/python/holoscan/resources/gxf_component_resource.cpp b/python/holoscan/resources/gxf_component_resource.cpp index d084ce70..1673dbbf 100644 --- a/python/holoscan/resources/gxf_component_resource.cpp +++ b/python/holoscan/resources/gxf_component_resource.cpp @@ -93,7 +93,7 @@ void init_gxf_component_resource(py::module_& m) { gxf::GXFResource, std::shared_ptr>( m, "GXFComponentResource", doc::GXFComponentResource::doc_GXFComponentResource) - .def(py::init<>(), doc::GXFComponentResource::doc_GXFComponentResource) + .def(py::init<>()) .def(py::init +spec: +""" + in repr(cond) + ) + + # assert no warnings or errors logged + captured = capfd.readouterr() + assert "error" not in captured.err + assert "warning" not in captured.err + + def test_default_initialization(self, app): + ExpiringMessageAvailableCondition(app, 1, 4) + + def test_positional_initialization(self, app): + ExpiringMessageAvailableCondition(app, 1, 4, RealtimeClock(app, name="clock"), "expiring") + + class TestPeriodicCondition: def test_kwarg_based_initialization(self, app, capfd): name = "periodic" diff --git a/python/tests/unit/test_core.py b/python/tests/unit/test_core.py index fd50e930..72fbf246 100644 --- a/python/tests/unit/test_core.py +++ b/python/tests/unit/test_core.py @@ -27,7 +27,6 @@ ArgType, CLIOptions, Component, - ComponentSpec, Condition, ConditionType, Config, @@ -48,6 +47,7 @@ io_type_registry, py_object_to_arg, ) +from holoscan.core._core import ComponentSpec as ComponentSpecBase from holoscan.core._core import OperatorSpec as OperatorSpecBase from holoscan.core._core import ParameterFlag, PyOperatorSpec from holoscan.executors import GXFExecutor @@ -192,14 +192,14 @@ def test_dynamic_attribute_not_allowed(self): obj.custom_attribute = 5 -class TestComponentSpec: +class TestComponentSpecBase: def test_init(self, fragment): - c = ComponentSpec(fragment) + c = ComponentSpecBase(fragment) assert c.params == {} assert c.fragment is fragment def test_dynamic_attribute_not_allowed(self, fragment): - obj = ComponentSpec(fragment) + obj = ComponentSpecBase(fragment) with pytest.raises(AttributeError): obj.custom_attribute = 5 @@ -268,7 +268,7 @@ def test_initialize(self): c.initialize() def test_setup(self, fragment): - spec = ComponentSpec(fragment=fragment) + spec = ComponentSpecBase(fragment=fragment) c = Condition() c.setup(spec) @@ -280,55 +280,55 @@ def test_dynamic_attribute_not_allowed(self): class TestResource: def test_init(self, fragment): - r = Resource() + r = Resource(fragment) assert r.name == "" - assert r.fragment is None + assert r.fragment is fragment + assert r.resource_type == Resource.ResourceType.NATIVE - def test_init_with_kwargs(self): - r = Resource(a=5, b=(13.7, 15.2), c="abcd") + def test_init_with_kwargs(self, fragment): + r = Resource(fragment, a=5, b=(13.7, 15.2), c="abcd") assert r.name == "" - assert r.fragment is None + assert r.fragment is fragment assert len(r.args) == 3 - def test_init_with_name_and_kwargs(self): + def test_init_with_name_and_kwargs(self, fragment): # name provided by kwarg - r = Resource(name="r2", a=5, b=(13.7, 15.2), c="abcd") + r = Resource(fragment, name="r2", a=5, b=(13.7, 15.2), c="abcd") assert r.name == "r2" - assert r.fragment is None + assert r.fragment is fragment assert len(r.args) == 3 - def test_name(self): - r = Resource() + def test_name(self, fragment): + r = Resource(fragment) r.name = "res1" assert r.name == "res1" - r = Resource(name="res3") + r = Resource(fragment, name="res3") assert r.name == "res3" def test_fragment(self, fragment): - r = Resource() - assert r.fragment is None + r = Resource(fragment) + assert r.fragment is fragment # not allowed to assign fragment with pytest.raises(AttributeError): r.fragment = fragment - def test_add_arg(self): - r = Resource() + def test_add_arg(self, fragment): + r = Resource(fragment) r.add_arg(Arg("a1")) - def test_initialize(self): - r = Resource() + def test_initialize(self, fragment): + r = Resource(fragment) r.initialize() def test_setup(self, fragment): - spec = ComponentSpec(fragment=fragment) - r = Resource() + spec = ComponentSpecBase(fragment=fragment) + r = Resource(fragment) r.setup(spec) - def test_dynamic_attribute_not_allowed(self): - obj = Resource() - with pytest.raises(AttributeError): - obj.custom_attribute = 5 + def test_dynamic_attribute_allowed(self, fragment): + obj = Resource(fragment) + obj.custom_attribute = 5 class TestOperatorSpecBase: @@ -405,6 +405,61 @@ def test_input_connector_ucx(self, fragment, capfd, kwargs): assert iospec.io_type == IOSpec.IOType.INPUT assert isinstance(iospec.connector(), UcxReceiver) + def test_input_connector_and_condition(self, fragment, capfd): + c = OperatorSpecBase(fragment) + iospec = c.input("in").connector( + IOSpec.ConnectorType.DOUBLE_BUFFER, + capacity=5, + policy=1, + ) + b = iospec.condition( + ConditionType.EXPIRING_MESSAGE_AVAILABLE, + max_batch_size=5, + max_delay_n=1_000_000_000, + ) + + assert iospec == b + + assert isinstance(iospec, IOSpec) + assert iospec.name == "in" + assert iospec.io_type == IOSpec.IOType.INPUT + assert isinstance(iospec.connector(), DoubleBufferReceiver) + + assert len(iospec.conditions) == 1 + assert iospec.conditions[0][0] == ConditionType.EXPIRING_MESSAGE_AVAILABLE + assert iospec.conditions[0][1] is not None + + assert c.inputs["in"] == iospec + assert len(c.inputs["in"].conditions) == 1 + + def test_input_condition_and_connector(self, fragment, capfd): + c = OperatorSpecBase(fragment) + iospec = ( + c.input("in") + .condition( + ConditionType.EXPIRING_MESSAGE_AVAILABLE, + max_batch_size=5, + max_delay_n=1_000_000_000, + ) + .connector( + IOSpec.ConnectorType.DOUBLE_BUFFER, + capacity=5, + policy=1, + ) + ) + assert isinstance(iospec, IOSpec) + assert iospec.name == "in" + assert iospec.io_type == IOSpec.IOType.INPUT + assert isinstance(iospec.connector(), DoubleBufferReceiver) + + assert len(iospec.conditions) == 1 + assert iospec.conditions[0][0] == ConditionType.EXPIRING_MESSAGE_AVAILABLE + assert iospec.conditions[0][1] is not None + + assert c.inputs["in"] == iospec + + assert len(c.inputs["in"].conditions) == 1 + def test_output(self, fragment, capfd): c = OperatorSpecBase(fragment) iospec = c.output() diff --git a/python/tests/unit/test_decorator.py b/python/tests/unit/test_decorator.py new file mode 100644 index 00000000..ea2a0e3e --- /dev/null +++ b/python/tests/unit/test_decorator.py @@ -0,0 +1,346 @@ +""" + SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + SPDX-License-Identifier: Apache-2.0 + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +""" # noqa: E501 +import pytest + +from holoscan.core import Application, ConditionType, IOSpec, Operator +from holoscan.decorator import Input, Output, create_op +from holoscan.operators import PingRxOp, PingTxOp + + +class TestInput: + def test_input(self): + obj = Input("in") + assert obj.name == "in" + assert not obj.arg_map + + def test_input_string_arg_map(self): + obj = Input("in", arg_map="x") + assert obj.arg_map == "x" + + def test_input_dict_arg_map(self): + obj = Input("in", arg_map={"image": "x", "mask": "m"}) + assert isinstance(obj.arg_map, dict) + assert len(obj.arg_map.keys()) == 2 + + def test_create_input_with_condition(self): + app = Application() + op = PingRxOp(fragment=app, name="rx") + + # initially PingRxOp has one input port named "in" with a default connector + assert tuple(op.spec.inputs.keys()) == ("in",) + assert op.spec.inputs["in"].connector_type == IOSpec.ConnectorType.DEFAULT + + # add a new port with NONE condition via Input.create_input + obj = Input("in2", condition_type=ConditionType.NONE, condition_kwargs={}) + obj.create_input(op.spec) + in_spec = op.spec.inputs["in2"] + assert len(in_spec.conditions) == 1 + assert in_spec.conditions[0][0] == ConditionType.NONE + + # add a new port with MESSAGE_AVAILABLE condition via Input.create_input + obj = Input( + "in3", condition_type=ConditionType.MESSAGE_AVAILABLE, condition_kwargs=dict(min_size=2) + ) + obj.create_input(op.spec) + in_spec = op.spec.inputs["in3"] + assert len(in_spec.conditions) == 1 + cond_type, cond_obj = in_spec.conditions[0] + assert cond_type == ConditionType.MESSAGE_AVAILABLE + assert len(cond_obj.args) == 1 + assert cond_obj.args[0].name == "min_size" + assert "value: 2" in cond_obj.args[0].description + + def test_create_input_with_connector(self): + app = Application() + op = PingRxOp(fragment=app, name="rx") + + # initially PingRxOp has one input port named "in" with a default connector + assert tuple(op.spec.inputs.keys()) == ("in",) + assert op.spec.inputs["in"].connector_type == IOSpec.ConnectorType.DEFAULT + + obj = Input( + "in2", + connector_type=IOSpec.ConnectorType.DOUBLE_BUFFER, + connector_kwargs=dict(capacity=2, policy=1), + ) + obj.create_input(op.spec) + in_spec = op.spec.inputs["in2"] + assert in_spec.connector_type == IOSpec.ConnectorType.DOUBLE_BUFFER + connector = in_spec.connector() + assert len(connector.args) == 2 + assert connector.args[0].name == "capacity" + assert "value: 2" in connector.args[0].description + assert connector.args[1].name == "policy" + assert "value: 1" in connector.args[1].description + + +class TestOutput: + def test_output(self): + obj = Output("out") + assert obj.name == "out" + assert obj.tensor_names == () + + def test_output_tensor_names(self): + tensor_names = ("x", "waveform") + obj = Output("out", tensor_names=tensor_names) + assert obj.tensor_names == tensor_names + + def test_create_output_with_condition(self): + app = Application() + op = PingTxOp(fragment=app, name="rx") + + # initially PingTxOp has one output port named "out" with a default connector + assert tuple(op.spec.outputs.keys()) == ("out",) + assert op.spec.outputs["out"].connector_type == IOSpec.ConnectorType.DEFAULT + + # add a new port with NONE condition via Output.create_output + obj = Output("out2", condition_type=ConditionType.NONE, condition_kwargs={}) + obj.create_output(op.spec) + in_spec = op.spec.outputs["out2"] + assert len(in_spec.conditions) == 1 + assert in_spec.conditions[0][0] == ConditionType.NONE + + # add a new port with MESSAGE_AVAILABLE condition via Output.create_output + obj = Output( + "out3", + condition_type=ConditionType.DOWNSTREAM_MESSAGE_AFFORDABLE, + condition_kwargs=dict(min_size=2), + ) + obj.create_output(op.spec) + in_spec = op.spec.outputs["out3"] + assert len(in_spec.conditions) == 1 + cond_type, cond_obj = in_spec.conditions[0] + assert cond_type == ConditionType.DOWNSTREAM_MESSAGE_AFFORDABLE + assert len(cond_obj.args) == 1 + assert cond_obj.args[0].name == "min_size" + assert "value: 2" in cond_obj.args[0].description + + def test_create_output_with_connector(self): + app = Application() + op = PingTxOp(fragment=app, name="rx") + + # initially PingTxOp has one output port named "out" with a default connector + assert tuple(op.spec.outputs.keys()) == ("out",) + assert op.spec.outputs["out"].connector_type == IOSpec.ConnectorType.DEFAULT + + obj = Output( + "out2", + connector_type=IOSpec.ConnectorType.DOUBLE_BUFFER, + connector_kwargs=dict(capacity=2, policy=1), + ) + obj.create_output(op.spec) + in_spec = op.spec.outputs["out2"] + assert in_spec.connector_type == IOSpec.ConnectorType.DOUBLE_BUFFER + connector = in_spec.connector() + assert len(connector.args) == 2 + assert connector.args[0].name == "capacity" + assert "value: 2" in connector.args[0].description + assert connector.args[1].name == "policy" + assert "value: 1" in connector.args[1].description + + +class TestCreateOp: + def test_create_op_no_args_func(self): + @create_op() + def func_no_args(): + pass + + with pytest.raises(ValueError, match="fragment must be provided"): + func_no_args() + + # pass fragment positionally + app = Application() + my_op = func_no_args(app) + # __name__ will be a camelcase version of the function name + assert my_op.__name__ == "FuncNoArgsOp" + assert my_op.name == "func_no_args" + + # pass fragment and name via kwarg + my_op2 = func_no_args(fragment=app, name="my-op") + assert my_op2.__name__ == "FuncNoArgsOp" + assert my_op2.name == "my-op" + + def test_create_op_input_not_specified(self): + @create_op() + def func_one_positional_arg(image): + return image + + app = Application() + with pytest.raises(ValueError, match="required argument, 'image', has not been specified"): + func_one_positional_arg(app) + + @pytest.mark.parametrize( + "inputs", + [ + "image", + ("image",), + Input("image", arg_map="image"), + Input("image", arg_map={"tensor": "image"}), + (Input("image", arg_map={"tensor": "image"}),), + ], + ) + def test_create_op_inputs_specified(self, inputs): + @create_op(inputs=inputs) + def func_one_positional_arg(image): + return image + + # pass fragment positionally + app = Application() + my_op = func_one_positional_arg(app) + # __name__ will be a camelcase version of the function name + assert my_op.__name__ == "FuncOnePositionalArgOp" + assert my_op.name == "func_one_positional_arg" + assert "image" in my_op.dynamic_kwargs + assert "image" not in my_op.fixed_kwargs + + @pytest.mark.parametrize( + "inputs, exception_type, expected_error_message", + [ + ("tensor", KeyError, "Provided func does not have an arg or kwarg named 'tensor'"), + (("tensor",), KeyError, "Provided func does not have an arg or kwarg named 'tensor'"), + # image not in destinations for arg_map + ( + Input("image", arg_map=()), + ValueError, + "required argument, 'image', has not been specified", + ), + ( + Input("image", arg_map={"tensor": "tensor"}), + KeyError, + "Provided func does not have an arg or kwarg named 'tensor'", + ), + ( + (Input("image", arg_map={"tensor": "tensor"}),), + KeyError, + "Provided func does not have an arg or kwarg named 'tensor'", + ), + ], + ) + def test_create_op_invalid_input_name(self, inputs, exception_type, expected_error_message): + @create_op(inputs=inputs) + def func_one_positional_arg(image): + return image + + app = Application() + with pytest.raises(exception_type, match=expected_error_message): + func_one_positional_arg(app) + + @pytest.mark.parametrize("input_as_tuple", [False, True]) + def test_create_op_inputs_specified_via_input_obj(self, input_as_tuple): + port_name = "image_in" + inputs = Input(port_name, {"image": "image"}, condition_type=ConditionType.NONE) + if input_as_tuple: + inputs = (inputs,) + + @create_op(inputs=inputs) + def func_one_positional_arg(image): + return image + + # pass fragment positionally + app = Application() + my_op = func_one_positional_arg(app) + assert "image" in my_op.dynamic_kwargs + assert "image" not in my_op.fixed_kwargs + + cond_type, cond_obj = my_op.spec.inputs[port_name].conditions[0] + assert cond_obj is None + assert cond_type == ConditionType.NONE + + def test_create_op_inputs_keyword_only_arg(self): + @create_op(inputs="image", outputs="image") + def func_one_positional_arg(image, x=5, *, y=7): + return image + + # pass fragment positionally + app = Application() + my_op = func_one_positional_arg(app, y=12) + assert "image" in my_op.dynamic_kwargs + assert "x" in my_op.fixed_kwargs + assert my_op.fixed_kwargs["x"] == 5 + assert "y" in my_op.fixed_kwargs + assert my_op.fixed_kwargs["y"] == 12 + + def test_create_op_generator_func(self): + @create_op(inputs="image", outputs="image") + def int_generator(image, *, count=10): + yield from range(count) + + # pass fragment positionally + app = Application() + my_op = int_generator(app) + assert my_op.fixed_kwargs["count"] == 10 + + my_op = int_generator(app, count=1) + assert my_op.fixed_kwargs["count"] == 1 + + @pytest.mark.parametrize("explicit_inputs_and_outputs", [False, True]) + def test_create_op_from_class(self, explicit_inputs_and_outputs): + if explicit_inputs_and_outputs: + + @create_op(inputs="image", outputs="out") + class TensorGenerator: + def __init__(self, start_index=5): + self.counter = start_index - 1 + + def __call__(self, image, *, msg="hello"): + print(f"{msg}: {image.shape=}") + self.counter += 1 + return self.counter + else: + + @create_op + class TensorGenerator: + def __init__(self, start_index=5): + self.counter = start_index - 1 + + def __call__(self, image, *, msg="hello"): + print(f"{msg}: {image.shape=}") + self.counter += 1 + return self.counter + + # pass fragment positionally + app = Application() + start_index = 10 + my_op = TensorGenerator(start_index=start_index)(app, name="class_op") + + assert isinstance(my_op, Operator) + # verify input port name + inputs = my_op.spec.inputs + assert len(inputs) == 1 + assert inputs["image"].name == "image" + + # verify output port name + outputs = my_op.spec.outputs + assert len(outputs) == 1 + if explicit_inputs_and_outputs: + assert "out" in outputs + else: + assert "" in outputs + + # check internal state of the wrapped class + assert my_op.class_obj.counter == start_index - 1 + assert my_op.class_obj.__class__.__name__ == "TensorGenerator" + + # check names + assert my_op.name == "class_op" + assert my_op.__name__ == "TensorGeneratorOp" + + # verify kwargs based on __call__ function signature + assert len(my_op.dynamic_kwargs) == 1 + assert "image" in my_op.dynamic_kwargs + assert len(my_op.fixed_kwargs) == 1 + assert "msg" in my_op.fixed_kwargs diff --git a/python/tests/unit/test_gxf.py b/python/tests/unit/test_gxf.py index 9ff26490..5baa85c8 100644 --- a/python/tests/unit/test_gxf.py +++ b/python/tests/unit/test_gxf.py @@ -17,7 +17,9 @@ import pytest -from holoscan.core import Component, Condition, Resource, _Operator +from holoscan.core import Component, Condition +from holoscan.core import _Operator as OperatorBase +from holoscan.core import _Resource as ResourceBase from holoscan.gxf import ( Entity, GXFComponent, @@ -102,13 +104,13 @@ class TestGXFResource(TestGXFComponent): def test_type(self): r = GXFResource() assert isinstance(r, Component) - assert isinstance(r, Resource) + assert isinstance(r, ResourceBase) assert isinstance(r, GXFComponent) - def test_dynamic_attribute_not_allowed(self): + def test_dynamic_attribute_allowed(self): + # parent Resource class allows dynamic attributes obj = GXFResource() - with pytest.raises(AttributeError): - obj.custom_attribute = 5 + obj.custom_attribute = 5 class TestGXFInputContext: @@ -166,7 +168,7 @@ def test_eid(self): def test_type(self): op = GXFOperator() - assert isinstance(op, _Operator) + assert isinstance(op, OperatorBase) def test_dynamic_attribute_allowed(self): obj = GXFOperator() diff --git a/python/tests/unit/test_network_context.py b/python/tests/unit/test_network_context.py index 24d74c8a..ec6f01e6 100644 --- a/python/tests/unit/test_network_context.py +++ b/python/tests/unit/test_network_context.py @@ -15,7 +15,8 @@ limitations under the License. """ # noqa: E501 -from holoscan.core import ComponentSpec, NetworkContext +from holoscan.core import NetworkContext +from holoscan.core._core import ComponentSpec as ComponentSpecBase from holoscan.gxf import GXFNetworkContext from holoscan.network_contexts import UcxContext from holoscan.resources import UcxEntitySerializer @@ -26,9 +27,7 @@ def test_default_init(self, app): e = UcxContext(app) assert isinstance(e, GXFNetworkContext) assert isinstance(e, NetworkContext) - # The 'e.spec' is from the binder (ComponentSpec), and 'ComponentSpec' actually - # derives from PyComponentSpec, which inherits from ComponentSpec. - assert issubclass(ComponentSpec, type(e.spec)) + assert issubclass(ComponentSpecBase, type(e.spec)) def test_init_kwargs(self, app): entity_serializer = UcxEntitySerializer( diff --git a/python/tests/unit/test_operators_native.py b/python/tests/unit/test_operators_native.py index 7edaf00e..239fdcc4 100644 --- a/python/tests/unit/test_operators_native.py +++ b/python/tests/unit/test_operators_native.py @@ -359,6 +359,29 @@ def test_kwarg_based_initialization(self, app, config_file, capfd): assert "error" not in captured.err assert "warning" not in captured.err + def test_channel_kwarg_string_variant(self, app, config_file, capfd): + app.config(config_file) + name = "source" + op = AJASourceOp( + fragment=app, + name=name, + channel="NTV2_CHANNEL1", + width=1920, + height=1080, + rdma=True, + enable_overlay=False, + overlay_channel="NTV2_CHANNEL2", + overlay_rdma=True, + ) + assert isinstance(op, _Operator) + assert op.operator_type == Operator.OperatorType.NATIVE + assert f"name: {name}" in repr(op) + + # assert no warnings or errors logged + captured = capfd.readouterr() + assert "error" not in captured.err + assert "warning" not in captured.err + def test_initialization_from_yaml(self, app, config_file, capfd): app.config(config_file) name = "source" diff --git a/python/tests/unit/test_resources.py b/python/tests/unit/test_resources.py index 2efd0ad5..7215c755 100644 --- a/python/tests/unit/test_resources.py +++ b/python/tests/unit/test_resources.py @@ -15,8 +15,10 @@ limitations under the License. """ # noqa: E501 -from holoscan.core import Resource +from holoscan.core import ComponentSpec, Resource +from holoscan.core import _Resource as ResourceBase from holoscan.gxf import GXFResource +from holoscan.operators import PingTxOp from holoscan.resources import ( Allocator, BlockMemoryPool, @@ -54,7 +56,7 @@ def test_kwarg_based_initialization(self, app, capfd): ) assert isinstance(pool, Allocator) assert isinstance(pool, GXFResource) - assert isinstance(pool, Resource) + assert isinstance(pool, ResourceBase) assert pool.id == -1 assert pool.gxf_typename == "nvidia::gxf::BlockMemoryPool" @@ -74,7 +76,7 @@ def test_default_initialization(self, app, capfd): pool = CudaStreamPool(fragment=app, name=name) assert isinstance(pool, Allocator) assert isinstance(pool, GXFResource) - assert isinstance(pool, Resource) + assert isinstance(pool, ResourceBase) assert pool.id == -1 assert pool.gxf_typename == "nvidia::gxf::CudaStreamPool" assert f"name: {name}" in repr(pool) @@ -96,7 +98,7 @@ def test_kwarg_based_initialization(self, app, capfd): ) assert isinstance(pool, Allocator) assert isinstance(pool, GXFResource) - assert isinstance(pool, Resource) + assert isinstance(pool, ResourceBase) assert pool.id == -1 assert pool.gxf_typename == "nvidia::gxf::CudaStreamPool" assert f"name: {name}" in repr(pool) @@ -118,7 +120,7 @@ def test_kwarg_based_initialization(self, app, capfd): ) assert isinstance(alloc, Allocator) assert isinstance(alloc, GXFResource) - assert isinstance(alloc, Resource) + assert isinstance(alloc, ResourceBase) assert alloc.id == -1 assert alloc.gxf_typename == "nvidia::gxf::UnboundedAllocator" assert f"name: {name}" in repr(alloc) @@ -143,15 +145,18 @@ def test_kwarg_based_initialization(self, app, capfd): ) assert isinstance(r, Receiver) assert isinstance(r, GXFResource) - assert isinstance(r, Resource) + assert isinstance(r, ResourceBase) assert r.id == -1 assert r.gxf_typename == "nvidia::gxf::DoubleBufferReceiver" + r.initialize() # manually initialize so we can check resource_type + assert r.resource_type == Resource.ResourceType.GXF assert f"name: {name}" in repr(r) - # assert no warnings or errors logged + # assert no unexpected warnings or errors logged captured = capfd.readouterr() assert "error" not in captured.err - assert "warning" not in captured.err + # expect one warning due to manually calling initialize() above + assert captured.err.count("warning") < 2 def test_default_initialization(self, app): DoubleBufferReceiver(app) @@ -168,15 +173,18 @@ def test_kwarg_based_initialization(self, app, capfd): ) assert isinstance(r, Transmitter) assert isinstance(r, GXFResource) - assert isinstance(r, Resource) + assert isinstance(r, ResourceBase) assert r.id == -1 assert r.gxf_typename == "nvidia::gxf::DoubleBufferTransmitter" + r.initialize() # manually initialize so we can check resource_type + assert r.resource_type == Resource.ResourceType.GXF assert f"name: {name}" in repr(r) - # assert no warnings or errors logged + # assert no unexpected warnings or errors logged captured = capfd.readouterr() assert "error" not in captured.err - assert "warning" not in captured.err + # expect one warning due to manually calling initialize() above + assert captured.err.count("warning") < 2 def test_default_initialization(self, app): DoubleBufferTransmitter(app) @@ -190,7 +198,7 @@ def test_kwarg_based_initialization(self, app, capfd): name=name, ) assert isinstance(r, GXFResource) - assert isinstance(r, Resource) + assert isinstance(r, ResourceBase) assert r.id == -1 assert r.gxf_typename == "nvidia::gxf::StdComponentSerializer" assert f"name: {name}" in repr(r) @@ -212,7 +220,7 @@ def test_kwarg_based_initialization(self, app, capfd): name=name, ) assert isinstance(r, GXFResource) - assert isinstance(r, Resource) + assert isinstance(r, ResourceBase) assert r.id == -1 assert r.gxf_typename == "nvidia::gxf::StdEntitySerializer" assert f"name: {name}" in repr(r) @@ -236,7 +244,7 @@ def test_kwarg_based_initialization(self, app, capfd): ) assert isinstance(clk, Clock) assert isinstance(clk, GXFResource) - assert isinstance(clk, Resource) + assert isinstance(clk, ResourceBase) assert clk.id == -1 assert clk.gxf_typename == "nvidia::gxf::ManualClock" assert f"name: {name}" in repr(clk) @@ -262,7 +270,7 @@ def test_kwarg_based_initialization(self, app, capfd): ) assert isinstance(clk, Clock) assert isinstance(clk, GXFResource) - assert isinstance(clk, Resource) + assert isinstance(clk, ResourceBase) assert clk.id == -1 assert clk.gxf_typename == "nvidia::gxf::RealtimeClock" assert f"name: {name}" in repr(clk) @@ -286,7 +294,7 @@ def test_kwarg_based_initialization(self, app, capfd): name=name, ) assert isinstance(res, GXFResource) - assert isinstance(res, Resource) + assert isinstance(res, ResourceBase) assert res.id == -1 # -1 because initialize() isn't called assert res.gxf_typename == "nvidia::gxf::SerializationBuffer" assert f"name: {name}" in repr(res) @@ -307,7 +315,7 @@ def test_kwarg_based_initialization(self, app, capfd): name=name, ) assert isinstance(res, GXFResource) - assert isinstance(res, Resource) + assert isinstance(res, ResourceBase) assert res.id == -1 assert res.gxf_typename == "nvidia::gxf::UcxSerializationBuffer" assert f"name: {name}" in repr(res) @@ -327,7 +335,7 @@ def test_kwarg_based_initialization(self, app, capfd): name=name, ) assert isinstance(res, GXFResource) - assert isinstance(res, Resource) + assert isinstance(res, ResourceBase) assert res.id == -1 assert res.gxf_typename == "nvidia::gxf::UcxComponentSerializer" assert f"name: {name}" in repr(res) @@ -347,7 +355,7 @@ def test_kwarg_based_initialization(self, app, capfd): name=name, ) assert isinstance(res, GXFResource) - assert isinstance(res, Resource) + assert isinstance(res, ResourceBase) assert res.id == -1 assert res.gxf_typename == "nvidia::gxf::UcxHoloscanComponentSerializer" assert f"name: {name}" in repr(res) @@ -367,7 +375,7 @@ def test_intialization_default_serializers(self, app, capfd): name=name, ) assert isinstance(res, GXFResource) - assert isinstance(res, Resource) + assert isinstance(res, ResourceBase) assert res.id == -1 assert res.gxf_typename == "nvidia::gxf::UcxEntitySerializer" assert f"name: {name}" in repr(res) @@ -397,7 +405,7 @@ def test_kwarg_based_initialization(self, app, capfd): name=name, ) assert isinstance(res, GXFResource) - assert isinstance(res, Resource) + assert isinstance(res, ResourceBase) assert isinstance(res, Receiver) assert res.id == -1 assert res.gxf_typename == "nvidia::gxf::UcxReceiver" @@ -431,7 +439,7 @@ def test_kwarg_based_initialization(self, app, capfd): name=name, ) assert isinstance(res, GXFResource) - assert isinstance(res, Resource) + assert isinstance(res, ResourceBase) assert isinstance(res, Transmitter) assert res.id == -1 assert res.gxf_typename == "nvidia::gxf::UcxTransmitter" @@ -441,3 +449,31 @@ def test_kwarg_based_initialization(self, app, capfd): captured = capfd.readouterr() assert "error" not in captured.err assert "warning" not in captured.err + + +class DummyNativeResource(Resource): + def __init__(self, fragment, *args, **kwargs): + super().__init__(fragment, *args, **kwargs) + + def setup(self, spec: ComponentSpec): + pass + + +class TestNativeResource: + def test_native_resource_to_operator(self, app): + """Tests passing a native resource as a positional argument to an operator.""" + tx = PingTxOp( + app, + DummyNativeResource(fragment=app, name="native_resource"), + name="tx", + ) + tx.initialize() + + # verify that the resource is included in the operator's description + resource_repr = """ +resources: + - id: -1 + name: native_resource +""" + assert resource_repr in tx.__repr__() + assert resource_repr in tx.description diff --git a/python/tests/unit/test_schedulers.py b/python/tests/unit/test_schedulers.py index 0981b33b..2c62376b 100644 --- a/python/tests/unit/test_schedulers.py +++ b/python/tests/unit/test_schedulers.py @@ -17,7 +17,8 @@ import pytest -from holoscan.core import ComponentSpec, Scheduler +from holoscan.core import Scheduler +from holoscan.core._core import ComponentSpec as ComponentSpecBase from holoscan.gxf import GXFScheduler from holoscan.resources import ManualClock, RealtimeClock from holoscan.schedulers import EventBasedScheduler, GreedyScheduler, MultiThreadScheduler @@ -28,9 +29,7 @@ def test_default_init(self, app): scheduler = GreedyScheduler(app) assert isinstance(scheduler, GXFScheduler) assert isinstance(scheduler, Scheduler) - # The 'scheduler.spec' is from the binder (ComponentSpec), and 'ComponentSpec' actually - # derives from PyComponentSpec, which inherits from ComponentSpec. - assert issubclass(ComponentSpec, type(scheduler.spec)) + assert issubclass(ComponentSpecBase, type(scheduler.spec)) @pytest.mark.parametrize("ClockClass", [ManualClock, RealtimeClock]) def test_init_kwargs(self, app, ClockClass): # noqa: N803 @@ -83,9 +82,7 @@ def test_default_init(self, app): scheduler = MultiThreadScheduler(app) assert isinstance(scheduler, GXFScheduler) assert isinstance(scheduler, Scheduler) - # The 'scheduler.spec' is from the binder (ComponentSpec), and 'ComponentSpec' actually - # derives from PyComponentSpec, which inherits from ComponentSpec. - assert issubclass(ComponentSpec, type(scheduler.spec)) + assert issubclass(ComponentSpecBase, type(scheduler.spec)) @pytest.mark.parametrize("ClockClass", [ManualClock, RealtimeClock]) def test_init_kwargs(self, app, ClockClass): # noqa: N803 @@ -146,9 +143,7 @@ def test_default_init(self, app): scheduler = EventBasedScheduler(app) assert isinstance(scheduler, GXFScheduler) assert isinstance(scheduler, Scheduler) - # The 'scheduler.spec' is from the binder (ComponentSpec), and 'ComponentSpec' actually - # derives from PyComponentSpec, which inherits from ComponentSpec. - assert issubclass(ComponentSpec, type(scheduler.spec)) + assert issubclass(ComponentSpecBase, type(scheduler.spec)) @pytest.mark.parametrize("ClockClass", [ManualClock, RealtimeClock]) def test_init_kwargs(self, app, ClockClass): # noqa: N803 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 030191e4..ef74fc47 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -129,6 +129,7 @@ add_holoscan_library(core core/conditions/gxf/downstream_affordable.cpp core/conditions/gxf/periodic.cpp core/conditions/gxf/message_available.cpp + core/conditions/gxf/expiring_message.cpp core/config.cpp core/dataflow_tracker.cpp core/domain/tensor.cpp diff --git a/src/common/logger/spdlog_logger.cpp b/src/common/logger/spdlog_logger.cpp index 9f34526d..419d63f9 100644 --- a/src/common/logger/spdlog_logger.cpp +++ b/src/common/logger/spdlog_logger.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include namespace spdlog { @@ -40,13 +41,13 @@ class ansicolor_file_sink : public ansicolor_sink { } // namespace sinks -static inline std::shared_ptr create_file_logger(std::string name, FILE* file) { +static inline std::shared_ptr create_file_logger(const std::string name, FILE* file) { // Do not register to spdlog registry spdlog::details::registry::instance().set_automatic_registration(false); return spdlog::synchronous_factory::template create< spdlog::sinks::ansicolor_file_sink>( - name, file, spdlog::color_mode::automatic); + std::move(name), file, spdlog::color_mode::automatic); } } // namespace spdlog diff --git a/src/core/app_driver.cpp b/src/core/app_driver.cpp index b8353228..cdff6bec 100644 --- a/src/core/app_driver.cpp +++ b/src/core/app_driver.cpp @@ -255,8 +255,8 @@ void AppDriver::run() { HOLOSCAN_LOG_ERROR("Send interrupt once more to terminate immediately"); SignalHandler::unregister_signal_handler(context, signum); // Register the global signal handler. - SignalHandler::register_global_signal_handler(signum, [](int signum) { - (void)signum; + SignalHandler::register_global_signal_handler(signum, [](int sig) { + (void)sig; HOLOSCAN_LOG_ERROR("Interrupted by user (global signal handler)"); exit(1); }); @@ -271,13 +271,13 @@ void AppDriver::run() { app_status_ = AppStatus::kError; // Stop the driver server - driver_server_->stop(); + if (driver_server_) { driver_server_->stop(); } // Do not wait for the driver server to stop because it will block the main thread }; SignalHandler::register_signal_handler(app_->executor().context(), SIGINT, sig_handler); SignalHandler::register_signal_handler(app_->executor().context(), SIGTERM, sig_handler); } - driver_server_->wait(); + if (driver_server_) { driver_server_->wait(); } } } @@ -963,11 +963,11 @@ void AppDriver::check_fragment_schedule(const std::string& worker_address) { std::unordered_set not_participated_workers(worker_addresses.begin(), worker_addresses.end()); for (auto& [fragment_name, worker_id] : schedule) { not_participated_workers.erase(worker_id); } - for (const auto& worker_address : not_participated_workers) { - HOLOSCAN_LOG_INFO("{}' does not participate in the schedule", worker_address); - auto& worker_client = driver_server_->connect_to_worker(worker_address); + for (const auto& worker_addr : not_participated_workers) { + HOLOSCAN_LOG_INFO("{}' does not participate in the schedule", worker_addr); + auto& worker_client = driver_server_->connect_to_worker(worker_addr); worker_client->terminate_worker(AppWorkerTerminationCode::kCancelled); - driver_server_->close_worker_connection(worker_address); + driver_server_->close_worker_connection(worker_addr); } auto& fragment_graph = app_->fragment_graph(); @@ -984,6 +984,7 @@ void AppDriver::check_fragment_schedule(const std::string& worker_address) { } // collect port information from each worker (must be before the collect_connections call) + bool is_port_info_collected = true; for (const auto& [worker_id, fragment_names] : id_to_fragment_names_vector) { auto& worker_client = driver_server_->connect_to_worker(worker_id); @@ -995,12 +996,25 @@ void AppDriver::check_fragment_schedule(const std::string& worker_address) { HOLOSCAN_LOG_ERROR( "Failed to retrieve port info for all fragments scheduled on worker with id '{}'", worker_id); + is_port_info_collected = false; break; } } // Merge the collected port info into the app driver's port information map all_fragment_port_map_->merge(scheduled_fragments_port_info); } + if (!is_port_info_collected) { + HOLOSCAN_LOG_ERROR("Unable to collect port information from workers"); + // Terminate all worker and close all worker connections + terminate_all_workers(AppWorkerTerminationCode::kFailure); + + // Set app status to error + app_status_ = AppStatus::kError; + + // Stop the driver server + driver_server_->stop(); + return; + } // (populates index_to_port_map_, index_to_ip_map_, connection_map_, receiver_port_map_) if (!collect_connections(fragment_graph)) { HOLOSCAN_LOG_ERROR("Cannot collect connections"); } diff --git a/src/core/app_worker.cpp b/src/core/app_worker.cpp index 987e46b3..f70e7747 100644 --- a/src/core/app_worker.cpp +++ b/src/core/app_worker.cpp @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -106,7 +106,19 @@ bool AppWorker::execute_fragments( } // Compose scheduled fragments - for (auto& fragment : scheduled_fragments) { fragment->compose_graph(); } + for (auto& fragment : scheduled_fragments) { + try { + fragment->compose_graph(); + } catch (const std::exception& exception) { + HOLOSCAN_LOG_ERROR( + "Failed to compose fragment graph '{}': {}", fragment->name(), exception.what()); + // Notify the worker server that the worker execution is finished with failure + termination_code_ = AppWorkerTerminationCode::kFailure; + submit_message( + WorkerMessage{AppWorker::WorkerMessageCode::kNotifyWorkerExecutionFinished, {}}); + return false; + } + } // Add the UCX network context for (auto& fragment : scheduled_fragments) { diff --git a/src/core/application.cpp b/src/core/application.cpp index cbfd16bf..7d2f01ad 100644 --- a/src/core/application.cpp +++ b/src/core/application.cpp @@ -330,8 +330,13 @@ void Application::compose_graph() { HOLOSCAN_LOG_DEBUG("The application({}) has already been composed. Skipping...", name()); return; } - is_composed_ = true; + + // Load extensions from the config file before composing the graph. + // (The GXFCodeletOp and GXFComponentResource classes are required to access the underlying GXF + // types in the setup() method when composing a graph.) + load_extensions_from_config(); compose(); + is_composed_ = true; } void Application::set_scheduler_for_fragments(std::vector& target_fragments) { diff --git a/src/core/cli_parser.cpp b/src/core/cli_parser.cpp index 3422d236..3e628a6a 100644 --- a/src/core/cli_parser.cpp +++ b/src/core/cli_parser.cpp @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,6 +20,7 @@ #include #include #include +#include #include #include "CLI/Config.hpp" @@ -30,7 +31,7 @@ namespace holoscan { void CLIParser::initialize(std::string app_description, std::string app_version) { // Set the application description and version. - app_.description(app_description); + app_.description(std::move(app_description)); app_.set_version_flag("--version", app_version, "Show the version of the application."); if (!is_initialized_) { diff --git a/src/core/condition.cpp b/src/core/condition.cpp index 9d47d5b7..8dfc147a 100644 --- a/src/core/condition.cpp +++ b/src/core/condition.cpp @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: Copyright (c) 2022-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,7 +17,10 @@ #include "holoscan/core/condition.hpp" +#include +#include #include "holoscan/core/component_spec.hpp" +#include "holoscan/core/resource.hpp" namespace holoscan { @@ -31,4 +34,26 @@ YAML::Node Condition::to_yaml_node() const { return node; } +void Condition::add_arg(const std::shared_ptr& arg) { + if (resources_.find(arg->name()) != resources_.end()) { + HOLOSCAN_LOG_ERROR( + "Resource '{}' already exists in the condition. Please specify a unique " + "name when creating a Resource instance.", + arg->name()); + } else { + resources_[arg->name()] = arg; + } +} + +void Condition::Condition::add_arg(std::shared_ptr&& arg) { + if (resources_.find(arg->name()) != resources_.end()) { + HOLOSCAN_LOG_ERROR( + "Resource '{}' already exists in the condition. Please specify a unique " + "name when creating a Resource instance.", + arg->name()); + } else { + resources_[arg->name()] = std::move(arg); + } +} + } // namespace holoscan diff --git a/src/core/conditions/gxf/asynchronous.cpp b/src/core/conditions/gxf/asynchronous.cpp index 61d65802..07b19dff 100644 --- a/src/core/conditions/gxf/asynchronous.cpp +++ b/src/core/conditions/gxf/asynchronous.cpp @@ -25,13 +25,7 @@ namespace holoscan { AsynchronousCondition::AsynchronousCondition(const std::string& name, nvidia::gxf::AsynchronousSchedulingTerm* term) - : GXFCondition(name, term) { - if (term) { - // no parameters to configure for this condition type - } else { - HOLOSCAN_LOG_ERROR("AsynchronousCondition: term is null"); - } -} + : GXFCondition(name, term) {} nvidia::gxf::AsynchronousSchedulingTerm* AsynchronousCondition::get() const { return static_cast(gxf_cptr_); diff --git a/src/core/conditions/gxf/expiring_message.cpp b/src/core/conditions/gxf/expiring_message.cpp new file mode 100644 index 00000000..b63fe9ef --- /dev/null +++ b/src/core/conditions/gxf/expiring_message.cpp @@ -0,0 +1,96 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "holoscan/core/conditions/gxf/expiring_message.hpp" +#include "holoscan/core/component_spec.hpp" +#include "holoscan/core/fragment.hpp" + +namespace holoscan { + +void ExpiringMessageAvailableCondition::setup(ComponentSpec& spec) { + spec.param(receiver_, + "receiver", + "Queue channel", + "The scheduling term permits execution if this channel has at least a given number of " + "messages available."); + spec.param(clock_, "clock", "Clock", "The clock to be used to get the time from."); + spec.param(max_batch_size_, + "max_batch_size", + "Maximum Batch Size", + "The maximum number of messages to be batched together"); + spec.param(max_delay_ns_, + "max_delay_ns", + "Maximum delay in nano seconds.", + "The maximum delay from first message to wait before submitting workload"); +} + +nvidia::gxf::ExpiringMessageAvailableSchedulingTerm* ExpiringMessageAvailableCondition::get() + const { + return static_cast(gxf_cptr_); +} + +void ExpiringMessageAvailableCondition::initialize() { + // Set up prerequisite parameters before calling Scheduler::initialize() + auto frag = fragment(); + + // Find if there is an argument for 'clock' + auto has_clock = std::find_if( + args().begin(), args().end(), [](const auto& arg) { return (arg.name() == "clock"); }); + // Create the clock if there was no argument provided. + if (has_clock == args().end()) { + clock_ = frag->make_resource("expiring_message__realtime_clock"); + clock_->gxf_cname(clock_->name().c_str()); + if (gxf_eid_ != 0) { clock_->gxf_eid(gxf_eid_); } + add_arg(clock_.get()); + } + + // parent class initialize() call must be after the argument additions above + GXFCondition::initialize(); +} + +void ExpiringMessageAvailableCondition::max_batch_size(int64_t max_batch_size) { + auto expiring_message = get(); + if (expiring_message) { + // expiring_message->setMaxBatchSize(max_batch_size); + GxfParameterSetInt64(gxf_context_, gxf_cid_, "max_batch_size", max_batch_size); + } + max_batch_size_ = max_batch_size; +} + +void ExpiringMessageAvailableCondition::max_delay(int64_t max_delay_ns) { + auto expiring_message = get(); + + if (expiring_message) { + HOLOSCAN_LOG_INFO("Setting max delay to {}", max_delay_ns); + // expiring_message->setMaxDelayNs(max_delay_ns); + GxfParameterSetInt64(gxf_context_, gxf_cid_, "max_delay_ns", max_delay_ns); + } + max_delay_ns_ = max_delay_ns; +} + +int64_t ExpiringMessageAvailableCondition::max_delay_ns() { + auto expiring_message = get(); + if (expiring_message) { + int64_t max_delay_ns = 0; + // int64_t max_delay_ns = expiring_message->maxDelayNs(); + GxfParameterGetInt64(gxf_context_, gxf_cid_, "max_delay_ns", &max_delay_ns); + if (max_delay_ns != max_delay_ns_) { max_delay_ns_ = max_delay_ns; } + } + return max_delay_ns_; +} + +} // namespace holoscan diff --git a/src/core/dataflow_tracker.cpp b/src/core/dataflow_tracker.cpp index 6840e4bd..a617f786 100644 --- a/src/core/dataflow_tracker.cpp +++ b/src/core/dataflow_tracker.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include "holoscan/core/dataflow_tracker.hpp" @@ -43,7 +44,7 @@ void DataFlowTracker::end_logging() { if (!logger_ofstream_.is_open()) return; // Write out the remaining messages from the log buffer and close ofstream - for (auto it : buffered_messages_) { logger_ofstream_ << it << "\n"; } + for (const auto& it : buffered_messages_) { logger_ofstream_ << it << "\n"; } logger_ofstream_.close(); } @@ -51,9 +52,9 @@ void DataFlowTracker::print() const { std::cout << "Data Flow Tracking Results:\n"; std::cout << "Total paths: " << all_path_metrics_.size() << "\n\n"; int i = 0; - for (auto it : all_path_metrics_) { + for (const auto& it : all_path_metrics_) { std::cout << "Path " << ++i << ": " << it.first << "\n"; - for (auto it2 : it.second->metrics) { + for (const auto& it2 : it.second->metrics) { std::cout << metricToString.at(it2.first) << ": " << it2.second << "\n"; } std::cout << "\n"; @@ -61,7 +62,7 @@ void DataFlowTracker::print() const { std::cout << "Number of source messages [format: source operator->transmitter name: number of " "messages]:\n"; - for (auto it : source_messages_) { std::cout << it.first << ": " << it.second << "\n"; } + for (const auto& it : source_messages_) { std::cout << it.first << ": " << it.second << "\n"; } std::cout.flush(); // flush standard output; otherwise output may not be printed } @@ -153,7 +154,7 @@ int DataFlowTracker::get_num_paths() { std::vector DataFlowTracker::get_path_strings() { std::vector all_pathstrings; all_pathstrings.reserve(all_path_metrics_.size()); - for (auto it : all_path_metrics_) { all_pathstrings.push_back(it.first); } + for (const auto& it : all_path_metrics_) { all_pathstrings.push_back(it.first); } return all_pathstrings; } @@ -185,7 +186,8 @@ void DataFlowTracker::set_skip_latencies(int threshold) { void DataFlowTracker::enable_logging(std::string filename, uint64_t num_buffered_messages) { is_file_logging_enabled_ = true; this->num_buffered_messages_ = num_buffered_messages; - logger_filename_ = filename; + logger_filename_ = std::move(filename); + std::scoped_lock lock(buffered_messages_mutex_); buffered_messages_.reserve(this->num_buffered_messages_); logfile_messages_ = 0; } @@ -193,18 +195,17 @@ void DataFlowTracker::enable_logging(std::string filename, uint64_t num_buffered void DataFlowTracker::write_to_logfile(std::string text) { if (!text.empty() && is_file_logging_enabled_) { if (!logger_ofstream_.is_open()) { logger_ofstream_.open(logger_filename_); } - buffered_messages_mutex_.lock(); + std::scoped_lock lock(buffered_messages_mutex_); buffered_messages_.push_back(std::to_string(++logfile_messages_) + ":\n" + text); // When the vector's size is equal to buffered number of messages, // flush out the buffer to file // and clear the vector to re-reserve the memory if (buffered_messages_.size() == num_buffered_messages_) { - for (auto it : buffered_messages_) { logger_ofstream_ << it << "\n"; } + for (const auto& it : buffered_messages_) { logger_ofstream_ << it << "\n"; } logger_ofstream_ << std::flush; buffered_messages_.clear(); buffered_messages_.reserve(num_buffered_messages_); } - buffered_messages_mutex_.unlock(); } } diff --git a/src/core/executors/gxf/gxf_executor.cpp b/src/core/executors/gxf/gxf_executor.cpp index a7f6fffb..e9099f53 100644 --- a/src/core/executors/gxf/gxf_executor.cpp +++ b/src/core/executors/gxf/gxf_executor.cpp @@ -40,6 +40,7 @@ #include "holoscan/core/condition.hpp" #include "holoscan/core/conditions/gxf/downstream_affordable.hpp" #include "holoscan/core/conditions/gxf/message_available.hpp" +#include "holoscan/core/conditions/gxf/expiring_message.hpp" #include "holoscan/core/config.hpp" #include "holoscan/core/domain/tensor.hpp" #include "holoscan/core/errors.hpp" @@ -249,7 +250,7 @@ GXFExecutor::GXFExecutor(holoscan::Fragment* fragment, bool create_gxf_context) HOLOSCAN_GXF_CALL_FATAL(GxfContextCreate(&context_)); // } own_gxf_context_ = true; - gxf_extension_manager_ = std::make_shared(context_); + extension_manager_ = std::make_shared(context_); // Register extensions for holoscan (GXFWrapper codelet) register_extensions(); @@ -273,12 +274,22 @@ GXFExecutor::~GXFExecutor() { if (own_gxf_context_) { auto frag_name_display = fragment_->name(); if (!frag_name_display.empty()) { frag_name_display = "[" + frag_name_display + "] "; } - HOLOSCAN_LOG_INFO("{}Destroying context", frag_name_display); + try { + HOLOSCAN_LOG_INFO("{}Destroying context", frag_name_display); + } catch (const std::exception& e) {} // Unregister signal handlers if any - SignalHandler::unregister_signal_handler(context_, SIGINT); - SignalHandler::unregister_signal_handler(context_, SIGTERM); - HOLOSCAN_GXF_CALL(GxfContextDestroy(context_)); + try { + SignalHandler::unregister_signal_handler(context_, SIGINT); + SignalHandler::unregister_signal_handler(context_, SIGTERM); + } catch (const std::exception& e) { + try { + HOLOSCAN_LOG_ERROR("Failed to unregister signal handlers: {}", e.what()); + } catch (const std::exception& e) {} + } + try { + HOLOSCAN_GXF_CALL(GxfContextDestroy(context_)); + } catch (const std::exception& e) {} } // Delete GXF Holoscan Extension @@ -310,10 +321,11 @@ void GXFExecutor::initialize_gxf_resources( void GXFExecutor::add_operator_to_entity_group(gxf_context_t context, gxf_uid_t entity_group_gid, std::shared_ptr op) { auto graph_entity = op->graph_entity(); - gxf_uid_t op_eid = graph_entity->eid(); if (!graph_entity) { HOLOSCAN_LOG_ERROR("null GraphEntity found during add_operator_to_entity_group"); + return; } + gxf_uid_t op_eid = graph_entity->eid(); HOLOSCAN_LOG_DEBUG("Adding operator eid '{}' to entity group '{}'", op_eid, entity_group_gid); HOLOSCAN_GXF_CALL_FATAL(GxfUpdateEntityGroup(context, entity_group_gid, op_eid)); } @@ -348,11 +360,11 @@ void GXFExecutor::interrupt() { void GXFExecutor::context(void* context) { context_ = context; - gxf_extension_manager_ = std::make_shared(context_); + extension_manager_ = std::make_shared(context_); } std::shared_ptr GXFExecutor::extension_manager() { - return gxf_extension_manager_; + return extension_manager_; } namespace { @@ -580,6 +592,22 @@ void GXFExecutor::create_input_port(Fragment* fragment, gxf_context_t gxf_contex message_available_condition->add_to_graph_entity(op); break; } + case ConditionType::kExpiringMessageAvailable: { + std::shared_ptr expiring_message_available_condition = + std::dynamic_pointer_cast(condition); + // Note: GraphEntity::addSchedulingTerm requires a unique name here + std::string cond_name = + fmt::format("__{}_{}_cond_{}", op->name(), rx_name, condition_index); + expiring_message_available_condition->receiver(connector); + expiring_message_available_condition->name(cond_name); + expiring_message_available_condition->fragment(fragment); + auto rx_condition_spec = std::make_shared(fragment); + expiring_message_available_condition->setup(*rx_condition_spec); + expiring_message_available_condition->spec(std::move(rx_condition_spec)); + // Add to the same entity as the operator and initialize + expiring_message_available_condition->add_to_graph_entity(op); + break; + } case ConditionType::kNone: // No condition break; @@ -866,7 +894,7 @@ void create_virtual_operators_and_connections( std::string source_address_str(source_address); auto [ip, _] = holoscan::CLIOptions::parse_address(source_address_str, "0.0.0.0", "0"); // Convert port string 'port' to int32_t. - source_ip = ip; + source_ip = std::move(ip); } for (auto& [op, port_map] : connection_map) { @@ -1052,7 +1080,6 @@ void GXFExecutor::connect_broadcast_to_previous_op( // Create a transmitter based on the prev_connector_type. switch (prev_connector_type) { - case IOSpec::ConnectorType::kDefault: case IOSpec::ConnectorType::kDoubleBuffer: { // We don't create a AnnotatedDoubleBufferTransmitter even if DFFT is on because // we don't want to annotate a message at the Broadcast component. @@ -1685,17 +1712,6 @@ bool GXFExecutor::initialize_gxf_graph(OperatorGraph& graph) { // multiple threads are setting up the graph. static std::mutex gxf_execution_mutex; - // Load extensions from config file only if not already loaded, - // to avoid unnecessary loading on multiple run() calls. - if (!is_extensions_loaded_) { - HOLOSCAN_LOG_INFO("Loading extensions from configs..."); - // Load extensions from config file if exists. - for (const auto& yaml_node : fragment_->config().yaml_nodes()) { - gxf_extension_manager_->load_extensions_from_yaml(yaml_node); - } - is_extensions_loaded_ = true; - } - { // Lock the GXF context for execution std::scoped_lock lock{gxf_execution_mutex}; @@ -1776,7 +1792,7 @@ bool GXFExecutor::initialize_gxf_graph(OperatorGraph& graph) { dfft_collector_ptr->data_flow_tracker(fragment_->data_flow_tracker()); // Identify leaf and root operators and add to the DFFTCollector object - for (auto op : graph.get_nodes()) { + for (auto& op : graph.get_nodes()) { if (op->is_leaf()) { dfft_collector_ptr->add_leaf_op(op.get()); } else if (op->is_root() || op->is_user_defined_root()) { @@ -1794,8 +1810,7 @@ bool GXFExecutor::initialize_gxf_graph(OperatorGraph& graph) { network_context->gxf_eid(eid); network_context->initialize(); - std::string entity_group_name = "network_entity_group"; - auto entity_group_gid = ::holoscan::gxf::add_entity_group(context_, entity_group_name); + auto entity_group_gid = ::holoscan::gxf::add_entity_group(context_, "network_entity_group"); int32_t gpu_id = static_cast(AppDriver::get_int_env_var("HOLOSCAN_UCX_DEVICE_ID", 0)); @@ -1834,7 +1849,7 @@ bool GXFExecutor::initialize_gxf_graph(OperatorGraph& graph) { GxfUpdateEntityGroup(context, entity_group_gid, gxf_network_context->gxf_eid())); // Loop through all operators and add any operators with a UCX port to the entity group - auto operator_graph = static_cast(fragment_->graph()); + auto& operator_graph = static_cast(fragment_->graph()); for (auto& node : operator_graph.get_nodes()) { auto op_spec = node->spec(); bool already_added = false; @@ -1872,7 +1887,7 @@ bool GXFExecutor::initialize_gxf_graph(OperatorGraph& graph) { "UCX-based connection found, but there is no NetworkContext."}; // Raise an error if any operator has a UCX connector. - auto operator_graph = static_cast(fragment_->graph()); + auto& operator_graph = static_cast(fragment_->graph()); for (auto& node : operator_graph.get_nodes()) { if (node->has_ucx_connector()) { throw std::runtime_error(ucx_error_msg); } } @@ -1912,8 +1927,8 @@ void GXFExecutor::run_gxf_graph() { HOLOSCAN_LOG_ERROR("Send interrupt once more to terminate immediately"); SignalHandler::unregister_signal_handler(context, signum); // Register the global signal handler. - SignalHandler::register_global_signal_handler(signum, [](int signum) { - (void)signum; + SignalHandler::register_global_signal_handler(signum, [](int sig) { + (void)sig; HOLOSCAN_LOG_ERROR("Interrupted by user (global signal handler)"); exit(1); }); @@ -1977,18 +1992,19 @@ void GXFExecutor::register_extensions() { // Register the default GXF extensions for (auto& gxf_extension_file_name : kDefaultGXFExtensions) { - gxf_extension_manager_->load_extension(gxf_extension_file_name); + extension_manager_->load_extension(gxf_extension_file_name); } // Register the default Holoscan GXF extensions for (auto& gxf_extension_file_name : kDefaultHoloscanGXFExtensions) { - gxf_extension_manager_->load_extension(gxf_extension_file_name); + extension_manager_->load_extension(gxf_extension_file_name); } // Register the GXF extension that provides the native operators gxf_tid_t gxf_wrapper_tid{0xd4e7c16bcae741f8, 0xa5eb93731de9ccf6}; + auto gxf_extension_manager = std::dynamic_pointer_cast(extension_manager_); - if (!gxf_extension_manager_->is_extension_loaded(gxf_wrapper_tid)) { + if (gxf_extension_manager && !gxf_extension_manager->is_extension_loaded(gxf_wrapper_tid)) { GXFExtensionRegistrar extension_factory( context_, "HoloscanSdkInternalExtension", @@ -2206,10 +2222,10 @@ void GXFExecutor::add_component_args_to_graph_entity( if (container_type == ArgContainerType::kNative) { if (element_type == ArgElementType::kCondition) { auto condition = std::any_cast>(arg.value()); - add_condition_to_graph_entity(condition, graph_entity); + add_condition_to_graph_entity(std::move(condition), graph_entity); } else if (element_type == ArgElementType::kResource) { auto resource = std::any_cast>(arg.value()); - add_resource_to_graph_entity(resource, graph_entity); + add_resource_to_graph_entity(std::move(resource), graph_entity); } else if (element_type == ArgElementType::kIOSpec) { auto io_spec = std::any_cast(arg.value()); add_iospec_to_graph_entity(io_spec, graph_entity); diff --git a/src/core/fragment.cpp b/src/core/fragment.cpp index a4714e97..7a0210e3 100644 --- a/src/core/fragment.cpp +++ b/src/core/fragment.cpp @@ -104,6 +104,10 @@ void Fragment::config(std::shared_ptr& config) { } Config& Fragment::config() { + return *config_shared(); +} + +std::shared_ptr Fragment::config_shared() { if (!config_) { // If the application is executed with `--config` option or HOLOSCAN_CONFIG_PATH environment // variable, we take the config file from there. @@ -112,7 +116,7 @@ Config& Fragment::config() { if (!config_path.empty() && config_path.size() > 0) { HOLOSCAN_LOG_DEBUG("Loading config from '{}' (through --config option)", config_path); config_ = make_config(config_path.c_str()); - return *config_; + return config_; } else { const char* env_value = std::getenv("HOLOSCAN_CONFIG_PATH"); if (env_value != nullptr && env_value[0] != '\0') { @@ -120,24 +124,31 @@ Config& Fragment::config() { "Loading config from '{}' (through HOLOSCAN_CONFIG_PATH environment variable)", env_value); config_ = make_config(env_value); - return *config_; + return config_; } } } - config_ = make_config(); } - return *config_; + return config_; } OperatorGraph& Fragment::graph() { + return *graph_shared(); +} + +std::shared_ptr Fragment::graph_shared() { if (!graph_) { graph_ = make_graph(); } - return *graph_; + return graph_; } Executor& Fragment::executor() { + return *executor_shared(); +} + +std::shared_ptr Fragment::executor_shared() { if (!executor_) { executor_ = make_executor(); } - return *executor_; + return executor_; } void Fragment::scheduler(const std::shared_ptr& scheduler) { @@ -484,8 +495,13 @@ void Fragment::compose_graph() { HOLOSCAN_LOG_DEBUG("The fragment({}) has already been composed. Skipping...", name()); return; } - is_composed_ = true; + + // Load extensions from the config file before composing the graph. + // (The GXFCodeletOp and GXFComponentResource classes are required to access the underlying GXF + // types in the setup() method when composing a graph.) + load_extensions_from_config(); compose(); + is_composed_ = true; // Protect against the case where no add_operator or add_flow calls were made if (!graph_) { @@ -505,7 +521,7 @@ FragmentPortMap Fragment::port_info() const { return fragment_port_info; } std::vector operators = graph_->get_nodes(); - for (auto op : operators) { + for (auto& op : operators) { HOLOSCAN_LOG_TRACE("\toperator: {}", name_, op->name()); OperatorSpec* op_spec = op->spec(); @@ -549,4 +565,12 @@ void Fragment::reset_graph_entities() { if (gxf_network_context) { gxf_network_context->reset_graph_entities(); } } +void Fragment::load_extensions_from_config() { + HOLOSCAN_LOG_INFO("Loading extensions from configs..."); + // Load any extensions that may be present in the config file + for (const auto& yaml_node : config().yaml_nodes()) { + executor().extension_manager()->load_extensions_from_yaml(yaml_node); + } +} + } // namespace holoscan diff --git a/src/core/gxf/gxf_condition.cpp b/src/core/gxf/gxf_condition.cpp index fea5184d..7e8a7268 100644 --- a/src/core/gxf/gxf_condition.cpp +++ b/src/core/gxf/gxf_condition.cpp @@ -31,6 +31,12 @@ namespace holoscan::gxf { GXFCondition::GXFCondition(const std::string& name, nvidia::gxf::SchedulingTerm* term) { + if (term == nullptr) { + std::string err_msg = + fmt::format("SchedulingTerm pointer is null. Cannot initialize GXFCondition '{}'", name); + HOLOSCAN_LOG_ERROR(err_msg); + throw std::runtime_error(err_msg); + } id_ = term->cid(); name_ = name; gxf_context_ = term->context(); diff --git a/src/core/gxf/gxf_execution_context.cpp b/src/core/gxf/gxf_execution_context.cpp index 58d34f68..5d2b9970 100644 --- a/src/core/gxf/gxf_execution_context.cpp +++ b/src/core/gxf/gxf_execution_context.cpp @@ -19,6 +19,7 @@ #include "holoscan/core/gxf/gxf_execution_context.hpp" #include +#include #include "holoscan/core/gxf/gxf_operator.hpp" @@ -36,7 +37,8 @@ GXFExecutionContext::GXFExecutionContext(gxf_context_t context, Operator* op) { GXFExecutionContext::GXFExecutionContext(gxf_context_t context, std::shared_ptr gxf_input_context, std::shared_ptr gxf_output_context) - : gxf_input_context_(gxf_input_context), gxf_output_context_(gxf_output_context) { + : gxf_input_context_(std::move(gxf_input_context)), + gxf_output_context_(std::move(gxf_output_context)) { context_ = context; } diff --git a/src/core/gxf/gxf_extension_manager.cpp b/src/core/gxf/gxf_extension_manager.cpp index ebe55ddd..5ee2410c 100644 --- a/src/core/gxf/gxf_extension_manager.cpp +++ b/src/core/gxf/gxf_extension_manager.cpp @@ -110,7 +110,9 @@ bool GXFExtensionManager::load_extension(const std::string& file_name, bool no_e HOLOSCAN_LOG_DEBUG("Trying extension {} found in search path {}", base_name.c_str(), candidate_parent_path.c_str()); - handle = dlopen(candidate_path.c_str(), RTLD_LAZY | RTLD_NODELETE); + if (handle == nullptr) { + handle = dlopen(candidate_path.c_str(), RTLD_LAZY | RTLD_NODELETE); + } if (handle != nullptr) { HOLOSCAN_LOG_DEBUG("Loaded extension {} from search path '{}'", base_name.c_str(), diff --git a/src/core/gxf/gxf_io_context.cpp b/src/core/gxf/gxf_io_context.cpp index f998b022..90bb6e11 100644 --- a/src/core/gxf/gxf_io_context.cpp +++ b/src/core/gxf/gxf_io_context.cpp @@ -62,6 +62,10 @@ gxf_context_t GXFInputContext::gxf_context() const { bool GXFInputContext::empty_impl(const char* name) { std::string input_name = holoscan::get_well_formed_name(name, inputs_); auto it = inputs_.find(input_name); + if (it == inputs_.end()) { + HOLOSCAN_LOG_ERROR("The input port with name {} is not found", input_name); + return false; + } auto receiver = get_gxf_receiver(it->second); return receiver->size() == 0; } @@ -118,7 +122,7 @@ std::any GXFInputContext::receive_impl(const char* name, bool no_error_message) auto entity = receiver->receive(); if (!entity || entity.value().is_null()) { - return nullptr; // to indicate that there is no data + return kNoReceivedMessage; // to indicate that there is no data } auto message = entity.value().get(); @@ -147,7 +151,8 @@ gxf_context_t GXFOutputContext::gxf_context() const { return nullptr; } -void GXFOutputContext::emit_impl(std::any data, const char* name, OutputType out_type) { +void GXFOutputContext::emit_impl(std::any data, const char* name, OutputType out_type, + const int64_t acq_timestamp) { std::string output_name = holoscan::get_well_formed_name(name, outputs_); auto it = outputs_.find(output_name); @@ -217,7 +222,11 @@ void GXFOutputContext::emit_impl(std::any data, const char* name, OutputType out buffer.value()->set_value(data); // Publish the Entity object. // TODO(gbae): Check error message - static_cast(tx_ptr)->publish(std::move(gxf_entity.value())); + if (acq_timestamp != -1) { + static_cast(tx_ptr)->publish(gxf_entity.value(), acq_timestamp); + } else { + static_cast(tx_ptr)->publish(std::move(gxf_entity.value())); + } break; } case OutputType::kGXFEntity: { @@ -225,7 +234,11 @@ void GXFOutputContext::emit_impl(std::any data, const char* name, OutputType out try { auto gxf_entity = std::any_cast(data); // TODO(gbae): Check error message - static_cast(tx_ptr)->publish(std::move(gxf_entity)); + if (acq_timestamp != -1) { + static_cast(tx_ptr)->publish(gxf_entity, acq_timestamp); + } else { + static_cast(tx_ptr)->publish(std::move(gxf_entity)); + } } catch (const std::bad_any_cast& e) { HOLOSCAN_LOG_ERROR("Unable to cast to gxf::Entity: {}", e.what()); } diff --git a/src/core/gxf/gxf_resource.cpp b/src/core/gxf/gxf_resource.cpp index 4db484b6..7717993e 100644 --- a/src/core/gxf/gxf_resource.cpp +++ b/src/core/gxf/gxf_resource.cpp @@ -33,6 +33,12 @@ namespace holoscan::gxf { GXFResource::GXFResource(const std::string& name, nvidia::gxf::Component* component) { + if (component == nullptr) { + std::string err_msg = + fmt::format("Component pointer is null. Cannot initialize GXFResource '{}'", name); + HOLOSCAN_LOG_ERROR(err_msg); + throw std::runtime_error(err_msg); + } id_ = component->cid(); name_ = name; gxf_context_ = component->context(); @@ -178,7 +184,8 @@ bool GXFResource::handle_dev_id(std::optional& dev_id_value) { // Create an EntityGroup to associate the GPUDevice with this resource std::string entity_group_name = fmt::format("{}_eid{}_dev_id{}_group", name(), gxf_eid_, device_id); - auto entity_group_gid = ::holoscan::gxf::add_entity_group(gxf_context_, entity_group_name); + auto entity_group_gid = + ::holoscan::gxf::add_entity_group(gxf_context_, std::move(entity_group_name)); // Add GPUDevice component to the same entity as this resource // TODO (GXF4): requested an addResource method to handle nvidia::gxf::ResourceBase types diff --git a/src/core/messagelabel.cpp b/src/core/messagelabel.cpp index 59b288b6..3fc8c87d 100644 --- a/src/core/messagelabel.cpp +++ b/src/core/messagelabel.cpp @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -59,7 +59,7 @@ void MessageLabel::print_all() { std::string MessageLabel::to_string() const { auto msg_buf = fmt::memory_buffer(); - for (auto it : message_paths) { + for (auto& it : message_paths) { fmt::format_to(std::back_inserter(msg_buf), "{}", to_string(it)); } return fmt::to_string(msg_buf); @@ -67,7 +67,7 @@ std::string MessageLabel::to_string() const { std::string MessageLabel::to_string(MessageLabel::TimestampedPath path) { auto msg_buf = fmt::memory_buffer(); - for (auto it : path) { + for (auto& it : path) { if (!it.operator_ptr) { HOLOSCAN_LOG_ERROR("MessageLabel::to_string - Operator pointer is null"); } else { @@ -132,7 +132,7 @@ MessageLabel::TimestampedPath MessageLabel::get_path(int index) { std::string MessageLabel::get_path_name(int index) { auto pathstring = fmt::memory_buffer(); - for (auto oplabel : message_paths[index]) { + for (auto& oplabel : message_paths[index]) { if (!oplabel.operator_ptr) { HOLOSCAN_LOG_ERROR( "MessageLabel::get_path_name - Operator pointer is null. Path until now: {}.", diff --git a/src/core/operator.cpp b/src/core/operator.cpp index 3595e7e8..7439c4d8 100644 --- a/src/core/operator.cpp +++ b/src/core/operator.cpp @@ -88,9 +88,9 @@ holoscan::MessageLabel Operator::get_consolidated_input_label() { if (this->input_message_labels.size()) { // Flatten the message_paths in input_message_labels into a single MessageLabel - for (auto it : this->input_message_labels) { + for (auto& it : this->input_message_labels) { MessageLabel everyinput = it.second; - for (auto p : everyinput.paths()) { m.add_new_path(p); } + for (auto& p : everyinput.paths()) { m.add_new_path(p); } } } else { // Root operator if (!this->is_root() && !this->is_user_defined_root()) { diff --git a/src/core/resources/gxf/annotated_double_buffer_receiver.cpp b/src/core/resources/gxf/annotated_double_buffer_receiver.cpp index ec03ca86..7fd6ec8a 100644 --- a/src/core/resources/gxf/annotated_double_buffer_receiver.cpp +++ b/src/core/resources/gxf/annotated_double_buffer_receiver.cpp @@ -32,7 +32,7 @@ gxf_result_t AnnotatedDoubleBufferReceiver::receive_abi(gxf_uid_t* uid) { static gxf_tid_t message_label_tid = GxfTidNull(); if (message_label_tid == GxfTidNull()) { - GxfComponentTypeId(context(), "holoscan::MessageLabel", &message_label_tid); + HOLOSCAN_GXF_CALL(GxfComponentTypeId(context(), "holoscan::MessageLabel", &message_label_tid)); } if (gxf::has_component(context(), *uid, message_label_tid, "message_label")) { diff --git a/src/core/resources/gxf/dfft_collector.cpp b/src/core/resources/gxf/dfft_collector.cpp index c1eacf7c..0760d115 100644 --- a/src/core/resources/gxf/dfft_collector.cpp +++ b/src/core/resources/gxf/dfft_collector.cpp @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -27,7 +27,10 @@ namespace holoscan { gxf_result_t DFFTCollector::on_execute_abi(gxf_uid_t eid, uint64_t timestamp, gxf_result_t code) { - if (!data_flow_tracker_) { HOLOSCAN_LOG_ERROR("data_flow_tracker_ is null in DFFTCollector."); } + if (!data_flow_tracker_) { + HOLOSCAN_LOG_ERROR("data_flow_tracker_ is null in DFFTCollector."); + return GXF_FAILURE; + } // Get handle to entity auto entity = nvidia::gxf::Entity::Shared(context(), eid); @@ -66,7 +69,7 @@ gxf_result_t DFFTCollector::on_execute_abi(gxf_uid_t eid, uint64_t timestamp, gx } else if (root_ops_.find(codelet_id) != root_ops_.end()) { holoscan::Operator* cur_op = root_ops_[codelet_id]; - for (auto it : cur_op->num_published_messages_map()) { + for (auto& it : cur_op->num_published_messages_map()) { data_flow_tracker_->update_source_messages_number(it.first, it.second); } } diff --git a/src/core/schedulers/gxf/greedy_scheduler.cpp b/src/core/schedulers/gxf/greedy_scheduler.cpp index 49c85e46..9e5665ab 100644 --- a/src/core/schedulers/gxf/greedy_scheduler.cpp +++ b/src/core/schedulers/gxf/greedy_scheduler.cpp @@ -74,7 +74,7 @@ void GreedyScheduler::initialize() { // Find if there is an argument for 'clock' auto has_clock = std::find_if( args().begin(), args().end(), [](const auto& arg) { return (arg.name() == "clock"); }); - // Create the BooleanCondition if there is no argument provided. + // Create the clock if there was no argument provided. if (has_clock == args().end()) { clock_ = frag->make_resource("greedy_scheduler__realtime_clock"); clock_->gxf_cname(clock_->name().c_str()); diff --git a/src/core/services/app_driver/client.cpp b/src/core/services/app_driver/client.cpp index 30d165d7..82499a3e 100644 --- a/src/core/services/app_driver/client.cpp +++ b/src/core/services/app_driver/client.cpp @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -50,12 +50,13 @@ bool AppDriverClient::fragment_allocation(const std::string& worker_ip, // Creating AvailableSystemResource and adding it to the request - float cpu_memory = cpuinfo.memory_total / 1024 / 1024 / 1024; /// convert to GiB - float cpu_shared_memory = cpuinfo.shared_memory_total / 1024 / 1024; /// convert to MiB + float cpu_memory = cpuinfo.memory_total / 1024.0 / 1024.0 / 1024.0; /// convert to GiB + float cpu_shared_memory = cpuinfo.shared_memory_total / 1024.0 / 1024.0; /// convert to MiB float gpu_memory = std::numeric_limits::max(); // Calculate the minimum GPU memory among all GPUs for (const auto& gpu : gpuinfo) { - gpu_memory = std::min(gpu_memory, static_cast(gpu.memory_total / 1024 / 1024 / 1024)); + gpu_memory = + std::min(gpu_memory, static_cast(gpu.memory_total / 1024.0 / 1024.0 / 1024.0)); } // Format float value with one decimal place and convert it to string diff --git a/src/core/services/app_driver/service_impl.cpp b/src/core/services/app_driver/service_impl.cpp index 407b2ea5..ff79cdfa 100644 --- a/src/core/services/app_driver/service_impl.cpp +++ b/src/core/services/app_driver/service_impl.cpp @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,6 +20,7 @@ #include #include #include +#include #include "holoscan/core/app_driver.hpp" #include "holoscan/logger/logger.hpp" @@ -170,7 +171,7 @@ std::string AppDriverServiceImpl::parse_ip_from_peer(const std::string& peer) { // for IPv6 addresses true); // enclose IPv6 addresses in brackets - return ip; + return std::move(ip); } std::string AppDriverServiceImpl::parse_port_from_peer(const std::string& peer) { diff --git a/src/core/services/app_worker/client.cpp b/src/core/services/app_worker/client.cpp index ce0e8b24..f4ea3a4a 100644 --- a/src/core/services/app_worker/client.cpp +++ b/src/core/services/app_worker/client.cpp @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -42,7 +42,7 @@ AppWorkerClient::AppWorkerClient(const std::string& worker_address, // Assign the extracted IP to worker_ip_. We don't need to enclose IPv6 in brackets for this use // case. - worker_ip_ = extracted_ip; + worker_ip_ = std::move(extracted_ip); } const std::string& AppWorkerClient::ip_address() const { diff --git a/src/core/signal_handler.cpp b/src/core/signal_handler.cpp index 0de24f77..bbf96781 100644 --- a/src/core/signal_handler.cpp +++ b/src/core/signal_handler.cpp @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -119,9 +119,9 @@ void SignalHandler::install_signal_handler_impl(int signal) { return; } - for (auto& [signal, handler] : old_signal_handlers_) { - HOLOSCAN_LOG_DEBUG("Installing signal handler for signal {}", signal); - sigaction(signal, &signal_handler_, nullptr); // can ignore storing old handler + for (auto& [sig, handler] : old_signal_handlers_) { + HOLOSCAN_LOG_DEBUG("Installing signal handler for signal {}", sig); + sigaction(sig, &signal_handler_, nullptr); // can ignore storing old handler } } diff --git a/src/core/system/cpu_resource_monitor.cpp b/src/core/system/cpu_resource_monitor.cpp index 968d014f..634b2398 100644 --- a/src/core/system/cpu_resource_monitor.cpp +++ b/src/core/system/cpu_resource_monitor.cpp @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -81,8 +81,6 @@ static void get_proc_meminfo(uint64_t* stats) { case 3: matched = sscanf(line, "MemAvailable: %lu kB", &stats[2]); break; - default: - break; } if (matched != 1) { HOLOSCAN_LOG_ERROR( @@ -184,9 +182,13 @@ CPUInfo& CPUResourceMonitor::update(CPUInfo& cpu_info, uint64_t metric_flags) { cpu_info.memory_total = mem_info[0] * 1024; cpu_info.memory_free = mem_info[1] * 1024; cpu_info.memory_available = mem_info[2] * 1024; - cpu_info.memory_usage = static_cast(1.0 - (static_cast(mem_info[2]) / - static_cast(mem_info[0]))) * - 100.0f; + double memory_total = static_cast(mem_info[0]); + if (memory_total <= 0) { + throw std::runtime_error( + fmt::format("Invalid cpu_info.memory_total value: {}", memory_total)); + } + cpu_info.memory_usage = + static_cast(1.0 - (static_cast(mem_info[2]) / memory_total)) * 100.0f; } if (metric_flags & CPUMetricFlag::SHARED_MEMORY_USAGE) { diff --git a/src/core/system/gpu_resource_monitor.cpp b/src/core/system/gpu_resource_monitor.cpp index 820b2fd7..e227e096 100644 --- a/src/core/system/gpu_resource_monitor.cpp +++ b/src/core/system/gpu_resource_monitor.cpp @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -517,7 +517,7 @@ bool GPUResourceMonitor::bind_cuda_runtime_methods() { cudaDeviceGetPCIBusId = reinterpret_cast(dlsym(cuda_handle_, "cudaDeviceGetPCIBusId")); // for cudaMemGetInfo method - cudaMemGetInfo = reinterpret_cast(dlsym(handle_, "cudaMemGetInfo")); + cudaMemGetInfo = reinterpret_cast(dlsym(cuda_handle_, "cudaMemGetInfo")); if (cudaGetErrorString == nullptr || cudaGetDeviceCount == nullptr || cudaGetDeviceProperties == nullptr || cudaDeviceGetPCIBusId == nullptr || @@ -605,17 +605,19 @@ bool GPUResourceMonitor::init_cuda_runtime() { return true; } -void GPUResourceMonitor::shutdown_nvml() { +void GPUResourceMonitor::shutdown_nvml() noexcept { if (handle_) { - nvml::nvmlReturn_t result = nvmlShutdown(); - if (result != 0) { HOLOSCAN_LOG_ERROR("Could not shutdown NVML"); } + if (nvmlShutdown) { + nvml::nvmlReturn_t result = nvmlShutdown(); + if (result != 0) { HOLOSCAN_LOG_ERROR("Could not shutdown NVML"); } + } dlclose(handle_); handle_ = nullptr; is_cached_ = false; } } -void GPUResourceMonitor::shutdown_cuda_runtime() { +void GPUResourceMonitor::shutdown_cuda_runtime() noexcept { if (cuda_handle_) { dlclose(cuda_handle_); cuda_handle_ = nullptr; diff --git a/src/logger/logger.cpp b/src/logger/logger.cpp index 757e17bb..2eda5444 100644 --- a/src/logger/logger.cpp +++ b/src/logger/logger.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include "common/logger/spdlog_logger.hpp" @@ -89,7 +90,7 @@ void set_log_pattern(std::string pattern) { bool is_overridden_by_env = false; // https://spdlog.docsforge.com/v1.x/0.faq/#colors-do-not-appear-when-using-custom-format - Logger::set_pattern(pattern, &is_overridden_by_env); + Logger::set_pattern(std::move(pattern), &is_overridden_by_env); if (is_overridden_by_env) { const char* env_p = std::getenv("HOLOSCAN_LOG_FORMAT"); @@ -153,7 +154,7 @@ void Logger::set_pattern(std::string pattern, bool* is_overridden_by_env) { if (env_p) { std::string env_pattern; std::string log_pattern = env_p; - env_pattern = get_concrete_log_pattern(log_pattern); + env_pattern = get_concrete_log_pattern(std::move(log_pattern)); if (is_overridden_by_env) { *is_overridden_by_env = true; } diff --git a/src/operators/aja_source/aja_source.cpp b/src/operators/aja_source/aja_source.cpp index b6f74d6b..b1496d51 100644 --- a/src/operators/aja_source/aja_source.cpp +++ b/src/operators/aja_source/aja_source.cpp @@ -461,7 +461,7 @@ void AJASourceOp::compute(InputContext& op_input, OutputContext& op_output, nvidia::gxf::VideoBufferInfo info{width_, height_, video_type.value, - color_planes, + std::move(color_planes), nvidia::gxf::SurfaceLayout::GXF_SURFACE_LAYOUT_PITCH_LINEAR}; if (enable_overlay_) { diff --git a/src/operators/bayer_demosaic/bayer_demosaic.cpp b/src/operators/bayer_demosaic/bayer_demosaic.cpp index 00b03810..15f6e637 100644 --- a/src/operators/bayer_demosaic/bayer_demosaic.cpp +++ b/src/operators/bayer_demosaic/bayer_demosaic.cpp @@ -101,6 +101,13 @@ void BayerDemosaicOp::initialize() { Operator::initialize(); npp_bayer_interp_mode_ = static_cast(bayer_interp_mode_.get()); + if (npp_bayer_interp_mode_ != NPPI_INTER_UNDEFINED) { + // according to NPP docs only NPPI_INTER_UNDEFINED is supported for Bayer demosaic + // https://docs.nvidia.com/cuda/archive/12.2.0/npp/group__image__color__debayer.html + throw std::runtime_error(fmt::format("Unsupported bayer_interp_mode: {}. Must be 0", + static_cast(npp_bayer_interp_mode_))); + } + npp_bayer_grid_pos_ = static_cast(bayer_grid_pos_.get()); } diff --git a/src/operators/format_converter/format_converter.cpp b/src/operators/format_converter/format_converter.cpp index b6ebf8a5..0375874d 100644 --- a/src/operators/format_converter/format_converter.cpp +++ b/src/operators/format_converter/format_converter.cpp @@ -336,9 +336,10 @@ void FormatConverterOp::compute(InputContext& op_input, OutputContext& op_output // If the buffer is in host memory, copy it to a device (GPU) buffer // as needed for the NPP resize/convert operations. - if (in_memory_storage_type == nvidia::gxf::MemoryStorageType::kSystem) { + if (in_memory_storage_type == nvidia::gxf::MemoryStorageType::kSystem || + in_memory_storage_type == nvidia::gxf::MemoryStorageType::kHost) { uint32_t element_size = nvidia::gxf::PrimitiveTypeSize(in_primitive_type); - size_t buffer_size = rows * columns * in_channels * element_size; + size_t buffer_size = static_cast(rows) * columns * in_channels * element_size; if (buffer_size > device_scratch_buffer_->size()) { device_scratch_buffer_->resize( pool.value(), buffer_size, nvidia::gxf::MemoryStorageType::kDevice); @@ -403,9 +404,10 @@ void FormatConverterOp::compute(InputContext& op_input, OutputContext& op_output stride_string)); } - if (in_memory_storage_type == nvidia::gxf::MemoryStorageType::kSystem) { + if (in_memory_storage_type == nvidia::gxf::MemoryStorageType::kSystem || + in_memory_storage_type == nvidia::gxf::MemoryStorageType::kHost) { uint32_t element_size = nvidia::gxf::PrimitiveTypeSize(in_primitive_type); - size_t buffer_size = rows * columns * in_channels * element_size; + size_t buffer_size = static_cast(rows) * columns * in_channels * element_size; if (buffer_size > device_scratch_buffer_->size()) { device_scratch_buffer_->resize( @@ -577,7 +579,7 @@ nvidia::gxf::Expected FormatConverterOp::resizeImage( auto pool = nvidia::gxf::Handle::Create(frag->executor().context(), pool_->gxf_cid()); - uint64_t buffer_size = resize_width * resize_height * channels; + uint64_t buffer_size = static_cast(resize_width) * resize_height * channels; resize_buffer_->resize(pool.value(), buffer_size, nvidia::gxf::MemoryStorageType::kDevice); } @@ -752,7 +754,7 @@ void FormatConverterOp::convertTensorFormat( auto pool = nvidia::gxf::Handle::Create(frag->executor().context(), pool_->gxf_cid()); - uint64_t buffer_size = rows * columns * 3; // 4 channels -> 3 channels + uint64_t buffer_size = static_cast(rows) * columns * 3; // 4 channels -> 3 channels channel_buffer_->resize(pool.value(), buffer_size, nvidia::gxf::MemoryStorageType::kDevice); } diff --git a/src/operators/inference/inference.cpp b/src/operators/inference/inference.cpp index 6b6e7486..4dfb5c9a 100644 --- a/src/operators/inference/inference.cpp +++ b/src/operators/inference/inference.cpp @@ -19,6 +19,7 @@ #include #include +#include #include #include "holoscan/core/execution_context.hpp" @@ -49,7 +50,7 @@ struct YAML::convert { for (YAML::const_iterator it = node.begin(); it != node.end(); ++it) { std::string key = it->first.as(); std::string value = it->second.as(); - datamap.insert(key, value); + datamap.insert(key, std::move(value)); } } catch (const std::exception& e) { HOLOSCAN_LOG_ERROR(e.what()); @@ -96,7 +97,7 @@ struct YAML::convert { key); HOLOSCAN_LOG_WARN("Single I/O per model supported in backward compatibility mode."); std::string value = it->second.as(); - datavmap.insert(key, {value}); + datavmap.insert(key, {std::move(value)}); } break; case YAML::NodeType::Sequence: { std::vector value = it->second.as>(); @@ -139,6 +140,11 @@ void InferenceOp::setup(OperatorSpec& spec) { "Model Keyword with associated frame execution delay", "Frame delay for model inference.", DataMap()); + spec.param(activation_map_, + "activation_map", + "Model Keyword with associated model inference activation", + "Activation of model inference (1 = active, 0 = inactive).", + DataMap()); spec.param(pre_processor_map_, "pre_processor_map", "Pre processor setting per model", @@ -199,6 +205,7 @@ void InferenceOp::start() { inference_map_.get().get_map(), device_map_.get().get_map(), temporal_map_.get().get_map(), + activation_map_.get().get_map(), is_engine_path_.get(), infer_on_cpu_.get(), parallel_inference_.get(), @@ -250,8 +257,10 @@ void InferenceOp::compute(InputContext& op_input, OutputContext& op_output, // Execute inference and populate output buffer in inference specifications HoloInfer::TimePoint s_time, e_time; HoloInfer::timer_init(s_time); - auto status = holoscan_infer_context_->execute_inference(inference_specs_->data_per_tensor_, - inference_specs_->output_per_model_); + + inference_specs_->set_activation_map(activation_map_.get().get_map()); + + auto status = holoscan_infer_context_->execute_inference(inference_specs_); HoloInfer::timer_init(e_time); HoloInfer::timer_check(s_time, e_time, "Inference Operator: Inference execution"); if (status.get_code() != HoloInfer::holoinfer_code::H_SUCCESS) { diff --git a/src/operators/inference_processor/inference_processor.cpp b/src/operators/inference_processor/inference_processor.cpp index 5c6f9723..643363fb 100644 --- a/src/operators/inference_processor/inference_processor.cpp +++ b/src/operators/inference_processor/inference_processor.cpp @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: Copyright (c) 2022-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,6 +19,7 @@ #include #include +#include #include #include "holoscan/core/execution_context.hpp" @@ -89,7 +90,7 @@ struct YAML::convert { HOLOSCAN_LOG_INFO( "Converting mappings for tensor {} to vector for backward compatibility.", key); std::string value = it->second.as(); - datavmap.insert(key, {value}); + datavmap.insert(key, {std::move(value)}); } break; case YAML::NodeType::Sequence: { std::vector value = it->second.as>(); diff --git a/src/operators/v4l2_video_capture/v4l2_video_capture.cpp b/src/operators/v4l2_video_capture/v4l2_video_capture.cpp index 2d1bfe3c..2c2e5192 100644 --- a/src/operators/v4l2_video_capture/v4l2_video_capture.cpp +++ b/src/operators/v4l2_video_capture/v4l2_video_capture.cpp @@ -165,10 +165,10 @@ void V4L2VideoCaptureOp::compute(InputContext& op_input, OutputContext& op_outpu buf.length, nvidia::gxf::MemoryStorageType::kHost, read_buf.ptr, - [buffer = buf, fd = fd_, device = device_](void*) mutable { + [buffer = buf, fd = fd_, &device_ = device_](void*) mutable { if (ioctl(fd, VIDIOC_QBUF, &buffer) < 0) { - throw std::runtime_error( - fmt::format("Failed to queue buffer {} on {}", buffer.index, device.get().c_str())); + throw std::runtime_error(fmt::format( + "Failed to queue buffer {} on {}", buffer.index, device_.get().c_str())); } return nvidia::gxf::Success; }); @@ -208,7 +208,9 @@ void V4L2VideoCaptureOp::v4l2_initialize() { struct v4l2_capability caps; CLEAR(caps); - ioctl(fd_, VIDIOC_QUERYCAP, &caps); + if (ioctl(fd_, VIDIOC_QUERYCAP, &caps)) { + throw std::runtime_error("ioctl VIDIOC_QUERYCAP failed"); + } if (!(caps.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { throw std::runtime_error("No V4l2 Video capture node"); } diff --git a/src/operators/video_stream_recorder/video_stream_recorder.cpp b/src/operators/video_stream_recorder/video_stream_recorder.cpp index 53836f1e..0b3402d6 100644 --- a/src/operators/video_stream_recorder/video_stream_recorder.cpp +++ b/src/operators/video_stream_recorder/video_stream_recorder.cpp @@ -19,6 +19,7 @@ #include #include +#include #include "gxf/core/expected.hpp" #include "gxf/serialization/entity_serializer.hpp" @@ -109,14 +110,18 @@ VideoStreamRecorderOp::~VideoStreamRecorderOp() { nvidia::gxf::Expected result = binary_file_stream_.close(); if (!result) { auto code = nvidia::gxf::ToResultCode(result); - HOLOSCAN_LOG_ERROR("Failed to close binary_file_stream_ with code: {}", code); + try { + HOLOSCAN_LOG_ERROR("Failed to close binary_file_stream_ with code: {}", code); + } catch (std::exception& e) {} } // Close index file stream result = index_file_stream_.close(); if (!result) { auto code = nvidia::gxf::ToResultCode(result); - HOLOSCAN_LOG_ERROR("Failed to close index_file_stream_ with code: {}", code); + try { + HOLOSCAN_LOG_ERROR("Failed to close index_file_stream_ with code: {}", code); + } catch (std::exception& e) {} } } @@ -154,7 +159,7 @@ void VideoStreamRecorderOp::compute(InputContext& op_input, OutputContext& op_ou auto entity_serializer = nvidia::gxf::Handle::Create( context.context(), vs_serializer->gxf_cid()); nvidia::gxf::Expected size = - entity_serializer.value()->serializeEntity(entity, &binary_file_stream_); + entity_serializer.value()->serializeEntity(std::move(entity), &binary_file_stream_); if (!size) { auto code = nvidia::gxf::ToResultCode(size); throw std::runtime_error(fmt::format("Failed to serialize entity with code {}", code)); diff --git a/src/utils/cuda_stream_handler.cpp b/src/utils/cuda_stream_handler.cpp index 92070aec..9f84f523 100644 --- a/src/utils/cuda_stream_handler.cpp +++ b/src/utils/cuda_stream_handler.cpp @@ -34,7 +34,9 @@ CudaStreamHandler::~CudaStreamHandler() { for (auto&& event : cuda_events_) { const cudaError_t result = cudaEventDestroy(event); if (cudaSuccess != result) { - HOLOSCAN_LOG_ERROR("Failed to destroy CUDA event: %s", cudaGetErrorString(result)); + try { + HOLOSCAN_LOG_ERROR("Failed to destroy CUDA event: %s", cudaGetErrorString(result)); + } catch (std::exception& e) {} } } cuda_events_.clear(); diff --git a/src/utils/holoinfer_utils.cpp b/src/utils/holoinfer_utils.cpp index fffa56d4..731dc871 100644 --- a/src/utils/holoinfer_utils.cpp +++ b/src/utils/holoinfer_utils.cpp @@ -121,6 +121,7 @@ gxf_result_t get_data_per_model(InputContext& op_input, const std::vector>("receivers").value(); for (unsigned int i = 0; i < in_tensors.size(); ++i) { // nvidia::gxf::Handle in_tensor; + HOLOSCAN_LOG_DEBUG("Extracting data from tensor {}", in_tensors[i]); std::shared_ptr in_tensor; cudaStream_t cstream = 0; for (unsigned int j = 0; j < messages.size(); ++j) { @@ -151,10 +152,10 @@ gxf_result_t get_data_per_model(InputContext& op_input, const std::vectoradd_fragment(fragment); // First call to graph creates a FlowGraph object - // F.graph() returns a pointer to the abstract Graph base class so use + // F.graph() returns a reference to the abstract Graph base class so use // static_cast here - FragmentFlowGraph G = static_cast(app->fragment_graph()); + FragmentFlowGraph& G = static_cast(app->fragment_graph()); // verify that the operator was added to the graph auto nodes = G.get_nodes(); @@ -168,9 +168,9 @@ TEST(Application, TestAddFlow) { app->add_flow(fragment1, fragment2, {{"blur_image", "sharpen_image"}}); // First call to graph creates a FlowGraph object - // F.graph() returns a pointer to the abstract Graph base class so use + // F.graph() returns a reference to the abstract Graph base class so use // static_cast here - FragmentFlowGraph G = static_cast(app->fragment_graph()); + FragmentFlowGraph& G = static_cast(app->fragment_graph()); // verify that the fragments and edges were added to the graph auto nodes = G.get_nodes(); diff --git a/tests/core/arg.cpp b/tests/core/arg.cpp index 4f3d2137..1395bc91 100644 --- a/tests/core/arg.cpp +++ b/tests/core/arg.cpp @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: Copyright (c) 2022-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -29,8 +29,12 @@ #include #include "../config.hpp" +#include "holoscan/core/conditions/gxf/boolean.hpp" #include "holoscan/core/fragment.hpp" +#include "holoscan/core/io_spec.hpp" +#include "holoscan/core/operator_spec.hpp" #include "holoscan/core/parameter.hpp" +#include "holoscan/core/resources/gxf/unbounded_allocator.hpp" using namespace std::string_literals; @@ -217,16 +221,26 @@ TEST(Arg, TestArgHandleType) { check_arg_types(A, ArgElementType::kHandle, ArgContainerType::kVector); } -TEST(Arg, TestOtherEnums) { - // TODO: add parametrized test cases above for these. +TEST(Arg, TestCondition) { + Fragment F; + auto bool_cond = F.make_condition("boolean"s, Arg{"enable_tick", true}); + Arg condition_arg{"bool cond", bool_cond}; + check_arg_types(condition_arg, ArgElementType::kCondition, ArgContainerType::kNative); +} + +TEST(Arg, TestResource) { + Fragment F; + auto allocator = F.make_resource("unbounded"); + Arg resource_arg{"allocator", allocator}; + check_arg_types(resource_arg, ArgElementType::kResource, ArgContainerType::kNative); +} - // For now, just check that enum entries exist for: - // kIOSpec (holoscan::IOSpec*) - // kCondition (std::shared_ptr) - // kResource (std::shared_ptr) - ArgElementType T = ArgElementType::kIOSpec; - T = ArgElementType::kCondition; - T = ArgElementType::kResource; +TEST(Arg, TestIOSpec) { + OperatorSpec op_spec = OperatorSpec(); + IOSpec spec = + IOSpec(&op_spec, std::string("a"), IOSpec::IOType::kInput, &typeid(holoscan::gxf::Entity)); + Arg spec_arg{"iospec", &spec}; + check_arg_types(spec_arg, ArgElementType::kIOSpec, ArgContainerType::kNative); } TEST(Arg, TestArgDescription) { diff --git a/tests/core/argument_setter.cpp b/tests/core/argument_setter.cpp index c2d0fc87..e2792303 100644 --- a/tests/core/argument_setter.cpp +++ b/tests/core/argument_setter.cpp @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -33,8 +33,12 @@ namespace holoscan { TEST(ArgumentSetter, TestArgumentSetterInstance) { ArgumentSetter instance = ArgumentSetter::get_instance(); + // call static ensure_type method ArgumentSetter::ensure_type; - // ArgumentSetter::ensure_type>; // will fail to compile + + // get the setter corresponding to float + float f = 1.0; + auto func = instance.get_argument_setter(typeid(f)); } } // namespace holoscan diff --git a/tests/core/condition.cpp b/tests/core/condition.cpp index cde5aa3e..b30545a1 100644 --- a/tests/core/condition.cpp +++ b/tests/core/condition.cpp @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: Copyright (c) 2022-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -34,8 +34,8 @@ TEST(Condition, TestConditionName) { EXPECT_EQ(C.name(), ""); C.name("my_name"); - Fragment* f; - C.fragment(f); + Fragment f; + C.fragment(&f); EXPECT_EQ(C.name(), "my_name"); } @@ -45,41 +45,40 @@ TEST(Condition, TestConditionFragment) { Condition C = Condition(); EXPECT_EQ(C.fragment(), nullptr); - Fragment* f; - C.fragment(f); - EXPECT_EQ(C.fragment(), f); + Fragment f; + C.fragment(&f); + EXPECT_EQ(C.fragment(), &f); } TEST(Condition, TestConditionSpec) { // initialization Condition C = Condition(); - Fragment* f; + Fragment f; - C.spec(std::make_shared(f)); + C.spec(std::make_shared(&f)); } TEST(Condition, TestConditionChainedAssignments) { // initialization Condition C; - Fragment *f1, *f2, *f3; + Fragment f1, f2, f3; - C.fragment(f1).name("name1"); - EXPECT_EQ(C.fragment(), f1); + C.fragment(&f1).name("name1"); + EXPECT_EQ(C.fragment(), &f1); EXPECT_EQ(C.name(), "name1"); - C.name("name2").fragment(f2); - EXPECT_EQ(C.fragment(), f2); + C.name("name2").fragment(&f2); + EXPECT_EQ(C.fragment(), &f2); EXPECT_EQ(C.name(), "name2"); - C.spec(std::make_shared(f3)).name("name3").fragment(f3); - EXPECT_EQ(C.fragment(), f3); + C.spec(std::make_shared(&f3)).name("name3").fragment(&f3); + EXPECT_EQ(C.fragment(), &f3); EXPECT_EQ(C.name(), "name3"); } TEST(Condition, TestConditionSpecFragmentNull) { // initialization Condition C = Condition(); - Fragment* f; // component spec can take in nullptr fragment C.spec(std::make_shared()); diff --git a/tests/core/condition_classes.cpp b/tests/core/condition_classes.cpp index e8420c78..95228b76 100644 --- a/tests/core/condition_classes.cpp +++ b/tests/core/condition_classes.cpp @@ -35,6 +35,7 @@ #include "holoscan/core/conditions/gxf/downstream_affordable.hpp" #include "holoscan/core/conditions/gxf/periodic.hpp" #include "holoscan/core/conditions/gxf/message_available.hpp" +#include "holoscan/core/conditions/gxf/expiring_message.hpp" #include "holoscan/core/config.hpp" #include "holoscan/core/executor.hpp" #include "holoscan/core/graph.hpp" @@ -207,6 +208,19 @@ TEST(ConditionClasses, TestMessageAvailableCondition) { EXPECT_TRUE(condition->description().find("name: " + name) != std::string::npos); } +TEST(ConditionClasses, TestExpiringMessageAvailableCondition) { + Fragment F; + const std::string name{"expiring-message-available-condition"}; + ArgList arglist{Arg{"min_size", 1L}, Arg{"front_stage_max_size", 2L}}; + auto condition = F.make_condition(name, arglist); + EXPECT_EQ(condition->name(), name); + EXPECT_EQ(typeid(condition), + typeid(std::make_shared(arglist))); + EXPECT_EQ(std::string(condition->gxf_typename()), + "nvidia::gxf::ExpiringMessageAvailableSchedulingTerm"s); + EXPECT_TRUE(condition->description().find("name: " + name) != std::string::npos); +} + TEST(ConditionClasses, TestMessageAvailableConditionDefaultConstructor) { Fragment F; auto condition = F.make_condition(); @@ -351,7 +365,8 @@ TEST_F(ConditionClassesWithGXFContext, TestPeriodicConditionInitializeWithArg) { const GxfEntityCreateInfo entity_create_info = {"dummy_entity", GXF_ENTITY_CREATE_PROGRAM_BIT}; gxf_uid_t eid = 0; gxf_result_t code; - GxfCreateEntity(context, &entity_create_info, &eid); + code = GxfCreateEntity(context, &entity_create_info, &eid); + ASSERT_EQ(code, GXF_SUCCESS); std::vector> conditions; for (auto& pair : pairs) { diff --git a/tests/core/dataflow_tracker.cpp b/tests/core/dataflow_tracker.cpp index 4d194168..0aa0d5cd 100644 --- a/tests/core/dataflow_tracker.cpp +++ b/tests/core/dataflow_tracker.cpp @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -248,7 +248,7 @@ TEST(DataFlowTracker, GetPathStrings) { auto paths = tracker.get_path_strings(); - for (auto path : paths) { + for (const auto& path : paths) { ASSERT_TRUE(std::find(path_strings.begin(), path_strings.end(), path) != path_strings.end()); } } diff --git a/tests/core/fragment.cpp b/tests/core/fragment.cpp index 268234d4..4489a7ee 100644 --- a/tests/core/fragment.cpp +++ b/tests/core/fragment.cpp @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: Copyright (c) 2022-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -84,7 +84,7 @@ TEST(Fragment, TestFragmentConfig) { const std::string config_file = test_config.get_test_data_file("app_config.yaml"); F.config(config_file); - Config C = F.config(); + Config& C = F.config(); ASSERT_TRUE(C.config_file() == config_file); ArgList args = F.from_config("format_converter_replayer"s); @@ -112,7 +112,7 @@ TEST(Fragment, TestFragmentConfigNestedArgs) { const std::string config_file = test_config.get_test_data_file("app_config.yaml"); F.config(config_file); - Config C = F.config(); + Config& C = F.config(); ASSERT_TRUE(C.config_file() == config_file); // can directly access a specific argument under the "aja" section @@ -126,7 +126,7 @@ TEST(Fragment, TestFragmentConfigNestedArgs) { TEST(Fragment, TestConfigUninitializedWarning) { Fragment F; - Config C = F.config(); + Config& C = F.config(); EXPECT_EQ(C.config_file(), ""); } @@ -138,7 +138,7 @@ TEST(Fragment, TestFragmentFromConfigNonexistentKey) { const std::string config_file = test_config.get_test_data_file("app_config.yaml"); F.config(config_file); - Config C = F.config(); + Config& C = F.config(); ASSERT_TRUE(C.config_file() == config_file); ArgList args = F.from_config("non-existent"s); EXPECT_EQ(args.size(), 0); @@ -169,9 +169,9 @@ TEST(Fragment, TestFragmentGraph) { Fragment F; // First call to graph creates a FlowGraph object - // F.graph() returns a pointer to the abstract Graph base class so use + // F.graph() returns a reference to the abstract Graph base class so use // static_cast here - OperatorFlowGraph G = static_cast(F.graph()); + OperatorFlowGraph& G = static_cast(F.graph()); } TEST(Fragment, TestAddOperator) { @@ -181,9 +181,9 @@ TEST(Fragment, TestAddOperator) { F.add_operator(op); // First call to graph creates a FlowGraph object - // F.graph() returns a pointer to the abstract Graph base class so use + // F.graph() returns a reference to the abstract Graph base class so use // static_cast here - OperatorFlowGraph G = static_cast(F.graph()); + OperatorFlowGraph& G = static_cast(F.graph()); // verify that the operator was added to the graph auto nodes = G.get_nodes(); @@ -212,9 +212,9 @@ TEST(Fragment, TestAddFlow) { F.add_flow(tx, rx, {{"out", "in"}}); // First call to graph creates a FlowGraph object - // F.graph() returns a pointer to the abstract Graph base class so use + // F.graph() returns a reference to the abstract Graph base class so use // static_cast here - OperatorFlowGraph G = static_cast(F.graph()); + OperatorFlowGraph& G = static_cast(F.graph()); // verify that the operators and edges were added to the graph auto nodes = G.get_nodes(); @@ -243,7 +243,7 @@ TEST(Fragment, TestOperatorOrder) { F.add_flow(tx, rx, {{"out", "in"}}); F.add_flow(tx2, rx2, {{"out", "in"}}); - OperatorFlowGraph G = static_cast(F.graph()); + OperatorFlowGraph& G = static_cast(F.graph()); auto order = G.get_nodes(); const std::vector expected_order = {"tx2", "tx", "rx", "rx2"}; @@ -256,7 +256,7 @@ TEST(Fragment, TestFragmentExecutor) { Fragment F; // First call to executor generates an Executor object - Executor E = F.executor(); + Executor& E = F.executor(); // this fragment is associated with the executor that was created EXPECT_EQ(E.fragment(), &F); @@ -271,7 +271,6 @@ TEST(Fragment, TestFragmentMoveAssignment) { // can only move assign (copy assignment operator has been deleted) F = std::move(G); EXPECT_EQ(F.name(), "G"); - EXPECT_EQ(G.name(), ""); } // Fragment::make_condition is tested elsewhere in condition_classes.cpp diff --git a/tests/core/resource.cpp b/tests/core/resource.cpp index f3df16d6..8cb484a6 100644 --- a/tests/core/resource.cpp +++ b/tests/core/resource.cpp @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: Copyright (c) 2022-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -35,8 +35,8 @@ TEST(Resource, TestResourceName) { EXPECT_EQ(R.name(), ""); R.name("my_name"); - Fragment* f; - R.fragment(f); + Fragment f; + R.fragment(&f); EXPECT_EQ(R.name(), "my_name"); } @@ -46,23 +46,23 @@ TEST(Resource, TestResourceFragment) { Resource R = Resource(); EXPECT_EQ(R.fragment(), nullptr); - Fragment* f; - R.fragment(f); - EXPECT_EQ(R.fragment(), f); + Fragment f; + R.fragment(&f); + EXPECT_EQ(R.fragment(), &f); } TEST(Resource, TestResourceSpec) { // initialization Resource R = Resource(); - Fragment* f; + Fragment f; - R.spec(std::make_shared(f)); + R.spec(std::make_shared(&f)); } TEST(Resource, TestResourceSpecFragmentNull) { // initialization Resource R = Resource(); - Fragment* f; + Fragment f; // component spec can take in nullptr fragment R.spec(std::make_shared()); @@ -71,18 +71,18 @@ TEST(Resource, TestResourceSpecFragmentNull) { TEST(Resource, TestResourceChainedAssignments) { // initialization Resource R; - Fragment *f1, *f2, *f3; + Fragment f1, f2, f3; - R.fragment(f1).name("name1"); - EXPECT_EQ(R.fragment(), f1); + R.fragment(&f1).name("name1"); + EXPECT_EQ(R.fragment(), &f1); EXPECT_EQ(R.name(), "name1"); - R.name("name2").fragment(f2); - EXPECT_EQ(R.fragment(), f2); + R.name("name2").fragment(&f2); + EXPECT_EQ(R.fragment(), &f2); EXPECT_EQ(R.name(), "name2"); - R.spec(std::make_shared(f3)).name("name3").fragment(f3); - EXPECT_EQ(R.fragment(), f3); + R.spec(std::make_shared(&f3)).name("name3").fragment(&f3); + EXPECT_EQ(R.fragment(), &f3); EXPECT_EQ(R.name(), "name3"); } diff --git a/tests/data/loading_gxf_extension.yaml b/tests/data/loading_gxf_extension.yaml new file mode 100644 index 00000000..a1735125 --- /dev/null +++ b/tests/data/loading_gxf_extension.yaml @@ -0,0 +1,19 @@ +%YAML 1.2 +# SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +--- +extensions: +- libgxf_cuda.so +- libgxf_sample.so diff --git a/tests/holoinfer/inference/test_core.cpp b/tests/holoinfer/inference/test_core.cpp index 3df1307b..754c2436 100644 --- a/tests/holoinfer/inference/test_core.cpp +++ b/tests/holoinfer/inference/test_core.cpp @@ -117,6 +117,7 @@ void HoloInferTests::setup_specifications() { inference_map, device_map, temporal_map, + activation_map, is_engine_path, infer_on_cpu, parallel_inference, @@ -145,7 +146,7 @@ HoloInfer::InferStatus HoloInferTests::prepare_for_inference() { auto status = create_specifications(); - for (const auto td : in_tensor_dimensions) { + for (const auto& td : in_tensor_dimensions) { auto db = std::make_shared(); size_t buffer_size = std::accumulate(td.second.begin(), td.second.end(), 1, std::multiplies()); @@ -163,8 +164,7 @@ HoloInfer::InferStatus HoloInferTests::do_inference() { try { if (!holoscan_infer_context_) { return status; } - return holoscan_infer_context_->execute_inference(inference_specs_->data_per_tensor_, - inference_specs_->output_per_model_); + return holoscan_infer_context_->execute_inference(inference_specs_); } catch (...) { std::cout << "Exception occurred in inference.\n"; return status; diff --git a/tests/holoinfer/inference/test_core.hpp b/tests/holoinfer/inference/test_core.hpp index 48ef8e3b..37651fd7 100644 --- a/tests/holoinfer/inference/test_core.hpp +++ b/tests/holoinfer/inference/test_core.hpp @@ -71,6 +71,7 @@ class HoloInferTests { std::map device_map = {{"model_1", "0"}, {"model_2", "0"}}; std::map temporal_map = {{"model_1", "1"}, {"model_2", "1"}}; + std::map activation_map = {{"model_1", "1"}, {"model_2", "1"}}; std::map backend_map; diff --git a/tests/operators/operator_classes.cpp b/tests/operators/operator_classes.cpp index b8f78621..06944625 100644 --- a/tests/operators/operator_classes.cpp +++ b/tests/operators/operator_classes.cpp @@ -162,7 +162,9 @@ TEST_F(OperatorClassesWithGXFContext, TestVideoStreamRecorderOp) { TEST_F(OperatorClassesWithGXFContext, TestVideoStreamReplayerOp) { const std::string name{"replayer"}; - const std::string sample_data_path = std::string(std::getenv("HOLOSCAN_INPUT_PATH")); + auto in_path = std::getenv("HOLOSCAN_INPUT_PATH"); + if (!in_path) { GTEST_SKIP() << "Skipping test due to undefined HOLOSCAN_INPUT_PATH env var"; } + const std::string sample_data_path = std::string(in_path); ArgList args{ Arg{"directory", sample_data_path + "/racerx"s}, Arg{"basename", "racerx"s}, diff --git a/tests/operators/segmentation_postprocessor/test_postprocessor.cpp b/tests/operators/segmentation_postprocessor/test_postprocessor.cpp index 6d65ff5a..08f606de 100644 --- a/tests/operators/segmentation_postprocessor/test_postprocessor.cpp +++ b/tests/operators/segmentation_postprocessor/test_postprocessor.cpp @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -123,14 +123,50 @@ static const uint8_t kArgmaxOutputData[] = { 4, 1, 0, 2, 2, 1, 0, 3, 3, 4, 2, 2, 4, 0, 0, 0, 2, 4, 4, 2, 0, 0, 2, 2, 3, 0, 0, 2, 2, 2, 1, 3, 2, 1, 0, 4, 3, 1, 0, 4, 2, 4, 4, 1, 4, 3, 3, 0, 4, 2, 4, 1, 1, 1, 3, 1, 4, 1, 3, 0, 2, 0}; -TEST(SegmentationPostprocessor, Argmax) { - holoscan::ops::segmentation_postprocessor::Shape shape; - shape.height = 19; - shape.width = 10; - shape.channels = 5; +// The fixture for testing the Segmentation Postprocessor +class SegmentationPostprocessorTest : public testing::Test { + protected: + void SetUp() override { + shape.height = 19; + shape.width = 10; + shape.channels = 5; + + // Allocate device memory needed by the tests + cuda_status = cudaMalloc(reinterpret_cast(&device_input_data), input_data_size); + if (cuda_status == cudaSuccess) { + cuda_status = cudaMalloc(reinterpret_cast(&device_output_data), output_data_size); + } + // Copy input data to the device + if (cuda_status == cudaSuccess) { + cuda_status = cudaMemcpy(device_input_data, kArgmaxInputData, input_data_size, + cudaMemcpyHostToDevice); + } + } + + void TearDown() override { + // Free any device memory allocated during SetUp + if (device_input_data) { + cudaFree(device_input_data); + } + if (device_output_data) { + cudaFree(device_output_data); + } + } + + // Any members defined here can be directly accessed from the test case + holoscan::ops::segmentation_postprocessor::Shape shape; const uint32_t input_data_size = sizeof(kArgmaxInputData); const uint32_t output_data_size = sizeof(kArgmaxOutputData); + cudaError_t cuda_status; + float* device_input_data = nullptr; + holoscan::ops::segmentation_postprocessor::output_type_t* device_output_data = nullptr; +}; + + +TEST_F(SegmentationPostprocessorTest, Argmax) { + // check that no CUDA errors occurred during SetUp() + ASSERT_EQ(cudaSuccess, cuda_status); ASSERT_EQ(input_data_size, shape.height * shape.width * shape.channels * sizeof(float)); ASSERT_EQ(output_data_size, @@ -139,15 +175,6 @@ TEST(SegmentationPostprocessor, Argmax) { holoscan::ops::segmentation_postprocessor::output_type_t host_output_data[output_data_size] = {}; - float* device_input_data = nullptr; - holoscan::ops::segmentation_postprocessor::output_type_t* device_output_data = nullptr; - ASSERT_EQ(cudaSuccess, cudaMalloc(reinterpret_cast(&device_input_data), input_data_size)); - ASSERT_EQ(cudaSuccess, - cudaMalloc(reinterpret_cast(&device_output_data), output_data_size)); - - ASSERT_EQ( - cudaSuccess, - cudaMemcpy(device_input_data, kArgmaxInputData, input_data_size, cudaMemcpyHostToDevice)); ASSERT_EQ(cudaSuccess, cudaMemset(device_output_data, 0, output_data_size)); holoscan::ops::segmentation_postprocessor::cuda_postprocess( @@ -161,9 +188,6 @@ TEST(SegmentationPostprocessor, Argmax) { cudaSuccess, cudaMemcpy(host_output_data, device_output_data, output_data_size, cudaMemcpyDeviceToHost)); - ASSERT_EQ(cudaSuccess, cudaFree(device_input_data)); - ASSERT_EQ(cudaSuccess, cudaFree(device_output_data)); - for (uint32_t i = 0; i < output_data_size / sizeof(host_output_data[0]); i++) { ASSERT_EQ(kArgmaxOutputData[i], host_output_data[i]) << "Failed at index: " << i; } diff --git a/tests/system/distributed/distributed_app.cpp b/tests/system/distributed/distributed_app.cpp index f68a6775..207a0071 100644 --- a/tests/system/distributed/distributed_app.cpp +++ b/tests/system/distributed/distributed_app.cpp @@ -54,7 +54,8 @@ TEST(DistributedApp, TestTwoMultiInputsOutputsFragmentsApp) { app->run(); std::string log_output = testing::internal::GetCapturedStderr(); - EXPECT_TRUE(log_output.find("received count: 10") != std::string::npos); + EXPECT_TRUE(log_output.find("received count: 10") != std::string::npos) << "===LogMessage===\n" + << log_output; } TEST(DistributedApp, TestTwoMultipleSingleOutputOperatorsApp) { diff --git a/tests/system/distributed/ucx_message_serialization_ping_app.cpp b/tests/system/distributed/ucx_message_serialization_ping_app.cpp index d926a165..9e278070 100644 --- a/tests/system/distributed/ucx_message_serialization_ping_app.cpp +++ b/tests/system/distributed/ucx_message_serialization_ping_app.cpp @@ -147,8 +147,8 @@ TEST_P(UcxMessageTypeParmeterizedTestFixture, TestUcxMessageSerializationApp) { if (message_type == MessageType::VEC_DOUBLE_LARGE) { // message is larger than kDefaultUcxSerializationBufferSize // set HOLOSCAN_UCX_SERIALIZATION_BUFFER_SIZE to a value large enough to hold the data - const char* buffer_size = std::to_string(10 * 1024 * 1024).c_str(); - setenv("HOLOSCAN_UCX_SERIALIZATION_BUFFER_SIZE", buffer_size, 1); + std::string buffer_size = std::to_string(10 * 1024 * 1024); + setenv("HOLOSCAN_UCX_SERIALIZATION_BUFFER_SIZE", buffer_size.c_str(), 1); } HOLOSCAN_LOG_INFO("Creating UcxMessageSerializationApp for type: {}", diff --git a/tests/system/loading_gxf_extension.cpp b/tests/system/loading_gxf_extension.cpp new file mode 100644 index 00000000..1cf205cf --- /dev/null +++ b/tests/system/loading_gxf_extension.cpp @@ -0,0 +1,175 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include + +#include +#include + +#include "../config.hpp" + +static HoloscanTestConfig test_config; + +namespace holoscan { + +// Do not pollute holoscan namespace with utility classes +namespace { + +/////////////////////////////////////////////////////////////////////////////// +// Utility Resources/Operators +/////////////////////////////////////////////////////////////////////////////// + +HOLOSCAN_WRAP_GXF_COMPONENT_AS_RESOURCE(MyCudaStreamPool, "nvidia::gxf::CudaStreamPool") +HOLOSCAN_WRAP_GXF_CODELET_AS_OPERATOR(HelloWorldOp, "nvidia::gxf::HelloWorld") + +/////////////////////////////////////////////////////////////////////////////// +// Utility Applications +/////////////////////////////////////////////////////////////////////////////// + +class LoadInsideComposeApp : public holoscan::Application { + public: + using Application::Application; + + void compose() override { + auto extension_manager = executor().extension_manager(); + extension_manager->load_extension("libgxf_cuda.so"); + extension_manager->load_extension("libgxf_sample.so"); + + auto pool = make_resource("pool"); + auto hello = make_operator("hello", make_condition(10)); + add_operator(hello); + } +}; + +class DummyApp : public holoscan::Application { + public: + using Application::Application; + + void compose() override { + auto pool = make_resource("pool"); + auto hello = make_operator("hello", make_condition(10)); + add_operator(hello); + } +}; + +} // namespace + +/////////////////////////////////////////////////////////////////////////////// +// Tests +/////////////////////////////////////////////////////////////////////////////// + +TEST(Extensions, LoadInsideComposeMethod) { + auto app = make_application(); + + // Capture stderr output to check for specific error messages + testing::internal::CaptureStderr(); + + app->run(); + + std::string log_output = testing::internal::GetCapturedStderr(); + // Check that log_output has 10 instances of "Hello world" + auto pos = log_output.find("Hello world"); + int count = 0; + while (pos != std::string::npos) { + count++; + pos = log_output.find("Hello world", pos + 1); + } + EXPECT_EQ(count, 10) << "Expected to find 10 instances of 'Hello world' in log output, but found " + << count << ".\nLog output:\n" + << log_output; +} + +TEST(Extensions, LoadOutsideApp) { + auto app = make_application(); + + // Load the extensions outside of the application before calling run() method + auto& executor = app->executor(); + auto extension_manager = executor.extension_manager(); + extension_manager->load_extension("libgxf_cuda.so"); + extension_manager->load_extension("libgxf_sample.so"); + + // Capture stderr output to check for specific error messages + testing::internal::CaptureStderr(); + + app->run(); + + std::string log_output = testing::internal::GetCapturedStderr(); + // Check that log_output has 10 instances of "Hello world" + auto pos = log_output.find("Hello world"); + int count = 0; + while (pos != std::string::npos) { + count++; + pos = log_output.find("Hello world", pos + 1); + } + EXPECT_EQ(count, 10) << "Expected to find 10 instances of 'Hello world' in log output, but found " + << count << ".\nLog output:\n" + << log_output; +} + +TEST(Extensions, LoadFromConfigFile) { + auto app = make_application(); + + const std::string config_file = test_config.get_test_data_file("loading_gxf_extension.yaml"); + app->config(config_file); + + // Capture stderr output to check for specific error messages + testing::internal::CaptureStderr(); + + app->run(); + + std::string log_output = testing::internal::GetCapturedStderr(); + // Check that log_output has 10 instances of "Hello world" + auto pos = log_output.find("Hello world"); + int count = 0; + while (pos != std::string::npos) { + count++; + pos = log_output.find("Hello world", pos + 1); + } + EXPECT_EQ(count, 10) << "Expected to find 10 instances of 'Hello world' in log output, but found " + << count << ".\nLog output:\n" + << log_output; +} + +TEST(Extensions, LoadFromConfigFileAfterAccessingExecutor) { + auto app = make_application(); + // Access executor before calling config() or run() method to see if it works + app->executor().context(); + + const std::string config_file = test_config.get_test_data_file("loading_gxf_extension.yaml"); + app->config(config_file); + + // Capture stderr output to check for specific error messages + testing::internal::CaptureStderr(); + + app->run(); + + std::string log_output = testing::internal::GetCapturedStderr(); + // Check that log_output has 10 instances of "Hello world" + auto pos = log_output.find("Hello world"); + int count = 0; + while (pos != std::string::npos) { + count++; + pos = log_output.find("Hello world", pos + 1); + } + EXPECT_EQ(count, 10) << "Expected to find 10 instances of 'Hello world' in log output, but found " + << count << ".\nLog output:\n" + << log_output; +} + +} // namespace holoscan

    EUZ$`eGxUZGX3V9?v)4;I3<` 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