holoscan 2.1.0__cp38-cp38-manylinux_2_35_aarch64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (138) hide show
  1. holoscan-2.1.0.data/purelib/holoscan/__init__.py +121 -0
  2. holoscan-2.1.0.data/purelib/holoscan/cli/__init__.py +32 -0
  3. holoscan-2.1.0.data/purelib/holoscan/cli/__main__.py +159 -0
  4. holoscan-2.1.0.data/purelib/holoscan/cli/common/argparse_types.py +154 -0
  5. holoscan-2.1.0.data/purelib/holoscan/cli/common/artifact_sources.py +144 -0
  6. holoscan-2.1.0.data/purelib/holoscan/cli/common/constants.py +120 -0
  7. holoscan-2.1.0.data/purelib/holoscan/cli/common/dockerutils.py +506 -0
  8. holoscan-2.1.0.data/purelib/holoscan/cli/common/enum_types.py +52 -0
  9. holoscan-2.1.0.data/purelib/holoscan/cli/common/exceptions.py +132 -0
  10. holoscan-2.1.0.data/purelib/holoscan/cli/common/sdk_utils.py +180 -0
  11. holoscan-2.1.0.data/purelib/holoscan/cli/common/utils.py +131 -0
  12. holoscan-2.1.0.data/purelib/holoscan/cli/logging.json +37 -0
  13. holoscan-2.1.0.data/purelib/holoscan/cli/nics/__init__.py +18 -0
  14. holoscan-2.1.0.data/purelib/holoscan/cli/nics/nics.py +34 -0
  15. holoscan-2.1.0.data/purelib/holoscan/cli/packager/__init__.py +18 -0
  16. holoscan-2.1.0.data/purelib/holoscan/cli/packager/arguments.py +137 -0
  17. holoscan-2.1.0.data/purelib/holoscan/cli/packager/config_reader.py +181 -0
  18. holoscan-2.1.0.data/purelib/holoscan/cli/packager/container_builder.py +349 -0
  19. holoscan-2.1.0.data/purelib/holoscan/cli/packager/manifest_files.py +220 -0
  20. holoscan-2.1.0.data/purelib/holoscan/cli/packager/models.py +93 -0
  21. holoscan-2.1.0.data/purelib/holoscan/cli/packager/package_command.py +183 -0
  22. holoscan-2.1.0.data/purelib/holoscan/cli/packager/packager.py +123 -0
  23. holoscan-2.1.0.data/purelib/holoscan/cli/packager/parameters.py +534 -0
  24. holoscan-2.1.0.data/purelib/holoscan/cli/packager/platforms.py +405 -0
  25. holoscan-2.1.0.data/purelib/holoscan/cli/packager/sdk_downloader.py +147 -0
  26. holoscan-2.1.0.data/purelib/holoscan/cli/packager/templates/Dockerfile.jinja2 +191 -0
  27. holoscan-2.1.0.data/purelib/holoscan/cli/packager/templates/dockerignore +93 -0
  28. holoscan-2.1.0.data/purelib/holoscan/cli/packager/templates/tools.sh +416 -0
  29. holoscan-2.1.0.data/purelib/holoscan/cli/py.typed +0 -0
  30. holoscan-2.1.0.data/purelib/holoscan/cli/runner/__init__.py +18 -0
  31. holoscan-2.1.0.data/purelib/holoscan/cli/runner/resources.py +174 -0
  32. holoscan-2.1.0.data/purelib/holoscan/cli/runner/run_command.py +204 -0
  33. holoscan-2.1.0.data/purelib/holoscan/cli/runner/runner.py +306 -0
  34. holoscan-2.1.0.data/purelib/holoscan/cli/version/__init__.py +18 -0
  35. holoscan-2.1.0.data/purelib/holoscan/cli/version/version.py +50 -0
  36. holoscan-2.1.0.data/purelib/holoscan/conditions/__init__.py +45 -0
  37. holoscan-2.1.0.data/purelib/holoscan/conditions/_conditions.cpython-38-aarch64-linux-gnu.so +0 -0
  38. holoscan-2.1.0.data/purelib/holoscan/core/__init__.py +367 -0
  39. holoscan-2.1.0.data/purelib/holoscan/core/_core.cpython-38-aarch64-linux-gnu.so +0 -0
  40. holoscan-2.1.0.data/purelib/holoscan/executors/__init__.py +26 -0
  41. holoscan-2.1.0.data/purelib/holoscan/executors/_executors.cpython-38-aarch64-linux-gnu.so +0 -0
  42. holoscan-2.1.0.data/purelib/holoscan/graphs/__init__.py +32 -0
  43. holoscan-2.1.0.data/purelib/holoscan/graphs/_graphs.cpython-38-aarch64-linux-gnu.so +0 -0
  44. holoscan-2.1.0.data/purelib/holoscan/gxf/__init__.py +57 -0
  45. holoscan-2.1.0.data/purelib/holoscan/gxf/_gxf.cpython-38-aarch64-linux-gnu.so +0 -0
  46. holoscan-2.1.0.data/purelib/holoscan/lib/gxf_extensions/libgxf_holoscan_wrapper.so +0 -0
  47. holoscan-2.1.0.data/purelib/holoscan/lib/gxf_extensions/libgxf_holoscan_wrapper_lib.so +0 -0
  48. holoscan-2.1.0.data/purelib/holoscan/lib/gxf_extensions/libgxf_ucx_holoscan.so +0 -0
  49. holoscan-2.1.0.data/purelib/holoscan/lib/gxf_extensions/libgxf_ucx_holoscan_lib.so +0 -0
  50. holoscan-2.1.0.data/purelib/holoscan/lib/libgxf_app.so +0 -0
  51. holoscan-2.1.0.data/purelib/holoscan/lib/libgxf_core.so +0 -0
  52. holoscan-2.1.0.data/purelib/holoscan/lib/libgxf_cuda.so +0 -0
  53. holoscan-2.1.0.data/purelib/holoscan/lib/libgxf_logger.so +0 -0
  54. holoscan-2.1.0.data/purelib/holoscan/lib/libgxf_multimedia.so +0 -0
  55. holoscan-2.1.0.data/purelib/holoscan/lib/libgxf_sample.so +0 -0
  56. holoscan-2.1.0.data/purelib/holoscan/lib/libgxf_serialization.so +0 -0
  57. holoscan-2.1.0.data/purelib/holoscan/lib/libgxf_std.so +0 -0
  58. holoscan-2.1.0.data/purelib/holoscan/lib/libgxf_ucx.so +0 -0
  59. holoscan-2.1.0.data/purelib/holoscan/lib/libholoscan_core.so.2.1.0 +0 -0
  60. holoscan-2.1.0.data/purelib/holoscan/lib/libholoscan_infer.so.2.1.0 +0 -0
  61. holoscan-2.1.0.data/purelib/holoscan/lib/libholoscan_infer_onnx_runtime.so.2.1.0 +0 -0
  62. holoscan-2.1.0.data/purelib/holoscan/lib/libholoscan_infer_torch.so.2.1.0 +0 -0
  63. holoscan-2.1.0.data/purelib/holoscan/lib/libholoscan_infer_utils.so.2.1.0 +0 -0
  64. holoscan-2.1.0.data/purelib/holoscan/lib/libholoscan_logger.so.2.1.0 +0 -0
  65. holoscan-2.1.0.data/purelib/holoscan/lib/libholoscan_op_aja.so.2.1.0 +0 -0
  66. holoscan-2.1.0.data/purelib/holoscan/lib/libholoscan_op_async_ping_rx.so.2.1.0 +0 -0
  67. holoscan-2.1.0.data/purelib/holoscan/lib/libholoscan_op_async_ping_tx.so.2.1.0 +0 -0
  68. holoscan-2.1.0.data/purelib/holoscan/lib/libholoscan_op_bayer_demosaic.so.2.1.0 +0 -0
  69. holoscan-2.1.0.data/purelib/holoscan/lib/libholoscan_op_format_converter.so.2.1.0 +0 -0
  70. holoscan-2.1.0.data/purelib/holoscan/lib/libholoscan_op_gxf_codelet.so.2.1.0 +0 -0
  71. holoscan-2.1.0.data/purelib/holoscan/lib/libholoscan_op_holoviz.so.2.1.0 +0 -0
  72. holoscan-2.1.0.data/purelib/holoscan/lib/libholoscan_op_inference.so.2.1.0 +0 -0
  73. holoscan-2.1.0.data/purelib/holoscan/lib/libholoscan_op_inference_processor.so.2.1.0 +0 -0
  74. holoscan-2.1.0.data/purelib/holoscan/lib/libholoscan_op_ping_rx.so.2.1.0 +0 -0
  75. holoscan-2.1.0.data/purelib/holoscan/lib/libholoscan_op_ping_tx.so.2.1.0 +0 -0
  76. holoscan-2.1.0.data/purelib/holoscan/lib/libholoscan_op_segmentation_postprocessor.so.2.1.0 +0 -0
  77. holoscan-2.1.0.data/purelib/holoscan/lib/libholoscan_op_v4l2.so.2.1.0 +0 -0
  78. holoscan-2.1.0.data/purelib/holoscan/lib/libholoscan_op_video_stream_recorder.so.2.1.0 +0 -0
  79. holoscan-2.1.0.data/purelib/holoscan/lib/libholoscan_op_video_stream_replayer.so.2.1.0 +0 -0
  80. holoscan-2.1.0.data/purelib/holoscan/lib/libholoscan_spdlog_logger.so.2.1.0 +0 -0
  81. holoscan-2.1.0.data/purelib/holoscan/lib/libholoscan_viz.so.2.1.0 +0 -0
  82. holoscan-2.1.0.data/purelib/holoscan/lib/libucm.so.0.0.0 +0 -0
  83. holoscan-2.1.0.data/purelib/holoscan/lib/libucp.so.0.0.0 +0 -0
  84. holoscan-2.1.0.data/purelib/holoscan/lib/libucs.so.0.0.0 +0 -0
  85. holoscan-2.1.0.data/purelib/holoscan/lib/libucs_signal.so.0.0.0 +0 -0
  86. holoscan-2.1.0.data/purelib/holoscan/lib/libuct.so.0.0.0 +0 -0
  87. holoscan-2.1.0.data/purelib/holoscan/lib/libyaml-cpp.so.0.7.0 +0 -0
  88. holoscan-2.1.0.data/purelib/holoscan/lib/ucx/libucm_cuda.so.0.0.0 +0 -0
  89. holoscan-2.1.0.data/purelib/holoscan/lib/ucx/libuct_cma.so.0.0.0 +0 -0
  90. holoscan-2.1.0.data/purelib/holoscan/lib/ucx/libuct_cuda.so.0.0.0 +0 -0
  91. holoscan-2.1.0.data/purelib/holoscan/lib/ucx/libuct_cuda_gdrcopy.so.0.0.0 +0 -0
  92. holoscan-2.1.0.data/purelib/holoscan/lib/ucx/libuct_ib.so.0.0.0 +0 -0
  93. holoscan-2.1.0.data/purelib/holoscan/lib/ucx/libuct_rdmacm.so.0.0.0 +0 -0
  94. holoscan-2.1.0.data/purelib/holoscan/lib/ucx/libucx_perftest_cuda.so.0.0.0 +0 -0
  95. holoscan-2.1.0.data/purelib/holoscan/logger/__init__.py +37 -0
  96. holoscan-2.1.0.data/purelib/holoscan/logger/_logger.cpython-38-aarch64-linux-gnu.so +0 -0
  97. holoscan-2.1.0.data/purelib/holoscan/network_contexts/__init__.py +28 -0
  98. holoscan-2.1.0.data/purelib/holoscan/network_contexts/_network_contexts.cpython-38-aarch64-linux-gnu.so +0 -0
  99. holoscan-2.1.0.data/purelib/holoscan/operators/__init__.py +93 -0
  100. holoscan-2.1.0.data/purelib/holoscan/operators/aja_source/__init__.py +22 -0
  101. holoscan-2.1.0.data/purelib/holoscan/operators/aja_source/_aja_source.cpython-38-aarch64-linux-gnu.so +0 -0
  102. holoscan-2.1.0.data/purelib/holoscan/operators/bayer_demosaic/__init__.py +24 -0
  103. holoscan-2.1.0.data/purelib/holoscan/operators/bayer_demosaic/_bayer_demosaic.cpython-38-aarch64-linux-gnu.so +0 -0
  104. holoscan-2.1.0.data/purelib/holoscan/operators/format_converter/__init__.py +23 -0
  105. holoscan-2.1.0.data/purelib/holoscan/operators/format_converter/_format_converter.cpython-38-aarch64-linux-gnu.so +0 -0
  106. holoscan-2.1.0.data/purelib/holoscan/operators/gxf_codelet/__init__.py +67 -0
  107. holoscan-2.1.0.data/purelib/holoscan/operators/gxf_codelet/_gxf_codelet.cpython-38-aarch64-linux-gnu.so +0 -0
  108. holoscan-2.1.0.data/purelib/holoscan/operators/holoviz/__init__.py +230 -0
  109. holoscan-2.1.0.data/purelib/holoscan/operators/holoviz/_holoviz.cpython-38-aarch64-linux-gnu.so +0 -0
  110. holoscan-2.1.0.data/purelib/holoscan/operators/inference/__init__.py +23 -0
  111. holoscan-2.1.0.data/purelib/holoscan/operators/inference/_inference.cpython-38-aarch64-linux-gnu.so +0 -0
  112. holoscan-2.1.0.data/purelib/holoscan/operators/inference_processor/__init__.py +23 -0
  113. holoscan-2.1.0.data/purelib/holoscan/operators/inference_processor/_inference_processor.cpython-38-aarch64-linux-gnu.so +0 -0
  114. holoscan-2.1.0.data/purelib/holoscan/operators/ping_rx/__init__.py +45 -0
  115. holoscan-2.1.0.data/purelib/holoscan/operators/ping_tx/__init__.py +46 -0
  116. holoscan-2.1.0.data/purelib/holoscan/operators/segmentation_postprocessor/__init__.py +23 -0
  117. holoscan-2.1.0.data/purelib/holoscan/operators/segmentation_postprocessor/_segmentation_postprocessor.cpython-38-aarch64-linux-gnu.so +0 -0
  118. holoscan-2.1.0.data/purelib/holoscan/operators/v4l2_video_capture/__init__.py +23 -0
  119. holoscan-2.1.0.data/purelib/holoscan/operators/v4l2_video_capture/_v4l2_video_capture.cpython-38-aarch64-linux-gnu.so +0 -0
  120. holoscan-2.1.0.data/purelib/holoscan/operators/video_stream_recorder/__init__.py +22 -0
  121. holoscan-2.1.0.data/purelib/holoscan/operators/video_stream_recorder/_video_stream_recorder.cpython-38-aarch64-linux-gnu.so +0 -0
  122. holoscan-2.1.0.data/purelib/holoscan/operators/video_stream_replayer/__init__.py +22 -0
  123. holoscan-2.1.0.data/purelib/holoscan/operators/video_stream_replayer/_video_stream_replayer.cpython-38-aarch64-linux-gnu.so +0 -0
  124. holoscan-2.1.0.data/purelib/holoscan/resources/__init__.py +138 -0
  125. holoscan-2.1.0.data/purelib/holoscan/resources/_resources.cpython-38-aarch64-linux-gnu.so +0 -0
  126. holoscan-2.1.0.data/purelib/holoscan/schedulers/__init__.py +32 -0
  127. holoscan-2.1.0.data/purelib/holoscan/schedulers/_schedulers.cpython-38-aarch64-linux-gnu.so +0 -0
  128. holoscan-2.1.0.data/purelib/holoscan-2.1.0.pth +1 -0
  129. holoscan-2.1.0.dist-info/LICENSE.txt +202 -0
  130. holoscan-2.1.0.dist-info/METADATA +111 -0
  131. holoscan-2.1.0.dist-info/NOTICE.txt +170 -0
  132. holoscan-2.1.0.dist-info/NVIDIA-AI-PRODUCT-EULA.txt +243 -0
  133. holoscan-2.1.0.dist-info/RECORD +138 -0
  134. holoscan-2.1.0.dist-info/WHEEL +5 -0
  135. holoscan-2.1.0.dist-info/axle.lck +0 -0
  136. holoscan-2.1.0.dist-info/entry_points.txt +3 -0
  137. holoscan-2.1.0.dist-info/symlinks.txt +72 -0
  138. holoscan-2.1.0.dist-info/top_level.txt +3 -0
@@ -0,0 +1,18 @@
1
+ """
2
+ SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3
+ SPDX-License-Identifier: Apache-2.0
4
+
5
+ Licensed under the Apache License, Version 2.0 (the "License");
6
+ you may not use this file except in compliance with the License.
7
+ You may obtain a copy of the License at
8
+
9
+ http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ Unless required by applicable law or agreed to in writing, software
12
+ distributed under the License is distributed on an "AS IS" BASIS,
13
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ See the License for the specific language governing permissions and
15
+ limitations under the License.
16
+ """ # noqa: E501
17
+
18
+ from .runner import execute_run_command # noqa: F401
@@ -0,0 +1,174 @@
1
+ """
2
+ SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3
+ SPDX-License-Identifier: Apache-2.0
4
+
5
+ Licensed under the Apache License, Version 2.0 (the "License");
6
+ you may not use this file except in compliance with the License.
7
+ You may obtain a copy of the License at
8
+
9
+ http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ Unless required by applicable law or agreed to in writing, software
12
+ distributed under the License is distributed on an "AS IS" BASIS,
13
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ See the License for the specific language governing permissions and
15
+ limitations under the License.
16
+ """ # noqa: E501
17
+
18
+ import logging
19
+ import re
20
+ from typing import Dict, Optional, Union
21
+
22
+ from ..common.constants import Constants, DefaultValues
23
+ from ..common.exceptions import InvalidSharedMemoryValueError
24
+
25
+ logger = logging.getLogger("runner")
26
+
27
+
28
+ def get_shared_memory_size(
29
+ pkg_info: dict, worker: bool, driver: bool, fragments: str, user_shm_size: Optional[str]
30
+ ) -> Optional[float]:
31
+ """Queries the pkg.json file for shared memory requirement of the application
32
+
33
+ Args:
34
+ pkg_info (dict): package manifest
35
+ worker (bool): start the application as App Worker
36
+ driver (bool): start the application as App Driver
37
+ fragments (str): comma-separated list of fragments
38
+ user_shm_size (Optional[str]): user provided share memory size
39
+
40
+ Returns:
41
+ float: shared memory value in bytes
42
+ """
43
+
44
+ if user_shm_size == "config":
45
+ return _read_shm_size_from_config(pkg_info, worker, driver, fragments)
46
+ elif user_shm_size is not None:
47
+ return _convert_to_bytes(user_shm_size)
48
+ else:
49
+ return None
50
+
51
+
52
+ def _read_shm_size_from_config(pkg_info: dict, worker: bool, driver: bool, fragments: str) -> float:
53
+ """Queries the pkg.json file for shared memory requirement of the application
54
+
55
+ Args:
56
+ pkg_info (dict): package manifest
57
+ worker (bool): start the application as App Worker
58
+ driver (bool): start the application as App Driver
59
+ fragments (str): comma-separated list of fragments
60
+
61
+ Returns:
62
+ float: shared memory value in bytes
63
+ """
64
+ resources = pkg_info.get("resources") if pkg_info is not None else None
65
+
66
+ if resources is None:
67
+ return DefaultValues.DEFAULT_SHM_SIZE
68
+
69
+ max_value: float = 0
70
+ global_shared_memory_size = _convert_to_bytes(
71
+ resources.get(Constants.RESOURCE_SHARED_MEMORY_KEY, DefaultValues.DEFAULT_SHM_SIZE)
72
+ )
73
+
74
+ resources_fragments = resources.get("fragments", {})
75
+ if worker:
76
+ if fragments is None or fragments.lower() == "all":
77
+ max_value = _find_maximum_shared_memory_value_from_all_fragments(resources_fragments)
78
+ else:
79
+ max_value = _find_maximum_shared_memory_value_from_matching_fragments(
80
+ resources_fragments, fragments
81
+ )
82
+ max_value = max(max_value, global_shared_memory_size)
83
+ else:
84
+ if driver:
85
+ max_value = global_shared_memory_size
86
+ else:
87
+ max_value = _find_maximum_shared_memory_value_from_all_fragments(resources_fragments)
88
+ max_value = max(max_value, global_shared_memory_size)
89
+
90
+ return max_value
91
+
92
+
93
+ def _find_maximum_shared_memory_value_from_matching_fragments(
94
+ resources_fragments: Dict, fragments: str
95
+ ) -> Optional[float]:
96
+ """Scan matching fragments for the maximum shared memory value.
97
+
98
+ Args:
99
+ resources_fragments (Dict): fragment resources; resources->fragments
100
+ fragments (str): comma-separated list of fragments to match
101
+
102
+ Returns:
103
+ Optional[float]: maximum shred memory value or zero if no fragments found.
104
+ """
105
+ user_fragments = fragments.split(",")
106
+ fragment_values = [
107
+ _convert_to_bytes(val[Constants.RESOURCE_SHARED_MEMORY_KEY])
108
+ for key, val in resources_fragments.items()
109
+ if Constants.RESOURCE_SHARED_MEMORY_KEY in val and key in user_fragments
110
+ ]
111
+
112
+ if fragment_values:
113
+ return max(fragment_values)
114
+ else:
115
+ return 0
116
+
117
+
118
+ def _find_maximum_shared_memory_value_from_all_fragments(
119
+ resources_fragments: Dict,
120
+ ) -> Optional[float]:
121
+ """Scan all fragments for the maximum shared memory value.
122
+
123
+ Args:
124
+ resources_fragments (Dict): fragment resources; resources->fragments
125
+
126
+ Returns:
127
+ Optional[float]: maximum shred memory value or zero if no fragments found.
128
+ """
129
+ fragment_values = [
130
+ _convert_to_bytes(val[Constants.RESOURCE_SHARED_MEMORY_KEY])
131
+ for _, val in resources_fragments.items()
132
+ if Constants.RESOURCE_SHARED_MEMORY_KEY in val
133
+ ]
134
+
135
+ if fragment_values:
136
+ return max(fragment_values)
137
+ else:
138
+ return 0
139
+
140
+
141
+ def _convert_to_bytes(raw_value: Union[str, float, int]) -> float:
142
+ """Converts data measurements in string to float.
143
+
144
+ Supported units are Mi|MiB (mebibytes), Gi|GiB (gibibytes), MB|m (megabytes) and
145
+ GB|g (gigabytes)
146
+
147
+ Args:
148
+ raw_value (str): data measurement with a number and a supporting unit.
149
+
150
+ Returns:
151
+ float: number of bytes
152
+ """
153
+
154
+ if type(raw_value) in [float, int]:
155
+ return raw_value
156
+
157
+ result = re.search(r"([.\d]+)\s*(Mi|MiB|Gi|GiB|MB|GB|m|g)", raw_value)
158
+
159
+ if result is not None:
160
+ value = float(result.group(1))
161
+ if result.group(2) in ["Mi", "MiB"]:
162
+ return value * 1048576
163
+ if result.group(2) in ["Gi", "GiB"]:
164
+ return value * 1073741824
165
+ if result.group(2) == "MB":
166
+ return value * 1000000
167
+ if result.group(2) == "GB":
168
+ return value * 1000000000
169
+ if result.group(2) == "m":
170
+ return value * 1000000
171
+ if result.group(2) == "g":
172
+ return value * 1000000000
173
+
174
+ raise InvalidSharedMemoryValueError(f"Invalid/unsupported shared memory value: {raw_value}. ")
@@ -0,0 +1,204 @@
1
+ """
2
+ SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3
+ SPDX-License-Identifier: Apache-2.0
4
+
5
+ Licensed under the Apache License, Version 2.0 (the "License");
6
+ you may not use this file except in compliance with the License.
7
+ You may obtain a copy of the License at
8
+
9
+ http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ Unless required by applicable law or agreed to in writing, software
12
+ distributed under the License is distributed on an "AS IS" BASIS,
13
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ See the License for the specific language governing permissions and
15
+ limitations under the License.
16
+ """ # noqa: E501
17
+
18
+ import logging
19
+ import os
20
+ from argparse import ArgumentParser, HelpFormatter, _SubParsersAction
21
+ from typing import List
22
+
23
+ from ..common import argparse_types
24
+ from ..common.argparse_types import valid_existing_path
25
+
26
+ logger = logging.getLogger("runner")
27
+
28
+
29
+ def create_run_parser(
30
+ subparser: _SubParsersAction, command: str, parents: List[ArgumentParser]
31
+ ) -> ArgumentParser:
32
+ parser: ArgumentParser = subparser.add_parser(
33
+ command, formatter_class=HelpFormatter, parents=parents, add_help=False
34
+ )
35
+
36
+ parser.add_argument("map", metavar="<image[:tag]>", help="HAP/MAP image name.")
37
+
38
+ parser.add_argument(
39
+ "--address",
40
+ dest="address",
41
+ help="address ('[<IP or hostname>][:<port>]') of the App Driver. If not specified, "
42
+ "the App Driver uses the default host address ('0.0.0.0') with the default port "
43
+ "number ('8765').",
44
+ )
45
+
46
+ parser.add_argument(
47
+ "--driver",
48
+ dest="driver",
49
+ action="store_true",
50
+ default=False,
51
+ help="run the App Driver on the current machine. Can be used together with the "
52
+ "'--worker' option "
53
+ "to run both the App Driver and the App Worker on the same machine.",
54
+ )
55
+
56
+ parser.add_argument(
57
+ "-i",
58
+ "--input",
59
+ metavar="<input>",
60
+ type=argparse_types.valid_dir_path,
61
+ help="input data directory path.",
62
+ required=False,
63
+ )
64
+
65
+ parser.add_argument(
66
+ "-o",
67
+ "--output",
68
+ metavar="<output>",
69
+ type=argparse_types.valid_dir_path,
70
+ help="output data directory path.",
71
+ required=False,
72
+ )
73
+
74
+ parser.add_argument(
75
+ "-f",
76
+ "--fragments",
77
+ dest="fragments",
78
+ help="comma-separated names of the fragments to be executed by the App Worker. "
79
+ "If not specified, only one fragment (selected by the App Driver) will be executed. "
80
+ "'all' can be used to run all the fragments.",
81
+ )
82
+
83
+ parser.add_argument(
84
+ "--worker",
85
+ dest="worker",
86
+ action="store_true",
87
+ default=False,
88
+ help="run the App Worker.",
89
+ )
90
+
91
+ parser.add_argument(
92
+ "--worker-address",
93
+ dest="worker_address",
94
+ help="address (`[<IP or hostname>][:<port>]`) of the App Worker. If not specified, the App "
95
+ "Worker uses the default host address ('0.0.0.0') with a randomly chosen port number "
96
+ "between 10000 and 32767 that is not currently in use.",
97
+ )
98
+
99
+ advanced_group = parser.add_argument_group(title="advanced run options")
100
+
101
+ advanced_group.add_argument(
102
+ "--config",
103
+ dest="config",
104
+ type=valid_existing_path,
105
+ help="path to the configuration file. This will override the configuration file embedded "
106
+ "in the application.",
107
+ )
108
+
109
+ advanced_group.add_argument(
110
+ "--name",
111
+ dest="name",
112
+ help="name and hostname of the container to create.",
113
+ )
114
+ advanced_group.add_argument(
115
+ "-n",
116
+ "--network",
117
+ dest="network",
118
+ default="host",
119
+ help="name of the Docker network this application will be connected to. (default: host)",
120
+ )
121
+ advanced_group.add_argument(
122
+ "--nic",
123
+ dest="nic",
124
+ help="name of the network interface to use with a distributed multi-fragment application. "
125
+ "This option sets UCX_NET_DEVICES environment variable with the value specified.",
126
+ )
127
+ advanced_group.add_argument(
128
+ "--use-all-nics",
129
+ dest="use_all_nics",
130
+ action="store_true",
131
+ default=False,
132
+ help="allow UCX to control the selection of network interface cards for data "
133
+ "transfer. Otherwise, the network interface card specified with '--nic' is used. "
134
+ "This option sets UCX_CM_USE_ALL_DEVICES to 'y'. (default: False)",
135
+ )
136
+ advanced_group.add_argument(
137
+ "-r",
138
+ "--render",
139
+ dest="render",
140
+ action="store_true",
141
+ default=False,
142
+ help="enable rendering (default: False); runs the container with required flags to enable "
143
+ "rendering of graphics.",
144
+ )
145
+ advanced_group.add_argument(
146
+ "-q",
147
+ "--quiet",
148
+ dest="quiet",
149
+ action="store_true",
150
+ default=False,
151
+ help="suppress the STDOUT and print only STDERR from the application. (default: False)",
152
+ )
153
+ advanced_group.add_argument(
154
+ "--shm-size",
155
+ dest="shm_size",
156
+ help="set the size of /dev/shm. The format is "
157
+ "<number(int,float)>[MB|m|GB|g|Mi|MiB|Gi|GiB]. "
158
+ "Use 'config' to read the shared memory value defined in the app.json manifest. "
159
+ "If not specified, the container is launched using '--ipc=host' with host system's "
160
+ "/dev/shm mounted.",
161
+ )
162
+ advanced_group.add_argument(
163
+ "--terminal",
164
+ dest="terminal",
165
+ action="store_true",
166
+ default=False,
167
+ help="enter terminal with all configured volume mappings and environment variables. "
168
+ "(default: False)",
169
+ )
170
+ advanced_group.add_argument(
171
+ "--device",
172
+ dest="device",
173
+ nargs="+",
174
+ action="extend",
175
+ help="""Mount additional devices.
176
+ For example:
177
+ --device ajantv* to mount all AJA capture cards.
178
+ --device ajantv0 ajantv1 to mount AJA capture card 0 and 1.
179
+ --device video1 to mount V4L2 video device 1. """,
180
+ )
181
+ advanced_group.add_argument(
182
+ "--gpus",
183
+ dest="gpus",
184
+ help="""Override the value of NVIDIA_VISIBLE_DEVICES environment variable.
185
+ default: the value specified in the package manifest file or 'all' if not specified.
186
+ Refer to https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/docker-specialized.html#gpu-enumeration
187
+ for all available options.""",
188
+ )
189
+
190
+ user_group = parser.add_argument_group(title="security options")
191
+ user_group.add_argument(
192
+ "--uid",
193
+ type=str,
194
+ default=os.getuid(),
195
+ help=f"run the container with the UID. (default:{os.getuid()})",
196
+ )
197
+ user_group.add_argument(
198
+ "--gid",
199
+ type=str,
200
+ default=os.getgid(),
201
+ help=f"run the container with the GID. (default:{os.getgid()})",
202
+ )
203
+
204
+ return parser
@@ -0,0 +1,306 @@
1
+ """
2
+ SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3
+ SPDX-License-Identifier: Apache-2.0
4
+
5
+ Licensed under the Apache License, Version 2.0 (the "License");
6
+ you may not use this file except in compliance with the License.
7
+ You may obtain a copy of the License at
8
+
9
+ http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ Unless required by applicable law or agreed to in writing, software
12
+ distributed under the License is distributed on an "AS IS" BASIS,
13
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ See the License for the specific language governing permissions and
15
+ limitations under the License.
16
+ """ # noqa: E501
17
+
18
+ import json
19
+ import logging
20
+ import os
21
+ import re
22
+ import shutil
23
+ import sys
24
+ import tempfile
25
+ from argparse import Namespace
26
+ from glob import glob
27
+ from pathlib import Path
28
+ from typing import List, Optional, Tuple
29
+
30
+ from ..common.dockerutils import create_or_use_network, docker_run, image_exists
31
+ from ..common.exceptions import ManifestReadError, UnmatchedDeviceError
32
+ from ..common.utils import (
33
+ compare_versions,
34
+ get_requested_gpus,
35
+ print_manifest_json,
36
+ run_cmd,
37
+ run_cmd_output,
38
+ )
39
+ from .resources import get_shared_memory_size
40
+
41
+ logger = logging.getLogger("runner")
42
+
43
+
44
+ def _fetch_map_manifest(map_name: str) -> Tuple[dict, dict]:
45
+ """
46
+ Execute HAP/MAP and fetch the manifest files.
47
+
48
+ Args:
49
+ map_name: HAP/MAP image name.
50
+
51
+ Returns:
52
+ app_info: application manifest as a python dict
53
+ pkg_info: package manifest as a python dict
54
+ returncode: command return code
55
+ """
56
+ logger.info("Reading HAP/MAP manifest...")
57
+
58
+ with tempfile.TemporaryDirectory() as info_dir:
59
+ cmd = f"""docker_id=$(docker create {map_name})
60
+ docker cp $docker_id:/etc/holoscan/app.json "{info_dir}/app.json"
61
+ docker cp $docker_id:/etc/holoscan/pkg.json "{info_dir}/pkg.json"
62
+ docker rm -v $docker_id > /dev/null
63
+ """
64
+ returncode = run_cmd(cmd)
65
+ if returncode != 0:
66
+ raise ManifestReadError("Error reading manifest file form the package.")
67
+
68
+ app_json = Path(f"{info_dir}/app.json")
69
+ pkg_json = Path(f"{info_dir}/pkg.json")
70
+
71
+ app_info = json.loads(app_json.read_text())
72
+ pkg_info = json.loads(pkg_json.read_text())
73
+
74
+ print_manifest_json(app_info, "app.json")
75
+ print_manifest_json(pkg_info, "pkg.json")
76
+
77
+ return app_info, pkg_info
78
+
79
+
80
+ def _run_app(args: Namespace, app_info: dict, pkg_info: dict):
81
+ """
82
+ Executes the Holoscan Application.
83
+
84
+ Args:
85
+ args: user arguments
86
+ app_info: application manifest dictionary
87
+ pkg_info: package manifest dictionary
88
+
89
+ Returns:
90
+ returncode: command returncode
91
+ """
92
+
93
+ map_name: str = args.map
94
+ input_path: Path = args.input
95
+ output_path: Path = args.output
96
+ quiet: bool = args.quiet
97
+ driver: bool = args.driver
98
+ worker: bool = args.worker
99
+ fragments: str = args.fragments if args.fragments else None
100
+ network: str = create_or_use_network(args.network, map_name)
101
+ nic: str = args.nic if args.nic else None
102
+ use_all_nics: bool = args.use_all_nics
103
+ gpus: str = args.gpus if args.gpus else None
104
+ config: Path = args.config if args.config else None
105
+ address: str = args.address if args.address else None
106
+ worker_address: str = args.worker_address if args.worker_address else None
107
+ render: bool = args.render
108
+ user: str = f"{args.uid}:{args.gid}"
109
+ hostname: str = None
110
+ terminal: bool = args.terminal
111
+ platform_config: str = pkg_info["platformConfig"] if "platformConfig" in pkg_info else None
112
+ shared_memory_size: Optional[str] = (
113
+ get_shared_memory_size(pkg_info, worker, driver, fragments, args.shm_size)
114
+ if args.shm_size
115
+ else None
116
+ )
117
+
118
+ commands = []
119
+ devices = _lookup_devices(args.device) if args.device else []
120
+
121
+ if driver:
122
+ commands.append("--driver")
123
+ logger.info("Application running in Driver mode")
124
+ if worker:
125
+ commands.append("--worker")
126
+ logger.info("Application running in Worker mode")
127
+ if fragments:
128
+ commands.append("--fragments")
129
+ commands.append(fragments)
130
+ logger.info(f"Configured fragments: {fragments}")
131
+ if address:
132
+ commands.append("--address")
133
+ commands.append(address)
134
+ logger.info(f"App Driver address and port: {address}")
135
+ if worker_address:
136
+ commands.append("--worker_address")
137
+ commands.append(worker_address)
138
+ logger.info(f"App Worker address and port: {worker_address}")
139
+
140
+ if driver:
141
+ hostname = "driver"
142
+
143
+ docker_run(
144
+ hostname,
145
+ map_name,
146
+ input_path,
147
+ output_path,
148
+ app_info,
149
+ pkg_info,
150
+ quiet,
151
+ commands,
152
+ network,
153
+ nic,
154
+ use_all_nics,
155
+ gpus,
156
+ config,
157
+ render,
158
+ user,
159
+ terminal,
160
+ devices,
161
+ platform_config,
162
+ shared_memory_size,
163
+ args.uid == 0,
164
+ )
165
+
166
+
167
+ def _lookup_devices(devices: List[str]) -> List[str]:
168
+ """
169
+ Looks up matching devices in /dev and returns a list
170
+ of fully qualified device paths.
171
+
172
+ Raises exception if any devices cannot be found.
173
+ """
174
+ matched_devices = []
175
+ unmatched_devices = []
176
+
177
+ for dev in devices:
178
+ pattern = dev
179
+ if not pattern.startswith("/"):
180
+ pattern = "/dev/" + pattern
181
+ found_devices = glob(pattern)
182
+ if len(found_devices) == 0:
183
+ unmatched_devices.append(dev)
184
+ else:
185
+ matched_devices.extend(found_devices)
186
+
187
+ if len(unmatched_devices) > 0:
188
+ raise UnmatchedDeviceError(unmatched_devices)
189
+
190
+ return matched_devices
191
+
192
+
193
+ def _dependency_verification(map_name: str) -> bool:
194
+ """Check if all the dependencies are installed or not.
195
+
196
+ Args:
197
+ map_name: HAP/MAP name
198
+
199
+ Returns:
200
+ True if all dependencies are satisfied, otherwise False.
201
+ """
202
+ logger.info("Checking dependencies...")
203
+
204
+ # check for docker
205
+ prog = "docker"
206
+ logger.info('--> Verifying if "%s" is installed...\n', prog)
207
+ if not shutil.which(prog):
208
+ logger.error(
209
+ '"%s" not installed, please install it from https://docs.docker.com/engine/install/.',
210
+ prog,
211
+ )
212
+ return False
213
+
214
+ buildx_paths = [
215
+ os.path.expandvars("$HOME/.docker/cli-plugins"),
216
+ "/usr/local/lib/docker/cli-plugins",
217
+ "/usr/local/libexec/docker/cli-plugins",
218
+ "/usr/lib/docker/cli-plugins",
219
+ "/usr/libexec/docker/cli-plugins",
220
+ ]
221
+ prog = "docker-buildx"
222
+ logger.info('--> Verifying if "%s" is installed...\n', prog)
223
+ buildx_found = False
224
+ for path in buildx_paths:
225
+ if shutil.which(os.path.join(path, prog)):
226
+ buildx_found = True
227
+
228
+ if not buildx_found:
229
+ logger.error(
230
+ '"%s" not installed, please install it from https://docs.docker.com/engine/install/.',
231
+ prog,
232
+ )
233
+ return False
234
+
235
+ # check for map image
236
+ logger.info('--> Verifying if "%s" is available...\n', map_name)
237
+ if not image_exists(map_name):
238
+ logger.error("Unable to fetch required image.")
239
+ return False
240
+
241
+ return True
242
+
243
+
244
+ def _pkg_specific_dependency_verification(pkg_info: dict) -> bool:
245
+ """Checks for any package specific dependencies.
246
+
247
+ Currently it verifies the following dependencies:
248
+ * If gpu has been requested by the application, verify that nvidia-ctk is installed.
249
+ Note: when running inside a Docker container, always assume nvidia-ctk is installed.
250
+ Args:
251
+ pkg_info: package manifest as a python dict
252
+
253
+ Returns:
254
+ True if all dependencies are satisfied, otherwise False.
255
+ """
256
+ if os.path.exists("/.dockerenv"):
257
+ logger.info("--> Skipping nvidia-ctk check inside Docker...\n")
258
+ return True
259
+
260
+ requested_gpus = get_requested_gpus(pkg_info)
261
+ if requested_gpus > 0:
262
+ # check for NVIDIA Container TOolkit
263
+ prog = "nvidia-ctk"
264
+ logger.info('--> Verifying if "%s" is installed...\n', prog)
265
+ if not shutil.which(prog):
266
+ logger.error('"%s" not installed, please install NVIDIA Container Toolkit.', prog)
267
+ return False
268
+
269
+ logger.info('--> Verifying "%s" version...\n', prog)
270
+ output = run_cmd_output("nvidia-ctk --version | grep version")
271
+ match = re.search(r"([0-9]+\.[0-9]+\.[0-9]+)", output)
272
+ min_ctk_version = "1.12.0"
273
+ recommended_ctk_version = "1.14.1"
274
+ if compare_versions(min_ctk_version, match.group()) > 0:
275
+ logger.error(
276
+ f"Found '{prog}' Version {match.group()}. "
277
+ f"Version {min_ctk_version}+ is required ({recommended_ctk_version}+ recommended)."
278
+ )
279
+ return False
280
+
281
+ return True
282
+
283
+
284
+ def execute_run_command(args: Namespace):
285
+ if not _dependency_verification(args.map):
286
+ logger.error("Execution Aborted")
287
+ sys.exit(1)
288
+
289
+ try:
290
+ # Fetch application manifest from MAP
291
+ app_info, pkg_info = _fetch_map_manifest(args.map)
292
+ except Exception as e:
293
+ logger.error(f"Failed to fetch MAP manifest: {e}")
294
+ sys.exit(1)
295
+
296
+ if not _pkg_specific_dependency_verification(pkg_info):
297
+ logger.error("Execution Aborted")
298
+ sys.exit(1)
299
+
300
+ try:
301
+ # Run Holoscan Application
302
+ _run_app(args, app_info, pkg_info)
303
+ except Exception as ex:
304
+ logger.debug(ex, exc_info=True)
305
+ logger.error(f"Error executing {args.map}: {ex}")
306
+ sys.exit(1)