From 5c346eddad1acc2d6b6a7cf661760279f63d274e Mon Sep 17 00:00:00 2001 From: HailoRT-Automation <98901220+HailoRT-Automation@users.noreply.github.com> Date: Sun, 8 Jan 2023 12:14:08 +0200 Subject: [PATCH] v4.12.0 (#6) Co-authored-by: HailoRT-Automation --- CMakeLists.txt | 22 - README.md | 8 + common/include/context_switch_defs.h | 66 +- common/include/control_protocol.h | 464 +-- common/include/d2h_events.h | 15 +- common/include/firmware_header_utils.h | 8 +- common/include/firmware_status.h | 49 +- common/include/user_config_common.h | 6 +- hailort/CMakeLists.txt | 73 +- hailort/LICENSE-3RD-PARTY.md | 3 +- hailort/common/circular_buffer.hpp | 7 +- hailort/common/file_utils.cpp | 2 +- hailort/common/filesystem.hpp | 30 + hailort/common/latency_meter.hpp | 12 +- hailort/common/os/posix/filesystem.cpp | 67 +- hailort/common/os/posix/socket.cpp | 4 +- hailort/common/os/windows/filesystem.cpp | 92 + hailort/common/utils.hpp | 38 +- hailort/drivers/common/hailo_ioctl_common.h | 75 +- hailort/drivers/win/include/Public.h | 2 +- hailort/hailort_service/CMakeLists.txt | 25 +- hailort/hailort_service/hailort.service | 7 +- .../hailort_service/hailort_rpc_service.cpp | 328 +- .../hailort_service/hailort_rpc_service.hpp | 32 +- hailort/hailort_service/hailort_service | 12 + hailort/hailort_service/hailort_service.cpp | 33 +- hailort/hailortcli/CMakeLists.txt | 8 +- hailort/hailortcli/board_config_command.cpp | 4 + hailort/hailortcli/command.cpp | 13 + hailort/hailortcli/command.hpp | 5 +- hailort/hailortcli/common.cpp | 21 +- hailort/hailortcli/common.hpp | 4 + .../download_action_list_command.cpp | 125 +- .../download_action_list_command.hpp | 30 +- hailort/hailortcli/fw_config_command.cpp | 6 +- hailort/hailortcli/fw_control_command.cpp | 8 +- hailort/hailortcli/fw_logger_command.cpp | 5 +- hailort/hailortcli/hailortcli.cpp | 24 +- hailort/hailortcli/mon_command.cpp | 111 +- hailort/hailortcli/run2/live_printer.cpp | 69 + hailort/hailortcli/run2/live_printer.hpp | 43 + .../hailortcli/run2/network_live_track.cpp | 33 + .../hailortcli/run2/network_live_track.hpp | 29 + hailort/hailortcli/run2/network_runner.cpp | 197 + hailort/hailortcli/run2/network_runner.hpp | 72 + hailort/hailortcli/run2/run2_command.cpp | 348 ++ hailort/hailortcli/run2/run2_command.hpp | 23 + hailort/hailortcli/run2/timer_live_track.cpp | 31 + hailort/hailortcli/run2/timer_live_track.hpp | 27 + hailort/hailortcli/run_command.cpp | 287 +- hailort/hailortcli/run_command.hpp | 34 +- hailort/hailortcli/scan_command.cpp | 6 - hailort/hailortcli/sensor_config_command.cpp | 4 + hailort/libhailort/CMakeLists.txt | 6 +- .../bindings/gstreamer/CMakeLists.txt | 4 +- hailort/libhailort/bindings/gstreamer/README | 6 +- .../bindings/gstreamer/gst-hailo/common.hpp | 6 +- .../gstreamer/gst-hailo/gsthailonet.cpp | 65 +- .../gstreamer/gst-hailo/gsthailonet.hpp | 6 +- .../gstreamer/gst-hailo/gsthailorecv.cpp | 11 + .../gstreamer/gst-hailo/gsthailorecv.hpp | 1 + .../gstreamer/gst-hailo/gsthailosend.cpp | 33 +- .../gstreamer/gst-hailo/gsthailosend.hpp | 1 + .../gst-hailo/network_group_handle.cpp | 106 +- .../gst-hailo/network_group_handle.hpp | 10 +- .../libhailort/bindings/python/CMakeLists.txt | 8 - .../examples/hef_infer_pipeline_vstream.py | 6 +- .../examples/hef_infer_virtual_stream.py | 16 +- .../platform/hailo_platform/__init__.py | 22 +- .../hailo_platform/pyhailort/hw_object.py | 38 +- .../hailo_platform/pyhailort/pyhailort.py | 179 +- .../tools/hailocli/hailo_device_utils.py | 8 - .../tools/hailocli/hailocli_commands.py | 6 + .../hailo_platform/tools/hailocli/main.py | 8 +- .../notebooks/HRT_0_Inference_Tutorial.ipynb | 4 +- .../HRT_1_Power_Measurement_Tutorial.ipynb | 6 +- .../bindings/python/platform/requirements.txt | 5 +- .../bindings/python/platform/setup.py | 5 +- .../bindings/python/src/CMakeLists.txt | 31 +- .../bindings/python/src/device_api.cpp | 7 + .../bindings/python/src/device_api.hpp | 1 + .../python/src/internal/CMakeLists.txt | 1 - .../src/internal/pyhailort_internal.cpp | 163 +- .../src/internal/pyhailort_internal.hpp | 1 + .../bindings/python/src/net_flow_api.hpp | 102 + .../bindings/python/src/pyhailort.cpp | 17 +- .../bindings/python/src/vdevice_api.hpp | 21 +- .../cmake/toolchains/toolchains.yaml | 23 +- hailort/libhailort/examples/CMakeLists.txt | 20 +- hailort/libhailort/examples/README.md | 24 +- hailort/libhailort/examples/c/CMakeLists.txt | 48 +- .../examples/c/{ => common}/common.h | 0 .../examples/c/{ => common}/hailo_thread.h | 0 .../data_quantization_example/CMakeLists.txt | 20 + .../data_quantization_example.c | 9 +- .../c/infer_pipeline_example/CMakeLists.txt | 20 + .../infer_pipeline_example.c | 5 +- .../c/multi_device_example/CMakeLists.txt | 20 + .../multi_device_example.c | 8 +- .../CMakeLists.txt | 20 + .../multi_network_vstream_example.c | 3 + .../power_measurement_example/CMakeLists.txt | 17 + .../power_measurement_example.c | 3 + .../c/raw_streams_example/CMakeLists.txt | 20 + .../raw_streams_example.c | 0 .../CMakeLists.txt | 20 + .../switch_network_groups_example.c | 13 +- .../CMakeLists.txt | 20 + .../switch_network_groups_manually_example.c} | 3 +- .../c/vstreams_example/CMakeLists.txt | 20 + .../{ => vstreams_example}/vstreams_example.c | 9 +- .../libhailort/examples/cpp/CMakeLists.txt | 43 +- .../cpp/infer_pipeline_example/CMakeLists.txt | 16 + .../infer_pipeline_example.cpp | 0 .../cpp/multi_device_example/CMakeLists.txt | 19 + .../multi_device_example.cpp | 6 - .../CMakeLists.txt | 19 + .../multi_network_vstream_example.cpp | 2 + .../cpp/multi_process_example/CMakeLists.txt | 19 + .../multi_process_example.cpp | 1 - .../multi_process_example.sh | 23 +- .../power_measurement_example/CMakeLists.txt | 16 + .../power_measurement_example.cpp | 3 + .../cpp/raw_streams_example/CMakeLists.txt | 19 + .../raw_streams_example.cpp | 0 .../CMakeLists.txt | 19 + .../switch_network_groups_example.cpp | 25 +- .../CMakeLists.txt | 19 + ...switch_network_groups_manually_example.cpp | 1 + .../cpp/vstreams_example/CMakeLists.txt | 19 + .../vstreams_example.cpp | 6 - hailort/libhailort/hef.proto | 190 + hailort/libhailort/include/hailo/device.hpp | 68 +- hailort/libhailort/include/hailo/hailort.h | 113 +- .../include/hailo/hailort_common.hpp | 30 +- hailort/libhailort/include/hailo/hef.hpp | 10 +- .../include/hailo/network_group.hpp | 5 +- .../libhailort/include/hailo/quantization.hpp | 25 +- hailort/libhailort/include/hailo/stream.hpp | 4 +- hailort/libhailort/include/hailo/vdevice.hpp | 18 +- hailort/libhailort/include/hailo/vstream.hpp | 20 +- hailort/libhailort/scheduler_mon.proto | 2 +- hailort/libhailort/src/CMakeLists.txt | 26 +- hailort/libhailort/src/buffer.cpp | 23 +- hailort/libhailort/src/channel_allocator.cpp | 20 +- hailort/libhailort/src/channel_allocator.hpp | 8 +- hailort/libhailort/src/config_buffer.cpp | 63 +- hailort/libhailort/src/config_buffer.hpp | 23 +- .../active_network_group_holder.hpp | 2 +- .../src/context_switch/config_manager.hpp | 59 - .../context_switch/context_switch_actions.cpp | 1327 +++++++ .../context_switch/context_switch_actions.hpp | 781 ++++ .../context_switch_buffer_builder.cpp | 71 + .../context_switch_buffer_builder.hpp | 42 + .../hcp_config_activated_network_group.cpp | 46 +- .../src/context_switch/hcp_config_manager.cpp | 157 - .../hcp_config_network_group.cpp | 55 +- .../src/context_switch/hef_metadata.cpp | 949 ----- .../src/context_switch/hef_metadata.hpp | 474 --- .../multi_context/resource_manager.hpp | 194 +- .../vdma_config_activated_network_group.hpp | 37 +- .../multi_context/vdma_config_manager.hpp | 72 +- .../vdma_config_network_group.hpp | 71 +- .../src/context_switch/network_group.cpp | 227 +- .../context_switch/network_group_internal.hpp | 82 +- .../context_switch/network_group_wrapper.cpp | 204 - .../context_switch/network_group_wrapper.hpp | 94 - .../src/context_switch/resource_manager.cpp | 510 +-- .../resource_manager_builder.cpp | 1217 ++++++ .../resource_manager_builder.hpp | 33 + .../hcp_config_activated_network_group.hpp | 23 +- .../single_context/hcp_config_manager.hpp | 53 - .../hcp_config_network_group.hpp | 15 +- .../context_switch/vdevice_network_group.cpp | 368 ++ .../context_switch/vdevice_network_group.hpp | 182 + .../vdma_config_activated_network_group.cpp | 94 +- .../context_switch/vdma_config_manager.cpp | 380 -- .../vdma_config_network_group.cpp | 261 +- hailort/libhailort/src/control.cpp | 234 +- hailort/libhailort/src/control.hpp | 38 +- hailort/libhailort/src/control_protocol.cpp | 137 +- hailort/libhailort/src/control_protocol.hpp | 45 +- hailort/libhailort/src/core_device.cpp | 59 +- hailort/libhailort/src/core_device.hpp | 14 +- hailort/libhailort/src/ddr_channels_pair.cpp | 2 +- hailort/libhailort/src/ddr_channels_pair.hpp | 3 +- hailort/libhailort/src/device.cpp | 102 +- hailort/libhailort/src/device_internal.cpp | 11 +- hailort/libhailort/src/device_internal.hpp | 3 +- hailort/libhailort/src/eth_device.cpp | 103 +- hailort/libhailort/src/eth_device.hpp | 7 +- hailort/libhailort/src/eth_stream.cpp | 30 +- hailort/libhailort/src/hailort.cpp | 202 +- hailort/libhailort/src/hailort_defaults.hpp | 20 +- hailort/libhailort/src/hailort_logger.cpp | 178 +- hailort/libhailort/src/hailort_logger.hpp | 13 +- hailort/libhailort/src/hailort_rpc_client.cpp | 340 +- hailort/libhailort/src/hailort_rpc_client.hpp | 21 +- hailort/libhailort/src/hef.cpp | 3285 +++++------------ hailort/libhailort/src/hef_internal.hpp | 739 +--- hailort/libhailort/src/hlpcie.cpp | 405 -- hailort/libhailort/src/hlpcie.hpp | 71 - hailort/libhailort/src/inference_pipeline.cpp | 12 +- hailort/libhailort/src/layer_info.hpp | 104 +- .../src/multi_device_scheduled_stream.cpp | 126 + .../src/multi_device_scheduled_stream.hpp | 183 + .../libhailort/src/net_flow/CMakeLists.txt | 1 + .../src/net_flow/ops/yolo_post_processing.hpp | 386 ++ .../libhailort/src/network_group_client.cpp | 75 +- .../libhailort/src/network_group_metadata.cpp | 463 +++ .../libhailort/src/network_group_metadata.hpp | 178 + .../src/network_group_scheduler.cpp | 1016 +++-- .../src/network_group_scheduler.hpp | 137 +- hailort/libhailort/src/os/CMakeLists.txt | 13 +- .../pcie_driver_scan.hpp => driver_scan.hpp} | 10 +- hailort/libhailort/src/os/hailort_driver.hpp | 79 +- .../src/os/posix/hailort_driver.cpp | 185 +- .../{pcie_driver_scan.cpp => driver_scan.cpp} | 22 +- .../src/os/posix/unix/driver_scan.cpp | 69 + .../src/os/posix/unix/pcie_driver_scan.cpp | 101 - .../libhailort/src/os/windows/driver_scan.cpp | 208 ++ .../src/os/windows/hailort_driver.cpp | 421 +-- hailort/libhailort/src/pcie_device.cpp | 172 +- hailort/libhailort/src/pcie_device.hpp | 19 +- hailort/libhailort/src/pipeline.cpp | 371 +- hailort/libhailort/src/pipeline.hpp | 157 +- .../pipeline_multiplexer.cpp | 129 +- .../pipeline_multiplexer.hpp | 17 +- .../src/scheduled_network_group.cpp | 391 ++ .../src/scheduled_network_group.hpp | 210 ++ hailort/libhailort/src/scheduled_stream.hpp | 115 + hailort/libhailort/src/scheduler_oracle.cpp | 74 + hailort/libhailort/src/scheduler_oracle.hpp | 34 + hailort/libhailort/src/stream.cpp | 10 +- hailort/libhailort/src/stream_internal.hpp | 5 +- hailort/libhailort/src/tracer.cpp | 232 ++ hailort/libhailort/src/tracer.hpp | 240 ++ hailort/libhailort/src/tracer_macros.hpp | 32 + hailort/libhailort/src/transform.cpp | 143 +- hailort/libhailort/src/udp.cpp | 4 +- hailort/libhailort/src/vdevice.cpp | 190 +- hailort/libhailort/src/vdevice_internal.hpp | 17 +- .../libhailort/src/vdevice_native_stream.hpp | 69 + hailort/libhailort/src/vdevice_stream.cpp | 536 +-- hailort/libhailort/src/vdevice_stream.hpp | 159 +- ...=> vdevice_stream_multiplexer_wrapper.cpp} | 145 +- ...=> vdevice_stream_multiplexer_wrapper.hpp} | 54 +- .../libhailort/src/vdma/continuous_buffer.cpp | 2 +- .../libhailort/src/vdma/continuous_buffer.hpp | 2 +- hailort/libhailort/src/vdma/mapped_buffer.cpp | 20 +- hailort/libhailort/src/vdma/mapped_buffer.hpp | 8 +- hailort/libhailort/src/vdma/sg_buffer.cpp | 19 +- hailort/libhailort/src/vdma/sg_buffer.hpp | 10 +- hailort/libhailort/src/vdma/vdma_buffer.hpp | 2 +- .../src/vdma/vdma_mapped_buffer_impl.cpp | 2 + hailort/libhailort/src/vdma_channel.cpp | 267 +- hailort/libhailort/src/vdma_channel.hpp | 68 +- .../libhailort/src/vdma_descriptor_list.cpp | 11 +- .../libhailort/src/vdma_descriptor_list.hpp | 6 +- hailort/libhailort/src/vdma_device.cpp | 204 +- hailort/libhailort/src/vdma_device.hpp | 18 +- hailort/libhailort/src/vdma_stream.cpp | 91 +- hailort/libhailort/src/vdma_stream.hpp | 19 +- hailort/libhailort/src/vstream.cpp | 643 +++- hailort/libhailort/src/vstream_internal.hpp | 123 +- hailort/pre_build/external/CMakeLists.txt | 5 +- hailort/prepare_externals.cmake | 22 + hailort/rpc/hailort_rpc.proto | 185 +- hailort/scripts/download_firmware_eth.cmd | 12 + hailort/scripts/download_firmware_eth.sh | 17 + hailort/scripts/download_hefs.cmd | 2 +- hailort/scripts/download_hefs.sh | 2 +- hailort/tools/hw_debug/CMakeLists.txt | 53 + hailort/tools/hw_debug/driver_memory.cpp | 127 + hailort/tools/hw_debug/driver_memory.hpp | 39 + .../mercury/dram_dma_engine_config_macros.h | 2270 ++++++++++++ .../mercury/dram_dma_engine_config_regs.h | 143 + .../mercury/dram_dma_package_macros.h | 92 + hailort/tools/hw_debug/main.cpp | 152 + hailort/tools/hw_debug/memory_commands.cpp | 106 + hailort/tools/hw_debug/memory_commands.hpp | 211 ++ hailort/tools/hw_debug/mercury_fields.cpp | 171 + hailort/tools/hw_debug/mercury_fields.hpp | 66 + hailort/tools/hw_debug/readline_wrapper.cpp | 110 + hailort/tools/hw_debug/readline_wrapper.hpp | 26 + hailort/tools/hw_debug/shell.cpp | 197 + hailort/tools/hw_debug/shell.hpp | 116 + 287 files changed, 20850 insertions(+), 11470 deletions(-) create mode 100644 hailort/hailort_service/hailort_service create mode 100644 hailort/hailortcli/run2/live_printer.cpp create mode 100644 hailort/hailortcli/run2/live_printer.hpp create mode 100644 hailort/hailortcli/run2/network_live_track.cpp create mode 100644 hailort/hailortcli/run2/network_live_track.hpp create mode 100644 hailort/hailortcli/run2/network_runner.cpp create mode 100644 hailort/hailortcli/run2/network_runner.hpp create mode 100644 hailort/hailortcli/run2/run2_command.cpp create mode 100644 hailort/hailortcli/run2/run2_command.hpp create mode 100644 hailort/hailortcli/run2/timer_live_track.cpp create mode 100644 hailort/hailortcli/run2/timer_live_track.hpp create mode 100644 hailort/libhailort/bindings/python/src/net_flow_api.hpp rename hailort/libhailort/examples/c/{ => common}/common.h (100%) rename hailort/libhailort/examples/c/{ => common}/hailo_thread.h (100%) create mode 100644 hailort/libhailort/examples/c/data_quantization_example/CMakeLists.txt rename hailort/libhailort/examples/c/{ => data_quantization_example}/data_quantization_example.c (96%) create mode 100644 hailort/libhailort/examples/c/infer_pipeline_example/CMakeLists.txt rename hailort/libhailort/examples/c/{ => infer_pipeline_example}/infer_pipeline_example.c (98%) create mode 100644 hailort/libhailort/examples/c/multi_device_example/CMakeLists.txt rename hailort/libhailort/examples/c/{ => multi_device_example}/multi_device_example.c (95%) create mode 100644 hailort/libhailort/examples/c/multi_network_vstream_example/CMakeLists.txt rename hailort/libhailort/examples/c/{ => multi_network_vstream_example}/multi_network_vstream_example.c (98%) create mode 100644 hailort/libhailort/examples/c/power_measurement_example/CMakeLists.txt rename hailort/libhailort/examples/c/{ => power_measurement_example}/power_measurement_example.c (97%) create mode 100644 hailort/libhailort/examples/c/raw_streams_example/CMakeLists.txt rename hailort/libhailort/examples/c/{ => raw_streams_example}/raw_streams_example.c (100%) create mode 100644 hailort/libhailort/examples/c/switch_network_groups_example/CMakeLists.txt rename hailort/libhailort/examples/c/{ => switch_network_groups_example}/switch_network_groups_example.c (94%) create mode 100644 hailort/libhailort/examples/c/switch_network_groups_manually_example/CMakeLists.txt rename hailort/libhailort/examples/c/{switch_single_io_network_groups_manually_example.c => switch_network_groups_manually_example/switch_network_groups_manually_example.c} (99%) create mode 100644 hailort/libhailort/examples/c/vstreams_example/CMakeLists.txt rename hailort/libhailort/examples/c/{ => vstreams_example}/vstreams_example.c (94%) create mode 100644 hailort/libhailort/examples/cpp/infer_pipeline_example/CMakeLists.txt rename hailort/libhailort/examples/cpp/{ => infer_pipeline_example}/infer_pipeline_example.cpp (100%) create mode 100644 hailort/libhailort/examples/cpp/multi_device_example/CMakeLists.txt rename hailort/libhailort/examples/cpp/{ => multi_device_example}/multi_device_example.cpp (95%) create mode 100644 hailort/libhailort/examples/cpp/multi_network_vstream_example/CMakeLists.txt rename hailort/libhailort/examples/cpp/{ => multi_network_vstream_example}/multi_network_vstream_example.cpp (98%) create mode 100644 hailort/libhailort/examples/cpp/multi_process_example/CMakeLists.txt rename hailort/libhailort/examples/cpp/{ => multi_process_example}/multi_process_example.cpp (98%) rename hailort/libhailort/examples/cpp/{ => multi_process_example}/multi_process_example.sh (67%) create mode 100644 hailort/libhailort/examples/cpp/power_measurement_example/CMakeLists.txt rename hailort/libhailort/examples/cpp/{ => power_measurement_example}/power_measurement_example.cpp (97%) create mode 100644 hailort/libhailort/examples/cpp/raw_streams_example/CMakeLists.txt rename hailort/libhailort/examples/cpp/{ => raw_streams_example}/raw_streams_example.cpp (100%) create mode 100644 hailort/libhailort/examples/cpp/switch_network_groups_example/CMakeLists.txt rename hailort/libhailort/examples/cpp/{ => switch_network_groups_example}/switch_network_groups_example.cpp (87%) create mode 100644 hailort/libhailort/examples/cpp/switch_network_groups_manually_example/CMakeLists.txt rename hailort/libhailort/examples/cpp/{ => switch_network_groups_manually_example}/switch_network_groups_manually_example.cpp (99%) create mode 100644 hailort/libhailort/examples/cpp/vstreams_example/CMakeLists.txt rename hailort/libhailort/examples/cpp/{ => vstreams_example}/vstreams_example.cpp (95%) delete mode 100644 hailort/libhailort/src/context_switch/config_manager.hpp create mode 100644 hailort/libhailort/src/context_switch/context_switch_actions.cpp create mode 100644 hailort/libhailort/src/context_switch/context_switch_actions.hpp create mode 100644 hailort/libhailort/src/context_switch/context_switch_buffer_builder.cpp create mode 100644 hailort/libhailort/src/context_switch/context_switch_buffer_builder.hpp delete mode 100644 hailort/libhailort/src/context_switch/hcp_config_manager.cpp delete mode 100644 hailort/libhailort/src/context_switch/hef_metadata.cpp delete mode 100644 hailort/libhailort/src/context_switch/hef_metadata.hpp delete mode 100644 hailort/libhailort/src/context_switch/network_group_wrapper.cpp delete mode 100644 hailort/libhailort/src/context_switch/network_group_wrapper.hpp create mode 100644 hailort/libhailort/src/context_switch/resource_manager_builder.cpp create mode 100644 hailort/libhailort/src/context_switch/resource_manager_builder.hpp delete mode 100644 hailort/libhailort/src/context_switch/single_context/hcp_config_manager.hpp create mode 100644 hailort/libhailort/src/context_switch/vdevice_network_group.cpp create mode 100644 hailort/libhailort/src/context_switch/vdevice_network_group.hpp delete mode 100644 hailort/libhailort/src/context_switch/vdma_config_manager.cpp delete mode 100644 hailort/libhailort/src/hlpcie.cpp delete mode 100644 hailort/libhailort/src/hlpcie.hpp create mode 100644 hailort/libhailort/src/multi_device_scheduled_stream.cpp create mode 100644 hailort/libhailort/src/multi_device_scheduled_stream.hpp create mode 100644 hailort/libhailort/src/net_flow/CMakeLists.txt create mode 100644 hailort/libhailort/src/net_flow/ops/yolo_post_processing.hpp create mode 100644 hailort/libhailort/src/network_group_metadata.cpp create mode 100644 hailort/libhailort/src/network_group_metadata.hpp rename hailort/libhailort/src/os/{posix/pcie_driver_scan.hpp => driver_scan.hpp} (75%) rename hailort/libhailort/src/os/posix/qnx/{pcie_driver_scan.cpp => driver_scan.cpp} (75%) create mode 100644 hailort/libhailort/src/os/posix/unix/driver_scan.cpp delete mode 100644 hailort/libhailort/src/os/posix/unix/pcie_driver_scan.cpp create mode 100644 hailort/libhailort/src/os/windows/driver_scan.cpp rename hailort/libhailort/src/{context_switch => }/pipeline_multiplexer.cpp (71%) rename hailort/libhailort/src/{context_switch => }/pipeline_multiplexer.hpp (84%) create mode 100644 hailort/libhailort/src/scheduled_network_group.cpp create mode 100644 hailort/libhailort/src/scheduled_network_group.hpp create mode 100644 hailort/libhailort/src/scheduled_stream.hpp create mode 100644 hailort/libhailort/src/scheduler_oracle.cpp create mode 100644 hailort/libhailort/src/scheduler_oracle.hpp create mode 100644 hailort/libhailort/src/tracer.cpp create mode 100644 hailort/libhailort/src/tracer.hpp create mode 100644 hailort/libhailort/src/tracer_macros.hpp create mode 100644 hailort/libhailort/src/vdevice_native_stream.hpp rename hailort/libhailort/src/{vdevice_stream_wrapper.cpp => vdevice_stream_multiplexer_wrapper.cpp} (57%) rename hailort/libhailort/src/{vdevice_stream_wrapper.hpp => vdevice_stream_multiplexer_wrapper.hpp} (63%) create mode 100644 hailort/prepare_externals.cmake create mode 100644 hailort/scripts/download_firmware_eth.cmd create mode 100755 hailort/scripts/download_firmware_eth.sh create mode 100644 hailort/tools/hw_debug/CMakeLists.txt create mode 100644 hailort/tools/hw_debug/driver_memory.cpp create mode 100644 hailort/tools/hw_debug/driver_memory.hpp create mode 100644 hailort/tools/hw_debug/hw_consts/mercury/dram_dma_engine_config_macros.h create mode 100644 hailort/tools/hw_debug/hw_consts/mercury/dram_dma_engine_config_regs.h create mode 100644 hailort/tools/hw_debug/hw_consts/mercury/dram_dma_package_macros.h create mode 100644 hailort/tools/hw_debug/main.cpp create mode 100644 hailort/tools/hw_debug/memory_commands.cpp create mode 100644 hailort/tools/hw_debug/memory_commands.hpp create mode 100644 hailort/tools/hw_debug/mercury_fields.cpp create mode 100644 hailort/tools/hw_debug/mercury_fields.hpp create mode 100644 hailort/tools/hw_debug/readline_wrapper.cpp create mode 100644 hailort/tools/hw_debug/readline_wrapper.hpp create mode 100644 hailort/tools/hw_debug/shell.cpp create mode 100644 hailort/tools/hw_debug/shell.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index c95ca7f..f44f4fc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,19 +1,5 @@ cmake_minimum_required(VERSION 3.0.0) -option(HAILO_BUILD_PYBIND "Build Python binding" OFF) -option(HAILO_BUILD_PYHAILORT_VENV "Build pyhailort in venv. Only used if HAILO_BUILD_PYBIND is on" ON) -option(HAILO_BUILD_EMULATOR "Build hailort for emulator" OFF) -option(HAILO_BUILD_UT "Build Unit Tests" OFF) -option(HAILO_BUILD_GSTREAMER "Compile gstreamer plugins" OFF) -option(HAILO_BUILD_EXAMPLES "Build examples" OFF) -option(HAILO_OFFLINE_COMPILATION "Don't download external dependencies" OFF) -option(HAILO_MICROPROFILE "Microprofile code" OFF) -option(HAILO_BUILD_SERVICE "Build hailort service" OFF) - -if(WIN32 AND ${HAILO_BUILD_SERVICE}) - message(FATAL_ERROR "HailoRT service is not supported on Windows") -endif() - find_program(CCACHE_PROGRAM ccache) if(CCACHE_PROGRAM) set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCACHE_PROGRAM}") @@ -67,14 +53,6 @@ else() message(FATAL_ERROR "Unexpeced host, stopping build") endif() -enable_testing() - -# Flag for emulator (FPGA/Veloce) -if(HAILO_BUILD_EMULATOR) - message(WARNING "HailoRT is building with Emulator flag on") - set(HAILORT_COMPILE_OPTIONS ${HAILORT_COMPILE_OPTIONS} -DHAILO_EMULATOR) -endif() - # Enable output of compile commands during generation set(CMAKE_EXPORT_COMPILE_COMMANDS ON) diff --git a/README.md b/README.md index 2f4ae55..fff49e1 100644 --- a/README.md +++ b/README.md @@ -23,12 +23,20 @@ HailoRT supports Linux and Windows, and can be compiled from sources to be integ See [**hailo.ai developer zone documentation**](https://hailo.ai/developer-zone/documentation/hailort/latest/) (registration is required for full documentation access). +For compilation instructions, see [**Compiling HailoRT from Sources**](https://hailo.ai/developer-zone/documentation/hailort/latest/?sp_referrer=install/install.html#compiling-from-sources). + For HailoRT API examples - see [**HailoRT examples**](https://github.com/hailo-ai/hailort/tree/master/hailort/libhailort/examples). ## Changelog See [**hailo.ai developer zone - HailoRT changelog**](https://hailo.ai/developer-zone/documentation/hailort/latest/?sp_referrer=changelog/changelog.html) (registration required). +## Licenses + +HailoRT uses 2 licenses: +- libhailort, pyhailort & hailortcli - distributed under the [**MIT license**](https://opensource.org/licenses/MIT) +- hailonet (GStreamer plugin) - distributed under the [**LGPL 2.1 license**](https://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt) + ## Contact Contact information and support is available at [**hailo.ai**](https://hailo.ai/contact-us/). diff --git a/common/include/context_switch_defs.h b/common/include/context_switch_defs.h index 7a15520..b7a0fe8 100644 --- a/common/include/context_switch_defs.h +++ b/common/include/context_switch_defs.h @@ -96,16 +96,25 @@ typedef enum __attribute__((packed)) { CONTEXT_SWITCH_DEFS__ACTION_TYPE_DEACTIVATE_CFG_CHANNEL, CONTEXT_SWITCH_DEFS__ACTION_TYPE_REPEATED_ACTION, CONTEXT_SWITCH_DEFS__ACTION_TYPE_WAIT_FOR_DMA_IDLE_ACTION, - CONTEXT_SWITCH_DEFS__ACTION_TYPE_WAIT_FOR_NMS_IDLE, + CONTEXT_SWITCH_DEFS__ACTION_TYPE_WAIT_FOR_NMS, CONTEXT_SWITCH_DEFS__ACTION_TYPE_FETCH_CCW_BURSTS, CONTEXT_SWITCH_DEFS__ACTION_TYPE_VALIDATE_VDMA_CHANNEL, CONTEXT_SWITCH_DEFS__ACTION_TYPE_BURST_CREDITS_TASK_START, CONTEXT_SWITCH_DEFS__ACTION_TYPE_DDR_BUFFERING_RESET, - + CONTEXT_SWITCH_DEFS__ACTION_TYPE_OPEN_BOUNDARY_INPUT_CHANNEL, + CONTEXT_SWITCH_DEFS__ACTION_TYPE_OPEN_BOUNDARY_OUTPUT_CHANNEL, + CONTEXT_SWITCH_DEFS__ACTION_TYPE_ENABLE_NMS, + /* Must be last */ CONTEXT_SWITCH_DEFS__ACTION_TYPE_COUNT } CONTEXT_SWITCH_DEFS__ACTION_TYPE_t; +typedef enum { + CONTEXT_SWITCH_DEFS__EDGE_LAYER_DIRECTION_UNINITIALIZED = 0, + CONTEXT_SWITCH_DEFS__EDGE_LAYER_DIRECTION_HOST_TO_DEVICE, + CONTEXT_SWITCH_DEFS__EDGE_LAYER_DIRECTION_DEVICE_TO_HOST, +} CONTEXT_SWITCH_DEFS__EDGE_LAYER_DIRECTION_t; + typedef struct { CONTEXT_SWITCH_DEFS__ACTION_TYPE_t action_type; uint32_t time_stamp; @@ -117,7 +126,7 @@ typedef struct { * 2) CONTEXT_SWITCH_DEFS__repeated_action_header_t * 3) 'count' sub-actions whose type matches the 'sub_action_type' defined by (1). * The sub-actions will be consecutive, and won't have 'CONTEXT_SWITCH_DEFS__common_action_header_t's - * + * * E.g - 3 repeated 'CONTEXT_SWITCH_DEFS__enable_lcu_action_default_data_t's: * |-------------------------------------------------------------------------------------------------------| * | action_list | data | @@ -164,9 +173,20 @@ typedef struct { uint8_t config_stream_index; } CONTEXT_SWITCH_DEFS__fetch_ccw_bursts_action_data_t; +typedef struct { + uint8_t initial_l3_cut; + uint16_t initial_l3_offset; + uint32_t active_apu; + uint32_t active_ia; + uint64_t active_sc; + uint64_t active_l2; + uint64_t l2_offset_0; + uint64_t l2_offset_1; +} CONTEXT_SWITCH_DEFS__sequencer_config_t; + typedef struct { uint8_t cluster_index; - CONTORL_PROTOCOL__sequencer_config_t sequencer_config; + CONTEXT_SWITCH_DEFS__sequencer_config_t sequencer_config; } CONTEXT_SWITCH_DEFS__trigger_sequencer_action_data_t; typedef struct { @@ -198,17 +218,22 @@ typedef struct { uint8_t packed_vdma_channel_id; uint8_t edge_layer_direction; bool is_inter_context; - bool is_single_context_network_group; uint8_t host_buffer_type; // CONTROL_PROTOCOL__HOST_BUFFER_TYPE_t uint32_t initial_credit_size; } CONTEXT_SWITCH_DEFS__validate_vdma_channel_action_data_t; +typedef enum { + CONTEXT_SWITCH_DEFS__CREDIT_TYPE_UNINITIALIZED = 0, + CONTEXT_SWITCH_DEFS__CREDIT_IN_BYTES, + CONTEXT_SWITCH_DEFS__CREDIT_IN_DESCRIPTORS, +} CONTEXT_SWITCH_DEFS__CREDIT_TYPE_t; + typedef struct { uint8_t packed_vdma_channel_id; uint8_t stream_index; uint8_t network_index; uint32_t frame_periph_size; - uint8_t credit_type; + uint8_t credit_type; // CONTEXT_SWITCH_DEFS__CREDIT_TYPE_t uint16_t periph_bytes_per_buffer; uint8_t host_buffer_type; // CONTROL_PROTOCOL__HOST_BUFFER_TYPE_t, relevant only for descriptors credit. } CONTEXT_SWITCH_DEFS__fetch_data_action_data_t; @@ -247,7 +272,7 @@ typedef struct { uint8_t pred_cluster_ob_interface; uint8_t succ_prepost_ob_index; uint8_t succ_prepost_ob_interface; -} CONTEXT_SWITCH_DEFS__wait_nms_idle_data_t; +} CONTEXT_SWITCH_DEFS__wait_nms_data_t; typedef struct { uint8_t packed_vdma_channel_id; @@ -259,10 +284,6 @@ typedef struct { uint8_t module_index; } CONTEXT_SWITCH_DEFS__module_config_done_interrupt_data_t; -typedef struct { - uint8_t application_index; -} CONTEXT_SWITCH_DEFS__application_change_interrupt_data_t; - /* edge layers structs */ typedef struct { uint8_t packed_vdma_channel_id; @@ -270,7 +291,6 @@ typedef struct { CONTEXT_SWITCH_DEFS__stream_reg_info_t stream_reg_info; CONTROL_PROTOCOL__host_buffer_info_t host_buffer_info; uint32_t initial_credit_size; - bool is_single_context_app; } CONTEXT_SWITCH_DEFS__activate_boundary_input_data_t; typedef struct { @@ -314,14 +334,15 @@ typedef struct { uint32_t buffered_rows_count; } CONTEXT_SWITCH_DEFS__activate_ddr_buffer_output_data_t; -typedef union { - CONTEXT_SWITCH_DEFS__activate_boundary_input_data_t activate_boundary_input_data; - CONTEXT_SWITCH_DEFS__activate_inter_context_input_data_t activate_inter_context_input_data; - CONTEXT_SWITCH_DEFS__activate_ddr_buffer_input_data_t activate_ddr_buffer_input_data; - CONTEXT_SWITCH_DEFS__activate_boundary_output_data_t activate_boundary_output_data; - CONTEXT_SWITCH_DEFS__activate_inter_context_output_data_t activate_inter_context_output_data; - CONTEXT_SWITCH_DEFS__activate_ddr_buffer_output_data_t activate_ddr_buffer_output_data; -} CONTEXT_SWITCH_COMMON__activate_edge_layer_action_t; +typedef struct { + uint8_t packed_vdma_channel_id; + CONTROL_PROTOCOL__host_buffer_info_t host_buffer_info; +} CONTEXT_SWITCH_DEFS__open_boundary_input_channel_data_t; + +typedef struct { + uint8_t packed_vdma_channel_id; + CONTROL_PROTOCOL__host_buffer_info_t host_buffer_info; +} CONTEXT_SWITCH_DEFS__open_boundary_output_channel_data_t; typedef struct { uint8_t packed_vdma_channel_id; @@ -334,6 +355,11 @@ typedef struct { uint8_t config_stream_index; } CONTEXT_SWITCH_DEFS__deactivate_cfg_channel_t; +typedef struct { + uint8_t nms_unit_index; + uint8_t network_index; +} CONTEXT_SWITCH_DEFS__enable_nms_action_t; + #pragma pack(pop) #ifdef __cplusplus diff --git a/common/include/control_protocol.h b/common/include/control_protocol.h index a08768c..48952a1 100644 --- a/common/include/control_protocol.h +++ b/common/include/control_protocol.h @@ -38,7 +38,6 @@ extern "C" { #define CONTROL_PROTOCOL__MAX_CONTEXT_SWITCH_APPLICATIONS (32) #define CONTROL_PROTOCOL__MAX_NUMBER_OF_CLUSTERS (8) #define CONTROL_PROTOCOL__MAX_CONTROL_LENGTH (1500) -#define CONTROL_PROTOCOL__MAX_TOTAL_CONTEXTS (128) #define CONTROL_PROTOCOL__SOC_ID_LENGTH (32) #define CONTROL_PROTOCOL__MAX_CFG_CHANNELS (4) #define CONTROL_PROTOCOL__MAX_NETWORKS_PER_NETWORK_GROUP (8) @@ -67,13 +66,6 @@ extern "C" { */ #define CONTROL_PROTOCOL__IGNORE_DYNAMIC_BATCH_SIZE (0) -#define CONTROL_PROTOCOL__TRIGGER_SUB_INDEX_SHIFT (0) -#define CONTROL_PROTOCOL__TRIGGER_SUB_INDEX_BIT_MASK (0x000000FF) -#define CONTROL_PROTOCOL__TRIGGER_INDEX_SHIFT (16) -#define CONTROL_PROTOCOL__TRIGGER_INDEX_BIT_MASK (0x00FF0000) -#define CONTROL_PROTOCOL__TRIGGER_TYPE_SHIFT (28) -#define CONTROL_PROTOCOL__TRIGGER_TYPE_BIT_MASK (0xF0000000) - // Tightly coupled with BOARD_CONFIG_supported_features_t struct #define CONTROL_PROTOCOL__SUPPORTED_FEATURES_ETHERNET_BIT_OFFSET (0) #define CONTROL_PROTOCOL__SUPPORTED_FEATURES_MIPI_BIT_OFFSET (1) @@ -86,19 +78,6 @@ extern "C" { /* Value to represent an operation should be performed on all streams. */ #define CONTROL_PROTOCOL__ALL_DATAFLOW_MANAGERS (0xFF) -#define CONTROL_PROTOCOL__WRITE_TRIGGER_SUB_INDEX(val)\ - (((uint32_t)val) << CONTROL_PROTOCOL__TRIGGER_SUB_INDEX_SHIFT) -#define CONTROL_PROTOCOL__READ_TRIGGER_SUB_INDEX(val)\ - (((uint32_t)(val) & CONTROL_PROTOCOL__TRIGGER_SUB_INDEX_BIT_MASK) >> (CONTROL_PROTOCOL__TRIGGER_SUB_INDEX_SHIFT)) -#define CONTROL_PROTOCOL__WRITE_TRIGGER_INDEX(val)\ - (((uint32_t)val) << CONTROL_PROTOCOL__TRIGGER_INDEX_SHIFT) -#define CONTROL_PROTOCOL__READ_TRIGGER_INDEX(val)\ - (((uint32_t)(val) & CONTROL_PROTOCOL__TRIGGER_INDEX_BIT_MASK) >> (CONTROL_PROTOCOL__TRIGGER_INDEX_SHIFT)) -#define CONTROL_PROTOCOL__WRITE_TRIGGER_TYPE(val)\ - (((uint32_t)val) << CONTROL_PROTOCOL__TRIGGER_TYPE_SHIFT) -#define CONTROL_PROTOCOL__READ_TRIGGER_TYPE(val)\ - (((uint32_t)(val) & CONTROL_PROTOCOL__TRIGGER_TYPE_BIT_MASK) >> (CONTROL_PROTOCOL__TRIGGER_TYPE_SHIFT)) - #define CONTROL_PROTOCOL__OPCODES_VARIABLES \ CONTROL_PROTOCOL__OPCODE_X(HAILO_CONTROL_OPCODE_IDENTIFY, true, CPU_ID_APP_CPU)\ @@ -133,7 +112,7 @@ extern "C" { CONTROL_PROTOCOL__OPCODE_X(HAILO_CONTROL_OPCODE_SENSOR_LOAD_AND_START, false, CPU_ID_APP_CPU)\ CONTROL_PROTOCOL__OPCODE_X(HAILO_CONTROL_OPCODE_SENSOR_RESET, false, CPU_ID_APP_CPU)\ CONTROL_PROTOCOL__OPCODE_X(HAILO_CONTROL_OPCODE_SENSOR_GET_SECTIONS_INFO, false, CPU_ID_APP_CPU)\ - CONTROL_PROTOCOL__OPCODE_X(HAILO_CONTROL_OPCODE_CONTEXT_SWITCH_SET_MAIN_HEADER, false, CPU_ID_CORE_CPU)\ + CONTROL_PROTOCOL__OPCODE_X(HAILO_CONTROL_OPCODE_CONTEXT_SWITCH_SET_NETWORK_GROUP_HEADER, false, CPU_ID_CORE_CPU)\ CONTROL_PROTOCOL__OPCODE_X(HAILO_CONTROL_OPCODE_CONTEXT_SWITCH_SET_CONTEXT_INFO, false, CPU_ID_CORE_CPU)\ CONTROL_PROTOCOL__OPCODE_X(HAILO_CONTROL_OPCODE_IDLE_TIME_SET_MEASUREMENT, false, CPU_ID_APP_CPU)\ CONTROL_PROTOCOL__OPCODE_X(HAILO_CONTROL_OPCODE_IDLE_TIME_GET_MEASUREMENT, false, CPU_ID_APP_CPU)\ @@ -173,6 +152,8 @@ extern "C" { CONTROL_PROTOCOL__OPCODE_X(HAILO_CONTROL_OPCODE_CORE_WD_ENABLE, false, CPU_ID_CORE_CPU)\ CONTROL_PROTOCOL__OPCODE_X(HAILO_CONTROL_OPCODE_CORE_WD_CONFIG, false, CPU_ID_CORE_CPU)\ CONTROL_PROTOCOL__OPCODE_X(HAILO_CONTROL_OPCODE_CONTEXT_SWITCH_CLEAR_CONFIGURED_APPS, false, CPU_ID_CORE_CPU)\ + CONTROL_PROTOCOL__OPCODE_X(HAILO_CONTROL_OPCODE_GET_HW_CONSTS, false, CPU_ID_CORE_CPU)\ + CONTROL_PROTOCOL__OPCODE_X(HAILO_CONTROL_OPCODE_SET_SLEEP_STATE, false, CPU_ID_APP_CPU)\ typedef enum { #define CONTROL_PROTOCOL__OPCODE_X(name, is_critical, cpu_id) name, @@ -432,6 +413,11 @@ typedef struct { bool should_activate; } CONTROL_PROTOCOL__set_overcurrent_state_request_t; +typedef struct { + uint32_t sleep_state_length; + uint8_t sleep_state; /* of type CONTROL_PROTOCOL__sleep_state_t */ +} CONTROL_PROTOCOL__set_sleep_state_request_t; + typedef struct { uint32_t is_required_length; bool is_required; @@ -446,6 +432,7 @@ typedef struct { uint16_t core_bytes_per_buffer; uint16_t core_buffers_per_frame; uint16_t periph_bytes_per_buffer; + uint16_t periph_buffers_per_frame; uint16_t feature_padding_payload; uint16_t buffer_padding_payload; uint16_t buffer_padding; @@ -868,10 +855,6 @@ typedef struct { uint32_t inbound_to_outbound_latency_nsec; } CONTROL_PROTOCOL__latency_read_response_t; -typedef enum { - CONTROL_PROTOCOL__CONTEXT_SWITCH_VER_V1_0_0 = 0x010000, -} CONTROL_PROTOCOL__CONTEXT_SWITCH_VERSION_t; - typedef struct { bool is_abbale_supported; } CONTROL_PROTOCOL__VALIDATION_FEATURE_LIST_t; @@ -882,8 +865,6 @@ typedef struct { typedef struct { uint8_t dynamic_contexts_count; - uint32_t host_boundary_channels_bitmap[CONTROL_PROTOCOL__MAX_VDMA_ENGINES_COUNT]; - uint8_t power_mode; // CONTROL_PROTOCOL__power_mode_t CONTROL_PROTOCOL__INFER_FEATURE_LIST_t infer_features; CONTROL_PROTOCOL__VALIDATION_FEATURE_LIST_t validation_features; uint8_t networks_count; @@ -891,13 +872,9 @@ typedef struct { } CONTROL_PROTOCOL__application_header_t; typedef struct { - uint32_t context_switch_version_length; - uint32_t context_switch_version; - uint32_t application_count_length; - uint8_t application_count; uint32_t application_header_length; - CONTROL_PROTOCOL__application_header_t application_header[CONTROL_PROTOCOL__MAX_CONTEXT_SWITCH_APPLICATIONS]; -} CONTROL_PROTOCOL__context_switch_set_main_header_request_t; + CONTROL_PROTOCOL__application_header_t application_header; +} CONTROL_PROTOCOL__context_switch_set_network_group_header_request_t; typedef enum { CONTROL_PROTOCOL__WATCHDOG_MODE_HW_SW = 0, @@ -908,7 +885,6 @@ typedef enum { } CONTROL_PROTOCOL__WATCHDOG_MODE_t; typedef struct { - CONTROL_PROTOCOL__CONTEXT_SWITCH_VERSION_t context_switch_version; uint8_t application_count; CONTROL_PROTOCOL__application_header_t application_header[CONTROL_PROTOCOL__MAX_CONTEXT_SWITCH_APPLICATIONS]; } CONTROL_PROTOCOL__context_switch_main_header_t; @@ -943,109 +919,13 @@ typedef struct { CONTROL_PROTOCOL__temperature_info_t info; } CONTROL_PROTOCOL__get_chip_temperature_response_t; -typedef enum { - CONTROL_PROTOCOL__CONTEXT_SWITCH_TRIGGER_TYPE_NONE = 0, - CONTROL_PROTOCOL__CONTEXT_SWITCH_TRIGGER_TYPE_LCU, - CONTROL_PROTOCOL__CONTEXT_SWITCH_TRIGGER_TYPE_INPUT_STREAM, - CONTROL_PROTOCOL__CONTEXT_SWITCH_TRIGGER_TYPE_OUTPUT_STREAM, - CONTROL_PROTOCOL__CONTEXT_SWITCH_TRIGGER_TYPE_NMS_IDLE, - CONTROL_PROTOCOL__CONTEXT_SWITCH_TRIGGER_TYPE_DMA_IDLE, - - /* must be last*/ - CONTROL_PROTOCOL__CONTEXT_SWITCH_TRIGGER_TYPE_COUNT, -} CONTROL_PROTOCOL__CONTEXT_SWITCH_TRIGGER_TYPE_t; - -typedef enum { - /* this enum starts from 128 for each debug while reading memory buffer */ - CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_START_INDEX = 128, - CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_READ_VDMA = CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_START_INDEX, - CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_TRIGGER_SEQUENCER, - CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_WAIT_FOR_SEQUENCER_DONE, - CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_TRIGGER_NEW_DATA_FROM_DATA_INPUT, - CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_ENABLE_LCU_NON_DEFAULT, - CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_DISABLE_LCU, - CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_WAIT_FOR_MODULE_CONFIG_DONE, - CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_ADD_DDR_PAIR_INFO, - CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_ADD_DDR_BUFFERING_START, - CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_ENABLE_LCU_DEFAULT, - CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_ADD_REPEATED, - CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_FETCH_CCW_BURSTS, - CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_BURST_CREDITS_TASK_START, - CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_EDGE_LAYER_ACTIVATION_ACTIONS_POSITION, - - /* must be last*/ - CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_COUNT, -} CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_TYPE_t; - -typedef uint8_t CONTROL_PROTOCOL__TRIGGER_TYPE_t; - -typedef struct { - /* Empty struct - place holder */ - uint8_t reserved; -} CONTROL_PROTOCOL__TRIGGER_NONE_t; - -typedef struct { - uint8_t cluster_index; - uint8_t lcu_index; -} CONTROL_PROTOCOL__TRIGGER_LCU_t; - -typedef struct { - uint8_t stream_index; -} CONTROL_PROTOCOL__TRIGGER_INPUT_STREAM_t; - -typedef struct { - uint8_t stream_index; -} CONTROL_PROTOCOL__TRIGGER_OUTPUT_STREAM_t; - -typedef struct { - uint8_t aggregator_index; - uint8_t pred_cluster_ob_index; - uint8_t pred_cluster_ob_cluster_index; - uint8_t pred_cluster_ob_interface; - uint8_t succ_prepost_ob_index; - uint8_t succ_prepost_ob_interface; -} CONTROL_PROTOCOL__TRIGGER_NMS_IDLE_t; - -typedef struct { - uint8_t stream_index; -} CONTROL_PROTOCOL__TRIGGER_DMA_IDLE_t; - -typedef union { - CONTROL_PROTOCOL__TRIGGER_NONE_t none_trigger; - CONTROL_PROTOCOL__TRIGGER_LCU_t lcu_trigger; - CONTROL_PROTOCOL__TRIGGER_INPUT_STREAM_t input_stream_trigger; - CONTROL_PROTOCOL__TRIGGER_OUTPUT_STREAM_t output_stream_trigger; - CONTROL_PROTOCOL__TRIGGER_NMS_IDLE_t nms_idle_trigger; - CONTROL_PROTOCOL__TRIGGER_DMA_IDLE_t dma_idle_trigger; -} CONTROL_PROTOCOL__trigger_parameters_t; - -typedef struct { - CONTROL_PROTOCOL__TRIGGER_TYPE_t type; - CONTROL_PROTOCOL__trigger_parameters_t params; -} CONTROL_PROTOCOL__TRIGGER_t; - -typedef uint8_t CONTROL_PROTOCOL__shmifo_to_pcie_channel_mapping_t; - -typedef enum { - CONTROL_PROTOCOL__EDGE_CONNECTION_TYPE_NETWORK_BOUNDARY_INPUT, - CONTROL_PROTOCOL__EDGE_CONNECTION_TYPE_NETWORK_BOUNDARY_OUTPUT, - CONTROL_PROTOCOL__EDGE_CONNECTION_TYPE_INTERMEDIATE_BUFFER_INPUT, - CONTROL_PROTOCOL__EDGE_CONNECTION_TYPE_INTERMEDIATE_BUFFER_OUTPUT, - CONTROL_PROTOCOL__EDGE_CONNECTION_TYPE_DDR_BUFFER_INPUT, - CONTROL_PROTOCOL__EDGE_CONNECTION_TYPE_DDR_BUFFER_OUTPUT, - - /* must be last */ - CONTROL_PROTOCOL__EDGE_CONNECTION_TYPE_COUNT -} CONTROL_PROTOCOL__EDGE_CONNECTION_TYPE_t; typedef enum { CONTROL_PROTOCOL__HOST_BUFFER_TYPE_EXTERNAL_DESC = 0, CONTROL_PROTOCOL__HOST_BUFFER_TYPE_CCB, + CONTROL_PROTOCOL__HOST_BUFFER_TYPE_HOST_MANAGED_EXTERNAL_DESC, /* DEPRECATED */ - // The buffer uses external descriptors that is host managed - the firmware don't need to config this buffer - CONTROL_PROTOCOL__HOST_BUFFER_TYPE_HOST_MANAGED_EXTERNAL_DESC, - - /* must be last*/ + /* must be last */ CONTROL_PROTOCOL__HOST_BUFFER_TYPE_COUNT } CONTROL_PROTOCOL__HOST_BUFFER_TYPE_t; @@ -1057,74 +937,6 @@ typedef struct { uint32_t bytes_in_pattern; } CONTROL_PROTOCOL__host_buffer_info_t; -/* TODO: merge CONTROL_PROTOCOL__edge_layer_common_info_t into the header (HRT-7113) */ -typedef struct { - uint8_t communication_type; - uint8_t edge_connection_type; -} CONTROL_PROTOCOL__edge_layer_header_t; - -typedef struct { - uint8_t engine_index; - uint8_t vdma_channel_index; - uint8_t stream_index; - uint8_t network_index; - CONTROL_PROTOCOL__nn_stream_config_t nn_stream_config; -} CONTROL_PROTOCOL__edge_layer_common_info_t; - -typedef struct { - CONTROL_PROTOCOL__edge_layer_common_info_t common_info; - CONTROL_PROTOCOL__host_buffer_info_t host_buffer_info; -} CONTROL_PROTOCOL__network_boundary_output_t; - -typedef struct { - CONTROL_PROTOCOL__edge_layer_common_info_t common_info; - CONTROL_PROTOCOL__host_buffer_info_t host_buffer_info; -} CONTROL_PROTOCOL__inter_context_output_t; - -typedef struct { - CONTROL_PROTOCOL__edge_layer_common_info_t common_info; - CONTROL_PROTOCOL__host_buffer_info_t host_buffer_info; - uint32_t buffered_rows_count; -} CONTROL_PROTOCOL__ddr_buffer_output_t; - - -typedef struct { - CONTROL_PROTOCOL__edge_layer_common_info_t common_info; -} CONTROL_PROTOCOL__eth_network_boundary_output_t; - -typedef struct { - CONTROL_PROTOCOL__edge_layer_common_info_t common_info; - CONTROL_PROTOCOL__host_buffer_info_t host_buffer_info; - uint32_t initial_credit_size; -} CONTROL_PROTOCOL__network_boundary_input_t; - -typedef struct { - CONTROL_PROTOCOL__edge_layer_common_info_t common_info; - CONTROL_PROTOCOL__host_buffer_info_t host_buffer_info; - uint32_t initial_credit_size; -} CONTROL_PROTOCOL__inter_context_input_t; - -typedef struct { - CONTROL_PROTOCOL__edge_layer_common_info_t common_info; - CONTROL_PROTOCOL__host_buffer_info_t host_buffer_info; - uint32_t initial_credit_size; - uint8_t connected_d2h_engine_index; - uint8_t connected_d2h_channel_index; -} CONTROL_PROTOCOL__ddr_buffer_input_t; - -typedef struct { - CONTROL_PROTOCOL__edge_layer_common_info_t common_info; -} CONTROL_PROTOCOL__eth_network_boundary_input_t; - -typedef struct { - uint8_t should_use_stream_remap; -} CONTROL_PROTOCOL__stream_remap_data_t; - -typedef struct { - CONTROL_PROTOCOL__host_buffer_info_t config_buffer_info; - uint8_t engine_index; - uint8_t vdma_channel_index; -} CONTROL_PROTOCOL__config_channel_info_t; #if defined(_MSC_VER) // TODO: warning C4200 @@ -1136,16 +948,10 @@ typedef struct { uint8_t is_first_control_per_context; uint32_t is_last_control_per_context_length; uint8_t is_last_control_per_context; - uint32_t cfg_channels_count_length; - uint8_t cfg_channels_count; - uint32_t config_channel_infos_length; - CONTROL_PROTOCOL__config_channel_info_t config_channel_infos[CONTROL_PROTOCOL__MAX_CFG_CHANNELS]; - uint32_t context_stream_remap_data_length; - CONTROL_PROTOCOL__stream_remap_data_t context_stream_remap_data; - uint32_t number_of_edge_layers_length; - uint8_t number_of_edge_layers; - uint32_t number_of_trigger_groups_length; - uint8_t number_of_trigger_groups; + uint32_t context_type_length; + uint8_t context_type; // CONTROL_PROTOCOL__context_switch_context_type_t + uint32_t actions_count_length; + uint32_t actions_count; uint32_t context_network_data_length; uint8_t context_network_data[0]; } CONTROL_PROTOCOL__context_switch_set_context_info_request_t; @@ -1153,169 +959,12 @@ typedef struct { #pragma warning(pop) #endif -typedef uint8_t CONTROL_PROTOCOL__ACTION_TYPE_t; - -/* Each CONTROL_PROTOCOL__*_ACTION_t must start with a CONTROL_PROTOCOL__ACTION_HEADER_t */ typedef struct { /* Must be first */ - CONTROL_PROTOCOL__ACTION_TYPE_t action_type; + uint8_t action_type; // CONTEXT_SWITCH_DEFS__ACTION_TYPE_t bool is_repeated; } CONTROL_PROTOCOL__ACTION_HEADER_t; -/** - * Repeated actions are sent in the following manner via the control protocol: - * 1) CONTROL_PROTOCOL__REPEATED_ACTION_t with: - * a) 'action_type' = CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_ADD_REPEATED - * b) 'is_repeated' = false - * 2) 'count' sub-actions whose type matches the 'sub_action_type' defined by (1). - * The sub-actions will be consecutive, and will all be marked as 'is_repeated' = true in thier headers. - * The sub-actions may be in different slices, if there is a 'CONTROL_PROTOCOL__CONTEXT_SWITCH_TRIGGER_TYPE_NONE' between them. - * - * E.g. - 3 repeated 'CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_ENABLE_LCU_DEFAULT's: - * |--------------------------------------------------------------------------------------------------| - * | time | data | - * |--------------------------------------------------------------------------------------------------| - * | ... | | - * | | | CONTROL_PROTOCOL__REPEATED_ACTION_t { | - * | | | .header = { CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_ADD_REPEATED, false}; | - * | | | .sub_action_type = CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_ENABLE_LCU_DEFAULT; | - * | | | .num_actions = 3; | - * | | | } | - * | | | CONTROL_PROTOCOL__ENABLE_LCU_DEFAULT_ACTION_t { | - * | | | .header = { CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_ENABLE_LCU_DEFAULT, true }; | - * | | | .cluster_index = ; | - * | | | .lcu_index = ; | - * | | | .network_index = ; | - * | | | } | - * | | | CONTROL_PROTOCOL__ENABLE_LCU_DEFAULT_ACTION_t { | - * | | | .header = { CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_ENABLE_LCU_DEFAULT, true }; | - * | | | .cluster_index = ; | - * | | | .lcu_index = ; | - * | | | .network_index = ; | - * | | | } | - * | | | CONTROL_PROTOCOL__ENABLE_LCU_DEFAULT_ACTION_t { | - * | | | .header = { CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_ENABLE_LCU_DEFAULT, true }; | - * | | | .cluster_index = ; | - * | | | .lcu_index = ; | - * | | | .network_index = ; | - * | V | } | - * | ... | (Next action control) | - * |--------------------------------------------------------------------------------------------------| - * See also: "CONTEXT_SWITCH_DEFS__repeated_action_header_t" in "context_switch_defs.h" - */ -typedef struct { - /* Must be first */ - CONTROL_PROTOCOL__ACTION_HEADER_t header; - CONTROL_PROTOCOL__ACTION_TYPE_t sub_action_type; - uint8_t num_actions; -} CONTROL_PROTOCOL__REPEATED_ACTION_t; - -typedef struct { - /* Must be first */ - CONTROL_PROTOCOL__ACTION_HEADER_t header; - uint16_t descriptors_count; - uint8_t config_stream_index; -} CONTROL_PROTOCOL__READ_VDMA_ACTION_t; - -typedef struct { - /* Must be first */ - CONTROL_PROTOCOL__ACTION_HEADER_t header; - uint16_t ccw_bursts; - uint8_t config_stream_index; -} CONTROL_PROTOCOL__FETCH_CCW_BURSTS_ACTION_t; - -typedef struct { - uint8_t initial_l3_cut; - uint16_t initial_l3_offset; - uint32_t active_apu; - uint32_t active_ia; - uint64_t active_sc; - uint64_t active_l2; - uint64_t l2_offset_0; - uint64_t l2_offset_1; -} CONTORL_PROTOCOL__sequencer_config_t; - -typedef struct { - /* Must be first */ - CONTROL_PROTOCOL__ACTION_HEADER_t header; - uint8_t cluster_index; - CONTORL_PROTOCOL__sequencer_config_t sequencer_config; -} CONTROL_PROTOCOL__TRIGGER_SEQUENCER_ACTION_t; - -typedef struct { - /* Must be first */ - CONTROL_PROTOCOL__ACTION_HEADER_t header; - uint8_t sequencer_index; -} CONTROL_PROTOCOL__WAIT_FOR_SEQUENCER_ACTION_t; - -typedef struct { - /* Must be first */ - CONTROL_PROTOCOL__ACTION_HEADER_t header; - uint8_t stream_index; -} CONTROL_PROTOCOL__FETCH_NEW_DATA_ACTION_t; - -typedef struct { - /* Must be first */ - CONTROL_PROTOCOL__ACTION_HEADER_t header; - uint8_t cluster_index; - uint8_t lcu_index; - uint16_t kernel_done_address; - uint32_t kernel_done_count; - uint8_t network_index; -} CONTROL_PROTOCOL__ENABLE_LCU_NON_DEAFULT_ACTION_t; - -typedef struct { - /* Must be first */ - CONTROL_PROTOCOL__ACTION_HEADER_t header; - uint8_t cluster_index; - uint8_t lcu_index; - uint8_t network_index; -} CONTROL_PROTOCOL__ENABLE_LCU_DEFAULT_ACTION_t; - -typedef struct { - /* Must be first */ - CONTROL_PROTOCOL__ACTION_HEADER_t header; - uint8_t cluster_index; - uint8_t lcu_index; -} CONTROL_PROTOCOL__DISABLE_LCU_ACTION_t; - -typedef struct { - /* Must be first */ - CONTROL_PROTOCOL__ACTION_HEADER_t header; - uint8_t module_index; -} CONTORL_PROTOCOL__WAIT_FOR_MODULE_CONFIG_DONE_ACTION_t; - -typedef struct { - /* Must be first */ - CONTROL_PROTOCOL__ACTION_HEADER_t header; - uint8_t h2d_engine_index; - uint8_t h2d_vdma_channel_index; - uint8_t d2h_engine_index; - uint8_t d2h_vdma_channel_index; - uint32_t descriptors_per_frame; - uint16_t programmed_descriptors_count; -} CONTROL_PROTOCOL__ADD_DDR_PAIR_ACTION_t; - -typedef struct { - /* Must be first */ - CONTROL_PROTOCOL__ACTION_HEADER_t header; -} CONTROL_PROTOCOL__ADD_DDR_BUFFERING_START_ACTION_t; - -typedef struct { - /* Must be first */ - CONTROL_PROTOCOL__ACTION_HEADER_t header; -} CONTROL_PROTOCOL__BURST_CREDITS_TASK_START_ACTION_T; - -typedef struct { - /* Must be first */ - CONTROL_PROTOCOL__ACTION_HEADER_t header; -} CONTROL_PROTOCOL__EDGE_LAYER_ACTIVATION_ACTIONS_POSITION_MARKER_T; - -typedef struct { - CONTROL_PROTOCOL__TRIGGER_t trigger; - uint16_t triggers_action_count; -} CONTROL_PROTOCOL__trigger_group_t; - typedef CONTROL_PROTOCOL__read_memory_request_t CONTROL_PROTOCOL__read_user_config_request_t; typedef CONTROL_PROTOCOL__read_memory_response_t CONTROL_PROTOCOL__read_user_config_response_t; typedef CONTROL_PROTOCOL__write_memory_request_t CONTROL_PROTOCOL__write_user_config_request_t; @@ -1331,6 +980,10 @@ typedef struct { } CONTROL_PROTOCOL__idle_time_get_measurement_response_t; typedef struct { + uint32_t network_group_id_length; + uint32_t network_group_id; + uint32_t context_type_length; + uint8_t context_type; // CONTROL_PROTOCOL__context_switch_context_type_t uint32_t context_index_length; uint8_t context_index; uint32_t action_list_offset_length; @@ -1579,7 +1232,15 @@ typedef enum { CONTROL_PROTOCOL__TOP_MEM_BLOCK_SUB_SERVER6_26, CONTROL_PROTOCOL__TOP_MEM_BLOCK_SUB_SERVER7_27, CONTROL_PROTOCOL__TOP_NUM_MEM_BLOCKS -} CONTROL_PROTOCOL__biTOP_st_top_mem_block_t; +} CONTROL_PROTOCOL__bist_top_mem_block_t; + +/* Must be identical to hailo_sleep_state_t, tightly coupled */ +typedef enum { + CONTROL_PROTOCOL_SLEEP_STATE_SLEEPING = 0, + CONTROL_PROTOCOL_SLEEP_STATE_AWAKE = 1, + /* must be last */ + CONTROL_PROTOCOL_SLEEP_STATE_COUNT +} CONTROL_PROTOCOL__sleep_state_t; /*only allowing bist on the following memories*/ #define CONTROL_PROTOCOL__BIST_TOP_WHITELIST ((1 << CONTROL_PROTOCOL__TOP_MEM_BLOCK_L4_0_2) | \ @@ -1603,6 +1264,21 @@ typedef struct { uint32_t cluster_bypass_bitmap_1; } CONTROL_PROTOCOL__run_bist_test_request_t; +typedef struct { + uint32_t fifo_word_granularity_bytes; + uint16_t max_periph_buffers_per_frame; + uint16_t max_periph_bytes_per_buffer; + uint16_t max_acceptable_bytes_per_buffer; + uint32_t outbound_data_stream_size; + uint8_t should_optimize_credits; + uint32_t default_initial_credit_size; +} CONTROL_PROTOCOL__hw_consts_t; + +typedef struct { + uint32_t hw_consts_length; + CONTROL_PROTOCOL__hw_consts_t hw_consts; +} CONTROL_PROTOCOL__get_hw_consts_response_t; + typedef union { CONTROL_PROTOCOL_identify_response_t identity_response; CONTROL_PROTOCOL__core_identify_response_t core_identity_response; @@ -1628,6 +1304,8 @@ typedef union { CONTROL_PROTOCOL__get_health_information_response_t get_health_information_response; CONTROL_PROTOCOL__get_throttling_state_response_t get_throttling_state_response; CONTROL_PROTOCOL__get_overcurrent_state_response_t get_overcurrent_state_response; + CONTROL_PROTOCOL__get_hw_consts_response_t get_hw_consts_response; + // Note: This array is larger than any legal request: // * Functions in this module won't write more than CONTROL_PROTOCOL__MAX_CONTROL_LENGTH bytes // when recieving a pointer to CONTROL_PROTOCOL__request_parameters_t. @@ -1660,7 +1338,7 @@ typedef union { CONTROL_PROTOCOL__sensor_reset_request_t sensor_reset_request; CONTROL_PROTOCOL__sensor_get_config_request_t sensor_get_config_request; CONTROL_PROTOCOL__sensor_set_generic_i2c_slave_request_t sensor_set_generic_i2c_slave_request; - CONTROL_PROTOCOL__context_switch_set_main_header_request_t context_switch_set_main_header_request; + CONTROL_PROTOCOL__context_switch_set_network_group_header_request_t context_switch_set_network_group_header_request; CONTROL_PROTOCOL__context_switch_set_context_info_request_t context_switch_set_context_info_request; CONTROL_PROTOCOL__idle_time_set_measurement_request_t idle_time_set_measurement_request; CONTROL_PROTOCOL__download_context_action_list_request_t download_context_action_list_request; @@ -1685,6 +1363,7 @@ typedef union { CONTROL_PROTOCOL__set_throttling_state_request_t set_throttling_state_request; CONTROL_PROTOCOL__sensor_set_i2c_bus_index_t sensor_set_i2c_bus_index; CONTROL_PROTOCOL__set_overcurrent_state_request_t set_overcurrent_state_request; + CONTROL_PROTOCOL__set_sleep_state_request_t set_sleep_state_request; // Note: This array is larger than any legal request: // * Functions in this module won't write more than CONTROL_PROTOCOL__MAX_CONTROL_LENGTH bytes // when recieving a pointer to CONTROL_PROTOCOL__request_parameters_t. @@ -1721,28 +1400,40 @@ typedef struct { #define CONTROL_PROTOCOL__CONTEXT_NETWORK_DATA_SINGLE_CONTROL_MAX_SIZE \ (CONTROL_PROTOCOL__MAX_REQUEST_PARAMETERS_LENGTH - sizeof(CONTROL_PROTOCOL__context_switch_set_context_info_request_t)) +typedef enum { + CONTROL_PROTOCOL__CONTEXT_SWITCH_CONTEXT_TYPE_PRELIMINARY, + CONTROL_PROTOCOL__CONTEXT_SWITCH_CONTEXT_TYPE_DYNAMIC, + CONTROL_PROTOCOL__CONTEXT_SWITCH_CONTEXT_TYPE_BATCH_SWITCHING, + CONTROL_PROTOCOL__CONTEXT_SWITCH_CONTEXT_TYPE_ACTIVATION, + + /* must be last*/ + CONTROL_PROTOCOL__CONTEXT_SWITCH_CONTEXT_TYPE_COUNT, +} CONTROL_PROTOCOL__context_switch_context_type_t; + +typedef enum { + CONTROL_PROTOCOL__CONTEXT_SWITCH_INDEX_ACTIVATION_CONTEXT = 0, + CONTROL_PROTOCOL__CONTEXT_SWITCH_INDEX_BATCH_SWITCHING_CONTEXT, + CONTROL_PROTOCOL__CONTEXT_SWITCH_INDEX_PRELIMINARY_CONTEXT, + CONTROL_PROTOCOL__CONTEXT_SWITCH_NUMBER_OF_NON_DYNAMIC_CONTEXTS, + CONTROL_PROTOCOL__CONTEXT_SWITCH_INDEX_FIRST_DYNAMIC_CONTEXT = CONTROL_PROTOCOL__CONTEXT_SWITCH_NUMBER_OF_NON_DYNAMIC_CONTEXTS, + + /* must be last*/ + CONTROL_PROTOCOL__CONTEXT_SWITCH_INDEX_COUNT, +} CONTROL_PROTOCOL__context_switch_context_index_t; + +#define CONTROL_PROTOCOL__MAX_CONTEXTS_PER_NETWORK_GROUP (64) + typedef struct { bool is_first_control_per_context; bool is_last_control_per_context; - uint8_t cfg_channels_count; - CONTROL_PROTOCOL__config_channel_info_t config_channel_infos[CONTROL_PROTOCOL__MAX_CFG_CHANNELS]; - CONTROL_PROTOCOL__stream_remap_data_t context_stream_remap_data; - uint8_t number_of_edge_layers; - uint8_t number_of_trigger_groups; + uint8_t context_type; // CONTROL_PROTOCOL__context_switch_context_type_t + uint32_t actions_count; uint32_t context_network_data_length; uint8_t context_network_data[CONTROL_PROTOCOL__CONTEXT_NETWORK_DATA_SINGLE_CONTROL_MAX_SIZE]; } CONTROL_PROTOCOL__context_switch_context_info_single_control_t; -/* Context switch user structs */ - -#define CONTROL_PROTOCOL__CONTEXT_NETWORK_DATA_MAX_SIZE (8 * 1024) - -typedef struct { - uint8_t interrupt_type; - uint8_t interrupt_index; - uint8_t interrupt_sub_index; -} CONTROL_PROTOCOL__dataflow_interrupt_t; -/* End of context switch structs */ +CASSERT(sizeof(CONTROL_PROTOCOL__context_switch_context_index_t)<=UINT8_MAX, control_protocol_h); +CASSERT(sizeof(CONTROL_PROTOCOL__context_switch_context_type_t)<=UINT8_MAX, control_protocol_h); typedef enum { CONTROL_PROTOCOL__MESSAGE_TYPE__REQUEST = 0, @@ -1769,7 +1460,6 @@ typedef enum { CONTROL_PROTOCOL__RESET_TYPE__COUNT } CONTROL_PROTOCOL__reset_type_t; - typedef union { /* Needed in order to parse unknown header */ CONTROL_PROTOCOL__common_header_t common; diff --git a/common/include/d2h_events.h b/common/include/d2h_events.h index e2c78d9..6eff396 100644 --- a/common/include/d2h_events.h +++ b/common/include/d2h_events.h @@ -29,7 +29,7 @@ typedef enum { typedef enum { D2H_EVENT_COMMUNICATION_TYPE_UDP = 0, - D2H_EVENT_COMMUNICATION_TYPE_PCIE, + D2H_EVENT_COMMUNICATION_TYPE_VDMA, D2H_EVENT_COMMUNICATION_TYPE__COUNT } D2H_EVENT_COMMUNICATION_TYPE_t; @@ -72,7 +72,7 @@ typedef struct { typedef struct { uint32_t connection_status; uint32_t connection_type; - uint32_t pcie_is_active; + uint32_t vdma_is_active; uint32_t host_port; uint32_t host_ip_addr; } D2H_EVENT_host_info_event_message_t; @@ -156,7 +156,16 @@ typedef struct { D2H_EVENT__message_parameters_t message_parameters; } D2H_EVENT_MESSAGE_t; -#define PCIE_D2H_EVENT_MAX_SIZE (0x370) +#define D2H_EVENT_BUFFER_NOT_IN_USE (0) +#define D2H_EVENT_BUFFER_IN_USE (1) +#define D2H_EVENT_MAX_SIZE (0x370) + +typedef struct { + uint16_t is_buffer_in_use; + uint16_t buffer_len; + uint8_t buffer[D2H_EVENT_MAX_SIZE]; +} D2H_event_buffer_t; + /********************************************************************** * Public Functions **********************************************************************/ diff --git a/common/include/firmware_header_utils.h b/common/include/firmware_header_utils.h index 1a001f0..6324101 100644 --- a/common/include/firmware_header_utils.h +++ b/common/include/firmware_header_utils.h @@ -22,26 +22,28 @@ extern "C" { #define REVISION_NUMBER_SHIFT (0) #define REVISION_APP_CORE_FLAG_BIT_SHIFT (27) #define REVISION_RESERVED_0_FLAG_BIT_SHIFT (28) -#define REVISION_RESERVED_1_FLAG_BIT_SHIFT (29) +#define REVISION_EXTENDED_CONTEXT_SWITCH_BUFFER_FLAG_BIT_SHIFT (29) #define REVISION_DEV_FLAG_BIT_SHIFT (30) #define REVISION_SECOND_STAGE_FLAG_BIT_SHIFT (31) #define REVISION_NUMBER_WIDTH (27U) #define REVISION_APP_CORE_FLAG_BIT_WIDTH (1U) #define REVISION_RESERVED_0_FLAG_BIT_WIDTH (1U) -#define REVISION_RESERVED_1_FLAG_BIT_WIDTH (1U) +#define REVISION_EXTENDED_CONTEXT_SWITCH_BUFFER_FLAG_BIT_WIDTH (1U) #define REVISION_DEV_FLAG_BIT_WIDTH (1U) #define REVISION_SECOND_STAGE_FLAG_BIT_WIDTH (1U) #define REVISION_NUMBER_MASK (GET_MASK(REVISION_NUMBER_WIDTH, REVISION_NUMBER_SHIFT)) #define REVISION_APP_CORE_FLAG_BIT_MASK (GET_MASK(REVISION_APP_CORE_FLAG_BIT_WIDTH, REVISION_APP_CORE_FLAG_BIT_SHIFT)) #define REVISION_RESERVED_0_FLAG_BIT_MASK (GET_MASK(REVISION_RESERVED_0_FLAG_BIT_WIDTH, REVISION_RESERVED_0_FLAG_BIT_SHIFT)) -#define REVISION_RESERVED_1_FLAG_BIT_MASK (GET_MASK(REVISION_RESERVED_1_FLAG_BIT_WIDTH, REVISION_RESERVED_1_FLAG_BIT_SHIFT)) +#define REVISION_EXTENDED_CONTEXT_SWITCH_BUFFER_FLAG_BIT_MASK (GET_MASK(REVISION_EXTENDED_CONTEXT_SWITCH_BUFFER_FLAG_BIT_WIDTH, REVISION_EXTENDED_CONTEXT_SWITCH_BUFFER_FLAG_BIT_SHIFT)) #define REVISION_DEV_FLAG_BIT_MASK (GET_MASK(REVISION_DEV_FLAG_BIT_WIDTH, REVISION_DEV_FLAG_BIT_SHIFT)) #define REVISION_SECOND_STAGE_FLAG_BIT_MASK (GET_MASK(REVISION_SECOND_STAGE_FLAG_BIT_WIDTH, REVISION_SECOND_STAGE_FLAG_BIT_SHIFT)) #define GET_REVISION_NUMBER_VALUE(binary_revision) (REVISION_NUMBER_MASK & binary_revision) #define IS_REVISION_DEV(binary_revision) (REVISION_DEV_FLAG_BIT_MASK == (REVISION_DEV_FLAG_BIT_MASK & binary_revision)) +#define IS_REVISION_EXTENDED_CONTEXT_SWITCH_BUFFER(binary_revision) (REVISION_EXTENDED_CONTEXT_SWITCH_BUFFER_FLAG_BIT_MASK == \ + (REVISION_EXTENDED_CONTEXT_SWITCH_BUFFER_FLAG_BIT_MASK & binary_revision)) #define DEV_STRING_NOTE(__is_release) ((__is_release)? "" : " (dev)") /** diff --git a/common/include/firmware_status.h b/common/include/firmware_status.h index edea0ac..7eb20e2 100644 --- a/common/include/firmware_status.h +++ b/common/include/firmware_status.h @@ -307,7 +307,7 @@ Updating rules: FIRMWARE_STATUS__X(CONTROL_PROTOCOL_STATUS_INVALID_CONTEXT_SWITCH_APP_HEADER_LENGTH)\ FIRMWARE_STATUS__X(CONTROL_PROTOCOL_STATUS_INVALID_CONTEXT_SWITCH_CLUSTER_END_GARANTEE_TRIGGER_LENGTH)/* DEPRECATED */\ FIRMWARE_STATUS__X(CONTROL_PROTOCOL_STATUS_INVALID_CONTEXT_SWITCH_NUMBER_OF_EDGE_LAYERS_LENGTH)\ - FIRMWARE_STATUS__X(CONTROL_PROTOCOL_STATUS_INVALID_CONTEXT_SWITCH_NUMBER_OF_TRIGGER_GROUPS_LENGTH)\ + FIRMWARE_STATUS__X(CONTROL_PROTOCOL_STATUS_INVALID_CONTEXT_SWITCH_NUMBER_OF_ACTION_LENGTH)\ FIRMWARE_STATUS__X(CONTROL_PROTOCOL_STATUS_INVALID_CONTEXT_SWITCH_TRIGGER_GROUPS_LENGTH)\ FIRMWARE_STATUS__X(CONTROL_PROTOCOL_STATUS_CONTEXT_SWITCH_CONTEXT_NETWORK_DATA_LENGTH_HIGHER_THEN_MAX_CONTROL_SIZE)\ FIRMWARE_STATUS__X(CONTROL_PROTOCOL_STATUS_IDLE_TIME_MEASUREMENT_ALREADY_SET)\ @@ -404,6 +404,11 @@ Updating rules: FIRMWARE_STATUS__X(CONTROL_PROTOCOL_STATUS_INVALID_INFER_FEATURES_LENGTH) /* DEPRECATED */\ FIRMWARE_STATUS__X(CONTROL_PROTOCOL_STATUS_INVALID_CONFIG_CHANNEL_INFOS)\ FIRMWARE_STATUS__X(CONTROL_PROTOCOL_STATUS_INVALID_IS_BATCH_SIZE_FLOW_LENGTH)\ + FIRMWARE_STATUS__X(CONTROL_PROTOCOL_STATUS_INVALID_CONTEXT_SWITCH_CONTEXT_TYPE_LENGTH)\ + FIRMWARE_STATUS__X(CONTROL_PROTOCOL_STATUS_INVALID_CONTEXT_SWITCH_CONTEXT_NETWORK_GROUP_ID_LENGTH)\ + FIRMWARE_STATUS__X(CONTROL_PROTOCOL_STATUS_SET_SLEEP_STATE_FAILED)\ + FIRMWARE_STATUS__X(CONTROL_PROTOCOL_STATUS_INVALID_SLEEP_STATE_SIZE)\ + FIRMWARE_STATUS__X(CONTROL_PROTOCOL_STATUS_INVALID_SLEEP_STATE)\ \ FIRMWARE_MODULE__X(FIRMWARE_MODULE__POWER_MEASUREMENT)\ FIRMWARE_STATUS__X(HAILO_POWER_MEASUREMENT_STATUS_POWER_INIT_ERROR)\ @@ -650,7 +655,7 @@ Updating rules: FIRMWARE_STATUS__X(CONTEXT_SWITCH_TASK_STATUS_ADD_ACTION_FUNCTION_REACHED_FORBIDDEN_MEMORY_SPACE)\ FIRMWARE_STATUS__X(CONTEXT_SWITCH_TASK_STATUS_ADD_CONTEXT_INFO_FUNCTION_REACHED_FORBIDDEN_MEMORY_SPACE)\ FIRMWARE_STATUS__X(CONTEXT_SWITCH_TASK_STATUS_PARSING_ERROR_WHILE_READING_TRIGGER_GROUPS)\ - FIRMWARE_STATUS__X(CONTEXT_SWITCH_TASK_STATUS_TRIGGER_GROUP_POINTER_REACHED_FORBIDDEN_MEMORY_SPACE)\ + FIRMWARE_STATUS__X(CONTEXT_SWITCH_TASK_STATUS_POINTER_REACHED_FORBIDDEN_MEMORY_SPACE)\ FIRMWARE_STATUS__X(CONTEXT_SWITCH_TASK_STATUS_DOWNLOAD_ACTION_LIST_INVALID_CONTEXT_INDEX)\ FIRMWARE_STATUS__X(CONTEXT_SWITCH_TASK_STATUS_RECEIVED_INVALID_APPLICATION_COUNT)\ FIRMWARE_STATUS__X(CONTEXT_SWITCH_TASK_STATUS_RECEIVED_INVALID_TOTAL_CONTEXTS_COUNT)\ @@ -732,10 +737,6 @@ Updating rules: FIRMWARE_STATUS__X(CONTEXT_SWITCH_STATUS_WAIT_FOR_PREDICATE_INTERRUPTED_BY_RESET_REQUEST)\ FIRMWARE_STATUS__X(CONTEXT_SWITCH_STATUS_WAIT_FOR_DMA_IDLE_INTERRUPTED_BY_RESET_REQUEST)\ FIRMWARE_STATUS__X(CONTEXT_SWITCH_STATUS_ACTION_NOT_SUPPORTED)\ - FIRMWARE_STATUS__X(CONTEXT_SWITCH_STATUS_INVALID_AGGREGATOR_INDEX)\ - FIRMWARE_STATUS__X(CONTEXT_SWITCH_STATUS_INVALID_OUTPUT_BUFFER_INDEX)\ - FIRMWARE_STATUS__X(CONTEXT_SWITCH_STATUS_INVALID_OUTPUT_BUFFER_CLUSTER_INDEX)\ - FIRMWARE_STATUS__X(CONTEXT_SWITCH_STATUS_INVALID_OUTPUT_BUFFER_INTERFACE)\ FIRMWARE_STATUS__X(CONTEXT_SWITCH_STATUS_ACTION_IS_NOT_SUPPORTED)\ FIRMWARE_STATUS__X(CONTEXT_SWITCH_STATUS_INVALID_CFG_CHANNELS_COUNT)\ FIRMWARE_STATUS__X(CONTEXT_SWITCH_STATUS_INVALID_HOST_BUFFER_TYPE)\ @@ -745,6 +746,11 @@ Updating rules: FIRMWARE_STATUS__X(CONTEXT_SWITCH_STATUS_ADD_ACTION_TO_BATCH_SWITCH_BUFFER_REACHED_FORBIDDEN_MEMORY_SPACE)\ FIRMWARE_STATUS__X(CONTEXT_SWITCH_TASK_STATUS_WAIT_FOR_INTERRUPT_INTERRUPTED_BY_BATCH_CHANGE_REQUEST)\ FIRMWARE_STATUS__X(CONTEXT_SWITCH_STATUS_CANT_CLEAR_CONFIGURED_APPS_WHILE_ACTIVATED)\ + FIRMWARE_STATUS__X(CONTEXT_SWITCH_STATUS_INVALID_CONTEXT_TYPE)\ + FIRMWARE_STATUS__X(CONTEXT_SWITCH_STATUS_UNEXPECTED_CONTEXT_ORDER)\ + FIRMWARE_STATUS__X(CONTEXT_SWITCH_STATUS_INVALID_DYNAMIC_CONTEXT_COUNT)\ + FIRMWARE_STATUS__X(CONTEXT_SWITCH_STATUS_CONTEXT_INDEX_OUT_OF_RANGE)\ + FIRMWARE_STATUS__X(CONTEXT_SWITCH_STATUS_TOTAL_PROVIDED_EDGE_LAYERS_LARGER_THEN_EXPECTED)\ \ FIRMWARE_MODULE__X(FIRMWARE_MODULE__D2H_EVENT_MANAGER)\ FIRMWARE_STATUS__X(HAILO_D2H_EVENT_MANAGER_STATUS_MESSAGE_HIGH_PRIORITY_QUEUE_CREATE_FAILED)\ @@ -753,11 +759,12 @@ Updating rules: FIRMWARE_STATUS__X(HAILO_D2H_EVENT_MANAGER_STATUS_INVALID_MESSAGE_QUEUE_HANDLE)\ FIRMWARE_STATUS__X(HAILO_D2H_EVENT_MANAGER_STATUS_SENDING_MESSAGE_FAIL)\ FIRMWARE_STATUS__X(HAILO_D2H_EVENT_MANAGER_STATUS_SEND_EVENT_OVER_UDP_FAIL)\ - FIRMWARE_STATUS__X(HAILO_D2H_EVENT_MANAGER_STATUS_SEND_EVENT_OVER_PCIE_FAIL)\ + FIRMWARE_STATUS__X(HAILO_D2H_EVENT_MANAGER_STATUS_SEND_EVENT_OVER_VDMA_FAIL)\ FIRMWARE_STATUS__X(HAILO_D2H_EVENT_MANAGER_STATUS_INVALID_COMMUNICATION_TYPE)\ - FIRMWARE_STATUS__X(HAILO_D2H_EVENT_MANAGER_STATUS_PCIE_NOT_ACTIVE)\ + FIRMWARE_STATUS__X(HAILO_D2H_EVENT_MANAGER_STATUS_VDMA_COMMUNICATION_NOT_ACTIVE)\ FIRMWARE_STATUS__X(HAILO_D2H_EVENT_MANAGER_STATUS_INVALID_PRIORITY_QUEUE_HANDLE)\ FIRMWARE_STATUS__X(HAILO_D2H_EVENT_MANAGER_STATUS_INIT_UDP_FAIL)\ + FIRMWARE_STATUS__X(HAILO_D2H_EVENT_MANAGER_STATUS_INVALID_PARAMETERS)\ \ FIRMWARE_MODULE__X(FIRMWARE_MODULE__WD)\ FIRMWARE_STATUS__X(WD_STATUS_INVALID_PARAMETERS)\ @@ -997,6 +1004,8 @@ Updating rules: FIRMWARE_STATUS__X(VDMA_SERVICE_STATUS_TOO_LARGE_BYTES_IN_PATTERN)\ FIRMWARE_STATUS__X(VDMA_SERVICE_STATUS_INVALID_ENGINE_INDEX)\ FIRMWARE_STATUS__X(VDMA_SERVICE_STATUS_INVALID_CONSTANTS)\ + FIRMWARE_STATUS__X(VDMA_SERVICE_STATUS_INVALID_CHANNEL_INDEX)\ + FIRMWARE_STATUS__X(VDMA_SERVICE_STATUS_INVALID_EDGE_LAYER_DIRECTION)\ \ FIRMWARE_MODULE__X(FIRMWARE_MODULE__MEMORY_LOGGER)\ FIRMWARE_STATUS__X(MEMORY_LOGGER_STATUS_DEBUG_INSUFFICIENT_MEMORY)\ @@ -1049,6 +1058,30 @@ Updating rules: FIRMWARE_STATUS__X(BURST_CREDITS_TASK_STATUS_INFER_REACHED_TIMEOUT)\ FIRMWARE_STATUS__X(BURST_CREDITS_TASK_STATUS_TASK_DEACTIVATED)\ \ + FIRMWARE_MODULE__X(FIRMWARE_MODULE__TASK_SYNC_EVENTS)\ + FIRMWARE_STATUS__X(TASK_SYNC_EVENTS_STATUS_START_TASK_WHILE_IT_IS_RUNNING)\ + FIRMWARE_STATUS__X(TASK_SYNC_EVENTS_STATUS_START_TASK_WHILE_TASK_NOT_DONE)\ + FIRMWARE_STATUS__X(TASK_SYNC_EVENTS_STATUS_FAILED_TO_RESET_STATE_MACHINE)\ + FIRMWARE_STATUS__X(TASK_SYNC_EVENTS_STATUS_DONE_TASK_WHILE_IT_IS_NOT_RUNNING)\ + \ + FIRMWARE_MODULE__X(FIRMWARE_MODULE__NMS_MANAGER)\ + FIRMWARE_STATUS__X(NMS_MANAGER_STATUS_INVALID_ARGUMENT)\ + FIRMWARE_STATUS__X(NMS_MANAGER_STATUS_WAIT_FOR_INTERRUPT_INTERRUPTED_BY_RESET_REQUEST)\ + FIRMWARE_STATUS__X(NMS_MANAGER_STATUS_INVALID_AGGREGATOR_INDEX)\ + FIRMWARE_STATUS__X(NMS_MANAGER_STATUS_INVALID_OUTPUT_BUFFER_INDEX)\ + FIRMWARE_STATUS__X(NMS_MANAGER_STATUS_INVALID_OUTPUT_BUFFER_CLUSTER_INDEX)\ + FIRMWARE_STATUS__X(NMS_MANAGER_STATUS_INVALID_OUTPUT_BUFFER_INTERFACE)\ + FIRMWARE_STATUS__X(NMS_MANAGER_STATUS_NOT_SUPPORTED_OPERATION)\ + FIRMWARE_STATUS__X(NMS_MANAGER_STATUS_INVALID_NETWORK_INDEX)\ + FIRMWARE_STATUS__X(NMS_MANAGER_STATUS_INVALID_NMS_UNIT_INDEX)\ + \ + FIRMWARE_MODULE__X(FIRMWARE_MODULE__CLUSTER_MANAGER)\ + FIRMWARE_STATUS__X(CLUSTER_MANAGER_STATUS_INVALID_CLUSTER_INDEX)\ + FIRMWARE_STATUS__X(CLUSTER_MANAGER_STATUS_INVALID_INITIAL_L3_CUT)\ + FIRMWARE_STATUS__X(CLUSTER_MANAGER_STATUS_INVALID_INITIAL_L3_OFFSET)\ + FIRMWARE_STATUS__X(CLUSTER_MANAGER_STATUS_INVALID_LCU_INDEX)\ + FIRMWARE_STATUS__X(CLUSTER_MANAGER_STATUS_INVALID_KERNEL_DONE_ADDRESS)\ + FIRMWARE_STATUS__X(CLUSTER_MANAGER_STATUS_RECEIVED_UNEXPECTED_INTERRUPT)\ typedef enum { diff --git a/common/include/user_config_common.h b/common/include/user_config_common.h index 8ecd24c..8fc77d2 100644 --- a/common/include/user_config_common.h +++ b/common/include/user_config_common.h @@ -66,7 +66,8 @@ typedef enum { SOC__NN_CLOCK_250MHz = 250 * 1000 * 1000, SOC__NN_CLOCK_225MHz = 225 * 1000 * 1000, SOC__NN_CLOCK_200MHz = 200 * 1000 * 1000, - SOC__NN_CLOCK_100MHz = 100 * 1000 * 1000 + SOC__NN_CLOCK_100MHz = 100 * 1000 * 1000, + SOC__NN_CLOCK_25MHz = 25 * 1000 * 1000 } SOC__NN_CLOCK_HZ_t; typedef enum { @@ -79,7 +80,8 @@ typedef enum { SOC__CPU_CLOCK_125MHz = SOC__NN_CLOCK_250MHz >> 1, SOC__CPU_CLOCK_112MHz = SOC__NN_CLOCK_225MHz >> 1, SOC__CPU_CLOCK_100MHz = SOC__NN_CLOCK_200MHz >> 1, - SOC__CPU_CLOCK_50MHz = SOC__NN_CLOCK_100MHz >> 1 + SOC__CPU_CLOCK_50MHz = SOC__NN_CLOCK_100MHz >> 1, + SOC__CPU_CLOCK_12MHz = SOC__NN_CLOCK_25MHz >> 1 } SOC__CPU_CLOCK_HZ_t; typedef enum { diff --git a/hailort/CMakeLists.txt b/hailort/CMakeLists.txt index fa34309..bfa42a9 100644 --- a/hailort/CMakeLists.txt +++ b/hailort/CMakeLists.txt @@ -1,32 +1,35 @@ cmake_minimum_required(VERSION 3.0.0) +option(HAILO_BUILD_PYBIND "Build Python binding" OFF) +option(HAILO_BUILD_EMULATOR "Build hailort for emulator" OFF) +option(HAILO_BUILD_UT "Build Unit Tests" OFF) +option(HAILO_BUILD_HW_DEBUG_TOOL "Build hw debug tool" OFF) +option(HAILO_BUILD_GSTREAMER "Compile gstreamer plugins" OFF) +option(HAILO_BUILD_EXAMPLES "Build examples" OFF) +option(HAILO_OFFLINE_COMPILATION "Don't download external dependencies" OFF) +option(HAILO_BUILD_SERVICE "Build hailort service" OFF) +option(HAILO_BUILD_PROFILER "Build hailort profiler" ON) + +if(WIN32 AND ${HAILO_BUILD_SERVICE}) + message(FATAL_ERROR "HailoRT service is not supported on Windows") +endif() + +# Flag for emulator (FPGA/Veloce) +if(HAILO_BUILD_EMULATOR) + message(WARNING "HailoRT is building with Emulator flag on") + set(HAILORT_COMPILE_OPTIONS ${HAILORT_COMPILE_OPTIONS} -DHAILO_EMULATOR) +endif() + # Set firmware version add_definitions( -DFIRMWARE_VERSION_MAJOR=4 ) -add_definitions( -DFIRMWARE_VERSION_MINOR=10 ) +add_definitions( -DFIRMWARE_VERSION_MINOR=12 ) add_definitions( -DFIRMWARE_VERSION_REVISION=0 ) if(HAILO_BUILD_SERVICE) add_definitions( -DHAILO_SUPPORT_MULTI_PROCESS ) endif() -message(STATUS "Building pre_build") -include(${CMAKE_CURRENT_LIST_DIR}/cmake/execute_cmake.cmake) -set(HAILO_EXTERNAL_DIR ${CMAKE_CURRENT_LIST_DIR}/external) -set(HAILO_PRE_BUILD_BUILD_TOOLS ${CMAKE_CURRENT_LIST_DIR}/pre_build/build/tools) - -set(PRE_BUILD_BUILD_TYPE "Release") -execute_cmake( - SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/pre_build - BUILD_DIR ${CMAKE_CURRENT_LIST_DIR}/pre_build/build - CONFIGURE_ARGS - -DCMAKE_BUILD_TYPE=${PRE_BUILD_BUILD_TYPE} - -DCMAKE_INSTALL_PREFIX=${CMAKE_CURRENT_LIST_DIR}/pre_build/install - -DHAILO_EXTERNAL_DIR=${HAILO_EXTERNAL_DIR} - -DHAILO_OFFLINE_COMPILATION=${HAILO_OFFLINE_COMPILATION} - -DHAILO_BUILD_SERVICE=${HAILO_BUILD_SERVICE} - BUILD_ARGS - --config ${PRE_BUILD_BUILD_TYPE} --target install ${CMAKE_EXTRA_BUILD_ARGS} - PARALLEL_BUILD -) +# The logic of prepare_externals is executed in a sperate module so that it can be run externally (via cmake -P prepare_externals.cmake) +include(prepare_externals.cmake) # BENCHMARK_ENABLE_TESTING can be used by other 3rd party projects, therefore we define it # before adding projects @@ -83,7 +86,7 @@ if(HAILO_BUILD_PYBIND) if(NOT PYTHON_EXECUTABLE AND PYBIND11_PYTHON_VERSION) # PYBIND11_PYTHON_VERSION is prioritized (not virtual environment) if PYTHON_EXECUTABLE is not set. # See https://pybind11.readthedocs.io/en/stable/changelog.html#v2-6-0-oct-21-2020 - if(${CMAKE_VERSION} VERSION_LESS "3.12.0") + if(${CMAKE_VERSION} VERSION_LESS "3.22.0") find_package(PythonInterp ${PYBIND11_PYTHON_VERSION} REQUIRED) set(PYTHON_EXECUTABLE ${Python_EXECUTABLE}) else() @@ -116,32 +119,12 @@ if(HAILO_BUILD_SERVICE) add_subdirectory(rpc) endif() -# microprofile -if(HAILO_MICROPROFILE) - add_library(microprofile STATIC EXCLUDE_FROM_ALL external/microprofile/microprofile.cpp) - set_target_properties(microprofile PROPERTIES - CXX_STANDARD 11 - CXX_STANDARD_REQUIRED YES - POSITION_INDEPENDENT_CODE ON - ) - target_compile_definitions(microprofile - PRIVATE - -DMICROPROFILE_WEBSERVER=1 - -DMICROPROFILE_GPU_TIMERS=0 - -DMICROPROFILE_NAME_MAX_LEN=256 - PUBLIC - -DMICROPROFILE_ENABLED=1 - ) - target_include_directories(microprofile PUBLIC external/microprofile) -else() - add_library(microprofile INTERFACE) - target_compile_definitions(microprofile INTERFACE -DMICROPROFILE_ENABLED=0) - target_include_directories(microprofile INTERFACE external/microprofile) -endif() - add_subdirectory(common) add_subdirectory(libhailort) add_subdirectory(hailortcli) +if(HAILO_BUILD_HW_DEBUG_TOOL) + add_subdirectory(tools/hw_debug) +endif() if(HAILO_BUILD_SERVICE) add_subdirectory(hailort_service) @@ -155,4 +138,4 @@ endif() # Compile PCIe Driver if QNX if(CMAKE_SYSTEM_NAME STREQUAL QNX) add_subdirectory(drivers/qnx) -endif() \ No newline at end of file +endif() diff --git a/hailort/LICENSE-3RD-PARTY.md b/hailort/LICENSE-3RD-PARTY.md index 46aead9..04f6ece 100644 --- a/hailort/LICENSE-3RD-PARTY.md +++ b/hailort/LICENSE-3RD-PARTY.md @@ -3,7 +3,7 @@ | CLI11 | University of Cincinnati | 3-Clause BSD | 2.2.0 | Fork | https://github.com/hailo-ai/CLI11 | | Catch2 | Catch2 Authors | BSL-1.0 | 2.13.7 | Cloned entire package | https://github.com/catchorg/Catch2 | | protobuf | Google Inc. | BSD | 3.19.4 | Cloned entire package | https://github.com/protocolbuffers/protobuf | -| pybind11 | Wenzel Jakob | BSD | 2.6.2 | Cloned entire package | https://github.com/pybind/pybind11 | +| pybind11 | Wenzel Jakob | BSD | 2.10.1 | Cloned entire package | https://github.com/pybind/pybind11 | | spdlog | Gabi Melman | MIT | 1.6.1 | Cloned entire package | https://github.com/gabime/spdlog | | folly | Facebook, Inc. and its affiliates | Apache License 2.0 | v2020.08.17.00 | Copied only the file `folly/TokenBucket.h` | https://github.com/facebook/folly | | nlohmann_json_cmake_fetchcontent | ArthurSonzogni | MIT License | v3.9.1 | Cloned entire package | https://github.com/ArthurSonzogni/nlohmann_json_cmake_fetchcontent | @@ -12,5 +12,4 @@ | benchmark | Google Inc. | Apache License 2.0 | 1.6.0 | Cloned entire package | https://github.com/google/benchmark.git | | md5 | Alexander Peslyak | cut-down BSD | - | Copied code from website | http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5 | | pevents | Mahmoud Al-Qudsi | MIT License | master | Cloned entire package | https://github.com/neosmart/pevents.git | -| microprofile | Jonas Meyer | Unlicense License | 3.1 | Cloned entire package | https://github.com/jonasmr/microprofile | | grpc | Google Inc. | Apache License 2.0 | 1.46.0 | Cloned entire package | https://github.com/grpc/grpc | diff --git a/hailort/common/circular_buffer.hpp b/hailort/common/circular_buffer.hpp index 8da5bf0..24c8ca6 100644 --- a/hailort/common/circular_buffer.hpp +++ b/hailort/common/circular_buffer.hpp @@ -4,7 +4,8 @@ **/ /** * @file circular_buffer.hpp - * @brief + * @brief Manages a Single-Producer Single-Consumer queue. The size of the queue must be a power of 2. + * This file exports both low level C struct, and a C++ wrapper. * **/ @@ -45,7 +46,7 @@ typedef struct { (circbuf).size_mask = static_cast((s) - 1) #define CB_RESET(circbuf) \ (circbuf).head = 0; \ - (circbuf).tail = 0 + (circbuf).tail = 0 #define CB_HEAD(x) _CB_FETCH((x).head) #define CB_TAIL(x) _CB_FETCH((x).tail) #define CB_SIZE(x) _CB_FETCH((x).size) @@ -77,7 +78,7 @@ public: void push_back(const T& element) { - // assert(CB_AVAIL(m_circ, CB_HEAD(m_circ), CB_TAIL(m_circ))); + assert(CB_AVAIL(m_circ, CB_HEAD(m_circ), CB_TAIL(m_circ))); m_array[CB_HEAD(m_circ)] = element; CB_ENQUEUE(m_circ, 1); } diff --git a/hailort/common/file_utils.cpp b/hailort/common/file_utils.cpp index 90ff088..4d3faea 100644 --- a/hailort/common/file_utils.cpp +++ b/hailort/common/file_utils.cpp @@ -42,7 +42,7 @@ Expected read_binary_file(const std::string &file_path) auto file_size = get_istream_size(file); CHECK_EXPECTED(file_size, "Failed to get file size"); - auto buffer = Buffer::create(file_size.value()); + auto buffer = Buffer::create(file_size.value()); CHECK_EXPECTED(buffer, "Failed to allocate file buffer ({} bytes}", file_size.value()); // Read the data diff --git a/hailort/common/filesystem.hpp b/hailort/common/filesystem.hpp index 3afe4e8..74d6c77 100644 --- a/hailort/common/filesystem.hpp +++ b/hailort/common/filesystem.hpp @@ -22,6 +22,7 @@ #include #endif + namespace hailort { @@ -34,11 +35,35 @@ public: static Expected get_file_modified_time(const std::string &file_path); static Expected is_directory(const std::string &path); static hailo_status create_directory(const std::string &dir_path); + static Expected get_current_dir(); + static std::string get_home_directory(); + static bool is_path_accesible(const std::string &path); + static bool does_file_exists(const std::string &path); static bool has_suffix(const std::string &file_name, const std::string &suffix) { return (file_name.size() >= suffix.size()) && equal(suffix.rbegin(), suffix.rend(), file_name.rbegin()); } + static std::string remove_suffix(const std::string &file_name, const std::string &suffix) + { + if (!has_suffix(file_name, suffix)) { + return file_name; + } + + return file_name.substr(0, file_name.length() - suffix.length()); + } + + // Emultes https://docs.python.org/3/library/os.path.html#os.path.basename + static std::string basename(const std::string &file_name) + { + const auto last_separator_index = file_name.find_last_of(SEPARATOR); + if (std::string::npos == last_separator_index) { + // No separator found => the file_name is a "basename" + return file_name; + } + return file_name.substr(last_separator_index + 1); + } + private: // OS-specific filesystem directory separator char (i.e. backslash on Windows or forward slash on UNIX) static const char *SEPARATOR; @@ -117,6 +142,11 @@ public: static Expected create(const std::string &file_path, const std::string &mode); ~LockedFile(); + LockedFile(const LockedFile &other) = delete; + LockedFile &operator=(const LockedFile &other) = delete; + LockedFile &operator=(LockedFile &&other) = delete; + LockedFile(LockedFile &&other); + int get_fd() const; private: diff --git a/hailort/common/latency_meter.hpp b/hailort/common/latency_meter.hpp index eaed098..07ca56a 100644 --- a/hailort/common/latency_meter.hpp +++ b/hailort/common/latency_meter.hpp @@ -29,12 +29,12 @@ public: using duration = std::chrono::nanoseconds; using TimestampsArray = CircularArray; - explicit LatencyMeter(const std::set &output_channels, size_t timestamps_list_length) : + explicit LatencyMeter(const std::set &output_names, size_t timestamps_list_length) : m_start_timestamps(timestamps_list_length), m_latency_count(0), m_latency_sum(0) { - for (uint32_t ch : output_channels) { + for (auto &ch : output_names) { m_end_timestamps_per_channel.emplace(ch, TimestampsArray(timestamps_list_length)); } } @@ -54,12 +54,12 @@ public: * after this function is called on all channels. * @note Assumes that only one thread per channel is calling this function. */ - void add_end_sample(uint32_t channel_index, duration timestamp) + void add_end_sample(const std::string &stream_name, duration timestamp) { // Safe to access from several threads (when each pass different channel) because the map cannot // be changed in runtime. - assert(m_end_timestamps_per_channel.find(channel_index) != m_end_timestamps_per_channel.end()); - m_end_timestamps_per_channel.at(channel_index).push_back(timestamp); + assert(m_end_timestamps_per_channel.find(stream_name) != m_end_timestamps_per_channel.end()); + m_end_timestamps_per_channel.at(stream_name).push_back(timestamp); update_latency(); } @@ -118,7 +118,7 @@ private: std::mutex m_lock; TimestampsArray m_start_timestamps; - std::unordered_map m_end_timestamps_per_channel; + std::unordered_map m_end_timestamps_per_channel; size_t m_latency_count; duration m_latency_sum; diff --git a/hailort/common/os/posix/filesystem.cpp b/hailort/common/os/posix/filesystem.cpp index a22d237..1a41347 100644 --- a/hailort/common/os/posix/filesystem.cpp +++ b/hailort/common/os/posix/filesystem.cpp @@ -11,9 +11,11 @@ #include "common/logger_macros.hpp" #include "common/utils.hpp" +#include #include #include #include +#include namespace hailort { @@ -145,7 +147,12 @@ static_assert(false, "Unsupported Platform!"); Expected Filesystem::is_directory(const std::string &path) { struct stat path_stat{}; - CHECK(0 == stat(path.c_str(), &path_stat), make_unexpected(HAILO_FILE_OPERATION_FAILURE), + auto ret_Val = stat(path.c_str(), &path_stat); + if (ret_Val != 0 && (errno == ENOENT)) { + // Directory path does not exist + return false; + } + CHECK(0 == ret_Val, make_unexpected(HAILO_FILE_OPERATION_FAILURE), "stat() on path \"{}\" failed. errno {}", path.c_str(), errno); return S_ISDIR(path_stat.st_mode); @@ -158,6 +165,54 @@ hailo_status Filesystem::create_directory(const std::string &dir_path) return HAILO_SUCCESS; } +Expected Filesystem::get_current_dir() +{ + char cwd[PATH_MAX]; + auto ret_val = getcwd(cwd, sizeof(cwd)); + CHECK_AS_EXPECTED(nullptr != ret_val, HAILO_FILE_OPERATION_FAILURE, "Failed to get current directory path with errno {}", errno); + + return std::string(cwd); +} + +std::string Filesystem::get_home_directory() +{ + const char *homedir = getenv("HOME"); + if (NULL == homedir) { + homedir = getpwuid(getuid())->pw_dir; + } + +#ifdef __QNX__ + const std::string root_dir = "/"; + std::string homedir_str = std::string(homedir); + if (homedir_str == root_dir) { + return homedir_str + "home"; + } +#endif + + return homedir; +} + +bool Filesystem::is_path_accesible(const std::string &path) +{ + auto ret = access(path.c_str(), W_OK); + if (ret == 0) { + return true; + } + else if (EACCES == errno) { + return false; + } else { + std::cerr << "Failed checking path " << path << " access permissions, errno = " << errno << std::endl; + return false; + } +} + +bool Filesystem::does_file_exists(const std::string &path) +{ + // From https://stackoverflow.com/a/12774387 + struct stat buffer; + return (0 == stat(path.c_str(), &buffer)); +} + Expected TempFile::create(const std::string &file_name, const std::string &file_directory) { if (!file_directory.empty()) { @@ -211,12 +266,18 @@ LockedFile::LockedFile(FILE *fp, int fd) : m_fp(fp), m_fd(fd) LockedFile::~LockedFile() { - if (-1 == flock(m_fd, LOCK_UN)) { - LOGGER__ERROR("Failed to unlock file with errno {}", errno); + if (m_fp != nullptr) { + // The lock is released when all descriptors are closed. + // Since we use LOCK_EX, this is the only fd open and the lock will be release after d'tor. fclose(m_fp); } } +LockedFile::LockedFile(LockedFile &&other) : + m_fp(std::exchange(other.m_fp, nullptr)), + m_fd(other.m_fd) +{} + int LockedFile::get_fd() const { return m_fd; diff --git a/hailort/common/os/posix/socket.cpp b/hailort/common/os/posix/socket.cpp index 74d5fc3..4a964fb 100644 --- a/hailort/common/os/posix/socket.cpp +++ b/hailort/common/os/posix/socket.cpp @@ -230,7 +230,7 @@ hailo_status Socket::send_to(const uint8_t *src_buffer, size_t src_buffer_size, } else if (EPIPE == errno) { // When socket is aborted from another thread sendto will return errno EPIPE LOGGER__INFO("Udp send aborted!"); - return HAILO_STREAM_INTERNAL_ABORT; + return HAILO_STREAM_ABORTED_BY_USER; } else { LOGGER__ERROR("Udp failed to send data, errno:{}.", errno); return HAILO_ETH_SEND_FAILURE; @@ -272,7 +272,7 @@ hailo_status Socket::recv_from(uint8_t *dest_buffer, size_t dest_buffer_size, in } else if ((0 == number_of_received_bytes) && (0 != dest_buffer_size)) { LOGGER__INFO("Udp socket was aborted"); - return HAILO_STREAM_INTERNAL_ABORT; + return HAILO_STREAM_ABORTED_BY_USER; } if (result_src_addr_size > src_addr_size) { diff --git a/hailort/common/os/windows/filesystem.cpp b/hailort/common/os/windows/filesystem.cpp index f274385..d9adeae 100644 --- a/hailort/common/os/windows/filesystem.cpp +++ b/hailort/common/os/windows/filesystem.cpp @@ -11,6 +11,9 @@ #include "common/logger_macros.hpp" #include "common/utils.hpp" +#include +#include +#include #include namespace hailort @@ -145,4 +148,93 @@ Expected Filesystem::is_directory(const std::string &path) return PathIsDirectoryA(path.c_str()); } +Expected Filesystem::get_current_dir() +{ + char cwd[MAX_PATH]; + auto ret_val = GetCurrentDirectoryA(MAX_PATH, cwd); + CHECK_AS_EXPECTED(0 != ret_val, HAILO_FILE_OPERATION_FAILURE, "Failed to get current directory path with error: {}", WSAGetLastError()); + + return std::string(cwd); +} + +hailo_status Filesystem::create_directory(const std::string &dir_path) +{ + auto ret_val = CreateDirectory(dir_path.c_str(), nullptr); + CHECK((0 != ret_val) || (GetLastError() == ERROR_ALREADY_EXISTS), HAILO_FILE_OPERATION_FAILURE, "Failed to create directory {}", dir_path); + return HAILO_SUCCESS; +} + +bool Filesystem::is_path_accesible(const std::string &path) +{ + // The code is based on examples from: https://cpp.hotexamples.com/examples/-/-/AccessCheck/cpp-accesscheck-function-examples.html + bool return_val = false; + SECURITY_INFORMATION security_Info = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION; + PSECURITY_DESCRIPTOR security_desc = NULL; + DWORD access_mask = GENERIC_WRITE; + GENERIC_MAPPING mapping = {0xFFFFFFFF}; + mapping.GenericRead = FILE_GENERIC_READ; + mapping.GenericWrite = FILE_GENERIC_WRITE; + mapping.GenericExecute = FILE_GENERIC_EXECUTE; + mapping.GenericAll = FILE_ALL_ACCESS; + HANDLE h_token = NULL; + HANDLE h_impersonated_token = NULL; + PRIVILEGE_SET privilege_set = {0}; + DWORD privilege_set_size = sizeof(privilege_set); + DWORD granted_access = 0; + BOOL access_status = FALSE; + + // Retrieves a copy of the security descriptor for the path + DWORD result = GetNamedSecurityInfo(path.c_str(), SE_FILE_OBJECT, security_Info, NULL, NULL, NULL, NULL, &security_desc); + if (result != ERROR_SUCCESS) { + std::cerr << "Failed to get security information for path " << path << " with error = " << result << std::endl; + return_val = false; + goto l_exit; + } + + MapGenericMask(&access_mask, &mapping); + if (OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &h_token) == 0) { + return_val = false; + std::cerr << "OpenProcessToken() Failed. Cannot check path " << path << " access permissions, last_error = " << GetLastError() << std::endl; + goto l_release_security_desc; + } + + // Getting a handle to an impersonation token. It will represent the client that is attempting to gain access. + if (DuplicateToken(h_token, SecurityImpersonation, &h_impersonated_token) == 0) { + std::cerr << "DuplicateToken() Failed. Cannot check path " << path << " access permissions, last_error = " << GetLastError() << std::endl; + return_val = false; + goto l_close_token; + } + + if (AccessCheck(security_desc, h_impersonated_token, access_mask, &mapping, &privilege_set, &privilege_set_size, &granted_access, &access_status) == 0) { + std::cerr << "AccessCheck Failed. Cannot check path " << path << " access permissions, last_error = " << GetLastError() << std::endl; + return_val = false; + goto l_close_impersonated_token; + } + + return_val = (access_status == TRUE); + +l_close_impersonated_token: + if (NULL != h_impersonated_token) { + (void)CloseHandle(h_impersonated_token); + } + +l_close_token: + if (NULL != h_token) { + (void)CloseHandle(h_token); + } + +l_release_security_desc: + if (NULL != security_desc) { + (void)LocalFree(security_desc); + } +l_exit: + return return_val; +} + +bool Filesystem::does_file_exists(const std::string &path) +{ + // From https://stackoverflow.com/a/2112304 + return ((GetFileAttributes(path.c_str()) != INVALID_FILE_ATTRIBUTES) && (GetLastError() == ERROR_FILE_NOT_FOUND)); +} + } /* namespace hailort */ diff --git a/hailort/common/utils.hpp b/hailort/common/utils.hpp index f74cb21..5bb6f30 100644 --- a/hailort/common/utils.hpp +++ b/hailort/common/utils.hpp @@ -26,8 +26,6 @@ namespace hailort #define IS_FIT_IN_UINT8(number) ((std::numeric_limits::max() >= ((int32_t)(number))) && (std::numeric_limits::min() <= ((int32_t)(number)))) #define IS_FIT_IN_UINT16(number) ((std::numeric_limits::max() >= ((int32_t)(number))) && (std::numeric_limits::min() <= ((int32_t)(number)))) -#define IS_FIT_IN_UINT16(number) ((std::numeric_limits::max() >= ((int32_t)(number))) && (std::numeric_limits::min() <= ((int32_t)(number)))) - template static inline bool contains(const std::vector &container, const T &value) @@ -53,24 +51,6 @@ static inline bool contains(const std::set &container, T value) return (container.find(value) != container.end()); } -template -class unlock_guard { -public: - unlock_guard(T &lock) : m_lock(lock) { - m_lock.unlock(); - } - - ~unlock_guard() { - m_lock.lock(); - } - - unlock_guard(const unlock_guard&) = delete; - unlock_guard& operator=(const unlock_guard&) = delete; - -private: - T &m_lock; -}; - // From https://stackoverflow.com/questions/57092289/do-stdmake-shared-and-stdmake-unique-have-a-nothrow-version template static inline std::unique_ptr make_unique_nothrow(Args&&... args) @@ -250,16 +230,18 @@ _ISEMPTY( \ } while(0) #define CHECK_AS_RPC_STATUS(cond, reply, ret_val, ...) _CHECK_AS_RPC_STATUS((cond), (reply), (ret_val), ISEMPTY(__VA_ARGS__), "" __VA_ARGS__) -#define _CHECK_GRPC_STATUS(status, ret_val) \ - do { \ - if (!status.ok()) { \ - LOGGER__ERROR("CHECK_GRPC_STATUS failed with error massage: {}.", status.error_message()); \ - return ret_val; \ - } \ +#define _CHECK_GRPC_STATUS(status, ret_val, warning_msg) \ + do { \ + if (!status.ok()) { \ + LOGGER__ERROR("CHECK_GRPC_STATUS failed with error massage: {}.", status.error_message()); \ + LOGGER__WARNING(warning_msg); \ + return ret_val; \ + } \ } while(0) -#define CHECK_GRPC_STATUS(status) _CHECK_GRPC_STATUS(status, HAILO_RPC_FAILED) -#define CHECK_GRPC_STATUS_AS_EXPECTED(status) _CHECK_GRPC_STATUS(status, make_unexpected(HAILO_RPC_FAILED)) +#define SERVICE_WARNING_MSG ("Make sure HailoRT service is enabled and active!") +#define CHECK_GRPC_STATUS(status) _CHECK_GRPC_STATUS(status, HAILO_RPC_FAILED, SERVICE_WARNING_MSG) +#define CHECK_GRPC_STATUS_AS_EXPECTED(status) _CHECK_GRPC_STATUS(status, make_unexpected(HAILO_RPC_FAILED), SERVICE_WARNING_MSG) #endif #define _CHECK_EXPECTED(obj, is_default, fmt, ...) \ diff --git a/hailort/drivers/common/hailo_ioctl_common.h b/hailort/drivers/common/hailo_ioctl_common.h index 3b25845..594d88d 100644 --- a/hailort/drivers/common/hailo_ioctl_common.h +++ b/hailort/drivers/common/hailo_ioctl_common.h @@ -6,6 +6,9 @@ #ifndef _HAILO_IOCTL_COMMON_H_ #define _HAILO_IOCTL_COMMON_H_ + +#define DESCRIPTORS_IN_BUFFER(buffer_size, desc_page_size) (((buffer_size) + (desc_page_size) - 1) / (desc_page_size)) + // This value is not easily changeable. // For example: the channel interrupts ioctls assume we have up to 32 channels #define MAX_VDMA_CHANNELS_PER_ENGINE (32) @@ -84,6 +87,11 @@ struct hailo_channel_interrupt_timestamp { uint16_t desc_num_processed; }; +typedef struct { + uint16_t is_buffer_in_use; + uint16_t buffer_len; +} hailo_d2h_buffer_details_t; + // This struct is the same as `enum dma_data_direction` (defined in linux/dma-direction) enum hailo_dma_data_direction { HAILO_DMA_BIDIRECTIONAL = 0, @@ -145,6 +153,7 @@ struct hailo_desc_list_bind_vdma_buffer_params { uintptr_t desc_handle; // in uint16_t desc_page_size; // in uint8_t channel_index; // in + size_t offset; // in }; /* structure used in ioctl HAILO_VDMA_CHANNEL_ENABLE */ @@ -152,9 +161,6 @@ struct hailo_vdma_channel_enable_params { uint8_t engine_index; // in uint8_t channel_index; // in enum hailo_dma_data_direction direction; // in - // If desc_list_handle is set to valid handle (different than INVALID_DRIVER_HANDLE_VALUE), - // the driver will start the channel with the given descriptors list. - uintptr_t desc_list_handle; // in bool enable_timestamps_measure; // in uint64_t channel_handle; // out }; @@ -221,9 +227,9 @@ struct hailo_fw_control { enum hailo_cpu_id cpu_id; }; -/* structure used in ioctl HAILO_BAR_TRANSFER */ +/* structure used in ioctl HAILO_MEMORY_TRANSFER */ // Max bar transfer size gotten from ATR0_TABLE_SIZE -#define MAX_BAR_TRANSFER_LENGTH (4096) +#define MAX_MEMORY_TRANSFER_LENGTH (4096) enum hailo_transfer_direction { TRANSFER_READ = 0, @@ -233,12 +239,34 @@ enum hailo_transfer_direction { TRANSFER_MAX_ENUM = INT_MAX, }; -struct hailo_bar_transfer_params { +enum hailo_transfer_memory_type { + HAILO_TRANSFER_DEVICE_DIRECT_MEMORY, + + // vDMA memories + HAILO_TRANSFER_MEMORY_VDMA0 = 0x100, + HAILO_TRANSFER_MEMORY_VDMA1, + HAILO_TRANSFER_MEMORY_VDMA2, + + // PCIe driver memories + HAILO_TRANSFER_MEMORY_PCIE_BAR0 = 0x200, + HAILO_TRANSFER_MEMORY_PCIE_BAR2 = 0x202, + HAILO_TRANSFER_MEMORY_PCIE_BAR4 = 0x204, + + // DRAM DMA driver memories + HAILO_TRANSFER_MEMORY_DMA_ENGINE0 = 0x300, + HAILO_TRANSFER_MEMORY_DMA_ENGINE1, + HAILO_TRANSFER_MEMORY_DMA_ENGINE2, + + /** Max enum value to maintain ABI Integrity */ + HAILO_TRANSFER_MEMORY_MAX_ENUM = INT_MAX, +}; + +struct hailo_memory_transfer_params { enum hailo_transfer_direction transfer_direction; // in - uint32_t bar_index; // in - off_t offset; // in + enum hailo_transfer_memory_type memory_type; // in + uint64_t address; // in size_t count; // in - uint8_t buffer[MAX_BAR_TRANSFER_LENGTH]; // in/out + uint8_t buffer[MAX_MEMORY_TRANSFER_LENGTH]; // in/out }; /* structure used in ioctl HAILO_VDMA_CHANNEL_READ_REGISTER */ @@ -286,10 +314,12 @@ struct hailo_d2h_notification { }; enum hailo_board_type { - HAILO8 = 0, - HAILO_MERCURY, - HAILO_BOARD_COUNT, - HAILO_INVALID_BOARD = 0xFFFFFFFF, + HAILO_BOARD_TYPE_HAILO8 = 0, + HAILO_BOARD_TYPE_MERCURY, + HAILO_BOARD_TYPE_COUNT, + + /** Max enum value to maintain ABI Integrity */ + HAILO_BOARD_TYPE_MAX_ENUM = INT_MAX }; enum hailo_dma_type { @@ -306,6 +336,7 @@ struct hailo_device_properties { enum hailo_allocation_mode allocation_mode; enum hailo_dma_type dma_type; size_t dma_engines_count; + bool is_fw_loaded; #ifdef __QNX__ pid_t resource_manager_pid; #endif // __QNX__ @@ -345,7 +376,7 @@ struct hailo_allocate_continuous_buffer_params { #pragma pack(pop) enum hailo_general_ioctl_code { - HAILO_BAR_TRANSFER_CODE, + HAILO_MEMORY_TRANSFER_CODE, HAILO_FW_CONTROL_CODE, HAILO_READ_NOTIFICATION_CODE, HAILO_DISABLE_NOTIFICATION_CODE, @@ -358,7 +389,7 @@ enum hailo_general_ioctl_code { HAILO_GENERAL_IOCTL_MAX_NR, }; -#define HAILO_BAR_TRANSFER _IOWR_(HAILO_GENERAL_IOCTL_MAGIC, HAILO_BAR_TRANSFER_CODE, struct hailo_bar_transfer_params) +#define HAILO_MEMORY_TRANSFER _IOWR_(HAILO_GENERAL_IOCTL_MAGIC, HAILO_MEMORY_TRANSFER_CODE, struct hailo_memory_transfer_params) #define HAILO_FW_CONTROL _IOWR_(HAILO_GENERAL_IOCTL_MAGIC, HAILO_FW_CONTROL_CODE, struct hailo_fw_control) #define HAILO_READ_NOTIFICATION _IOW_(HAILO_GENERAL_IOCTL_MAGIC, HAILO_READ_NOTIFICATION_CODE, struct hailo_d2h_notification) #define HAILO_DISABLE_NOTIFICATION _IO_(HAILO_GENERAL_IOCTL_MAGIC, HAILO_DISABLE_NOTIFICATION_CODE) @@ -391,13 +422,13 @@ enum hailo_vdma_ioctl_code { HAILO_VDMA_IOCTL_MAX_NR, }; -#define HAILO_VDMA_CHANNEL_ENABLE _IOWR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_CHANNEL_ENABLE_CODE, struct hailo_vdma_channel_enable_params) -#define HAILO_VDMA_CHANNEL_DISABLE _IOR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_CHANNEL_DISABLE_CODE, struct hailo_vdma_channel_disable_params) -#define HAILO_VDMA_CHANNEL_WAIT_INT _IOR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_CHANNEL_WAIT_INT_CODE, struct hailo_vdma_channel_wait_params) -#define HAILO_VDMA_CHANNEL_ABORT _IOR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_CHANNEL_ABORT_CODE, struct hailo_vdma_channel_abort_params) -#define HAILO_VDMA_CHANNEL_CLEAR_ABORT _IOR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_CHANNEL_CLEAR_ABORT_CODE, struct hailo_vdma_channel_clear_abort_params) -#define HAILO_VDMA_CHANNEL_READ_REGISTER _IOWR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_CHANNEL_READ_REGISTER_CODE, struct hailo_vdma_channel_read_register_params) -#define HAILO_VDMA_CHANNEL_WRITE_REGISTER _IOR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_CHANNEL_WRITE_REGISTER_CODE, struct hailo_vdma_channel_write_register_params) +#define HAILO_VDMA_CHANNEL_ENABLE _IOWR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_CHANNEL_ENABLE_CODE, struct hailo_vdma_channel_enable_params) +#define HAILO_VDMA_CHANNEL_DISABLE _IOR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_CHANNEL_DISABLE_CODE, struct hailo_vdma_channel_disable_params) +#define HAILO_VDMA_CHANNEL_WAIT_INT _IOWR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_CHANNEL_WAIT_INT_CODE, struct hailo_vdma_channel_wait_params) +#define HAILO_VDMA_CHANNEL_ABORT _IOR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_CHANNEL_ABORT_CODE, struct hailo_vdma_channel_abort_params) +#define HAILO_VDMA_CHANNEL_CLEAR_ABORT _IOR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_CHANNEL_CLEAR_ABORT_CODE, struct hailo_vdma_channel_clear_abort_params) +#define HAILO_VDMA_CHANNEL_READ_REGISTER _IOWR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_CHANNEL_READ_REGISTER_CODE, struct hailo_vdma_channel_read_register_params) +#define HAILO_VDMA_CHANNEL_WRITE_REGISTER _IOR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_CHANNEL_WRITE_REGISTER_CODE, struct hailo_vdma_channel_write_register_params) #define HAILO_VDMA_BUFFER_MAP _IOWR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_BUFFER_MAP_CODE, struct hailo_vdma_buffer_map_params) #define HAILO_VDMA_BUFFER_UNMAP _IOR_(HAILO_VDMA_IOCTL_MAGIC, HAILO_VDMA_BUFFER_UNMAP_CODE, struct hailo_vdma_buffer_unmap_params) diff --git a/hailort/drivers/win/include/Public.h b/hailort/drivers/win/include/Public.h index 8423713..7c0c9d9 100644 --- a/hailort/drivers/win/include/Public.h +++ b/hailort/drivers/win/include/Public.h @@ -102,7 +102,7 @@ struct tCompatibleHailoIoctlData tCompatibleHailoIoctlParam Parameters; ULONG_PTR Value; union { - hailo_bar_transfer_params BarTransfer; + hailo_memory_transfer_params MemoryTransfer; hailo_vdma_channel_enable_params ChannelEnable; hailo_vdma_channel_disable_params ChannelDisable; hailo_vdma_channel_wait_params ChannelWait; diff --git a/hailort/hailort_service/CMakeLists.txt b/hailort/hailort_service/CMakeLists.txt index 2a6fdff..98f1278 100644 --- a/hailort/hailort_service/CMakeLists.txt +++ b/hailort/hailort_service/CMakeLists.txt @@ -4,6 +4,7 @@ add_executable(hailort_service hailort_rpc_service.cpp hailort_service.cpp service_resource_manager.hpp + ${HAILORT_COMMON_CPP_SOURCES} ) target_compile_options(hailort_service PRIVATE ${HAILORT_COMPILE_OPTIONS}) set_property(TARGET hailort_service PROPERTY CXX_STANDARD 14) @@ -15,17 +16,28 @@ target_link_libraries(hailort_service target_include_directories(hailort_service PRIVATE ${HAILORT_INC_DIR} + ${HAILORT_COMMON_DIR} ${COMMON_INC_DIR} ${RPC_DIR} ) disable_exceptions(hailort_service) -# Install systemd unit file -set(SYSTEMD_UNIT_DIR "/lib/systemd/system/") +set(SYSTEMD_UNIT_DIR "lib/systemd/system/") if(NOT CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) set(SYSTEMD_UNIT_DIR ${CMAKE_INSTALL_PREFIX}/${SYSTEMD_UNIT_DIR}) endif() +# Install service's environment variables file +set(ENV_VARS_FILE_DIR ${CMAKE_INSTALL_SYSCONFDIR}/default/) +set(HAILORT_SERVICE_ENV_VARS_FILE ${CMAKE_CURRENT_SOURCE_DIR}/hailort_service) +install( + FILES "${HAILORT_SERVICE_ENV_VARS_FILE}" + DESTINATION "${ENV_VARS_FILE_DIR}" + CONFIGURATIONS Release + COMPONENT hailort_service +) + +# Install systemd unit file set(HAILORT_SERVICE_UNIT_FILE ${CMAKE_CURRENT_SOURCE_DIR}/hailort.service) install( FILES "${HAILORT_SERVICE_UNIT_FILE}" @@ -40,8 +52,15 @@ install( CONFIGURATIONS Release ) -# Create empty directory for hailort log file +set(DAEMON_PID_DIR "/run/hailo") +add_definitions(-DHAILO_DAEMON_PID_DIR="${DAEMON_PID_DIR}") +add_definitions(-DHAILO_DAEMON_PID_FILE="${DAEMON_PID_DIR}/hailort_service.pid") + if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + # Create empty directory for hailort log file set(HAILORT_LOG_DIR "/var/log/hailo") install(DIRECTORY DESTINATION ${HAILORT_LOG_DIR}) + + # Create empty directory for default PID file + install(DIRECTORY DESTINATION ${DAEMON_PID_DIR}) endif() \ No newline at end of file diff --git a/hailort/hailort_service/hailort.service b/hailort/hailort_service/hailort.service index f702002..05efb6f 100644 --- a/hailort/hailort_service/hailort.service +++ b/hailort/hailort_service/hailort.service @@ -4,10 +4,13 @@ Documentation=https://github.com/hailo-ai/hailort [Service] Type=forking +EnvironmentFile=/etc/default/hailort_service ExecStart=/usr/local/bin/hailort_service Restart=on-failure RemainAfterExit=yes -Environment="HAILORT_LOGGER_PATH=/var/log/hailo" +PIDFile=/run/hailo/hailort_service.pid +ExecReload=/bin/kill -HUP $MAINPID +ExecStartPost=/bin/sleep 0.1 [Install] -WantedBy=multi-user.target \ No newline at end of file +WantedBy=multi-user.target diff --git a/hailort/hailort_service/hailort_rpc_service.cpp b/hailort/hailort_service/hailort_rpc_service.cpp index c24c626..a7222cb 100644 --- a/hailort/hailort_service/hailort_rpc_service.cpp +++ b/hailort/hailort_service/hailort_rpc_service.cpp @@ -65,7 +65,6 @@ grpc::Status HailoRtRpcService::VDevice_create(grpc::ServerContext *, const VDev hailo_vdevice_params_t params = { .device_count = params_proto.device_count(), - .device_infos = nullptr, .device_ids = device_ids.data(), .scheduling_algorithm = static_cast(params_proto.scheduling_algorithm()), .group_id = params_proto.group_id().c_str(), @@ -180,6 +179,19 @@ grpc::Status HailoRtRpcService::VDevice_get_physical_devices_ids(grpc::ServerCon return grpc::Status::OK; } +grpc::Status HailoRtRpcService::VDevice_get_default_streams_interface(grpc::ServerContext*, + const VDevice_get_default_streams_interface_Request* request, VDevice_get_default_streams_interface_Reply* reply) +{ + auto lambda = [](std::shared_ptr vdevice) { + return vdevice->get_default_streams_interface(); + }; + auto &vdevice_manager = ServiceResourceManager::get_instance(); + auto stream_interface = vdevice_manager.execute>(request->handle(), lambda); + CHECK_EXPECTED_AS_RPC_STATUS(stream_interface, reply); + reply->set_stream_interface(*stream_interface); + return grpc::Status::OK; +} + grpc::Status HailoRtRpcService::ConfiguredNetworkGroup_release(grpc::ServerContext*, const Release_Request *request, Release_Reply *reply) { @@ -189,6 +201,22 @@ grpc::Status HailoRtRpcService::ConfiguredNetworkGroup_release(grpc::ServerConte return grpc::Status::OK; } +ProtoNamedVStreamParams get_named_params(const std::string &name, const hailo_vstream_params_t ¶ms) +{ + ProtoNamedVStreamParams named_params; + named_params.set_name(name); + auto proto_params = named_params.mutable_params(); + auto proto_user_buffer_format = proto_params->mutable_user_buffer_format(); + proto_user_buffer_format->set_type(params.user_buffer_format.type); + proto_user_buffer_format->set_order(params.user_buffer_format.order); + proto_user_buffer_format->set_flags(params.user_buffer_format.flags); + proto_params->set_timeout_ms(params.timeout_ms); + proto_params->set_queue_size(params.queue_size); + proto_params->set_vstream_stats_flags(params.vstream_stats_flags); + proto_params->set_pipeline_elements_stats_flags(params.pipeline_elements_stats_flags); + return named_params; +} + grpc::Status HailoRtRpcService::ConfiguredNetworkGroup_make_input_vstream_params(grpc::ServerContext*, const ConfiguredNetworkGroup_make_input_vstream_params_Request *request, ConfiguredNetworkGroup_make_input_vstream_params_Reply *reply) @@ -202,20 +230,10 @@ grpc::Status HailoRtRpcService::ConfiguredNetworkGroup_make_input_vstream_params request->timeout_ms(), request->queue_size(), request->network_name()); CHECK_EXPECTED_AS_RPC_STATUS(expected_params, reply); auto params_map = reply->mutable_vstream_params_map(); + auto params_map_impl = params_map->mutable_vstream_params_map(); for (auto& name_to_params : expected_params.value()) { - NamedVStreamParams named_params; - named_params.set_name(name_to_params.first); - auto params = name_to_params.second; - auto proto_params = named_params.mutable_params(); - auto proto_user_buffer_format = proto_params->mutable_user_buffer_format(); - proto_user_buffer_format->set_type(params.user_buffer_format.type); - proto_user_buffer_format->set_order(params.user_buffer_format.order); - proto_user_buffer_format->set_flags(params.user_buffer_format.flags); - proto_params->set_timeout_ms(params.timeout_ms); - proto_params->set_queue_size(params.queue_size); - proto_params->set_vstream_stats_flags(params.vstream_stats_flags); - proto_params->set_pipeline_elements_stats_flags(params.pipeline_elements_stats_flags); - params_map->Add(std::move(named_params)); + auto named_params = get_named_params(name_to_params.first, name_to_params.second); + params_map_impl->Add(std::move(named_params)); } reply->set_status(static_cast(HAILO_SUCCESS)); return grpc::Status::OK; @@ -235,20 +253,37 @@ grpc::Status HailoRtRpcService::ConfiguredNetworkGroup_make_output_vstream_param request->timeout_ms(), request->queue_size(), request->network_name()); CHECK_EXPECTED_AS_RPC_STATUS(expected_params, reply); auto params_map = reply->mutable_vstream_params_map(); + auto params_map_impl = params_map->mutable_vstream_params_map(); for (auto& name_to_params : expected_params.value()) { - NamedVStreamParams named_params; - named_params.set_name(name_to_params.first); - auto params = name_to_params.second; - auto proto_params = named_params.mutable_params(); - auto proto_user_buffer_format = proto_params->mutable_user_buffer_format(); - proto_user_buffer_format->set_type(params.user_buffer_format.type); - proto_user_buffer_format->set_order(params.user_buffer_format.order); - proto_user_buffer_format->set_flags(params.user_buffer_format.flags); - proto_params->set_timeout_ms(params.timeout_ms); - proto_params->set_queue_size(params.queue_size); - proto_params->set_vstream_stats_flags(params.vstream_stats_flags); - proto_params->set_pipeline_elements_stats_flags(params.pipeline_elements_stats_flags); - params_map->Add(std::move(named_params)); + auto named_params = get_named_params(name_to_params.first, name_to_params.second); + params_map_impl->Add(std::move(named_params)); + } + reply->set_status(static_cast(HAILO_SUCCESS)); + return grpc::Status::OK; +} + +grpc::Status HailoRtRpcService::ConfiguredNetworkGroup_make_output_vstream_params_groups(grpc::ServerContext*, + const ConfiguredNetworkGroup_make_output_vstream_params_groups_Request *request, + ConfiguredNetworkGroup_make_output_vstream_params_groups_Reply *reply) +{ + auto lambda = [](std::shared_ptr cng, bool quantized, + hailo_format_type_t format_type, uint32_t timeout_ms, uint32_t queue_size) { + return cng->make_output_vstream_params_groups(quantized, format_type, timeout_ms, queue_size); + }; + auto &manager = ServiceResourceManager::get_instance(); + auto expected_params = manager.execute>>>(request->handle(), + lambda, request->quantized(), static_cast(request->format_type()), + request->timeout_ms(), request->queue_size()); + CHECK_EXPECTED_AS_RPC_STATUS(expected_params, reply); + auto params_map_vector = reply->mutable_vstream_params_groups(); + for (auto ¶ms_map : expected_params.value()) { + ProtoNamedVStreamParamsMap params_map_proto; + auto params_map_impl_proto = params_map_proto.mutable_vstream_params_map(); + for (auto& name_to_params : params_map) { + auto named_params = get_named_params(name_to_params.first, name_to_params.second); + params_map_impl_proto->Add(std::move(named_params)); + } + params_map_vector->Add(std::move(params_map_proto)); } reply->set_status(static_cast(HAILO_SUCCESS)); return grpc::Status::OK; @@ -282,7 +317,7 @@ grpc::Status HailoRtRpcService::ConfiguredNetworkGroup_get_output_vstream_groups auto output_vstream_groups = expected_output_vstream_groups.value(); auto groups_proto = reply->mutable_output_vstream_groups(); for (auto& group : output_vstream_groups) { - VStreamGroup group_proto; + ProtoVStreamGroup group_proto; for (auto& name : group) { auto vstream_group_proto = group_proto.mutable_vstream_group(); vstream_group_proto->Add(std::move(name)); @@ -293,34 +328,39 @@ grpc::Status HailoRtRpcService::ConfiguredNetworkGroup_get_output_vstream_groups return grpc::Status::OK; } +void serialize_vstream_info(const hailo_vstream_info_t &info, ProtoVStreamInfo *info_proto) +{ + info_proto->set_name(std::string(info.name)); + info_proto->set_network_name(std::string(info.network_name)); + info_proto->set_direction(static_cast(info.direction)); + auto format_proto = info_proto->mutable_format(); + format_proto->set_flags(info.format.flags); + format_proto->set_order(info.format.order); + format_proto->set_type(info.format.type); + if (info.format.order == HAILO_FORMAT_ORDER_HAILO_NMS) { + auto nms_shape_proto = info_proto->mutable_nms_shape(); + nms_shape_proto->set_number_of_classes(info.nms_shape.number_of_classes); + nms_shape_proto->set_max_bbox_per_class(info.nms_shape.max_bboxes_per_class); + } else { + auto shape_proto = info_proto->mutable_shape(); + shape_proto->set_height(info.shape.height); + shape_proto->set_width(info.shape.width); + shape_proto->set_features(info.shape.features); + } + auto quant_info_proto = info_proto->mutable_quant_info(); + quant_info_proto->set_qp_zp(info.quant_info.qp_zp); + quant_info_proto->set_qp_scale(info.quant_info.qp_scale); + quant_info_proto->set_limvals_min(info.quant_info.limvals_min); + quant_info_proto->set_limvals_max(info.quant_info.limvals_max); +} + void serialize_vstream_infos(ConfiguredNetworkGroup_get_vstream_infos_Reply *reply, const std::vector &infos) { auto vstream_infos_proto = reply->mutable_vstream_infos(); for (auto& info : infos) { - VStreamInfo info_proto; - info_proto.set_name(std::string(info.name)); - info_proto.set_network_name(std::string(info.network_name)); - info_proto.set_direction(static_cast(info.direction)); - auto format_proto = info_proto.mutable_format(); - format_proto->set_flags(info.format.flags); - format_proto->set_order(info.format.order); - format_proto->set_type(info.format.type); - if (info.format.order == HAILO_FORMAT_ORDER_HAILO_NMS) { - auto nms_shape_proto = info_proto.mutable_nms_shape(); - nms_shape_proto->set_number_of_classes(info.nms_shape.number_of_classes); - nms_shape_proto->set_max_bbox_per_class(info.nms_shape.max_bboxes_per_class); - } else { - auto shape_proto = info_proto.mutable_shape(); - shape_proto->set_height(info.shape.height); - shape_proto->set_width(info.shape.width); - shape_proto->set_features(info.shape.features); - } - auto quant_info_proto = info_proto.mutable_quant_info(); - quant_info_proto->set_qp_zp(info.quant_info.qp_zp); - quant_info_proto->set_qp_scale(info.quant_info.qp_scale); - quant_info_proto->set_limvals_min(info.quant_info.limvals_min); - quant_info_proto->set_limvals_max(info.quant_info.limvals_max); + ProtoVStreamInfo info_proto; + serialize_vstream_info(info, &info_proto); vstream_infos_proto->Add(std::move(info_proto)); } } @@ -397,6 +437,42 @@ grpc::Status HailoRtRpcService::ConfiguredNetworkGroup_set_scheduler_threshold(g return grpc::Status::OK; } +grpc::Status HailoRtRpcService::ConfiguredNetworkGroup_get_config_params(grpc::ServerContext*, + const ConfiguredNetworkGroup_get_config_params_Request *request, + ConfiguredNetworkGroup_get_config_params_Reply *reply) +{ + auto lambda = [](std::shared_ptr cng) { + return cng->get_config_params(); + }; + auto &net_group_manager = ServiceResourceManager::get_instance(); + auto expected_params = net_group_manager.execute>(request->handle(), lambda); + CHECK_EXPECTED_AS_RPC_STATUS(expected_params, reply); + auto net_configure_params = expected_params.value(); + auto proto_network_configure_params = reply->mutable_params(); + proto_network_configure_params->set_batch_size(net_configure_params.batch_size); + proto_network_configure_params->set_power_mode(net_configure_params.power_mode); + proto_network_configure_params->set_latency(net_configure_params.latency); + for (const auto &name_stream_params_pair : net_configure_params.stream_params_by_name) { + auto proto_name_streams_params = proto_network_configure_params->add_stream_params_map(); + proto_name_streams_params->set_name(name_stream_params_pair.first); + + auto proto_stream_params = proto_name_streams_params->mutable_params(); + auto stream_params = name_stream_params_pair.second; + proto_stream_params->set_stream_interface(stream_params.stream_interface); + proto_stream_params->set_direction(stream_params.direction); + } + for (const auto &name_network_params_pair : net_configure_params.network_params_by_name) { + auto proto_name_network_params = proto_network_configure_params->add_network_params_map(); + proto_name_network_params->set_name(name_network_params_pair.first); + + auto proto_network_params = proto_name_network_params->mutable_params(); + auto network_params = name_network_params_pair.second; + proto_network_params->set_batch_size(network_params.batch_size); + } + reply->set_status(static_cast(HAILO_SUCCESS)); + return grpc::Status::OK; +} + grpc::Status HailoRtRpcService::InputVStreams_create(grpc::ServerContext *, const VStream_create_Request *request, VStreams_create_Reply *reply) { @@ -493,9 +569,9 @@ grpc::Status HailoRtRpcService::OutputVStream_release(grpc::ServerContext *, con return grpc::Status::OK; } -grpc::Status HailoRtRpcService::ConfiguredNetworkGroup_get_name(grpc::ServerContext*, - const ConfiguredNetworkGroup_get_name_Request *request, - ConfiguredNetworkGroup_get_name_Reply *reply) +grpc::Status HailoRtRpcService::ConfiguredNetworkGroup_name(grpc::ServerContext*, + const ConfiguredNetworkGroup_name_Request *request, + ConfiguredNetworkGroup_name_Reply *reply) { auto lambda = [](std::shared_ptr cng) { return cng->name(); @@ -568,7 +644,7 @@ grpc::Status HailoRtRpcService::ConfiguredNetworkGroup_get_all_stream_infos(grpc CHECK_EXPECTED_AS_RPC_STATUS(expected_stream_infos, reply); auto proto_stream_infos = reply->mutable_stream_infos(); for (auto& stream_info : expected_stream_infos.value()) { - StreamInfo proto_stream_info; + ProtoStreamInfo proto_stream_info; if (stream_info.format.order == HAILO_FORMAT_ORDER_HAILO_NMS) { auto proto_nms_info = proto_stream_info.mutable_nms_info(); proto_nms_info->set_number_of_classes(stream_info.nms_info.number_of_classes); @@ -626,6 +702,20 @@ grpc::Status HailoRtRpcService::ConfiguredNetworkGroup_get_latency_measurement(g return grpc::Status::OK; } +grpc::Status HailoRtRpcService::ConfiguredNetworkGroup_is_multi_context(grpc::ServerContext*, + const ConfiguredNetworkGroup_is_multi_context_Request *request, + ConfiguredNetworkGroup_is_multi_context_Reply *reply) +{ + auto lambda = [](std::shared_ptr cng) { + return cng->is_multi_context(); + }; + auto &manager = ServiceResourceManager::get_instance(); + auto is_multi_context = manager.execute(request->handle(), lambda); + reply->set_is_multi_context(static_cast(is_multi_context)); + reply->set_status(static_cast(HAILO_SUCCESS)); + return grpc::Status::OK; +} + grpc::Status HailoRtRpcService::InputVStream_get_frame_size(grpc::ServerContext*, const VStream_get_frame_size_Request *request, VStream_get_frame_size_Reply *reply) { @@ -673,7 +763,7 @@ grpc::Status HailoRtRpcService::InputVStream_name(grpc::ServerContext*, const VS auto &manager = ServiceResourceManager::get_instance(); auto name = manager.execute(request->handle(), lambda); reply->set_name(name); - reply->set_status(HAILO_SUCCESS); + reply->set_status(static_cast(HAILO_SUCCESS)); return grpc::Status::OK; } @@ -686,7 +776,33 @@ grpc::Status HailoRtRpcService::OutputVStream_name(grpc::ServerContext*, const V auto &manager = ServiceResourceManager::get_instance(); auto name = manager.execute(request->handle(), lambda); reply->set_name(name); - reply->set_status(HAILO_SUCCESS); + reply->set_status(static_cast(HAILO_SUCCESS)); + return grpc::Status::OK; +} + +grpc::Status HailoRtRpcService::InputVStream_network_name(grpc::ServerContext*, const VStream_network_name_Request *request, + VStream_network_name_Reply *reply) +{ + auto lambda = [](std::shared_ptr input_vstream) { + return input_vstream->network_name(); + }; + auto &manager = ServiceResourceManager::get_instance(); + auto name = manager.execute(request->handle(), lambda); + reply->set_network_name(name); + reply->set_status(static_cast(HAILO_SUCCESS)); + return grpc::Status::OK; +} + +grpc::Status HailoRtRpcService::OutputVStream_network_name(grpc::ServerContext*, const VStream_network_name_Request *request, + VStream_network_name_Reply *reply) +{ + auto lambda = [](std::shared_ptr output_vstream) { + return output_vstream->network_name(); + }; + auto &manager = ServiceResourceManager::get_instance(); + auto name = manager.execute(request->handle(), lambda); + reply->set_network_name(name); + reply->set_status(static_cast(HAILO_SUCCESS)); return grpc::Status::OK; } @@ -714,29 +830,91 @@ grpc::Status HailoRtRpcService::OutputVStream_abort(grpc::ServerContext*, const return grpc::Status::OK; } -grpc::Status HailoRtRpcService::InputVStream_resume(grpc::ServerContext*, const VStream_resume_Request *, - VStream_resume_Reply *) +grpc::Status HailoRtRpcService::InputVStream_resume(grpc::ServerContext*, const VStream_resume_Request *request, + VStream_resume_Reply *reply) +{ + auto lambda = [](std::shared_ptr input_vstream) { + return input_vstream->resume(); + }; + auto &manager = ServiceResourceManager::get_instance(); + auto status = manager.execute(request->handle(), lambda); + reply->set_status(status); + return grpc::Status::OK; +} + +grpc::Status HailoRtRpcService::OutputVStream_resume(grpc::ServerContext*, const VStream_resume_Request *request, + VStream_resume_Reply *reply) +{ + auto lambda = [](std::shared_ptr output_vstream) { + return output_vstream->resume(); + }; + auto &manager = ServiceResourceManager::get_instance(); + auto status = manager.execute(request->handle(), lambda); + reply->set_status(status); + return grpc::Status::OK; +} + +grpc::Status HailoRtRpcService::InputVStream_get_user_buffer_format(grpc::ServerContext*, const VStream_get_user_buffer_format_Request *request, + VStream_get_user_buffer_format_Reply *reply) { - // TODO - HRT-7892 - // auto lambda = [](std::shared_ptr input_vstream) { - // return input_vstream->resume(); - // }; - // auto &manager = ServiceResourceManager::get_instance(); - // auto status = manager.execute(request->handle(), lambda); - // reply->set_status(status); + auto lambda = [](std::shared_ptr input_vstream) { + return input_vstream->get_user_buffer_format(); + }; + auto &manager = ServiceResourceManager::get_instance(); + auto format = manager.execute(request->handle(), lambda); + reply->set_status(static_cast(HAILO_SUCCESS)); + + auto proto_user_buffer_format = reply->mutable_user_buffer_format(); + proto_user_buffer_format->set_type(format.type); + proto_user_buffer_format->set_order(format.order); + proto_user_buffer_format->set_flags(format.flags); + + return grpc::Status::OK; +} + +grpc::Status HailoRtRpcService::OutputVStream_get_user_buffer_format(grpc::ServerContext*, const VStream_get_user_buffer_format_Request *request, + VStream_get_user_buffer_format_Reply *reply) +{ + auto lambda = [](std::shared_ptr output_vstream) { + return output_vstream->get_user_buffer_format(); + }; + auto &manager = ServiceResourceManager::get_instance(); + auto format = manager.execute(request->handle(), lambda); + reply->set_status(static_cast(HAILO_SUCCESS)); + + auto proto_user_buffer_format = reply->mutable_user_buffer_format(); + proto_user_buffer_format->set_type(format.type); + proto_user_buffer_format->set_order(format.order); + proto_user_buffer_format->set_flags(format.flags); + + return grpc::Status::OK; +} + +grpc::Status HailoRtRpcService::InputVStream_get_info(grpc::ServerContext*, const VStream_get_info_Request *request, + VStream_get_info_Reply *reply) +{ + auto lambda = [](std::shared_ptr input_vstream) { + return input_vstream->get_info(); + }; + auto &manager = ServiceResourceManager::get_instance(); + auto info = manager.execute(request->handle(), lambda); + auto info_proto = reply->mutable_vstream_info(); + serialize_vstream_info(info, info_proto); + reply->set_status(static_cast(HAILO_SUCCESS)); return grpc::Status::OK; } -grpc::Status HailoRtRpcService::OutputVStream_resume(grpc::ServerContext*, const VStream_resume_Request *, - VStream_resume_Reply *) +grpc::Status HailoRtRpcService::OutputVStream_get_info(grpc::ServerContext*, const VStream_get_info_Request *request, + VStream_get_info_Reply *reply) { - // TODO - HRT-7892 - // auto lambda = [](std::shared_ptr output_vstream) { - // return output_vstream->resume(); - // }; - // auto &manager = ServiceResourceManager::get_instance(); - // auto status = manager.execute(request->handle(), lambda); - // reply->set_status(status); + auto lambda = [](std::shared_ptr output_vstream) { + return output_vstream->get_info(); + }; + auto &manager = ServiceResourceManager::get_instance(); + auto info = manager.execute(request->handle(), lambda); + auto info_proto = reply->mutable_vstream_info(); + serialize_vstream_info(info, info_proto); + reply->set_status(static_cast(HAILO_SUCCESS)); return grpc::Status::OK; } diff --git a/hailort/hailort_service/hailort_rpc_service.hpp b/hailort/hailort_service/hailort_rpc_service.hpp index ed52176..3540b9f 100644 --- a/hailort/hailort_service/hailort_rpc_service.hpp +++ b/hailort/hailort_service/hailort_rpc_service.hpp @@ -28,7 +28,7 @@ namespace hailort { -class HailoRtRpcService final : public HailoRtRpc::Service { +class HailoRtRpcService final : public ProtoHailoRtRpc::Service { public: virtual grpc::Status client_keep_alive(grpc::ServerContext *ctx, const keepalive_Request *request, @@ -45,6 +45,8 @@ public: VDevice_configure_Reply* reply) override; virtual grpc::Status VDevice_get_physical_devices_ids(grpc::ServerContext*, const VDevice_get_physical_devices_ids_Request* request, VDevice_get_physical_devices_ids_Reply* reply) override; + virtual grpc::Status VDevice_get_default_streams_interface(grpc::ServerContext*, const VDevice_get_default_streams_interface_Request* request, + VDevice_get_default_streams_interface_Reply* reply) override; virtual grpc::Status InputVStreams_create(grpc::ServerContext *, const VStream_create_Request *request, VStreams_create_Reply *reply) override; @@ -68,6 +70,10 @@ public: VStream_name_Reply *reply) override; virtual grpc::Status OutputVStream_name(grpc::ServerContext*, const VStream_name_Request *request, VStream_name_Reply *reply) override; + virtual grpc::Status InputVStream_network_name(grpc::ServerContext*, const VStream_network_name_Request *request, + VStream_network_name_Reply *reply) override; + virtual grpc::Status OutputVStream_network_name(grpc::ServerContext*, const VStream_network_name_Request *request, + VStream_network_name_Reply *reply) override; virtual grpc::Status InputVStream_abort(grpc::ServerContext*, const VStream_abort_Request *request, VStream_abort_Reply *reply) override; virtual grpc::Status OutputVStream_abort(grpc::ServerContext*, const VStream_abort_Request *request, @@ -76,7 +82,14 @@ public: VStream_resume_Reply *reply) override; virtual grpc::Status OutputVStream_resume(grpc::ServerContext*, const VStream_resume_Request *request, VStream_resume_Reply *reply) override; - + virtual grpc::Status InputVStream_get_user_buffer_format(grpc::ServerContext*, const VStream_get_user_buffer_format_Request *request, + VStream_get_user_buffer_format_Reply *reply) override; + virtual grpc::Status OutputVStream_get_user_buffer_format(grpc::ServerContext*, const VStream_get_user_buffer_format_Request *request, + VStream_get_user_buffer_format_Reply *reply) override; + virtual grpc::Status InputVStream_get_info(grpc::ServerContext*, const VStream_get_info_Request *request, + VStream_get_info_Reply *reply) override; + virtual grpc::Status OutputVStream_get_info(grpc::ServerContext*, const VStream_get_info_Request *request, + VStream_get_info_Reply *reply) override; virtual grpc::Status ConfiguredNetworkGroup_release(grpc::ServerContext*, const Release_Request* request, Release_Reply* reply) override; virtual grpc::Status ConfiguredNetworkGroup_make_input_vstream_params(grpc::ServerContext*, @@ -85,9 +98,12 @@ public: virtual grpc::Status ConfiguredNetworkGroup_make_output_vstream_params(grpc::ServerContext*, const ConfiguredNetworkGroup_make_output_vstream_params_Request *request, ConfiguredNetworkGroup_make_output_vstream_params_Reply *reply) override; - virtual grpc::Status ConfiguredNetworkGroup_get_name(grpc::ServerContext*, - const ConfiguredNetworkGroup_get_name_Request *request, - ConfiguredNetworkGroup_get_name_Reply *reply) override; + virtual grpc::Status ConfiguredNetworkGroup_make_output_vstream_params_groups(grpc::ServerContext*, + const ConfiguredNetworkGroup_make_output_vstream_params_groups_Request *request, + ConfiguredNetworkGroup_make_output_vstream_params_groups_Reply *reply) override; + virtual grpc::Status ConfiguredNetworkGroup_name(grpc::ServerContext*, + const ConfiguredNetworkGroup_name_Request *request, + ConfiguredNetworkGroup_name_Reply *reply) override; virtual grpc::Status ConfiguredNetworkGroup_get_network_infos(grpc::ServerContext*, const ConfiguredNetworkGroup_get_network_infos_Request *request, ConfiguredNetworkGroup_get_network_infos_Reply *reply) override; @@ -118,6 +134,12 @@ public: virtual grpc::Status ConfiguredNetworkGroup_get_latency_measurement(grpc::ServerContext*, const ConfiguredNetworkGroup_get_latency_measurement_Request *request, ConfiguredNetworkGroup_get_latency_measurement_Reply *reply) override; + virtual grpc::Status ConfiguredNetworkGroup_is_multi_context(grpc::ServerContext*, + const ConfiguredNetworkGroup_is_multi_context_Request *request, + ConfiguredNetworkGroup_is_multi_context_Reply *reply) override; + virtual grpc::Status ConfiguredNetworkGroup_get_config_params(grpc::ServerContext*, + const ConfiguredNetworkGroup_get_config_params_Request *request, + ConfiguredNetworkGroup_get_config_params_Reply *reply) override; }; } diff --git a/hailort/hailort_service/hailort_service b/hailort/hailort_service/hailort_service new file mode 100644 index 0000000..8fd5b2b --- /dev/null +++ b/hailort/hailort_service/hailort_service @@ -0,0 +1,12 @@ +# This file contains HailoRT's configurable environment variables for HailoRT Service. +# The environment variables are set to their default values. +# To change an environment variable's value, follow the steps: +# 1. Change the value of the selected environemt variable in this file +# 2. Reload systemd unit files by running: `sudo systemctl daemon-reload` +# 3. Enable and start service by running: `sudo systemctl enable --now hailort.service` + +[Service] +HAILORT_LOGGER_PATH="/var/log/hailo" +HAILO_DISABLE_MULTIPLEXER=0 +HAILO_ENABLE_MULTI_DEVICE_SCHEDULER=0 +SCHEDULER_MONITOR=0 diff --git a/hailort/hailort_service/hailort_service.cpp b/hailort/hailort_service/hailort_service.cpp index 3f2071d..890e8bd 100644 --- a/hailort/hailort_service/hailort_service.cpp +++ b/hailort/hailort_service/hailort_service.cpp @@ -4,12 +4,11 @@ * * @file hailort_service.cpp * @brief main for hailort service - * TODO: move to user guide (HRT-7559) - * * To run as without daemonize the executable: + * To run as without daemonize the executable: * 1) Compile with `./build.sh` * 2) Run `./bin/linux.x86_64.debug/hailort_service standalone` * - * * To run as daemon service please follow the steps: + * To run as daemon service please follow the steps: * 1) Install the HailoRT: * cmake -H. -Bbuild -DCMAKE_BUILD_TYPE=Release -DHAILO_BUILD_SERVICE=1 && sudo cmake --build build --target install * @@ -26,6 +25,7 @@ #include "hailort_rpc_service.hpp" #include "rpc/rpc_definitions.hpp" #include "common/utils.hpp" +#include "common/filesystem.hpp" #include "hailo/hailort_common.hpp" #include @@ -44,17 +44,40 @@ void RunService() { server->Wait(); } +void write_pid_to_lock_file() +{ + auto status = hailort::Filesystem::create_directory(HAILO_DAEMON_PID_DIR); + if (status != HAILO_SUCCESS) { + syslog(LOG_ERR, "Cannot create directory at path, status=%i", status); + return; + } + + auto locked_file = hailort::LockedFile::create(HAILO_DAEMON_PID_FILE, "wx"); + if (HAILO_SUCCESS != locked_file.status()) { + syslog(LOG_ERR, "Failed to lock pid file for hailort service, status=%i", locked_file.status()); + return; + } + + std::string pid = std::to_string(getpid()); + auto ret = write(locked_file->get_fd(), pid.c_str(), pid.size()); + if (-1 == ret) { + syslog(LOG_ERR, "Failed to write pid to lock file for hailort service, errno=%i", errno); + return; + } +} + int main(int argc, char *argv[]) { bool is_standalone = ((1 < argc) && (strcmp("standalone", argv[1]) == 0)); if (!is_standalone) { - int ret = daemon(0,0); + int ret = daemon(0, 0); if (ret < 0) { syslog(LOG_ERR, "Failed to create daemon with errno %i", errno); exit(EXIT_FAILURE); } - } + write_pid_to_lock_file(); + } RunService(); return 0; } \ No newline at end of file diff --git a/hailort/hailortcli/CMakeLists.txt b/hailort/hailortcli/CMakeLists.txt index 1cb4956..45993e0 100644 --- a/hailort/hailortcli/CMakeLists.txt +++ b/hailort/hailortcli/CMakeLists.txt @@ -24,6 +24,12 @@ set(HAILORTCLI_CPP_FILES parse_hef_command.cpp graph_printer.cpp mon_command.cpp + + run2/run2_command.cpp + run2/network_runner.cpp + run2/live_printer.cpp + run2/timer_live_track.cpp + run2/network_live_track.cpp ) if(UNIX) @@ -61,8 +67,6 @@ target_link_libraries(hailortcli readerwriterqueue DotWriter scheduler_mon_proto) -# TODO: Remove microprofile after removing pipeline.cpp from hailortcli sources -target_link_libraries(hailortcli microprofile) if(WIN32) target_link_libraries(hailortcli Ws2_32 Iphlpapi Shlwapi) diff --git a/hailort/hailortcli/board_config_command.cpp b/hailort/hailortcli/board_config_command.cpp index d9a0012..8619880 100644 --- a/hailort/hailortcli/board_config_command.cpp +++ b/hailort/hailortcli/board_config_command.cpp @@ -31,6 +31,10 @@ BoardConfigReadSubcommand::BoardConfigReadSubcommand(CLI::App &parent_app) : hailo_status BoardConfigReadSubcommand::execute_on_device(Device &device) { + auto status = validate_specific_device_is_given(); + CHECK_SUCCESS(status, + "'board-config read' command should get a specific device-id."); + auto buffer = device.read_board_config(); CHECK_EXPECTED_AS_STATUS(buffer, "Failed reading board config from device"); diff --git a/hailort/hailortcli/command.cpp b/hailort/hailortcli/command.cpp index f0f7754..dae8600 100644 --- a/hailort/hailortcli/command.cpp +++ b/hailort/hailortcli/command.cpp @@ -61,3 +61,16 @@ hailo_status DeviceCommand::execute_on_devices(std::vectorsize()) { + return HAILO_INVALID_OPERATION; + } + } + return HAILO_SUCCESS; +} diff --git a/hailort/hailortcli/command.hpp b/hailort/hailortcli/command.hpp index 729b5dc..2002a8d 100644 --- a/hailort/hailortcli/command.hpp +++ b/hailort/hailortcli/command.hpp @@ -64,11 +64,12 @@ public: virtual hailo_status execute() override final; protected: + hailo_device_params m_device_params; + virtual hailo_status execute_on_device(Device &device) = 0; hailo_status execute_on_devices(std::vector> &devices); + hailo_status validate_specific_device_is_given(); -private: - hailo_device_params m_device_params; }; #endif /* _HAILO_COMMAND_HPP_ */ \ No newline at end of file diff --git a/hailort/hailortcli/common.cpp b/hailort/hailortcli/common.cpp index 27b45ec..16fb5ac 100644 --- a/hailort/hailortcli/common.cpp +++ b/hailort/hailortcli/common.cpp @@ -71,4 +71,23 @@ void CliCommon::reset_cursor(size_t lines_count) for (size_t i = 0; i < lines_count; i++) { std::cout << FORMAT_CURSOR_UP_LINE; } -} \ No newline at end of file +} + +void CliCommon::clear_lines_down(size_t lines_count) +{ + for (size_t i = 0; i < lines_count; i++) { + std::cout << FORMAT_CURSOR_DOWN_CLEAR_LINE; + } +} + +bool CliCommon::is_positive_number(const std::string &s) +{ + bool is_number = (!s.empty()) && (std::all_of(s.begin(), s.end(), ::isdigit)); + return is_number && (0 < std::stoi(s)); +} + +bool CliCommon::is_non_negative_number(const std::string &s) +{ + bool is_number = (!s.empty()) && (std::all_of(s.begin(), s.end(), ::isdigit)); + return is_number && (0 <= std::stoi(s)); +} diff --git a/hailort/hailortcli/common.hpp b/hailort/hailortcli/common.hpp index 8c8ce43..4a3c6bd 100644 --- a/hailort/hailortcli/common.hpp +++ b/hailort/hailortcli/common.hpp @@ -22,6 +22,7 @@ using namespace hailort; // http://www.climagic.org/mirrors/VT100_Escape_Codes.html #define FORMAT_CLEAR_LINE "\033[2K\r" #define FORMAT_CURSOR_UP_LINE "\033[F" +#define FORMAT_CURSOR_DOWN_CLEAR_LINE "\033[B\33[2K\r" class CliCommon final { @@ -31,6 +32,9 @@ public: static std::string duration_to_string(std::chrono::seconds secs); static Expected current_time_to_string(); static void reset_cursor(size_t number_of_lines); + static void clear_lines_down(size_t number_of_lines); + static bool is_positive_number(const std::string &s); + static bool is_non_negative_number(const std::string &s); }; // Validators diff --git a/hailort/hailortcli/download_action_list_command.cpp b/hailort/hailortcli/download_action_list_command.cpp index 0eb16c4..a51c853 100644 --- a/hailort/hailortcli/download_action_list_command.cpp +++ b/hailort/hailortcli/download_action_list_command.cpp @@ -20,6 +20,7 @@ // TODO - HRT-7364 - add CPU subsystem frequency into the device extended info control // and use it for get the timer's frequency #define NN_CORE_TO_TIMER_FREQ_FACTOR (2) +#define MERCURY_VPU_CORE_CPU_DEFAULT_FREQ_MHZ (200) constexpr int DownloadActionListCommand::INVALID_NUMERIC_VALUE; @@ -40,9 +41,17 @@ hailo_status DownloadActionListCommand::execute(Device &device, const std::strin auto curr_time = CliCommon::current_time_to_string(); CHECK_EXPECTED_AS_STATUS(curr_time); - auto extended_info = device.get_extended_device_information(); - CHECK_EXPECTED_AS_STATUS(extended_info); - const auto clock_cycle = (extended_info->neural_network_core_clock_rate / NN_CORE_TO_TIMER_FREQ_FACTOR) / MHz; + auto chip_arch = device.get_architecture(); + CHECK_EXPECTED_AS_STATUS(chip_arch); + unsigned int clock_cycle = 0; + // TODO - HRT-8046 Implement extended device info for mercury + if (HAILO_ARCH_MERCURY_VPU == chip_arch.value()) { + clock_cycle = MERCURY_VPU_CORE_CPU_DEFAULT_FREQ_MHZ; + } else { + auto extended_info = device.get_extended_device_information(); + CHECK_EXPECTED_AS_STATUS(extended_info); + clock_cycle = (extended_info->neural_network_core_clock_rate / NN_CORE_TO_TIMER_FREQ_FACTOR) / MHz; + } ordered_json action_list_json = { {"version", ACTION_LIST_FORMAT_VERSION()}, @@ -75,6 +84,10 @@ hailo_status DownloadActionListCommand::set_batch_to_measure(Device &device, uin hailo_status DownloadActionListCommand::execute_on_device(Device &device) { + auto status = validate_specific_device_is_given(); + CHECK_SUCCESS(status, + "'fw-control action-list' command should get a specific device-id."); + return execute(device, m_output_file_path); } @@ -179,9 +192,9 @@ Expected DownloadActionListCommand::parse_action_data(uint32_t bas data_json = *reinterpret_cast(action); action_length_local = sizeof(CONTEXT_SWITCH_DEFS__wait_dma_idle_data_t); break; - case CONTEXT_SWITCH_DEFS__ACTION_TYPE_WAIT_FOR_NMS_IDLE: - data_json = *reinterpret_cast(action); - action_length_local = sizeof(CONTEXT_SWITCH_DEFS__wait_nms_idle_data_t); + case CONTEXT_SWITCH_DEFS__ACTION_TYPE_WAIT_FOR_NMS: + data_json = *reinterpret_cast(action); + action_length_local = sizeof(CONTEXT_SWITCH_DEFS__wait_nms_data_t); break; case CONTEXT_SWITCH_DEFS__ACTION_TYPE_OUTPUT_CHANNEL_TRANSFER_DONE_INTERRUPT: data_json = *reinterpret_cast(action); @@ -192,8 +205,8 @@ Expected DownloadActionListCommand::parse_action_data(uint32_t bas action_length_local = sizeof(CONTEXT_SWITCH_DEFS__module_config_done_interrupt_data_t); break; case CONTEXT_SWITCH_DEFS__ACTION_TYPE_APPLICATION_CHANGE_INTERRUPT: - data_json = *reinterpret_cast(action); - action_length_local = sizeof(CONTEXT_SWITCH_DEFS__application_change_interrupt_data_t); + data_json = json({}); + action_length_local = 0; break; case CONTEXT_SWITCH_DEFS__ACTION_TYPE_FETCH_CFG_CHANNEL_DESCRIPTORS: data_json = *reinterpret_cast(action); @@ -283,6 +296,18 @@ Expected DownloadActionListCommand::parse_action_data(uint32_t bas data_json = json({}); action_length_local = 0; break; + case CONTEXT_SWITCH_DEFS__ACTION_TYPE_OPEN_BOUNDARY_INPUT_CHANNEL: + data_json = *reinterpret_cast(action); + action_length_local = sizeof(CONTEXT_SWITCH_DEFS__open_boundary_input_channel_data_t); + break; + case CONTEXT_SWITCH_DEFS__ACTION_TYPE_OPEN_BOUNDARY_OUTPUT_CHANNEL: + data_json = *reinterpret_cast(action); + action_length_local = sizeof(CONTEXT_SWITCH_DEFS__open_boundary_output_channel_data_t); + break; + case CONTEXT_SWITCH_DEFS__ACTION_TYPE_ENABLE_NMS: + data_json = *reinterpret_cast(action); + action_length_local = sizeof(CONTEXT_SWITCH_DEFS__enable_nms_action_t); + break; case CONTEXT_SWITCH_DEFS__ACTION_TYPE_COUNT: // Fallthrough // Handling CONTEXT_SWITCH_DEFS__ACTION_TYPE_COUNT is needed because we compile this file with -Wswitch-enum @@ -326,24 +351,35 @@ Expected DownloadActionListCommand::parse_single_action(uint32_t b return json.release(); } -Expected DownloadActionListCommand::parse_context(uint32_t action_list_base_address, - uint8_t *context_action_list, uint16_t action_list_size, uint32_t batch_counter) +Expected DownloadActionListCommand::parse_context(Device &device, uint32_t network_group_id, + CONTROL_PROTOCOL__context_switch_context_type_t context_type, uint8_t context_index, const std::string &context_name) { + uint32_t action_list_base_address = 0; + uint32_t batch_counter = 0; + + auto action_list = device.download_context_action_list(network_group_id, context_type, context_index, + &action_list_base_address, &batch_counter); + CHECK_EXPECTED(action_list); + // Needs to fit in 2 bytes due to firmware limitation of action list size + CHECK_AS_EXPECTED(IS_FIT_IN_UINT16(action_list->size()), HAILO_INTERNAL_FAILURE, + "Action list size is expected to fit in 2B. actual size is {}", action_list->size()); + ordered_json context_json { {"action_list_base_address", action_list_base_address}, - {"action_list_size", action_list_size }, - {"batch_counter", batch_counter} + {"action_list_size", action_list->size() }, + {"batch_counter", batch_counter}, + {"context_name", context_name}, }; ordered_json action_list_json; uint16_t current_buffer_offset = 0; - while (current_buffer_offset < action_list_size) { + while (current_buffer_offset < action_list->size()) { bool is_repeated = false; uint8_t num_repeated = 0; CONTEXT_SWITCH_DEFS__ACTION_TYPE_t sub_action_type = CONTEXT_SWITCH_DEFS__ACTION_TYPE_COUNT; uint32_t single_action_length = 0; uint32_t timestamp = 0; - auto action_json = parse_single_action(action_list_base_address, context_action_list, + auto action_json = parse_single_action(action_list_base_address, action_list->data(), current_buffer_offset, &single_action_length, &is_repeated, &num_repeated, &sub_action_type, ×tamp); CHECK_EXPECTED(action_json); current_buffer_offset = (uint16_t)(current_buffer_offset + single_action_length); @@ -353,7 +389,7 @@ Expected DownloadActionListCommand::parse_context(uint32_t action_ for (uint8_t index_in_repeated_block = 0; index_in_repeated_block < num_repeated; index_in_repeated_block++) { uint32_t sub_action_length = 0; auto repeated_action_json = parse_single_repeated_action(action_list_base_address, - context_action_list + current_buffer_offset, current_buffer_offset, &sub_action_length, + action_list->data() + current_buffer_offset, current_buffer_offset, &sub_action_length, sub_action_type, timestamp, index_in_repeated_block); CHECK_EXPECTED(repeated_action_json); current_buffer_offset = (uint16_t)(current_buffer_offset + sub_action_length); @@ -361,7 +397,7 @@ Expected DownloadActionListCommand::parse_context(uint32_t action_ } } } - CHECK_AS_EXPECTED(current_buffer_offset == action_list_size, HAILO_INTERNAL_FAILURE, + CHECK_AS_EXPECTED(current_buffer_offset == action_list->size(), HAILO_INTERNAL_FAILURE, "PARSING ERROR ! Reached forbidden memory space"); context_json["actions"] = action_list_json; @@ -377,16 +413,19 @@ double DownloadActionListCommand::get_accumulator_mean_value(const AccumulatorPt Expected DownloadActionListCommand::parse_network_groups(Device &device, const ConfiguredNetworkGroupVector &network_groups) { - const auto number_of_contexts_per_network_group = device.get_number_of_contexts_per_network_group(); - CHECK_EXPECTED(number_of_contexts_per_network_group); + const auto number_of_dynamic_contexts_per_network_group = device.get_number_of_dynamic_contexts_per_network_group(); + CHECK_EXPECTED(number_of_dynamic_contexts_per_network_group); ordered_json network_group_list_json; - uint8_t global_context_index = 0; - for (uint32_t network_group_index = 0; network_group_index < number_of_contexts_per_network_group->size(); network_group_index++) { + for (uint32_t network_group_index = 0; network_group_index < number_of_dynamic_contexts_per_network_group->size(); network_group_index++) { + // TODO: HRT-8147 use the real network_group_id instead of network_group_index + const uint32_t network_group_id = network_group_index; + // TODO: network_group_name via Hef::get_network_groups_names (HRT-5997) ordered_json network_group_json = { {"mean_activation_time_ms", INVALID_NUMERIC_VALUE}, {"mean_deactivation_time_ms", INVALID_NUMERIC_VALUE}, + {"network_group_id", network_group_id}, {"contexts", json::array()} }; // We assume the the order of the network_groups in the ConfiguredNetworkGroupVector and in the action_list @@ -399,25 +438,31 @@ Expected DownloadActionListCommand::parse_network_groups(Device &d network_groups[network_group_index]->get_deactivation_time_accumulator()); } - const auto num_contexts_in_network_group = number_of_contexts_per_network_group.value()[network_group_index]; - for (uint8_t i = 0; i < num_contexts_in_network_group; i++) { - uint32_t batch_counter = 0; - uint32_t base_address = 0; - auto action_list = device.download_context_action_list(global_context_index, &base_address, &batch_counter); - CHECK_EXPECTED(action_list); - // Needs to fit in 2 bytes due to firmware limitation of action list size - CHECK_AS_EXPECTED(IS_FIT_IN_UINT16(action_list->size()), HAILO_INTERNAL_FAILURE, - "Action list size is expected to fit in 2B. actual size is {}", action_list->size()); - - auto context_json = parse_context(base_address, action_list->data(), - static_cast(action_list->size()), batch_counter); + auto activation_context_json = parse_context(device, network_group_id, + CONTROL_PROTOCOL__CONTEXT_SWITCH_CONTEXT_TYPE_ACTIVATION, 0, "activation"); + CHECK_EXPECTED(activation_context_json); + network_group_json["contexts"].emplace_back(activation_context_json.release()); + + auto preliminary_context_json = parse_context(device, network_group_id, + CONTROL_PROTOCOL__CONTEXT_SWITCH_CONTEXT_TYPE_PRELIMINARY, 0, "preliminary"); + CHECK_EXPECTED(preliminary_context_json); + network_group_json["contexts"].emplace_back(preliminary_context_json.release()); + + const auto dynamic_contexts_count = number_of_dynamic_contexts_per_network_group.value()[network_group_index]; + for (uint8_t context_index = 0; context_index < dynamic_contexts_count; context_index++) { + auto context_json = parse_context(device, network_group_id, + CONTROL_PROTOCOL__CONTEXT_SWITCH_CONTEXT_TYPE_DYNAMIC, context_index, + fmt::format("dynamic_{}", context_index)); CHECK_EXPECTED(context_json); network_group_json["contexts"].emplace_back(context_json.release()); - - // Device::get_number_of_contexts_per_network_group guarantees no overflow - global_context_index++; } + + auto batch_switching_context_json = parse_context(device, network_group_id, + CONTROL_PROTOCOL__CONTEXT_SWITCH_CONTEXT_TYPE_BATCH_SWITCHING, 0, "batch_switching"); + CHECK_EXPECTED(batch_switching_context_json); + network_group_json["contexts"].emplace_back(batch_switching_context_json.release()); + network_group_list_json.emplace_back(network_group_json); } @@ -567,3 +612,13 @@ void to_json(json &j, const CONTEXT_SWITCH_DEFS__add_ddr_pair_info_action_data_t j = json{{"h2d_engine_index", h2d_engine_index}, {"h2d_vdma_channel_index", h2d_vdma_channel_index}, {"d2h_engine_index", d2h_engine_index}, {"d2h_vdma_channel_index", d2h_vdma_channel_index}}; } + +void to_json(json &j, const CONTEXT_SWITCH_DEFS__open_boundary_input_channel_data_t &data) +{ + j = unpack_vdma_channel_id(data); +} + +void to_json(json &j, const CONTEXT_SWITCH_DEFS__open_boundary_output_channel_data_t &data) +{ + j = unpack_vdma_channel_id(data); +} diff --git a/hailort/hailortcli/download_action_list_command.hpp b/hailort/hailortcli/download_action_list_command.hpp index 65638a1..1aa271e 100644 --- a/hailort/hailortcli/download_action_list_command.hpp +++ b/hailort/hailortcli/download_action_list_command.hpp @@ -56,8 +56,9 @@ private: static Expected parse_single_action(uint32_t base_address, uint8_t *context_action_list, uint32_t current_buffer_offset, uint32_t *action_length, bool *is_repeated, uint8_t *num_repeated, CONTEXT_SWITCH_DEFS__ACTION_TYPE_t *sub_action_type, uint32_t *time_stamp); - static Expected parse_context(uint32_t action_list_base_address, uint8_t *context_action_list, - uint16_t action_list_size, uint32_t batch_counter); + static Expected parse_context(Device &device, uint32_t network_group_id, + CONTROL_PROTOCOL__context_switch_context_type_t context_type, uint8_t context_index, + const std::string &context_name); static double get_accumulator_mean_value(const AccumulatorPtr &accumulator, double default_value = INVALID_NUMERIC_VALUE); static Expected parse_network_groups(Device &device, const ConfiguredNetworkGroupVector &network_groups); }; @@ -93,9 +94,12 @@ static std::pair mapping[] = { {CONTEXT_SWITCH_DEFS__ACTION_TYPE_DEACTIVATE_CFG_CHANNEL, "deactivate_cfg_channel"}, {CONTEXT_SWITCH_DEFS__ACTION_TYPE_REPEATED_ACTION, "repeated_action"}, {CONTEXT_SWITCH_DEFS__ACTION_TYPE_WAIT_FOR_DMA_IDLE_ACTION, "wait_for_dma_idle_action"}, - {CONTEXT_SWITCH_DEFS__ACTION_TYPE_WAIT_FOR_NMS_IDLE, "wait_for_nms_idle"}, + {CONTEXT_SWITCH_DEFS__ACTION_TYPE_WAIT_FOR_NMS, "wait_for_nms_idle"}, {CONTEXT_SWITCH_DEFS__ACTION_TYPE_FETCH_CCW_BURSTS, "fetch_ccw_bursts"}, - {CONTEXT_SWITCH_DEFS__ACTION_TYPE_DDR_BUFFERING_RESET, "ddr_buffering_reset"} + {CONTEXT_SWITCH_DEFS__ACTION_TYPE_DDR_BUFFERING_RESET, "ddr_buffering_reset"}, + {CONTEXT_SWITCH_DEFS__ACTION_TYPE_OPEN_BOUNDARY_INPUT_CHANNEL, "open_boundary_input_channel"}, + {CONTEXT_SWITCH_DEFS__ACTION_TYPE_OPEN_BOUNDARY_OUTPUT_CHANNEL, "open_boundary_output_channel"}, + {CONTEXT_SWITCH_DEFS__ACTION_TYPE_ENABLE_NMS, "enable_nms"}, }; static_assert(ARRAY_ENTRIES(mapping) == CONTEXT_SWITCH_DEFS__ACTION_TYPE_COUNT, "Missing a mapping from a CONTEXT_SWITCH_DEFS__ACTION_TYPE_t to it's string value"); @@ -106,10 +110,10 @@ NLOHMANN_JSON_SERIALIZE_ENUM2(CONTEXT_SWITCH_DEFS__ACTION_TYPE_t, mapping); NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(CONTEXT_SWITCH_DEFS__repeated_action_header_t, count, last_executed, sub_action_type); NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(CONTEXT_SWITCH_DEFS__trigger_sequencer_action_data_t, cluster_index); NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(CONTEXT_SWITCH_DEFS__sequencer_interrupt_data_t, sequencer_index); -NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(CONTEXT_SWITCH_DEFS__wait_nms_idle_data_t, aggregator_index); +NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(CONTEXT_SWITCH_DEFS__wait_nms_data_t, aggregator_index); NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(CONTEXT_SWITCH_DEFS__module_config_done_interrupt_data_t, module_index); -NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(CONTEXT_SWITCH_DEFS__application_change_interrupt_data_t, application_index); NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(CONTEXT_SWITCH_DEFS__fetch_ccw_bursts_action_data_t, config_stream_index); +NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(CONTEXT_SWITCH_DEFS__enable_nms_action_t, nms_unit_index, network_index); // Non-default implementations void to_json(json &j, const CONTEXT_SWITCH_DEFS__deactivate_vdma_channel_action_data_t &data); @@ -120,17 +124,19 @@ void to_json(json &j, const CONTEXT_SWITCH_DEFS__activate_ddr_buffer_input_data_ void to_json(json &j, const CONTEXT_SWITCH_DEFS__activate_boundary_output_data_t &data); void to_json(json &j, const CONTEXT_SWITCH_DEFS__activate_inter_context_output_data_t &data); void to_json(json &j, const CONTEXT_SWITCH_DEFS__activate_ddr_buffer_output_data_t &data); -void to_json(json &j, const CONTEXT_SWITCH_DEFS__enable_lcu_action_default_data_t& data); -void to_json(json &j, const CONTEXT_SWITCH_DEFS__enable_lcu_action_non_default_data_t& data); -void to_json(json &j, const CONTEXT_SWITCH_DEFS__disable_lcu_action_data_t& data); -void to_json(json &j, const CONTEXT_SWITCH_DEFS__fetch_cfg_channel_descriptors_action_data_t& data); -void to_json(json &j, const CONTEXT_SWITCH_DEFS__change_vdma_to_stream_mapping_data_t& data); +void to_json(json &j, const CONTEXT_SWITCH_DEFS__enable_lcu_action_default_data_t &data); +void to_json(json &j, const CONTEXT_SWITCH_DEFS__enable_lcu_action_non_default_data_t &data); +void to_json(json &j, const CONTEXT_SWITCH_DEFS__disable_lcu_action_data_t &data); +void to_json(json &j, const CONTEXT_SWITCH_DEFS__fetch_cfg_channel_descriptors_action_data_t &data); +void to_json(json &j, const CONTEXT_SWITCH_DEFS__change_vdma_to_stream_mapping_data_t &data); void to_json(json &j, const CONTEXT_SWITCH_DEFS__fetch_data_action_data_t &data); void to_json(json &j, const CONTEXT_SWITCH_DEFS__wait_dma_idle_data_t &data); void to_json(json &j, const CONTEXT_SWITCH_DEFS__vdma_dataflow_interrupt_data_t &data); -void to_json(json &j, const CONTEXT_SWITCH_DEFS__lcu_interrupt_data_t& data); +void to_json(json &j, const CONTEXT_SWITCH_DEFS__lcu_interrupt_data_t &data); void to_json(json &j, const CONTEXT_SWITCH_DEFS__activate_cfg_channel_t &data); void to_json(json &j, const CONTEXT_SWITCH_DEFS__deactivate_cfg_channel_t &data); void to_json(json &j, const CONTEXT_SWITCH_DEFS__add_ddr_pair_info_action_data_t &data); +void to_json(json &j, const CONTEXT_SWITCH_DEFS__open_boundary_input_channel_data_t &data); +void to_json(json &j, const CONTEXT_SWITCH_DEFS__open_boundary_output_channel_data_t &data); #endif /* _HAILO_DOWNLOAD_ACTION_LIST_COMMAND_HPP_ */ diff --git a/hailort/hailortcli/fw_config_command.cpp b/hailort/hailortcli/fw_config_command.cpp index f30f111..6c5ef40 100644 --- a/hailort/hailortcli/fw_config_command.cpp +++ b/hailort/hailortcli/fw_config_command.cpp @@ -18,10 +18,14 @@ FwConfigReadSubcommand::FwConfigReadSubcommand(CLI::App &parent_app) : hailo_status FwConfigReadSubcommand::execute_on_device(Device &device) { + auto status = validate_specific_device_is_given(); + CHECK_SUCCESS(status, + "'fw-config read' command should get a specific device-id."); + auto user_config_buffer = device.read_user_config(); CHECK_EXPECTED_AS_STATUS(user_config_buffer, "Failed reading user config from device"); - auto status = FwConfigJsonSerializer::deserialize_config( + status = FwConfigJsonSerializer::deserialize_config( *reinterpret_cast(user_config_buffer->data()), user_config_buffer->size(), m_output_file); CHECK_SUCCESS(status); diff --git a/hailort/hailortcli/fw_control_command.cpp b/hailort/hailortcli/fw_control_command.cpp index 757df33..23e3681 100644 --- a/hailort/hailortcli/fw_control_command.cpp +++ b/hailort/hailortcli/fw_control_command.cpp @@ -114,7 +114,7 @@ static std::string fw_version_string(const hailo_device_identity_t &identity) { std::stringstream os; const auto fw_mode = ((identity.is_release) ? "release" : "develop"); - // Currently will always return FW_BINARY_TYPE_APP_FIRMWARE as version bit is cleared in HailoRT + // TODO: Currently will always return FW_BINARY_TYPE_APP_FIRMWARE as version bit is cleared in HailoRT FW_BINARY_TYPE_t fw_binary_type = FIRMWARE_HEADER_UTILS__get_fw_binary_type(identity.fw_version.revision); auto fw_type = "invalid"; if (FW_BINARY_TYPE_CORE_FIRMWARE == fw_binary_type) { @@ -123,7 +123,11 @@ static std::string fw_version_string(const hailo_device_identity_t &identity) fw_type = "app"; } os << identity.fw_version.major << "." << identity.fw_version.minor << "." - << identity.fw_version.revision << " (" << fw_mode << "," << fw_type << ")"; + << identity.fw_version.revision << " (" << fw_mode << "," << fw_type; + if (identity.extended_context_switch_buffer) { + os << ",extended context switch buffer"; + } + os << ")"; return os.str(); } diff --git a/hailort/hailortcli/fw_logger_command.cpp b/hailort/hailortcli/fw_logger_command.cpp index c7fc5dc..efd59e9 100644 --- a/hailort/hailortcli/fw_logger_command.cpp +++ b/hailort/hailortcli/fw_logger_command.cpp @@ -49,8 +49,11 @@ hailo_status write_logs_to_file(Device &device, std::ofstream &ofs, hailo_cpu_id hailo_status FwLoggerCommand::execute_on_device(Device &device) { + auto status = validate_specific_device_is_given(); + CHECK_SUCCESS(status, + "'fw-logger' command should get a specific device-id"); + auto ofs_flags = std::ios::out | std::ios::binary; - hailo_status status = HAILO_UNINITIALIZED; if (!m_should_overwrite){ ofs_flags |= std::ios::app; diff --git a/hailort/hailortcli/hailortcli.cpp b/hailort/hailortcli/hailortcli.cpp index c3b589b..474a747 100644 --- a/hailort/hailortcli/hailortcli.cpp +++ b/hailort/hailortcli/hailortcli.cpp @@ -8,6 +8,7 @@ * * HailoRT command line interface. **/ +#include "run2/run2_command.hpp" #include "hailortcli.hpp" #include "scan_command.hpp" #include "power_measurement_command.hpp" @@ -96,9 +97,9 @@ void add_vdevice_options(CLI::App *app, hailo_vdevice_params &vdevice_params) auto group = app->add_option_group("VDevice Options"); auto device_count_option = group->add_option("--device-count", vdevice_params.device_count, "VDevice device count") ->check(CLI::PositiveNumber); - auto multi_process_option = group->add_flag("--multi-process-service", vdevice_params.multi_process_service, + group->add_flag("--multi-process-service", vdevice_params.multi_process_service, "VDevice multi process service"); - group->add_option("--group-id", vdevice_params.group_id, "VDevice group id")->needs(multi_process_option); + group->add_option("--group-id", vdevice_params.group_id, "VDevice group id"); group->parse_complete_callback([&vdevice_params, device_count_option](){ if (vdevice_params.device_params.device_ids.size() > 0) { // Check either device_count or device_id @@ -136,13 +137,6 @@ void add_device_options(CLI::App *app, hailo_device_params &device_params, bool auto *ip_option = group->add_option("--ip", device_params.device_ids, "IP address of the target") ->check(CLI::ValidIPV4); - auto *device_type_option = group->add_option("-d,--device-type,--target", "ignored."); - - std::vector actions{ - std::make_shared(device_type_option), - }; - hailo_deprecate_options(app, actions, false); - group->parse_complete_callback([&device_params, device_id_option, pcie_bdf_option, ip_option, support_asterisk]() { // Check that only one device id param is given @@ -190,18 +184,10 @@ class HailoRTCLI : public ContainerCommand { public: HailoRTCLI(CLI::App *app) : ContainerCommand(app) { - - m_app->add_flag_callback("-v,--version", - [] () { - std::cout << "HailoRT-CLI version " << - HAILORT_MAJOR_VERSION << "." << HAILORT_MINOR_VERSION << "." << HAILORT_REVISION_VERSION << std::endl; - // throw CLI::Success to stop parsing and not failing require_subcommand(1) we set earlier - throw (CLI::Success{}); - }, - "Print program version and exit" - ); + m_app->set_version_flag("-v,--version", fmt::format("HailoRT-CLI version {}.{}.{}", HAILORT_MAJOR_VERSION, HAILORT_MINOR_VERSION, HAILORT_REVISION_VERSION)); add_subcommand(); + add_subcommand(); add_subcommand(); add_subcommand(); add_subcommand(); diff --git a/hailort/hailortcli/mon_command.cpp b/hailort/hailortcli/mon_command.cpp index 38daf1d..a2f47a4 100644 --- a/hailort/hailortcli/mon_command.cpp +++ b/hailort/hailortcli/mon_command.cpp @@ -13,6 +13,9 @@ #include "common/filesystem.hpp" #include +#if defined(__GNUC__) +#include +#endif namespace hailort { @@ -20,8 +23,11 @@ namespace hailort // TODO: Deal with longer networks names - should use HAILO_MAX_NETWORK_NAME_SIZE but its too long for one line constexpr size_t NETWORK_NAME_WIDTH = 40; constexpr size_t STREAM_NAME_WIDTH = 60; +constexpr size_t ACTIVE_TIME_WIDTH = 25; constexpr size_t NUMBER_WIDTH = 15; +constexpr size_t TERMINAL_DEFAULT_WIDTH = 80; constexpr size_t LINE_LENGTH = 125; +constexpr std::chrono::milliseconds EPSILON_TIME(500); MonCommand::MonCommand(CLI::App &parent_app) : Command(parent_app.add_subcommand("monitor", "Monitor of networks - Presents information about the running networks. " \ @@ -43,7 +49,7 @@ size_t MonCommand::print_networks_info_header() std::cout << std::setw(NETWORK_NAME_WIDTH) << std::left << "Network" << std::setw(NUMBER_WIDTH) << std::left << "FPS" << - std::setw(NUMBER_WIDTH) << std::left << "Core%" << + std::setw(ACTIVE_TIME_WIDTH) << std::left << "Active Time (%) " << std::setw(NUMBER_WIDTH) << std::left << "PID" << "\n" << std::left << std::string(LINE_LENGTH, '-') << "\n"; static const uint32_t header_lines_count = 2; @@ -53,17 +59,21 @@ size_t MonCommand::print_networks_info_header() size_t MonCommand::print_networks_info_table(const ProtoMon &mon_message) { + const uint32_t NUMBER_OBJECTS_COUNT = 3; + auto data_line_len = (NUMBER_WIDTH * NUMBER_OBJECTS_COUNT) + NETWORK_NAME_WIDTH; + auto rest_line_len = LINE_LENGTH - data_line_len; + const std::string &pid = mon_message.pid(); for (auto net_info : mon_message.networks_infos()) { auto &net_name = net_info.network_name(); auto fps = net_info.fps(); - auto core = net_info.core_utilization(); + auto active_time = net_info.active_time(); std::cout << std::setprecision(1) << std::fixed << std::setw(NETWORK_NAME_WIDTH) << std::left << net_name << std::setw(NUMBER_WIDTH) << std::left << fps << - std::setw(NUMBER_WIDTH) << std::left << core << - std::setw(NUMBER_WIDTH) << std::left << pid << "\n"; + std::setw(ACTIVE_TIME_WIDTH) << std::left << active_time << + std::setw(NUMBER_WIDTH) << std::left << pid << std::string(rest_line_len, ' ') << "\n"; } return mon_message.networks_infos().size(); @@ -110,50 +120,93 @@ size_t MonCommand::print_frames_table(const ProtoMon &mon_message) } #if defined(__GNUC__) +Expected get_terminal_line_width() +{ + struct winsize w; + int ret = ioctl(0, TIOCGWINSZ, &w); + if (ret != 0) { + LOGGER__DEBUG("Failed to get_terminal_line_width, with errno: {}, using default value: {}", errno); + return TERMINAL_DEFAULT_WIDTH; + } + + uint16_t terminal_line_width = w.ws_col; + return terminal_line_width; +} + hailo_status MonCommand::print_table() { + std::chrono::milliseconds time_interval = DEFAULT_SCHEDULER_MON_INTERVAL + EPSILON_TIME; + auto terminal_line_width_expected = get_terminal_line_width(); + CHECK_EXPECTED_AS_STATUS(terminal_line_width_expected); + auto terminal_line_width = terminal_line_width_expected.release(); + + size_t last_run_total_lines_count = 0; + bool data_was_printed = false; while (true) { - auto epsilon = std::chrono::milliseconds(500); - std::chrono::milliseconds time_interval = DEFAULT_SCHEDULER_MON_INTERVAL + epsilon; - auto scheduler_mon_files = Filesystem::get_latest_files_in_dir_flat(SCHEDULER_MON_TMP_DIR, time_interval); - if (HAILO_SUCCESS != scheduler_mon_files.status() || scheduler_mon_files->empty()) { - LOGGER__WARNING("Getting scheduler monitor files failed. Please check the application is running and environment variable '{}' is set to 1.", - SCHEDULER_MON_ENV_VAR); - return HAILO_NOT_FOUND; - } + size_t total_lines_count = 0; + bool print_warning_msg = true; // Will change to false only if mon directory is valid and there are updated files in it. - std::vector mon_messages; - mon_messages.reserve(scheduler_mon_files->size()); - for (const auto &mon_file : scheduler_mon_files.value()) { - auto file = LockedFile::create(mon_file, "r"); - if (HAILO_SUCCESS != file.status()) { - LOGGER__ERROR("Failed to open and lock file {}, with status: {}", mon_file, file.status()); - continue; - } + auto mon_dir_valid = Filesystem::is_directory(SCHEDULER_MON_TMP_DIR); + CHECK_EXPECTED_AS_STATUS(mon_dir_valid); - ProtoMon mon_message; - if (!mon_message.ParseFromFileDescriptor(file->get_fd())) { - LOGGER__WARNING("Failed to ParseFromFileDescriptor monitor file {} with errno {}", mon_file, errno); - continue; + std::vector mon_messages; + if (mon_dir_valid.value()) { + auto scheduler_mon_files = Filesystem::get_latest_files_in_dir_flat(SCHEDULER_MON_TMP_DIR, time_interval); + CHECK_EXPECTED_AS_STATUS(scheduler_mon_files); + print_warning_msg = scheduler_mon_files->empty(); + + mon_messages.reserve(scheduler_mon_files->size()); + for (const auto &mon_file : scheduler_mon_files.value()) { + auto file = LockedFile::create(mon_file, "r"); + if (HAILO_SUCCESS != file.status()) { + LOGGER__ERROR("Failed to open and lock file {}, with status: {}", mon_file, file.status()); + total_lines_count++; + continue; + } + + ProtoMon mon_message; + if (!mon_message.ParseFromFileDescriptor(file->get_fd())) { + LOGGER__WARNING("Failed to ParseFromFileDescriptor monitor file {} with errno {}", mon_file, errno); + total_lines_count++; + continue; + } + + mon_messages.emplace_back(std::move(mon_message)); } - - mon_messages.emplace_back(std::move(mon_message)); } - size_t total_lines_count = print_networks_info_header(); + total_lines_count += print_networks_info_header(); for (auto &mon_message : mon_messages) { total_lines_count += print_networks_info_table(mon_message); } - std::cout << "\n\n"; + std::cout << std::string(terminal_line_width, ' ') << "\n"; + std::cout << std::string(terminal_line_width, ' ') << "\n"; total_lines_count += 2; total_lines_count += print_frames_header(); for (auto &mon_message : mon_messages) { total_lines_count += print_frames_table(mon_message); } - CliCommon::reset_cursor(total_lines_count); + if (print_warning_msg) { + std::cout << "Monitor did not retrieve any files. This occurs when there is no application currently running. If this is not the case, verify that environment variable '" << + SCHEDULER_MON_ENV_VAR << "' is set to 1.\n"; + total_lines_count++; + + if (data_was_printed) { + auto lines_to_clear = last_run_total_lines_count - total_lines_count; + CliCommon::clear_lines_down(lines_to_clear); + total_lines_count += lines_to_clear; + data_was_printed = false; + } + } + else { + data_was_printed = true; + last_run_total_lines_count = total_lines_count; + } + + CliCommon::reset_cursor(total_lines_count); std::this_thread::sleep_for(DEFAULT_SCHEDULER_MON_INTERVAL); } diff --git a/hailort/hailortcli/run2/live_printer.cpp b/hailort/hailortcli/run2/live_printer.cpp new file mode 100644 index 0000000..d0bacf3 --- /dev/null +++ b/hailort/hailortcli/run2/live_printer.cpp @@ -0,0 +1,69 @@ +/** + * Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved. + * Distributed under the MIT license (https://opensource.org/licenses/MIT) + **/ +/** + * @file live_printer.cpp + * @brief Live printer + **/ + +#include "live_printer.hpp" +#include "../common.hpp" +#include +#include +using namespace hailort; + +LivePrinter::LivePrinter(std::chrono::milliseconds interval) : + m_interval(interval), + m_stop_event(Event::create_shared(Event::State::not_signalled)), + m_tracks(), + m_mutex() +{ +} + +LivePrinter::~LivePrinter() +{ + (void)m_stop_event->signal(); + if (m_thread.joinable()) { + m_thread.join(); + } + print(false); +} + +void LivePrinter::add(std::shared_ptr track) +{ + std::unique_lock lock(m_mutex); + m_tracks.emplace_back(track); +} + +void LivePrinter::print(bool reset) +{ + std::stringstream ss; + uint32_t count = 0; + + { + std::unique_lock lock(m_mutex); + for (auto &track : m_tracks) { + count += track->get_text(ss); + } + } + + std::cout << ss.str() << std::flush; + if (reset) { + CliCommon::reset_cursor(count); + //TODO: what aout leftovers from prev line? + } +} + +void LivePrinter::start() +{ + m_thread = std::thread([this] () { + while (true) { + print(true); + auto status = m_stop_event->wait(m_interval); + if (HAILO_TIMEOUT != status) { + break; + } + } + }); +} \ No newline at end of file diff --git a/hailort/hailortcli/run2/live_printer.hpp b/hailort/hailortcli/run2/live_printer.hpp new file mode 100644 index 0000000..0d67364 --- /dev/null +++ b/hailort/hailortcli/run2/live_printer.hpp @@ -0,0 +1,43 @@ +/** + * Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved. + * Distributed under the MIT license (https://opensource.org/licenses/MIT) + **/ +/** + * @file live_printer.hpp + * @brief Live printer + **/ + +#ifndef _HAILO_HAILORTCLI_RUN2_LIVE_PRINTER_HPP_ +#define _HAILO_HAILORTCLI_RUN2_LIVE_PRINTER_HPP_ + +#include "hailo/event.hpp" +#include +#include +#include +#include +#include + +class LivePrinter final +{ +public: + class Track + { + public: + virtual uint32_t get_text(std::stringstream &ss) = 0; + }; + + LivePrinter(std::chrono::milliseconds interval); + ~LivePrinter(); + void add(std::shared_ptr track); + void print(bool reset); + void start(); + +private: + std::chrono::milliseconds m_interval; + hailort::EventPtr m_stop_event; + std::vector> m_tracks; + std::thread m_thread; + std::mutex m_mutex; +}; + +#endif /* _HAILO_HAILORTCLI_RUN2_LIVE_PRINTER_HPP_ */ \ No newline at end of file diff --git a/hailort/hailortcli/run2/network_live_track.cpp b/hailort/hailortcli/run2/network_live_track.cpp new file mode 100644 index 0000000..e3dc99c --- /dev/null +++ b/hailort/hailortcli/run2/network_live_track.cpp @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved. + * Distributed under the MIT license (https://opensource.org/licenses/MIT) + **/ +/** + * @file network_live_track.cpp + * @brief Network live track + **/ + +#include "network_live_track.hpp" +#include +#include + +NetworkLiveTrack::NetworkLiveTrack(const std::string &name) : + m_name(name), m_count(0), m_last_get_time(std::chrono::steady_clock::now()) +{ +} + +uint32_t NetworkLiveTrack::get_text(std::stringstream &ss) +{ + auto elapsed_time = std::chrono::steady_clock::now() - m_last_get_time; + auto count = m_count.load(); + + auto fps = count / std::chrono::duration(elapsed_time).count(); + ss << fmt::format("{} - fps: {:.2f}\n", m_name, fps); + + return 1; +} + +void NetworkLiveTrack::progress() +{ + m_count++; +} \ No newline at end of file diff --git a/hailort/hailortcli/run2/network_live_track.hpp b/hailort/hailortcli/run2/network_live_track.hpp new file mode 100644 index 0000000..1eacb52 --- /dev/null +++ b/hailort/hailortcli/run2/network_live_track.hpp @@ -0,0 +1,29 @@ +/** + * Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved. + * Distributed under the MIT license (https://opensource.org/licenses/MIT) + **/ +/** + * @file network_live_track.hpp + * @brief Network live track + **/ + +#include "live_printer.hpp" + +#ifndef _HAILO_HAILORTCLI_RUN2_NETWORK_LIVE_TRACK_HPP_ +#define _HAILO_HAILORTCLI_RUN2_NETWORK_LIVE_TRACK_HPP_ + +class NetworkLiveTrack : public LivePrinter::Track +{ +public: + NetworkLiveTrack(const std::string &name); + virtual ~NetworkLiveTrack() = default; + uint32_t get_text(std::stringstream &ss); + void progress(); + +private: + std::string m_name; + std::atomic m_count; + std::chrono::time_point m_last_get_time; +}; + +#endif /* _HAILO_HAILORTCLI_RUN2_NETWORK_LIVE_TRACK_HPP_ */ \ No newline at end of file diff --git a/hailort/hailortcli/run2/network_runner.cpp b/hailort/hailortcli/run2/network_runner.cpp new file mode 100644 index 0000000..130817c --- /dev/null +++ b/hailort/hailortcli/run2/network_runner.cpp @@ -0,0 +1,197 @@ +/** + * Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved. + * Distributed under the MIT license (https://opensource.org/licenses/MIT) + **/ +/** + * @file network_runner.cpp + * @brief Run network on hailo device + **/ + +#include "network_runner.hpp" +#include "common/async_thread.hpp" +#include "hailort_defaults.hpp" //TODO: not API + +using namespace hailort; + +//TODO: duplicated +static hailo_status wait_for_threads(std::vector> &threads) +{ + auto last_error_status = HAILO_SUCCESS; + for (auto &thread : threads) { + auto thread_status = thread->get(); + if ((HAILO_SUCCESS != thread_status) && (HAILO_STREAM_ABORTED_BY_USER != thread_status)) { + last_error_status = thread_status; + LOGGER__ERROR("Thread failed with with status {}", thread_status); + } + } + return last_error_status; +} + +VStreamParams::VStreamParams() : name(), params(HailoRTDefaults::get_vstreams_params()) +{ +} + +NetworkRunner::NetworkRunner(const NetworkParams ¶ms, const std::string &name, + std::vector &&input_vstreams, std::vector &&output_vstreams) + : m_params(params), m_name(name), m_input_vstreams(std::move(input_vstreams)), + m_output_vstreams(std::move(output_vstreams)) +{ +} + +Expected> NetworkRunner::create_shared(VDevice &vdevice, const NetworkParams ¶ms) +{ + auto hef = Hef::create(params.hef_path); + CHECK_EXPECTED(hef); + + // Get NG's name if single + auto net_group_name = params.net_group_name; + if (net_group_name.empty()) { + auto net_groups_names = hef->get_network_groups_names(); + CHECK_AS_EXPECTED(net_groups_names.size() == 1, HAILO_INVALID_ARGUMENT, "HEF {} doesn't contain a single NetworkGroup. Pass --name", params.hef_path); + net_group_name = net_groups_names[0]; + } + + auto interface = vdevice.get_default_streams_interface(); + CHECK_EXPECTED(interface, "Failed to get default streams interface"); + + auto cfg_params = hef->create_configure_params(*interface, net_group_name); + CHECK_EXPECTED(cfg_params); + cfg_params->batch_size = params.batch_size; + auto cfgr_net_groups = vdevice.configure(hef.value(), {{net_group_name, cfg_params.value()}}); + CHECK_EXPECTED(cfgr_net_groups); + assert(1 == cfgr_net_groups->size()); + auto cfgr_net_group = cfgr_net_groups.value()[0]; + + CHECK_SUCCESS_AS_EXPECTED(cfgr_net_group->set_scheduler_threshold(params.scheduler_threshold)); + CHECK_SUCCESS_AS_EXPECTED(cfgr_net_group->set_scheduler_timeout(std::chrono::milliseconds(params.scheduler_timeout_ms))); + + std::map vstreams_params; + for (auto &vstream_params : params.vstream_params) { + vstreams_params.emplace(vstream_params.name, vstream_params.params); + } + auto vstreams = create_vstreams(*cfgr_net_group, vstreams_params); + CHECK_EXPECTED(vstreams); + + auto net_runner = make_shared_nothrow(params, net_group_name, std::move(vstreams->first), std::move(vstreams->second)); + CHECK_NOT_NULL_AS_EXPECTED(net_runner, HAILO_OUT_OF_HOST_MEMORY); + return net_runner; +} + +hailo_status NetworkRunner::run_input_vstream(InputVStream &vstream) +{ + auto dataset = Buffer::create(vstream.get_frame_size(), 0xAB); + CHECK_EXPECTED_AS_STATUS(dataset); + auto last_write_time = std::chrono::steady_clock::now(); + auto framerate_interval = std::chrono::duration(1) / m_params.framerate; + while(true) { + auto status = vstream.write(MemoryView(dataset.value())); + if (status == HAILO_STREAM_ABORTED_BY_USER) { + return status; + } + CHECK_SUCCESS(status); + + if (m_params.framerate != UNLIMITED_FRAMERATE) { + auto elapsed_time = std::chrono::steady_clock::now() - last_write_time; + std::this_thread::sleep_for(framerate_interval - elapsed_time); + last_write_time = std::chrono::steady_clock::now(); + } + } + return HAILO_SUCCESS; +} + +hailo_status NetworkRunner::run_output_vstream(OutputVStream &vstream, bool first, std::shared_ptr net_live_track) +{ + auto result = Buffer::create(vstream.get_frame_size()); + CHECK_EXPECTED_AS_STATUS(result); + while(true) { + auto status = vstream.read(MemoryView(result.value())); + if (status == HAILO_STREAM_ABORTED_BY_USER) { + return status; + } + CHECK_SUCCESS(status); + if (first) { + net_live_track->progress(); + } + } + return HAILO_SUCCESS; +} + +hailo_status NetworkRunner::run(Event &shutdown_event, LivePrinter &live_printer) +{ + std::vector> threads; + for (auto &input_vstream : m_input_vstreams) { + threads.emplace_back(std::make_unique>([this, &input_vstream](){ + return run_input_vstream(input_vstream); + })); + } + + auto net_live_track = std::make_shared(m_name); + live_printer.add(net_live_track);//support progress over multiple outputs + + bool first = true;//TODO: check with multiple outputs + for (auto &output_vstream : m_output_vstreams) { + threads.emplace_back(std::make_unique>([&output_vstream, first, net_live_track](){ + return run_output_vstream(output_vstream, first, net_live_track); + })); + first = false; + } + + //TODO: signal a barrier that we should start infer and timer. return threads and move stop outside? + CHECK_SUCCESS(shutdown_event.wait(HAILO_INFINITE_TIMEOUT)); + stop(); + return wait_for_threads(threads); +} + +void NetworkRunner::stop() +{ + for (auto &input_vstream : m_input_vstreams) { + (void) input_vstream.abort(); + } + for (auto &output_vstream : m_output_vstreams) { + (void) output_vstream.abort(); + } +} + +Expected, std::vector>> NetworkRunner::create_vstreams( + ConfiguredNetworkGroup &net_group, const std::map ¶ms) +{//TODO: support network name + size_t match_count = 0; + + std::map input_vstreams_params; + auto input_vstreams_info = net_group.get_input_vstream_infos(); + CHECK_EXPECTED(input_vstreams_info); + for (auto &input_vstream_info : input_vstreams_info.value()) { + auto elem_it = params.find(input_vstream_info.name); + if (elem_it != params.end()) { + input_vstreams_params.emplace(input_vstream_info.name, elem_it->second); + match_count++; + } + else { + input_vstreams_params.emplace(input_vstream_info.name, HailoRTDefaults::get_vstreams_params()); + } + } + + std::map output_vstreams_params; + auto output_vstreams_info = net_group.get_output_vstream_infos(); + CHECK_EXPECTED(output_vstreams_info); + for (auto &output_vstream_info : output_vstreams_info.value()) { + auto elem_it = params.find(output_vstream_info.name); + if (elem_it != params.end()) { + output_vstreams_params.emplace(output_vstream_info.name, elem_it->second); + match_count++; + } + else { + output_vstreams_params.emplace(output_vstream_info.name, HailoRTDefaults::get_vstreams_params()); + } + } + + CHECK(match_count == params.size(), make_unexpected(HAILO_INVALID_ARGUMENT), "One of the params has an invalid vStream name"); + + auto input_vstreams = VStreamsBuilder::create_input_vstreams(net_group, input_vstreams_params); + CHECK_EXPECTED(input_vstreams); + + auto output_vstreams = VStreamsBuilder::create_output_vstreams(net_group, output_vstreams_params); + CHECK_EXPECTED(output_vstreams); + + return {{input_vstreams.release(), output_vstreams.release()}};//TODO: move? copy elision? +} \ No newline at end of file diff --git a/hailort/hailortcli/run2/network_runner.hpp b/hailort/hailortcli/run2/network_runner.hpp new file mode 100644 index 0000000..d59cf23 --- /dev/null +++ b/hailort/hailortcli/run2/network_runner.hpp @@ -0,0 +1,72 @@ +/** + * Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved. + * Distributed under the MIT license (https://opensource.org/licenses/MIT) + **/ +/** + * @file network_runner.hpp + * @brief Run network on hailo device + **/ + +#ifndef _HAILO_HAILORTCLI_RUN2_NETWORK_RUNNER_HPP_ +#define _HAILO_HAILORTCLI_RUN2_NETWORK_RUNNER_HPP_ + +#include "hailo/vdevice.hpp" +#include "hailo/vstream.hpp" +#include "hailo/event.hpp" +#include "hailo/network_group.hpp" +#include "hailo/expected.hpp" + +#include "live_printer.hpp" +#include "network_live_track.hpp" + +#include +#include + +constexpr uint32_t UNLIMITED_FRAMERATE = 0; + +struct VStreamParams +{ + VStreamParams(); + + std::string name; + hailo_vstream_params_t params; +}; + +struct NetworkParams +{ + std::string hef_path; + std::string net_group_name; + std::vector vstream_params; + + // Network parameters + uint16_t batch_size; + uint32_t scheduler_threshold; + uint32_t scheduler_timeout_ms; + + // Run parameters + uint32_t framerate; +}; + +class NetworkRunner +{ +public: + NetworkRunner(const NetworkParams ¶ms, const std::string &name, + std::vector &&input_vstreams, std::vector &&output_vstreams); + static hailort::Expected> create_shared(hailort::VDevice &vdevice, const NetworkParams ¶ms); + hailo_status run(hailort::Event &shutdown_event, LivePrinter &live_printer); + void stop(); + +private: + static hailort::Expected, std::vector>> create_vstreams( + hailort::ConfiguredNetworkGroup &net_group, const std::map ¶ms); + hailo_status run_input_vstream(hailort::InputVStream &vstream); + static hailo_status run_output_vstream(hailort::OutputVStream &vstream, bool first, std::shared_ptr net_live_track); + + + const NetworkParams &m_params;//TODO: copy instead of ref? + std::string m_name; + std::vector m_input_vstreams; + std::vector m_output_vstreams; +}; + +#endif /* _HAILO_HAILORTCLI_RUN2_NETWORK_RUNNER_HPP_ */ \ No newline at end of file diff --git a/hailort/hailortcli/run2/run2_command.cpp b/hailort/hailortcli/run2/run2_command.cpp new file mode 100644 index 0000000..01d492f --- /dev/null +++ b/hailort/hailortcli/run2/run2_command.cpp @@ -0,0 +1,348 @@ +/** + * Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved. + * Distributed under the MIT license (https://opensource.org/licenses/MIT) + **/ +/** + * @file run2_command.cpp + * @brief Run inference on hailo device + **/ + +#include "run2_command.hpp" +#include "live_printer.hpp" +#include "timer_live_track.hpp" +#include "network_runner.hpp" + +#include "common/async_thread.hpp" +#include "hailo/vdevice.hpp" +#include "hailo/hef.hpp" + +#include +#include + +using namespace hailort; + +constexpr uint32_t DEFAULT_TIME_TO_RUN_SECONDS = 5; + +/** VStreamNameValidator */ +class VStreamNameValidator : public CLI::Validator { + public: + VStreamNameValidator(const CLI::Option *hef_path_option, const CLI::Option *net_group_name_option); +private: + static std::vector get_values(const std::string &hef_path, const std::string &net_group_name); +}; + +VStreamNameValidator::VStreamNameValidator(const CLI::Option *hef_path_option, const CLI::Option *net_group_name_option) : Validator("VSTREAM") { + func_ = [](std::string&) { + //TODO: support? + return std::string(); + }; + autocomplete_func_ = [hef_path_option, net_group_name_option](const std::string&) { + // TODO: remove existing names from prev user input + return get_values(hef_path_option->as(), net_group_name_option->as()); + }; +} + +std::vector VStreamNameValidator::get_values(const std::string &hef_path, const std::string &net_group_name) +{ + auto hef = Hef::create(hef_path); + if (!hef.has_value()) { + return {}; + } + + // TODO: duplicate + auto actual_net_group_name = net_group_name; + if (actual_net_group_name.empty()) { + auto net_groups_names = hef->get_network_groups_names(); + if (net_groups_names.size() != 1) { + return {}; + } + actual_net_group_name = net_groups_names[0]; + } + + auto vstreams_info = hef->get_all_vstream_infos(actual_net_group_name); + if (!vstreams_info.has_value()) { + return {}; + } + + std::vector names; + for (auto &vstream_info : vstreams_info.value()) { + names.emplace_back(vstream_info.name); + } + return names; +} + +/** VStreamApp */ +class VStreamApp : public CLI::App +{ +public: + VStreamApp(const std::string &description, const std::string &name, CLI::Option *hef_path_option, CLI::Option *net_group_name_option); + const VStreamParams& get_params(); + +private: + CLI::Option* add_flag_callback(CLI::App *app, const std::string &name, const std::string &description, + std::function function); + + VStreamParams m_params; +}; + +VStreamApp::VStreamApp(const std::string &description, const std::string &name, CLI::Option *hef_path_option, + CLI::Option *net_group_name_option) : CLI::App(description, name), m_params() +{ + add_option("name", m_params.name, "vStream name") + ->check(VStreamNameValidator(hef_path_option, net_group_name_option)); + + auto format_opt_group = add_option_group("Format"); + format_opt_group->add_option("--type", m_params.params.user_buffer_format.type, "Format type") + ->transform(HailoCheckedTransformer({ + { "auto", HAILO_FORMAT_TYPE_AUTO }, + { "uint8", HAILO_FORMAT_TYPE_UINT8 }, + { "uint16", HAILO_FORMAT_TYPE_UINT16 }, + { "float32", HAILO_FORMAT_TYPE_FLOAT32 } + })) + ->default_val("auto"); + + format_opt_group->add_option("--order", m_params.params.user_buffer_format.order, "Format order") + ->transform(HailoCheckedTransformer({ + { "auto", HAILO_FORMAT_ORDER_AUTO }, + { "nhwc", HAILO_FORMAT_ORDER_NHWC }, + { "nhcw",HAILO_FORMAT_ORDER_NHCW }, + { "fcr", HAILO_FORMAT_ORDER_FCR }, + { "f8cr", HAILO_FORMAT_ORDER_F8CR }, + { "nhw", HAILO_FORMAT_ORDER_NHW }, + { "nc", HAILO_FORMAT_ORDER_NC }, + { "bayer_rgb", HAILO_FORMAT_ORDER_BAYER_RGB }, + { "12_bit_bayer_rgb", HAILO_FORMAT_ORDER_12_BIT_BAYER_RGB }, + { "hailo_nms", HAILO_FORMAT_ORDER_HAILO_NMS }, + { "nchw", HAILO_FORMAT_ORDER_NCHW }, + { "yuy2", HAILO_FORMAT_ORDER_YUY2 }, + { "nv12", HAILO_FORMAT_ORDER_NV12 }, + { "nv21", HAILO_FORMAT_ORDER_NV21 } + })) + ->default_val("auto"); + + add_flag_callback(format_opt_group, "-q,--quantized,!--no-quantized", "Whether or not data is quantized", + [this](bool result){ + m_params.params.user_buffer_format.flags = result ? + m_params.params.user_buffer_format.flags | HAILO_FORMAT_FLAGS_QUANTIZED : + static_cast(m_params.params.user_buffer_format.flags & (~HAILO_FORMAT_FLAGS_QUANTIZED));}) + ->run_callback_for_default() + ->default_val(true); // default_val() must be after run_callback_for_default() +} + +const VStreamParams& VStreamApp::get_params() +{ + //TODO: instead of copy do a move + call reset()? change func name to move_params? same for NetworkParams/NetworkApp class + return m_params; +} + +CLI::Option* VStreamApp::add_flag_callback(CLI::App *app, const std::string &name, const std::string &description, + std::function function) + { + // get_option doesn't support multiple names so taking the first one + auto first_name = name.substr(0, name.find(',')); + auto wrap_function = [app, function, first_name](std::int64_t){function(app->get_option(first_name)->as());}; + return app->add_flag_function(name, wrap_function, description); + } + +/** NetworkGroupNameValidator */ +class NetworkGroupNameValidator : public CLI::Validator { + public: + NetworkGroupNameValidator(const CLI::Option *hef_path_option); +}; + +NetworkGroupNameValidator::NetworkGroupNameValidator(const CLI::Option *hef_path_option) : Validator("NETWORK_GROUP") { + func_ = [](std::string&) { + //TODO: support? + return std::string(); + }; + autocomplete_func_ = [hef_path_option](const std::string&) -> std::vector{ + auto hef = Hef::create(hef_path_option->as()); + if (!hef.has_value()) { + return {}; + } + return hef->get_network_groups_names(); + }; +} + +/** NetworkApp */ +class NetworkApp : public CLI::App +{ +public: + NetworkApp(const std::string &description, const std::string &name); + const NetworkParams& get_params(); + +private: + void add_vstream_app_subcom(CLI::Option *hef_path_option, CLI::Option *net_group_name_option); + NetworkParams m_params; +}; + +NetworkApp::NetworkApp(const std::string &description, const std::string &name) : CLI::App(description, name), m_params() +{ + auto hef_path_option = add_option("hef", m_params.hef_path, "HEF file path")->check(CLI::ExistingFile); + auto net_group_name_option = add_option("--name", m_params.net_group_name, "Network group name") + ->default_val("") + ->needs(hef_path_option) + ->check(NetworkGroupNameValidator(hef_path_option)); + // NOTE: callbacks/params aren't called/updated before auto-completion (even after changing the order in App.hpp - at least for 2 jumps) + auto net_params = add_option_group("Network Group Parameters"); + net_params->add_option("--batch-size", m_params.batch_size, "Batch size")->default_val(HAILO_DEFAULT_BATCH_SIZE); + net_params->add_option("--scheduler-threshold", m_params.scheduler_threshold, "Scheduler threshold")->default_val(0); + net_params->add_option("--scheduler-timeout", m_params.scheduler_timeout_ms, "Scheduler timeout in milliseconds")->default_val(0); + + auto run_params = add_option_group("Run Parameters"); + run_params->add_option("--framerate", m_params.framerate, "Input vStreams framerate")->default_val(UNLIMITED_FRAMERATE); + + add_vstream_app_subcom(hef_path_option, net_group_name_option); +} + +void NetworkApp::add_vstream_app_subcom(CLI::Option *hef_path_option, CLI::Option *net_group_name_option) +{ + auto vstream_app = std::make_shared("Set vStream", "set-vstream", hef_path_option, net_group_name_option); + vstream_app->immediate_callback(); + vstream_app->callback([this, vstream_app, hef_path_option, net_group_name_option]() { + m_params.vstream_params.push_back(vstream_app->get_params()); + + // Throw an error if anything is left over and should not be. + _process_extras(); + + // NOTE: calling "net_app->clear(); m_params = NetworkParams();" is not sufficient because default values + // need to be re-set. we can override clear and reset them but there might be other issues as well + // and this one feels less hacky ATM + remove_subcommand(vstream_app.get()); + // Remove from parsed_subcommands_ as well (probably a bug in CLI11) + parsed_subcommands_.erase(std::remove_if( + parsed_subcommands_.begin(), parsed_subcommands_.end(), + [vstream_app](auto x){return x == vstream_app.get();}), + parsed_subcommands_.end()); + add_vstream_app_subcom(hef_path_option, net_group_name_option); + }); + + // Must set fallthrough to support nested repeated subcommands. + vstream_app->fallthrough(); + add_subcommand(vstream_app); +} + +const NetworkParams& NetworkApp::get_params() +{ + return m_params; +} + +/** Run2 */ +class Run2 : public CLI::App +{ +public: + Run2(); + + const std::vector& get_network_params(); + std::chrono::seconds get_time_to_run(); + +private: + void add_net_app_subcom(); + std::vector m_network_params; + uint32_t m_time_to_run; +}; + +Run2::Run2() : CLI::App("Run networks (preview)", "run2") +{ + add_net_app_subcom(); + add_option("-t,--time-to-run", m_time_to_run, "Time to run (seconds)") + ->default_val(DEFAULT_TIME_TO_RUN_SECONDS) + ->check(CLI::PositiveNumber); +} + +void Run2::add_net_app_subcom() +{ + auto net_app = std::make_shared("Set network", "set-net"); + net_app->immediate_callback(); + net_app->callback([this, net_app]() { + m_network_params.push_back(net_app->get_params()); + + // Throw an error if anything is left over and should not be. + _process_extras(); + + // NOTE: calling "net_app->clear(); m_params = NetworkParams();" is not sufficient because default values + // need to be re-set. we can override clear and reset them but there might be other issues as well + // and this one feels less hacky ATM + remove_subcommand(net_app.get()); + // Remove from parsed_subcommands_ as well (probably a bug in CLI11) + parsed_subcommands_.erase(std::remove_if( + parsed_subcommands_.begin(), parsed_subcommands_.end(), + [net_app](auto x){return x == net_app.get();}), + parsed_subcommands_.end()); + add_net_app_subcom(); + }); + // NOTE: fallthrough() is not a must here but it is also not working (causing only a single vstream param + // instead of >1). Debug - App.hpp::void _parse(std::vector &args) + add_subcommand(net_app); +} + +const std::vector& Run2::get_network_params() +{ + return m_network_params; +} + +std::chrono::seconds Run2::get_time_to_run() +{ + return std::chrono::seconds(m_time_to_run); +} + +/** Run2Command */ +Run2Command::Run2Command(CLI::App &parent_app) : Command(parent_app.add_subcommand(std::make_shared())) +{ +} + +static hailo_status wait_for_threads(std::vector> &threads) +{ + auto last_error_status = HAILO_SUCCESS; + for (auto& thread : threads) { + auto thread_status = thread->get(); + if ((HAILO_SUCCESS != thread_status) && (HAILO_STREAM_ABORTED_BY_USER != thread_status)) { + last_error_status = thread_status; + LOGGER__ERROR("Thread failed with with status {}", thread_status); + } + } + return last_error_status; +} + +hailo_status Run2Command::execute() +{ + Run2 *app = reinterpret_cast(m_app); + + if (0 == app->get_network_params().size()) { + LOGGER__ERROR("Nothing to run"); + return HAILO_INVALID_OPERATION; + } + if (1 == app->get_network_params().size()) { + LOGGER__WARN("\"hailortcli run2\" is in preview. It is recommended to use \"hailortcli run\" command for a single network group"); + } + + // TODO: support multi-device. maybe get all by default? + hailo_vdevice_params_t vdevice_params = {}; + CHECK_SUCCESS(hailo_init_vdevice_params(&vdevice_params)); + auto vdevice = VDevice::create(vdevice_params); + CHECK_EXPECTED_AS_STATUS(vdevice); + + // create network runners + std::vector> net_runners; + for (auto &net_params : app->get_network_params()) { + auto net_runner = NetworkRunner::create_shared(*vdevice->get(), net_params); + CHECK_EXPECTED_AS_STATUS(net_runner); + net_runners.emplace_back(net_runner.release()); + } + LivePrinter live_printer(std::chrono::seconds(1)); + live_printer.add(std::make_shared(app->get_time_to_run())); + + auto shutdown_event = Event::create(Event::State::not_signalled); + CHECK_EXPECTED_AS_STATUS(shutdown_event); + std::vector> threads; + for (auto &net_runner : net_runners) { + threads.emplace_back(std::make_unique>([&net_runner, &shutdown_event, &live_printer](){ + return net_runner->run(shutdown_event.value(), live_printer); + })); + } + // TODO: wait for all nets before starting timer. start() should update TimerLiveTrack to start. or maybe append here but first in vector... + live_printer.start(); + std::this_thread::sleep_for(app->get_time_to_run()); + shutdown_event->signal(); + return wait_for_threads(threads); +} \ No newline at end of file diff --git a/hailort/hailortcli/run2/run2_command.hpp b/hailort/hailortcli/run2/run2_command.hpp new file mode 100644 index 0000000..e569deb --- /dev/null +++ b/hailort/hailortcli/run2/run2_command.hpp @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved. + * Distributed under the MIT license (https://opensource.org/licenses/MIT) + **/ +/** + * @file run2_command.hpp + * @brief Run inference on hailo device + **/ + +#ifndef _HAILO_HAILORTCLI_RUN2_RUN2_COMMAND_HPP_ +#define _HAILO_HAILORTCLI_RUN2_RUN2_COMMAND_HPP_ + +#include "../command.hpp" + +class Run2Command : public Command { +public: + explicit Run2Command(CLI::App &parent_app); + + hailo_status execute() override; +private: +}; + +#endif /* _HAILO_HAILORTCLI_RUN2_RUN2_COMMAND_HPP_ */ \ No newline at end of file diff --git a/hailort/hailortcli/run2/timer_live_track.cpp b/hailort/hailortcli/run2/timer_live_track.cpp new file mode 100644 index 0000000..33aeb2b --- /dev/null +++ b/hailort/hailortcli/run2/timer_live_track.cpp @@ -0,0 +1,31 @@ +/** + * Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved. + * Distributed under the MIT license (https://opensource.org/licenses/MIT) + **/ +/** + * @file timer_live_track.cpp + * @brief Timer live track + **/ + +#include "timer_live_track.hpp" +#include "../common.hpp" +#include +#include + +TimerLiveTrack::TimerLiveTrack(std::chrono::milliseconds duration) : + m_duration(duration), m_start(std::chrono::steady_clock::now()) +{ +} + +uint32_t TimerLiveTrack::get_text(std::stringstream &ss) +{ + static const uint32_t MAX_PROGRESS_BAR_WIDTH = 20; + auto elapsed_time = std::chrono::steady_clock::now() - m_start; + auto eta = std::chrono::seconds(std::max(0, static_cast(std::round(std::chrono::duration(m_duration - elapsed_time).count())))); // std::chrono::round is from C++17 + auto elapsed_percentage = std::min(100, static_cast(std::round(std::chrono::duration(100 * elapsed_time / m_duration).count()))); + auto progress_bar_width = std::max(1, std::min(MAX_PROGRESS_BAR_WIDTH, + static_cast(std::round(std::chrono::duration(MAX_PROGRESS_BAR_WIDTH * elapsed_time / m_duration).count())))); + + ss << fmt::format("[{:=>{}}{:{}}] {:>3}% {}\n", '>', progress_bar_width, "", MAX_PROGRESS_BAR_WIDTH - progress_bar_width, elapsed_percentage, CliCommon::duration_to_string(eta)); + return 1; +} \ No newline at end of file diff --git a/hailort/hailortcli/run2/timer_live_track.hpp b/hailort/hailortcli/run2/timer_live_track.hpp new file mode 100644 index 0000000..ce9d548 --- /dev/null +++ b/hailort/hailortcli/run2/timer_live_track.hpp @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved. + * Distributed under the MIT license (https://opensource.org/licenses/MIT) + **/ +/** + * @file timer_live_track.hpp + * @brief Timer live track + **/ + +#include "live_printer.hpp" + +#ifndef _HAILO_HAILORTCLI_RUN2_TIMER_LIVE_TRACK_HPP_ +#define _HAILO_HAILORTCLI_RUN2_TIMER_LIVE_TRACK_HPP_ + +class TimerLiveTrack : public LivePrinter::Track +{ +public: + TimerLiveTrack(std::chrono::milliseconds duration); + virtual ~TimerLiveTrack() = default; + virtual uint32_t get_text(std::stringstream &ss) override; + +private: + std::chrono::milliseconds m_duration; + std::chrono::time_point m_start; +}; + +#endif /* _HAILO_HAILORTCLI_RUN2_TIMER_LIVE_TRACK_HPP_ */ \ No newline at end of file diff --git a/hailort/hailortcli/run_command.cpp b/hailort/hailortcli/run_command.cpp index 8eff84f..ef4bc82 100644 --- a/hailort/hailortcli/run_command.cpp +++ b/hailort/hailortcli/run_command.cpp @@ -19,6 +19,7 @@ #endif #include "common.hpp" +#include "common/string_utils.hpp" #include "common/file_utils.hpp" #include "common/async_thread.hpp" #include "common/barrier.hpp" @@ -29,8 +30,11 @@ #include "hailo/vstream.hpp" #include "hailo/vdevice.hpp" +#include "spdlog/fmt/fmt.h" + #include #include +#include #include #include std::condition_variable wait_for_exit_cv; @@ -48,6 +52,9 @@ constexpr std::chrono::milliseconds TIME_TO_WAIT_FOR_CONFIG(300); constexpr std::chrono::milliseconds TIME_TO_WAIT_FOR_CONFIG(30000); #define HAILORTCLI_DEFAULT_VSTREAM_TIMEOUT_MS (HAILO_DEFAULT_VSTREAM_TIMEOUT_MS * 100) #endif /* ifndef HAILO_EMULATOR */ +static const char *RUNTIME_DATA_OUTPUT_PATH_HEF_PLACE_HOLDER = ""; +static const char *RUNTIME_DATA_BATCH_TO_MEASURE_OPT_LAST = "last"; +static const char *RUNTIME_DATA_BATCH_TO_MEASURE_OPT_DEFAULT = "2"; #ifndef _MSC_VER void user_signal_handler_func(int signum) @@ -86,7 +93,17 @@ bool should_measure_pipeline_stats(const inference_runner_params& params) bool use_batch_to_measure_opt(const inference_runner_params& params) { return params.runtime_data.collect_runtime_data && - (params.runtime_data.batch_to_measure != RUNTIME_DATA_IGNORE_BATCH_TO_MEASURE_OPT); + (params.runtime_data.batch_to_measure_str != RUNTIME_DATA_BATCH_TO_MEASURE_OPT_LAST); +} + +// We assume that hef_place_holder_regex is valid +std::string format_runtime_data_output_path(const std::string &base_output_path, const std::string &hef_path, + const std::string &hef_place_holder_regex = RUNTIME_DATA_OUTPUT_PATH_HEF_PLACE_HOLDER, + const std::string &hef_suffix = ".hef") +{ + const auto hef_basename = Filesystem::basename(hef_path); + const auto hef_no_suffix = Filesystem::remove_suffix(hef_basename, hef_suffix); + return std::regex_replace(base_output_path, std::regex(hef_place_holder_regex), hef_no_suffix); } static void add_run_command_params(CLI::App *run_subcommand, inference_runner_params& params) @@ -118,7 +135,7 @@ static void add_run_command_params(CLI::App *run_subcommand, inference_runner_pa auto total_batch_size = run_subcommand->add_option("--batch-size", params.batch_size, "Inference batch (should be a divisor of --frames-count if provided).\n" "This batch applies to the whole network_group. for differential batch per network, see --net-batch-size") - ->check(CLI::PositiveNumber) + ->check(CLI::NonNegativeNumber) ->default_val(HAILO_DEFAULT_BATCH_SIZE); run_subcommand->add_option("--net-batch-size", params.batch_per_network, @@ -208,16 +225,16 @@ static void add_run_command_params(CLI::App *run_subcommand, inference_runner_pa auto *collect_runtime_data_subcommand = run_subcommand->add_subcommand("collect-runtime-data", "Collect runtime data to be used by the Profiler"); static const char *JSON_SUFFIX = ".json"; - collect_runtime_data_subcommand->add_option("--output-path", - params.runtime_data.runtime_data_output_path, "Runtime data output file path") - ->default_val("runtime_data.json") + collect_runtime_data_subcommand->add_option("--output-path", params.runtime_data.runtime_data_output_path, + fmt::format("Runtime data output file path\n'{}' will be replaced with the current running hef", + RUNTIME_DATA_OUTPUT_PATH_HEF_PLACE_HOLDER)) + ->default_val(fmt::format("runtime_data_{}.json", RUNTIME_DATA_OUTPUT_PATH_HEF_PLACE_HOLDER)) ->check(FileSuffixValidator(JSON_SUFFIX)); - std::stringstream batch_to_measure_help; - batch_to_measure_help << "Batch to be measured " << std::endl - << "The last batch will be measured if " << RUNTIME_DATA_IGNORE_BATCH_TO_MEASURE_OPT << " is provided"; - collect_runtime_data_subcommand->add_option("--batch-to-measure", - params.runtime_data.batch_to_measure, batch_to_measure_help.str()) - ->default_val(RUNTIME_DATA_DEFAULT_BATCH_TO_MEASURE_OPT); + collect_runtime_data_subcommand->add_option("--batch-to-measure", params.runtime_data.batch_to_measure_str, + fmt::format("Batch to be measured (non-negative integer)\nThe last batch will be measured if '{}' is provided", + RUNTIME_DATA_BATCH_TO_MEASURE_OPT_LAST)) + ->default_val(RUNTIME_DATA_BATCH_TO_MEASURE_OPT_DEFAULT) + ->check(UintOrKeywordValidator(RUNTIME_DATA_BATCH_TO_MEASURE_OPT_LAST)); collect_runtime_data_subcommand->parse_complete_callback([¶ms]() { // If this subcommand was parsed, then we need to download runtime_data params.runtime_data.collect_runtime_data = true; @@ -257,7 +274,7 @@ static void add_run_command_params(CLI::App *run_subcommand, inference_runner_pa "--sampling-period requires --measure-power or --measure-current"); PARSE_CHECK(power_averaging_factor->empty() || has_oneof_measure_flags, "--averaging-period factor --measure-power or --measure-current"); - PARSE_CHECK(((0 != params.time_to_run) || (0 == (params.frames_count % params.batch_size))), + PARSE_CHECK(((0 != params.time_to_run) || (HAILO_DEFAULT_BATCH_SIZE == params.batch_size) || (0 == (params.frames_count % params.batch_size))), "--batch-size should be a divisor of --frames-count if provided"); // TODO HRT-5363 support multiple devices PARSE_CHECK((params.vdevice_params.device_count == 1) || params.csv_output.empty() || @@ -278,11 +295,14 @@ static void add_run_command_params(CLI::App *run_subcommand, inference_runner_pa PARSE_CHECK(!(params.vdevice_params.multi_process_service && is_hw_only), "--hw-only mode is not supported for multi process service"); - if (use_batch_to_measure_opt(params) && - (0 != params.frames_count) && (params.frames_count < params.runtime_data.batch_to_measure)) { - LOGGER__WARNING("--frames-count ({}) is smaller than --batch-to-measure ({}), " - "hence timestamps will not be updated in runtime data", params.frames_count, - params.runtime_data.batch_to_measure); + if (use_batch_to_measure_opt(params)) { + // This cast is ok because we validate params.runtime_data.batch_to_measure_str with UintOrKeywordValidator + params.runtime_data.batch_to_measure = static_cast(std::stoi(params.runtime_data.batch_to_measure_str)); + if ((0 != params.frames_count) && (params.frames_count < params.runtime_data.batch_to_measure)) { + LOGGER__WARNING("--frames-count ({}) is smaller than --batch-to-measure ({}), " + "hence timestamps will not be updated in runtime data", params.frames_count, + params.runtime_data.batch_to_measure); + } } }); } @@ -385,7 +405,7 @@ hailo_status send_loop(const inference_runner_params ¶ms, SendObject &send_o auto status = send_object.write(MemoryView( const_cast(input_buffer->data()) + offset, send_object.get_frame_size())); - if (HAILO_STREAM_INTERNAL_ABORT == status) { + if (HAILO_STREAM_ABORTED_BY_USER == status) { LOGGER__DEBUG("Input stream was aborted!"); return status; } @@ -401,7 +421,7 @@ hailo_status send_loop(const inference_runner_params ¶ms, SendObject &send_o template hailo_status recv_loop(const inference_runner_params ¶ms, RecvObject &recv_object, std::shared_ptr progress_bar, Barrier &barrier, LatencyMeter &overall_latency_meter, - std::map &dst_data, std::atomic_size_t &received_frames_count, uint32_t output_idx, bool show_progress, + std::map &dst_data, std::atomic_size_t &received_frames_count, bool show_progress, uint16_t batch_size) { uint32_t num_of_batches = ((0 == params.time_to_run) ? (params.frames_count / batch_size) : UINT32_MAX); @@ -410,13 +430,14 @@ hailo_status recv_loop(const inference_runner_params ¶ms, RecvObject &recv_o barrier.arrive_and_wait(); } for (int j = 0; j < batch_size; j++) { - auto status = recv_object.read(MemoryView(*dst_data[recv_object.name()])); + auto dst_buffer = MemoryView(*dst_data[recv_object.name()]); + auto status = recv_object.read(dst_buffer); if (HAILO_SUCCESS != status) { return status; } if (params.measure_overall_latency) { - overall_latency_meter.add_end_sample(output_idx, std::chrono::steady_clock::now().time_since_epoch()); + overall_latency_meter.add_end_sample(recv_object.name(), std::chrono::steady_clock::now().time_since_epoch()); } if (show_progress && params.show_progress) { @@ -433,17 +454,17 @@ hailo_status abort_streams(std::vector> &send std::vector> &recv_objects) { auto status = HAILO_SUCCESS; // Best effort - for (auto &input_stream : send_objects) { - auto abort_status = input_stream.get().abort(); + for (auto &output_stream : recv_objects) { + auto abort_status = output_stream.get().abort(); if (HAILO_SUCCESS != abort_status) { - LOGGER__ERROR("Failed to abort input stream {}", input_stream.get().name()); + LOGGER__ERROR("Failed to abort output stream {}", output_stream.get().name()); status = abort_status; } } - for (auto &output_stream : recv_objects) { - auto abort_status = output_stream.get().abort(); + for (auto &input_stream : send_objects) { + auto abort_status = input_stream.get().abort(); if (HAILO_SUCCESS != abort_status) { - LOGGER__ERROR("Failed to abort output stream {}", output_stream.get().name()); + LOGGER__ERROR("Failed to abort input stream {}", input_stream.get().name()); status = abort_status; } } @@ -549,15 +570,18 @@ std::pair get_network_to_batch(const std::string &name_to uint16_t get_batch_size(const inference_runner_params ¶ms, const std::string &network_name) { + uint16_t batch_size = params.batch_size; + /* params.batch_per_network is a partial list of networks. If a network is not in it, it gets the network_group_batch (params.batch_size) */ for (auto &name_to_batch_str : params.batch_per_network) { auto name_to_batch = get_network_to_batch(name_to_batch_str); if (network_name == name_to_batch.first) { - return name_to_batch.second; + batch_size = name_to_batch.second; + break; } } - return params.batch_size; + return (HAILO_DEFAULT_BATCH_SIZE == batch_size ? 1 : batch_size); } Expected> get_configure_params(const inference_runner_params ¶ms, hailort::Hef &hef, hailo_stream_interface_t interface) @@ -620,12 +644,12 @@ static hailo_status run_streaming_impl(std::shared_ptr c if (params.measure_overall_latency) { CHECK((send_objects.size() == 1), HAILO_INVALID_OPERATION, "Overall latency measurement not support multiple inputs network"); } - std::set output_channels; - for (uint32_t output_channel_index = 0; output_channel_index < recv_objects.size(); output_channel_index++) { - output_channels.insert(output_channel_index); + std::set output_names; + for (auto &output : recv_objects) { + output_names.insert(output.get().name()); } - LatencyMeter overall_latency_meter(output_channels, OVERALL_LATENCY_TIMESTAMPS_LIST_LENGTH); + LatencyMeter overall_latency_meter(output_names, OVERALL_LATENCY_TIMESTAMPS_LIST_LENGTH); Barrier barrier(send_objects.size() + recv_objects.size()); std::vector frames_recieved_per_output(recv_objects.size()); @@ -648,9 +672,9 @@ static hailo_status run_streaming_impl(std::shared_ptr c auto &frames_recieved = frames_recieved_per_output[output_index]; results.emplace_back(std::make_unique>( [network_progress_bar, params, &recv_object, &output_buffers, first, &barrier, &overall_latency_meter, - &frames_recieved, output_index, batch_size]() { + &frames_recieved, batch_size]() { auto res = recv_loop(params, recv_object.get(), network_progress_bar, barrier, overall_latency_meter, - output_buffers, frames_recieved, output_index, first, batch_size); + output_buffers, frames_recieved, first, batch_size); if (HAILO_SUCCESS != res) { barrier.terminate(); } @@ -685,7 +709,7 @@ static hailo_status run_streaming_impl(std::shared_ptr c auto error_status = HAILO_SUCCESS; for (auto& result : results) { auto status = result->get(); - if (HAILO_STREAM_INTERNAL_ABORT == status) { + if (HAILO_STREAM_ABORTED_BY_USER == status) { continue; } if (HAILO_SUCCESS != status) { @@ -1051,7 +1075,7 @@ static Expected>> create_dataset( return results; } -Expected activate_network_group_and_run( +Expected activate_and_run_single_device( Device &device, const std::vector> &network_groups, const inference_runner_params ¶ms) @@ -1164,7 +1188,7 @@ Expected run_command_hef_single_device(const inference_runner_param } #endif - auto inference_result = activate_network_group_and_run(*device, network_group_list.value(), params); + auto inference_result = activate_and_run_single_device(*device, network_group_list.value(), params); #if defined(__GNUC__) // TODO: Support on windows (HRT-5919) @@ -1179,8 +1203,10 @@ Expected run_command_hef_single_device(const inference_runner_param } if (params.runtime_data.collect_runtime_data) { - DownloadActionListCommand::execute(*device, params.runtime_data.runtime_data_output_path, - network_group_list.value(), params.hef_path); + const auto runtime_data_output_path = format_runtime_data_output_path( + params.runtime_data.runtime_data_output_path, params.hef_path); + DownloadActionListCommand::execute(*device, runtime_data_output_path, network_group_list.value(), + params.hef_path); } #endif @@ -1188,54 +1214,21 @@ Expected run_command_hef_single_device(const inference_runner_param return inference_result; } -Expected run_command_hef_vdevice(const inference_runner_params ¶ms) -{ - auto hef = Hef::create(params.hef_path.c_str()); - CHECK_EXPECTED(hef, "Failed reading hef file {}", params.hef_path); - - auto network_groups_infos = hef->get_network_groups_infos(); - CHECK_EXPECTED(network_groups_infos); - bool scheduler_is_used = (1 < network_groups_infos->size()) || params.vdevice_params.multi_process_service; - - hailo_vdevice_params_t vdevice_params = {}; - auto status = hailo_init_vdevice_params(&vdevice_params); - CHECK_SUCCESS_AS_EXPECTED(status); - if (params.vdevice_params.device_count != HAILO_DEFAULT_DEVICE_COUNT) { - vdevice_params.device_count = params.vdevice_params.device_count; - } - std::vector dev_ids; - if (!params.vdevice_params.device_params.device_ids.empty()) { - auto dev_ids_exp = get_device_ids(params.vdevice_params.device_params); - CHECK_EXPECTED(dev_ids_exp); - - auto dev_ids_struct_exp = HailoRTCommon::to_device_ids_vector(dev_ids_exp.value()); - CHECK_EXPECTED(dev_ids_struct_exp); - dev_ids = dev_ids_struct_exp.release(); - - vdevice_params.device_ids = dev_ids.data(); - vdevice_params.device_count = static_cast(dev_ids.size()); - } - vdevice_params.scheduling_algorithm = (scheduler_is_used) ? HAILO_SCHEDULING_ALGORITHM_ROUND_ROBIN : HAILO_SCHEDULING_ALGORITHM_NONE; - vdevice_params.group_id = params.vdevice_params.group_id.c_str(); - vdevice_params.multi_process_service = params.vdevice_params.multi_process_service; - auto vdevice = VDevice::create(vdevice_params); - CHECK_EXPECTED(vdevice, "Failed creating vdevice"); - - // VDevice always has Pcie devices - auto configure_params = get_configure_params(params, hef.value(), hailo_stream_interface_t::HAILO_STREAM_INTERFACE_PCIE); - CHECK_EXPECTED(configure_params); - - auto network_group_list = vdevice.value()->configure(hef.value(), configure_params.value()); - CHECK_EXPECTED(network_group_list, "Failed configure vdevice from hef"); +Expected activate_and_run_vdevice( + std::vector> &physical_devices, + bool scheduler_is_used, + const std::vector> &network_groups, + const inference_runner_params ¶ms) +{ std::unique_ptr activated_network_group; if (!scheduler_is_used) { - auto activated_net_group_exp = activate_network_group(*network_group_list.value()[0]); + auto activated_net_group_exp = activate_network_group(*network_groups[0]); CHECK_EXPECTED(activated_net_group_exp, "Failed activate network_group"); activated_network_group = activated_net_group_exp.release(); } - auto input_dataset = create_dataset(network_group_list.value(), params); + auto input_dataset = create_dataset(network_groups, params); CHECK_EXPECTED(input_dataset, "Failed creating input dataset"); hailo_power_measurement_types_t measurement_type = HAILO_POWER_MEASUREMENT_TYPES__MAX_ENUM; @@ -1248,13 +1241,6 @@ Expected run_command_hef_vdevice(const inference_runner_params &par should_measure_power = true; } - std::vector> physical_devices; - if (!params.vdevice_params.multi_process_service) { - auto expected_physical_devices = vdevice.value()->get_physical_devices(); - CHECK_EXPECTED(expected_physical_devices); - physical_devices = expected_physical_devices.value(); - } - std::map> power_measurements; if (should_measure_power) { for (auto &device : physical_devices) { @@ -1273,50 +1259,20 @@ Expected run_command_hef_vdevice(const inference_runner_params &par for (auto &device : physical_devices) { auto temp_measure = make_shared_nothrow(device); CHECK_NOT_NULL_AS_EXPECTED(temp_measure, HAILO_OUT_OF_HOST_MEMORY); - status = temp_measure->start_measurement(); + auto status = temp_measure->start_measurement(); CHECK_SUCCESS_AS_EXPECTED(status, "Failed starting temperature measurement on device {}", device.get().get_dev_id()); temp_measurements.emplace(device.get().get_dev_id(), std::move(temp_measure)); } } -#if defined(__GNUC__) - for (auto &device : physical_devices) { - // TODO: Support on windows (HRT-5919) - if (use_batch_to_measure_opt(params)) { - status = DownloadActionListCommand::set_batch_to_measure(device.get(), params.runtime_data.batch_to_measure); - CHECK_SUCCESS_AS_EXPECTED(status); - } - } -#endif - - auto infer_result = run_inference(network_group_list.value(), input_dataset.value(), params); - -#if defined(__GNUC__) - for (auto &device : physical_devices) { - // TODO: Support on windows (HRT-5919) - if (use_batch_to_measure_opt(params) && (0 == params.frames_count) && infer_result) { - auto min_frames_count = get_min_inferred_frames_count(infer_result.value()); - CHECK_EXPECTED(min_frames_count); - if (min_frames_count.value() < params.runtime_data.batch_to_measure) { - LOGGER__WARNING("Number of frames sent ({}) is smaller than --batch-to-measure ({}), " - "hence timestamps will not be updated in runtime data", min_frames_count.value() , - params.runtime_data.batch_to_measure); - } - } - - if (params.runtime_data.collect_runtime_data) { - DownloadActionListCommand::execute(device.get(), params.runtime_data.runtime_data_output_path, - network_group_list.value(), params.hef_path); - } - } -#endif - + auto infer_result = run_inference(network_groups, input_dataset.value(), params); CHECK_EXPECTED(infer_result, "Error failed running inference"); InferResult inference_result(infer_result.release()); inference_result.initialize_measurements(physical_devices); if (should_measure_power) { + auto status = HAILO_SUCCESS; for (auto &power_measure_pair : power_measurements) { auto measurement_status = power_measure_pair.second->stop(); if (HAILO_SUCCESS != measurement_status) { @@ -1344,7 +1300,7 @@ Expected run_command_hef_vdevice(const inference_runner_params &par temp_measure_pair.second->stop_measurement(); auto temp_measure_p = make_shared_nothrow(temp_measure_pair.second->get_data()); CHECK_NOT_NULL_AS_EXPECTED(temp_measure_p, HAILO_OUT_OF_HOST_MEMORY); - status = inference_result.set_temp_measurement(temp_measure_pair.first, std::move(temp_measure_p)); + auto status = inference_result.set_temp_measurement(temp_measure_pair.first, std::move(temp_measure_p)); CHECK_SUCCESS_AS_EXPECTED(status); } } @@ -1352,6 +1308,93 @@ Expected run_command_hef_vdevice(const inference_runner_params &par return inference_result; } +Expected run_command_hef_vdevice(const inference_runner_params ¶ms) +{ + auto hef = Hef::create(params.hef_path.c_str()); + CHECK_EXPECTED(hef, "Failed reading hef file {}", params.hef_path); + + auto network_groups_infos = hef->get_network_groups_infos(); + CHECK_EXPECTED(network_groups_infos); + bool scheduler_is_used = (1 < network_groups_infos->size()) || params.vdevice_params.multi_process_service; + + hailo_vdevice_params_t vdevice_params = {}; + auto status = hailo_init_vdevice_params(&vdevice_params); + CHECK_SUCCESS_AS_EXPECTED(status); + if (params.vdevice_params.device_count != HAILO_DEFAULT_DEVICE_COUNT) { + vdevice_params.device_count = params.vdevice_params.device_count; + } + std::vector dev_ids; + if (!params.vdevice_params.device_params.device_ids.empty()) { + auto dev_ids_exp = get_device_ids(params.vdevice_params.device_params); + CHECK_EXPECTED(dev_ids_exp); + + auto dev_ids_struct_exp = HailoRTCommon::to_device_ids_vector(dev_ids_exp.value()); + CHECK_EXPECTED(dev_ids_struct_exp); + dev_ids = dev_ids_struct_exp.release(); + + vdevice_params.device_ids = dev_ids.data(); + vdevice_params.device_count = static_cast(dev_ids.size()); + } + vdevice_params.scheduling_algorithm = (scheduler_is_used) ? HAILO_SCHEDULING_ALGORITHM_ROUND_ROBIN : HAILO_SCHEDULING_ALGORITHM_NONE; + vdevice_params.group_id = params.vdevice_params.group_id.c_str(); + vdevice_params.multi_process_service = params.vdevice_params.multi_process_service; + auto vdevice = VDevice::create(vdevice_params); + CHECK_EXPECTED(vdevice, "Failed creating vdevice"); + + std::vector> physical_devices; + if (!params.vdevice_params.multi_process_service) { + auto expected_physical_devices = vdevice.value()->get_physical_devices(); + CHECK_EXPECTED(expected_physical_devices); + physical_devices = expected_physical_devices.value(); + } + + auto interface = vdevice.value()->get_default_streams_interface(); + CHECK_EXPECTED(interface, "Failed to get default streams interface"); + + auto configure_params = get_configure_params(params, hef.value(), *interface); + CHECK_EXPECTED(configure_params); + + auto network_group_list = vdevice.value()->configure(hef.value(), configure_params.value()); + CHECK_EXPECTED(network_group_list, "Failed configure vdevice from hef"); + +#if defined(__GNUC__) + for (auto &device : physical_devices) { + // TODO: Support on windows (HRT-5919) + if (use_batch_to_measure_opt(params)) { + status = DownloadActionListCommand::set_batch_to_measure(device.get(), params.runtime_data.batch_to_measure); + CHECK_SUCCESS_AS_EXPECTED(status); + } + } +#endif + + auto infer_result = activate_and_run_vdevice(physical_devices, scheduler_is_used, network_group_list.value(), params); + CHECK_EXPECTED(infer_result, "Error failed running inference"); + +#if defined(__GNUC__) + for (auto &device : physical_devices) { + // TODO: Support on windows (HRT-5919) + if (use_batch_to_measure_opt(params) && (0 == params.frames_count) && infer_result) { + auto min_frames_count = get_min_inferred_frames_count(infer_result.value()); + CHECK_EXPECTED(min_frames_count); + if (min_frames_count.value() < params.runtime_data.batch_to_measure) { + LOGGER__WARNING("Number of frames sent ({}) is smaller than --batch-to-measure ({}), " + "hence timestamps will not be updated in runtime data", min_frames_count.value() , + params.runtime_data.batch_to_measure); + } + } + + if (params.runtime_data.collect_runtime_data) { + const auto runtime_data_output_path = format_runtime_data_output_path( + params.runtime_data.runtime_data_output_path, params.hef_path); + DownloadActionListCommand::execute(device.get(), runtime_data_output_path, network_group_list.value(), + params.hef_path); + } + } +#endif + + return infer_result; +} + Expected use_vdevice(const hailo_vdevice_params ¶ms) { if (params.device_count > 1) { diff --git a/hailort/hailortcli/run_command.hpp b/hailort/hailortcli/run_command.hpp index 806ba05..5eaf834 100644 --- a/hailort/hailortcli/run_command.hpp +++ b/hailort/hailortcli/run_command.hpp @@ -11,6 +11,7 @@ #define _HAILO_RUN_COMMAND_HPP_ #include "hailortcli.hpp" +#include "common.hpp" #include "power_measurement_command.hpp" #include "temp_measurement.hpp" #include "CLI/CLI.hpp" @@ -44,12 +45,10 @@ struct pipeline_stats_measurement_params { std::string pipeline_stats_output_path; }; -static constexpr uint16_t RUNTIME_DATA_IGNORE_BATCH_TO_MEASURE_OPT = std::numeric_limits::max(); -static constexpr uint16_t RUNTIME_DATA_DEFAULT_BATCH_TO_MEASURE_OPT = 2; - struct runtime_data_params { bool collect_runtime_data; std::string runtime_data_output_path; + std::string batch_to_measure_str; uint16_t batch_to_measure; }; @@ -91,6 +90,26 @@ private: inference_runner_params m_params; }; +class UintOrKeywordValidator : public CLI::Validator { +public: + UintOrKeywordValidator(const std::string &keyword) { + name_ = "UINT_OR_KEYWORD"; + func_ = [keyword](const std::string &s) { + if (s == keyword) { + // s is the allowed keyword + return std::string(); // Success + } + + if (CliCommon::is_non_negative_number(s)) { + // s is an int + return std::string(); // Success + } + + return std::string("should be a positive integer or '" + keyword + "'."); + }; + } +}; + class InputNameToFilePairValidator : public CLI::Validator { public: InputNameToFilePairValidator() : CLI::Validator("InputNameToFilePair"), m_first_run(true), m_must_fail(false) { @@ -143,7 +162,7 @@ public: auto batch_size = key_value_pair_str.substr(first_delimiter + 1); auto network_name = key_value_pair_str.substr(0, first_delimiter); // Batch size must be a positive number - if (!is_positive_number(batch_size)) { + if (!CliCommon::is_positive_number(batch_size)) { m_must_fail = true; return std::string("Failed parsing batch size (" + batch_size + ") for network (" + network_name + "). batch should be a positive number."); } @@ -151,13 +170,8 @@ public: }; } -private: - bool is_positive_number(const std::string &s) - { - bool is_number = (!s.empty()) && (std::all_of(s.begin(), s.end(), ::isdigit)); - return is_number && (0 < std::stoi(s)); - } +private: bool m_must_fail; }; diff --git a/hailort/hailortcli/scan_command.cpp b/hailort/hailortcli/scan_command.cpp index aedee0c..74e5d5f 100644 --- a/hailort/hailortcli/scan_command.cpp +++ b/hailort/hailortcli/scan_command.cpp @@ -16,12 +16,6 @@ ScanSubcommand::ScanSubcommand(CLI::App &parent_app) : Command(parent_app.add_subcommand("scan", "Shows all available devices")) { - auto *device_type_option = m_app->add_option("-d,--device-type,--target", "ignored."); - std::vector actions{ - std::make_shared(device_type_option), - }; - hailo_deprecate_options(m_app, actions, false); - // Ethernet options auto *eth_options_group = m_app->add_option_group("Ethernet Device Options"); auto *interface_ip_option = eth_options_group->add_option("--interface-ip", m_interface_ip_addr, diff --git a/hailort/hailortcli/sensor_config_command.cpp b/hailort/hailortcli/sensor_config_command.cpp index 0342edf..37232aa 100644 --- a/hailort/hailortcli/sensor_config_command.cpp +++ b/hailort/hailortcli/sensor_config_command.cpp @@ -157,6 +157,10 @@ SensorDumpConfigSubcommand::SensorDumpConfigSubcommand(CLI::App &parent_app) : hailo_status SensorDumpConfigSubcommand::execute_on_device(Device &device) { + auto status = validate_specific_device_is_given(); + CHECK_SUCCESS(status, + "'sensor-config get-config' command should get a specific device-id."); + return device.sensor_dump_config(m_section_index, m_output_file_path); } diff --git a/hailort/libhailort/CMakeLists.txt b/hailort/libhailort/CMakeLists.txt index 2ef6154..b5aff5a 100644 --- a/hailort/libhailort/CMakeLists.txt +++ b/hailort/libhailort/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.0.0) # set(CMAKE_C_CLANG_TIDY "clang-tidy;-checks=*") set(HAILORT_MAJOR_VERSION 4) -set(HAILORT_MINOR_VERSION 10) +set(HAILORT_MINOR_VERSION 12) set(HAILORT_REVISION_VERSION 0) # Add the cmake folder so the modules there are found @@ -25,6 +25,10 @@ target_include_directories(hef_proto $ ) +if(HAILO_BUILD_PROFILER) + add_definitions( -DHAILO_ENABLE_PROFILER_BUILD ) +endif() + protobuf_generate_cpp(PROTO_SCHEDULER_MON_SRC PROTO_SCHEDULER_MON_HEADR scheduler_mon.proto) add_library(scheduler_mon_proto ${PROTO_SCHEDULER_MON_SRC} ${PROTO_SCHEDULER_MON_HEADR}) target_link_libraries(scheduler_mon_proto libprotobuf-lite) diff --git a/hailort/libhailort/bindings/gstreamer/CMakeLists.txt b/hailort/libhailort/bindings/gstreamer/CMakeLists.txt index e5f782b..b367c43 100644 --- a/hailort/libhailort/bindings/gstreamer/CMakeLists.txt +++ b/hailort/libhailort/bindings/gstreamer/CMakeLists.txt @@ -8,7 +8,7 @@ if(NOT CMAKE_HOST_UNIX) message(FATAL_ERROR "Only unix hosts are supported, stopping build") endif() -find_package(HailoRT 4.10.0 EXACT REQUIRED) +find_package(HailoRT 4.12.0 EXACT REQUIRED) # GST_PLUGIN_DEFINE needs PACKAGE to be defined set(GST_HAILO_PACKAGE_NAME "hailo") @@ -37,7 +37,7 @@ set_target_properties(gsthailo PROPERTIES ) target_compile_options(gsthailo PRIVATE - -Werror -Wall -Wextra -Wconversion -O3 -DNDEBUG # TODO support debug/release builds + -Werror -Wall -Wextra -Wconversion -DVERSION="${GST_HAILO_VERSION}" -DPACKAGE="${GST_HAILO_PACKAGE_NAME}") diff --git a/hailort/libhailort/bindings/gstreamer/README b/hailort/libhailort/bindings/gstreamer/README index 621cf1e..bf85229 100644 --- a/hailort/libhailort/bindings/gstreamer/README +++ b/hailort/libhailort/bindings/gstreamer/README @@ -1,7 +1,7 @@ Compiling the plugin: - cmake -H. -Bbuild - cmake --build build + cmake -H. -Bbuild -DCMAKE_BUILD_TYPE=Release + cmake --build build --config release Using the plugin: The plugin is dependent on libhailort which is included in the `hailort/lib/` directory. - Use LD_LIBRARY_PATH to specify the location of the libhailort library. \ No newline at end of file + Use LD_LIBRARY_PATH to specify the location of the libhailort library. diff --git a/hailort/libhailort/bindings/gstreamer/gst-hailo/common.hpp b/hailort/libhailort/bindings/gstreamer/gst-hailo/common.hpp index ff98230..592125b 100644 --- a/hailort/libhailort/bindings/gstreamer/gst-hailo/common.hpp +++ b/hailort/libhailort/bindings/gstreamer/gst-hailo/common.hpp @@ -48,11 +48,13 @@ using namespace hailort; #define DEFAULT_VDEVICE_KEY (0) #define MIN_VALID_VDEVICE_KEY (1) -#define HAILO_SUPPORTED_FORMATS "{ RGB, RGBA, YUY2 }" +#define HAILO_SUPPORTED_FORMATS "{ RGB, RGBA, YUY2, NV12, NV21 }" #define HAILO_VIDEO_CAPS GST_VIDEO_CAPS_MAKE(HAILO_SUPPORTED_FORMATS) #define HAILO_DEFAULT_SCHEDULER_TIMEOUT_MS (0) -#define HAILO_DEFAULT_SCHEDULER_THRESHOLD (1) +#define HAILO_DEFAULT_SCHEDULER_THRESHOLD (0) + +#define HAILO_DEFAULT_MULTI_PROCESS_SERVICE (false) #define GST_CHECK(cond, ret_val, element, domain, ...) \ do { \ diff --git a/hailort/libhailort/bindings/gstreamer/gst-hailo/gsthailonet.cpp b/hailort/libhailort/bindings/gstreamer/gst-hailo/gsthailonet.cpp index 171a351..c4c0ea8 100644 --- a/hailort/libhailort/bindings/gstreamer/gst-hailo/gsthailonet.cpp +++ b/hailort/libhailort/bindings/gstreamer/gst-hailo/gsthailonet.cpp @@ -79,6 +79,7 @@ enum PROP_SCHEDULING_ALGORITHM, PROP_SCHEDULER_TIMEOUT_MS, PROP_SCHEDULER_THRESHOLD, + PROP_MULTI_PROCESS_SERVICE, }; G_DEFINE_TYPE(GstHailoNet, gst_hailonet, GST_TYPE_BIN); @@ -150,8 +151,8 @@ static void gst_hailonet_class_init(GstHailoNetClass *klass) "Gets values from the enum GstHailoSchedulingAlgorithms. " "Using Model Scheduler algorithm different than HAILO_SCHEDULING_ALGORITHM_NONE, excludes the property 'is-active'. " "When using the same VDevice across multiple hailonets, all should have the same 'scheduling-algorithm'. " - "Currently only supported with 1 device (e.g. device-count=1).", - GST_TYPE_SCHEDULING_ALGORITHM, HAILO_SCHEDULING_ALGORITHM_NONE, + "To run with more than one device, set env variable 'HAILO_ENABLE_MULTI_DEVICE_SCHEDULER' to 1.", + GST_TYPE_SCHEDULING_ALGORITHM, HAILO_SCHEDULING_ALGORITHM_ROUND_ROBIN, (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); g_object_class_install_property(gobject_class, PROP_SCHEDULER_TIMEOUT_MS, g_param_spec_uint("scheduler-timeout-ms", "Timeout for for scheduler in ms", "The maximum time period that may pass before getting run time from the scheduler," @@ -160,7 +161,10 @@ static void gst_hailonet_class_init(GstHailoNetClass *klass) g_object_class_install_property(gobject_class, PROP_SCHEDULER_THRESHOLD, g_param_spec_uint("scheduler-threshold", "Frames threshold for scheduler", "The minimum number of send requests required before the hailonet is considered ready to get run time from the scheduler.", HAILO_DEFAULT_SCHEDULER_THRESHOLD, std::numeric_limits::max(), HAILO_DEFAULT_SCHEDULER_THRESHOLD, (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); - + g_object_class_install_property(gobject_class, PROP_MULTI_PROCESS_SERVICE, + g_param_spec_boolean("multi-process-service", "Should run over HailoRT service", "Controls wether to run HailoRT over its service. " + "To use this property, the service should be active and scheduling-algorithm should be set. Defaults to false.", + HAILO_DEFAULT_MULTI_PROCESS_SERVICE, (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); // See information about the "flush" signal in the element description g_signal_new( "flush", @@ -170,13 +174,19 @@ static void gst_hailonet_class_init(GstHailoNetClass *klass) ); } +std::string create_name(std::string prefix, uint32_t id) +{ + return prefix + std::to_string(id); +} + Expected> HailoNetImpl::create(GstHailoNet *element) { if (nullptr == element) { return make_unexpected(HAILO_INVALID_ARGUMENT); } - GstElement *hailosend = gst_element_factory_make("hailosend", "hailosend"); + auto hailosend_name = create_name("hailosend", HailoNetImpl::m_hailonet_count); + GstElement *hailosend = gst_element_factory_make("hailosend", hailosend_name.c_str()); if (nullptr == hailosend) { GST_ELEMENT_ERROR(element, RESOURCE, FAILED, ("Failed creating hailosend element in bin!"), (NULL)); return make_unexpected(HAILO_INTERNAL_FAILURE); @@ -184,7 +194,8 @@ Expected> HailoNetImpl::create(GstHailoNet *elemen g_object_set(hailosend, "qos", FALSE, NULL); - GstElement *queue = gst_element_factory_make("queue", "hailo_infer_q_0"); + auto hailoqueue_name = create_name("hailoqueue", HailoNetImpl::m_hailonet_count); + GstElement *queue = gst_element_factory_make("queue", hailoqueue_name.c_str()); if (nullptr == queue) { GST_ELEMENT_ERROR(element, RESOURCE, FAILED, ("Failed creating queue element in bin!"), (NULL)); gst_object_unref(hailosend); @@ -192,12 +203,13 @@ Expected> HailoNetImpl::create(GstHailoNet *elemen } // Passing 0 disables the features here - g_object_set(queue, "max-size-time", 0, NULL); - g_object_set(queue, "max-size-bytes", 0, NULL); + g_object_set(queue, "max-size-time", (guint64)0, NULL); + g_object_set(queue, "max-size-bytes", (guint)0, NULL); g_signal_connect(queue, "overrun", G_CALLBACK(gst_hailonet_inner_queue_overrun_callback), nullptr); g_signal_connect(queue, "underrun", G_CALLBACK(gst_hailonet_inner_queue_underrun_callback), nullptr); - GstElement *hailorecv = gst_element_factory_make("hailorecv", "hailorecv"); + auto hailorecv_name = create_name("hailorecv", HailoNetImpl::m_hailonet_count); + GstElement *hailorecv = gst_element_factory_make("hailorecv", hailorecv_name.c_str()); if (nullptr == hailorecv) { GST_ELEMENT_ERROR(element, RESOURCE, FAILED, ("Failed creating hailorecv element in bin!"), (NULL)); gst_object_unref(hailosend); @@ -375,7 +387,7 @@ void HailoNetImpl::set_property(GObject *object, guint property_id, const GValue { gboolean new_is_active = g_value_get_boolean(value); - if (HAILO_SCHEDULING_ALGORITHM_NONE != m_props.m_scheduling_algorithm.get()) { + if (m_props.m_scheduling_algorithm.was_changed() && (HAILO_SCHEDULING_ALGORITHM_NONE != m_props.m_scheduling_algorithm.get())) { g_error("scheduling-algorithm different than HAILO_SCHEDULING_ALGORITHM_NONE in combination with 'is-active' is not supported."); break; } @@ -438,6 +450,13 @@ void HailoNetImpl::set_property(GObject *object, guint property_id, const GValue } m_props.m_scheduler_threshold = g_value_get_uint(value); break; + case PROP_MULTI_PROCESS_SERVICE: + if (m_was_configured) { + g_warning("The network was already configured so changing the multi-process-service property will not take place!"); + break; + } + m_props.m_multi_process_service = g_value_get_boolean(value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); break; @@ -505,6 +524,9 @@ void HailoNetImpl::get_property(GObject *object, guint property_id, GValue *valu case PROP_SCHEDULER_THRESHOLD: g_value_set_uint(value, m_props.m_scheduler_threshold.get()); break; + case PROP_MULTI_PROCESS_SERVICE: + g_value_set_boolean(value, m_props.m_multi_process_service.get()); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); break; @@ -516,12 +538,18 @@ hailo_status HailoNetImpl::set_hef() m_net_group_handle = make_unique_nothrow(GST_ELEMENT(m_element)); GST_CHECK(nullptr != m_net_group_handle, HAILO_OUT_OF_HOST_MEMORY, m_element, RESOURCE, "Failed allocating memory for network handle!"); - hailo_status status = m_net_group_handle->set_hef(m_props.m_device_id.get(), m_props.m_device_count.get(), m_props.m_vdevice_key.get(), - m_props.m_scheduling_algorithm.get(), m_props.m_hef_path.get()); + hailo_status status = m_net_group_handle->set_hef(m_props.m_device_id.get(), m_props.m_device_count.get(), + m_props.m_vdevice_key.get(), m_props.m_scheduling_algorithm.get(), static_cast(m_props.m_multi_process_service.get()), + m_props.m_hef_path.get()); if (HAILO_SUCCESS != status) { return status; } + if (m_props.m_multi_process_service.get()) { + GST_CHECK(m_props.m_scheduling_algorithm.get() != HAILO_SCHEDULING_ALGORITHM_NONE, + HAILO_INVALID_OPERATION, m_element, RESOURCE, "To use multi-process-service please set scheduling-algorithm."); + } + if (nullptr == m_props.m_network_name.get()) { // TODO: HRT-4957 GST_CHECK(m_net_group_handle->hef()->get_network_groups_names().size() == 1, HAILO_INVALID_ARGUMENT, m_element, RESOURCE, @@ -541,7 +569,7 @@ hailo_status HailoNetImpl::set_hef() GST_CHECK(1 == input_vstream_infos->size(), HAILO_INVALID_OPERATION, m_element, RESOURCE, "hailonet element supports only HEFs with one input for now!"); auto input_vstream_info = input_vstream_infos.value()[0]; - GST_HAILOSEND(m_hailosend)->impl->set_input_vstream_infos(std::move(input_vstream_infos.release())); + GST_HAILOSEND(m_hailosend)->impl->set_input_vstream_infos(input_vstream_infos.release()); GST_HAILOSEND(m_hailosend)->impl->set_batch_size(m_props.m_batch_size.get()); GstBufferPool *pool = gst_buffer_pool_new(); @@ -661,7 +689,11 @@ hailo_status HailoNetImpl::abort_streams() return HAILO_SUCCESS; } - return m_net_group_handle->abort_streams(); + auto status = GST_HAILOSEND(m_hailosend)->impl->abort_vstreams(); + GST_CHECK_SUCCESS(status, m_element, RESOURCE, "Failed aborting input VStreams of hailosend, status = %d", status); + status = GST_HAILORECV(m_hailorecv)->impl->abort_vstreams(); + GST_CHECK_SUCCESS(status, m_element, RESOURCE, "Failed aborting output VStreams of hailorecv, status = %d", status); + return HAILO_SUCCESS; } hailo_status HailoNetImpl::deactivate_network_group() @@ -834,13 +866,8 @@ static GstStateChangeReturn gst_hailonet_change_state(GstElement *element, GstSt } case GST_STATE_CHANGE_READY_TO_NULL: { - // VStreams are destructed in hailosend's/hailorecv's GST_STATE_CHANGE_READY_TO_NULL (which calls 'clear_abort' on low-level streams) - // We abort streams again because deactivation of the activated network group calls flush, and it can fail on timeout unless we call abort - hailo_status status = hailonet->abort_streams(); - GST_CHECK(HAILO_SUCCESS == status, GST_STATE_CHANGE_FAILURE, element, RESOURCE, "Aborting streams has failed, status = %d\n", status); - if (HAILO_SCHEDULING_ALGORITHM_NONE == hailonet->get_props().m_scheduling_algorithm.get()) { - status = hailonet->deactivate_network_group(); + auto status = hailonet->deactivate_network_group(); GST_CHECK(HAILO_SUCCESS == status, GST_STATE_CHANGE_FAILURE, element, RESOURCE, "Deactivating network group failed, status = %d\n", status); } diff --git a/hailort/libhailort/bindings/gstreamer/gst-hailo/gsthailonet.hpp b/hailort/libhailort/bindings/gstreamer/gst-hailo/gsthailonet.hpp index 7ff211d..ccb4d4b 100644 --- a/hailort/libhailort/bindings/gstreamer/gst-hailo/gsthailonet.hpp +++ b/hailort/libhailort/bindings/gstreamer/gst-hailo/gsthailonet.hpp @@ -52,8 +52,9 @@ struct HailoNetProperties final { public: HailoNetProperties() : m_device_id(nullptr), m_hef_path(nullptr), m_network_name(nullptr), m_batch_size(HAILO_DEFAULT_BATCH_SIZE), - m_is_active(false), m_device_count(0), m_vdevice_key(DEFAULT_VDEVICE_KEY), m_scheduling_algorithm(HAILO_SCHEDULING_ALGORITHM_NONE), - m_scheduler_timeout_ms(HAILO_DEFAULT_SCHEDULER_TIMEOUT_MS), m_scheduler_threshold(HAILO_DEFAULT_SCHEDULER_THRESHOLD) + m_is_active(false), m_device_count(0), m_vdevice_key(DEFAULT_VDEVICE_KEY), m_scheduling_algorithm(HAILO_SCHEDULING_ALGORITHM_ROUND_ROBIN), + m_scheduler_timeout_ms(HAILO_DEFAULT_SCHEDULER_TIMEOUT_MS), m_scheduler_threshold(HAILO_DEFAULT_SCHEDULER_THRESHOLD), + m_multi_process_service(HAILO_DEFAULT_MULTI_PROCESS_SERVICE) {} HailoElemProperty m_device_id; @@ -66,6 +67,7 @@ public: HailoElemProperty m_scheduling_algorithm; HailoElemProperty m_scheduler_timeout_ms; HailoElemProperty m_scheduler_threshold; + HailoElemProperty m_multi_process_service; }; class HailoNetImpl final diff --git a/hailort/libhailort/bindings/gstreamer/gst-hailo/gsthailorecv.cpp b/hailort/libhailort/bindings/gstreamer/gst-hailo/gsthailorecv.cpp index 9c6835c..5a0624b 100644 --- a/hailort/libhailort/bindings/gstreamer/gst-hailo/gsthailorecv.cpp +++ b/hailort/libhailort/bindings/gstreamer/gst-hailo/gsthailorecv.cpp @@ -308,6 +308,15 @@ hailo_status HailoRecvImpl::clear_vstreams() return OutputVStream::clear(m_output_vstreams); } +hailo_status HailoRecvImpl::abort_vstreams() +{ + for (auto& output_vstream : m_output_vstreams) { + auto status = output_vstream.abort(); + GST_CHECK_SUCCESS(status, m_element, STREAM, "Failed aborting output vstream %s, status = %d", output_vstream.name().c_str(), status); + } + return HAILO_SUCCESS; +} + static void gst_hailorecv_init(GstHailoRecv *self) { auto hailorecv_impl = HailoRecvImpl::create(self); @@ -343,6 +352,8 @@ static GstStateChangeReturn gst_hailorecv_change_state(GstElement *element, GstS } if (GST_STATE_CHANGE_READY_TO_NULL == transition) { + auto status = GST_HAILORECV(element)->impl->abort_vstreams(); + GST_CHECK(HAILO_SUCCESS == status, GST_STATE_CHANGE_FAILURE, element, STREAM, "Aborting output vstreams failed, status = %d\n", status); // Cleanup all of hailorecv memory GST_HAILORECV(element)->impl.reset(); } diff --git a/hailort/libhailort/bindings/gstreamer/gst-hailo/gsthailorecv.hpp b/hailort/libhailort/bindings/gstreamer/gst-hailo/gsthailorecv.hpp index 892610a..56e0b96 100644 --- a/hailort/libhailort/bindings/gstreamer/gst-hailo/gsthailorecv.hpp +++ b/hailort/libhailort/bindings/gstreamer/gst-hailo/gsthailorecv.hpp @@ -92,6 +92,7 @@ public: GstFlowReturn handle_frame(GstVideoFilter *filter, GstVideoFrame *frame); hailo_status set_output_vstreams(std::vector &&output_vstreams, uint32_t batch_size); hailo_status clear_vstreams(); + hailo_status abort_vstreams(); private: hailo_status read_from_vstreams(bool should_print_latency); diff --git a/hailort/libhailort/bindings/gstreamer/gst-hailo/gsthailosend.cpp b/hailort/libhailort/bindings/gstreamer/gst-hailo/gsthailosend.cpp index cebeee1..19568e0 100644 --- a/hailort/libhailort/bindings/gstreamer/gst-hailo/gsthailosend.cpp +++ b/hailort/libhailort/bindings/gstreamer/gst-hailo/gsthailosend.cpp @@ -176,6 +176,19 @@ hailo_status HailoSendImpl::write_to_vstreams(void *buf, size_t size) return HAILO_SUCCESS; } +uint32_t get_height_by_order(const hailo_vstream_info_t &input_vstream_info) +{ + auto original_height = input_vstream_info.shape.height; + switch (input_vstream_info.format.order) { + case HAILO_FORMAT_ORDER_NV12: + case HAILO_FORMAT_ORDER_NV21: + return original_height * 2; + default: + break; + } + return original_height; +} + GstCaps *HailoSendImpl::get_caps(GstBaseTransform */*trans*/, GstPadDirection /*direction*/, GstCaps *caps, GstCaps */*filter*/) { GST_DEBUG_OBJECT(m_element, "transform_caps"); @@ -192,6 +205,7 @@ GstCaps *HailoSendImpl::get_caps(GstBaseTransform */*trans*/, GstPadDirection /* const gchar *format = nullptr; switch (m_input_vstream_infos[0].format.order) { + case HAILO_FORMAT_ORDER_RGB4: case HAILO_FORMAT_ORDER_NHWC: if (m_input_vstream_infos[0].shape.features == RGBA_FEATURES_SIZE) { format = "RGBA"; @@ -232,10 +246,10 @@ GstCaps *HailoSendImpl::get_caps(GstBaseTransform */*trans*/, GstPadDirection /* /* filter against set allowed caps on the pad */ GstCaps *new_caps = gst_caps_new_simple("video/x-raw", - "format", G_TYPE_STRING, format, - "width", G_TYPE_INT, m_input_vstream_infos[0].shape.width, - "height", G_TYPE_INT, m_input_vstream_infos[0].shape.height, - NULL); + "format", G_TYPE_STRING, format, + "width", G_TYPE_INT, m_input_vstream_infos[0].shape.width, + "height", G_TYPE_INT, get_height_by_order(m_input_vstream_infos[0]), + NULL); return gst_caps_intersect(caps, new_caps); } @@ -254,6 +268,15 @@ hailo_status HailoSendImpl::clear_vstreams() return InputVStream::clear(m_input_vstreams); } +hailo_status HailoSendImpl::abort_vstreams() +{ + for (auto& input_vstream : m_input_vstreams) { + auto status = input_vstream.abort(); + GST_CHECK_SUCCESS(status, m_element, STREAM, "Failed aborting input vstream %s, status = %d", input_vstream.name().c_str(), status); + } + return HAILO_SUCCESS; +} + static void gst_hailosend_init(GstHailoSend *self) { auto hailosend_impl = HailoSendImpl::create(self); @@ -303,6 +326,8 @@ static GstStateChangeReturn gst_hailosend_change_state(GstElement *element, GstS } if (GST_STATE_CHANGE_READY_TO_NULL == transition) { + auto status = GST_HAILOSEND(element)->impl->abort_vstreams(); + GST_CHECK(HAILO_SUCCESS == status, GST_STATE_CHANGE_FAILURE, element, STREAM, "Aborting input vstreams failed, status = %d\n", status); // Cleanup all of hailosend memory GST_HAILOSEND(element)->impl.reset(); } diff --git a/hailort/libhailort/bindings/gstreamer/gst-hailo/gsthailosend.hpp b/hailort/libhailort/bindings/gstreamer/gst-hailo/gsthailosend.hpp index 3e2167a..5ea816b 100644 --- a/hailort/libhailort/bindings/gstreamer/gst-hailo/gsthailosend.hpp +++ b/hailort/libhailort/bindings/gstreamer/gst-hailo/gsthailosend.hpp @@ -71,6 +71,7 @@ public: void set_input_vstream_infos(std::vector &&input_vstream_infos); void set_input_vstreams(std::vector &&input_vstreams); hailo_status clear_vstreams(); + hailo_status abort_vstreams(); void set_batch_size(uint32_t batch_size) { diff --git a/hailort/libhailort/bindings/gstreamer/gst-hailo/network_group_handle.cpp b/hailort/libhailort/bindings/gstreamer/gst-hailo/network_group_handle.cpp index 9808c59..7a04149 100644 --- a/hailort/libhailort/bindings/gstreamer/gst-hailo/network_group_handle.cpp +++ b/hailort/libhailort/bindings/gstreamer/gst-hailo/network_group_handle.cpp @@ -28,7 +28,7 @@ NetworkGroupActivationManager NetworkGroupHandle::m_net_group_activation_manager Expected> create_shared_vdevice(const void *element, const std::string &device_id, - uint32_t vdevice_key, hailo_scheduling_algorithm_t scheduling_algorithm) + uint32_t vdevice_key, hailo_scheduling_algorithm_t scheduling_algorithm, bool multi_process_service) { // If passing device_id, than device_count must be 1 const auto device_count = 1; @@ -43,6 +43,7 @@ Expected> create_shared_vdevice(const void *element, co params.device_count = device_count; params.device_ids = &(device_id_expected.value()); params.scheduling_algorithm = scheduling_algorithm; + params.multi_process_service = multi_process_service; if (vdevice_key == DEFAULT_VDEVICE_KEY) { params.group_id = HAILO_UNIQUE_VDEVICE_GROUP_ID; } else { @@ -51,12 +52,12 @@ Expected> create_shared_vdevice(const void *element, co } auto vdevice = VDevice::create(params); GST_CHECK_EXPECTED(vdevice, element, RESOURCE, "Failed creating vdevice, status = %d", vdevice.status()); - std::shared_ptr vdevice_ptr = std::move(vdevice.release()); + std::shared_ptr vdevice_ptr = vdevice.release(); return vdevice_ptr; } Expected> create_shared_vdevice(const void *element, uint16_t device_count, uint32_t vdevice_key, - hailo_scheduling_algorithm_t scheduling_algorithm) + hailo_scheduling_algorithm_t scheduling_algorithm, bool multi_process_service) { auto device_id = std::to_string(vdevice_key); hailo_vdevice_params_t params = {}; @@ -65,14 +66,15 @@ Expected> create_shared_vdevice(const void *element, ui params.device_count = device_count; params.scheduling_algorithm = scheduling_algorithm; params.group_id = device_id.c_str(); + params.multi_process_service = multi_process_service; auto vdevice = VDevice::create(params); GST_CHECK_EXPECTED(vdevice, element, RESOURCE, "Failed creating vdevice, status = %d", vdevice.status()); - std::shared_ptr vdevice_ptr = std::move(vdevice.release()); + std::shared_ptr vdevice_ptr = vdevice.release(); return vdevice_ptr; } Expected> create_unique_vdevice(const void *element, uint16_t device_count, - hailo_scheduling_algorithm_t scheduling_algorithm) + hailo_scheduling_algorithm_t scheduling_algorithm, bool multi_process_service) { hailo_vdevice_params_t params = {}; auto status = hailo_init_vdevice_params(¶ms); @@ -81,43 +83,44 @@ Expected> create_unique_vdevice(const void *element, ui params.device_count = device_count; params.scheduling_algorithm = scheduling_algorithm; params.group_id = HAILO_UNIQUE_VDEVICE_GROUP_ID; + params.multi_process_service = multi_process_service; auto vdevice = VDevice::create(params); GST_CHECK_EXPECTED(vdevice, element, RESOURCE, "Failed creating vdevice, status = %d", vdevice.status()); - std::shared_ptr vdevice_ptr = std::move(vdevice.release()); + std::shared_ptr vdevice_ptr = vdevice.release(); return vdevice_ptr; } Expected> NetworkGroupHandle::create_vdevice(const void *element, const std::string &device_id, uint16_t device_count, - uint32_t vdevice_key, hailo_scheduling_algorithm_t scheduling_algorithm) + uint32_t vdevice_key, hailo_scheduling_algorithm_t scheduling_algorithm, bool multi_process_service) { if (!device_id.empty()) { - auto result = create_shared_vdevice(element, device_id, vdevice_key, scheduling_algorithm); + auto result = create_shared_vdevice(element, device_id, vdevice_key, scheduling_algorithm, multi_process_service); GST_CHECK_EXPECTED(result, element, RESOURCE, "Failed creating vdevice, status = %d", result.status()); m_vdevices.insert(result.value()); return result; } if (DEFAULT_VDEVICE_KEY != vdevice_key) { - auto result = create_shared_vdevice(element, device_count, vdevice_key, scheduling_algorithm); + auto result = create_shared_vdevice(element, device_count, vdevice_key, scheduling_algorithm, multi_process_service); GST_CHECK_EXPECTED(result, element, RESOURCE, "Failed creating vdevice, status = %d", result.status()); m_vdevices.insert(result.value()); return result; } - auto result = create_unique_vdevice(element, device_count, scheduling_algorithm); + auto result = create_unique_vdevice(element, device_count, scheduling_algorithm, multi_process_service); GST_CHECK_EXPECTED(result, element, RESOURCE, "Failed creating vdevice, status = %d", result.status()); m_vdevices.insert(result.value()); return result; } Expected> NetworkGroupHandle::create_vdevice(const std::string &device_id, uint16_t device_count, uint32_t vdevice_key, - hailo_scheduling_algorithm_t scheduling_algorithm) + hailo_scheduling_algorithm_t scheduling_algorithm, bool multi_process_service) { - auto expected_device = create_vdevice(m_element, device_id, device_count, vdevice_key, scheduling_algorithm); + auto expected_device = create_vdevice(m_element, device_id, device_count, vdevice_key, scheduling_algorithm, multi_process_service); GST_CHECK_EXPECTED(expected_device, m_element, RESOURCE, "Failed creating vdevice, status = %d", expected_device.status()); return expected_device; } hailo_status NetworkGroupHandle::set_hef(const char *device_id, uint16_t device_count, uint32_t vdevice_key, - hailo_scheduling_algorithm_t scheduling_algorithm, const char *hef_path) + hailo_scheduling_algorithm_t scheduling_algorithm, bool multi_process_service, const char *hef_path) { if (0 == device_count) { device_count = HAILO_DEFAULT_DEVICE_COUNT; @@ -125,7 +128,7 @@ hailo_status NetworkGroupHandle::set_hef(const char *device_id, uint16_t device_ std::string device_id_str = (nullptr == device_id) ? "" : device_id; - auto vdevice = create_vdevice(device_id_str, device_count, vdevice_key, scheduling_algorithm); + auto vdevice = create_vdevice(device_id_str, device_count, vdevice_key, scheduling_algorithm, multi_process_service); GST_CHECK_EXPECTED_AS_STATUS(vdevice, m_element, RESOURCE, "Failed creating vdevice, status = %d", vdevice.status()); m_vdevice = vdevice.release(); @@ -141,7 +144,7 @@ hailo_status NetworkGroupHandle::set_hef(const char *device_id, uint16_t device_ auto hef = Hef::create(hef_path); GST_CHECK_EXPECTED_AS_STATUS(hef, m_element, RESOURCE, "Failed reading hef file %s, status = %d", hef_path, hef.status()); - m_hef = make_shared_nothrow(std::move(hef.release())); + m_hef = make_shared_nothrow(hef.release()); GST_CHECK(nullptr != m_hef, HAILO_OUT_OF_HOST_MEMORY, m_element, RESOURCE, "Allocating memory for HEF has failed!"); return HAILO_SUCCESS; @@ -149,7 +152,7 @@ hailo_status NetworkGroupHandle::set_hef(const char *device_id, uint16_t device_ hailo_status NetworkGroupHandle::configure_network_group(const char *net_group_name, hailo_scheduling_algorithm_t scheduling_algorithm, uint16_t batch_size) { - auto net_groups_params_map = get_configure_params(*m_hef, net_group_name, batch_size); + auto net_groups_params_map = get_configure_params(*m_hef, *m_vdevice, net_group_name, batch_size); GST_CHECK_EXPECTED_AS_STATUS(net_groups_params_map, m_element, RESOURCE, "Failed getting configure params, status = %d", net_groups_params_map.status()); auto expected_cng = m_net_group_config_manager.configure_network_group(m_element, m_shared_device_id, scheduling_algorithm, @@ -185,12 +188,27 @@ Expected, std::vector>> Netwo "Inserting network name to configured networks has failed, status = %d", status); } - auto input_params_map = m_cng->make_input_vstream_params(true, HAILO_FORMAT_TYPE_AUTO, HAILO_DEFAULT_VSTREAM_TIMEOUT_MS, + auto expected_input_vstream_infos = hef()->get_input_vstream_infos(network_name); + GST_CHECK_EXPECTED(expected_input_vstream_infos, m_element, RESOURCE, "Failed getting input vstream infos, status = %d", + expected_input_vstream_infos.status()); + auto expected_input_params_map = m_cng->make_input_vstream_params(true, HAILO_FORMAT_TYPE_AUTO, HAILO_DEFAULT_VSTREAM_TIMEOUT_MS, HAILO_DEFAULT_VSTREAM_QUEUE_SIZE, m_network_name); - GST_CHECK_EXPECTED(input_params_map, m_element, RESOURCE, "Failed making input vstream params, status = %d", - input_params_map.status()); + GST_CHECK_EXPECTED(expected_input_params_map, m_element, RESOURCE, "Failed making input vstream params, status = %d", + expected_input_params_map.status()); + + // In RGB formats, Gstreamer is padding each row to 4. + auto &&input_params_map = expected_input_params_map.release(); + auto &&input_infos = expected_input_vstream_infos.release(); + for (auto &input_info : input_infos) { + if (input_params_map.count(input_info.name)) { + auto &input_params = input_params_map[input_info.name]; + if (input_info.format.order == HAILO_FORMAT_ORDER_NHWC) { + input_params.user_buffer_format.order = HAILO_FORMAT_ORDER_RGB4; + } + } + } - auto input_vstreams = VStreamsBuilder::create_input_vstreams(*m_cng, input_params_map.release()); + auto input_vstreams = VStreamsBuilder::create_input_vstreams(*m_cng, input_params_map); GST_CHECK_EXPECTED(input_vstreams, m_element, RESOURCE, "Failed creating input vstreams, status = %d", input_vstreams.status()); // TODO: HRT-4095 @@ -220,17 +238,22 @@ Expected, std::vector>> Netwo GST_CHECK_EXPECTED(output_vstreams, m_element, RESOURCE, "Failed creating output vstreams, status = %d", output_vstreams.status()); return std::pair, std::vector>( - std::move(input_vstreams.release()), std::move(output_vstreams.release())); + input_vstreams.release(), output_vstreams.release()); } -Expected NetworkGroupHandle::get_configure_params(Hef &hef, const char *net_group_name, uint16_t batch_size) +Expected NetworkGroupHandle::get_configure_params(Hef &hef, const VDevice &vdevice, + const char *net_group_name, uint16_t batch_size) { - auto params = hef.create_configure_params(HAILO_STREAM_INTERFACE_PCIE, net_group_name); + auto stream_interface = vdevice.get_default_streams_interface(); + GST_CHECK_EXPECTED(stream_interface, m_element, RESOURCE, + "Failed default stream interface configure params, status = %d", stream_interface.status()); + + auto params = hef.create_configure_params(*stream_interface, net_group_name); GST_CHECK_EXPECTED(params, m_element, RESOURCE, "Failed creating configure params, status = %d", params.status()); params->batch_size = batch_size; NetworkGroupsParamsMap net_groups_params_map; - net_groups_params_map[net_group_name] = std::move(params.release()); + net_groups_params_map[net_group_name] = params.release(); return net_groups_params_map; } @@ -243,39 +266,6 @@ hailo_status NetworkGroupHandle::activate_network_group() return HAILO_SUCCESS; } -hailo_status NetworkGroupHandle::abort_streams() -{ - if (nullptr == m_cng) { - return HAILO_SUCCESS; - } - - hailo_status final_status = HAILO_SUCCESS; - auto input_streams = m_cng->get_input_streams_by_network(m_network_name); - GST_CHECK_EXPECTED_AS_STATUS(input_streams, m_element, RESOURCE, "Getting input streams by network name %s failed, status = %d", - m_network_name.c_str(), input_streams.status()); - - for (auto &input_stream : input_streams.value()) { - hailo_status status = input_stream.get().abort(); - if (HAILO_SUCCESS != status) { - g_warning("Abort of input stream %s has failed, status = %d", input_stream.get().name().c_str(), status); - final_status = status; - } - } - - auto output_streams = m_cng->get_output_streams_by_network(m_network_name); - GST_CHECK_EXPECTED_AS_STATUS(output_streams, m_element, RESOURCE, "Getting output streams by network name %s failed, status = %d", - m_network_name.c_str(), output_streams.status()); - - for (auto &output_stream : output_streams.value()) { - hailo_status status = output_stream.get().abort(); - if (HAILO_SUCCESS != status) { - g_warning("Abort of output stream %s has failed, status = %d", output_stream.get().name().c_str(), status); - final_status = status; - } - } - return final_status; -} - Expected NetworkGroupHandle::remove_network_group() { bool was_network_deactivated = false; @@ -407,7 +397,7 @@ Expected> NetworkGroupActivationManager:: GST_CHECK_EXPECTED(activated_network_group, element, RESOURCE, "Failed activating network group, status = %d", activated_network_group.status()); - std::shared_ptr ang = std::move(activated_network_group.release()); + std::shared_ptr ang = activated_network_group.release(); m_activated_net_groups[NetworkGroupConfigManager::get_configure_string(device_id, hef_hash, net_group_name, batch_size)] = ang; return ang; diff --git a/hailort/libhailort/bindings/gstreamer/gst-hailo/network_group_handle.hpp b/hailort/libhailort/bindings/gstreamer/gst-hailo/network_group_handle.hpp index 93f86b1..246118f 100644 --- a/hailort/libhailort/bindings/gstreamer/gst-hailo/network_group_handle.hpp +++ b/hailort/libhailort/bindings/gstreamer/gst-hailo/network_group_handle.hpp @@ -80,12 +80,11 @@ public: m_vdevice(nullptr), m_hef(nullptr), m_cng(nullptr), m_ang(nullptr) {} hailo_status set_hef(const char *device_id, uint16_t device_count, uint32_t vdevice_key, hailo_scheduling_algorithm_t scheduling_algorithm, - const char *hef_path); + bool multi_process_service, const char *hef_path); hailo_status configure_network_group(const char *net_group_name, hailo_scheduling_algorithm_t scheduling_algorithm, uint16_t batch_size); Expected, std::vector>> create_vstreams(const char *network_name, hailo_scheduling_algorithm_t scheduling_algorithm, const std::vector &output_formats); hailo_status activate_network_group(); - hailo_status abort_streams(); Expected remove_network_group(); hailo_status set_scheduler_timeout(const char *network_name, uint32_t timeout_ms); @@ -98,11 +97,12 @@ public: } private: - Expected get_configure_params(Hef &hef, const char *net_group_name, uint16_t batch_size); + Expected get_configure_params(Hef &hef, const VDevice &vdevice, const char *net_group_name, + uint16_t batch_size); static Expected> create_vdevice(const void *element, const std::string &device_id, uint16_t device_count, - uint32_t vdevice_key, hailo_scheduling_algorithm_t scheduling_algorithm); + uint32_t vdevice_key, hailo_scheduling_algorithm_t scheduling_algorithm, bool multi_process_service); Expected> create_vdevice(const std::string &device_id, uint16_t device_count, uint32_t vdevice_key, - hailo_scheduling_algorithm_t scheduling_algorithm); + hailo_scheduling_algorithm_t scheduling_algorithm, bool multi_process_service); static std::unordered_set> m_vdevices; static NetworkGroupConfigManager m_net_group_config_manager; diff --git a/hailort/libhailort/bindings/python/CMakeLists.txt b/hailort/libhailort/bindings/python/CMakeLists.txt index d38c6e8..febd4f0 100644 --- a/hailort/libhailort/bindings/python/CMakeLists.txt +++ b/hailort/libhailort/bindings/python/CMakeLists.txt @@ -1,9 +1 @@ add_subdirectory(src) - -# copy files to venv -if(HAILO_BUILD_PYHAILORT_VENV) - add_custom_target(pyhailort_venv ALL - COMMAND ${CMAKE_COMMAND} -E copy $ ${CMAKE_CURRENT_LIST_DIR}/platform/hailo_platform/pyhailort/ - ) - add_dependencies(pyhailort_venv _pyhailort) -endif() \ No newline at end of file diff --git a/hailort/libhailort/bindings/python/examples/hef_infer_pipeline_vstream.py b/hailort/libhailort/bindings/python/examples/hef_infer_pipeline_vstream.py index c5bfbeb..2eea36c 100644 --- a/hailort/libhailort/bindings/python/examples/hef_infer_pipeline_vstream.py +++ b/hailort/libhailort/bindings/python/examples/hef_infer_pipeline_vstream.py @@ -1,4 +1,4 @@ -from hailo_platform import (HEF, PcieDevice, ConfigureParams, InferVStreams, InputVStreamParams, +from hailo_platform import (HEF, VDevice, ConfigureParams, InferVStreams, InputVStreamParams, OutputVStreamParams, FormatType) from hailo_platform.pyhailort.pyhailort import HailoStreamInterface import numpy as np @@ -12,7 +12,7 @@ def parse_args(): def main(): args = parse_args() - with PcieDevice() as target: + with VDevice() as target: hef = HEF(args.hef_path) configure_params = ConfigureParams.create_from_hef(hef, interface=HailoStreamInterface.PCIe) network_groups = target.configure(hef, configure_params) @@ -26,7 +26,7 @@ def main(): with network_group.activate(network_group_params): _ = infer_pipeline.infer(input_data) fps = args.num_frames / infer_pipeline.get_hw_time() - + print('Inference ran successfully') print(f'FPS: {fps}') diff --git a/hailort/libhailort/bindings/python/examples/hef_infer_virtual_stream.py b/hailort/libhailort/bindings/python/examples/hef_infer_virtual_stream.py index a447f39..f9dd2b6 100644 --- a/hailort/libhailort/bindings/python/examples/hef_infer_virtual_stream.py +++ b/hailort/libhailort/bindings/python/examples/hef_infer_virtual_stream.py @@ -1,8 +1,9 @@ import argparse -from multiprocessing import Process - +import time import numpy as np -from hailo_platform import (HEF, PcieDevice, HailoStreamInterface, ConfigureParams, InputVStreamParams, InputVStreams, + +from multiprocessing import Process +from hailo_platform import (HEF, VDevice, HailoStreamInterface, ConfigureParams, InputVStreamParams, InputVStreams, OutputVStreamParams, OutputVStreams) def send(configured_network, num_frames): @@ -45,17 +46,24 @@ def main(): args = parse_args() hef = HEF(args.hef_path) - with PcieDevice() as device: + with VDevice() as device: configure_params = ConfigureParams.create_from_hef(hef, interface=HailoStreamInterface.PCIe) network_group = device.configure(hef, configure_params)[0] network_group_params = network_group.create_params() send_process = Process(target=send, args=(network_group, args.num_frames)) recv_process = Process(target=recv_all, args=(network_group, args.num_frames)) + + time_before = time.time() recv_process.start() send_process.start() with network_group.activate(network_group_params): send_process.join() recv_process.join() + fps = args.num_frames / (time.time() - time_before) + + print('Inference ran successfully') + print(f'FPS: {fps}') + if __name__ == '__main__': main() diff --git a/hailort/libhailort/bindings/python/platform/hailo_platform/__init__.py b/hailort/libhailort/bindings/python/platform/hailo_platform/__init__.py index 4e84909..b307e7d 100644 --- a/hailort/libhailort/bindings/python/platform/hailo_platform/__init__.py +++ b/hailort/libhailort/bindings/python/platform/hailo_platform/__init__.py @@ -17,16 +17,16 @@ def join_drivers_path(path): from hailo_platform.tools.udp_rate_limiter import UDPRateLimiter from hailo_platform.pyhailort.hw_object import PcieDevice, EthernetDevice from hailo_platform.pyhailort.pyhailort import (HEF, ConfigureParams, - FormatType, FormatOrder, - MipiDataTypeRx, MipiPixelsPerClock, - MipiClockSelection, MipiIspImageInOrder, - MipiIspImageOutDataType, IspLightFrequency, HailoPowerMode, - Endianness, HailoStreamInterface, - InputVStreamParams, OutputVStreamParams, - InputVStreams, OutputVStreams, - InferVStreams, HailoStreamDirection, HailoFormatFlags, HailoCpuId, Device, VDevice, - DvmTypes, PowerMeasurementTypes, SamplingPeriod, AveragingFactor, MeasurementBufferIndex, - HailoRTException) + FormatType, FormatOrder, + MipiDataTypeRx, MipiPixelsPerClock, + MipiClockSelection, MipiIspImageInOrder, + MipiIspImageOutDataType, IspLightFrequency, HailoPowerMode, + Endianness, HailoStreamInterface, + InputVStreamParams, OutputVStreamParams, + InputVStreams, OutputVStreams, + InferVStreams, HailoStreamDirection, HailoFormatFlags, HailoCpuId, Device, VDevice, + DvmTypes, PowerMeasurementTypes, SamplingPeriod, AveragingFactor, MeasurementBufferIndex, + HailoRTException, YOLOv5PostProcessingOp) def _verify_pyhailort_lib_exists(): python_version = "".join(str(i) for i in sys.version_info[:2]) @@ -62,4 +62,4 @@ __all__ = ['EthernetDevice', 'DvmTypes', 'PowerMeasurementTypes', 'MipiIspImageInOrder', 'MipiIspImageOutDataType', 'join_drivers_path', 'IspLightFrequency', 'HailoPowerMode', 'Endianness', 'HailoStreamInterface', 'InputVStreamParams', 'OutputVStreamParams', 'InputVStreams', 'OutputVStreams', 'InferVStreams', 'HailoStreamDirection', 'HailoFormatFlags', 'HailoCpuId', - 'Device', 'VDevice', 'HailoRTException'] + 'Device', 'VDevice', 'HailoRTException', 'YOLOv5PostProcessingOp'] diff --git a/hailort/libhailort/bindings/python/platform/hailo_platform/pyhailort/hw_object.py b/hailort/libhailort/bindings/python/platform/hailo_platform/pyhailort/hw_object.py index e0a389a..5871dca 100644 --- a/hailort/libhailort/bindings/python/platform/hailo_platform/pyhailort/hw_object.py +++ b/hailort/libhailort/bindings/python/platform/hailo_platform/pyhailort/hw_object.py @@ -50,17 +50,19 @@ class HailoHWObject(object): @property def name(self): """str: The name of this target. Valid values are defined by :class:`~hailo_platform.pyhailort.hw_object.InferenceTargets`""" + # self._logger.warning("HailoHWObject name property is deprecated! Please use VDevice object with device_id.") return type(self).NAME @property def is_hardware(self): """bool: Indicates this target runs on a physical hardware device.""" + # TODO: SDK should implement in Target + # self._logger.warning("HailoHWObject is_hardware property is deprecated! Please use VDevice object, or derive from it.") return type(self).IS_HARDWARE @property def device_id(self): """Getter for the device_id. - Returns: str: A string ID of the device. BDF for PCIe devices, IP address for Ethernet devices, "Core" for core devices. """ @@ -72,12 +74,14 @@ class HailoHWObject(object): Returns: list of str: Sorted list of the output layer names. """ + # self._logger.warning("HailoHWObject sorted_output_layer_names property is deprecated! Please use ConfiguredNetwork get_sorted_output_names.") if len(self._loaded_network_groups) != 1: raise HailoHWObjectException("Access to sorted_output_layer_names is only allowed when there is a single loaded network group") return self._loaded_network_groups[0].get_sorted_output_names() @contextmanager def use_device(self, *args, **kwargs): + # self._logger.warning("HailoHWObject use_device context manager is deprecated! Please use VDevice object.") """A context manager that wraps the usage of the device (deprecated).""" self._is_device_used = True yield @@ -89,6 +93,7 @@ class HailoHWObject(object): Returns: dict: Keys are device output names and values are lists of layers' names. """ + # self._logger.warning("HailoHWObject get_output_device_layer_to_original_layer_map function is deprecated!") if len(self._loaded_network_groups) != 1: raise HailoHWObjectException("Access to layer names is only allowed when there is a single loaded network group") return {stream_info.name : self._loaded_network_groups[0].get_vstream_names_from_stream_name(stream_info.name) @@ -100,6 +105,7 @@ class HailoHWObject(object): Returns: dict: Keys are the names of the layers and values are device outputs names. """ + # self._logger.warning("HailoHWObject get_original_layer_to_device_layer_map function is deprecated!") if len(self._loaded_network_groups) != 1: raise HailoHWObjectException("Access to layer names is only allowed when there is a single loaded network group") return {vstream_info.name : self._loaded_network_groups[0].get_stream_names_from_vstream_name(vstream_info.name) @@ -108,24 +114,31 @@ class HailoHWObject(object): @property def device_input_layers(self): """Get a list of the names of the device's inputs.""" + # self._logger.warning("HailoHWObject device_input_layers function is deprecated! Please use ConfiguredNetwork object.") return [layer.name for layer in self.get_input_stream_infos()] @property def device_output_layers(self): """Get a list of the names of the device's outputs.""" + # self._logger.warning("HailoHWObject device_output_layers function is deprecated! Please use ConfiguredNetwork object.") return [layer.name for layer in self.get_output_stream_infos()] def hef_loaded(self): """Return True if this object has loaded the model HEF to the hardware device.""" + # TODO: SDK should implement in Target + # self._logger.warning("HailoHWObject hef_loaded function is deprecated! Please use VDevice object, or derive from it.") return self._hef_loaded def outputs_count(self): """Return the amount of output tensors that are returned from the hardware device for every input image. """ + # self._logger.warning("HailoHWObject outputs_count function is deprecated! Please use ConfiguredNetwork object.") return len(self.get_output_vstream_infos()) def _clear_shapes(self): + # TODO: SDK should implement in Target + # self._logger.warning("HailoHWObject _clear_shapes function is deprecated! Please use ConfiguredNetwork object.") self._hw_consts = None @property @@ -135,6 +148,7 @@ class HailoHWObject(object): Returns: str: Model name. """ + # self._logger.warning("HailoHWObject model_name property is deprecated! Please use ConfiguredNetwork object.") if len(self._loaded_network_groups) == 1: return self._loaded_network_groups[0].name raise HailoHWObjectException( @@ -146,6 +160,7 @@ class HailoHWObject(object): Returns: Tuple of output shapes, sorted by the output names. """ + # self._logger.warning("HailoHWObject get_output_shapes function is deprecated! Please use ConfiguredNetwork object.") if len(self._loaded_network_groups) != 1: raise HailoHWObjectException("Calling get_output_shapes is only allowed when there is a single loaded network group") return self._loaded_network_groups[0].get_output_shapes() @@ -166,7 +181,6 @@ class HailoChipObject(HailoHWObject): def control(self): """:class:`HailoControl `: Returns the control object of this device, which implements the control API of the Hailo device. - .. attention:: Use the low level control API with care. """ if self._control_object is None: @@ -181,6 +195,7 @@ class HailoChipObject(HailoHWObject): Returns: dict of :obj:'numpy.dtype': where the key is model input_layer name, and the value is dtype as the device expect to get for this input. """ + # self._logger.warning("HailoChipObject get_all_input_layers_dtype function is deprecated! Please use ConfiguredNetwork object.") return {stream.name: HailoRTTransformUtils.get_dtype(stream.data_bytes) for stream in self.get_input_stream_infos()} def get_input_vstream_infos(self, network_name=None): @@ -193,7 +208,7 @@ class HailoChipObject(HailoHWObject): If there is exactly one configured network group, returns a list of :obj:`hailo_platform.pyhailort._pyhailort.VStreamInfo`: with all the information objects of all input vstreams """ - + # self._logger.warning("HailoChipObject get_input_vstream_infos function is deprecated! Please use ConfiguredNetwork object.") if len(self._loaded_network_groups) != 1: raise HailoHWObjectException("Access to network vstream info is only allowed when there is a single loaded network group") return self._loaded_network_groups[0].get_input_vstream_infos(network_name=network_name) @@ -208,7 +223,7 @@ class HailoChipObject(HailoHWObject): If there is exactly one configured network group, returns a list of :obj:`hailo_platform.pyhailort._pyhailort.VStreamInfo`: with all the information objects of all output vstreams """ - + # self._logger.warning("HailoChipObject get_output_vstream_infos function is deprecated! Please use ConfiguredNetwork object.") if len(self._loaded_network_groups) != 1: raise HailoHWObjectException("Access to network vstream info is only allowed when there is a single loaded network group") return self._loaded_network_groups[0].get_output_vstream_infos(network_name=network_name) @@ -223,7 +238,7 @@ class HailoChipObject(HailoHWObject): If there is exactly one configured network group, returns a list of :obj:`hailo_platform.pyhailort._pyhailort.VStreamInfo`: with all the information objects of all input and output vstreams """ - + # self._logger.warning("HailoChipObject get_all_vstream_infos function is deprecated! Please use ConfiguredNetwork object.") if len(self._loaded_network_groups) != 1: raise HailoHWObjectException("Access to network vstream info is only allowed when there is a single loaded network group") return self._loaded_network_groups[0].get_all_vstream_infos(network_name=network_name) @@ -239,6 +254,7 @@ class HailoChipObject(HailoHWObject): :obj:`hailo_platform.pyhailort._pyhailort.VStreamInfo`: with information objects of all input low-level streams. """ + # self._logger.warning("HailoChipObject get_input_stream_infos function is deprecated! Please use ConfiguredNetwork object.") if len(self._loaded_network_groups) != 1: raise HailoHWObjectException("Access to network stream info is only allowed when there is a single loaded network group") return self._loaded_network_groups[0].get_input_stream_infos(network_name=network_name) @@ -254,6 +270,7 @@ class HailoChipObject(HailoHWObject): :obj:`hailo_platform.pyhailort._pyhailort.VStreamInfo`: with information objects of all output low-level streams. """ + # self._logger.warning("HailoChipObject get_output_stream_infos function is deprecated! Please use ConfiguredNetwork object.") if len(self._loaded_network_groups) != 1: raise HailoHWObjectException("Access to network stream info is only allowed when there is a single loaded network group") return self._loaded_network_groups[0].get_output_stream_infos(network_name=network_name) @@ -268,7 +285,7 @@ class HailoChipObject(HailoHWObject): If there is exactly one configured network group, returns a list of :obj:`hailo_platform.pyhailort._pyhailort.StreamInfo`: with all the information objects of all input and output streams """ - + # self._logger.warning("HailoChipObject get_all_stream_infos function is deprecated! Please use ConfiguredNetwork object.") if len(self._loaded_network_groups) != 1: raise HailoHWObjectException("Access to network stream info is only allowed when there is a single loaded network group") return self._loaded_network_groups[0].get_all_stream_infos(network_name=network_name) @@ -276,7 +293,6 @@ class HailoChipObject(HailoHWObject): @property def loaded_network_groups(self): """Getter for the property _loaded_network_groups. - Returns: list of :obj:`ConfiguredNetwork`: List of the the configured network groups loaded on the device. """ @@ -290,7 +306,6 @@ class HailoChipObject(HailoHWObject): def configure(self, hef, configure_params_by_name={}): """Configures target device from HEF object. - Args: hef (:class:`~hailo_platform.pyhailort.pyhailort.HEF`): HEF to configure the device from configure_params_by_name (dict, optional): Maps between each net_group_name to configure_params. If not provided, default params will be applied @@ -313,6 +328,7 @@ class HailoChipObject(HailoHWObject): Returns: Tuple of integers representing the input_shape. """ + # self._logger.warning("HailoChipObject get_input_shape function is deprecated! Please use ConfiguredNetwork object.") if name is None: name = self.get_input_vstream_infos()[0].name @@ -332,6 +348,7 @@ class HailoChipObject(HailoHWObject): Returns: int: The index of the layer name in the output list. """ + # self._logger.warning("HailoChipObject get_index_from_name function is deprecated! Please use ConfiguredNetwork object.") try: return self.sorted_output_layer_names.index(name) except ValueError: @@ -383,7 +400,6 @@ class EthernetDevice(HailoChipObject): self._control_object = None self._open_device() - self._id = "{}".format(self._remote_ip) identity = self._control_object._identify_info self._hw_arch = BoardInformation.get_hw_arch_str(identity.device_architecture) @@ -398,6 +414,7 @@ class EthernetDevice(HailoChipObject): Returns: list of str: IPs of scanned devices. """ + # default_logger().warning("EthernetDevice scan_devices method is deprecated! Please use scan() of Device object.") udp_scanner = HailoUdpScan() return udp_scanner.scan_devices(interface_name, timeout_seconds=timeout_seconds) @@ -418,6 +435,7 @@ class EthernetDevice(HailoChipObject): @property def remote_ip(self): """Return the IP of the remote device.""" + # self._logger.warning("EthernetDevice remote_ip method is deprecated! Please use Device object.") return self._remote_ip @@ -437,6 +455,7 @@ class PcieDevice(HailoChipObject): :func:`PcieDevice.scan_devices` to get list of all available devices. """ super(PcieDevice, self).__init__() + # self._logger.warning("PcieDevice deprecated! Please use VDevice object.") gc.collect() # PcieDevice __del__ function tries to release self._device. @@ -460,6 +479,7 @@ class PcieDevice(HailoChipObject): Returns: list of :obj:`hailo_platform.pyhailort.pyhailort.PcieDeviceInfo` """ + # default_logger().warning("PcieDevice scan_devices method is deprecated! Please use scan() of Device object.") return InternalPcieDevice.scan_devices() def _open_device(self, device_info): diff --git a/hailort/libhailort/bindings/python/platform/hailo_platform/pyhailort/pyhailort.py b/hailort/libhailort/bindings/python/platform/hailo_platform/pyhailort/pyhailort.py index 921b623..688cd40 100644 --- a/hailort/libhailort/bindings/python/platform/hailo_platform/pyhailort/pyhailort.py +++ b/hailort/libhailort/bindings/python/platform/hailo_platform/pyhailort/pyhailort.py @@ -1,5 +1,4 @@ from enum import Enum, IntEnum -import re import signal import struct import pkg_resources @@ -123,7 +122,7 @@ class ExceptionWrapper(object): raise HailoRTInvalidFrameException("An invalid frame was received") if string_error_code == "HAILO_TIMEOUT": raise HailoRTTimeout("Received a timeout - hailort has failed because a timeout had occurred") - if string_error_code == "HAILO_STREAM_ABORTED": + if string_error_code == "HAILO_STREAM_ABORTED_BY_HW": raise HailoRTStreamAborted("Stream aborted due to an external event") if string_error_code == "HAILO_INVALID_OPERATION": @@ -1076,6 +1075,7 @@ class HailoRTTransformUtils(object): class InternalEthernetDevice(object): def __init__(self, address, port, response_timeout_seconds=10, max_number_of_attempts=3): + # default_logger().warning("InternalEthernetDevice is deprecated! Please use Device object.") self.device = None self._address = address self._port = port @@ -1104,6 +1104,7 @@ class PcieDeviceInfo(_pyhailort.PcieDeviceInfo): def __init__(self, bus, device, func, domain=None): super(PcieDeviceInfo, self).__init__() + # default_logger().warning("PcieDeviceInfo is deprecated! Please use Device object with device_id.") self.bus = bus self.device = device self.func = func @@ -1140,6 +1141,7 @@ class PcieDeviceInfo(_pyhailort.PcieDeviceInfo): class InternalPcieDevice(object): def __init__(self, device_info=None): + # self._logger.warning("InternalPcieDevice deprecated! Please use Device object.") self.device = None if device_info is None: device_info = InternalPcieDevice.scan_devices()[0] @@ -1233,7 +1235,7 @@ class HailoFormatFlags(_pyhailort.FormatFlags): SUPPORTED_PROTOCOL_VERSION = 2 SUPPORTED_FW_MAJOR = 4 -SUPPORTED_FW_MINOR = 10 +SUPPORTED_FW_MINOR = 12 SUPPORTED_FW_REVISION = 0 MEGA_MULTIPLIER = 1000.0 * 1000.0 @@ -1250,9 +1252,11 @@ class DeviceArchitectureTypes(IntEnum): class BoardInformation(object): def __init__(self, protocol_version, fw_version_major, fw_version_minor, fw_version_revision, - logger_version, board_name, is_release, device_architecture, serial_number, part_number, product_name): + logger_version, board_name, is_release, extended_context_switch_buffer, device_architecture, + serial_number, part_number, product_name): self.protocol_version = protocol_version - self.firmware_version = HailoFirmwareVersion.construct_from_params(fw_version_major, fw_version_minor, fw_version_revision, is_release, HailoFirmwareType.APP) + self.firmware_version = HailoFirmwareVersion.construct_from_params(fw_version_major, fw_version_minor, fw_version_revision, is_release, + extended_context_switch_buffer, HailoFirmwareType.APP) self.logger_version = logger_version self.board_name = board_name self.is_release = is_release @@ -1303,8 +1307,9 @@ class BoardInformation(object): raise HailoRTException("Unsupported device architecture.") class CoreInformation(object): - def __init__(self, fw_version_major, fw_version_minor, fw_version_revision, is_release): - self.firmware_version = HailoFirmwareVersion.construct_from_params(fw_version_major, fw_version_minor, fw_version_revision, is_release, HailoFirmwareType.CORE) + def __init__(self, fw_version_major, fw_version_minor, fw_version_revision, is_release, extended_context_switch_buffer): + self.firmware_version = HailoFirmwareVersion.construct_from_params(fw_version_major, fw_version_minor, fw_version_revision, is_release, + extended_context_switch_buffer, HailoFirmwareType.CORE) self.is_release = is_release def __str__(self): @@ -1456,17 +1461,20 @@ class HailoFirmwareType(Enum): class HailoFirmwareVersion(object): """Represents a Hailo chip firmware version.""" - DEV_BIT = 0x80000000 - CORE_BIT = 0x08000000 + CORE_BIT = 0x08000000 + EXTENDED_CONTEXT_SWITCH_BUFFER_BIT = 0x40000000 + DEV_BIT = 0x80000000 FW_VERSION_FORMAT = ' "35" if(${dpython} LESS "38") set(m_flag "m") @@ -45,11 +49,24 @@ exclude_archive_libs_symbols(_pyhailort) if (HAILO_BUILD_PYHAILORT_INTERNAL) add_subdirectory(internal) - # copy files to venv - if(HAILO_BUILD_PYHAILORT_VENV) - add_custom_target(pyhailort_internal_venv ALL - COMMAND ${CMAKE_COMMAND} -E copy $ ${PROJECT_SOURCE_DIR}/platform_internals/hailo_platform_internals/pyhailort/ - ) - add_dependencies(pyhailort_internal_venv _pyhailort_internal) - endif() + # copy files to a path the venv will look for + add_custom_target(pyhailort_internal_venv ALL + COMMAND ${CMAKE_COMMAND} -E copy $ ${PROJECT_SOURCE_DIR}/platform_internals/hailo_platform_internals/pyhailort/ + ) + add_dependencies(pyhailort_internal_venv _pyhailort_internal) endif() + +# TODO (HRT-8637): change this hard-coded path +set(HAILO_PYHAILORT_TARGET_DIR ${CMAKE_CURRENT_LIST_DIR}/../platform/hailo_platform/pyhailort/) + +# copy files to a path the venv and whl will look for +message(STATUS "Copying _pyhailort artifacts into " ${HAILO_PYHAILORT_TARGET_DIR}) +add_custom_target(pyhailort_venv ALL + COMMAND ${CMAKE_COMMAND} -E copy $ ${HAILO_PYHAILORT_TARGET_DIR} +) +add_dependencies(pyhailort_venv _pyhailort) + +install(TARGETS _pyhailort + LIBRARY DESTINATION ${HAILO_PYHAILORT_TARGET_DIR} + CONFIGURATIONS Release +) \ No newline at end of file diff --git a/hailort/libhailort/bindings/python/src/device_api.cpp b/hailort/libhailort/bindings/python/src/device_api.cpp index 047427b..b2423e1 100644 --- a/hailort/libhailort/bindings/python/src/device_api.cpp +++ b/hailort/libhailort/bindings/python/src/device_api.cpp @@ -469,6 +469,12 @@ const char *DeviceWrapper::get_dev_id() const return device().get_dev_id(); } +void DeviceWrapper::set_sleep_state(hailo_sleep_state_t sleep_state) +{ + auto status = device().set_sleep_state(sleep_state); + VALIDATE_STATUS(status); +} + void DeviceWrapper::add_to_python_module(py::module &m) { py::class_(m, "Device") @@ -533,6 +539,7 @@ void DeviceWrapper::add_to_python_module(py::module &m) .def("set_notification_callback", &DeviceWrapper::set_notification_callback) .def("remove_notification_callback", &DeviceWrapper::remove_notification_callback) + .def("set_sleep_state", &DeviceWrapper::set_sleep_state) ; } diff --git a/hailort/libhailort/bindings/python/src/device_api.hpp b/hailort/libhailort/bindings/python/src/device_api.hpp index e55d222..1d3c18e 100644 --- a/hailort/libhailort/bindings/python/src/device_api.hpp +++ b/hailort/libhailort/bindings/python/src/device_api.hpp @@ -125,6 +125,7 @@ public: void direct_write_memory(uint32_t address, py::bytes buffer); py::bytes direct_read_memory(uint32_t address, uint32_t size); const char *get_dev_id() const; + void set_sleep_state(hailo_sleep_state_t sleep_state); static void add_to_python_module(py::module &m); diff --git a/hailort/libhailort/bindings/python/src/internal/CMakeLists.txt b/hailort/libhailort/bindings/python/src/internal/CMakeLists.txt index a03aa79..ccf091f 100644 --- a/hailort/libhailort/bindings/python/src/internal/CMakeLists.txt +++ b/hailort/libhailort/bindings/python/src/internal/CMakeLists.txt @@ -26,7 +26,6 @@ target_link_libraries(_pyhailort_internal PRIVATE hef_proto spdlog::spdlog readerwriterqueue - microprofile scheduler_mon_proto) if(HAILO_BUILD_SERVICE) target_link_libraries(_pyhailort_internal PRIVATE grpc++_unsecure hailort_rpc_grpc_proto) diff --git a/hailort/libhailort/bindings/python/src/internal/pyhailort_internal.cpp b/hailort/libhailort/bindings/python/src/internal/pyhailort_internal.cpp index 3b27ea0..18f4c49 100644 --- a/hailort/libhailort/bindings/python/src/internal/pyhailort_internal.cpp +++ b/hailort/libhailort/bindings/python/src/internal/pyhailort_internal.cpp @@ -13,10 +13,163 @@ #include "hailo/hailort.h" #include "transform_internal.hpp" +#include "bindings_common.hpp" + namespace hailort { +static const uint32_t TEST_NUM_OF_CLASSES2 = 80; + +py::array PyhailortInternal::get_yolov5_post_process_expected_buffer() +{ + static const uint32_t DETECTION_CLASS_ID_1 = 0; + static const float32_t CLASS_ID_1_DETECTION_COUNT = 5; + static const uint32_t DETECTION_CLASS_ID_3 = 2; + static const float32_t CLASS_ID_3_DETECTION_COUNT = 2; + static const uint32_t DETECTION_CLASS_ID_8 = 7; + static const float32_t CLASS_ID_8_DETECTION_COUNT = 1; + static const uint32_t DETECTION_CLASS_ID_26 = 25; + static const float32_t CLASS_ID_26_DETECTION_COUNT = 1; + + static const hailo_bbox_float32_t bbox1_0 = { + /*.y_min =*/ 0.5427529811859131f, + /*.x_min =*/ 0.2485126256942749f, + /*.y_max =*/ 0.6096446067f, + /*.x_max =*/ 0.27035075984f, + /*.score =*/ 0.7761699557304382f, + }; + + static const hailo_bbox_float32_t bbox1_1 = { + /*.y_min =*/ 0.5454554557800293f, + /*.x_min =*/ 0.33257606625556948f, + /*.y_max =*/ 0.7027952075f, + /*.x_max =*/ 0.40901548415f, + /*.score =*/ 0.7637669444084168f, + }; + + static const hailo_bbox_float32_t bbox1_2 = { + /*.y_min =*/ 0.5521867275238037f, + /*.x_min =*/ 0.19988654553890229f, + /*.y_max =*/ 0.60256312787f, + /*.x_max =*/ 0.21917282976f, + /*.score =*/ 0.7451231479644775f, + }; + + static const hailo_bbox_float32_t bbox1_3 = { + /*.y_min =*/ 0.5514537692070007f, + /*.x_min =*/ 0.2693796157836914f, + /*.y_max =*/ 0.60397491604f, + /*.x_max =*/ 0.28537025302f, + /*.score =*/ 0.3756354749202728f, + }; + + static const hailo_bbox_float32_t bbox1_4 = { + /*.y_min =*/ 0.553998589515686f, + /*.x_min =*/ 0.18612079322338105f, + /*.y_max =*/ 0.58339602686f, + /*.x_max =*/ 0.2008818537f, + /*.score =*/ 0.3166312277317047f, + }; + + static const hailo_bbox_float32_t bbox3_0 = { + /*.y_min =*/ 0.5026738047599793f, + /*.x_min =*/ -0.005611047148704529f, + /*.y_max =*/ 0.65071095526f, + /*.x_max =*/ 0.13888412714f, + /*.score =*/ 0.5734351277351379f, + }; + + static const hailo_bbox_float32_t bbox3_1 = { + /*.y_min =*/ 0.5620155334472656f, + /*.x_min =*/ 0.16757474839687348f, + /*.y_max =*/ 0.58410947769f, + /*.x_max =*/ 0.19325175508f, + /*.score =*/ 0.4062519371509552f, + }; + + static const hailo_bbox_float32_t bbox8_0 = { + /*.y_min =*/ 0.5028372406959534f, + /*.x_min =*/ -0.0017736181616783143f, + /*.y_max =*/ 0.65114967525f, + /*.x_max =*/ 0.13592261821f, + /*.score =*/ 0.4223918318748474f, + }; + + static const hailo_bbox_float32_t bbox26_0 = { + /*.y_min =*/ 0.5854946374893189f, + /*.x_min =*/ 0.2693060040473938f, + /*.y_max =*/ 0.68259389698f, + /*.x_max =*/ 0.38090330362f, + /*.score =*/ 0.6338639259338379f, + }; + + static const uint32_t DETECTION_COUNT = 9; + auto buffer_size = (DETECTION_COUNT * sizeof(hailo_bbox_float32_t)) + (TEST_NUM_OF_CLASSES2 * sizeof(float32_t)); + auto buffer_expected = hailort::Buffer::create(buffer_size, 0); + // CATCH_REQUIRE_EXPECTED(buffer_expected); + auto buffer = buffer_expected.release(); + + size_t offset = 0; + for (uint32_t class_index = 0; class_index < TEST_NUM_OF_CLASSES2; class_index++) { + if (DETECTION_CLASS_ID_1 == class_index) { + memcpy(buffer.data() + offset, &CLASS_ID_1_DETECTION_COUNT, sizeof(CLASS_ID_1_DETECTION_COUNT)); + offset += sizeof(CLASS_ID_1_DETECTION_COUNT); + + memcpy(buffer.data() + offset, &bbox1_0, sizeof(bbox1_0)); + offset += sizeof(bbox1_0); + + memcpy(buffer.data() + offset, &bbox1_1, sizeof(bbox1_1)); + offset += sizeof(bbox1_1); + + memcpy(buffer.data() + offset, &bbox1_2, sizeof(bbox1_2)); + offset += sizeof(bbox1_2); + + memcpy(buffer.data() + offset, &bbox1_3, sizeof(bbox1_3)); + offset += sizeof(bbox1_3); + + memcpy(buffer.data() + offset, &bbox1_4, sizeof(bbox1_4)); + offset += sizeof(bbox1_4); + } + else if (DETECTION_CLASS_ID_3 == class_index) { + memcpy(buffer.data() + offset, &CLASS_ID_3_DETECTION_COUNT, sizeof(CLASS_ID_3_DETECTION_COUNT)); + offset += sizeof(CLASS_ID_3_DETECTION_COUNT); + + memcpy(buffer.data() + offset, &bbox3_0, sizeof(bbox3_0)); + offset += sizeof(bbox3_0); + + memcpy(buffer.data() + offset, &bbox3_1, sizeof(bbox3_1)); + offset += sizeof(bbox3_1); + } + else if (DETECTION_CLASS_ID_8 == class_index) { + memcpy(buffer.data() + offset, &CLASS_ID_8_DETECTION_COUNT, sizeof(CLASS_ID_8_DETECTION_COUNT)); + offset += sizeof(CLASS_ID_8_DETECTION_COUNT); + + memcpy(buffer.data() + offset, &bbox8_0, sizeof(bbox8_0)); + offset += sizeof(bbox8_0); + } + else if (DETECTION_CLASS_ID_26 == class_index) { + memcpy(buffer.data() + offset, &CLASS_ID_26_DETECTION_COUNT, sizeof(CLASS_ID_26_DETECTION_COUNT)); + offset += sizeof(CLASS_ID_26_DETECTION_COUNT); + + memcpy(buffer.data() + offset, &bbox26_0, sizeof(bbox26_0)); + offset += sizeof(bbox26_0); + } + else { + offset += sizeof(float32_t); + } + } + + // Note: The ownership of the buffer is transferred to Python wrapped as a py::array. + // When the py::array isn't referenced anymore in Python and is destructed, the py::capsule's dtor + // is called too (and it deletes the raw buffer) + auto type = py::dtype(HailoRTBindingsCommon::convert_format_type_to_string(HAILO_FORMAT_TYPE_FLOAT32)); + auto shape = *py::array::ShapeContainer({buffer.size()}); + const auto unmanaged_addr = buffer.release(); + return py::array(type, shape, unmanaged_addr, + py::capsule(unmanaged_addr, [](void *p) { delete reinterpret_cast(p); })); +} + void PyhailortInternal::demux_output_buffer( py::bytes src, const hailo_format_t &src_format, const hailo_3d_image_shape_t &src_shape, std::map dst_buffers, const LayerInfo &mux_layer_info) @@ -108,17 +261,15 @@ bool PyhailortInternal::is_output_transformation_required( py::list PyhailortInternal::get_all_layers_info(const HefWrapper &hef, const std::string &net_group_name) { - auto network_gorup_metadata = hef.hef_ptr()->pimpl->get_network_group_metadata(net_group_name); - VALIDATE_EXPECTED(network_gorup_metadata); - - auto layers_info = network_gorup_metadata->get_all_layer_infos(); - VALIDATE_EXPECTED(layers_info); + auto network_group_metadata = hef.hef_ptr()->pimpl->get_network_group_metadata(net_group_name); + VALIDATE_EXPECTED(network_group_metadata); - return py::cast(layers_info.release()); + return py::cast(network_group_metadata->get_all_layer_infos()); } PYBIND11_MODULE(_pyhailort_internal, m) { ControlWrapper::add_to_python_module(m); + m.def("get_yolov5_post_process_expected_buffer", &PyhailortInternal::get_yolov5_post_process_expected_buffer); m.def("demux_output_buffer", &PyhailortInternal::demux_output_buffer); m.def("transform_input_buffer", &PyhailortInternal::transform_input_buffer); m.def("transform_output_buffer", &PyhailortInternal::transform_output_buffer); diff --git a/hailort/libhailort/bindings/python/src/internal/pyhailort_internal.hpp b/hailort/libhailort/bindings/python/src/internal/pyhailort_internal.hpp index f763700..94f58d5 100644 --- a/hailort/libhailort/bindings/python/src/internal/pyhailort_internal.hpp +++ b/hailort/libhailort/bindings/python/src/internal/pyhailort_internal.hpp @@ -28,6 +28,7 @@ namespace hailort class PyhailortInternal { public: + static py::array get_yolov5_post_process_expected_buffer(); static void demux_output_buffer(py::bytes src, const hailo_format_t &src_format, const hailo_3d_image_shape_t &src_shape, std::map dst_buffers, const LayerInfo &mux_layer_info); static void transform_input_buffer(py::array src, const hailo_format_t &src_format, const hailo_3d_image_shape_t &src_shape, diff --git a/hailort/libhailort/bindings/python/src/net_flow_api.hpp b/hailort/libhailort/bindings/python/src/net_flow_api.hpp new file mode 100644 index 0000000..2bf26ab --- /dev/null +++ b/hailort/libhailort/bindings/python/src/net_flow_api.hpp @@ -0,0 +1,102 @@ +/** + * Copyright (c) 2022 Hailo Technologies Ltd. All rights reserved. + * Distributed under the MIT license (https://opensource.org/licenses/MIT) +**/ +/** + * @file net_flow_api.hpp + * @brief Defines binding to a HailoRT++ ops usage over Python. + **/ + +#ifndef _HAILO_NET_FLOW_API_HPP_ +#define _HAILO_NET_FLOW_API_HPP_ + +#include "utils.hpp" +#include "hailo/hailort.hpp" +#include "bindings_common.hpp" +#include "net_flow/ops/yolo_post_processing.hpp" + +namespace hailort +{ +namespace net_flow +{ + +class YOLOv5PostProcessingOpWrapper +{ +public: + static YOLOv5PostProcessingOpWrapper create(const std::vector> &anchors, + const std::vector &shapes, const std::vector &formats, + const std::vector &quant_infos, float32_t image_height, float32_t image_width, float32_t confidence_threshold, + float32_t iou_threshold, uint32_t num_of_classes, bool should_dequantize, uint32_t max_boxes, bool should_sigmoid, + bool one_class_per_bbox=true) + { + auto op = YOLOv5PostProcessingOp::create(anchors, shapes, formats, quant_infos, image_height, image_width, + confidence_threshold, iou_threshold, num_of_classes, should_dequantize, max_boxes, should_sigmoid, one_class_per_bbox); + VALIDATE_EXPECTED(op); + + return YOLOv5PostProcessingOpWrapper(op.release(), num_of_classes, max_boxes); + } + + static void add_to_python_module(py::module &m) + { + py::class_(m, "YOLOv5PostProcessingOp") + .def("create", &YOLOv5PostProcessingOpWrapper::create) + .def("execute",[](YOLOv5PostProcessingOpWrapper &self, const std::vector &tensors) + { + std::vector data_views; + data_views.reserve(tensors.size()); + for (auto &tensor : tensors) { + data_views.push_back(MemoryView(const_cast(reinterpret_cast(tensor.data())), tensor.nbytes())); + } + + hailo_nms_info_t nms_info = { + self.m_num_of_classes, + self.m_max_boxes, + sizeof(hailo_bbox_float32_t), + 1, + false, + hailo_nms_defuse_info_t() + }; + hailo_format_t output_format = { + HAILO_FORMAT_TYPE_FLOAT32, + HAILO_FORMAT_ORDER_HAILO_NMS, + HAILO_FORMAT_FLAGS_QUANTIZED, + }; + + auto buffer = Buffer::create(HailoRTCommon::get_nms_host_frame_size(nms_info, output_format), 0); + VALIDATE_STATUS(buffer.status()); + auto status = self.m_post_processing_op.execute(data_views, MemoryView(buffer.value().data(), buffer.value().size())); + VALIDATE_STATUS(status); + + // Note: The ownership of the buffer is transferred to Python wrapped as a py::array. + // When the py::array isn't referenced anymore in Python and is destructed, the py::capsule's dtor + // is called too (and it deletes the raw buffer) + auto type = py::dtype(HailoRTBindingsCommon::convert_format_type_to_string(HAILO_FORMAT_TYPE_FLOAT32)); + auto shape = *py::array::ShapeContainer({buffer.value().size()}); + const auto unmanaged_addr = buffer.release().release(); + return py::array(type, shape, unmanaged_addr, + py::capsule(unmanaged_addr, [](void *p) { delete reinterpret_cast(p); })); + }) + ; + } + +private: + YOLOv5PostProcessingOpWrapper(YOLOv5PostProcessingOp &&post_processing_op, uint32_t num_of_classes, uint32_t max_bboxes) + : m_post_processing_op(post_processing_op), + m_num_of_classes(num_of_classes), + m_max_boxes(max_bboxes) {} + + YOLOv5PostProcessingOp m_post_processing_op; + uint32_t m_num_of_classes = 0; + uint32_t m_max_boxes = 0; +}; + +void NetFlow_api_initialize_python_module(py::module &m) +{ + YOLOv5PostProcessingOpWrapper::add_to_python_module(m); +} + + +} /* namespace net_flow */ +} /* namespace hailort */ + +#endif /* _HAILO_NET_FLOW_API_HPP_ */ diff --git a/hailort/libhailort/bindings/python/src/pyhailort.cpp b/hailort/libhailort/bindings/python/src/pyhailort.cpp index 6ad0150..21b11f9 100644 --- a/hailort/libhailort/bindings/python/src/pyhailort.cpp +++ b/hailort/libhailort/bindings/python/src/pyhailort.cpp @@ -15,6 +15,7 @@ using namespace std; #include "vdevice_api.hpp" #include "device_api.hpp" #include "quantization_api.hpp" +#include "net_flow_api.hpp" #include "utils.hpp" #include "utils.h" @@ -157,8 +158,6 @@ private: #endif -// End of temp hack for hlpcie - static void validate_versions_match() { hailo_version_t libhailort_version = {}; @@ -324,7 +323,7 @@ PYBIND11_MODULE(_pyhailort, m) { py::class_(m, "DebugNotificationMessage") .def_readonly("connection_status", &hailo_debug_notification_message_t::connection_status) .def_readonly("connection_type", &hailo_debug_notification_message_t::connection_type) - .def_readonly("pcie_is_active", &hailo_debug_notification_message_t::pcie_is_active) + .def_readonly("vdma_is_active", &hailo_debug_notification_message_t::vdma_is_active) .def_readonly("host_port", &hailo_debug_notification_message_t::host_port) .def_readonly("host_ip_addr", &hailo_debug_notification_message_t::host_ip_addr) ; @@ -393,6 +392,7 @@ PYBIND11_MODULE(_pyhailort, m) { .def_readonly("logger_version", &hailo_device_identity_t::logger_version) .def_readonly("board_name_length", &hailo_device_identity_t::board_name_length) .def_readonly("is_release", &hailo_device_identity_t::is_release) + .def_readonly("extended_context_switch_buffer", &hailo_device_identity_t::extended_context_switch_buffer) .def_readonly("device_architecture", &hailo_device_identity_t::device_architecture) .def_property_readonly("board_name", [](const hailo_device_identity_t& board_info) -> py::str { return py::str(board_info.board_name, board_info.board_name_length); @@ -413,6 +413,7 @@ PYBIND11_MODULE(_pyhailort, m) { py::class_(m, "CoreInformation") .def_readonly("is_release", &hailo_core_information_t::is_release) + .def_readonly("extended_context_switch_buffer", &hailo_core_information_t::extended_context_switch_buffer) .def_readonly("fw_version", &hailo_core_information_t::fw_version) ; @@ -534,6 +535,10 @@ PYBIND11_MODULE(_pyhailort, m) { .value("RGB888", HAILO_FORMAT_ORDER_RGB888) .value("NCHW", HAILO_FORMAT_ORDER_NCHW) .value("YUY2", HAILO_FORMAT_ORDER_YUY2) + .value("NV12", HAILO_FORMAT_ORDER_NV12) + .value("YYUV", HAILO_FORMAT_ORDER_HAILO_YYUV) + .value("NV21", HAILO_FORMAT_ORDER_NV21) + .value("YYVU", HAILO_FORMAT_ORDER_HAILO_YYVU) ; py::enum_(m, "FormatFlags", py::arithmetic()) @@ -792,6 +797,7 @@ PYBIND11_MODULE(_pyhailort, m) { ) .def_static("default", []() { auto orig_params = HailoRTDefaults::get_vdevice_params(); + orig_params.scheduling_algorithm = HAILO_SCHEDULING_ALGORITHM_NONE; VDeviceParamsWrapper params_wrapper{orig_params, ""}; return params_wrapper; }); @@ -942,6 +948,10 @@ PYBIND11_MODULE(_pyhailort, m) { .value("CPU1", HAILO_CPU_ID_1) ; + py::enum_(m, "SleepState") + .value("SLEEP_STATE_SLEEPING", HAILO_SLEEP_STATE_SLEEPING) + .value("SLEEP_STATE_AWAKE", HAILO_SLEEP_STATE_AWAKE) + ; py::class_(m, "HailoRTDefaults") .def_static("HAILO_INFINITE", []() { return HAILO_INFINITE;} ) @@ -1066,6 +1076,7 @@ PYBIND11_MODULE(_pyhailort, m) { VStream_api_initialize_python_module(m); VDevice_api_initialize_python_module(m); DeviceWrapper::add_to_python_module(m); + hailort::net_flow::NetFlow_api_initialize_python_module(m); #if defined(__GNUC__) TrafficControlUtilWrapper::add_to_python_module(m); diff --git a/hailort/libhailort/bindings/python/src/vdevice_api.hpp b/hailort/libhailort/bindings/python/src/vdevice_api.hpp index 0468b76..746b72d 100644 --- a/hailort/libhailort/bindings/python/src/vdevice_api.hpp +++ b/hailort/libhailort/bindings/python/src/vdevice_api.hpp @@ -49,7 +49,18 @@ public: static VDeviceWrapper create_from_ids(const std::vector &device_ids) { - return VDeviceWrapper(device_ids); + auto device_ids_vector = HailoRTCommon::to_device_ids_vector(device_ids); + VALIDATE_EXPECTED(device_ids_vector); + + hailo_vdevice_params_t params = {}; + auto status = hailo_init_vdevice_params(¶ms); + VALIDATE_STATUS(status); + + params.device_ids = device_ids_vector->data(); + params.device_count = static_cast(device_ids_vector->size()); + params.scheduling_algorithm = HAILO_SCHEDULING_ALGORITHM_NONE; + + return VDeviceWrapper(params); } VDeviceWrapper(const hailo_vdevice_params_t ¶ms) @@ -60,14 +71,6 @@ public: m_vdevice = vdevice_expected.release(); }; - VDeviceWrapper(const std::vector &device_ids) - { - auto vdevice_expected = VDevice::create(device_ids); - VALIDATE_EXPECTED(vdevice_expected); - - m_vdevice = vdevice_expected.release(); - } - py::list get_physical_devices_ids() const { const auto phys_devs_ids = m_vdevice->get_physical_devices_ids(); diff --git a/hailort/libhailort/cmake/toolchains/toolchains.yaml b/hailort/libhailort/cmake/toolchains/toolchains.yaml index 3c5abf6..6218084 100644 --- a/hailort/libhailort/cmake/toolchains/toolchains.yaml +++ b/hailort/libhailort/cmake/toolchains/toolchains.yaml @@ -3,38 +3,31 @@ - gcc - g++ python_versions: - - version: '3.6' - installation: deb - package_name: python3.6-dev - - version: '3.7' - installation: deb - package_name: python3.7-dev - version: '3.8' installation: deb package_name: python3.8-dev - version: '3.9' installation: deb package_name: python3.9-dev + - version: '3.10' + installation: deb + package_name: python3.10-dev - name: linux.aarch64 required_packages: - gcc-aarch64-linux-gnu - g++-aarch64-linux-gnu python_versions: - - version: '3.6' - installation: manual - package_name: http://launchpadlibrarian.net/362976109/libpython3.6-dev_3.6.5-3_arm64.deb - package_dest: /usr/include/aarch64-linux-gnu - - version: '3.7' - installation: manual - package_name: http://launchpadlibrarian.net/450463692/libpython3.7-dev_3.7.5-2~18.04_arm64.deb - package_dest: /usr/include/aarch64-linux-gnu - version: '3.8' installation: manual package_name: https://launchpad.net/ubuntu/+source/python3.8/3.8.2-1ubuntu1/+build/18834117/+files/libpython3.8-dev_3.8.2-1ubuntu1_arm64.deb package_dest: /usr/include/aarch64-linux-gnu - version: '3.9' installation: manual - package_name: https://launchpad.net/~deadsnakes/+archive/ubuntu/ppa/+build/23779329/+files/libpython3.9-dev_3.9.13-1+bionic1_arm64.deb + package_name: https://launchpad.net/~deadsnakes/+archive/ubuntu/ppa/+build/24906233/+files/libpython3.9-dev_3.9.16-1+bionic1_arm64.deb + package_dest: /usr/include/aarch64-linux-gnu + - version: '3.10' + installation: manual + package_name: https://launchpadlibrarian.net/569418529/libpython3.10-dev_3.10.0-5_arm64.deb package_dest: /usr/include/aarch64-linux-gnu - name: linux.armv7l required_packages: diff --git a/hailort/libhailort/examples/CMakeLists.txt b/hailort/libhailort/examples/CMakeLists.txt index aae9461..b0cfdda 100644 --- a/hailort/libhailort/examples/CMakeLists.txt +++ b/hailort/libhailort/examples/CMakeLists.txt @@ -2,23 +2,9 @@ cmake_minimum_required(VERSION 3.0.0) project(hailort-examples) -find_package(Threads REQUIRED) -set(THREADS_PREFER_PTHREAD_FLAG ON) - -find_package(HailoRT 4.10.0 EXACT REQUIRED) - -add_library(example_base INTERFACE) -target_link_libraries(example_base INTERFACE HailoRT::libhailort Threads::Threads) - -if(WIN32) - target_compile_options(example_base INTERFACE /W4 /WX /DWIN32_LEAN_AND_MEAN /DNOMINMAX /wd4201 /wd4251) -else() - target_compile_options(example_base INTERFACE -Werror -Wall -Wextra -Wconversion -O3 -DNDEBUG) # TODO support debug/release builds -endif() - add_subdirectory(cpp) add_subdirectory(c) -set_target_properties(${EXAMPLES_CPP_TARGETS} PROPERTIES CXX_STANDARD 14) - -add_custom_target(hailort_examples DEPENDS ${EXAMPLES_C_TARGETS} ${EXAMPLES_CPP_TARGETS}) \ No newline at end of file +# We add a costum target in order to compile all of the hailort examples +add_custom_target(hailort_examples) +add_dependencies(hailort_examples c_hailort_examples cpp_hailort_examples) \ No newline at end of file diff --git a/hailort/libhailort/examples/README.md b/hailort/libhailort/examples/README.md index 768b080..0de5803 100644 --- a/hailort/libhailort/examples/README.md +++ b/hailort/libhailort/examples/README.md @@ -15,9 +15,9 @@ The following examples are provided, demonstrating the HailoRT API: - Get the networks information to create the vstreams for each network. - The data is sent to the device via input vstreams and received via output vstreams. - The data is transformed before sent and after receiving in a different thread using the virtual stream pipeline. - - `switch_network_groups_example` - Demonstrates how to work with multiple HEFs using virtual streams and HailoRT scheduler for automatic network group switching. + - `switch_network_groups_example` - Demonstrates how to work with multiple HEFs using virtual streams and HailoRT Model Scheduler for automatic network group switching. - This example uses pcie devices. - - `switch_single_io_network_groups_manually_example` - Demonstrates how to work with multiple single input single output HEFs, switching the created network groups manually, using virtual streams. + - `switch_network_groups_manually_example` - Demonstrates how to work with multiple single input single output HEFs, switching the created network groups manually, using virtual streams. - `data_quantization_example` - Demonstrates how to set input/output stream params so as to allow for custom quantization: - Input streams may be marked as quantized, so that input data will not to be automatically quantized by the HailoRT library. - Output streams may be marked as quantized, so that output data will remain quantized (as it is after exiting the device by default), and won't be 'de-quantized' by the HailoRT library. @@ -31,13 +31,13 @@ The following examples are provided, demonstrating the HailoRT API: - `vstreams_example` - Basic inference of a shortcut network, same as `vstreams_example` C example, uses HailoRT C++ api. - `multi_device_example` - Basic inference of a shortcut network over multiple devices, same as `multi_device_example` C example, uses HailoRT C++ api. - `multi_network_vstream_example` - Demonstrates how to work with multiple networks in a network group, same as `multi_network_vstream_example ` C example, uses HailoRT C++ api. - - `switch_network_groups_example` - Demonstrates how to work with multiple HEFs using virtual streams and HailoRT scheduler, same as `switch_network_groups_example ` C example, uses HailoRT C++ api. + - `switch_network_groups_example` - Demonstrates how to work with multiple HEFs using virtual streams and HailoRT Model Scheduler, same as `switch_network_groups_example ` C example, uses HailoRT C++ api. - `switch_network_groups_manually_example` -Demonstrates how to work with multiple HEFs, switching the running network_groups manually, with performance optimizations for I/O threads re-usage instead of re-creation at each network group activation. Uses C++ api. - `infer_streams_example` - Basic inference of a shortcut network, same as `raw_streams_example` C example, uses HailoRT C++ api. - `infer_pipeline_example` - Basic inference of a shortcut network using inference pipeline (blocking) api. - same as `infer_pipeline_example` C example, uses HailoRT C++ api. - `raw_streams_example` - Basic inference of a shortcut network, same as `raw_streams_example` C example, uses HailoRT C++ api. - - `multi_process_example` - Demonstrates how to work with HailoRT as a service and using the HailoRT scheduler for network groups switching. + - `multi_process_example` - Demonstrates how to work with HailoRT as a service and using the HailoRT Model Scheduler for network groups switching. Using the script `multi_process_example.sh` one can specify the number of processes to run each hef, see `multi_process_example.sh -h` for more information. ## Compiling with CMake @@ -49,9 +49,21 @@ cmake --build build --config release > **_NOTE:_** Write permissions are required to compile the examples from their current directory. If this is not the case, copy the examples directory to another location with the required permissions. +In order to compile a specific example, add the example name as target with a c/cpp prefix: +```sh +cmake -H. -Bbuild -DCMAKE_BUILD_TYPE=Release +cmake --build build --config release --target cpp_vstreams_example +``` + ## Running the examples -One can run the example using the following commands, from the examples directory: + +Before running an example, download the HEFs using the [download script](../../scripts/download_hefs.sh): + ```sh + ../../scripts/download_hefs.sh + ``` + +To run an example, use (from this examples directory): ```sh - build// [params..] + build/// [params..] ``` diff --git a/hailort/libhailort/examples/c/CMakeLists.txt b/hailort/libhailort/examples/c/CMakeLists.txt index ec29225..97275f7 100644 --- a/hailort/libhailort/examples/c/CMakeLists.txt +++ b/hailort/libhailort/examples/c/CMakeLists.txt @@ -1,43 +1,23 @@ cmake_minimum_required(VERSION 3.0.0) -file(GLOB_RECURSE C_EXAMPLE_SOURCES "*.c") -SET_SOURCE_FILES_PROPERTIES(${C_EXAMPLE_SOURCES} PROPERTIES LANGUAGE C) - -add_executable(c_data_quantization_example data_quantization_example.c) -target_link_libraries(c_data_quantization_example PRIVATE example_base) - -add_executable(c_raw_streams_example raw_streams_example.c) -target_link_libraries(c_raw_streams_example PRIVATE example_base) - -add_executable(c_vstreams_example vstreams_example.c) -target_link_libraries(c_vstreams_example PRIVATE example_base) - -add_executable(c_infer_pipeline_example infer_pipeline_example.c) -target_link_libraries(c_infer_pipeline_example PRIVATE example_base) - -add_executable(c_multi_network_vstream_example multi_network_vstream_example.c) -target_link_libraries(c_multi_network_vstream_example PRIVATE example_base) - -add_executable(c_switch_network_groups_example switch_network_groups_example.c) -target_link_libraries(c_switch_network_groups_example PRIVATE example_base) - -add_executable(c_switch_single_io_network_groups_manually_example switch_single_io_network_groups_manually_example.c) -target_link_libraries(c_switch_single_io_network_groups_manually_example PRIVATE example_base) - -add_executable(c_multi_device_example multi_device_example.c) -target_link_libraries(c_multi_device_example PRIVATE example_base) - -add_executable(c_power_measurement_example power_measurement_example.c) -target_link_libraries(c_power_measurement_example PRIVATE example_base) - -set(EXAMPLES_C_TARGETS +add_subdirectory(data_quantization_example) +add_subdirectory(raw_streams_example) +add_subdirectory(vstreams_example) +add_subdirectory(infer_pipeline_example) +add_subdirectory(multi_network_vstream_example) +add_subdirectory(switch_network_groups_example) +add_subdirectory(switch_network_groups_manually_example) +add_subdirectory(multi_device_example) +add_subdirectory(power_measurement_example) + +add_custom_target(c_hailort_examples) +add_dependencies(c_hailort_examples c_data_quantization_example c_raw_streams_example c_vstreams_example c_infer_pipeline_example c_multi_network_vstream_example c_switch_network_groups_example - c_switch_single_io_network_groups_manually_example + c_switch_network_groups_manually_example c_multi_device_example - c_power_measurement_example - PARENT_SCOPE) + c_power_measurement_example) \ No newline at end of file diff --git a/hailort/libhailort/examples/c/common.h b/hailort/libhailort/examples/c/common/common.h similarity index 100% rename from hailort/libhailort/examples/c/common.h rename to hailort/libhailort/examples/c/common/common.h diff --git a/hailort/libhailort/examples/c/hailo_thread.h b/hailort/libhailort/examples/c/common/hailo_thread.h similarity index 100% rename from hailort/libhailort/examples/c/hailo_thread.h rename to hailort/libhailort/examples/c/common/hailo_thread.h diff --git a/hailort/libhailort/examples/c/data_quantization_example/CMakeLists.txt b/hailort/libhailort/examples/c/data_quantization_example/CMakeLists.txt new file mode 100644 index 0000000..272ec19 --- /dev/null +++ b/hailort/libhailort/examples/c/data_quantization_example/CMakeLists.txt @@ -0,0 +1,20 @@ +cmake_minimum_required(VERSION 3.0.0) + +find_package(Threads REQUIRED) +set(THREADS_PREFER_PTHREAD_FLAG ON) + +find_package(HailoRT 4.12.0 EXACT REQUIRED) + +SET_SOURCE_FILES_PROPERTIES(data_quantization_example.c PROPERTIES LANGUAGE C) + +add_executable(c_data_quantization_example data_quantization_example.c) +target_link_libraries(c_data_quantization_example PRIVATE HailoRT::libhailort Threads::Threads) +target_include_directories(c_data_quantization_example PRIVATE "${CMAKE_CURRENT_LIST_DIR}/../common") + +if(WIN32) + target_compile_options(c_data_quantization_example PRIVATE + /DWIN32_LEAN_AND_MEAN + /DNOMINMAX # NOMINMAX is required in order to play nice with std::min/std::max (otherwise Windows.h defines it's own) + /wd4201 /wd4251 + ) +endif() \ No newline at end of file diff --git a/hailort/libhailort/examples/c/data_quantization_example.c b/hailort/libhailort/examples/c/data_quantization_example/data_quantization_example.c similarity index 96% rename from hailort/libhailort/examples/c/data_quantization_example.c rename to hailort/libhailort/examples/c/data_quantization_example/data_quantization_example.c index 4275bfe..7688d22 100644 --- a/hailort/libhailort/examples/c/data_quantization_example.c +++ b/hailort/libhailort/examples/c/data_quantization_example/data_quantization_example.c @@ -255,7 +255,6 @@ int main(int argc, char **argv) hailo_output_vstream output_vstreams[MAX_EDGE_LAYERS] = {NULL}; size_t input_vstreams_size = MAX_EDGE_LAYERS; size_t output_vstreams_size = MAX_EDGE_LAYERS; - hailo_activated_network_group activated_network_group = NULL; quantization_args_t quant_args; parse_arguments(argc, argv, &quant_args); @@ -282,16 +281,12 @@ int main(int argc, char **argv) &output_vstreams_size,quant_args); REQUIRE_SUCCESS(status, l_release_hef, "Failed creating virtual streams"); - status = hailo_activate_network_group(network_group, NULL, &activated_network_group); - REQUIRE_SUCCESS(status, l_release_vstreams, "Failed activate network group"); - status = infer(input_vstreams, input_vstreams_size, output_vstreams, output_vstreams_size, quant_args); - REQUIRE_SUCCESS(status, l_deactivate_network_group, "Inference failure"); + REQUIRE_SUCCESS(status, l_release_vstreams, "Inference failure"); printf("Inference ran successfully\n"); status = HAILO_SUCCESS; -l_deactivate_network_group: - (void)hailo_deactivate_network_group(activated_network_group); + l_release_vstreams: (void)hailo_release_output_vstreams(output_vstreams, output_vstreams_size); (void)hailo_release_input_vstreams(input_vstreams, input_vstreams_size); diff --git a/hailort/libhailort/examples/c/infer_pipeline_example/CMakeLists.txt b/hailort/libhailort/examples/c/infer_pipeline_example/CMakeLists.txt new file mode 100644 index 0000000..54c5bc3 --- /dev/null +++ b/hailort/libhailort/examples/c/infer_pipeline_example/CMakeLists.txt @@ -0,0 +1,20 @@ +cmake_minimum_required(VERSION 3.0.0) + +find_package(Threads REQUIRED) +set(THREADS_PREFER_PTHREAD_FLAG ON) + +find_package(HailoRT 4.12.0 EXACT REQUIRED) + +SET_SOURCE_FILES_PROPERTIES(infer_pipeline_example.c PROPERTIES LANGUAGE C) + +add_executable(c_infer_pipeline_example infer_pipeline_example.c) +target_link_libraries(c_infer_pipeline_example PRIVATE HailoRT::libhailort Threads::Threads) +target_include_directories(c_infer_pipeline_example PRIVATE "${CMAKE_CURRENT_LIST_DIR}/../common") + +if(WIN32) + target_compile_options(c_infer_pipeline_example PRIVATE + /DWIN32_LEAN_AND_MEAN + /DNOMINMAX # NOMINMAX is required in order to play nice with std::min/std::max (otherwise Windows.h defines it's own) + /wd4201 /wd4251 + ) +endif() \ No newline at end of file diff --git a/hailort/libhailort/examples/c/infer_pipeline_example.c b/hailort/libhailort/examples/c/infer_pipeline_example/infer_pipeline_example.c similarity index 98% rename from hailort/libhailort/examples/c/infer_pipeline_example.c rename to hailort/libhailort/examples/c/infer_pipeline_example/infer_pipeline_example.c index aca18fc..51478c8 100644 --- a/hailort/libhailort/examples/c/infer_pipeline_example.c +++ b/hailort/libhailort/examples/c/infer_pipeline_example/infer_pipeline_example.c @@ -11,7 +11,6 @@ #include "common.h" #include "string.h" -#include "hailo_thread.h" #include "hailo/hailort.h" #define MAX_NUM_OF_DEVICES (5) @@ -114,7 +113,7 @@ int main(int argc, char **argv) REQUIRE_SUCCESS(status, l_exit, "Failed to create eth_device"); status = hailo_create_hef_file(&hef, HEF_FILE); - REQUIRE_SUCCESS(status, l_release_vdevice, "Failed reading hef file"); + REQUIRE_SUCCESS(status, l_release_device, "Failed reading hef file"); status = hailo_init_configure_params(hef, HAILO_STREAM_INTERFACE_ETH, &config_params); REQUIRE_SUCCESS(status, l_release_hef, "Failed initializing configure parameters"); @@ -154,7 +153,7 @@ l_deactivate_network_group: (void)hailo_deactivate_network_group(activated_network_group); l_release_hef: (void) hailo_release_hef(hef); -l_release_vdevice: +l_release_device: (void) hailo_release_device(device); l_exit: return status; diff --git a/hailort/libhailort/examples/c/multi_device_example/CMakeLists.txt b/hailort/libhailort/examples/c/multi_device_example/CMakeLists.txt new file mode 100644 index 0000000..6495a30 --- /dev/null +++ b/hailort/libhailort/examples/c/multi_device_example/CMakeLists.txt @@ -0,0 +1,20 @@ +cmake_minimum_required(VERSION 3.0.0) + +find_package(Threads REQUIRED) +set(THREADS_PREFER_PTHREAD_FLAG ON) + +find_package(HailoRT 4.12.0 EXACT REQUIRED) + +SET_SOURCE_FILES_PROPERTIES(multi_device_example.c PROPERTIES LANGUAGE C) + +add_executable(c_multi_device_example multi_device_example.c) +target_link_libraries(c_multi_device_example PRIVATE HailoRT::libhailort Threads::Threads) +target_include_directories(c_multi_device_example PRIVATE "${CMAKE_CURRENT_LIST_DIR}/../common") + +if(WIN32) + target_compile_options(c_multi_device_example PRIVATE + /DWIN32_LEAN_AND_MEAN + /DNOMINMAX # NOMINMAX is required in order to play nice with std::min/std::max (otherwise Windows.h defines it's own) + /wd4201 /wd4251 + ) +endif() \ No newline at end of file diff --git a/hailort/libhailort/examples/c/multi_device_example.c b/hailort/libhailort/examples/c/multi_device_example/multi_device_example.c similarity index 95% rename from hailort/libhailort/examples/c/multi_device_example.c rename to hailort/libhailort/examples/c/multi_device_example/multi_device_example.c index 787168b..78cc1fc 100644 --- a/hailort/libhailort/examples/c/multi_device_example.c +++ b/hailort/libhailort/examples/c/multi_device_example/multi_device_example.c @@ -139,7 +139,6 @@ int main() hailo_output_vstream_params_by_name_t output_vstream_params[MAX_EDGE_LAYERS] = {0}; size_t input_vstreams_size = MAX_EDGE_LAYERS; size_t output_vstreams_size = MAX_EDGE_LAYERS; - hailo_activated_network_group activated_network_group = NULL; hailo_input_vstream input_vstreams[MAX_EDGE_LAYERS] = {NULL}; hailo_output_vstream output_vstreams[MAX_EDGE_LAYERS] = {NULL}; @@ -183,16 +182,11 @@ int main() status = hailo_create_output_vstreams(network_group, output_vstream_params, output_vstreams_size, output_vstreams); REQUIRE_SUCCESS(status, l_release_input_vstream, "Failed creating output virtual streams\n"); - status = hailo_activate_network_group(network_group, NULL, &activated_network_group); - REQUIRE_SUCCESS(status, l_release_output_vstream, "Failed activate network group"); - status = infer(input_vstreams, input_vstreams_size, output_vstreams, output_vstreams_size); - REQUIRE_SUCCESS(status, l_deactivate_network_group, "Inference failure"); + REQUIRE_SUCCESS(status, l_release_output_vstream, "Inference failure"); printf("Inference ran successfully\n"); status = HAILO_SUCCESS; -l_deactivate_network_group: - (void)hailo_deactivate_network_group(activated_network_group); l_release_output_vstream: (void)hailo_release_output_vstreams(output_vstreams, output_vstreams_size); l_release_input_vstream: diff --git a/hailort/libhailort/examples/c/multi_network_vstream_example/CMakeLists.txt b/hailort/libhailort/examples/c/multi_network_vstream_example/CMakeLists.txt new file mode 100644 index 0000000..b827b40 --- /dev/null +++ b/hailort/libhailort/examples/c/multi_network_vstream_example/CMakeLists.txt @@ -0,0 +1,20 @@ +cmake_minimum_required(VERSION 3.0.0) + +find_package(Threads REQUIRED) +set(THREADS_PREFER_PTHREAD_FLAG ON) + +find_package(HailoRT 4.12.0 EXACT REQUIRED) + +SET_SOURCE_FILES_PROPERTIES(multi_network_vstream_example.c PROPERTIES LANGUAGE C) + +add_executable(c_multi_network_vstream_example multi_network_vstream_example.c) +target_link_libraries(c_multi_network_vstream_example PRIVATE HailoRT::libhailort Threads::Threads) +target_include_directories(c_multi_network_vstream_example PRIVATE "${CMAKE_CURRENT_LIST_DIR}/../common") + +if(WIN32) + target_compile_options(c_multi_network_vstream_example PRIVATE + /DWIN32_LEAN_AND_MEAN + /DNOMINMAX # NOMINMAX is required in order to play nice with std::min/std::max (otherwise Windows.h defines it's own) + /wd4201 /wd4251 + ) +endif() \ No newline at end of file diff --git a/hailort/libhailort/examples/c/multi_network_vstream_example.c b/hailort/libhailort/examples/c/multi_network_vstream_example/multi_network_vstream_example.c similarity index 98% rename from hailort/libhailort/examples/c/multi_network_vstream_example.c rename to hailort/libhailort/examples/c/multi_network_vstream_example/multi_network_vstream_example.c index 09d26c9..552d07c 100644 --- a/hailort/libhailort/examples/c/multi_network_vstream_example.c +++ b/hailort/libhailort/examples/c/multi_network_vstream_example/multi_network_vstream_example.c @@ -171,6 +171,8 @@ int main() status = hailo_init_vdevice_params(¶ms); REQUIRE_SUCCESS(status, l_exit, "Failed init vdevice_params"); + /* Scheduler does not support different batches for different networks within the same network group */ + params.scheduling_algorithm = HAILO_SCHEDULING_ALGORITHM_NONE; params.device_count = DEVICE_COUNT; status = hailo_create_vdevice(¶ms, &vdevice); REQUIRE_SUCCESS(status, l_exit, "Failed to create vdevice"); @@ -233,6 +235,7 @@ int main() printf("Inference ran successfully\n"); status = HAILO_SUCCESS; + l_deactivate_network_group: (void)hailo_deactivate_network_group(activated_network_group); l_release_vstreams: diff --git a/hailort/libhailort/examples/c/power_measurement_example/CMakeLists.txt b/hailort/libhailort/examples/c/power_measurement_example/CMakeLists.txt new file mode 100644 index 0000000..2efc206 --- /dev/null +++ b/hailort/libhailort/examples/c/power_measurement_example/CMakeLists.txt @@ -0,0 +1,17 @@ +cmake_minimum_required(VERSION 3.0.0) + +find_package(HailoRT 4.12.0 EXACT REQUIRED) + +SET_SOURCE_FILES_PROPERTIES(power_measurement_example.c PROPERTIES LANGUAGE C) + +add_executable(c_power_measurement_example power_measurement_example.c) +target_link_libraries(c_power_measurement_example PRIVATE HailoRT::libhailort) +target_include_directories(c_power_measurement_example PRIVATE "${CMAKE_CURRENT_LIST_DIR}/../common") + +if(WIN32) + target_compile_options(c_power_measurement_example PRIVATE + /DWIN32_LEAN_AND_MEAN + /DNOMINMAX # NOMINMAX is required in order to play nice with std::min/std::max (otherwise Windows.h defines it's own) + /wd4201 /wd4251 + ) +endif() \ No newline at end of file diff --git a/hailort/libhailort/examples/c/power_measurement_example.c b/hailort/libhailort/examples/c/power_measurement_example/power_measurement_example.c similarity index 97% rename from hailort/libhailort/examples/c/power_measurement_example.c rename to hailort/libhailort/examples/c/power_measurement_example/power_measurement_example.c index 03a0ff1..b68687f 100644 --- a/hailort/libhailort/examples/c/power_measurement_example.c +++ b/hailort/libhailort/examples/c/power_measurement_example/power_measurement_example.c @@ -95,6 +95,9 @@ int main(int argc, char **argv) status = hailo_init_vdevice_params(¶ms); REQUIRE_SUCCESS(status, l_exit, "Failed to init vdevice_params"); + /* Scheduler over multiple devices is currently not supported */ + params.scheduling_algorithm = HAILO_SCHEDULING_ALGORITHM_NONE; + params.device_count = (uint32_t)actual_device_count; status = hailo_create_vdevice(¶ms, &vdevice); REQUIRE_SUCCESS(status, l_exit, "Failed to create vdevice"); diff --git a/hailort/libhailort/examples/c/raw_streams_example/CMakeLists.txt b/hailort/libhailort/examples/c/raw_streams_example/CMakeLists.txt new file mode 100644 index 0000000..000f0b0 --- /dev/null +++ b/hailort/libhailort/examples/c/raw_streams_example/CMakeLists.txt @@ -0,0 +1,20 @@ +cmake_minimum_required(VERSION 3.0.0) + +find_package(Threads REQUIRED) +set(THREADS_PREFER_PTHREAD_FLAG ON) + +find_package(HailoRT 4.12.0 EXACT REQUIRED) + +SET_SOURCE_FILES_PROPERTIES(raw_streams_example.c PROPERTIES LANGUAGE C) + +add_executable(c_raw_streams_example raw_streams_example.c) +target_link_libraries(c_raw_streams_example PRIVATE HailoRT::libhailort Threads::Threads) +target_include_directories(c_raw_streams_example PRIVATE "${CMAKE_CURRENT_LIST_DIR}/../common") + +if(WIN32) + target_compile_options(c_raw_streams_example PRIVATE + /DWIN32_LEAN_AND_MEAN + /DNOMINMAX # NOMINMAX is required in order to play nice with std::min/std::max (otherwise Windows.h defines it's own) + /wd4201 /wd4251 + ) +endif() \ No newline at end of file diff --git a/hailort/libhailort/examples/c/raw_streams_example.c b/hailort/libhailort/examples/c/raw_streams_example/raw_streams_example.c similarity index 100% rename from hailort/libhailort/examples/c/raw_streams_example.c rename to hailort/libhailort/examples/c/raw_streams_example/raw_streams_example.c diff --git a/hailort/libhailort/examples/c/switch_network_groups_example/CMakeLists.txt b/hailort/libhailort/examples/c/switch_network_groups_example/CMakeLists.txt new file mode 100644 index 0000000..4da59df --- /dev/null +++ b/hailort/libhailort/examples/c/switch_network_groups_example/CMakeLists.txt @@ -0,0 +1,20 @@ +cmake_minimum_required(VERSION 3.0.0) + +find_package(Threads REQUIRED) +set(THREADS_PREFER_PTHREAD_FLAG ON) + +find_package(HailoRT 4.12.0 EXACT REQUIRED) + +SET_SOURCE_FILES_PROPERTIES(switch_network_groups_example.c PROPERTIES LANGUAGE C) + +add_executable(c_switch_network_groups_example switch_network_groups_example.c) +target_link_libraries(c_switch_network_groups_example PRIVATE HailoRT::libhailort Threads::Threads) +target_include_directories(c_switch_network_groups_example PRIVATE "${CMAKE_CURRENT_LIST_DIR}/../common") + +if(WIN32) + target_compile_options(c_switch_network_groups_example PRIVATE + /DWIN32_LEAN_AND_MEAN + /DNOMINMAX # NOMINMAX is required in order to play nice with std::min/std::max (otherwise Windows.h defines it's own) + /wd4201 /wd4251 + ) +endif() \ No newline at end of file diff --git a/hailort/libhailort/examples/c/switch_network_groups_example.c b/hailort/libhailort/examples/c/switch_network_groups_example/switch_network_groups_example.c similarity index 94% rename from hailort/libhailort/examples/c/switch_network_groups_example.c rename to hailort/libhailort/examples/c/switch_network_groups_example/switch_network_groups_example.c index e1ac03f..df4e39b 100644 --- a/hailort/libhailort/examples/c/switch_network_groups_example.c +++ b/hailort/libhailort/examples/c/switch_network_groups_example/switch_network_groups_example.c @@ -21,6 +21,9 @@ #define HEF_COUNT (2) #define DEVICE_COUNT (1) +#define SCHEDULER_TIMEOUT_MS (100) +#define SCHEDULER_THRESHOLD (3) + typedef struct write_thread_args_t { hailo_input_vstream input_vstream; uint8_t *src_data; @@ -192,7 +195,6 @@ int main() REQUIRE_SUCCESS(status, l_exit, "Failed init vdevice_params"); params.device_count = DEVICE_COUNT; - params.scheduling_algorithm = HAILO_SCHEDULING_ALGORITHM_ROUND_ROBIN; status = hailo_create_vdevice(¶ms, &vdevice); REQUIRE_SUCCESS(status, l_exit, "Failed to create vdevice"); @@ -209,6 +211,15 @@ int main() REQUIRE_ACTION(network_groups_size == 1, status = HAILO_INVALID_ARGUMENT, l_release_hef, "Unexpected network group size"); + // Set scheduler's timeout and threshold for the first network group, in order to give priority to the second network group + if (0 == hef_index) { + status = hailo_set_scheduler_timeout(network_groups[hef_index], SCHEDULER_TIMEOUT_MS, NULL); + REQUIRE_SUCCESS(status, l_release_hef, "Failed setting scheduler timeout"); + + status = hailo_set_scheduler_threshold(network_groups[hef_index], SCHEDULER_THRESHOLD, NULL); + REQUIRE_SUCCESS(status, l_release_hef, "Failed setting scheduler threshold"); + } + status = build_vstreams(network_groups[hef_index], input_vstreams[hef_index], input_frame_size[hef_index], src_data[hef_index], output_vstreams[hef_index], output_frame_size[hef_index], dst_data[hef_index], diff --git a/hailort/libhailort/examples/c/switch_network_groups_manually_example/CMakeLists.txt b/hailort/libhailort/examples/c/switch_network_groups_manually_example/CMakeLists.txt new file mode 100644 index 0000000..dadc4b2 --- /dev/null +++ b/hailort/libhailort/examples/c/switch_network_groups_manually_example/CMakeLists.txt @@ -0,0 +1,20 @@ +cmake_minimum_required(VERSION 3.0.0) + +find_package(Threads REQUIRED) +set(THREADS_PREFER_PTHREAD_FLAG ON) + +find_package(HailoRT 4.12.0 EXACT REQUIRED) + +SET_SOURCE_FILES_PROPERTIES(switch_network_groups_manually_example.c PROPERTIES LANGUAGE C) + +add_executable(c_switch_network_groups_manually_example switch_network_groups_manually_example.c) +target_link_libraries(c_switch_network_groups_manually_example PRIVATE HailoRT::libhailort Threads::Threads) +target_include_directories(c_switch_network_groups_manually_example PRIVATE "${CMAKE_CURRENT_LIST_DIR}/../common") + +if(WIN32) + target_compile_options(c_switch_network_groups_manually_example PRIVATE + /DWIN32_LEAN_AND_MEAN + /DNOMINMAX # NOMINMAX is required in order to play nice with std::min/std::max (otherwise Windows.h defines it's own) + /wd4201 /wd4251 + ) +endif() \ No newline at end of file diff --git a/hailort/libhailort/examples/c/switch_single_io_network_groups_manually_example.c b/hailort/libhailort/examples/c/switch_network_groups_manually_example/switch_network_groups_manually_example.c similarity index 99% rename from hailort/libhailort/examples/c/switch_single_io_network_groups_manually_example.c rename to hailort/libhailort/examples/c/switch_network_groups_manually_example/switch_network_groups_manually_example.c index 190d087..5d56190 100644 --- a/hailort/libhailort/examples/c/switch_single_io_network_groups_manually_example.c +++ b/hailort/libhailort/examples/c/switch_network_groups_manually_example/switch_network_groups_manually_example.c @@ -3,7 +3,7 @@ * Distributed under the MIT license (https://opensource.org/licenses/MIT) **/ /** - * @file switch_single_io_network_groups_manually_example.c + * @file switch_network_groups_manually_example.c * This example demonstrates basic usage of HailoRT streaming api over multiple network groups, using vstreams. * It loads several HEF networks with a single input and a single output into a Hailo VDevice and performs a inference on each one. * After inference is finished, the example switches to the next HEF and start inference again. @@ -180,6 +180,7 @@ int main() status = hailo_init_vdevice_params(¶ms); REQUIRE_SUCCESS(status, l_exit, "Failed init vdevice_params"); + params.scheduling_algorithm = HAILO_SCHEDULING_ALGORITHM_NONE; params.device_count = DEVICE_COUNT; status = hailo_create_vdevice(¶ms, &vdevice); REQUIRE_SUCCESS(status, l_exit, "Failed to create vdevice"); diff --git a/hailort/libhailort/examples/c/vstreams_example/CMakeLists.txt b/hailort/libhailort/examples/c/vstreams_example/CMakeLists.txt new file mode 100644 index 0000000..a9e007a --- /dev/null +++ b/hailort/libhailort/examples/c/vstreams_example/CMakeLists.txt @@ -0,0 +1,20 @@ +cmake_minimum_required(VERSION 3.0.0) + +find_package(Threads REQUIRED) +set(THREADS_PREFER_PTHREAD_FLAG ON) + +find_package(HailoRT 4.12.0 EXACT REQUIRED) + +SET_SOURCE_FILES_PROPERTIES(vstreams_example.c PROPERTIES LANGUAGE C) + +add_executable(c_vstreams_example vstreams_example.c) +target_link_libraries(c_vstreams_example PRIVATE HailoRT::libhailort Threads::Threads) +target_include_directories(c_vstreams_example PRIVATE "${CMAKE_CURRENT_LIST_DIR}/../common") + +if(WIN32) + target_compile_options(c_vstreams_example PRIVATE + /DWIN32_LEAN_AND_MEAN + /DNOMINMAX # NOMINMAX is required in order to play nice with std::min/std::max (otherwise Windows.h defines it's own) + /wd4201 /wd4251 + ) +endif() \ No newline at end of file diff --git a/hailort/libhailort/examples/c/vstreams_example.c b/hailort/libhailort/examples/c/vstreams_example/vstreams_example.c similarity index 94% rename from hailort/libhailort/examples/c/vstreams_example.c rename to hailort/libhailort/examples/c/vstreams_example/vstreams_example.c index e75ef41..04c5076 100644 --- a/hailort/libhailort/examples/c/vstreams_example.c +++ b/hailort/libhailort/examples/c/vstreams_example/vstreams_example.c @@ -135,7 +135,6 @@ int main() hailo_output_vstream_params_by_name_t output_vstream_params[MAX_EDGE_LAYERS] = {0}; size_t input_vstreams_size = MAX_EDGE_LAYERS; size_t output_vstreams_size = MAX_EDGE_LAYERS; - hailo_activated_network_group activated_network_group = NULL; hailo_input_vstream input_vstreams[MAX_EDGE_LAYERS] = {NULL}; hailo_output_vstream output_vstreams[MAX_EDGE_LAYERS] = {NULL}; @@ -172,16 +171,12 @@ int main() status = hailo_create_output_vstreams(network_group, output_vstream_params, output_vstreams_size, output_vstreams); REQUIRE_SUCCESS(status, l_release_input_vstream, "Failed creating output virtual streams\n"); - status = hailo_activate_network_group(network_group, NULL, &activated_network_group); - REQUIRE_SUCCESS(status, l_release_output_vstream, "Failed activate network group"); - status = infer(input_vstreams, input_vstreams_size, output_vstreams, output_vstreams_size); - REQUIRE_SUCCESS(status, l_deactivate_network_group, "Inference failure"); + REQUIRE_SUCCESS(status, l_release_output_vstream, "Inference failure"); printf("Inference ran successfully\n"); status = HAILO_SUCCESS; -l_deactivate_network_group: - (void)hailo_deactivate_network_group(activated_network_group); + l_release_output_vstream: (void)hailo_release_output_vstreams(output_vstreams, output_vstreams_size); l_release_input_vstream: diff --git a/hailort/libhailort/examples/cpp/CMakeLists.txt b/hailort/libhailort/examples/cpp/CMakeLists.txt index 60d822c..4dad532 100644 --- a/hailort/libhailort/examples/cpp/CMakeLists.txt +++ b/hailort/libhailort/examples/cpp/CMakeLists.txt @@ -1,33 +1,17 @@ cmake_minimum_required(VERSION 3.0.0) -add_executable(cpp_vstreams_example vstreams_example.cpp) -target_link_libraries(cpp_vstreams_example PRIVATE example_base) - -add_executable(cpp_infer_pipeline_example infer_pipeline_example.cpp) -target_link_libraries(cpp_infer_pipeline_example PRIVATE example_base) - -add_executable(cpp_raw_streams_example raw_streams_example.cpp) -target_link_libraries(cpp_raw_streams_example PRIVATE example_base) - -add_executable(cpp_multi_network_vstream_example multi_network_vstream_example.cpp) -target_link_libraries(cpp_multi_network_vstream_example PRIVATE example_base) - -add_executable(cpp_switch_network_groups_example switch_network_groups_example.cpp) -target_link_libraries(cpp_switch_network_groups_example PRIVATE example_base) - -add_executable(cpp_switch_network_groups_manually_example switch_network_groups_manually_example.cpp) -target_link_libraries(cpp_switch_network_groups_manually_example PRIVATE example_base) - -add_executable(cpp_multi_device_example multi_device_example.cpp) -target_link_libraries(cpp_multi_device_example PRIVATE example_base) - -add_executable(cpp_power_measurement_example power_measurement_example.cpp) -target_link_libraries(cpp_power_measurement_example PRIVATE example_base) - -add_executable(cpp_multi_process_example multi_process_example.cpp) -target_link_libraries(cpp_multi_process_example PRIVATE example_base) - -set(EXAMPLES_CPP_TARGETS +add_subdirectory(vstreams_example) +add_subdirectory(infer_pipeline_example) +add_subdirectory(raw_streams_example) +add_subdirectory(multi_network_vstream_example) +add_subdirectory(switch_network_groups_example) +add_subdirectory(switch_network_groups_manually_example) +add_subdirectory(multi_device_example) +add_subdirectory(power_measurement_example) +add_subdirectory(multi_process_example) + +add_custom_target(cpp_hailort_examples) +add_dependencies(cpp_hailort_examples cpp_vstreams_example cpp_infer_pipeline_example cpp_raw_streams_example @@ -36,5 +20,4 @@ set(EXAMPLES_CPP_TARGETS cpp_switch_network_groups_manually_example cpp_multi_device_example cpp_power_measurement_example - cpp_multi_process_example - PARENT_SCOPE) + cpp_multi_process_example) \ No newline at end of file diff --git a/hailort/libhailort/examples/cpp/infer_pipeline_example/CMakeLists.txt b/hailort/libhailort/examples/cpp/infer_pipeline_example/CMakeLists.txt new file mode 100644 index 0000000..94b0063 --- /dev/null +++ b/hailort/libhailort/examples/cpp/infer_pipeline_example/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.0.0) + +find_package(HailoRT 4.12.0 EXACT REQUIRED) + +add_executable(cpp_infer_pipeline_example infer_pipeline_example.cpp) +target_link_libraries(cpp_infer_pipeline_example PRIVATE HailoRT::libhailort) + +if(WIN32) + target_compile_options(cpp_infer_pipeline_example PRIVATE + /DWIN32_LEAN_AND_MEAN + /DNOMINMAX # NOMINMAX is required in order to play nice with std::min/std::max (otherwise Windows.h defines it's own) + /wd4201 /wd4251 + ) +endif() + +set_target_properties(cpp_infer_pipeline_example PROPERTIES CXX_STANDARD 14) diff --git a/hailort/libhailort/examples/cpp/infer_pipeline_example.cpp b/hailort/libhailort/examples/cpp/infer_pipeline_example/infer_pipeline_example.cpp similarity index 100% rename from hailort/libhailort/examples/cpp/infer_pipeline_example.cpp rename to hailort/libhailort/examples/cpp/infer_pipeline_example/infer_pipeline_example.cpp diff --git a/hailort/libhailort/examples/cpp/multi_device_example/CMakeLists.txt b/hailort/libhailort/examples/cpp/multi_device_example/CMakeLists.txt new file mode 100644 index 0000000..3a43db2 --- /dev/null +++ b/hailort/libhailort/examples/cpp/multi_device_example/CMakeLists.txt @@ -0,0 +1,19 @@ +cmake_minimum_required(VERSION 3.0.0) + +find_package(Threads REQUIRED) +set(THREADS_PREFER_PTHREAD_FLAG ON) + +find_package(HailoRT 4.12.0 EXACT REQUIRED) + +add_executable(cpp_multi_device_example multi_device_example.cpp) +target_link_libraries(cpp_multi_device_example PRIVATE HailoRT::libhailort Threads::Threads) + +if(WIN32) + target_compile_options(cpp_multi_device_example PRIVATE + /DWIN32_LEAN_AND_MEAN + /DNOMINMAX # NOMINMAX is required in order to play nice with std::min/std::max (otherwise Windows.h defines it's own) + /wd4201 /wd4251 + ) +endif() + +set_target_properties(cpp_multi_device_example PROPERTIES CXX_STANDARD 14) diff --git a/hailort/libhailort/examples/cpp/multi_device_example.cpp b/hailort/libhailort/examples/cpp/multi_device_example/multi_device_example.cpp similarity index 95% rename from hailort/libhailort/examples/cpp/multi_device_example.cpp rename to hailort/libhailort/examples/cpp/multi_device_example/multi_device_example.cpp index 02ee32a..c0334bc 100644 --- a/hailort/libhailort/examples/cpp/multi_device_example.cpp +++ b/hailort/libhailort/examples/cpp/multi_device_example/multi_device_example.cpp @@ -164,12 +164,6 @@ int main() return HAILO_INVALID_OPERATION; } - auto activated_network_group = network_group.value()->activate(); - if (!activated_network_group) { - std::cerr << "Failed activated network group " << activated_network_group.status(); - return activated_network_group.status(); - } - status = infer(vstreams->first, vstreams->second); if (HAILO_SUCCESS != status) { std::cerr << "Inference failed " << status << std::endl; diff --git a/hailort/libhailort/examples/cpp/multi_network_vstream_example/CMakeLists.txt b/hailort/libhailort/examples/cpp/multi_network_vstream_example/CMakeLists.txt new file mode 100644 index 0000000..95d4a76 --- /dev/null +++ b/hailort/libhailort/examples/cpp/multi_network_vstream_example/CMakeLists.txt @@ -0,0 +1,19 @@ +cmake_minimum_required(VERSION 3.0.0) + +find_package(Threads REQUIRED) +set(THREADS_PREFER_PTHREAD_FLAG ON) + +find_package(HailoRT 4.12.0 EXACT REQUIRED) + +add_executable(cpp_multi_network_vstream_example multi_network_vstream_example.cpp) +target_link_libraries(cpp_multi_network_vstream_example PRIVATE HailoRT::libhailort Threads::Threads) + +if(WIN32) + target_compile_options(cpp_multi_network_vstream_example PRIVATE + /DWIN32_LEAN_AND_MEAN + /DNOMINMAX # NOMINMAX is required in order to play nice with std::min/std::max (otherwise Windows.h defines it's own) + /wd4201 /wd4251 + ) +endif() + +set_target_properties(cpp_multi_network_vstream_example PROPERTIES CXX_STANDARD 14) diff --git a/hailort/libhailort/examples/cpp/multi_network_vstream_example.cpp b/hailort/libhailort/examples/cpp/multi_network_vstream_example/multi_network_vstream_example.cpp similarity index 98% rename from hailort/libhailort/examples/cpp/multi_network_vstream_example.cpp rename to hailort/libhailort/examples/cpp/multi_network_vstream_example/multi_network_vstream_example.cpp index eb52fb3..493393c 100644 --- a/hailort/libhailort/examples/cpp/multi_network_vstream_example.cpp +++ b/hailort/libhailort/examples/cpp/multi_network_vstream_example/multi_network_vstream_example.cpp @@ -194,6 +194,8 @@ int main() return status; } + /* Scheduler does not support different batches for different networks within the same network group */ + params.scheduling_algorithm = HAILO_SCHEDULING_ALGORITHM_NONE; params.device_count = DEVICE_COUNT; auto vdevice = VDevice::create(params); if (!vdevice) { diff --git a/hailort/libhailort/examples/cpp/multi_process_example/CMakeLists.txt b/hailort/libhailort/examples/cpp/multi_process_example/CMakeLists.txt new file mode 100644 index 0000000..731df0f --- /dev/null +++ b/hailort/libhailort/examples/cpp/multi_process_example/CMakeLists.txt @@ -0,0 +1,19 @@ +cmake_minimum_required(VERSION 3.0.0) + +find_package(Threads REQUIRED) +set(THREADS_PREFER_PTHREAD_FLAG ON) + +find_package(HailoRT 4.12.0 EXACT REQUIRED) + +add_executable(cpp_multi_process_example multi_process_example.cpp) +target_link_libraries(cpp_multi_process_example PRIVATE HailoRT::libhailort Threads::Threads) + +if(WIN32) + target_compile_options(cpp_multi_process_example PRIVATE + /DWIN32_LEAN_AND_MEAN + /DNOMINMAX # NOMINMAX is required in order to play nice with std::min/std::max (otherwise Windows.h defines it's own) + /wd4201 /wd4251 + ) +endif() + +set_target_properties(cpp_multi_process_example PROPERTIES CXX_STANDARD 14) \ No newline at end of file diff --git a/hailort/libhailort/examples/cpp/multi_process_example.cpp b/hailort/libhailort/examples/cpp/multi_process_example/multi_process_example.cpp similarity index 98% rename from hailort/libhailort/examples/cpp/multi_process_example.cpp rename to hailort/libhailort/examples/cpp/multi_process_example/multi_process_example.cpp index 6040507..bb5323d 100644 --- a/hailort/libhailort/examples/cpp/multi_process_example.cpp +++ b/hailort/libhailort/examples/cpp/multi_process_example/multi_process_example.cpp @@ -127,7 +127,6 @@ Expected> create_vdevice() std::cerr << "Failed init vdevice_params, status = " << status << std::endl; return make_unexpected(status); } - params.scheduling_algorithm = HAILO_SCHEDULING_ALGORITHM_ROUND_ROBIN; params.device_count = DEVICE_COUNT; params.multi_process_service = true; params.group_id = "SHARED"; diff --git a/hailort/libhailort/examples/cpp/multi_process_example.sh b/hailort/libhailort/examples/cpp/multi_process_example/multi_process_example.sh similarity index 67% rename from hailort/libhailort/examples/cpp/multi_process_example.sh rename to hailort/libhailort/examples/cpp/multi_process_example/multi_process_example.sh index 7d1386b..7b7e6fd 100755 --- a/hailort/libhailort/examples/cpp/multi_process_example.sh +++ b/hailort/libhailort/examples/cpp/multi_process_example/multi_process_example.sh @@ -7,6 +7,7 @@ readonly default_processes_count=1 function print_usage { echo "Usage: [-h help] [-n] [-m]" + echo "Before running the example, make sure the HailoRT service is enabled and active. See HailoRT user guide to understand how to enable and start the service." echo " -h Print usage and exit" echo " -n Number of processes to run example with $first_hef. Max is $max_processes_count (defualt is $default_processes_count)" echo " -m Number of processes to run example with $second_hef. Max is $max_processes_count (defualt is $default_processes_count)" @@ -35,35 +36,17 @@ then exit 1 fi -# Check service is enabled -service hailort status | grep 'disabled;' > /dev/null 2>&1 -if [ $? == 0 ] -then - echo "HailoRT service is not enabled." - echo "To enable and start the service run the following command: 'sudo systemctl enable --now hailort.service'" - exit 1 -fi - -# Check service is active -service hailort status | grep 'active (running)' > /dev/null 2>&1 -if [ $? != 0 ] -then - echo "HailoRT service is not active." - echo "To start the service run the following command: 'sudo systemctl start hailort.service'" - exit 1 -fi - max=$(( $first_hef_count > $second_hef_count ? $first_hef_count : $second_hef_count )) for i in $(seq 0 $max) do if (( $i < $first_hef_count)) then - ./build/cpp/cpp_multi_process_example $first_hef & + ./build/cpp/multi_process_example/cpp_multi_process_example $first_hef & fi if (( $i < $second_hef_count)) then - ./build/cpp/cpp_multi_process_example $second_hef & + ./build/cpp/multi_process_example/cpp_multi_process_example $second_hef & fi done diff --git a/hailort/libhailort/examples/cpp/power_measurement_example/CMakeLists.txt b/hailort/libhailort/examples/cpp/power_measurement_example/CMakeLists.txt new file mode 100644 index 0000000..e223d91 --- /dev/null +++ b/hailort/libhailort/examples/cpp/power_measurement_example/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.0.0) + +find_package(HailoRT 4.12.0 EXACT REQUIRED) + +add_executable(cpp_power_measurement_example power_measurement_example.cpp) +target_link_libraries(cpp_power_measurement_example PRIVATE HailoRT::libhailort) + +if(WIN32) + target_compile_options(cpp_power_measurement_example PRIVATE + /DWIN32_LEAN_AND_MEAN + /DNOMINMAX # NOMINMAX is required in order to play nice with std::min/std::max (otherwise Windows.h defines it's own) + /wd4201 /wd4251 + ) +endif() + +set_target_properties(cpp_power_measurement_example PROPERTIES CXX_STANDARD 14) \ No newline at end of file diff --git a/hailort/libhailort/examples/cpp/power_measurement_example.cpp b/hailort/libhailort/examples/cpp/power_measurement_example/power_measurement_example.cpp similarity index 97% rename from hailort/libhailort/examples/cpp/power_measurement_example.cpp rename to hailort/libhailort/examples/cpp/power_measurement_example/power_measurement_example.cpp index 21c5ce2..f3d3d18 100644 --- a/hailort/libhailort/examples/cpp/power_measurement_example.cpp +++ b/hailort/libhailort/examples/cpp/power_measurement_example/power_measurement_example.cpp @@ -83,6 +83,9 @@ int main(int argc, char **argv) return status; } + /* Scheduler over multiple devices is currently not supported */ + params.scheduling_algorithm = HAILO_SCHEDULING_ALGORITHM_NONE; + params.device_count = static_cast(scan_res->size()); auto vdevice = VDevice::create(params); if (!vdevice) { diff --git a/hailort/libhailort/examples/cpp/raw_streams_example/CMakeLists.txt b/hailort/libhailort/examples/cpp/raw_streams_example/CMakeLists.txt new file mode 100644 index 0000000..9385394 --- /dev/null +++ b/hailort/libhailort/examples/cpp/raw_streams_example/CMakeLists.txt @@ -0,0 +1,19 @@ +cmake_minimum_required(VERSION 3.0.0) + +find_package(Threads REQUIRED) +set(THREADS_PREFER_PTHREAD_FLAG ON) + +find_package(HailoRT 4.12.0 EXACT REQUIRED) + +add_executable(cpp_raw_streams_example raw_streams_example.cpp) +target_link_libraries(cpp_raw_streams_example PRIVATE HailoRT::libhailort Threads::Threads) + +if(WIN32) + target_compile_options(cpp_raw_streams_example PRIVATE + /DWIN32_LEAN_AND_MEAN + /DNOMINMAX # NOMINMAX is required in order to play nice with std::min/std::max (otherwise Windows.h defines it's own) + /wd4201 /wd4251 + ) +endif() + +set_target_properties(cpp_raw_streams_example PROPERTIES CXX_STANDARD 14) \ No newline at end of file diff --git a/hailort/libhailort/examples/cpp/raw_streams_example.cpp b/hailort/libhailort/examples/cpp/raw_streams_example/raw_streams_example.cpp similarity index 100% rename from hailort/libhailort/examples/cpp/raw_streams_example.cpp rename to hailort/libhailort/examples/cpp/raw_streams_example/raw_streams_example.cpp diff --git a/hailort/libhailort/examples/cpp/switch_network_groups_example/CMakeLists.txt b/hailort/libhailort/examples/cpp/switch_network_groups_example/CMakeLists.txt new file mode 100644 index 0000000..b22e8c2 --- /dev/null +++ b/hailort/libhailort/examples/cpp/switch_network_groups_example/CMakeLists.txt @@ -0,0 +1,19 @@ +cmake_minimum_required(VERSION 3.0.0) + +find_package(Threads REQUIRED) +set(THREADS_PREFER_PTHREAD_FLAG ON) + +find_package(HailoRT 4.12.0 EXACT REQUIRED) + +add_executable(cpp_switch_network_groups_example switch_network_groups_example.cpp) +target_link_libraries(cpp_switch_network_groups_example PRIVATE HailoRT::libhailort Threads::Threads) + +if(WIN32) + target_compile_options(cpp_switch_network_groups_example PRIVATE + /DWIN32_LEAN_AND_MEAN + /DNOMINMAX # NOMINMAX is required in order to play nice with std::min/std::max (otherwise Windows.h defines it's own) + /wd4201 /wd4251 + ) +endif() + +set_target_properties(cpp_switch_network_groups_example PROPERTIES CXX_STANDARD 14) \ No newline at end of file diff --git a/hailort/libhailort/examples/cpp/switch_network_groups_example.cpp b/hailort/libhailort/examples/cpp/switch_network_groups_example/switch_network_groups_example.cpp similarity index 87% rename from hailort/libhailort/examples/cpp/switch_network_groups_example.cpp rename to hailort/libhailort/examples/cpp/switch_network_groups_example/switch_network_groups_example.cpp index b100228..6c65417 100644 --- a/hailort/libhailort/examples/cpp/switch_network_groups_example.cpp +++ b/hailort/libhailort/examples/cpp/switch_network_groups_example/switch_network_groups_example.cpp @@ -19,6 +19,9 @@ constexpr hailo_format_type_t FORMAT_TYPE = HAILO_FORMAT_TYPE_AUTO; constexpr size_t INFER_FRAME_COUNT = 100; constexpr uint32_t DEVICE_COUNT = 1; +constexpr std::chrono::milliseconds SCHEDULER_TIMEOUT_MS(100); +constexpr uint32_t SCHEDULER_THRESHOLD = 3; + using namespace hailort; using ThreadsVector = std::vector>; using StatusVector = std::vector>; @@ -92,7 +95,6 @@ Expected> create_vdevice() std::cerr << "Failed init vdevice_params, status = " << status << std::endl; return make_unexpected(status); } - params.scheduling_algorithm = HAILO_SCHEDULING_ALGORITHM_ROUND_ROBIN; params.device_count = DEVICE_COUNT; return VDevice::create(params); @@ -136,6 +138,19 @@ int main() } auto configured_network_groups = configured_network_groups_exp.release(); + // Set scheduler's timeout and threshold for the first network group, in order to give priority to the second network group + auto status = configured_network_groups[0]->set_scheduler_timeout(SCHEDULER_TIMEOUT_MS); + if (HAILO_SUCCESS != status) { + std::cerr << "Failed to set scheduler timeout, status = " << status << std::endl; + return status; + } + + status = configured_network_groups[0]->set_scheduler_threshold(SCHEDULER_THRESHOLD); + if (HAILO_SUCCESS != status) { + std::cerr << "Failed to set scheduler threshold, status = " << status << std::endl; + return status; + } + auto vstreams_per_network_group_exp = build_vstreams(configured_network_groups); if (!vstreams_per_network_group_exp) { std::cerr << "Failed to create vstreams, status = " << vstreams_per_network_group_exp.status() << std::endl; @@ -158,10 +173,10 @@ int main() thread->join(); } } - for (auto &status : results) { - if (HAILO_SUCCESS != *status) { - std::cerr << "Inference failed, status = " << *status << std::endl; - return *status; + for (auto &status_ptr : results) { + if (HAILO_SUCCESS != *status_ptr) { + std::cerr << "Inference failed, status = " << *status_ptr << std::endl; + return *status_ptr; } } diff --git a/hailort/libhailort/examples/cpp/switch_network_groups_manually_example/CMakeLists.txt b/hailort/libhailort/examples/cpp/switch_network_groups_manually_example/CMakeLists.txt new file mode 100644 index 0000000..dcc325d --- /dev/null +++ b/hailort/libhailort/examples/cpp/switch_network_groups_manually_example/CMakeLists.txt @@ -0,0 +1,19 @@ +cmake_minimum_required(VERSION 3.0.0) + +find_package(Threads REQUIRED) +set(THREADS_PREFER_PTHREAD_FLAG ON) + +find_package(HailoRT 4.12.0 EXACT REQUIRED) + +add_executable(cpp_switch_network_groups_manually_example switch_network_groups_manually_example.cpp) +target_link_libraries(cpp_switch_network_groups_manually_example PRIVATE HailoRT::libhailort Threads::Threads) + +if(WIN32) + target_compile_options(cpp_switch_network_groups_manually_example PRIVATE + /DWIN32_LEAN_AND_MEAN + /DNOMINMAX # NOMINMAX is required in order to play nice with std::min/std::max (otherwise Windows.h defines it's own) + /wd4201 /wd4251 + ) +endif() + +set_target_properties(cpp_switch_network_groups_manually_example PROPERTIES CXX_STANDARD 14) \ No newline at end of file diff --git a/hailort/libhailort/examples/cpp/switch_network_groups_manually_example.cpp b/hailort/libhailort/examples/cpp/switch_network_groups_manually_example/switch_network_groups_manually_example.cpp similarity index 99% rename from hailort/libhailort/examples/cpp/switch_network_groups_manually_example.cpp rename to hailort/libhailort/examples/cpp/switch_network_groups_manually_example/switch_network_groups_manually_example.cpp index 7155e91..26d890d 100644 --- a/hailort/libhailort/examples/cpp/switch_network_groups_manually_example.cpp +++ b/hailort/libhailort/examples/cpp/switch_network_groups_manually_example/switch_network_groups_manually_example.cpp @@ -211,6 +211,7 @@ int main() return status; } + params.scheduling_algorithm = HAILO_SCHEDULING_ALGORITHM_NONE; params.device_count = DEVICE_COUNT; auto vdevice_exp = VDevice::create(params); if (!vdevice_exp) { diff --git a/hailort/libhailort/examples/cpp/vstreams_example/CMakeLists.txt b/hailort/libhailort/examples/cpp/vstreams_example/CMakeLists.txt new file mode 100644 index 0000000..9eb8bf6 --- /dev/null +++ b/hailort/libhailort/examples/cpp/vstreams_example/CMakeLists.txt @@ -0,0 +1,19 @@ +cmake_minimum_required(VERSION 3.0.0) + +find_package(Threads REQUIRED) +set(THREADS_PREFER_PTHREAD_FLAG ON) + +find_package(HailoRT 4.12.0 EXACT REQUIRED) + +add_executable(cpp_vstreams_example vstreams_example.cpp) +target_link_libraries(cpp_vstreams_example PRIVATE HailoRT::libhailort Threads::Threads) + +if(WIN32) + target_compile_options(cpp_vstreams_example PRIVATE + /DWIN32_LEAN_AND_MEAN + /DNOMINMAX # NOMINMAX is required in order to play nice with std::min/std::max (otherwise Windows.h defines it's own) + /wd4201 /wd4251 + ) +endif() + +set_target_properties(cpp_vstreams_example PROPERTIES CXX_STANDARD 14) \ No newline at end of file diff --git a/hailort/libhailort/examples/cpp/vstreams_example.cpp b/hailort/libhailort/examples/cpp/vstreams_example/vstreams_example.cpp similarity index 95% rename from hailort/libhailort/examples/cpp/vstreams_example.cpp rename to hailort/libhailort/examples/cpp/vstreams_example/vstreams_example.cpp index 5488e14..9e93cac 100644 --- a/hailort/libhailort/examples/cpp/vstreams_example.cpp +++ b/hailort/libhailort/examples/cpp/vstreams_example/vstreams_example.cpp @@ -150,12 +150,6 @@ int main() return HAILO_INVALID_OPERATION; } - auto activated_network_group = network_group.value()->activate(); - if (!activated_network_group) { - std::cerr << "Failed activated network group " << activated_network_group.status(); - return activated_network_group.status(); - } - auto status = infer(vstreams->first, vstreams->second); if (HAILO_SUCCESS != status) { std::cerr << "Inference failed " << status << std::endl; diff --git a/hailort/libhailort/hef.proto b/hailort/libhailort/hef.proto index 80aa2e8..9334b33 100644 --- a/hailort/libhailort/hef.proto +++ b/hailort/libhailort/hef.proto @@ -36,6 +36,8 @@ enum ProtoHEFExtensionType { OFFLOAD_ARGMAX = 10; HW_PADDING = 11; KO_RUN_ASAP = 12; + HAILO_NET_FLOW = 13; + HAILO_NET_FLOW_YOLO_NMS = 14; UNUSED = 0XFFFF; } @@ -84,12 +86,190 @@ message ProtoHEFPhysicalLayout { uint32 partial_clusters_layout_bitmap = 1; }; +// For backwards compatability message ProtoHEFPartialNetworkGroup { ProtoHEFNetworkGroup network_group = 1; ProtoHEFPhysicalLayout layout = 2; }; +message ProtoHEFPartialCoreOp { + ProtoHEFCoreOp core_op = 1; + ProtoHEFPhysicalLayout layout = 2; +}; + +message ProtoHEFCoreOp { + // Metadata describing the network_group + ProtoHEFNetworkGroupMetadata network_group_metadata = 1; + + // The preliminary configuration of the network_group + ProtoHEFPreliminaryConfig preliminary_config = 2; + + // The contexts of the network_group + repeated ProtoHEFContext contexts = 3; + + // List of sorted output names according to their order + repeated string sorted_outputs_order = 4; + + // Metadata for fused layers + ProtoHEFFusedLayersMetadata fused_layers_metadata = 5; + + // Connected component names ordered by index + repeated string networks_names = 6; + + // Partial core ops + repeated ProtoHEFPartialCoreOp partial_core_ops = 7; +}; + +message ProtoHEFYoloBboxDecoder { + // List of Height coordinates (given as fraction of input size), defining each box dimensions around the anchor coordinates + repeated uint32 h = 2; + + // List of Width coordinates (given as fraction of input size), defining each box dimensions around the anchor coordinates + repeated uint32 w = 3; + + // Pixels stride for given bbox + uint32 stride = 4; + + // Index of the pad connected to the layer in the decoder + uint32 pad_index = 5; +}; + +message ProtoHEFYoloNmsOp { + // Input image dimensions + double image_height = 1; + double image_width = 2; + + // Division factor of proposals sent to the NMS per class, instead of running NMS on all proposal together + uint32 input_division_factor = 3; + + // List of bbox decoders (anchors) for the NMS layer. Each model has its own number of boxes per anchor + repeated ProtoHEFYoloBboxDecoder bbox_decoders = 4; +}; + +message ProtoHEFNmsOp { + // NMS score threshold + double nms_score_th = 1; + + // NMS IOU threshold + double nms_iou_th = 2; + + // Fixed number of outputs allowed in this model + uint32 max_proposals_per_class = 3; + + // Number of detected classes + uint32 classes = 4; + + // Toggle background class removal from results + bool background_removal = 5; + + // Index of background class for background removal + uint32 background_removal_index = 6; + + // Additional information needed for specific NMS types + oneof nms_op { + ProtoHEFYoloNmsOp yolo_nms_op = 7; + } +}; + +enum ProtoHEFFormatOrder { + PROTO__FORMAT__ORDER__AUTO = 0; + PROTO__FORMAT__ORDER__NHWC = 1; + PROTO__FORMAT__ORDER__NHCW = 2; + PROTO__FORMAT__ORDER__FCR = 3; + PROTO__FORMAT__ORDER__F8CR = 4; + PROTO__FORMAT__ORDER__NHW = 5; + PROTO__FORMAT__ORDER__NC = 6; + PROTO__FORMAT__ORDER__BAYER_RGB = 7; + PROTO__FORMAT__ORDER__12_BIT_BAYER_RGB = 8; + PROTO__FORMAT__ORDER__HAILO_NMS = 9; + PROTO__FORMAT__ORDER__RGB888 = 10; + PROTO__FORMAT__ORDER__NCHW = 11; + PROTO__FORMAT__ORDER__YUY2 = 12; + PROTO__FORMAT__ORDER__NV12 = 13; + PROTO__FORMAT__ORDER__NV21 = 14; + PROTO__FORMAT__ORDER__HAILO_YYUV = 15; + PROTO__FORMAT__ORDER__HAILO_YYVU = 16; + PROTO__FORMAT__ORDER__MAX_ENUM = 0XFFFF; +}; + +enum ProtoHEFDataType { + PROTO__UINT8 = 0; + PROTO__UINT16 = 1; +}; + +message ProtoHEFTensorShape { + uint32 height = 1; + uint32 padded_height = 2; + uint32 width = 3; + uint32 padded_width = 4; + uint32 features = 5; + uint32 padded_features = 6; +} + +message ProtoHEFNmsShape { + // Amount of NMS classes + uint32 number_of_classes = 1; + // Maximum amount of bboxes per nms class + uint32 max_bboxes_per_class = 2; + // Internal usage + uint32 bbox_size = 3; + // Internal usage + uint32 division_factor = 4; +} + +message ProtoHEFPad { + // Pad's unique index + uint32 index = 1; + + // Pad's name, can be empty of meaningful + string name = 2; + + // Additional information describing the data going through this pad's interface + ProtoHEFFormatOrder format = 3; + ProtoHEFDataType data_bytes = 4; + ProtoHEFEdgeLayerNumericInfo numeric_info = 5; + oneof shape_info { + ProtoHEFTensorShape tensor_shape = 6; + ProtoHEFNmsShape nms_shape = 7; + } +}; + +message ProtoHEFOp { + string name = 1; + + // The interfaces between different Ops + repeated ProtoHEFPad input_pads = 2; + repeated ProtoHEFPad output_pads = 3; + + // Op's type + oneof op { + // Op type for a subgraph that is running on Hailo's core + ProtoHEFCoreOp core_op = 4; + + // Op type for NMS post-processing + ProtoHEFNmsOp nms_op = 5; + } +}; + +message ProtoHEFPadEdge { + uint32 src = 1; + uint32 dst = 2; +}; + message ProtoHEFNetworkGroup { + // Ops of Hailo's computational graph + repeated ProtoHEFOp ops = 8; + + // Edges of Hailo's computational graph + repeated ProtoHEFPadEdge pad_edges = 9; + + // The name of the network_group + string network_group_name = 10; + + // The index of the network_group (execution order) + uint32 network_group_index = 11; + + // For backwards compatability: // Metadata describing the network_group ProtoHEFNetworkGroupMetadata network_group_metadata = 1; @@ -240,6 +420,7 @@ message ProtoHEFAction { ProtoHEFActionAllowInputDataflow allow_input_dataflow = 10; ProtoHEFActionWaitForModuleConfigDone wait_for_module_config_done = 11; ProtoHEFActionDebugSleep debug_sleep = 12; + ProtoHEFActionEnableNMS enable_nms = 13; } } @@ -342,6 +523,14 @@ message ProtoHEFActionEnableLcu { uint32 network_index = 6; } +message ProtoHEFActionEnableNMS { + // Index of the nms unit + uint32 nms_unit_index = 1; + + // Index of the network + uint32 network_index = 2; +} + // None action - Do not do anything message ProtoHEFActionNone { } @@ -404,6 +593,7 @@ message ProtoHEFEdgeLayer { }; ProtoHEFContextSwitchInformation context_switch_info = 5; uint32 network_index = 6; + optional uint32 pad_index = 7; // In case of boundery } // Enum indicating the direction of the edge layer diff --git a/hailort/libhailort/include/hailo/device.hpp b/hailort/libhailort/include/hailo/device.hpp index 2fb1521..8896a44 100644 --- a/hailort/libhailort/include/hailo/device.hpp +++ b/hailort/libhailort/include/hailo/device.hpp @@ -344,51 +344,6 @@ public: */ Expected power_measurement(hailo_dvm_options_t dvm, hailo_power_measurement_types_t measurement_type); - /** - * Start performing a long power measurement. - * - * @param[in] unused Unused parameter. - * This time period is sleep time of the core. - * @param[in] averaging_factor Number of samples per time period, sensor configuration value. - * @param[in] sampling_period Related conversion time, sensor configuration value. - * The sensor samples the power every sampling_period {ms} and averages every - * averaging_factor samples. The sensor provides a new value every: 2 * sampling_period * averaging_factor {ms}. - * The firmware wakes up every interval_milliseconds {ms} and checks the sensor. - * If there is a new value to read from the sensor, the firmware reads it. - * Note that the average calculated by the firmware is 'average of averages', - * because it averages values that have already been averaged by the sensor. - * @return Upon success, returns ::HAILO_SUCCESS. Otherwise, returns a ::hailo_status error. - * @note This function is deprecated. One should use 'Device::start_power_measurement(hailo_averaging_factor_t averaging_factor, hailo_sampling_period_t sampling_period)' - */ - hailo_status start_power_measurement(uint32_t unused, hailo_averaging_factor_t averaging_factor, hailo_sampling_period_t sampling_period); - - /** - * Set parameters for long power measurement. - * - * @param[in] index Index of the buffer on the firmware the data would be saved at. - * @param[in] dvm Which DVM will be measured. Default (::HAILO_DVM_OPTIONS_AUTO) will be different according to the board:
- * - Default (::HAILO_DVM_OPTIONS_AUTO) for EVB is an approximation to the total power consumption of the chip in PCIe setups. - * It sums ::HAILO_DVM_OPTIONS_VDD_CORE, ::HAILO_DVM_OPTIONS_MIPI_AVDD and ::HAILO_DVM_OPTIONS_AVDD_H. - * Only ::HAILO_POWER_MEASUREMENT_TYPES__POWER can measured with this option. - * - Default (::HAILO_DVM_OPTIONS_AUTO) for platforms supporting current monitoring (such as M.2 and mPCIe): OVERCURRENT_PROTECTION. - * @param[in] measurement_type The type of the measurement. Choosing ::HAILO_POWER_MEASUREMENT_TYPES__AUTO - * will select the default value according to the supported features. - * @return Upon success, returns ::HAILO_SUCCESS. Otherwise, returns a ::hailo_status error. - * @note This function is deprecated. One should use 'Device::set_power_measurement(hailo_measurement_buffer_index_t buffer_index, hailo_dvm_options_t dvm, hailo_power_measurement_types_t measurement_type)' - */ - hailo_status set_power_measurement(uint32_t index, hailo_dvm_options_t dvm, hailo_power_measurement_types_t measurement_type); - - /** - * Read measured power from a long power measurement - * - * @param[in] index Index of the buffer on the firmware the data would be saved at. - * @param[in] should_clear Flag indicating if the results saved at the firmware will be deleted after reading. - * @return Upon success, returns @a hailo_power_measurement_data_t. Measured units are determined due to ::hailo_power_measurement_types_t - * passed to 'Device::set_power_measurement'. Otherwise, returns a ::hailo_status error. - * @note This function is deprecated. One should use "Device::get_power_measurement(hailo_measurement_buffer_index_t buffer_index, bool should_clear)' - */ - Expected get_power_measurement(uint32_t index, bool should_clear); - /** * Start performing a long power measurement. * @@ -487,6 +442,15 @@ public: */ hailo_status test_chip_memories(); + /** + * Set chip sleep state.. + * @note This is an advanced API. Please be advised not to use this API, unless supported by Hailo. + * + * @param[in] sleep_state The requested sleep state of the chip + * @return Upon success, returns ::HAILO_SUCCESS. Otherwise, returns a ::hailo_status error. + */ + hailo_status set_sleep_state(hailo_sleep_state_t sleep_state); + /** * Update the firmware of a Hailo device. * @@ -690,13 +654,19 @@ public: hailo_status set_overcurrent_state(bool should_activate); Expected get_overcurrent_state(); Expected get_health_information(); - // Returns a vector of the number of contexts per network group (preliminary + dynamic) + // Returns a vector of the number of dynamic contexts per network group // The sum of the number of contexts will fit in uint8_t - Expected> get_number_of_contexts_per_network_group(); - Expected download_context_action_list(uint8_t context_index, uint32_t *base_address, - uint32_t *batch_counter, uint16_t max_size = 10000); + Expected> get_number_of_dynamic_contexts_per_network_group(); + Expected download_context_action_list(uint32_t network_group_id, uint8_t context_type, + uint8_t context_index, uint32_t *base_address, uint32_t *batch_counter, uint16_t max_size = 10000); // The batch configured is reset between network groups hailo_status set_context_action_list_timestamp_batch(uint16_t batch_index); + hailo_status set_context_switch_breakpoint(uint8_t breakpoint_id, bool break_at_any_network_group_index, + uint8_t network_group_index, bool break_at_any_batch_index, uint16_t batch_index, bool break_at_any_context_index, + uint8_t context_index, bool break_at_any_action_index, uint16_t action_index); + hailo_status continue_context_switch_breakpoint(uint8_t breakpoint_id); + hailo_status clear_context_switch_breakpoint(uint8_t breakpoint_id); + Expected get_context_switch_breakpoint_status(uint8_t breakpoint_id); virtual ~Device() = default; Device(const Device &) = delete; diff --git a/hailort/libhailort/include/hailo/hailort.h b/hailort/libhailort/include/hailo/hailort.h index 746e374..a66cb12 100644 --- a/hailort/libhailort/include/hailo/hailort.h +++ b/hailort/libhailort/include/hailo/hailort.h @@ -48,7 +48,7 @@ extern "C" { #define HAILO_DEFAULT_BUFFERS_THRESHOLD (0) #define HAILO_DEFAULT_MAX_ETHERNET_BANDWIDTH_BYTES_PER_SEC (106300000) #define HAILO_MAX_STREAMS_COUNT (32) -#define HAILO_DEFAULT_BATCH_SIZE (1) +#define HAILO_DEFAULT_BATCH_SIZE (0) #define HAILO_MAX_NETWORK_GROUPS (8) #define HAILO_MAX_NETWORK_GROUP_NAME_SIZE (HAILO_MAX_NAME_SIZE) /* Network name is always attached to network group name with '/' separator */ @@ -68,7 +68,6 @@ extern "C" { #define HAILO_UNIQUE_VDEVICE_GROUP_ID ("UNIQUE") #define HAILO_DEFAULT_VDEVICE_GROUP_ID HAILO_UNIQUE_VDEVICE_GROUP_ID - typedef float float32_t; typedef double float64_t; typedef uint16_t nms_bbox_counter_t; @@ -137,8 +136,8 @@ typedef uint16_t nms_bbox_counter_t; HAILO_STATUS__X(59, HAILO_THREAD_NOT_ACTIVATED /*!< The given thread has not been activated */)\ HAILO_STATUS__X(60, HAILO_THREAD_NOT_JOINABLE /*!< The given thread is not joinable */)\ HAILO_STATUS__X(61, HAILO_NOT_FOUND /*!< Could not find element */)\ - HAILO_STATUS__X(62, HAILO_STREAM_ABORTED /*!< Stream aborted due to an external event */)\ - HAILO_STATUS__X(63, HAILO_STREAM_INTERNAL_ABORT /*!< Stream recv/send was aborted */)\ + HAILO_STATUS__X(62, HAILO_STREAM_ABORTED_BY_HW /*!< Stream aborted due to an external event */)\ + HAILO_STATUS__X(63, HAILO_STREAM_ABORTED_BY_USER /*!< Stream recv/send was aborted */)\ HAILO_STATUS__X(64, HAILO_PCIE_DRIVER_NOT_INSTALLED /*!< Pcie driver is not installed */)\ HAILO_STATUS__X(65, HAILO_NOT_AVAILABLE /*!< Component is not available */)\ HAILO_STATUS__X(66, HAILO_TRAFFIC_CONTROL_FAILURE /*!< Traffic control failure */)\ @@ -154,6 +153,7 @@ typedef uint16_t nms_bbox_counter_t; HAILO_STATUS__X(76, HAILO_INVALID_DRIVER_VERSION /*!< Invalid driver version */)\ HAILO_STATUS__X(77, HAILO_RPC_FAILED /*!< RPC failed */)\ HAILO_STATUS__X(78, HAILO_INVALID_SERVICE_VERSION /*!< Invalid service version */)\ + HAILO_STATUS__X(79, HAILO_NOT_SUPPORTED /*!< Not supported operation */)\ typedef enum { #define HAILO_STATUS__X(value, name) name = value, @@ -167,6 +167,9 @@ typedef enum { HAILO_STATUS_MAX_ENUM = HAILO_MAX_ENUM } hailo_status; +#define HAILO_STREAM_ABORTED HAILO_STREAM_ABORTED_BY_HW /* 'HAILO_STREAM_ABORTED' is deprecated. One should use 'HAILO_STREAM_ABORTED_BY_HW' */ +#define HAILO_STREAM_INTERNAL_ABORT HAILO_STREAM_ABORTED_BY_USER /* 'HAILO_STREAM_INTERNAL_ABORT' is deprecated. One should use 'HAILO_STREAM_ABORTED_BY_USER' */ + /** HailoRT library version */ typedef struct { uint32_t major; @@ -375,24 +378,14 @@ typedef enum hailo_scheduling_algorithm_e { /** Virtual device parameters */ typedef struct { /** - * Requested number of physical devices. if @a device_ids is not NULL, or @a device_infos is not NULL represents - * the number of ::hailo_device_id_t in @a device_ids or the number of ::hailo_pcie_device_info_t in - * @a device_infos. + * Requested number of physical devices. if @a device_ids is not NULL represents + * the number of ::hailo_device_id_t in @a device_ids. */ uint32_t device_count; /** - * This param is deprecated. One should use 'device_ids'. - * Specific physical devices information to create the vdevice from. If NULL, the vdevice will try to occupy + * Specific device ids to create the vdevice from. If NULL, the vdevice will try to occupy * devices from the available pool. - * This parameter cannot be used together with @a device_ids. - */ - hailo_pcie_device_info_t *device_infos DEPRECATED("'device_infos' param is deprecated. One should use 'device_ids'"); - - /** - * Specific device ids to create the vdevice from. If NULL, the vdevice the vdevice will try to occupy - * devices from the available pool. - * This parameter cannot be used together with @a device_infos. */ hailo_device_id_t *device_ids; @@ -439,6 +432,7 @@ typedef struct { uint8_t board_name_length; char board_name[HAILO_MAX_BOARD_NAME_LENGTH]; bool is_release; + bool extended_context_switch_buffer; hailo_device_architecture_t device_architecture; uint8_t serial_number_length; char serial_number[HAILO_MAX_SERIAL_NUMBER_LENGTH]; @@ -450,6 +444,7 @@ typedef struct { typedef struct { bool is_release; + bool extended_context_switch_buffer; hailo_firmware_version_t fw_version; } hailo_core_information_t; @@ -683,6 +678,13 @@ typedef enum { */ HAILO_FORMAT_ORDER_HAILO_YYVU = 16, + /** + * RGB, where every row is padded to 4. + * - Host side: [N, H, W, C], where width*channels are padded to 4. + * - Not used for device side + */ + HAILO_FORMAT_ORDER_RGB4 = 17, + /** Max enum value to maintain ABI Integrity */ HAILO_FORMAT_ORDER_MAX_ENUM = HAILO_MAX_ENUM } hailo_format_order_t; @@ -1205,7 +1207,7 @@ typedef struct { { /* Frame shape */ hailo_3d_image_shape_t shape; - /* NMS shape, only valid if format.order is ::HAILO_FORMAT_ORDER_NMS */ + /* NMS shape, only valid if format.order is ::HAILO_FORMAT_ORDER_HAILO_NMS */ hailo_nms_shape_t nms_shape; }; @@ -1326,7 +1328,7 @@ typedef struct { typedef struct { uint32_t connection_status; uint32_t connection_type; - uint32_t pcie_is_active; + uint32_t vdma_is_active; uint32_t host_port; uint32_t host_ip_addr; } hailo_debug_notification_message_t; @@ -1429,8 +1431,7 @@ typedef struct { * @param[in] opaque User specific data. * @warning Throwing exceptions in the callback is not supported! */ -typedef void (*hailo_notification_callback)(hailo_device, const hailo_notification_t*, void*); - +typedef void (*hailo_notification_callback)(hailo_device device, const hailo_notification_t *notification, void *opaque); /** Hailo device reset modes */ typedef enum { HAILO_RESET_DEVICE_MODE_CHIP = 0, @@ -2085,19 +2086,6 @@ HAILORTAPI hailo_status hailo_configure_vdevice(hailo_vdevice vdevice, hailo_hef HAILORTAPI hailo_status hailo_get_physical_devices(hailo_vdevice vdevice, hailo_device *devices, size_t *number_of_devices); -/** - * Gets the physical devices' infos from a vdevice. - * - * @param[in] vdevice A @a hailo_vdevice object to fetch physical devices from. - * @param[out] devices_infos Array of ::hailo_pcie_device_info_t to be fetched from vdevice. - * @param[inout] number_of_devices As input - the size of @a devices_infos array. As output - the number of physical devices under vdevice. - * @return Upon success, returns ::HAILO_SUCCESS. Otherwise, returns a ::hailo_status error. - * @note The returned physical devices are held in the scope of @a vdevice. - * @note This function is deprecated. One should use 'hailo_vdevice_get_physical_devices_ids()' - */ -HAILORTAPI hailo_status hailo_get_physical_devices_infos(hailo_vdevice vdevice, hailo_pcie_device_info_t *devices_infos, - size_t *number_of_devices) DEPRECATED("'hailo_get_physical_devices_infos' is deprecated. One should use 'hailo_vdevice_get_physical_devices_ids()'."); - /** * Gets the physical devices' ids from a vdevice. * @@ -2428,6 +2416,35 @@ HAILORTAPI hailo_status hailo_init_configure_params(hailo_hef hef, hailo_stream_ HAILORTAPI hailo_status hailo_init_configure_params_mipi_input(hailo_hef hef, hailo_stream_interface_t output_interface, hailo_mipi_input_stream_params_t *mipi_params, hailo_configure_params_t *params); +/** + * Init configure params with default values for a given hef. + * + * @param[in] hef A ::hailo_hef object to configure the @a device by. + * @param[in] stream_interface A @a hailo_stream_interface_t indicating which @a hailo_stream_parameters_t to create. + * @param[in] network_group_name The name of the network_group to make configure params for. If NULL is passed, + * the first network_group in the HEF will be addressed. + * @param[out] params A @a hailo_configure_params_t to be filled. + * @return Upon success, returns ::HAILO_SUCCESS. Otherwise, returns a ::hailo_status error. + */ +HAILORTAPI hailo_status hailo_init_configure_network_group_params(hailo_hef hef, hailo_stream_interface_t stream_interface, + const char *network_group_name, hailo_configure_network_group_params_t *params); + +/** + * Init configure params with default values for a given hef, where all input_streams_params are init to be MIPI type. + * + * @param[in] hef A ::hailo_hef object to configure the @a device by. + * @param[in] output_interface A @a hailo_stream_interface_t indicating which @a hailo_stream_parameters_t to + * create for the output streams. + * @param[in] mipi_params A ::hailo_mipi_input_stream_params_t object which contains the MIPI params for + * the input streams. + * @param[in] network_group_name The name of the network_group to make configure params for. If NULL is passed, + * the first network_group in the HEF will be addressed. + * @param[out] params A @a hailo_configure_params_t to be filled. + * @return Upon success, returns ::HAILO_SUCCESS. Otherwise, returns a ::hailo_status error. + */ +HAILORTAPI hailo_status hailo_init_configure_network_group_params_mipi_input(hailo_hef hef, hailo_stream_interface_t output_interface, + hailo_mipi_input_stream_params_t *mipi_params, const char *network_group_name, hailo_configure_network_group_params_t *params); + /** * Configure the device from an hef. * @@ -2598,7 +2615,7 @@ HAILORTAPI hailo_status hailo_set_scheduler_timeout(hailo_configured_network_gro * If NULL is passed, the threshold will be set for all the networks in the network group. * @return Upon success, returns ::HAILO_SUCCESS. Otherwise, returns a ::hailo_status error. * @note Using this function is only allowed when scheduling_algorithm is not ::HAILO_SCHEDULING_ALGORITHM_NONE, and before the creation of any vstreams. - * @note The default threshold is 1. + * @note The default threshold is 0, which means HailoRT will apply an automatic heuristic to choose the threshold. * @note Currently, setting the threshold for a specific network is not supported. * @note The threshold may be ignored to prevent idle time from the device. */ @@ -3227,6 +3244,32 @@ HAILORTAPI hailo_status hailo_get_network_infos(hailo_configured_network_group n /** @} */ // end of multi_network_functions +/** @defgroup group_advanced_API_functions hailo advence API functions + * @{ + */ + +typedef enum hailo_sleep_state_e { + HAILO_SLEEP_STATE_SLEEPING = 0, + HAILO_SLEEP_STATE_AWAKE = 1, + + /** Max enum value to maintain ABI Integrity */ + HAILO_SLEEP_STATE_MAX_ENUM = HAILO_MAX_ENUM +} hailo_sleep_state_t; + +/** + * Set chip sleep state. + * @note This is an advanced API. Please be advised not to use this API, unless supported by Hailo. + * + * @param[in] device A ::hailo_device object. + * @param[in] sleep_state The requested sleep state of the chip + * + * @return Upon success, returns @a HAILO_SUCCESS. Otherwise, returns an @a hailo_status error. + */ + +HAILORTAPI hailo_status hailo_set_sleep_state(hailo_device device, hailo_sleep_state_t sleep_state); + +/** @} */ // end of group_advanced_API_functions + /** @defgroup group_deprecated_functions_and_defines Deprecated functions and defines * @{ */ diff --git a/hailort/libhailort/include/hailo/hailort_common.hpp b/hailort/libhailort/include/hailo/hailort_common.hpp index 089b3fb..8b6f96f 100644 --- a/hailort/libhailort/include/hailo/hailort_common.hpp +++ b/hailort/libhailort/include/hailo/hailort_common.hpp @@ -12,6 +12,7 @@ #include "hailo/hailort.h" #include "hailo/expected.hpp" +#include #include #include #include @@ -19,6 +20,8 @@ namespace hailort { +#define RGB4_ALIGNMENT (4) + /*! Common utility functions and macros that help manage hailort.h structures */ class HAILORTAPI HailoRTCommon final { @@ -69,15 +72,30 @@ public: return size_per_class * nms_shape.number_of_classes; } + /** + * Rounds an integer value up to the next multiple of a specified size. + * + * @param[in] num Original number. + * @param[in] alignment Returned number should be aligned to this parameter. + * @return aligned number + */ + static constexpr uint32_t align_to(uint32_t num, uint32_t alignment) { + auto remainder = num % alignment; + return remainder == 0 ? num : num + (alignment - remainder); + } + /** * Gets the shape size. * * @param[in] shape The shape to get size from. + * @param[in] row_alignment The size the shape row is aligned to. * @return The shape size. */ - static constexpr uint32_t get_shape_size(const hailo_3d_image_shape_t &shape) + static constexpr uint32_t get_shape_size(const hailo_3d_image_shape_t &shape, uint32_t row_alignment = 1) { - return shape.height * shape.width * shape.features; + auto row_size = shape.width * shape.features; + row_size = align_to(row_size, row_alignment); + return shape.height * row_size; } /** @@ -181,6 +199,8 @@ public: return "NV21"; case HAILO_FORMAT_ORDER_HAILO_YYVU: return "YYVU"; + case HAILO_FORMAT_ORDER_RGB4: + return "RGB4"; default: return "Nan"; } @@ -245,7 +265,11 @@ public: */ static constexpr uint32_t get_frame_size(const hailo_3d_image_shape_t &shape, const hailo_format_t &format) { - return get_shape_size(shape) * get_format_data_bytes(format); + uint32_t row_alignment = 1; + if (format.order == HAILO_FORMAT_ORDER_RGB4) { + row_alignment = RGB4_ALIGNMENT; + } + return get_shape_size(shape, row_alignment) * get_format_data_bytes(format); } /** diff --git a/hailort/libhailort/include/hailo/hef.hpp b/hailort/libhailort/include/hailo/hef.hpp index 94287de..0aa6f13 100644 --- a/hailort/libhailort/include/hailo/hef.hpp +++ b/hailort/libhailort/include/hailo/hef.hpp @@ -38,8 +38,8 @@ struct ConfigureNetworkParams } } - bool operator==(const ConfigureNetworkParams &other); - bool operator!=(const ConfigureNetworkParams &other); + bool operator==(const ConfigureNetworkParams &other) const; + bool operator!=(const ConfigureNetworkParams &other) const; uint16_t batch_size; hailo_power_mode_t power_mode; @@ -442,13 +442,13 @@ public: private: friend class DeviceBase; - friend class ConfigManager; - friend class VdmaConfigManager; - friend class HcpConfigManager; + friend class VdmaDevice; + friend class EthernetDevice; friend class InputStream; friend class OutputStream; friend class PyhailortInternal; friend class ConfiguredNetworkGroupBase; + friend class VDeviceBase; #ifdef HAILO_SUPPORT_MULTI_PROCESS friend class HailoRtRpcClient; diff --git a/hailort/libhailort/include/hailo/network_group.hpp b/hailort/libhailort/include/hailo/network_group.hpp index 80278c7..8daba2f 100644 --- a/hailort/libhailort/include/hailo/network_group.hpp +++ b/hailort/libhailort/include/hailo/network_group.hpp @@ -39,7 +39,7 @@ using OutputStreamRefVector = std::vector>; using NameToVStreamParamsMap = std::unordered_map; /** Represents a vector of pairs of OutputStream and NameToVStreamParamsMap */ -using OutputStreamWithParamsVector = std::vector, NameToVStreamParamsMap>>; +using OutputStreamWithParamsVector = std::vector, NameToVStreamParamsMap>>; /** Latency measurement result info */ struct LatencyMeasurementResult { @@ -369,9 +369,6 @@ public: protected: ConfiguredNetworkGroup() = default; - virtual Expected> activate_internal( - const hailo_activate_network_group_params_t &network_group_params, uint16_t dynamic_batch_size) = 0; - private: friend class ActivatedNetworkGroup; }; diff --git a/hailort/libhailort/include/hailo/quantization.hpp b/hailort/libhailort/include/hailo/quantization.hpp index 51bb26c..7c2ca5f 100644 --- a/hailort/libhailort/include/hailo/quantization.hpp +++ b/hailort/libhailort/include/hailo/quantization.hpp @@ -147,11 +147,30 @@ public: } } + /** + * Indicates whether the @a quant_info contains the identity scale. + * If true there is no need to fix the data's scale. + */ static inline bool is_identity_qp(const hailo_quant_info_t &quant_info) { return ((1 == quant_info.qp_scale) && (0 == quant_info.qp_zp)); } + /** + * De-quantize @a number from data type @a Q to data type @a T and fix it's scale according to @a quant_info. + * + * @param[in] number The value to be de-quantized. + * @param[in] quant_info Quantization info. + * + * @return Returns the dequantized value of @a number. + * + */ + template + static inline T dequantize_output(Q number, hailo_quant_info_t quant_info) + { + return (T)((number - quant_info.qp_zp) * quant_info.qp_scale); + } + private: template static inline Q quantize_input(T number, hailo_quant_info_t quant_info) @@ -172,12 +191,6 @@ private: return n; } } - - template - static inline T dequantize_output(Q number, hailo_quant_info_t quant_info) - { - return (T)((number - quant_info.qp_zp) * quant_info.qp_scale); - } }; } /* namespace hailort */ diff --git a/hailort/libhailort/include/hailo/stream.hpp b/hailort/libhailort/include/hailo/stream.hpp index 93aa815..a2ebe5f 100644 --- a/hailort/libhailort/include/hailo/stream.hpp +++ b/hailort/libhailort/include/hailo/stream.hpp @@ -139,7 +139,7 @@ protected: private: friend class HefConfigurator; - friend class ActivatedNetworkGroupBase; + friend class ConfiguredNetworkGroupBase; }; /*! Output (device to host) stream representation */ @@ -257,7 +257,7 @@ private: void increase_invalid_frames_count(uint32_t value); friend class HefConfigurator; - friend class ActivatedNetworkGroupBase; + friend class ConfiguredNetworkGroupBase; friend class HwReadElement; friend class OutputDemuxer; }; diff --git a/hailort/libhailort/include/hailo/vdevice.hpp b/hailort/libhailort/include/hailo/vdevice.hpp index 2c112c1..9657374 100644 --- a/hailort/libhailort/include/hailo/vdevice.hpp +++ b/hailort/libhailort/include/hailo/vdevice.hpp @@ -19,6 +19,8 @@ namespace hailort { +#define HAILO_ENABLE_MULTI_DEVICE_SCHEDULER "HAILO_ENABLE_MULTI_DEVICE_SCHEDULER" + /*! Represents a bundle of physical devices. */ class HAILORTAPI VDevice { @@ -72,22 +74,20 @@ public: virtual Expected>> get_physical_devices() const = 0; /** - * Gets the devices informations. + * Gets the physical device IDs. * - * @return Upon success, returns Expected of a vector of ::hailo_pcie_device_info_t objects. + * @return Upon success, returns Expected of a vector of std::string device ids objects. * Otherwise, returns Unexpected of ::hailo_status error. - * @note This function is deprecated. One should use 'get_physical_devices_ids()' */ - Expected> get_physical_devices_infos() const - DEPRECATED("'VDevice::get_physical_devices_infos' is deprecated. One should use 'VDevice::get_physical_devices_ids()'."); + virtual Expected> get_physical_devices_ids() const = 0; /** - * Gets the physical device IDs. - * - * @return Upon success, returns Expected of a vector of std::string device ids objects. + * Gets the stream's default interface. + * + * @return Upon success, returns Expected of ::hailo_stream_interface_t. * Otherwise, returns Unexpected of ::hailo_status error. */ - virtual Expected> get_physical_devices_ids() const = 0; + virtual Expected get_default_streams_interface() const = 0; virtual ~VDevice() = default; VDevice(const VDevice &) = delete; diff --git a/hailort/libhailort/include/hailo/vstream.hpp b/hailort/libhailort/include/hailo/vstream.hpp index d0299e4..040e554 100644 --- a/hailort/libhailort/include/hailo/vstream.hpp +++ b/hailort/libhailort/include/hailo/vstream.hpp @@ -69,12 +69,19 @@ public: static hailo_status clear(std::vector> &vstreams); /** - * Aborts vstream in unrecoverable manner. + * Aborts vstream until its resumed. * * @return Upon success, returns ::HAILO_SUCCESS. Otherwise, returns a ::hailo_status error. */ hailo_status abort(); + /** + * Resumes vstream after it was aborted. + * + * @return Upon success, returns ::HAILO_SUCCESS. Otherwise, returns a ::hailo_status error. + */ + hailo_status resume(); + /** * @return the size of a virtual stream's frame on the host side in bytes. * @note The size could be affected by the format type - using UINT16, or by the data not being quantized yet. @@ -203,12 +210,19 @@ public: static hailo_status clear(std::vector> &vstreams); /** - * Aborts vstream in unrecoverable manner. + * Aborts vstream until its resumed. * * @return Upon success, returns ::HAILO_SUCCESS. Otherwise, returns a ::hailo_status error. */ hailo_status abort(); + /** + * Resumes vstream after it was aborted. + * + * @return Upon success, returns ::HAILO_SUCCESS. Otherwise, returns a ::hailo_status error. + */ + hailo_status resume(); + /** * @return the size of a virtual stream's frame on the host side in bytes. * @note The size could be affected by the format type - using UINT16, or by the data not being quantized yet. @@ -296,7 +310,7 @@ protected: std::shared_ptr m_vstream; friend class VStreamsBuilderUtils; - friend class VdmaConfigNetworkGroup; + friend class VDeviceNetworkGroup; }; /*! Contains the virtual streams creation functions */ diff --git a/hailort/libhailort/scheduler_mon.proto b/hailort/libhailort/scheduler_mon.proto index 25043a3..01155f8 100644 --- a/hailort/libhailort/scheduler_mon.proto +++ b/hailort/libhailort/scheduler_mon.proto @@ -5,7 +5,7 @@ option optimize_for = LITE_RUNTIME; message ProtoMonInfo { string network_name = 1; double fps = 2; - double core_utilization = 3; + double active_time = 3; } enum ProtoMonStreamDirection { diff --git a/hailort/libhailort/src/CMakeLists.txt b/hailort/libhailort/src/CMakeLists.txt index dd7a9aa..f42ec10 100644 --- a/hailort/libhailort/src/CMakeLists.txt +++ b/hailort/libhailort/src/CMakeLists.txt @@ -16,6 +16,7 @@ FUNCTION(relative_to_absolute_paths output) ENDFUNCTION(relative_to_absolute_paths) add_subdirectory(os) +add_subdirectory(net_flow) set(HAILORT_CPP_SOURCES device.cpp @@ -31,23 +32,26 @@ set(HAILORT_CPP_SOURCES hailort_common.cpp sensor_config_utils.cpp pipeline.cpp + pipeline_multiplexer.cpp eth_device.cpp eth_stream.cpp udp.cpp hef.cpp - context_switch/hef_metadata.cpp - context_switch/hcp_config_manager.cpp + network_group_metadata.cpp + + context_switch/context_switch_actions.cpp context_switch/hcp_config_network_group.cpp context_switch/hcp_config_activated_network_group.cpp - context_switch/vdma_config_manager.cpp context_switch/vdma_config_network_group.cpp + context_switch/vdevice_network_group.cpp context_switch/vdma_config_activated_network_group.cpp context_switch/network_group.cpp - context_switch/network_group_wrapper.cpp context_switch/resource_manager.cpp - context_switch/pipeline_multiplexer.cpp + context_switch/resource_manager_builder.cpp + context_switch/context_switch_buffer_builder.cpp + channel_allocator.cpp inter_context_buffer.cpp ddr_channels_pair.cpp @@ -55,7 +59,6 @@ set(HAILORT_CPP_SOURCES d2h_events_parser.cpp mipi_stream.cpp - hlpcie.cpp vdma_channel.cpp vdma_descriptor_list.cpp vdma_device.cpp @@ -75,7 +78,8 @@ set(HAILORT_CPP_SOURCES vdevice.cpp vdevice_stream.cpp - vdevice_stream_wrapper.cpp + vdevice_stream_multiplexer_wrapper.cpp + multi_device_scheduled_stream.cpp control_protocol.cpp @@ -83,11 +87,18 @@ set(HAILORT_CPP_SOURCES inference_pipeline.cpp network_group_scheduler.cpp + + scheduled_network_group.cpp + scheduler_oracle.cpp ) if(HAILO_BUILD_SERVICE) set(HAILORT_CPP_SOURCES "${HAILORT_CPP_SOURCES}" hailort_rpc_client.cpp network_group_client.cpp) endif() +if(HAILO_BUILD_PROFILER) + set(HAILORT_CPP_SOURCES "${HAILORT_CPP_SOURCES}" tracer.cpp) +endif() + set(common_dir "${PROJECT_SOURCE_DIR}/common/src") set(COMMON_C_SOURCES @@ -136,7 +147,6 @@ target_link_libraries(libhailort PRIVATE hef_proto) target_link_libraries(libhailort PRIVATE scheduler_mon_proto) target_link_libraries(libhailort PRIVATE spdlog::spdlog) target_link_libraries(libhailort PRIVATE readerwriterqueue) -target_link_libraries(libhailort PRIVATE microprofile) if(HAILO_BUILD_SERVICE) target_link_libraries(libhailort PRIVATE grpc++_unsecure) target_link_libraries(libhailort PRIVATE hailort_rpc_grpc_proto) diff --git a/hailort/libhailort/src/buffer.cpp b/hailort/libhailort/src/buffer.cpp index 6d14bc8..1430910 100644 --- a/hailort/libhailort/src/buffer.cpp +++ b/hailort/libhailort/src/buffer.cpp @@ -23,6 +23,21 @@ namespace hailort { +static void format_buffer(std::ostream& stream, const uint8_t *buffer, size_t size) +{ + assert(nullptr != buffer); + + static const bool UPPERCASE = true; + static const size_t BYTES_PER_LINE = 32; + static const char *BYTE_DELIM = " "; + for (size_t offset = 0; offset < size; offset += BYTES_PER_LINE) { + const size_t line_size = std::min(BYTES_PER_LINE, size - offset); + stream << fmt::format("0x{:08X}", offset) << BYTE_DELIM; // 32 bit offset into a buffer should be enough + stream << StringUtils::to_hex_string(buffer + offset, line_size, UPPERCASE, BYTE_DELIM) << std::endl; + } + stream << "[size = " << std::dec << size << "]"; +} + Buffer::Buffer() : m_data(nullptr), m_size(0) @@ -177,9 +192,7 @@ std::string Buffer::to_string() const // Note: This is a friend function std::ostream& operator<<(std::ostream& stream, const Buffer& buffer) { - const bool UPPERCASE = true; - stream << StringUtils::to_hex_string(buffer.data(), buffer.size(), UPPERCASE, "\t"); - stream << "\n[size = " << std::dec << buffer.size() << "]"; + format_buffer(stream, buffer.data(), buffer.size()); return stream; } @@ -261,9 +274,7 @@ bool MemoryView::empty() const noexcept // Note: This is a friend function std::ostream& operator<<(std::ostream& stream, const MemoryView& buffer) { - const bool UPPERCASE = true; - stream << StringUtils::to_hex_string(buffer.data(), buffer.size(), UPPERCASE, "\t"); - stream << "\n[size = " << std::dec << buffer.size() << "]"; + format_buffer(stream, buffer.data(), buffer.size()); return stream; } diff --git a/hailort/libhailort/src/channel_allocator.cpp b/hailort/libhailort/src/channel_allocator.cpp index 45c776f..28833a8 100644 --- a/hailort/libhailort/src/channel_allocator.cpp +++ b/hailort/libhailort/src/channel_allocator.cpp @@ -49,10 +49,10 @@ Expected ChannelAllocator::get_available_channel_id(const Layer continue; } - // In the case of boundary channels, if the channel id was used in previous context as fw-managed (and it - // was freed, so it doesn't appear in `currently_used_channel_index`), we can't reuse it. + // In the case of boundary channels, if the channel id was used in previous context as an internal channel (and + // it was freed, so it doesn't appear in `currently_used_channel_index`), we can't reuse it. if (std::get<0>(layer_identifier) == LayerType::BOUNDARY) { - if (contains(m_fw_managed_channel_ids, channel_id)) { + if (contains(m_internal_channel_ids, channel_id)) { continue; } } @@ -77,23 +77,17 @@ hailo_status ChannelAllocator::free_channel_index(const LayerIdentifier &layer_i return HAILO_SUCCESS; } -const std::set &ChannelAllocator::get_boundary_channel_ids() const +const std::set &ChannelAllocator::get_internal_channel_ids() const { - return m_boundary_channel_ids; -} - -const std::set &ChannelAllocator::get_fw_managed_channel_ids() const -{ - return m_fw_managed_channel_ids; + return m_internal_channel_ids; } void ChannelAllocator::insert_new_channel_id(const LayerIdentifier &layer_identifier, const vdma::ChannelId &channel_id) { if (LayerType::BOUNDARY == std::get<0>(layer_identifier)) { m_boundary_channel_ids.insert(channel_id); - } - else { - m_fw_managed_channel_ids.insert(channel_id); + } else { + m_internal_channel_ids.insert(channel_id); } m_allocated_channels.emplace(layer_identifier, channel_id); diff --git a/hailort/libhailort/src/channel_allocator.hpp b/hailort/libhailort/src/channel_allocator.hpp index 778ae8a..165bd84 100644 --- a/hailort/libhailort/src/channel_allocator.hpp +++ b/hailort/libhailort/src/channel_allocator.hpp @@ -14,8 +14,7 @@ #include "vdma_descriptor_list.hpp" #include "vdma/channel_id.hpp" #include "vdma_channel.hpp" -#include "hef_internal.hpp" - +#include "layer_info.hpp" #include namespace hailort @@ -31,8 +30,7 @@ public: VdmaChannel::Direction direction, uint8_t engine_index); hailo_status free_channel_index(const LayerIdentifier &layer_identifier); - const std::set &get_boundary_channel_ids() const; - const std::set &get_fw_managed_channel_ids() const; + const std::set &get_internal_channel_ids() const; private: void insert_new_channel_id(const LayerIdentifier &layer_identifier, const vdma::ChannelId &channel_id); @@ -44,7 +42,7 @@ private: // Contains all channels id allocated for the network group. This channels are never released. std::set m_boundary_channel_ids; - std::set m_fw_managed_channel_ids; + std::set m_internal_channel_ids; }; } /* namespace hailort */ diff --git a/hailort/libhailort/src/config_buffer.cpp b/hailort/libhailort/src/config_buffer.cpp index 20f8d92..f64b24a 100644 --- a/hailort/libhailort/src/config_buffer.cpp +++ b/hailort/libhailort/src/config_buffer.cpp @@ -50,23 +50,45 @@ Expected ConfigBuffer::program_descriptors() return descriptors_count; } -hailo_status ConfigBuffer::write(const void *data, size_t data_size) +hailo_status ConfigBuffer::pad_with_nops() { - size_t total_offset = (m_acc_desc_count * m_buffer->desc_page_size()) + m_acc_buffer_offset; - auto status = m_buffer->write(data, data_size, total_offset); - CHECK_SUCCESS(status); + static constexpr uint64_t CCW_NOP = 0x0; + + auto page_size = desc_page_size(); + auto buffer_size = m_total_buffer_size; + auto buffer_residue = buffer_size % page_size; + if (0 != buffer_residue % CCW_HEADER_SIZE) { + LOGGER__ERROR("CFG channel buffer size must be a multiple of CCW header size ({})", CCW_HEADER_SIZE); + return HAILO_INTERNAL_FAILURE; + } + /* If buffer does not fit info descriptor, the host must pad the buffer with CCW NOPs. */ + auto nop_count = (buffer_residue == 0) ? 0 : ((page_size - buffer_residue) / CCW_HEADER_SIZE); + for (uint8_t nop_index = 0; nop_index < nop_count; nop_index++) { + /* Generate nop transaction. + CCW of all zeros (64'h0) should be treated as NOP - ignore CCW and expect CCW in next 64b word. + When CSM recognize it is a NOP it pops it from the channel FIFO without forward any address/data/command, + does not contribute to CRC calculations but return credits to the peripheral as usual. */ + write_inner(MemoryView::create_const(reinterpret_cast(&CCW_NOP), sizeof(CCW_NOP))); + } + return HAILO_SUCCESS; +} + - m_acc_buffer_offset += data_size; - m_current_buffer_size += data_size; +hailo_status ConfigBuffer::write(const MemoryView &data) +{ + CHECK(data.size() <= size_left(), HAILO_INTERNAL_FAILURE, "Write too many config words"); + write_inner(data); + m_current_buffer_size += data.size(); return HAILO_SUCCESS; } -size_t ConfigBuffer::get_total_cfg_size() +size_t ConfigBuffer::size_left() const { - return m_total_buffer_size; + assert(m_total_buffer_size >= m_current_buffer_size); + return m_total_buffer_size - m_current_buffer_size; } -size_t ConfigBuffer::get_current_buffer_size() +size_t ConfigBuffer::get_current_buffer_size() const { return m_current_buffer_size; } @@ -76,13 +98,24 @@ uint16_t ConfigBuffer::desc_page_size() const return m_buffer->desc_page_size(); } -CONTROL_PROTOCOL__config_channel_info_t ConfigBuffer::get_config_channel_info() const +vdma::ChannelId ConfigBuffer::channel_id() const +{ + return m_channel_id; +} + +CONTROL_PROTOCOL__host_buffer_info_t ConfigBuffer::get_host_buffer_info() const +{ + return m_buffer->get_host_buffer_info(m_acc_desc_count * m_buffer->desc_page_size()); +} + +hailo_status ConfigBuffer::write_inner(const MemoryView &data) { - CONTROL_PROTOCOL__config_channel_info_t config_channel_info; - config_channel_info.config_buffer_info = m_buffer->get_host_buffer_info(m_acc_desc_count * m_buffer->desc_page_size()); - config_channel_info.engine_index = m_channel_id.engine_index; - config_channel_info.vdma_channel_index = m_channel_id.channel_index; - return config_channel_info; + size_t total_offset = (m_acc_desc_count * m_buffer->desc_page_size()) + m_acc_buffer_offset; + auto status = m_buffer->write(data.data(), data.size(), total_offset); + CHECK_SUCCESS(status); + + m_acc_buffer_offset += data.size(); + return HAILO_SUCCESS; } Expected> ConfigBuffer::create_sg_buffer(HailoRTDriver &driver, diff --git a/hailort/libhailort/src/config_buffer.hpp b/hailort/libhailort/src/config_buffer.hpp index ade4708..d121c03 100644 --- a/hailort/libhailort/src/config_buffer.hpp +++ b/hailort/libhailort/src/config_buffer.hpp @@ -12,9 +12,14 @@ #define _HAILO_CONFIG_BUFFER_HPP_ #include "vdma/vdma_buffer.hpp" +#include "hailo/buffer.hpp" namespace hailort { +#define CCW_BYTES_IN_WORD (4) +#define CCW_DATA_OFFSET (CCW_BYTES_IN_WORD * 2) +#define CCW_HEADER_SIZE (CCW_DATA_OFFSET) + class ConfigBuffer final { @@ -23,23 +28,29 @@ public: const std::vector &cfg_sizes); // Write data to config channel - hailo_status write(const void *data, size_t data_size); + hailo_status write(const MemoryView &data); // Program the descriptors for the data written so far Expected program_descriptors(); - size_t get_current_buffer_size(); + // On prefetch mode, we need to pad the config buffer with nops BEFORE the last write. + hailo_status pad_with_nops(); + + // Amount of bytes left to write into the buffer. + size_t size_left() const; - /* Get all the config size. It's not the same as the VdmaBuffer::size() - since we might add NOPs to the data (Pre-fetch mode) */ - size_t get_total_cfg_size(); + // Amount of bytes already written. + size_t get_current_buffer_size() const; uint16_t desc_page_size() const; - CONTROL_PROTOCOL__config_channel_info_t get_config_channel_info() const; + vdma::ChannelId channel_id() const; + CONTROL_PROTOCOL__host_buffer_info_t get_host_buffer_info() const; private: ConfigBuffer(std::unique_ptr &&buffer, vdma::ChannelId channel_id, size_t total_buffer_size); + hailo_status write_inner(const MemoryView &data); + static Expected> create_sg_buffer(HailoRTDriver &driver, uint8_t vdma_channel_index, const std::vector &cfg_sizes); static Expected> create_ccb_buffer(HailoRTDriver &driver, diff --git a/hailort/libhailort/src/context_switch/active_network_group_holder.hpp b/hailort/libhailort/src/context_switch/active_network_group_holder.hpp index 935c96e..c6edb5c 100644 --- a/hailort/libhailort/src/context_switch/active_network_group_holder.hpp +++ b/hailort/libhailort/src/context_switch/active_network_group_holder.hpp @@ -27,7 +27,7 @@ class ActiveNetworkGroupHolder final ExpectedRef get() { - CHECK(nullptr != m_net_group, HAILO_INVALID_OPERATION); + CHECK_NOT_NULL_AS_EXPECTED(m_net_group, HAILO_INVALID_OPERATION); return std::ref(*m_net_group); } void set(T &net_group) diff --git a/hailort/libhailort/src/context_switch/config_manager.hpp b/hailort/libhailort/src/context_switch/config_manager.hpp deleted file mode 100644 index caf0490..0000000 --- a/hailort/libhailort/src/context_switch/config_manager.hpp +++ /dev/null @@ -1,59 +0,0 @@ -/** - * Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved. - * Distributed under the MIT license (https://opensource.org/licenses/MIT) - **/ -/** - * @file config_manager.hpp - * @brief Manager of HEF parsing and network groups resources - * - * - **/ - -#ifndef HAILO_CONFIG_MANAGER_HPP_ -#define HAILO_CONFIG_MANAGER_HPP_ - -#include "hailo/hailort.h" -#include "hailo/device.hpp" -#include "hailo/expected.hpp" -#include "common/utils.hpp" - -#include -#include -#include - -namespace hailort -{ - -enum class ConfigManagerType { - NotSet = 0, - HcpConfigManager = 1, - VdmaConfigManager = 2, -}; - -class ConfigManager -{ - public: - virtual ~ConfigManager() {} - virtual ConfigManagerType get_manager_type() = 0; - virtual Expected add_hef(Hef &hef, const std::map &configure_params) = 0; - - protected: - hailo_status validate_boundary_streams_were_created(Hef &hef, const std::string &network_group_name, ConfiguredNetworkGroup &network_group) - { - auto number_of_inputs = hef.get_number_of_input_streams(network_group_name); - CHECK_EXPECTED_AS_STATUS(number_of_inputs); - CHECK((number_of_inputs.value() == network_group.get_input_streams().size()), - HAILO_INVALID_ARGUMENT, "passed configure_params for network group {} did not contain all input streams", network_group_name); - - auto number_of_outputs = hef.get_number_of_output_streams(network_group_name); - CHECK_EXPECTED_AS_STATUS(number_of_inputs); - CHECK((number_of_outputs.value() == network_group.get_output_streams().size()), - HAILO_INVALID_ARGUMENT, "passed configure_params for network group {} did not contain all output streams", network_group_name); - - return HAILO_SUCCESS; - } -}; - -} /* namespace hailort */ - -#endif /* HAILO_CONFIG_MANAGER_HPP_ */ \ No newline at end of file diff --git a/hailort/libhailort/src/context_switch/context_switch_actions.cpp b/hailort/libhailort/src/context_switch/context_switch_actions.cpp new file mode 100644 index 0000000..d9ad378 --- /dev/null +++ b/hailort/libhailort/src/context_switch/context_switch_actions.cpp @@ -0,0 +1,1327 @@ +/** + * Copyright (c) 2022 Hailo Technologies Ltd. All rights reserved. + * Distributed under the MIT license (https://opensource.org/licenses/MIT) +**/ +/** + * @file context_switch_actions.cpp + * @brief Contains classes represents the context switch action (Actions found in the HEFs + * and action sent to the fw). + **/ + +#include "context_switch_actions.hpp" +#include "context_switch_defs.h" +#include "context_switch/multi_context/resource_manager.hpp" + +namespace hailort +{ + + +static uint8_t pack_vdma_channel_id(const vdma::ChannelId &channel_id) +{ + return static_cast(channel_id.channel_index | + (channel_id.engine_index << CONTEXT_SWITCH_DEFS__PACKED_VDMA_CHANNEL_ID__ENGINE_INDEX_SHIFT)); +} + +static uint8_t pack_lcu_id(uint8_t cluster_index, uint8_t lcu_index) +{ + return static_cast(lcu_index | + (cluster_index << CONTEXT_SWITCH_DEFS__PACKED_LCU_ID_CLUSTER_INDEX_SHIFT)); +} + +ContextSwitchConfigAction::ContextSwitchConfigAction(Type type) : + ContextSwitchConfigAction(type, CONTEXT_SWITCH_DEFS__ACTION_TYPE_COUNT) +{} + +ContextSwitchConfigAction::ContextSwitchConfigAction(Type type, CONTEXT_SWITCH_DEFS__ACTION_TYPE_t action_list_type) : + m_type(type), + m_action_list_type(action_list_type) +{} + +Expected> ContextSwitchConfigAction::serialize(const ContextResources &context_resources, + bool is_repeated /*=false*/) const +{ + CHECK_AS_EXPECTED(m_action_list_type < CONTEXT_SWITCH_DEFS__ACTION_TYPE_COUNT, HAILO_INTERNAL_FAILURE, + "Action cannot be serialized"); + + auto header = serialize_header(is_repeated); + CHECK_EXPECTED(header); + + auto params = serialize_params(context_resources); + CHECK_EXPECTED(params); + + auto serialized_action = Buffer::create(header->size() + params->size()); + CHECK_EXPECTED(serialized_action); + + std::copy(header->begin(), header->end(), serialized_action->data()); + std::copy(params->begin(), params->end(), serialized_action->data() + header->size()); + + std::vector buffers; + buffers.emplace_back(serialized_action.release()); + return buffers; +} + +ContextSwitchConfigAction::Type ContextSwitchConfigAction::get_type() const +{ + return m_type; +} + +CONTEXT_SWITCH_DEFS__ACTION_TYPE_t ContextSwitchConfigAction::get_action_list_type() const +{ + return m_action_list_type; +} + +Expected ContextSwitchConfigAction::serialize_header(bool is_repeated) const +{ + CHECK_AS_EXPECTED(m_action_list_type != CONTEXT_SWITCH_DEFS__ACTION_TYPE_COUNT, HAILO_INTERNAL_FAILURE, + "Action cannot be serialized"); + + auto header = Buffer::create(sizeof(CONTROL_PROTOCOL__ACTION_HEADER_t), 0); + CHECK_EXPECTED(header); + header->as_type().action_type = m_action_list_type; + header->as_type().is_repeated = is_repeated; // TODO: prettier + return header.release(); +} + +Expected NoneAction::create() +{ + auto result = ContextSwitchConfigActionPtr(new (std::nothrow) NoneAction()); + CHECK_AS_EXPECTED((nullptr != result), HAILO_OUT_OF_HOST_MEMORY); + return result; +} + +NoneAction::NoneAction() : + ContextSwitchConfigAction(Type::None) +{} + +Expected> NoneAction::serialize(const ContextResources &, bool) const +{ + // Do nothing + return std::vector(); +} + +bool NoneAction::supports_repeated_block() const +{ + // None actions are ignored and aren't written to the FW's action list. Hence they can't be part of a repeated block. + return false; +} + +Expected NoneAction::serialize_params(const ContextResources &) const +{ + return make_unexpected(HAILO_NOT_IMPLEMENTED); +} + +Expected ActivateConfigChannelAction::create(uint8_t config_stream_index, + const vdma::ChannelId &channel_id, const CONTROL_PROTOCOL__host_buffer_info_t &host_buffer_info) +{ + auto result = ContextSwitchConfigActionPtr(new (std::nothrow) ActivateConfigChannelAction(config_stream_index, + channel_id, host_buffer_info)); + CHECK_AS_EXPECTED((nullptr != result), HAILO_OUT_OF_HOST_MEMORY); + return result; +} + +ActivateConfigChannelAction::ActivateConfigChannelAction(uint8_t config_stream_index, + const vdma::ChannelId &channel_id, const CONTROL_PROTOCOL__host_buffer_info_t &host_buffer_info) : + ContextSwitchConfigAction(Type::ActivateConfigChannel, + CONTEXT_SWITCH_DEFS__ACTION_TYPE_ACTIVATE_CFG_CHANNEL), + m_config_stream_index(config_stream_index), + m_channel_id(channel_id), + m_host_buffer_info(host_buffer_info) +{} + +bool ActivateConfigChannelAction::supports_repeated_block() const +{ + // Activate actions shouldn't be in repeated block for easier debug. + return false; +} + +Expected ActivateConfigChannelAction::serialize_params(const ContextResources &) const +{ + CONTEXT_SWITCH_DEFS__activate_cfg_channel_t params{}; + params.config_stream_index = m_config_stream_index; + params.packed_vdma_channel_id = pack_vdma_channel_id(m_channel_id); + params.host_buffer_info = m_host_buffer_info; + return Buffer::create(reinterpret_cast(¶ms), sizeof(params)); +} + +Expected DeactivateConfigChannelAction::create(uint8_t config_stream_index, + const vdma::ChannelId &channel_id) +{ + auto result = ContextSwitchConfigActionPtr(new (std::nothrow) DeactivateConfigChannelAction(config_stream_index, + channel_id)); + CHECK_AS_EXPECTED((nullptr != result), HAILO_OUT_OF_HOST_MEMORY); + return result; +} + +DeactivateConfigChannelAction::DeactivateConfigChannelAction(uint8_t config_stream_index, + const vdma::ChannelId &channel_id) : + ContextSwitchConfigAction(Type::DeactivateConfigChannel, + CONTEXT_SWITCH_DEFS__ACTION_TYPE_DEACTIVATE_CFG_CHANNEL), + m_config_stream_index(config_stream_index), + m_channel_id(channel_id) +{} + +bool DeactivateConfigChannelAction::supports_repeated_block() const +{ + // Activate actions shouldn't be in repeated block for easier debug. + return false; +} + +Expected DeactivateConfigChannelAction::serialize_params(const ContextResources &) const +{ + CONTEXT_SWITCH_DEFS__deactivate_cfg_channel_t params{}; + params.config_stream_index = m_config_stream_index; + params.packed_vdma_channel_id = pack_vdma_channel_id(m_channel_id); + return Buffer::create(reinterpret_cast(¶ms), sizeof(params)); +} + +Expected WriteDataCcwAction::create( + Buffer &&data, uint8_t config_stream_index) +{ + auto result = ContextSwitchConfigActionPtr(new (std::nothrow) WriteDataCcwAction( + std::move(data), config_stream_index)); + CHECK_AS_EXPECTED((nullptr != result), HAILO_OUT_OF_HOST_MEMORY); + return result; +} + +WriteDataCcwAction::WriteDataCcwAction(Buffer &&data, uint8_t config_stream_index) : + ContextSwitchConfigAction(Type::WriteDataCcw), + m_data(std::move(data)), + m_config_stream_index(config_stream_index) +{} + +Expected> WriteDataCcwAction::serialize(const ContextResources &, bool) const +{ + // WriteDataCcwActions aren't written to the FW's action list. Hence the execute will do nothing. + return std::vector(); +} + +bool WriteDataCcwAction::supports_repeated_block() const +{ + // WriteDataCcwActions aren't written to the FW's action list. Hence they can't be part of a repeated block. + return false; +} + +Expected WriteDataCcwAction::serialize_params(const ContextResources &) const +{ + return make_unexpected(HAILO_NOT_IMPLEMENTED); +} + +Expected AddCcwBurstAction::create(uint8_t config_stream_index, uint16_t ccw_bursts) +{ + auto result = ContextSwitchConfigActionPtr(new (std::nothrow) AddCcwBurstAction(config_stream_index, ccw_bursts)); + CHECK_AS_EXPECTED((nullptr != result), HAILO_OUT_OF_HOST_MEMORY); + return result; +} + +AddCcwBurstAction::AddCcwBurstAction(uint8_t config_stream_index, uint16_t ccw_bursts) : + ContextSwitchConfigAction(Type::AddCcwBurst, CONTEXT_SWITCH_DEFS__ACTION_TYPE_FETCH_CCW_BURSTS), + m_config_stream_index(config_stream_index), + m_ccw_bursts(ccw_bursts) +{} + +Expected AddCcwBurstAction::serialize_params(const ContextResources &) const +{ + CONTEXT_SWITCH_DEFS__fetch_ccw_bursts_action_data_t params{}; + params.ccw_bursts = m_ccw_bursts; + params.config_stream_index = m_config_stream_index; + return Buffer::create(reinterpret_cast(¶ms), sizeof(params)); +} + +bool AddCcwBurstAction::supports_repeated_block() const +{ + return false; +} + +Expected FetchCfgChannelDescriptorsAction::create(const vdma::ChannelId &channel_id, + uint16_t desc_count) +{ + auto result = ContextSwitchConfigActionPtr(new (std::nothrow) FetchCfgChannelDescriptorsAction(channel_id, + desc_count)); + CHECK_AS_EXPECTED((nullptr != result), HAILO_OUT_OF_HOST_MEMORY); + return result; +} + +FetchCfgChannelDescriptorsAction::FetchCfgChannelDescriptorsAction(const vdma::ChannelId &channel_id, uint16_t desc_count) : + ContextSwitchConfigAction(Type::FetchCfgChannelDescriptors, CONTEXT_SWITCH_DEFS__ACTION_TYPE_FETCH_CFG_CHANNEL_DESCRIPTORS), + m_channel_id(channel_id), + m_desc_count(desc_count) +{} + +bool FetchCfgChannelDescriptorsAction::supports_repeated_block() const +{ + return true; +} + +Expected FetchCfgChannelDescriptorsAction::serialize_params(const ContextResources &) const +{ + CONTEXT_SWITCH_DEFS__fetch_cfg_channel_descriptors_action_data_t params{}; + params.descriptors_count = m_desc_count; + params.packed_vdma_channel_id = pack_vdma_channel_id(m_channel_id); + return Buffer::create(reinterpret_cast(¶ms), sizeof(params)); +} + +Expected StartBurstCreditsTaskAction::create() +{ + auto result = ContextSwitchConfigActionPtr(new (std::nothrow) StartBurstCreditsTaskAction()); + CHECK_AS_EXPECTED((nullptr != result), HAILO_OUT_OF_HOST_MEMORY); + return result; +} + +StartBurstCreditsTaskAction::StartBurstCreditsTaskAction() : + ContextSwitchConfigAction(Type::StartBurstCreditsTask, CONTEXT_SWITCH_DEFS__ACTION_TYPE_BURST_CREDITS_TASK_START) +{} + +bool StartBurstCreditsTaskAction::supports_repeated_block() const +{ + // We don't support repeated blocks for this action, since only one is added per group of consecutive + // TriggerNewDataFromDataInput actions. + return false; +} + +Expected StartBurstCreditsTaskAction::serialize_params(const ContextResources &) const +{ + return Buffer::create(0); +} + +Expected WaitForNetworkGroupChangeAction::create() +{ + auto result = ContextSwitchConfigActionPtr(new (std::nothrow) WaitForNetworkGroupChangeAction()); + CHECK_AS_EXPECTED((nullptr != result), HAILO_OUT_OF_HOST_MEMORY); + return result; +} + +WaitForNetworkGroupChangeAction::WaitForNetworkGroupChangeAction() : + ContextSwitchConfigAction(Type::WaitForNetworkGroupChange, + CONTEXT_SWITCH_DEFS__ACTION_TYPE_APPLICATION_CHANGE_INTERRUPT) +{} + +bool WaitForNetworkGroupChangeAction::supports_repeated_block() const +{ + // Only one network group change action exists. + return false; +} + +Expected WaitForNetworkGroupChangeAction::serialize_params(const ContextResources &) const +{ + return Buffer::create(0); +} + + +Expected RepeatedAction::create( + std::vector &&actions) +{ + CHECK_AS_EXPECTED(!actions.empty(), HAILO_INVALID_HEF, "Invalid sub-action count (must be greater than zero)"); + CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(actions.size()), HAILO_INTERNAL_FAILURE, + "Too many repeated actions {}", actions.size()); + CHECK_AS_EXPECTED(actions[0]->supports_repeated_block(), HAILO_INVALID_HEF, + "Invalid repeated sub-action type (Action does not support repeated)"); + CHECK_AS_EXPECTED(actions[0]->get_action_list_type() != CONTEXT_SWITCH_DEFS__ACTION_TYPE_COUNT, HAILO_INVALID_HEF, + "Invalid repeated sub-action type (can't have sub-action with type CONTEXT_SWITCH_DEFS__ACTION_TYPE_COUNT)"); + + auto result = ContextSwitchConfigActionPtr(new (std::nothrow) RepeatedAction(std::move(actions))); + CHECK_AS_EXPECTED((nullptr != result), HAILO_OUT_OF_HOST_MEMORY); + return result; +} + +RepeatedAction::RepeatedAction(std::vector &&actions) : + ContextSwitchConfigAction(Type::AddRepeated, CONTEXT_SWITCH_DEFS__ACTION_TYPE_REPEATED_ACTION), + m_actions(std::move(actions)), + m_sub_action_type(m_actions[0]->get_action_list_type()) +{} + +bool RepeatedAction::supports_repeated_block() const +{ + // RepeatedActions can't be part of a repeated block themselves + return false; +} + +Expected RepeatedAction::serialize_params(const ContextResources &) const +{ + CONTEXT_SWITCH_DEFS__repeated_action_header_t params{}; + params.sub_action_type = m_sub_action_type; + params.last_executed = 0; + params.count = static_cast(m_actions.size()); + return Buffer::create(reinterpret_cast(¶ms), sizeof(params)); +} + +Expected> RepeatedAction::serialize(const ContextResources &context_resources, + bool is_repeated/*=false*/) const +{ + CHECK_AS_EXPECTED(!is_repeated, HAILO_INTERNAL_FAILURE, "Cant use recursive repeated"); + std::vector buffers; + buffers.reserve(m_actions.size() + 1); // Contains the repeated header and all of the actions + + auto repeated_header = ContextSwitchConfigAction::serialize(context_resources); + CHECK_EXPECTED(repeated_header); + CHECK_AS_EXPECTED(repeated_header->size() == 1, HAILO_INTERNAL_FAILURE, "Repeated action header should contain one buffer"); + buffers.emplace_back(std::move(repeated_header->at(0))); + + for (const auto &action : m_actions) { + assert(action->get_action_list_type() == m_sub_action_type); + const bool REPEATED = true; + auto action_buffers = action->serialize(context_resources, REPEATED); + CHECK_EXPECTED(action_buffers); + CHECK_AS_EXPECTED(action_buffers->size() == 1, HAILO_INTERNAL_FAILURE, "Sub action should contain one buffer"); + buffers.emplace_back(std::move(action_buffers->at(0))); + } + + return buffers; +} + +Expected DisableLcuAction::create(uint8_t cluster_index, uint8_t lcu_index) +{ + auto result = ContextSwitchConfigActionPtr(new (std::nothrow) DisableLcuAction(cluster_index, lcu_index)); + CHECK_AS_EXPECTED((nullptr != result), HAILO_OUT_OF_HOST_MEMORY); + return result; +} + +DisableLcuAction::DisableLcuAction(uint8_t cluster_index, uint8_t lcu_index) : + ContextSwitchConfigAction(Type::DisableLcu, CONTEXT_SWITCH_DEFS__ACTION_TYPE_DISABLE_LCU), + m_cluster_index(cluster_index), + m_lcu_index(lcu_index) +{} + +bool DisableLcuAction::supports_repeated_block() const +{ + return true; +} + +Expected DisableLcuAction::serialize_params(const ContextResources &) const +{ + CONTEXT_SWITCH_DEFS__disable_lcu_action_data_t params{}; + params.packed_lcu_id = pack_lcu_id(m_cluster_index, m_lcu_index); + return Buffer::create(reinterpret_cast(¶ms), sizeof(params)); +} + +Expected WaitForLcuAction::create(uint8_t cluster_index, uint8_t lcu_index) +{ + auto result = ContextSwitchConfigActionPtr(new (std::nothrow) WaitForLcuAction(cluster_index, lcu_index)); + CHECK_AS_EXPECTED((nullptr != result), HAILO_OUT_OF_HOST_MEMORY); + return result; +} + +WaitForLcuAction::WaitForLcuAction(uint8_t cluster_index, uint8_t lcu_index) : + ContextSwitchConfigAction(Type::WaitForLcu, CONTEXT_SWITCH_DEFS__ACTION_TYPE_LCU_INTERRUPT), + m_cluster_index(cluster_index), + m_lcu_index(lcu_index) +{} + +bool WaitForLcuAction::supports_repeated_block() const +{ + // Wait actions shouldn't be repeated (for easier debugging) + return false; +} + +Expected WaitForLcuAction::serialize_params(const ContextResources &) const +{ + CONTEXT_SWITCH_DEFS__lcu_interrupt_data_t params{}; + params.packed_lcu_id = pack_lcu_id(m_cluster_index, m_lcu_index); + return Buffer::create(reinterpret_cast(¶ms), sizeof(params)); +} + +Expected EnableLcuAction::create(uint8_t cluster_index, uint8_t lcu_index, + uint8_t network_index, uint16_t kernel_done_address, uint32_t kernel_done_count) +{ + const auto is_default = (CONTEXT_SWITCH_DEFS__ENABLE_LCU_DEFAULT_KERNEL_ADDRESS == kernel_done_address) && + (CONTEXT_SWITCH_DEFS__ENABLE_LCU_DEFAULT_KERNEL_COUNT == kernel_done_count); + auto result = ContextSwitchConfigActionPtr(new (std::nothrow) EnableLcuAction(cluster_index, lcu_index, + network_index, kernel_done_address, kernel_done_count, is_default)); + CHECK_AS_EXPECTED((nullptr != result), HAILO_OUT_OF_HOST_MEMORY); + return result; +} + +CONTEXT_SWITCH_DEFS__ACTION_TYPE_t EnableLcuAction::get_enable_lcu_action_type(bool is_default) +{ + return is_default ? CONTEXT_SWITCH_DEFS__ACTION_TYPE_ENABLE_LCU_DEFAULT : + CONTEXT_SWITCH_DEFS__ACTION_TYPE_ENABLE_LCU_NON_DEFAULT; +} + +ContextSwitchConfigAction::Type EnableLcuAction::get_enable_lcu_type(bool is_default) +{ + return is_default ? Type::EnableLcuDefault : Type::EnableLcuNonDefault; +} + +EnableLcuAction::EnableLcuAction(uint8_t cluster_index, uint8_t lcu_index, + uint8_t network_index, uint16_t kernel_done_address, uint32_t kernel_done_count, bool is_default) : + ContextSwitchConfigAction(get_enable_lcu_type(is_default), get_enable_lcu_action_type(is_default)), + m_cluster_index(cluster_index), + m_lcu_index(lcu_index), + m_network_index(network_index), + m_kernel_done_address(kernel_done_address), + m_kernel_done_count(kernel_done_count), + m_is_default(is_default) +{} + +Expected EnableLcuAction::serialize_params(const ContextResources &) const +{ + if (m_is_default) { + CONTEXT_SWITCH_DEFS__enable_lcu_action_default_data_t params{}; + params.packed_lcu_id = pack_lcu_id(m_cluster_index, m_lcu_index); + params.network_index = m_network_index; + return Buffer::create(reinterpret_cast(¶ms), sizeof(params)); + } + else { + CONTEXT_SWITCH_DEFS__enable_lcu_action_non_default_data_t params{}; + params.packed_lcu_id = pack_lcu_id(m_cluster_index, m_lcu_index); + params.kernel_done_address = m_kernel_done_address; + params.kernel_done_count = m_kernel_done_count; + params.network_index = m_network_index; + return Buffer::create(reinterpret_cast(¶ms), sizeof(params)); + } +} + +bool EnableLcuAction::supports_repeated_block() const +{ + return true; +} + +Expected EnableSequencerAction::create(uint8_t cluster_index, + uint8_t initial_l3_cut, uint16_t initial_l3_offset, uint32_t active_apu, uint32_t active_ia, + uint64_t active_sc, uint64_t active_l2, uint64_t l2_offset_0, uint64_t l2_offset_1) +{ + auto result = ContextSwitchConfigActionPtr(new (std::nothrow) EnableSequencerAction(cluster_index, initial_l3_cut, + initial_l3_offset, active_apu, active_ia, active_sc, active_l2, l2_offset_0, l2_offset_1)); + CHECK_AS_EXPECTED((nullptr != result), HAILO_OUT_OF_HOST_MEMORY); + return result; +} + +EnableSequencerAction::EnableSequencerAction(uint8_t cluster_index, uint8_t initial_l3_cut, uint16_t initial_l3_offset, + uint32_t active_apu, uint32_t active_ia, uint64_t active_sc, uint64_t active_l2, uint64_t l2_offset_0, + uint64_t l2_offset_1) : + ContextSwitchConfigAction(Type::TriggerSequencer, CONTEXT_SWITCH_DEFS__ACTION_TYPE_TRIGGER_SEQUENCER), + m_cluster_index(cluster_index), + m_initial_l3_cut(initial_l3_cut), + m_initial_l3_offset(initial_l3_offset), + m_active_apu(active_apu), + m_active_ia(active_ia), + m_active_sc(active_sc), + m_active_l2(active_l2), + m_l2_offset_0(l2_offset_0), + m_l2_offset_1(l2_offset_1) +{} + +bool EnableSequencerAction::supports_repeated_block() const +{ + return true; +} + +Expected EnableSequencerAction::serialize_params(const ContextResources &) const +{ + CONTEXT_SWITCH_DEFS__trigger_sequencer_action_data_t params{}; + params.cluster_index = m_cluster_index; + params.sequencer_config.initial_l3_cut = m_initial_l3_cut; + params.sequencer_config.initial_l3_offset = m_initial_l3_offset; + params.sequencer_config.active_apu = m_active_apu; + params.sequencer_config.active_ia = m_active_ia; + params.sequencer_config.active_sc = m_active_sc; + params.sequencer_config.active_l2 = m_active_l2; + params.sequencer_config.l2_offset_0 = m_l2_offset_0; + params.sequencer_config.l2_offset_1 = m_l2_offset_1; + return Buffer::create(reinterpret_cast(¶ms), sizeof(params)); +} + +Expected WaitForSequencerAction::create(uint8_t cluster_index) +{ + auto result = ContextSwitchConfigActionPtr(new (std::nothrow) WaitForSequencerAction(cluster_index)); + CHECK_AS_EXPECTED((nullptr != result), HAILO_OUT_OF_HOST_MEMORY); + return result; +} + +WaitForSequencerAction::WaitForSequencerAction(uint8_t cluster_index) : + ContextSwitchConfigAction(Type::WaitForSequencerDone, CONTEXT_SWITCH_DEFS__ACTION_TYPE_SEQUENCER_DONE_INTERRUPT), + m_cluster_index(cluster_index) +{} + +bool WaitForSequencerAction::supports_repeated_block() const +{ + // Wait actions shouldn't be repeated (for easier debugging) + return false; +} + +Expected WaitForSequencerAction::serialize_params(const ContextResources &) const +{ + CONTEXT_SWITCH_DEFS__sequencer_interrupt_data_t params{}; + params.sequencer_index = m_cluster_index; + return Buffer::create(reinterpret_cast(¶ms), sizeof(params)); +} + +Expected AllowInputDataflowAction::create(uint8_t stream_index) +{ + auto result = ContextSwitchConfigActionPtr(new (std::nothrow) AllowInputDataflowAction(stream_index)); + CHECK_AS_EXPECTED((nullptr != result), HAILO_OUT_OF_HOST_MEMORY); + return result; +} + + +AllowInputDataflowAction::AllowInputDataflowAction(uint8_t stream_index) : + ContextSwitchConfigAction(Type::TriggerNewDataFromDataInput, + CONTEXT_SWITCH_DEFS__ACTION_TYPE_FETCH_DATA_FROM_VDMA_CHANNEL), + m_stream_index(stream_index) +{} + +bool AllowInputDataflowAction::supports_repeated_block() const +{ + // DDR threads are implemented on HailoRT so no FW action is required. Hence they can't be part of a repeated block. + if (Type::TriggerNewDataFromDataInputDdr == m_type) { + return false; + } + + return true; +} + +Expected AllowInputDataflowAction::serialize_params(const ContextResources &context_resources) const +{ + for (const auto &edge_layer : context_resources.get_boundary_layers()) { + if (m_stream_index == edge_layer.layer_info.stream_index) { + CONTEXT_SWITCH_DEFS__fetch_data_action_data_t params{}; + params.packed_vdma_channel_id = pack_vdma_channel_id(edge_layer.channel_id); + params.stream_index = m_stream_index; + params.network_index = edge_layer.layer_info.network_index; + params.credit_type = CONTEXT_SWITCH_DEFS__CREDIT_IN_BYTES; + params.host_buffer_type = CONTROL_PROTOCOL__HOST_BUFFER_TYPE_t(edge_layer.buffer_info.buffer_type); + params.periph_bytes_per_buffer = edge_layer.layer_info.nn_stream_config.periph_bytes_per_buffer; + params.frame_periph_size = edge_layer.layer_info.nn_stream_config.periph_bytes_per_buffer * + edge_layer.layer_info.nn_stream_config.periph_buffers_per_frame; + return Buffer::create(reinterpret_cast(¶ms), sizeof(params)); + } + } + + for (const auto &edge_layer : context_resources.get_inter_context_layers()) { + if (m_stream_index == edge_layer.layer_info.stream_index) { + CONTEXT_SWITCH_DEFS__fetch_data_action_data_t params{}; + params.packed_vdma_channel_id = pack_vdma_channel_id(edge_layer.channel_id); + params.stream_index = m_stream_index; + params.network_index = edge_layer.layer_info.network_index; + params.credit_type = CONTEXT_SWITCH_DEFS__CREDIT_IN_DESCRIPTORS; + params.host_buffer_type = CONTROL_PROTOCOL__HOST_BUFFER_TYPE_t(edge_layer.buffer_info.buffer_type); + params.periph_bytes_per_buffer = edge_layer.layer_info.nn_stream_config.periph_bytes_per_buffer; + params.frame_periph_size = ((edge_layer.buffer_info.bytes_in_pattern - 1) / (edge_layer.buffer_info.desc_page_size)) + 1; + return Buffer::create(reinterpret_cast(¶ms), sizeof(params)); + } + } + + LOGGER__ERROR("Stream {} not found in edge layers", m_stream_index); + return make_unexpected(HAILO_INTERNAL_FAILURE); +} + +Expected WaitForModuleConfigDoneAction::create(uint8_t module_index) +{ + auto result = ContextSwitchConfigActionPtr(new (std::nothrow) WaitForModuleConfigDoneAction(module_index)); + CHECK_AS_EXPECTED((nullptr != result), HAILO_OUT_OF_HOST_MEMORY); + return result; +} + +WaitForModuleConfigDoneAction::WaitForModuleConfigDoneAction(uint8_t module_index) : + ContextSwitchConfigAction(Type::WaitForModuleConfigDone, CONTEXT_SWITCH_DEFS__ACTION_TYPE_MODULE_CONFIG_DONE_INTERRUPT), + m_module_index(module_index) +{} + +bool WaitForModuleConfigDoneAction::supports_repeated_block() const +{ + // Wait actions shouldn't be repeated (for easier debugging) + return false; +} + +Expected WaitForModuleConfigDoneAction::serialize_params(const ContextResources &) const +{ + CONTEXT_SWITCH_DEFS__module_config_done_interrupt_data_t params{}; + params.module_index = m_module_index; + return Buffer::create(reinterpret_cast(¶ms), sizeof(params)); +} + +Expected DdrPairInfoAction::create(const vdma::ChannelId &h2d_channel_id, + const vdma::ChannelId &d2h_channel_id, uint8_t network_index, uint32_t descriptors_per_frame, uint16_t descs_count) +{ + auto result = ContextSwitchConfigActionPtr(new (std::nothrow) DdrPairInfoAction( + h2d_channel_id, d2h_channel_id, network_index, descriptors_per_frame, descs_count)); + CHECK_AS_EXPECTED((nullptr != result), HAILO_OUT_OF_HOST_MEMORY); + return result; +} + +DdrPairInfoAction::DdrPairInfoAction(const vdma::ChannelId &h2d_channel_id, const vdma::ChannelId &d2h_channel_id, + uint8_t network_index, uint32_t descriptors_per_frame, uint16_t descs_count) : + ContextSwitchConfigAction(Type::DdrPairInfo, CONTEXT_SWITCH_DEFS__ACTION_TYPE_ADD_DDR_PAIR_INFO), + m_h2d_channel_id(h2d_channel_id), + m_d2h_channel_id(d2h_channel_id), + m_network_index(network_index), + m_descriptors_per_frame(descriptors_per_frame), + m_descs_count(descs_count) +{} + +bool DdrPairInfoAction::supports_repeated_block() const +{ + return true; +} + +Expected DdrPairInfoAction::serialize_params(const ContextResources &) const +{ + CONTEXT_SWITCH_DEFS__add_ddr_pair_info_action_data_t params{}; + params.h2d_packed_vdma_channel_id = pack_vdma_channel_id(m_h2d_channel_id); + params.d2h_packed_vdma_channel_id = pack_vdma_channel_id(m_d2h_channel_id); + params.network_index = m_network_index; + params.descriptors_per_frame = m_descriptors_per_frame; + params.programmed_descriptors_count = m_descs_count; + return Buffer::create(reinterpret_cast(¶ms), sizeof(params)); +} + +Expected StartDdrBufferingTaskAction::create() +{ + auto result = ContextSwitchConfigActionPtr(new (std::nothrow) StartDdrBufferingTaskAction()); + CHECK_AS_EXPECTED((nullptr != result), HAILO_OUT_OF_HOST_MEMORY); + return result; +} + +StartDdrBufferingTaskAction::StartDdrBufferingTaskAction() : + ContextSwitchConfigAction(Type::StartDdrBufferingTask, CONTEXT_SWITCH_DEFS__ACTION_TYPE_DDR_BUFFERING_START) +{} + +bool StartDdrBufferingTaskAction::supports_repeated_block() const +{ + // There should only be one "start ddr buffering task action" per context, + // so there's no need to support repeated blocks. + return false; +} + +Expected StartDdrBufferingTaskAction::serialize_params(const ContextResources &) const +{ + return Buffer::create(0); +} + +Expected ResetDdrBufferingTaskAction::create() +{ + auto result = ContextSwitchConfigActionPtr(new (std::nothrow) ResetDdrBufferingTaskAction()); + CHECK_AS_EXPECTED((nullptr != result), HAILO_OUT_OF_HOST_MEMORY); + return result; +} + +ResetDdrBufferingTaskAction::ResetDdrBufferingTaskAction() : + ContextSwitchConfigAction(Type::ResetDdrBufferingTask, CONTEXT_SWITCH_DEFS__ACTION_TYPE_DDR_BUFFERING_RESET) +{} + +bool ResetDdrBufferingTaskAction::supports_repeated_block() const +{ + // There should only be one "reset ddr buffering task action" per context at most, + // so there's no need to support repeated blocks. + return false; +} + +Expected ResetDdrBufferingTaskAction::serialize_params(const ContextResources &) const +{ + return Buffer::create(0); +} + +Expected ChangeVdmaToStreamMapping::create(const vdma::ChannelId &channel_id, + uint8_t stream_index, bool is_dummy_stream) +{ + auto result = ContextSwitchConfigActionPtr(new (std::nothrow) ChangeVdmaToStreamMapping(channel_id, stream_index, + is_dummy_stream)); + CHECK_AS_EXPECTED((nullptr != result), HAILO_OUT_OF_HOST_MEMORY); + return result; +} + +ChangeVdmaToStreamMapping::ChangeVdmaToStreamMapping(const vdma::ChannelId &channel_id, uint8_t stream_index, + bool is_dummy_stream) : + ContextSwitchConfigAction(Type::ChangeVdmaToStreamMapping, + CONTEXT_SWITCH_DEFS__ACTION_TYPE_CHANGE_VDMA_TO_STREAM_MAPPING), + m_channel_id(channel_id), + m_stream_index(stream_index), + m_is_dummy_stream(is_dummy_stream) +{} + +bool ChangeVdmaToStreamMapping::supports_repeated_block() const +{ + return true; +} + +Expected ChangeVdmaToStreamMapping::serialize_params(const ContextResources &) const +{ + CONTEXT_SWITCH_DEFS__change_vdma_to_stream_mapping_data_t params{}; + params.packed_vdma_channel_id = pack_vdma_channel_id(m_channel_id); + params.stream_index = m_stream_index; + params.is_dummy_stream = m_is_dummy_stream; + return Buffer::create(reinterpret_cast(¶ms), sizeof(params)); +} + +Expected WaitOutputTransferDoneAction::create(uint8_t stream_index) +{ + auto result = ContextSwitchConfigActionPtr(new (std::nothrow) WaitOutputTransferDoneAction(stream_index)); + CHECK_AS_EXPECTED((nullptr != result), HAILO_OUT_OF_HOST_MEMORY); + return result; +} + +WaitOutputTransferDoneAction::WaitOutputTransferDoneAction(uint8_t stream_index) : + ContextSwitchConfigAction(ContextSwitchConfigAction::Type::WaitOutputTransferDone, CONTEXT_SWITCH_DEFS__ACTION_TYPE_OUTPUT_CHANNEL_TRANSFER_DONE_INTERRUPT), + m_stream_index(stream_index) +{} + +bool WaitOutputTransferDoneAction::supports_repeated_block() const +{ + // Wait actions shouldn't be repeated (for easier debugging) + return false; +} + +Expected WaitOutputTransferDoneAction::serialize_params(const ContextResources &context_resources) const +{ + const auto channel_id = get_layer_channel_id(context_resources); + CHECK_EXPECTED(channel_id); + + CONTEXT_SWITCH_DEFS__vdma_dataflow_interrupt_data_t params{}; + params.packed_vdma_channel_id = pack_vdma_channel_id(channel_id.value()); + return Buffer::create(reinterpret_cast(¶ms), sizeof(params)); +} + +Expected WaitOutputTransferDoneAction::get_layer_channel_id(const ContextResources &context_resources) const +{ + // TODO: HRT-8611 use one loop + for (const auto &edge_layer : context_resources.get_boundary_layers()) { + if (m_stream_index == edge_layer.layer_info.stream_index) { + return vdma::ChannelId(edge_layer.channel_id); + } + } + + for (const auto &edge_layer : context_resources.get_inter_context_layers()) { + if (m_stream_index == edge_layer.layer_info.stream_index) { + return vdma::ChannelId(edge_layer.channel_id); + } + } + + LOGGER__ERROR("Stream {} not found in edge layers", m_stream_index); + return make_unexpected(HAILO_INTERNAL_FAILURE); +} + +Expected OpenBoundaryInputChannelAction::create(const vdma::ChannelId &channel_id, + const CONTROL_PROTOCOL__host_buffer_info_t &host_buffer_info) +{ + auto result = ContextSwitchConfigActionPtr(new (std::nothrow) OpenBoundaryInputChannelAction(channel_id, + host_buffer_info)); + CHECK_AS_EXPECTED((nullptr != result), HAILO_OUT_OF_HOST_MEMORY); + return result; +} + +OpenBoundaryInputChannelAction::OpenBoundaryInputChannelAction(const vdma::ChannelId &channel_id, + const CONTROL_PROTOCOL__host_buffer_info_t &host_buffer_info) : + ContextSwitchConfigAction(ContextSwitchConfigAction::Type::OpenBoundaryInputChannel, + CONTEXT_SWITCH_DEFS__ACTION_TYPE_OPEN_BOUNDARY_INPUT_CHANNEL), + m_channel_id(channel_id), + m_host_buffer_info(host_buffer_info) +{} + +bool OpenBoundaryInputChannelAction::supports_repeated_block() const +{ + // Open boundary actions shouldn't be repeated (for easier debugging). + return false; +} + +Expected OpenBoundaryInputChannelAction::serialize_params(const ContextResources &) const +{ + CONTEXT_SWITCH_DEFS__open_boundary_input_channel_data_t params{}; + params.packed_vdma_channel_id = pack_vdma_channel_id(m_channel_id); + params.host_buffer_info = m_host_buffer_info; + return Buffer::create(reinterpret_cast(¶ms), sizeof(params)); +} + +Expected OpenBoundaryOutputChannelAction::create(const vdma::ChannelId &channel_id, + const CONTROL_PROTOCOL__host_buffer_info_t &host_buffer_info) +{ + auto result = ContextSwitchConfigActionPtr(new (std::nothrow) OpenBoundaryOutputChannelAction(channel_id, + host_buffer_info)); + CHECK_AS_EXPECTED((nullptr != result), HAILO_OUT_OF_HOST_MEMORY); + return result; +} + +OpenBoundaryOutputChannelAction::OpenBoundaryOutputChannelAction(const vdma::ChannelId &channel_id, + const CONTROL_PROTOCOL__host_buffer_info_t &host_buffer_info) : + ContextSwitchConfigAction(ContextSwitchConfigAction::Type::OpenBoundaryOutputChannel, + CONTEXT_SWITCH_DEFS__ACTION_TYPE_OPEN_BOUNDARY_OUTPUT_CHANNEL), + m_channel_id(channel_id), + m_host_buffer_info(host_buffer_info) +{} + +bool OpenBoundaryOutputChannelAction::supports_repeated_block() const +{ + // Open boundary actions shouldn't be repeated (for easier debugging). + return false; +} + +Expected OpenBoundaryOutputChannelAction::serialize_params(const ContextResources &) const +{ + CONTEXT_SWITCH_DEFS__open_boundary_output_channel_data_t params{}; + params.packed_vdma_channel_id = pack_vdma_channel_id(m_channel_id); + params.host_buffer_info = m_host_buffer_info; + return Buffer::create(reinterpret_cast(¶ms), sizeof(params)); +} + +// TODO HRT-8705: remove nn_stream_config struct (that this function won't be needed) +static CONTEXT_SWITCH_DEFS__stream_reg_info_t parse_nn_config(const CONTROL_PROTOCOL__nn_stream_config_t &nn_config) +{ + CONTEXT_SWITCH_DEFS__stream_reg_info_t reg_info{}; + reg_info.core_bytes_per_buffer = nn_config.core_bytes_per_buffer; + reg_info.core_buffers_per_frame = nn_config.core_buffers_per_frame; + reg_info.feature_padding_payload = nn_config.feature_padding_payload; + reg_info.buffer_padding_payload = nn_config.buffer_padding_payload; + reg_info.buffer_padding = nn_config.buffer_padding; + reg_info.periph_bytes_per_buffer = nn_config.periph_bytes_per_buffer; + reg_info.periph_buffers_per_frame = nn_config.periph_buffers_per_frame; + return reg_info; +} + +Expected ActivateBoundaryInputChannelAction::create(const vdma::ChannelId &channel_id, + uint8_t stream_index, const CONTROL_PROTOCOL__nn_stream_config_t &nn_stream_config, + const CONTROL_PROTOCOL__host_buffer_info_t &host_buffer_info, uint32_t initial_credit_size) +{ + auto result = ContextSwitchConfigActionPtr(new (std::nothrow) ActivateBoundaryInputChannelAction(channel_id, + stream_index, nn_stream_config, host_buffer_info, initial_credit_size)); + CHECK_AS_EXPECTED((nullptr != result), HAILO_OUT_OF_HOST_MEMORY); + return result; +} + +ActivateBoundaryInputChannelAction::ActivateBoundaryInputChannelAction(const vdma::ChannelId &channel_id, + uint8_t stream_index, const CONTROL_PROTOCOL__nn_stream_config_t &nn_stream_config, + const CONTROL_PROTOCOL__host_buffer_info_t &host_buffer_info, uint32_t initial_credit_size) : + ContextSwitchConfigAction(ContextSwitchConfigAction::Type::ActivateBoundaryInputChannel, + CONTEXT_SWITCH_DEFS__ACTION_TYPE_ACTIVATE_BOUNDARY_INPUT), + m_channel_id(channel_id), + m_stream_index(stream_index), + m_nn_stream_config(nn_stream_config), + m_host_buffer_info(host_buffer_info), + m_initial_credit_size(initial_credit_size) +{} + +bool ActivateBoundaryInputChannelAction::supports_repeated_block() const +{ + // Activate actions shouldn't be repeated (for easier debugging). + return false; +} + +Expected ActivateBoundaryInputChannelAction::serialize_params(const ContextResources &) const +{ + CONTEXT_SWITCH_DEFS__activate_boundary_input_data_t params{}; + params.packed_vdma_channel_id = pack_vdma_channel_id(m_channel_id); + params.stream_index = m_stream_index; + params.stream_reg_info = parse_nn_config(m_nn_stream_config); + params.host_buffer_info = m_host_buffer_info; + params.initial_credit_size = m_initial_credit_size; + return Buffer::create(reinterpret_cast(¶ms), sizeof(params)); +} + +Expected ActivateBoundaryOutputChannelAction::create(const vdma::ChannelId &channel_id, + uint8_t stream_index, const CONTROL_PROTOCOL__nn_stream_config_t &nn_stream_config, + const CONTROL_PROTOCOL__host_buffer_info_t &host_buffer_info) +{ + auto result = ContextSwitchConfigActionPtr(new (std::nothrow) ActivateBoundaryOutputChannelAction(channel_id, + stream_index, nn_stream_config, host_buffer_info)); + CHECK_AS_EXPECTED((nullptr != result), HAILO_OUT_OF_HOST_MEMORY); + return result; +} + +ActivateBoundaryOutputChannelAction::ActivateBoundaryOutputChannelAction(const vdma::ChannelId &channel_id, + uint8_t stream_index, const CONTROL_PROTOCOL__nn_stream_config_t &nn_stream_config, + const CONTROL_PROTOCOL__host_buffer_info_t &host_buffer_info) : + ContextSwitchConfigAction(ContextSwitchConfigAction::Type::ActivateBoundaryOutputChannel, + CONTEXT_SWITCH_DEFS__ACTION_TYPE_ACTIVATE_BOUNDARY_OUTPUT), + m_channel_id(channel_id), + m_stream_index(stream_index), + m_nn_stream_config(nn_stream_config), + m_host_buffer_info(host_buffer_info) +{} + +bool ActivateBoundaryOutputChannelAction::supports_repeated_block() const +{ + // Activate actions shouldn't be repeated (for easier debugging). + return false; +} + +Expected ActivateBoundaryOutputChannelAction::serialize_params(const ContextResources &) const +{ + CONTEXT_SWITCH_DEFS__activate_boundary_output_data_t params{}; + params.packed_vdma_channel_id = pack_vdma_channel_id(m_channel_id); + params.stream_index = m_stream_index; + params.stream_reg_info = parse_nn_config(m_nn_stream_config); + params.host_buffer_info = m_host_buffer_info; + return Buffer::create(reinterpret_cast(¶ms), sizeof(params)); +} + +Expected ActivateInterContextInputChannelAction::create(const vdma::ChannelId &channel_id, + uint8_t stream_index, const CONTROL_PROTOCOL__nn_stream_config_t &nn_stream_config, + const CONTROL_PROTOCOL__host_buffer_info_t &host_buffer_info, uint32_t initial_credit_size) +{ + auto result = ContextSwitchConfigActionPtr(new (std::nothrow) ActivateInterContextInputChannelAction(channel_id, + stream_index, nn_stream_config, host_buffer_info, initial_credit_size)); + CHECK_AS_EXPECTED((nullptr != result), HAILO_OUT_OF_HOST_MEMORY); + return result; +} + +ActivateInterContextInputChannelAction::ActivateInterContextInputChannelAction(const vdma::ChannelId &channel_id, + uint8_t stream_index, const CONTROL_PROTOCOL__nn_stream_config_t &nn_stream_config, + const CONTROL_PROTOCOL__host_buffer_info_t &host_buffer_info, uint32_t initial_credit_size) : + ContextSwitchConfigAction(ContextSwitchConfigAction::Type::ActivateInterContextInputChannel, + CONTEXT_SWITCH_DEFS__ACTION_TYPE_ACTIVATE_INTER_CONTEXT_INPUT), + m_channel_id(channel_id), + m_stream_index(stream_index), + m_nn_stream_config(nn_stream_config), + m_host_buffer_info(host_buffer_info), + m_initial_credit_size(initial_credit_size) +{} + +bool ActivateInterContextInputChannelAction::supports_repeated_block() const +{ + // Activate actions shouldn't be repeated (for easier debugging). + return false; +} + +Expected ActivateInterContextInputChannelAction::serialize_params(const ContextResources &) const +{ + CONTEXT_SWITCH_DEFS__activate_inter_context_input_data_t params{}; + params.packed_vdma_channel_id = pack_vdma_channel_id(m_channel_id); + params.stream_index = m_stream_index; + params.stream_reg_info = parse_nn_config(m_nn_stream_config); + params.host_buffer_info = m_host_buffer_info; + params.initial_credit_size = m_initial_credit_size; + return Buffer::create(reinterpret_cast(¶ms), sizeof(params)); +} + +Expected ActivateInterContextOutputChannelAction::create(const vdma::ChannelId &channel_id, + uint8_t stream_index, uint8_t network_index, const CONTROL_PROTOCOL__nn_stream_config_t &nn_stream_config, + const CONTROL_PROTOCOL__host_buffer_info_t &host_buffer_info) +{ + auto result = ContextSwitchConfigActionPtr(new (std::nothrow) ActivateInterContextOutputChannelAction(channel_id, + stream_index, network_index, nn_stream_config, host_buffer_info)); + CHECK_AS_EXPECTED((nullptr != result), HAILO_OUT_OF_HOST_MEMORY); + return result; +} + +ActivateInterContextOutputChannelAction::ActivateInterContextOutputChannelAction(const vdma::ChannelId &channel_id, + uint8_t stream_index, uint8_t network_index, const CONTROL_PROTOCOL__nn_stream_config_t &nn_stream_config, + const CONTROL_PROTOCOL__host_buffer_info_t &host_buffer_info) : + ContextSwitchConfigAction(ContextSwitchConfigAction::Type::ActivateInterContextOutputChannel, + CONTEXT_SWITCH_DEFS__ACTION_TYPE_ACTIVATE_INTER_CONTEXT_OUTPUT), + m_channel_id(channel_id), + m_stream_index(stream_index), + m_network_index(network_index), + m_nn_stream_config(nn_stream_config), + m_host_buffer_info(host_buffer_info) +{} + +bool ActivateInterContextOutputChannelAction::supports_repeated_block() const +{ + // Activate actions shouldn't be repeated (for easier debugging). + return false; +} + +Expected ActivateInterContextOutputChannelAction::serialize_params(const ContextResources &) const +{ + CONTEXT_SWITCH_DEFS__activate_inter_context_output_data_t params{}; + params.packed_vdma_channel_id = pack_vdma_channel_id(m_channel_id); + params.stream_index = m_stream_index; + params.network_index = m_network_index; + params.stream_reg_info = parse_nn_config(m_nn_stream_config); + params.host_buffer_info = m_host_buffer_info; + return Buffer::create(reinterpret_cast(¶ms), sizeof(params)); +} + +Expected ActivateDdrInputChannelAction::create(const vdma::ChannelId &channel_id, + uint8_t stream_index, const CONTROL_PROTOCOL__nn_stream_config_t &nn_stream_config, + const CONTROL_PROTOCOL__host_buffer_info_t &host_buffer_info, uint32_t initial_credit_size, + const vdma::ChannelId &connected_d2h_channel_id) +{ + auto result = ContextSwitchConfigActionPtr(new (std::nothrow) ActivateDdrInputChannelAction(channel_id, + stream_index, nn_stream_config, host_buffer_info, initial_credit_size, connected_d2h_channel_id)); + CHECK_AS_EXPECTED((nullptr != result), HAILO_OUT_OF_HOST_MEMORY); + return result; +} + +ActivateDdrInputChannelAction::ActivateDdrInputChannelAction(const vdma::ChannelId &channel_id, + uint8_t stream_index, const CONTROL_PROTOCOL__nn_stream_config_t &nn_stream_config, + const CONTROL_PROTOCOL__host_buffer_info_t &host_buffer_info, uint32_t initial_credit_size, + const vdma::ChannelId &connected_d2h_channel_id) : + ContextSwitchConfigAction(ContextSwitchConfigAction::Type::ActivateDdrInputChannel, + CONTEXT_SWITCH_DEFS__ACTION_TYPE_ACTIVATE_DDR_BUFFER_INPUT), + m_channel_id(channel_id), + m_stream_index(stream_index), + m_nn_stream_config(nn_stream_config), + m_host_buffer_info(host_buffer_info), + m_initial_credit_size(initial_credit_size), + m_connected_d2h_channel_id(connected_d2h_channel_id) +{} + +bool ActivateDdrInputChannelAction::supports_repeated_block() const +{ + // Activate actions shouldn't be repeated (for easier debugging). + return false; +} + +Expected ActivateDdrInputChannelAction::serialize_params(const ContextResources &) const +{ + CONTEXT_SWITCH_DEFS__activate_ddr_buffer_input_data_t params{}; + params.packed_vdma_channel_id = pack_vdma_channel_id(m_channel_id); + params.stream_index = m_stream_index; + params.stream_reg_info = parse_nn_config(m_nn_stream_config); + params.host_buffer_info = m_host_buffer_info; + params.initial_credit_size = m_initial_credit_size; + params.connected_d2h_packed_vdma_channel_id = pack_vdma_channel_id(m_connected_d2h_channel_id); + return Buffer::create(reinterpret_cast(¶ms), sizeof(params)); +} + +Expected ActivateDdrOutputChannelAction::create(const vdma::ChannelId &channel_id, + uint8_t stream_index, const CONTROL_PROTOCOL__nn_stream_config_t &nn_stream_config, + const CONTROL_PROTOCOL__host_buffer_info_t &host_buffer_info, uint32_t buffered_rows_count) +{ + auto result = ContextSwitchConfigActionPtr(new (std::nothrow) ActivateDdrOutputChannelAction(channel_id, + stream_index, nn_stream_config, host_buffer_info, buffered_rows_count)); + CHECK_AS_EXPECTED((nullptr != result), HAILO_OUT_OF_HOST_MEMORY); + return result; +} + +ActivateDdrOutputChannelAction::ActivateDdrOutputChannelAction(const vdma::ChannelId &channel_id, + uint8_t stream_index, const CONTROL_PROTOCOL__nn_stream_config_t &nn_stream_config, + const CONTROL_PROTOCOL__host_buffer_info_t &host_buffer_info, uint32_t buffered_rows_count) : + ContextSwitchConfigAction(ContextSwitchConfigAction::Type::ActivateDdrOutputChannel, + CONTEXT_SWITCH_DEFS__ACTION_TYPE_ACTIVATE_DDR_BUFFER_OUTPUT), + m_channel_id(channel_id), + m_stream_index(stream_index), + m_nn_stream_config(nn_stream_config), + m_host_buffer_info(host_buffer_info), + m_buffered_rows_count(buffered_rows_count) +{} + +bool ActivateDdrOutputChannelAction::supports_repeated_block() const +{ + // Activate actions shouldn't be repeated (for easier debugging). + return false; +} + +Expected ActivateDdrOutputChannelAction::serialize_params(const ContextResources &) const +{ + CONTEXT_SWITCH_DEFS__activate_ddr_buffer_output_data_t params{}; + params.packed_vdma_channel_id = pack_vdma_channel_id(m_channel_id); + params.stream_index = m_stream_index; + params.stream_reg_info = parse_nn_config(m_nn_stream_config); + params.host_buffer_info = m_host_buffer_info; + params.buffered_rows_count = m_buffered_rows_count; + return Buffer::create(reinterpret_cast(¶ms), sizeof(params)); +} + +Expected ValidateChannelAction::create(const vdma::ChannelId &channel_id, + hailo_stream_direction_t stream_direction, bool is_inter_context, + CONTROL_PROTOCOL__HOST_BUFFER_TYPE_t host_buffer_type, uint32_t initial_credit_size) +{ + auto result = ContextSwitchConfigActionPtr(new (std::nothrow) ValidateChannelAction(channel_id, stream_direction, + is_inter_context, host_buffer_type, initial_credit_size)); + CHECK_AS_EXPECTED((nullptr != result), HAILO_OUT_OF_HOST_MEMORY); + return result; +} + +ValidateChannelAction::ValidateChannelAction(const vdma::ChannelId &channel_id, + hailo_stream_direction_t stream_direction, bool is_inter_context, + CONTROL_PROTOCOL__HOST_BUFFER_TYPE_t host_buffer_type, uint32_t initial_credit_size) : + ContextSwitchConfigAction(ContextSwitchConfigAction::Type::ValidateChannel, + CONTEXT_SWITCH_DEFS__ACTION_TYPE_VALIDATE_VDMA_CHANNEL), + m_channel_id(channel_id), + m_stream_direction(stream_direction), + m_is_inter_context(is_inter_context), + m_host_buffer_type(host_buffer_type), + m_initial_credit_size(initial_credit_size) +{} + +bool ValidateChannelAction::supports_repeated_block() const +{ + // Validate action shouldn't be repeated (for easier debugging). + return false; +} + +Expected ValidateChannelAction::serialize_params(const ContextResources &) const +{ + CONTEXT_SWITCH_DEFS__validate_vdma_channel_action_data_t params{}; + params.packed_vdma_channel_id = pack_vdma_channel_id(m_channel_id); + params.edge_layer_direction = m_stream_direction == HAILO_H2D_STREAM ? + static_cast(CONTEXT_SWITCH_DEFS__EDGE_LAYER_DIRECTION_HOST_TO_DEVICE) : + static_cast(CONTEXT_SWITCH_DEFS__EDGE_LAYER_DIRECTION_DEVICE_TO_HOST); + params.is_inter_context = m_is_inter_context; + params.host_buffer_type = static_cast(m_host_buffer_type); + params.initial_credit_size = m_initial_credit_size; + return Buffer::create(reinterpret_cast(¶ms), sizeof(params)); +} + +Expected DeactivateChannelAction::create(const vdma::ChannelId &channel_id, + hailo_stream_direction_t stream_direction, bool is_inter_context, + CONTROL_PROTOCOL__HOST_BUFFER_TYPE_t host_buffer_type, uint32_t initial_credit_size) +{ + auto result = ContextSwitchConfigActionPtr(new (std::nothrow) DeactivateChannelAction(channel_id, stream_direction, + is_inter_context, host_buffer_type, initial_credit_size)); + CHECK_AS_EXPECTED((nullptr != result), HAILO_OUT_OF_HOST_MEMORY); + return result; +} + +DeactivateChannelAction::DeactivateChannelAction(const vdma::ChannelId &channel_id, + hailo_stream_direction_t stream_direction, bool is_inter_context, + CONTROL_PROTOCOL__HOST_BUFFER_TYPE_t host_buffer_type, uint32_t initial_credit_size) : + ContextSwitchConfigAction(ContextSwitchConfigAction::Type::DeactivateChannel, + CONTEXT_SWITCH_DEFS__ACTION_TYPE_DEACTIVATE_VDMA_CHANNEL), + m_channel_id(channel_id), + m_stream_direction(stream_direction), + m_is_inter_context(is_inter_context), + m_host_buffer_type(host_buffer_type), + m_initial_credit_size(initial_credit_size) +{} + +bool DeactivateChannelAction::supports_repeated_block() const +{ + // Deactivate action shouldn't be repeated (for easier debugging). + return false; +} + +Expected DeactivateChannelAction::serialize_params(const ContextResources &) const +{ + CONTEXT_SWITCH_DEFS__deactivate_vdma_channel_action_data_t params{}; + params.packed_vdma_channel_id = pack_vdma_channel_id(m_channel_id); + params.edge_layer_direction = m_stream_direction == HAILO_H2D_STREAM ? + static_cast(CONTEXT_SWITCH_DEFS__EDGE_LAYER_DIRECTION_HOST_TO_DEVICE) : + static_cast(CONTEXT_SWITCH_DEFS__EDGE_LAYER_DIRECTION_DEVICE_TO_HOST); + params.is_inter_context = m_is_inter_context; + params.host_buffer_type = static_cast(m_host_buffer_type); + params.initial_credit_size = m_initial_credit_size; + return Buffer::create(reinterpret_cast(¶ms), sizeof(params)); +} + +Expected WaitDmaIdleAction::create(uint8_t stream_index) +{ + auto result = ContextSwitchConfigActionPtr(new (std::nothrow) WaitDmaIdleAction(stream_index)); + CHECK_AS_EXPECTED((nullptr != result), HAILO_OUT_OF_HOST_MEMORY); + return result; +} + +WaitDmaIdleAction::WaitDmaIdleAction(uint8_t stream_index) : + ContextSwitchConfigAction(ContextSwitchConfigAction::Type::WaitDmaIdle, CONTEXT_SWITCH_DEFS__ACTION_TYPE_WAIT_FOR_DMA_IDLE_ACTION), + m_stream_index(stream_index) +{} + +bool WaitDmaIdleAction::supports_repeated_block() const +{ + // Wait actions shouldn't be repeated (for easier debugging) + return false; +} + +Expected WaitDmaIdleAction::serialize_params(const ContextResources &context_resources) const +{ + auto channel_and_type = get_layer_channel_id_and_type(context_resources); + CHECK_EXPECTED(channel_and_type); + + const auto channel_id = channel_and_type->first; + assert(LayerType::INTER_CONTEXT == channel_and_type->second || LayerType::BOUNDARY == channel_and_type->second); + const bool is_inter_context = (LayerType::INTER_CONTEXT == channel_and_type->second); + + CONTEXT_SWITCH_DEFS__wait_dma_idle_data_t params{}; + params.packed_vdma_channel_id = pack_vdma_channel_id(channel_id); + params.is_inter_context = static_cast(is_inter_context); + params.stream_index = m_stream_index; + return Buffer::create(reinterpret_cast(¶ms), sizeof(params)); +} + +Expected> WaitDmaIdleAction::get_layer_channel_id_and_type( + const ContextResources &context_resources) const +{ + // TODO: HRT-8611 use one loop + for (const auto &edge_layer : context_resources.get_boundary_layers()) { + if (m_stream_index == edge_layer.layer_info.stream_index) { + return std::make_pair(edge_layer.channel_id, LayerType::BOUNDARY); + } + } + + for (const auto &edge_layer : context_resources.get_inter_context_layers()) { + if (m_stream_index == edge_layer.layer_info.stream_index) { + return std::make_pair(edge_layer.channel_id, LayerType::INTER_CONTEXT); + } + } + + LOGGER__ERROR("Stream {} not found in edge layers (as boundary or inter context)", m_stream_index); + return make_unexpected(HAILO_INTERNAL_FAILURE); +} + +Expected WaitNmsIdleAction::create(uint8_t aggregator_index, + uint8_t pred_cluster_ob_index, uint8_t pred_cluster_ob_cluster_index, uint8_t pred_cluster_ob_interface, + uint8_t succ_prepost_ob_index, uint8_t succ_prepost_ob_interface) +{ + auto result = ContextSwitchConfigActionPtr(new (std::nothrow) WaitNmsIdleAction(aggregator_index, + pred_cluster_ob_index, pred_cluster_ob_cluster_index, pred_cluster_ob_interface, succ_prepost_ob_index, + succ_prepost_ob_interface)); + CHECK_AS_EXPECTED((nullptr != result), HAILO_OUT_OF_HOST_MEMORY); + return result; +} + +WaitNmsIdleAction::WaitNmsIdleAction(uint8_t aggregator_index, uint8_t pred_cluster_ob_index, uint8_t pred_cluster_ob_cluster_index, + uint8_t pred_cluster_ob_interface, uint8_t succ_prepost_ob_index, uint8_t succ_prepost_ob_interface) : + ContextSwitchConfigAction(ContextSwitchConfigAction::Type::WaitNmsIdle, CONTEXT_SWITCH_DEFS__ACTION_TYPE_WAIT_FOR_NMS), + m_aggregator_index(aggregator_index), + m_pred_cluster_ob_index(pred_cluster_ob_index), + m_pred_cluster_ob_cluster_index(pred_cluster_ob_cluster_index), + m_pred_cluster_ob_interface(pred_cluster_ob_interface), + m_succ_prepost_ob_index(succ_prepost_ob_index), + m_succ_prepost_ob_interface(succ_prepost_ob_interface) +{} + +bool WaitNmsIdleAction::supports_repeated_block() const +{ + // Wait actions shouldn't be repeated (for easier debugging) + return false; +} + +Expected WaitNmsIdleAction::serialize_params(const ContextResources &) const +{ + CONTEXT_SWITCH_DEFS__wait_nms_data_t params{}; + params.aggregator_index = m_aggregator_index; + params.pred_cluster_ob_index = m_pred_cluster_ob_index; + params.pred_cluster_ob_cluster_index = m_pred_cluster_ob_cluster_index; + params.pred_cluster_ob_interface = m_pred_cluster_ob_interface; + params.succ_prepost_ob_index = m_succ_prepost_ob_index; + params.succ_prepost_ob_interface = m_succ_prepost_ob_interface; + return Buffer::create(reinterpret_cast(¶ms), sizeof(params)); +} + +Expected EnableNmsAction::create(uint8_t nms_unit_index, uint8_t network_index) +{ + auto result = ContextSwitchConfigActionPtr(new (std::nothrow) EnableNmsAction(nms_unit_index, network_index)); + CHECK_AS_EXPECTED((nullptr != result), HAILO_OUT_OF_HOST_MEMORY); + return result; +} + +EnableNmsAction::EnableNmsAction(uint8_t nms_unit_index, uint8_t network_index) : + ContextSwitchConfigAction(ContextSwitchConfigAction::Type::EnableNms, CONTEXT_SWITCH_DEFS__ACTION_TYPE_ENABLE_NMS), + m_nms_unit_index(nms_unit_index), + m_network_index(network_index) +{} + +Expected EnableNmsAction::serialize_params(const ContextResources &) const +{ + CONTEXT_SWITCH_DEFS__enable_nms_action_t params{}; + params.nms_unit_index = m_nms_unit_index; + params.network_index = m_network_index; + return Buffer::create(reinterpret_cast(¶ms), sizeof(params)); +} + +bool EnableNmsAction::supports_repeated_block() const +{ + return true; +} + +ContextSwitchOperation::ContextSwitchOperation(std::vector &&actions) : + m_actions(std::move(actions)) +{} + +const std::vector &ContextSwitchOperation::actions() const +{ + return m_actions; +} + +std::vector ContextSwitchOperation::get_actions_of_type( + const std::set &action_types) const +{ + std::vector filtered_actions; + for (const auto &action : m_actions) { + if (action_types.find(action->get_type()) != action_types.end()) { + filtered_actions.push_back(action); + } + } + return filtered_actions; +} + +} /* namespace hailort */ diff --git a/hailort/libhailort/src/context_switch/context_switch_actions.hpp b/hailort/libhailort/src/context_switch/context_switch_actions.hpp new file mode 100644 index 0000000..5b60fc7 --- /dev/null +++ b/hailort/libhailort/src/context_switch/context_switch_actions.hpp @@ -0,0 +1,781 @@ +/** + * Copyright (c) 2022 Hailo Technologies Ltd. All rights reserved. + * Distributed under the MIT license (https://opensource.org/licenses/MIT) +**/ +/** + * @file context_switch_actions.hpp + * @brief Contains classes represents the context switch action (Actions found in the HEFs + * and action sent to the fw). + **/ + +#ifndef _HAILO_CONTEXT_SWITCH_ACTIONS_HPP_ +#define _HAILO_CONTEXT_SWITCH_ACTIONS_HPP_ + +#include "hailo/expected.hpp" +#include "hailo/buffer.hpp" +#include "vdma/channel_id.hpp" +#include "layer_info.hpp" +#include "control_protocol.hpp" +#include "context_switch_defs.h" + +namespace hailort +{ + + +class ContextResources; + +class ContextSwitchConfigAction; +using ContextSwitchConfigActionPtr = std::shared_ptr; +class ContextSwitchConfigAction +{ +public: + enum class Type + { + None, + ActivateConfigChannel, + DeactivateConfigChannel, + WriteDataCcw, + AddCcwBurst, + FetchCfgChannelDescriptors, + TriggerSequencer, + WaitForSequencerDone, + TriggerNewDataFromDataInput, + TriggerNewDataFromDataInputDdr, + EnableLcuNonDefault, + EnableLcuDefault, + DisableLcu, + WaitForLcu, + WaitForModuleConfigDone, + DdrPairInfo, + StartDdrBufferingTask, + ResetDdrBufferingTask, + AddRepeated, + StartBurstCreditsTask, + WaitForNetworkGroupChange, + ChangeVdmaToStreamMapping, + WaitOutputTransferDone, + OpenBoundaryInputChannel, + OpenBoundaryOutputChannel, + ActivateBoundaryInputChannel, + ActivateBoundaryOutputChannel, + ActivateInterContextInputChannel, + ActivateInterContextOutputChannel, + ActivateDdrInputChannel, + ActivateDdrOutputChannel, + ValidateChannel, + DeactivateChannel, + WaitDmaIdle, + WaitNmsIdle, + EnableNms, + }; + + ContextSwitchConfigAction(ContextSwitchConfigAction &&) = default; + ContextSwitchConfigAction(const ContextSwitchConfigAction &) = delete; + ContextSwitchConfigAction &operator=(ContextSwitchConfigAction &&) = delete; + ContextSwitchConfigAction &operator=(const ContextSwitchConfigAction &) = delete; + virtual ~ContextSwitchConfigAction() = default; + + // Serialize the action a vector of buffers - each buffer is a chunk that must be sent continuously to the firmware + // (For example each chunk can be sub action of RepeatedAction). + virtual Expected> serialize(const ContextResources &context_resources, + bool is_repeated=false) const; + + virtual bool supports_repeated_block() const = 0; + Type get_type() const; + CONTEXT_SWITCH_DEFS__ACTION_TYPE_t get_action_list_type() const; + +protected: + ContextSwitchConfigAction(Type type); + ContextSwitchConfigAction(Type type, CONTEXT_SWITCH_DEFS__ACTION_TYPE_t action_list_type); + + Expected serialize_header(bool is_repeated) const; + virtual Expected serialize_params(const ContextResources &context_resources) const = 0; + + const Type m_type; + const CONTEXT_SWITCH_DEFS__ACTION_TYPE_t m_action_list_type; +}; + +class NoneAction : public ContextSwitchConfigAction +{ +public: + static Expected create(); + NoneAction(NoneAction &&) = default; + NoneAction(const NoneAction &) = delete; + NoneAction &operator=(NoneAction &&) = delete; + NoneAction &operator=(const NoneAction &) = delete; + virtual ~NoneAction() = default; + + virtual Expected> serialize(const ContextResources &context_resources, + bool is_repeated=false) const override; + virtual bool supports_repeated_block() const override; + virtual Expected serialize_params(const ContextResources &context_resources) const override; + +private: + NoneAction(); +}; + +class ActivateConfigChannelAction : public ContextSwitchConfigAction +{ +public: + static Expected create(uint8_t config_stream_index, const vdma::ChannelId &channel_id, + const CONTROL_PROTOCOL__host_buffer_info_t &host_buffer_info); + + virtual bool supports_repeated_block() const override; + virtual Expected serialize_params(const ContextResources &context_resources) const override; + +private: + ActivateConfigChannelAction(uint8_t config_stream_index, const vdma::ChannelId &channel_id, + const CONTROL_PROTOCOL__host_buffer_info_t &host_buffer_info); + + const uint8_t m_config_stream_index; + const vdma::ChannelId m_channel_id; + const CONTROL_PROTOCOL__host_buffer_info_t m_host_buffer_info; +}; + +class DeactivateConfigChannelAction : public ContextSwitchConfigAction +{ +public: + static Expected create(uint8_t config_stream_index, const vdma::ChannelId &channel_id); + + virtual bool supports_repeated_block() const override; + virtual Expected serialize_params(const ContextResources &context_resources) const override; + +private: + DeactivateConfigChannelAction(uint8_t config_stream_index, const vdma::ChannelId &channel_id); + + const uint8_t m_config_stream_index; + const vdma::ChannelId m_channel_id; +}; + +class WriteDataCcwAction : public ContextSwitchConfigAction +{ +public: + static Expected create(Buffer &&data, uint8_t config_stream_index); + WriteDataCcwAction(WriteDataCcwAction &&) = default; + WriteDataCcwAction(const WriteDataCcwAction &) = delete; + WriteDataCcwAction &operator=(WriteDataCcwAction &&) = delete; + WriteDataCcwAction &operator=(const WriteDataCcwAction &) = delete; + virtual ~WriteDataCcwAction() = default; + + virtual Expected> serialize(const ContextResources &context_resources, + bool is_repeated=false) const override; + virtual bool supports_repeated_block() const override; + virtual Expected serialize_params(const ContextResources &context_resources) const override; + + uint8_t config_stream_index() const { return m_config_stream_index; } + const MemoryView data() const { return MemoryView::create_const(m_data.data(), m_data.size()); } + +private: + WriteDataCcwAction(Buffer &&data, uint8_t config_stream_index); + + Buffer m_data; + const uint8_t m_config_stream_index; +}; + +class AddCcwBurstAction : public ContextSwitchConfigAction +{ +public: + static Expected create(uint8_t config_stream_index, uint16_t ccw_bursts); + virtual bool supports_repeated_block() const override; + virtual Expected serialize_params(const ContextResources &context_resources) const override; + +private: + AddCcwBurstAction(uint8_t config_stream_index, uint16_t ccw_bursts); + + const uint8_t m_config_stream_index; + const uint16_t m_ccw_bursts; +}; + +class FetchCfgChannelDescriptorsAction : public ContextSwitchConfigAction +{ +public: + static Expected create(const vdma::ChannelId &channel_id, uint16_t desc_count); + + FetchCfgChannelDescriptorsAction(FetchCfgChannelDescriptorsAction &&) = default; + FetchCfgChannelDescriptorsAction(const FetchCfgChannelDescriptorsAction &) = delete; + FetchCfgChannelDescriptorsAction &operator=(FetchCfgChannelDescriptorsAction &&) = delete; + FetchCfgChannelDescriptorsAction &operator=(const FetchCfgChannelDescriptorsAction &) = delete; + virtual ~FetchCfgChannelDescriptorsAction() = default; + virtual bool supports_repeated_block() const override; + virtual Expected serialize_params(const ContextResources &context_resources) const override; + +private: + FetchCfgChannelDescriptorsAction(const vdma::ChannelId &channel_id, uint16_t desc_count); + + const vdma::ChannelId m_channel_id; + const uint16_t m_desc_count; +}; + +class StartBurstCreditsTaskAction : public ContextSwitchConfigAction +{ +public: + static Expected create(); + + StartBurstCreditsTaskAction(StartBurstCreditsTaskAction &&) = default; + StartBurstCreditsTaskAction(const StartBurstCreditsTaskAction &) = delete; + StartBurstCreditsTaskAction &operator=(StartBurstCreditsTaskAction &&) = delete; + StartBurstCreditsTaskAction &operator=(const StartBurstCreditsTaskAction &) = delete; + virtual ~StartBurstCreditsTaskAction() = default; + virtual bool supports_repeated_block() const override; + virtual Expected serialize_params(const ContextResources &context_resources) const override; + +private: + StartBurstCreditsTaskAction(); +}; + +class WaitForNetworkGroupChangeAction : public ContextSwitchConfigAction +{ +public: + static Expected create(); + + virtual bool supports_repeated_block() const override; + virtual Expected serialize_params(const ContextResources &context_resources) const override; + +private: + WaitForNetworkGroupChangeAction(); +}; + +class RepeatedAction : public ContextSwitchConfigAction +{ +public: + static Expected create(std::vector &&actions); + RepeatedAction(RepeatedAction &&) = default; + RepeatedAction(const RepeatedAction &) = delete; + RepeatedAction &operator=(RepeatedAction &&) = delete; + RepeatedAction &operator=(const RepeatedAction &) = delete; + virtual ~RepeatedAction() = default; + virtual bool supports_repeated_block() const override; + virtual Expected serialize_params(const ContextResources &context_resources) const override; + + virtual Expected> serialize(const ContextResources &context_resources, + bool is_repeated=false) const override; + +private: + RepeatedAction(std::vector &&actions); + + const std::vector m_actions; + const CONTEXT_SWITCH_DEFS__ACTION_TYPE_t m_sub_action_type; +}; + +class DisableLcuAction : public ContextSwitchConfigAction +{ +public: + static Expected create(uint8_t cluster_index, uint8_t lcu_index); + DisableLcuAction(DisableLcuAction &&) = default; + DisableLcuAction(const DisableLcuAction &) = delete; + DisableLcuAction &operator=(DisableLcuAction &&) = delete; + DisableLcuAction &operator=(const DisableLcuAction &) = delete; + virtual ~DisableLcuAction() = default; + virtual bool supports_repeated_block() const override; + virtual Expected serialize_params(const ContextResources &context_resources) const override; + +private: + DisableLcuAction(uint8_t cluster_index, uint8_t lcu_index); + + const uint8_t m_cluster_index; + const uint8_t m_lcu_index; +}; + + +class WaitForLcuAction : public ContextSwitchConfigAction +{ +public: + static Expected create(uint8_t cluster_index, uint8_t lcu_index); + virtual bool supports_repeated_block() const override; + virtual Expected serialize_params(const ContextResources &context_resources) const override; + +private: + WaitForLcuAction(uint8_t cluster_index, uint8_t lcu_index); + + uint8_t m_cluster_index; + uint8_t m_lcu_index; +}; + +class EnableLcuAction : public ContextSwitchConfigAction +{ +public: + static Expected create(uint8_t cluster_index, uint8_t lcu_index, + uint8_t network_index, uint16_t kernel_done_address, uint32_t kernel_done_count); + EnableLcuAction(EnableLcuAction &&) = default; + EnableLcuAction(const EnableLcuAction &) = delete; + EnableLcuAction &operator=(EnableLcuAction &&) = delete; + EnableLcuAction &operator=(const EnableLcuAction &) = delete; + virtual ~EnableLcuAction() = default; + virtual bool supports_repeated_block() const override; + virtual Expected serialize_params(const ContextResources &context_resources) const override; + +private: + static CONTEXT_SWITCH_DEFS__ACTION_TYPE_t get_enable_lcu_action_type(bool is_default); + static Type get_enable_lcu_type(bool is_default); + + EnableLcuAction(uint8_t cluster_index, uint8_t lcu_index, + uint8_t network_index, uint16_t kernel_done_address, uint32_t kernel_done_count, bool is_default); + + const uint8_t m_cluster_index; + const uint8_t m_lcu_index; + const uint8_t m_network_index; + const uint16_t m_kernel_done_address; + const uint32_t m_kernel_done_count; + const bool m_is_default; +}; + +class EnableSequencerAction : public ContextSwitchConfigAction +{ +public: + static Expected create(uint8_t cluster_index, uint8_t initial_l3_cut, + uint16_t initial_l3_offset, uint32_t active_apu, uint32_t active_ia, uint64_t active_sc, uint64_t active_l2, + uint64_t l2_offset_0, uint64_t l2_offset_1); + EnableSequencerAction(EnableSequencerAction &&) = default; + EnableSequencerAction(const EnableSequencerAction &) = delete; + EnableSequencerAction &operator=(EnableSequencerAction &&) = delete; + EnableSequencerAction &operator=(const EnableSequencerAction &) = delete; + virtual ~EnableSequencerAction() = default; + virtual bool supports_repeated_block() const override; + virtual Expected serialize_params(const ContextResources &context_resources) const override; + +private: + EnableSequencerAction(uint8_t cluster_index, uint8_t initial_l3_cut, uint16_t initial_l3_offset, + uint32_t active_apu, uint32_t active_ia, uint64_t active_sc, uint64_t active_l2, uint64_t l2_offset_0, + uint64_t l2_offset_1); + + const uint8_t m_cluster_index; + const uint8_t m_initial_l3_cut; + const uint16_t m_initial_l3_offset; + const uint32_t m_active_apu; + const uint32_t m_active_ia; + const uint64_t m_active_sc; + const uint64_t m_active_l2; + const uint64_t m_l2_offset_0; + const uint64_t m_l2_offset_1; +}; + +class WaitForSequencerAction : public ContextSwitchConfigAction +{ +public: + static Expected create(uint8_t cluster_index); + WaitForSequencerAction(WaitForSequencerAction &&) = default; + WaitForSequencerAction(const WaitForSequencerAction &) = delete; + WaitForSequencerAction &operator=(WaitForSequencerAction &&) = delete; + WaitForSequencerAction &operator=(const WaitForSequencerAction &) = delete; + virtual ~WaitForSequencerAction() = default; + virtual bool supports_repeated_block() const override; + virtual Expected serialize_params(const ContextResources &context_resources) const override; + +private: + WaitForSequencerAction(uint8_t cluster_index); + + const uint8_t m_cluster_index; +}; + +class AllowInputDataflowAction : public ContextSwitchConfigAction +{ +public: + static Expected create(uint8_t stream_index); + AllowInputDataflowAction(AllowInputDataflowAction &&) = default; + AllowInputDataflowAction(const AllowInputDataflowAction &) = delete; + AllowInputDataflowAction &operator=(AllowInputDataflowAction &&) = delete; + AllowInputDataflowAction &operator=(const AllowInputDataflowAction &) = delete; + virtual ~AllowInputDataflowAction() = default; + virtual bool supports_repeated_block() const override; + virtual Expected serialize_params(const ContextResources &context_resources) const override; + +private: + explicit AllowInputDataflowAction(uint8_t stream_index); + + const uint8_t m_stream_index; +}; + +class WaitForModuleConfigDoneAction : public ContextSwitchConfigAction +{ +public: + static Expected create(uint8_t module_index); + WaitForModuleConfigDoneAction(WaitForModuleConfigDoneAction &&) = default; + WaitForModuleConfigDoneAction(const WaitForModuleConfigDoneAction &) = delete; + WaitForModuleConfigDoneAction &operator=(WaitForModuleConfigDoneAction &&) = delete; + WaitForModuleConfigDoneAction &operator=(const WaitForModuleConfigDoneAction &) = delete; + virtual ~WaitForModuleConfigDoneAction() = default; + virtual bool supports_repeated_block() const override; + virtual Expected serialize_params(const ContextResources &context_resources) const override; + +private: + WaitForModuleConfigDoneAction(uint8_t module_index); + + const uint8_t m_module_index; +}; + +class DdrPairInfoAction : public ContextSwitchConfigAction +{ +public: + static Expected create(const vdma::ChannelId &h2d_channel_id, + const vdma::ChannelId &d2h_channel_id, uint8_t network_index, uint32_t descriptors_per_frame, uint16_t descs_count); + DdrPairInfoAction(DdrPairInfoAction &&) = default; + DdrPairInfoAction(const DdrPairInfoAction &) = delete; + DdrPairInfoAction &operator=(DdrPairInfoAction &&) = delete; + DdrPairInfoAction &operator=(const DdrPairInfoAction &) = delete; + virtual ~DdrPairInfoAction() = default; + virtual bool supports_repeated_block() const override; + virtual Expected serialize_params(const ContextResources &context_resources) const override; + +private: + DdrPairInfoAction(const vdma::ChannelId &h2d_channel_id, const vdma::ChannelId &d2h_channel_id, + uint8_t network_index, uint32_t descriptors_per_frame, uint16_t descs_count); + + const vdma::ChannelId m_h2d_channel_id; + const vdma::ChannelId m_d2h_channel_id; + const uint8_t m_network_index; + const uint32_t m_descriptors_per_frame; + const uint16_t m_descs_count; +}; + +class StartDdrBufferingTaskAction : public ContextSwitchConfigAction +{ +public: + static Expected create(); + StartDdrBufferingTaskAction(StartDdrBufferingTaskAction &&) = default; + StartDdrBufferingTaskAction(const StartDdrBufferingTaskAction &) = delete; + StartDdrBufferingTaskAction &operator=(StartDdrBufferingTaskAction &&) = delete; + StartDdrBufferingTaskAction &operator=(const StartDdrBufferingTaskAction &) = delete; + virtual ~StartDdrBufferingTaskAction() = default; + virtual bool supports_repeated_block() const override; + virtual Expected serialize_params(const ContextResources &context_resources) const override; + +private: + StartDdrBufferingTaskAction(); +}; + +class ResetDdrBufferingTaskAction : public ContextSwitchConfigAction +{ +public: + static Expected create(); + ResetDdrBufferingTaskAction(ResetDdrBufferingTaskAction &&) = default; + ResetDdrBufferingTaskAction(const ResetDdrBufferingTaskAction &) = delete; + ResetDdrBufferingTaskAction &operator=(ResetDdrBufferingTaskAction &&) = delete; + ResetDdrBufferingTaskAction &operator=(const ResetDdrBufferingTaskAction &) = delete; + virtual ~ResetDdrBufferingTaskAction() = default; + virtual bool supports_repeated_block() const override; + virtual Expected serialize_params(const ContextResources &context_resources) const override; +private: + ResetDdrBufferingTaskAction(); +}; + +class ChangeVdmaToStreamMapping : public ContextSwitchConfigAction +{ +public: + static Expected create(const vdma::ChannelId &channel_id, uint8_t stream_index, + bool is_dummy_stream); + ChangeVdmaToStreamMapping(ChangeVdmaToStreamMapping &&) = default; + ChangeVdmaToStreamMapping(const ChangeVdmaToStreamMapping &) = delete; + ChangeVdmaToStreamMapping &operator=(ChangeVdmaToStreamMapping &&) = delete; + ChangeVdmaToStreamMapping &operator=(const ChangeVdmaToStreamMapping &) = delete; + virtual ~ChangeVdmaToStreamMapping() = default; + virtual bool supports_repeated_block() const override; + virtual Expected serialize_params(const ContextResources &context_resources) const override; + +private: + ChangeVdmaToStreamMapping(const vdma::ChannelId &channel_id, uint8_t stream_index, bool is_dummy_stream); + + const vdma::ChannelId m_channel_id; + const uint8_t m_stream_index; + const bool m_is_dummy_stream; +}; + +class WaitOutputTransferDoneAction : public ContextSwitchConfigAction +{ +public: + static Expected create(uint8_t stream_index); + + virtual bool supports_repeated_block() const override; + virtual Expected serialize_params(const ContextResources &context_resources) const override; + +private: + explicit WaitOutputTransferDoneAction(uint8_t stream_index); + + Expected get_layer_channel_id(const ContextResources &context_resources) const; + + uint8_t m_stream_index; +}; + +class OpenBoundaryInputChannelAction : public ContextSwitchConfigAction +{ +public: + static Expected create(const vdma::ChannelId &channel_id, + const CONTROL_PROTOCOL__host_buffer_info_t &host_buffer_info); + + virtual bool supports_repeated_block() const override; + virtual Expected serialize_params(const ContextResources &context_resources) const override; + +private: + OpenBoundaryInputChannelAction(const vdma::ChannelId &channel_id, + const CONTROL_PROTOCOL__host_buffer_info_t &host_buffer_info); + + const vdma::ChannelId m_channel_id; + CONTROL_PROTOCOL__host_buffer_info_t m_host_buffer_info; +}; + +class OpenBoundaryOutputChannelAction : public ContextSwitchConfigAction +{ +public: + static Expected create(const vdma::ChannelId &channel_id, + const CONTROL_PROTOCOL__host_buffer_info_t &host_buffer_info); + + virtual bool supports_repeated_block() const override; + virtual Expected serialize_params(const ContextResources &context_resources) const override; + +private: + OpenBoundaryOutputChannelAction(const vdma::ChannelId &channel_id, + const CONTROL_PROTOCOL__host_buffer_info_t &host_buffer_info); + + const vdma::ChannelId m_channel_id; + CONTROL_PROTOCOL__host_buffer_info_t m_host_buffer_info; +}; + +class ActivateBoundaryInputChannelAction : public ContextSwitchConfigAction +{ +public: + static Expected create(const vdma::ChannelId &channel_id, + uint8_t stream_index, const CONTROL_PROTOCOL__nn_stream_config_t &nn_stream_config, + const CONTROL_PROTOCOL__host_buffer_info_t &host_buffer_info, uint32_t initial_credit_size); + + virtual bool supports_repeated_block() const override; + virtual Expected serialize_params(const ContextResources &context_resources) const override; + +private: + ActivateBoundaryInputChannelAction(const vdma::ChannelId &channel_id, + uint8_t stream_index, const CONTROL_PROTOCOL__nn_stream_config_t &nn_stream_config, + const CONTROL_PROTOCOL__host_buffer_info_t &host_buffer_info, + uint32_t initial_credit_size); + + const vdma::ChannelId m_channel_id; + const uint8_t m_stream_index; + const CONTROL_PROTOCOL__nn_stream_config_t m_nn_stream_config; + const CONTROL_PROTOCOL__host_buffer_info_t m_host_buffer_info; + const uint32_t m_initial_credit_size; +}; + +class ActivateBoundaryOutputChannelAction : public ContextSwitchConfigAction +{ +public: + static Expected create(const vdma::ChannelId &channel_id, + uint8_t stream_index, const CONTROL_PROTOCOL__nn_stream_config_t &nn_stream_config, + const CONTROL_PROTOCOL__host_buffer_info_t &host_buffer_info); + + virtual bool supports_repeated_block() const override; + virtual Expected serialize_params(const ContextResources &context_resources) const override; + +private: + ActivateBoundaryOutputChannelAction(const vdma::ChannelId &channel_id, + uint8_t stream_index, const CONTROL_PROTOCOL__nn_stream_config_t &nn_stream_config, + const CONTROL_PROTOCOL__host_buffer_info_t &host_buffer_info); + + const vdma::ChannelId m_channel_id; + const uint8_t m_stream_index; + const CONTROL_PROTOCOL__nn_stream_config_t m_nn_stream_config; + const CONTROL_PROTOCOL__host_buffer_info_t m_host_buffer_info; +}; + +class ActivateInterContextInputChannelAction : public ContextSwitchConfigAction +{ +public: + static Expected create(const vdma::ChannelId &channel_id, + uint8_t stream_index, const CONTROL_PROTOCOL__nn_stream_config_t &nn_stream_config, + const CONTROL_PROTOCOL__host_buffer_info_t &host_buffer_info, uint32_t initial_credit_size); + + virtual bool supports_repeated_block() const override; + virtual Expected serialize_params(const ContextResources &context_resources) const override; + +private: + ActivateInterContextInputChannelAction(const vdma::ChannelId &channel_id, + uint8_t stream_index, const CONTROL_PROTOCOL__nn_stream_config_t &nn_stream_config, + const CONTROL_PROTOCOL__host_buffer_info_t &host_buffer_info, + uint32_t initial_credit_size); + + const vdma::ChannelId m_channel_id; + const uint8_t m_stream_index; + const CONTROL_PROTOCOL__nn_stream_config_t m_nn_stream_config; + const CONTROL_PROTOCOL__host_buffer_info_t m_host_buffer_info; + const uint32_t m_initial_credit_size; +}; + +class ActivateInterContextOutputChannelAction : public ContextSwitchConfigAction +{ +public: + static Expected create(const vdma::ChannelId &channel_id, uint8_t stream_index, + uint8_t network_index, const CONTROL_PROTOCOL__nn_stream_config_t &nn_stream_config, + const CONTROL_PROTOCOL__host_buffer_info_t &host_buffer_info); + + virtual bool supports_repeated_block() const override; + virtual Expected serialize_params(const ContextResources &context_resources) const override; + +private: + ActivateInterContextOutputChannelAction(const vdma::ChannelId &channel_id, uint8_t stream_index, + uint8_t network_index, const CONTROL_PROTOCOL__nn_stream_config_t &nn_stream_config, + const CONTROL_PROTOCOL__host_buffer_info_t &host_buffer_info); + + const vdma::ChannelId m_channel_id; + const uint8_t m_stream_index; + const uint8_t m_network_index; + const CONTROL_PROTOCOL__nn_stream_config_t m_nn_stream_config; + const CONTROL_PROTOCOL__host_buffer_info_t m_host_buffer_info; +}; + +class ActivateDdrInputChannelAction : public ContextSwitchConfigAction +{ +public: + static Expected create(const vdma::ChannelId &channel_id, + uint8_t stream_index, const CONTROL_PROTOCOL__nn_stream_config_t &nn_stream_config, + const CONTROL_PROTOCOL__host_buffer_info_t &host_buffer_info, uint32_t initial_credit_size, + const vdma::ChannelId &connected_d2h_channel_id); + + virtual bool supports_repeated_block() const override; + virtual Expected serialize_params(const ContextResources &context_resources) const override; + +private: + ActivateDdrInputChannelAction(const vdma::ChannelId &channel_id, + uint8_t stream_index, const CONTROL_PROTOCOL__nn_stream_config_t &nn_stream_config, + const CONTROL_PROTOCOL__host_buffer_info_t &host_buffer_info, uint32_t initial_credit_size, + const vdma::ChannelId &connected_d2h_channel_id); + + const vdma::ChannelId m_channel_id; + const uint8_t m_stream_index; + const CONTROL_PROTOCOL__nn_stream_config_t m_nn_stream_config; + const CONTROL_PROTOCOL__host_buffer_info_t m_host_buffer_info; + const uint32_t m_initial_credit_size; + const vdma::ChannelId m_connected_d2h_channel_id; +}; + +class ActivateDdrOutputChannelAction : public ContextSwitchConfigAction +{ +public: + static Expected create(const vdma::ChannelId &channel_id, + uint8_t stream_index, const CONTROL_PROTOCOL__nn_stream_config_t &nn_stream_config, + const CONTROL_PROTOCOL__host_buffer_info_t &host_buffer_info, uint32_t buffered_rows_count); + + virtual bool supports_repeated_block() const override; + virtual Expected serialize_params(const ContextResources &context_resources) const override; + +private: + ActivateDdrOutputChannelAction(const vdma::ChannelId &channel_id, + uint8_t stream_index, const CONTROL_PROTOCOL__nn_stream_config_t &nn_stream_config, + const CONTROL_PROTOCOL__host_buffer_info_t &host_buffer_info, uint32_t buffered_rows_count); + + const vdma::ChannelId m_channel_id; + const uint8_t m_stream_index; + const CONTROL_PROTOCOL__nn_stream_config_t m_nn_stream_config; + const CONTROL_PROTOCOL__host_buffer_info_t m_host_buffer_info; + const uint32_t m_buffered_rows_count; +}; + +class ValidateChannelAction : public ContextSwitchConfigAction +{ +public: + static Expected create(const vdma::ChannelId &channel_id, + hailo_stream_direction_t stream_direction, bool is_inter_context, + CONTROL_PROTOCOL__HOST_BUFFER_TYPE_t host_buffer_type, uint32_t initial_credit_size); + + virtual bool supports_repeated_block() const override; + virtual Expected serialize_params(const ContextResources &context_resources) const override; + +private: + ValidateChannelAction(const vdma::ChannelId &channel_id, hailo_stream_direction_t stream_direction, + bool is_inter_context, CONTROL_PROTOCOL__HOST_BUFFER_TYPE_t host_buffer_type, uint32_t initial_credit_size); + + const vdma::ChannelId m_channel_id; + const hailo_stream_direction_t m_stream_direction; + const bool m_is_inter_context; + const CONTROL_PROTOCOL__HOST_BUFFER_TYPE_t m_host_buffer_type; + const uint32_t m_initial_credit_size; +}; + +class DeactivateChannelAction : public ContextSwitchConfigAction +{ +public: + static Expected create(const vdma::ChannelId &channel_id, + hailo_stream_direction_t stream_direction, bool is_inter_context, + CONTROL_PROTOCOL__HOST_BUFFER_TYPE_t host_buffer_type, uint32_t initial_credit_size); + + virtual bool supports_repeated_block() const override; + virtual Expected serialize_params(const ContextResources &context_resources) const override; + +private: + DeactivateChannelAction(const vdma::ChannelId &channel_id, hailo_stream_direction_t stream_direction, + bool is_inter_context, CONTROL_PROTOCOL__HOST_BUFFER_TYPE_t host_buffer_type, uint32_t initial_credit_size); + + const vdma::ChannelId m_channel_id; + const hailo_stream_direction_t m_stream_direction; + const bool m_is_inter_context; + const CONTROL_PROTOCOL__HOST_BUFFER_TYPE_t m_host_buffer_type; + const uint32_t m_initial_credit_size; +}; + +class WaitDmaIdleAction : public ContextSwitchConfigAction +{ +public: + static Expected create(uint8_t stream_index); + + virtual bool supports_repeated_block() const override; + virtual Expected serialize_params(const ContextResources &context_resources) const override; + +private: + explicit WaitDmaIdleAction(uint8_t stream_index); + + Expected> get_layer_channel_id_and_type( + const ContextResources &context_resources) const; + + uint8_t m_stream_index; +}; + +class WaitNmsIdleAction : public ContextSwitchConfigAction +{ +public: + static Expected create(uint8_t aggregator_index, + uint8_t pred_cluster_ob_index, uint8_t pred_cluster_ob_cluster_index, uint8_t pred_cluster_ob_interface, + uint8_t succ_prepost_ob_index, uint8_t succ_prepost_ob_interface); + + virtual bool supports_repeated_block() const override; + virtual Expected serialize_params(const ContextResources &context_resources) const override; + +private: + WaitNmsIdleAction(uint8_t aggregator_index, uint8_t pred_cluster_ob_index, uint8_t pred_cluster_ob_cluster_index, + uint8_t pred_cluster_ob_interface, uint8_t succ_prepost_ob_index, uint8_t succ_prepost_ob_interface); + + uint8_t m_aggregator_index; + uint8_t m_pred_cluster_ob_index; + uint8_t m_pred_cluster_ob_cluster_index; + uint8_t m_pred_cluster_ob_interface; + uint8_t m_succ_prepost_ob_index; + uint8_t m_succ_prepost_ob_interface; +}; + +class EnableNmsAction : public ContextSwitchConfigAction +{ +public: + static Expected create(uint8_t nms_unit_index, uint8_t network_index); + EnableNmsAction(EnableNmsAction &&) = default; + EnableNmsAction(const EnableNmsAction &) = delete; + EnableNmsAction &operator=(EnableNmsAction &&) = delete; + EnableNmsAction &operator=(const EnableNmsAction &) = delete; + virtual ~EnableNmsAction() = default; + virtual bool supports_repeated_block() const override; + virtual Expected serialize_params(const ContextResources &context_resources) const override; + +private: + EnableNmsAction(uint8_t nms_unit_index, uint8_t network_index); + + const uint8_t m_nms_unit_index; + const uint8_t m_network_index; +}; + +class ContextSwitchOperation final { +public: + ContextSwitchOperation(std::vector &&actions); + + const std::vector &actions() const; + std::vector get_actions_of_type(const std::set &action_types) const; + +private: + std::vector m_actions; +}; + +} /* namespace hailort */ + +#endif /* _HAILO_CONTEXT_SWITCH_ACTIONS_HPP_ */ diff --git a/hailort/libhailort/src/context_switch/context_switch_buffer_builder.cpp b/hailort/libhailort/src/context_switch/context_switch_buffer_builder.cpp new file mode 100644 index 0000000..8f76282 --- /dev/null +++ b/hailort/libhailort/src/context_switch/context_switch_buffer_builder.cpp @@ -0,0 +1,71 @@ +/** + * Copyright (c) 2022 Hailo Technologies Ltd. All rights reserved. + * Distributed under the MIT license (https://opensource.org/licenses/MIT) +**/ +/** + * @file context_switch_buffer_builder.cpp + * @brief Class used to build the context switch buffer sent to the firmware + **/ + +#include "context_switch_buffer_builder.hpp" + +namespace hailort +{ + +ContextSwitchBufferBuilder::ContextSwitchBufferBuilder(CONTROL_PROTOCOL__context_switch_context_type_t context_type) : + m_context_type(context_type) +{ + // Initialize first control + start_new_control(); +} + +void ContextSwitchBufferBuilder::write_action(MemoryView action) +{ + assert(action.size() < std::numeric_limits::max()); + const uint32_t action_size = static_cast(action.size()); + + if (!has_space_for_action(action_size)) { + // Size exceeded single control size, creating a new control buffer. + start_new_control(); + } + + auto &control = current_control(); + memcpy(&control.context_network_data[control.context_network_data_length], action.data(), action_size); + control.context_network_data_length += action_size; + control.actions_count++; +} + +const std::vector &ContextSwitchBufferBuilder::get_controls() const +{ + return m_controls; +} + +CONTROL_PROTOCOL__context_switch_context_info_single_control_t &ContextSwitchBufferBuilder::current_control() +{ + assert(!m_controls.empty()); + return m_controls.back(); +} + +bool ContextSwitchBufferBuilder::has_space_for_action(uint32_t action_size) +{ + auto &control = current_control(); + return (control.context_network_data_length + action_size) <= ARRAY_ENTRIES(control.context_network_data); +} + +void ContextSwitchBufferBuilder::start_new_control() +{ + if (!m_controls.empty()) { + current_control().is_last_control_per_context = false; + } + + // Creating a new control directly inside the vector to avoid copying the control struct. + m_controls.emplace_back(); + auto &new_control = current_control(); + new_control.context_network_data_length = 0; + new_control.actions_count = 0; + new_control.context_type = static_cast(m_context_type); + new_control.is_first_control_per_context = (1 == m_controls.size()); + new_control.is_last_control_per_context = true; +} + +} /* namespace hailort */ diff --git a/hailort/libhailort/src/context_switch/context_switch_buffer_builder.hpp b/hailort/libhailort/src/context_switch/context_switch_buffer_builder.hpp new file mode 100644 index 0000000..645f30c --- /dev/null +++ b/hailort/libhailort/src/context_switch/context_switch_buffer_builder.hpp @@ -0,0 +1,42 @@ +/** + * Copyright (c) 2022 Hailo Technologies Ltd. All rights reserved. + * Distributed under the MIT license (https://opensource.org/licenses/MIT) +**/ +/** + * @file context_switch_buffer_builder.hpp + * @brief Class used to build the context switch buffer sent to the firmware. + **/ + +#ifndef _HAILO_CONTEXT_SWITCH_BUFFER_BUILDER_HPP_ +#define _HAILO_CONTEXT_SWITCH_BUFFER_BUILDER_HPP_ + +#include "hailo/hailort.h" +#include "control_protocol.hpp" +#include "layer_info.hpp" +#include "vdma/channel_id.hpp" + +namespace hailort +{ + +// This class manages a vector of CONTROL_PROTOCOL__context_switch_context_info_single_control_t controls to be sent +// to the firmware. Actions are written to the control buffer, until we reach the maximum control size, then we will +// start a new control. +class ContextSwitchBufferBuilder final { +public: + ContextSwitchBufferBuilder(CONTROL_PROTOCOL__context_switch_context_type_t context_type); + + void write_action(MemoryView action); + const std::vector &get_controls() const; + +private: + CONTROL_PROTOCOL__context_switch_context_info_single_control_t ¤t_control(); + bool has_space_for_action(uint32_t action_size); + void start_new_control(); + + CONTROL_PROTOCOL__context_switch_context_type_t m_context_type; + std::vector m_controls; +}; + +} /* namespace hailort */ + +#endif /* _HAILO_CONTEXT_SWITCH_BUFFER_BUILDER_HPP_ */ diff --git a/hailort/libhailort/src/context_switch/hcp_config_activated_network_group.cpp b/hailort/libhailort/src/context_switch/hcp_config_activated_network_group.cpp index 80b4f96..6b85a7e 100644 --- a/hailort/libhailort/src/context_switch/hcp_config_activated_network_group.cpp +++ b/hailort/libhailort/src/context_switch/hcp_config_activated_network_group.cpp @@ -16,10 +16,11 @@ namespace hailort Expected HcpConfigActivatedNetworkGroup::create(Device &device, std::vector &config, const std::string &network_group_name, const hailo_activate_network_group_params_t &network_group_params, - std::map> &input_streams, - std::map> &output_streams, - HcpConfigActiveAppHolder &active_net_group_holder, - hailo_power_mode_t power_mode, EventPtr network_group_activated_event) + std::map> &input_streams, + std::map> &output_streams, + ActiveNetGroupHolder &active_net_group_holder, + hailo_power_mode_t power_mode, EventPtr network_group_activated_event, + ConfiguredNetworkGroupBase &network_group) { CHECK(!active_net_group_holder.is_any_active(), make_unexpected(HAILO_INVALID_OPERATION), "network group is currently active. You must deactivate before activating another network_group"); @@ -38,23 +39,23 @@ Expected HcpConfigActivatedNetworkGroup::create( } HcpConfigActivatedNetworkGroup object(device, active_net_group_holder, network_group_name, network_group_params, input_streams, output_streams, - power_mode, std::move(network_group_activated_event), status); + power_mode, std::move(network_group_activated_event), network_group, status); CHECK_SUCCESS_AS_EXPECTED(status); return object; } HcpConfigActivatedNetworkGroup::HcpConfigActivatedNetworkGroup( Device &device, - HcpConfigActiveAppHolder &active_net_group_holder, + ActiveNetGroupHolder &active_net_group_holder, const std::string &network_group_name, const hailo_activate_network_group_params_t &network_group_params, - std::map> &input_streams, - std::map> &output_streams, + std::map> &input_streams, + std::map> &output_streams, hailo_power_mode_t power_mode, EventPtr &&network_group_activated_event, - hailo_status &status) : - ActivatedNetworkGroupBase(network_group_params, CONTROL_PROTOCOL__IGNORE_DYNAMIC_BATCH_SIZE, - input_streams, output_streams, std::move(network_group_activated_event), status), + ConfiguredNetworkGroupBase &network_group, hailo_status &status) : + ActivatedNetworkGroupBase(network_group_params, input_streams, output_streams, + std::move(network_group_activated_event), status), m_active_net_group_holder(active_net_group_holder), m_is_active(true), m_power_mode(power_mode), @@ -65,14 +66,29 @@ HcpConfigActivatedNetworkGroup::HcpConfigActivatedNetworkGroup( if (HAILO_SUCCESS != status) { return; } - m_active_net_group_holder.set(*this); + status = network_group.activate_impl(CONTROL_PROTOCOL__IGNORE_DYNAMIC_BATCH_SIZE); + if (HAILO_SUCCESS != status) { + LOGGER__ERROR("Failed to activate network group"); + return; + } } HcpConfigActivatedNetworkGroup::~HcpConfigActivatedNetworkGroup() { - if (m_is_active) { - m_active_net_group_holder.clear(); - deactivate_resources(); + if (!m_is_active) { + return; + } + + auto expected_config_network_ref = m_active_net_group_holder.get(); + if (!expected_config_network_ref.has_value()) { + LOGGER__ERROR("Error getting configured network group"); + return; + } + const auto &config_network_group = expected_config_network_ref.value(); + + const auto status = config_network_group.get().deactivate_impl(); + if (HAILO_SUCCESS != status) { + LOGGER__ERROR("Failed to deactivate network group"); } } diff --git a/hailort/libhailort/src/context_switch/hcp_config_manager.cpp b/hailort/libhailort/src/context_switch/hcp_config_manager.cpp deleted file mode 100644 index 8dd2b25..0000000 --- a/hailort/libhailort/src/context_switch/hcp_config_manager.cpp +++ /dev/null @@ -1,157 +0,0 @@ -/** - * Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved. - * Distributed under the MIT license (https://opensource.org/licenses/MIT) - **/ -/** - * @file hcp_config_manager.cpp - * @brief Manager of HEF parsing and network groups resources - * - * - **/ - -// https://github.com/protocolbuffers/protobuf/tree/master/cmake#notes-on-compiler-warnings -#if defined(_MSC_VER) -#pragma warning(push) -#pragma warning(disable: 4244 4267 4127) -#else -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wconversion" -#endif -#include "hef.pb.h" -#if defined(_MSC_VER) -#pragma warning( pop ) -#else -#pragma GCC diagnostic pop -#endif - -#include "context_switch/single_context/hcp_config_manager.hpp" -#include "hailo/hailort.h" -#include "common/utils.hpp" -#include "hailo/device.hpp" -#include "hailo/hef.hpp" -#include "control.hpp" -#include "pcie_device.hpp" -#include "hlpcie.hpp" - -#include -#include - -namespace hailort -{ - -Expected HcpConfigManager::add_hef(Hef &hef, - const NetworkGroupsParamsMap &configure_params) -{ - auto device_arch_exp = m_device.get_architecture(); - CHECK_EXPECTED(device_arch_exp); - auto device_arch = device_arch_exp.release(); - - auto partial_clusters_layout_bitmap_exp = Control::get_partial_clusters_layout_bitmap(m_device); - CHECK_EXPECTED(partial_clusters_layout_bitmap_exp); - auto partial_clusters_layout_bitmap = partial_clusters_layout_bitmap_exp.release(); - - auto &hef_network_groups = hef.pimpl->network_groups(); - auto current_net_group_index = static_cast(m_net_groups.size()); - ConfiguredNetworkGroupVector added_network_groups; - added_network_groups.reserve(hef_network_groups.size()); - auto configure_params_copy = configure_params; - auto hef_arch = hef.pimpl->get_device_arch(); - - // Reset FW state_machine status - static const auto REMOVE_NN_CONFIG_DURING_RESET = false; - auto status = Control::reset_context_switch_state_machine(m_device, REMOVE_NN_CONFIG_DURING_RESET); - CHECK_SUCCESS_AS_EXPECTED(status); - - const ProtoHEFNetworkGroup *network_group_ptr = nullptr; - for (const auto &net_group : hef_network_groups) { - CHECK_NOT_NULL_AS_EXPECTED(net_group, HAILO_INTERNAL_FAILURE); - - if (ProtoHEFHwArch::PROTO__HW_ARCH__HAILO8L == hef_arch) { - // Hailo8 can work with Hailo8L configurations. in that case we choose one of the configurations - for (auto &partial_network_group : net_group->partial_network_groups()) { - if ((partial_clusters_layout_bitmap == partial_network_group.layout().partial_clusters_layout_bitmap()) || - ((HAILO_ARCH_HAILO8 == device_arch))) { - network_group_ptr = &partial_network_group.network_group(); - break; - } - } - CHECK_AS_EXPECTED(nullptr != network_group_ptr, HAILO_INTERNAL_FAILURE, "There is no matching partial_clusters_layout_bitmap configuration in the given HEF"); - } else { - network_group_ptr = net_group.get(); - } - CHECK_NOT_NULL_AS_EXPECTED(network_group_ptr, HAILO_INTERNAL_FAILURE); - - /* Validate that all network_groups are single context */ - CHECK(1 == network_group_ptr->contexts_size(), make_unexpected(HAILO_INTERNAL_FAILURE), - "Only single_context network_groups is supported!. Network group {} has {} contexts.", - network_group_ptr->network_group_metadata().network_group_name(), network_group_ptr->contexts_size()); - CHECK_AS_EXPECTED(!(Hef::Impl::contains_ddr_layers(*network_group_ptr)), HAILO_INVALID_OPERATION, - "DDR layers are only supported for PCIe device. Network group {} contains DDR layers.", - network_group_ptr->network_group_metadata().network_group_name()); - status = Hef::Impl::validate_net_group_unique_layer_names(*network_group_ptr); - CHECK_SUCCESS_AS_EXPECTED(status); - - /* Update preliminary_config and dynamic_contexts recepies */ - auto &proto_preliminary_config = network_group_ptr->preliminary_config(); - auto net_group_config = Hef::Impl::create_single_context_network_group_config(proto_preliminary_config); - CHECK_EXPECTED(net_group_config); - - ConfigureNetworkParams config_params = {}; - if (contains(configure_params_copy, network_group_ptr->network_group_metadata().network_group_name())) { - config_params = configure_params_copy.at(network_group_ptr->network_group_metadata().network_group_name()); - configure_params_copy.erase(network_group_ptr->network_group_metadata().network_group_name()); - } else { - auto interface = m_device.get_default_streams_interface(); - CHECK_EXPECTED(interface); - auto config_params_exp = hef.create_configure_params(interface.value(), network_group_ptr->network_group_metadata().network_group_name()); - CHECK_EXPECTED(config_params_exp); - config_params = config_params_exp.release(); - } - - auto network_group_metadata = hef.pimpl->get_network_group_metadata(network_group_ptr->network_group_metadata().network_group_name()); - CHECK_EXPECTED(network_group_metadata); - - auto single_context_app = HcpConfigNetworkGroup(m_device, m_active_net_group_holder, net_group_config.release(), - config_params, current_net_group_index, network_group_metadata.release(), status); - CHECK_SUCCESS_AS_EXPECTED(status); - - auto net_group_shared_ptr = make_shared_nothrow(std::move(single_context_app)); - CHECK_AS_EXPECTED(nullptr != net_group_shared_ptr, HAILO_OUT_OF_HOST_MEMORY); - m_net_groups.emplace_back(net_group_shared_ptr); - - auto net_group_wrapper = ConfiguredNetworkGroupWrapper::create(net_group_shared_ptr); - CHECK_EXPECTED(net_group_wrapper); - - auto net_group_wrapper_ptr = make_shared_nothrow(net_group_wrapper.release()); - CHECK_AS_EXPECTED(nullptr != net_group_wrapper_ptr, HAILO_OUT_OF_HOST_MEMORY); - - m_net_group_wrappers.emplace_back(net_group_wrapper_ptr); - added_network_groups.emplace_back(std::static_pointer_cast(net_group_wrapper_ptr)); - - current_net_group_index++; - - // TODO: move this func into HcpConfigNetworkGroup c'tor - status = net_group_shared_ptr->create_streams_from_config_params(m_device); - CHECK_SUCCESS_AS_EXPECTED(status); - - // Check that all boundary streams were created - status = validate_boundary_streams_were_created(hef, network_group_ptr->network_group_metadata().network_group_name(), *net_group_shared_ptr); - CHECK_SUCCESS_AS_EXPECTED(status); - } - std::string unmatched_keys = ""; - for (const auto &pair : configure_params_copy) { - unmatched_keys.append(" "); - unmatched_keys.append(pair.first); - } - CHECK_AS_EXPECTED(unmatched_keys.size() == 0, HAILO_INVALID_ARGUMENT, - "Some network group names in the configuration are not found in the hef file:{}", unmatched_keys); - - return added_network_groups; -} - -ConfigManagerType HcpConfigManager::get_manager_type() -{ - return ConfigManagerType::HcpConfigManager; -} - -} /* namespace hailort */ diff --git a/hailort/libhailort/src/context_switch/hcp_config_network_group.cpp b/hailort/libhailort/src/context_switch/hcp_config_network_group.cpp index 22c9948..e6521f2 100644 --- a/hailort/libhailort/src/context_switch/hcp_config_network_group.cpp +++ b/hailort/libhailort/src/context_switch/hcp_config_network_group.cpp @@ -8,21 +8,21 @@ namespace hailort { -HcpConfigNetworkGroup::HcpConfigNetworkGroup(Device &device, HcpConfigActiveAppHolder &active_net_group_holder, - std::vector &&config, const ConfigureNetworkParams &config_params, uint8_t net_group_index, - NetworkGroupMetadata &&network_group_metadata, hailo_status &status) - : ConfiguredNetworkGroupBase(config_params, net_group_index, network_group_metadata, status), - m_config(std::move(config)), m_active_net_group_holder(active_net_group_holder), m_device(device) +HcpConfigNetworkGroup::HcpConfigNetworkGroup(Device &device, ActiveNetGroupHolder &active_net_group_holder, + std::vector &&config, const ConfigureNetworkParams &config_params, NetworkGroupMetadata &&network_group_metadata, + hailo_status &status, std::vector> &&net_flow_ops) + : ConfiguredNetworkGroupBase(config_params, network_group_metadata, std::move(net_flow_ops), status), + m_config(std::move(config)), m_active_net_group_holder(active_net_group_holder), m_device(device) {} -Expected> HcpConfigNetworkGroup::activate_impl( +Expected> HcpConfigNetworkGroup::create_activated_network_group( const hailo_activate_network_group_params_t &network_group_params, uint16_t /* dynamic_batch_size */) { auto start_time = std::chrono::steady_clock::now(); auto activated_net_group = HcpConfigActivatedNetworkGroup::create(m_device, m_config, name(), network_group_params, m_input_streams, m_output_streams, m_active_net_group_holder, m_config_params.power_mode, - m_network_group_activated_event); + m_network_group_activated_event, (*this)); CHECK_EXPECTED(activated_net_group); std::unique_ptr activated_net_group_ptr = make_unique_nothrow(activated_net_group.release()); @@ -68,4 +68,45 @@ Expected> HcpConfigNetworkGroup::get_boundary_vdma_ return make_unexpected(HAILO_INVALID_OPERATION); } +hailo_status HcpConfigNetworkGroup::activate_impl(uint16_t dynamic_batch_size) +{ + m_active_net_group_holder.set(*this); + + auto status = activate_low_level_streams(dynamic_batch_size); + CHECK_SUCCESS(status, "Failed activating low level streams"); + + status = m_network_group_activated_event->signal(); + CHECK_SUCCESS(status, "Failed to signal network activation event"); + + return HAILO_SUCCESS; +} +hailo_status HcpConfigNetworkGroup::deactivate_impl() +{ + auto expected_config_network_ref = m_active_net_group_holder.get(); + CHECK(expected_config_network_ref.has_value(), HAILO_INTERNAL_FAILURE, "Error getting configured network group"); + + const auto &config_network_group = expected_config_network_ref.value(); + // Make sure the network group we are deactivating is this object + CHECK(this == std::addressof(config_network_group.get()), HAILO_INTERNAL_FAILURE, + "Trying to deactivate different network goup"); + + m_active_net_group_holder.clear(); + + if (!m_network_group_activated_event) { + return HAILO_SUCCESS; + } + + m_network_group_activated_event->reset(); + + for (auto &name_pair : m_input_streams) { + const auto status = name_pair.second->flush(); + CHECK_SUCCESS(status, "Failed to flush input stream {}", name_pair.first); + } + + auto status = deactivate_low_level_streams(); + CHECK_SUCCESS(status, "Failed deactivating low level streams"); + + return HAILO_SUCCESS; +} + } /* namespace hailort */ diff --git a/hailort/libhailort/src/context_switch/hef_metadata.cpp b/hailort/libhailort/src/context_switch/hef_metadata.cpp deleted file mode 100644 index c2b851b..0000000 --- a/hailort/libhailort/src/context_switch/hef_metadata.cpp +++ /dev/null @@ -1,949 +0,0 @@ -#include -#include "common/utils.hpp" - -#include "context_switch/hef_metadata.hpp" -#include "control_protocol.h" -#include "context_switch_defs.h" -#include "byte_order.h" - -#include - -namespace hailort -{ - -CONTROL_PROTOCOL__TRIGGER_t HEF_METADATA__build_none_trigger() -{ - CONTROL_PROTOCOL__TRIGGER_t trigger{}; - trigger.type = CONTROL_PROTOCOL__CONTEXT_SWITCH_TRIGGER_TYPE_NONE; - // Note: none_trigger is empty - - return trigger; -} - -CONTROL_PROTOCOL__TRIGGER_t HEF_METADATA__build_input_stream_trigger(uint8_t stream_index) -{ - CONTROL_PROTOCOL__TRIGGER_t trigger{}; - trigger.type = CONTROL_PROTOCOL__CONTEXT_SWITCH_TRIGGER_TYPE_INPUT_STREAM; - trigger.params.input_stream_trigger.stream_index = stream_index; - - return trigger; -} - -CONTROL_PROTOCOL__TRIGGER_t HEF_METADATA__build_output_stream_trigger(uint8_t stream_index) -{ - CONTROL_PROTOCOL__TRIGGER_t trigger{}; - trigger.type = CONTROL_PROTOCOL__CONTEXT_SWITCH_TRIGGER_TYPE_OUTPUT_STREAM; - trigger.params.output_stream_trigger.stream_index = stream_index; - - return trigger; -} - -CONTROL_PROTOCOL__TRIGGER_t HEF_METADATA__build_lcu_trigger(uint8_t cluster_index, uint8_t lcu_index) -{ - CONTROL_PROTOCOL__TRIGGER_t trigger{}; - trigger.type = CONTROL_PROTOCOL__CONTEXT_SWITCH_TRIGGER_TYPE_LCU; - trigger.params.lcu_trigger.cluster_index = cluster_index; - trigger.params.lcu_trigger.lcu_index = lcu_index; - - return trigger; -} - -CONTROL_PROTOCOL__TRIGGER_t HEF_METADATA__build_nms_trigger(uint8_t aggregator_index, - uint8_t pred_cluster_ob_index, uint8_t pred_cluster_ob_cluster_index, uint8_t pred_cluster_ob_interface, - uint8_t succ_prepost_ob_index, uint8_t succ_prepost_ob_interface) -{ - CONTROL_PROTOCOL__TRIGGER_t trigger{}; - trigger.type = CONTROL_PROTOCOL__CONTEXT_SWITCH_TRIGGER_TYPE_NMS_IDLE; - trigger.params.nms_idle_trigger.aggregator_index = aggregator_index; - trigger.params.nms_idle_trigger.pred_cluster_ob_index = pred_cluster_ob_index; - trigger.params.nms_idle_trigger.pred_cluster_ob_cluster_index = pred_cluster_ob_cluster_index; - trigger.params.nms_idle_trigger.pred_cluster_ob_interface = pred_cluster_ob_interface; - trigger.params.nms_idle_trigger.succ_prepost_ob_index = succ_prepost_ob_index; - trigger.params.nms_idle_trigger.succ_prepost_ob_interface = succ_prepost_ob_interface; - - return trigger; -} - -CONTROL_PROTOCOL__TRIGGER_t HEF_METADATA__build_dma_idle_trigger(uint8_t stream_index) -{ - CONTROL_PROTOCOL__TRIGGER_t trigger{}; - trigger.type = CONTROL_PROTOCOL__CONTEXT_SWITCH_TRIGGER_TYPE_DMA_IDLE; - trigger.params.dma_idle_trigger.stream_index = stream_index; - - return trigger; -} - -uint16_t hef_metadata__return_network_data_offset( - CONTROL_PROTOCOL__context_switch_context_info_t *context_info) -{ - uint8_t current_slice_index = 0; - uint32_t current_offset_local = 0; - - current_offset_local = context_info->control_slicing_data.current_buillding_offset_inside_slice; - current_slice_index = context_info->control_slicing_data.current_building_slice_index; - - if (0 < current_slice_index) { - current_offset_local += context_info->control_slicing_data.control_slicing_offsets[current_slice_index - 1]; - } - - return ((uint16_t)(current_offset_local)); -} - -void hef_metadata__add_none_trigger_without_updating_slicing_info( - CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **trigger_group_data_current_offset) -{ - CONTROL_PROTOCOL__trigger_group_t trigger_group = {}; - - trigger_group.trigger = HEF_METADATA__build_none_trigger(); - trigger_group.triggers_action_count = 0; - - context_info->control_slicing_data.current_building_trigger = - (CONTROL_PROTOCOL__trigger_group_t *)(*trigger_group_data_current_offset); - - memcpy((*trigger_group_data_current_offset), &(trigger_group), sizeof(trigger_group)); - *(trigger_group_data_current_offset) += sizeof(trigger_group); -} - -hailo_status hef_metadata__update_slicing_info( - CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **struct_current_offset, - uint8_t struct_size, - bool is_action) -{ - uint16_t current_building_slice_index = 0; - bool would_exceed_slice_limit = false; - bool would_exceed_max_trigger_action_count = false; - - CHECK(CONTROL_PROTOCOL__CONTEXT_NETWORK_DATA_SINGLE_CONTROL_MAX_SIZE >= static_cast(struct_size), - HAILO_CHUNK_TOO_LARGE); - - /* extract current slice */ - current_building_slice_index = context_info->control_slicing_data.current_building_slice_index; - - const auto last_trigger_index = (current_building_slice_index == 0) ? 0 : (current_building_slice_index - 1); - const auto last_trigger_offset = context_info->control_slicing_data.control_slicing_offsets[last_trigger_index]; - const auto acummulated_metadata_offset = - last_trigger_offset + context_info->control_slicing_data.current_buillding_offset_inside_slice + struct_size; - - if (acummulated_metadata_offset > CONTROL_PROTOCOL__CONTEXT_NETWORK_DATA_MAX_SIZE) { - /* If condition failed - consider increasing 'CONTROL_PROTOCOL__CONTEXT_NETWORK_DATA_MAX_SIZE' define */ - LOGGER__ERROR("context metadata is larger than max data size. Acuumulated metadata offset is {}. Max size is {} ", - acummulated_metadata_offset, CONTROL_PROTOCOL__CONTEXT_NETWORK_DATA_MAX_SIZE); - return HAILO_INTERNAL_FAILURE; - } - - would_exceed_slice_limit = CONTROL_PROTOCOL__CONTEXT_NETWORK_DATA_SINGLE_CONTROL_MAX_SIZE - < (context_info->control_slicing_data.current_buillding_offset_inside_slice + struct_size); - if (is_action) { - /* context_info->control_slicing_data.current_building_trigger will be null if !is_action */ - static_assert(sizeof(uint16_t) == sizeof(context_info->control_slicing_data.current_building_trigger->triggers_action_count), - "triggers_action_count field isn't uint16_t"); - would_exceed_max_trigger_action_count = context_info->control_slicing_data.current_building_trigger->triggers_action_count - == (std::numeric_limits::max() - 1); - } - - /* If the next written struct would exceed the slice limit or max trigger action count */ - if (would_exceed_slice_limit || would_exceed_max_trigger_action_count) { - /* Save slice end offset */ - context_info->control_slicing_data.control_slicing_offsets[current_building_slice_index] = - hef_metadata__return_network_data_offset(context_info); - - /* Advance slice index */ - (context_info->control_slicing_data.current_building_slice_index)++; - current_building_slice_index++; - context_info->control_slicing_data.current_buillding_offset_inside_slice = 0; - - /* If slice was inside action - add NONE trigger to start slice with trigger */ - if (is_action) { - static_assert(CONTROL_PROTOCOL__CONTEXT_NETWORK_DATA_SINGLE_CONTROL_MAX_SIZE >= sizeof(CONTROL_PROTOCOL__trigger_group_t), - "Trigger cant fit the slice size"); - - /* Build trigger */ - hef_metadata__add_none_trigger_without_updating_slicing_info(context_info, struct_current_offset); - - /* Add the trigger offset */ - context_info->control_slicing_data.current_buillding_offset_inside_slice = sizeof(CONTROL_PROTOCOL__trigger_group_t); - context_info->control_slicing_data.slice_triggers[current_building_slice_index]++; - } - } - - if (is_action) { - context_info->control_slicing_data.current_building_trigger->triggers_action_count++; - } - - /* Add the struct offset */ - context_info->control_slicing_data.current_buillding_offset_inside_slice = - (uint16_t)(context_info->control_slicing_data.current_buillding_offset_inside_slice + struct_size); - - return HAILO_SUCCESS; -} - -hailo_status HEF_METADATA__add_trigger_to_trigger_group( - CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **trigger_group_data_current_offset, - const CONTROL_PROTOCOL__TRIGGER_t *trigger) -{ - hailo_status status = HAILO_UNINITIALIZED; - CONTROL_PROTOCOL__trigger_group_t trigger_group = {}; - uint8_t control_slice_index = 0; - - CHECK_ARG_NOT_NULL(context_info); - CHECK_ARG_NOT_NULL(trigger_group_data_current_offset); - CHECK_ARG_NOT_NULL(*trigger_group_data_current_offset); - CHECK_ARG_NOT_NULL(trigger); - - trigger_group.trigger = *trigger; - trigger_group.triggers_action_count = 0; - - /* Update slice data (before actual write) */ - context_info->control_slicing_data.current_building_trigger = - (CONTROL_PROTOCOL__trigger_group_t *)(*trigger_group_data_current_offset); - status = hef_metadata__update_slicing_info(context_info, - trigger_group_data_current_offset, - sizeof(trigger_group), - false); - CHECK_SUCCESS(status); - control_slice_index = context_info->control_slicing_data.current_building_slice_index; - - /* Check for overflow */ - static_assert(sizeof(uint8_t) == sizeof(context_info->control_slicing_data.slice_triggers[control_slice_index]), - "slice_triggers field isn't uint8_t"); - CHECK(context_info->control_slicing_data.slice_triggers[control_slice_index] < std::numeric_limits::max(), - HAILO_INTERNAL_FAILURE); - context_info->control_slicing_data.slice_triggers[control_slice_index]++; - - memcpy((*trigger_group_data_current_offset), &(trigger_group), sizeof(trigger_group)); - *(trigger_group_data_current_offset) += sizeof(trigger_group); - - return HAILO_SUCCESS; -} - -hailo_status hef_metadata__add_general_action( - CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **action_data_current_offset, - CONTROL_PROTOCOL__ACTION_TYPE_t action_type, - uint8_t action_data, - bool is_repeated) -{ - hailo_status status = HAILO_UNINITIALIZED; - CONTROL_PROTOCOL__ACTION_HEADER_t header{}; - - CHECK_ARG_NOT_NULL(action_data_current_offset); - CHECK_ARG_NOT_NULL(*action_data_current_offset); - - header.action_type = static_cast(action_type); - header.is_repeated = is_repeated; - - /* Update slice data (before actual write) */ - status = hef_metadata__update_slicing_info(context_info, - action_data_current_offset, - sizeof(header) + sizeof(action_data), - true); - CHECK_SUCCESS(status); - - /* Setting action header */ - memcpy((*action_data_current_offset), &header, sizeof(header)); - *(action_data_current_offset) += sizeof(header); - /* Setting action_data */ - memcpy((*action_data_current_offset), &action_data, sizeof(action_data)); - *(action_data_current_offset) += sizeof(action_data); - - return HAILO_SUCCESS; -} - -hailo_status HEF_METADATA__add_enable_sequencer_action( - CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **action_data_current_offset, - uint8_t cluster_index, - uint8_t initial_l3_cut, - uint16_t initial_l3_offset, - uint32_t active_apu, - uint32_t active_ia, - uint64_t active_sc, - uint64_t active_l2, - uint64_t l2_offset_0, - uint64_t l2_offset_1, - bool is_repeated) -{ - hailo_status status = HAILO_UNINITIALIZED; - CONTROL_PROTOCOL__TRIGGER_SEQUENCER_ACTION_t trigger_sequencer_action{}; - - CHECK_ARG_NOT_NULL(action_data_current_offset); - CHECK_ARG_NOT_NULL(*action_data_current_offset); - - trigger_sequencer_action.header.action_type = CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_TRIGGER_SEQUENCER; - trigger_sequencer_action.header.is_repeated = is_repeated; - trigger_sequencer_action.cluster_index = cluster_index; - trigger_sequencer_action.sequencer_config.initial_l3_cut = initial_l3_cut; - trigger_sequencer_action.sequencer_config.initial_l3_offset = initial_l3_offset; - trigger_sequencer_action.sequencer_config.active_apu = active_apu; - trigger_sequencer_action.sequencer_config.active_ia = active_ia; - trigger_sequencer_action.sequencer_config.active_sc = active_sc; - trigger_sequencer_action.sequencer_config.active_l2 = active_l2; - trigger_sequencer_action.sequencer_config.l2_offset_0 = l2_offset_0; - trigger_sequencer_action.sequencer_config.l2_offset_1 = l2_offset_1; - - status = hef_metadata__update_slicing_info(context_info, - action_data_current_offset, - sizeof(trigger_sequencer_action), - true); - CHECK_SUCCESS(status); - - memcpy((*action_data_current_offset), &trigger_sequencer_action, sizeof(trigger_sequencer_action)); - *(action_data_current_offset) += sizeof(trigger_sequencer_action); - - return HAILO_SUCCESS; -} - -hailo_status HEF_METADATA__add_read_vdma_action( - CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **action_data_current_offset, - uint16_t descriptors_count, - uint8_t config_stream_index, - bool is_repeated) -{ - hailo_status status = HAILO_UNINITIALIZED; - CONTROL_PROTOCOL__READ_VDMA_ACTION_t read_vdma_action{}; - - CHECK_ARG_NOT_NULL(action_data_current_offset); - CHECK_ARG_NOT_NULL(*action_data_current_offset); - - read_vdma_action.header.action_type = CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_READ_VDMA; - read_vdma_action.header.is_repeated = is_repeated; - read_vdma_action.descriptors_count = descriptors_count; - read_vdma_action.config_stream_index = config_stream_index; - - status = hef_metadata__update_slicing_info(context_info, - action_data_current_offset, - sizeof(read_vdma_action), - true); - CHECK_SUCCESS(status); - - memcpy((*action_data_current_offset), &read_vdma_action, sizeof(read_vdma_action)); - *(action_data_current_offset) += sizeof(read_vdma_action); - - return HAILO_SUCCESS; -} - -hailo_status HEF_METADATA__add_ccw_bursts_action( - CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **action_data_current_offset, - uint16_t ccw_bursts, - uint8_t config_stream_index, - bool is_repeated) -{ - hailo_status status = HAILO_UNINITIALIZED; - CONTROL_PROTOCOL__FETCH_CCW_BURSTS_ACTION_t fetch_ccw_bursts{}; - - CHECK_ARG_NOT_NULL(action_data_current_offset); - CHECK_ARG_NOT_NULL(*action_data_current_offset); - - fetch_ccw_bursts.header.action_type = CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_FETCH_CCW_BURSTS; - fetch_ccw_bursts.header.is_repeated = is_repeated; - fetch_ccw_bursts.ccw_bursts = ccw_bursts; - fetch_ccw_bursts.config_stream_index = config_stream_index; - - status = hef_metadata__update_slicing_info(context_info, - action_data_current_offset, - sizeof(fetch_ccw_bursts), - true); - CHECK_SUCCESS(status); - - memcpy((*action_data_current_offset), &fetch_ccw_bursts, sizeof(fetch_ccw_bursts)); - *(action_data_current_offset) += sizeof(fetch_ccw_bursts); - - return HAILO_SUCCESS; -} - -hailo_status HEF_METADATA__add_repeated_header_action( - CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **action_data_current_offset, - CONTROL_PROTOCOL__ACTION_TYPE_t sub_action_type, - uint8_t num_actions -) -{ - hailo_status status = HAILO_UNINITIALIZED; - CONTROL_PROTOCOL__REPEATED_ACTION_t repeated_action{}; - - CHECK_ARG_NOT_NULL(action_data_current_offset); - CHECK_ARG_NOT_NULL(*action_data_current_offset); - - repeated_action.header.action_type = CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_ADD_REPEATED; - repeated_action.header.is_repeated = false; - repeated_action.sub_action_type = sub_action_type; - repeated_action.num_actions = num_actions; - - status = hef_metadata__update_slicing_info(context_info, - action_data_current_offset, - sizeof(repeated_action), - true); - CHECK_SUCCESS(status); - - memcpy((*action_data_current_offset), &repeated_action, sizeof(repeated_action)); - *(action_data_current_offset) += sizeof(repeated_action); - - return HAILO_SUCCESS; -} - -hailo_status HEF_METADATA__add_wait_for_sequencer_action( - CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **action_data_current_offset, - uint8_t sequencer_index, - bool is_repeated) -{ - return hef_metadata__add_general_action( - context_info, - action_data_current_offset, - CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_WAIT_FOR_SEQUENCER_DONE, - sequencer_index, - is_repeated); -} - -hailo_status HEF_METADATA__add_fetch_new_data_action( - CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **action_data_current_offset, - uint8_t shmifo_index, - bool is_repeated) -{ - return hef_metadata__add_general_action( - context_info, - action_data_current_offset, - CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_TRIGGER_NEW_DATA_FROM_DATA_INPUT, - shmifo_index, - is_repeated); -} - -hailo_status HEF_METADATA__add_enable_lcu_non_default_action( - CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **action_data_current_offset, - uint8_t cluster_index, - uint8_t lcu_index, - uint16_t kernel_done_address, - uint32_t kernel_done_count, - uint8_t network_index, - bool is_repeated) -{ - hailo_status status = HAILO_UNINITIALIZED; - CONTROL_PROTOCOL__ENABLE_LCU_NON_DEAFULT_ACTION_t enable_lcu_action{}; - - CHECK_ARG_NOT_NULL(action_data_current_offset); - CHECK_ARG_NOT_NULL(*action_data_current_offset); - - enable_lcu_action.header.action_type = CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_ENABLE_LCU_NON_DEFAULT; - enable_lcu_action.header.is_repeated = is_repeated; - enable_lcu_action.cluster_index = cluster_index; - enable_lcu_action.lcu_index = lcu_index; - enable_lcu_action.kernel_done_address = kernel_done_address; - enable_lcu_action.kernel_done_count = kernel_done_count; - enable_lcu_action.network_index = network_index; - - status = hef_metadata__update_slicing_info(context_info, action_data_current_offset, - sizeof(enable_lcu_action), true); - CHECK_SUCCESS(status); - - memcpy((*action_data_current_offset), &enable_lcu_action, sizeof(enable_lcu_action)); - *(action_data_current_offset) += sizeof(enable_lcu_action); - - return HAILO_SUCCESS; -} - -hailo_status HEF_METADATA__add_enable_lcu_default_action( - CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **action_data_current_offset, - uint8_t cluster_index, - uint8_t lcu_index, - uint8_t network_index, - bool is_repeated) -{ - hailo_status status = HAILO_UNINITIALIZED; - CONTROL_PROTOCOL__ENABLE_LCU_DEFAULT_ACTION_t enable_lcu_action{}; - - CHECK_ARG_NOT_NULL(action_data_current_offset); - CHECK_ARG_NOT_NULL(*action_data_current_offset); - - enable_lcu_action.header.action_type = CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_ENABLE_LCU_DEFAULT; - enable_lcu_action.header.is_repeated = is_repeated; - enable_lcu_action.cluster_index = cluster_index; - enable_lcu_action.lcu_index = lcu_index; - enable_lcu_action.network_index = network_index; - - status = hef_metadata__update_slicing_info(context_info, action_data_current_offset, - sizeof(enable_lcu_action), true); - CHECK_SUCCESS(status); - - memcpy((*action_data_current_offset), &enable_lcu_action, sizeof(enable_lcu_action)); - *(action_data_current_offset) += sizeof(enable_lcu_action); - - return HAILO_SUCCESS; -} - -hailo_status HEF_METADATA__add_disable_lcu_action( - CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **action_data_current_offset, - uint8_t cluster_index, - uint8_t lcu_index, - bool is_repeated) -{ - hailo_status status = HAILO_UNINITIALIZED; - CONTROL_PROTOCOL__DISABLE_LCU_ACTION_t disable_lcu_action{}; - - CHECK_ARG_NOT_NULL(action_data_current_offset); - CHECK_ARG_NOT_NULL(*action_data_current_offset); - - disable_lcu_action.header.action_type = CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_DISABLE_LCU; - disable_lcu_action.header.is_repeated = is_repeated; - disable_lcu_action.cluster_index = cluster_index; - disable_lcu_action.lcu_index = lcu_index; - - status = hef_metadata__update_slicing_info(context_info, - action_data_current_offset, - sizeof(disable_lcu_action), - true); - CHECK_SUCCESS(status); - - memcpy((*action_data_current_offset), &disable_lcu_action, sizeof(disable_lcu_action)); - *(action_data_current_offset) += sizeof(disable_lcu_action); - - return HAILO_SUCCESS; -} - -hailo_status HEF_METADATA__add_wait_for_module_config_done_action( - CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **action_data_current_offset, - uint8_t module_index, - bool is_repeated) -{ - hailo_status status = HAILO_UNINITIALIZED; - CONTORL_PROTOCOL__WAIT_FOR_MODULE_CONFIG_DONE_ACTION_t wait_for_module_done_action{}; - - CHECK_ARG_NOT_NULL(action_data_current_offset); - CHECK_ARG_NOT_NULL(*action_data_current_offset); - - wait_for_module_done_action.header.action_type = CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_WAIT_FOR_MODULE_CONFIG_DONE; - wait_for_module_done_action.header.is_repeated = is_repeated; - wait_for_module_done_action.module_index = module_index; - - status = hef_metadata__update_slicing_info(context_info, - action_data_current_offset, - sizeof(wait_for_module_done_action), - true); - CHECK_SUCCESS(status); - - memcpy((*action_data_current_offset), &wait_for_module_done_action, sizeof(wait_for_module_done_action)); - *(action_data_current_offset) += sizeof(wait_for_module_done_action); - - return HAILO_SUCCESS; -} - -/* build edge layers functions */ -void hef_metadata__add_edge_layer_header( - uint8_t **edge_layer_current_offset, - CONTROL_PROTOCOL__EDGE_CONNECTION_TYPE_t edge_connection_type) -{ - CONTROL_PROTOCOL__edge_layer_header_t *edge_layer_header = nullptr; - - edge_layer_header = (CONTROL_PROTOCOL__edge_layer_header_t *)(*edge_layer_current_offset); - edge_layer_header->edge_connection_type = static_cast(edge_connection_type); - *(edge_layer_current_offset) += sizeof(*edge_layer_header); -} - -static void hef_metadata__fill_edge_layer_common_info( - CONTROL_PROTOCOL__edge_layer_common_info_t *edge_layer_common_info, - vdma::ChannelId channel_id, - uint8_t stream_index, - uint8_t network_index, - const CONTROL_PROTOCOL__nn_stream_config_t &nn_stream_config) -{ - edge_layer_common_info->engine_index = channel_id.engine_index; - edge_layer_common_info->vdma_channel_index = channel_id.channel_index; - edge_layer_common_info->stream_index = stream_index; - edge_layer_common_info->network_index = network_index; - edge_layer_common_info->nn_stream_config.core_bytes_per_buffer = BYTE_ORDER__htons(nn_stream_config.core_bytes_per_buffer); - edge_layer_common_info->nn_stream_config.core_buffers_per_frame = BYTE_ORDER__htons(nn_stream_config.core_buffers_per_frame); - edge_layer_common_info->nn_stream_config.periph_bytes_per_buffer = BYTE_ORDER__htons(nn_stream_config.periph_bytes_per_buffer); - edge_layer_common_info->nn_stream_config.feature_padding_payload = BYTE_ORDER__htons(nn_stream_config.feature_padding_payload); - edge_layer_common_info->nn_stream_config.buffer_padding_payload = BYTE_ORDER__htons(nn_stream_config.buffer_padding_payload); - edge_layer_common_info->nn_stream_config.buffer_padding = BYTE_ORDER__htons(nn_stream_config.buffer_padding); -} - -hailo_status HEF_METADATA__add_network_boundary_output_edge_layer( - CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **edge_layer_current_offset, - vdma::ChannelId channel_id, - uint8_t stream_index, - uint8_t network_index, - const CONTROL_PROTOCOL__nn_stream_config_t &nn_stream_config, - const CONTROL_PROTOCOL__host_buffer_info_t &host_buffer_info) -{ - hailo_status status = HAILO_UNINITIALIZED; - CONTROL_PROTOCOL__network_boundary_output_t *edge_layer_info = nullptr; - uint8_t control_slice_index = 0; - - CHECK_ARG_NOT_NULL(edge_layer_current_offset); - CHECK_ARG_NOT_NULL(*edge_layer_current_offset); - - status = hef_metadata__update_slicing_info(context_info, - edge_layer_current_offset, - (sizeof(CONTROL_PROTOCOL__edge_layer_header_t ) + sizeof(*edge_layer_info)), - false); - CHECK_SUCCESS(status); - control_slice_index = context_info->control_slicing_data.current_building_slice_index; - context_info->control_slicing_data.slice_edge_layers[control_slice_index]++; - - hef_metadata__add_edge_layer_header(edge_layer_current_offset, - CONTROL_PROTOCOL__EDGE_CONNECTION_TYPE_NETWORK_BOUNDARY_OUTPUT); - - edge_layer_info = (CONTROL_PROTOCOL__network_boundary_output_t *)(*edge_layer_current_offset); - - hef_metadata__fill_edge_layer_common_info(&(edge_layer_info->common_info), - channel_id, - stream_index, - network_index, - nn_stream_config); - - edge_layer_info->host_buffer_info = host_buffer_info; - - *(edge_layer_current_offset) += sizeof(*edge_layer_info); - - return HAILO_SUCCESS; -} - -hailo_status HEF_METADATA__add_inter_context_output_edge_layer( - CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **edge_layer_current_offset, - vdma::ChannelId channel_id, - uint8_t stream_index, - uint8_t network_index, - const CONTROL_PROTOCOL__nn_stream_config_t &nn_stream_config, - const CONTROL_PROTOCOL__host_buffer_info_t &host_buffer_info) -{ - hailo_status status = HAILO_UNINITIALIZED; - CONTROL_PROTOCOL__inter_context_output_t *edge_layer_info = nullptr; - uint8_t control_slice_index = 0; - - CHECK_ARG_NOT_NULL(edge_layer_current_offset); - CHECK_ARG_NOT_NULL(*edge_layer_current_offset); - - status = hef_metadata__update_slicing_info(context_info, - edge_layer_current_offset, - (sizeof(CONTROL_PROTOCOL__edge_layer_header_t ) + sizeof(*edge_layer_info)), - false); - CHECK_SUCCESS(status); - control_slice_index = context_info->control_slicing_data.current_building_slice_index; - context_info->control_slicing_data.slice_edge_layers[control_slice_index]++; - - hef_metadata__add_edge_layer_header(edge_layer_current_offset, - CONTROL_PROTOCOL__EDGE_CONNECTION_TYPE_INTERMEDIATE_BUFFER_OUTPUT); - - edge_layer_info = (CONTROL_PROTOCOL__inter_context_output_t *)(*edge_layer_current_offset); - - hef_metadata__fill_edge_layer_common_info(&(edge_layer_info->common_info), - channel_id, - stream_index, - network_index, - nn_stream_config); - - edge_layer_info->host_buffer_info = host_buffer_info; - - *(edge_layer_current_offset) += sizeof(*edge_layer_info); - - return HAILO_SUCCESS; -} - -hailo_status HEF_METADATA__add_ddr_buffer_output_edge_layer( - CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **edge_layer_current_offset, - vdma::ChannelId channel_id, - uint8_t stream_index, - uint8_t network_index, - const CONTROL_PROTOCOL__nn_stream_config_t &nn_stream_config, - const CONTROL_PROTOCOL__host_buffer_info_t &host_buffer_info, - uint32_t buffered_rows_count) -{ - hailo_status status = HAILO_UNINITIALIZED; - CONTROL_PROTOCOL__ddr_buffer_output_t *edge_layer_info = nullptr; - uint8_t control_slice_index = 0; - - CHECK_ARG_NOT_NULL(edge_layer_current_offset); - CHECK_ARG_NOT_NULL(*edge_layer_current_offset); - - status = hef_metadata__update_slicing_info(context_info, - edge_layer_current_offset, - (sizeof(CONTROL_PROTOCOL__edge_layer_header_t ) + sizeof(*edge_layer_info)), - false); - CHECK_SUCCESS(status); - control_slice_index = context_info->control_slicing_data.current_building_slice_index; - context_info->control_slicing_data.slice_edge_layers[control_slice_index]++; - - hef_metadata__add_edge_layer_header(edge_layer_current_offset, - CONTROL_PROTOCOL__EDGE_CONNECTION_TYPE_DDR_BUFFER_OUTPUT); - - edge_layer_info = (CONTROL_PROTOCOL__ddr_buffer_output_t *)(*edge_layer_current_offset); - - hef_metadata__fill_edge_layer_common_info(&(edge_layer_info->common_info), - channel_id, - stream_index, - network_index, - nn_stream_config); - - *(edge_layer_current_offset) += sizeof(*edge_layer_info); - - edge_layer_info->host_buffer_info = host_buffer_info; - edge_layer_info->buffered_rows_count = buffered_rows_count; - - return HAILO_SUCCESS; -} - -hailo_status HEF_METADATA__add_network_boundary_input_edge_layer( - CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **edge_layer_current_offset, - vdma::ChannelId channel_id, - uint8_t stream_index, - uint8_t network_index, - const CONTROL_PROTOCOL__nn_stream_config_t &nn_stream_config, - const CONTROL_PROTOCOL__host_buffer_info_t &host_buffer_info, - uint32_t initial_credit_size) -{ - hailo_status status = HAILO_UNINITIALIZED; - CONTROL_PROTOCOL__network_boundary_input_t *edge_layer_info = nullptr; - uint8_t control_slice_index = 0; - - CHECK_ARG_NOT_NULL(edge_layer_current_offset); - CHECK_ARG_NOT_NULL(*edge_layer_current_offset); - - status = hef_metadata__update_slicing_info(context_info, - edge_layer_current_offset, - (sizeof(CONTROL_PROTOCOL__edge_layer_header_t ) + sizeof(*edge_layer_info)), - false); - CHECK_SUCCESS(status); - control_slice_index = context_info->control_slicing_data.current_building_slice_index; - context_info->control_slicing_data.slice_edge_layers[control_slice_index]++; - - hef_metadata__add_edge_layer_header(edge_layer_current_offset, - CONTROL_PROTOCOL__EDGE_CONNECTION_TYPE_NETWORK_BOUNDARY_INPUT); - - edge_layer_info = (CONTROL_PROTOCOL__network_boundary_input_t *)(*edge_layer_current_offset); - - hef_metadata__fill_edge_layer_common_info(&(edge_layer_info->common_info), - channel_id, - stream_index, - network_index, - nn_stream_config); - - edge_layer_info->host_buffer_info = host_buffer_info; - edge_layer_info->initial_credit_size = initial_credit_size; - - *(edge_layer_current_offset) += sizeof(*edge_layer_info); - - return HAILO_SUCCESS; -} - -hailo_status HEF_METADATA__add_inter_context_input_edge_layer( - CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **edge_layer_current_offset, - vdma::ChannelId channel_id, - uint8_t stream_index, - uint8_t network_index, - const CONTROL_PROTOCOL__nn_stream_config_t &nn_stream_config, - const CONTROL_PROTOCOL__host_buffer_info_t &host_buffer_info, - uint32_t initial_credit_size) -{ - hailo_status status = HAILO_UNINITIALIZED; - CONTROL_PROTOCOL__inter_context_input_t *edge_layer_info = nullptr; - uint8_t control_slice_index = 0; - - CHECK_ARG_NOT_NULL(edge_layer_current_offset); - CHECK_ARG_NOT_NULL(*edge_layer_current_offset); - - status = hef_metadata__update_slicing_info(context_info, - edge_layer_current_offset, - (sizeof(CONTROL_PROTOCOL__edge_layer_header_t ) + sizeof(*edge_layer_info)), - false); - CHECK_SUCCESS(status); - control_slice_index = context_info->control_slicing_data.current_building_slice_index; - context_info->control_slicing_data.slice_edge_layers[control_slice_index]++; - - hef_metadata__add_edge_layer_header(edge_layer_current_offset, - CONTROL_PROTOCOL__EDGE_CONNECTION_TYPE_INTERMEDIATE_BUFFER_INPUT); - - edge_layer_info = (CONTROL_PROTOCOL__inter_context_input_t *)(*edge_layer_current_offset); - - hef_metadata__fill_edge_layer_common_info(&(edge_layer_info->common_info), - channel_id, - stream_index, - network_index, - nn_stream_config); - - edge_layer_info->host_buffer_info = host_buffer_info; - edge_layer_info->initial_credit_size = initial_credit_size; - - *(edge_layer_current_offset) += sizeof(*edge_layer_info); - - return HAILO_SUCCESS; -} - -hailo_status HEF_METADATA__add_ddr_buffer_input_edge_layer( - CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **edge_layer_current_offset, - vdma::ChannelId channel_id, - uint8_t stream_index, - uint8_t network_index, - const CONTROL_PROTOCOL__nn_stream_config_t &nn_stream_config, - const CONTROL_PROTOCOL__host_buffer_info_t &host_buffer_info, - uint32_t initial_credit_size, - vdma::ChannelId connected_d2h_channel_id) -{ - hailo_status status = HAILO_UNINITIALIZED; - CONTROL_PROTOCOL__ddr_buffer_input_t *edge_layer_info = nullptr; - uint8_t control_slice_index = 0; - - CHECK_ARG_NOT_NULL(edge_layer_current_offset); - CHECK_ARG_NOT_NULL(*edge_layer_current_offset); - - status = hef_metadata__update_slicing_info(context_info, - edge_layer_current_offset, - (sizeof(CONTROL_PROTOCOL__edge_layer_header_t ) + sizeof(*edge_layer_info)), - false); - CHECK_SUCCESS(status); - control_slice_index = context_info->control_slicing_data.current_building_slice_index; - context_info->control_slicing_data.slice_edge_layers[control_slice_index]++; - - hef_metadata__add_edge_layer_header(edge_layer_current_offset, - CONTROL_PROTOCOL__EDGE_CONNECTION_TYPE_DDR_BUFFER_INPUT); - - edge_layer_info = (CONTROL_PROTOCOL__ddr_buffer_input_t *)(*edge_layer_current_offset); - - hef_metadata__fill_edge_layer_common_info(&(edge_layer_info->common_info), - channel_id, - stream_index, - network_index, - nn_stream_config); - - edge_layer_info->host_buffer_info = host_buffer_info; - edge_layer_info->initial_credit_size = initial_credit_size; - edge_layer_info->connected_d2h_engine_index = connected_d2h_channel_id.engine_index; - edge_layer_info->connected_d2h_channel_index = connected_d2h_channel_id.channel_index; - - *(edge_layer_current_offset) += sizeof(*edge_layer_info); - - return HAILO_SUCCESS; -} - -hailo_status HEF_METADATA__add_ddr_pair_info( - CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **action_data_current_offset, - const vdma::ChannelId h2d_vdma_channel_id, - const vdma::ChannelId d2h_vdma_channel_id, - const uint32_t descriptors_per_frame, - const uint16_t programmed_descriptors_count, - bool is_repeated) -{ - hailo_status status = HAILO_UNINITIALIZED; - CONTROL_PROTOCOL__ADD_DDR_PAIR_ACTION_t ddr_pair_action{}; - - CHECK_ARG_NOT_NULL(action_data_current_offset); - CHECK_ARG_NOT_NULL(*action_data_current_offset); - - ddr_pair_action.header.action_type = CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_ADD_DDR_PAIR_INFO; - ddr_pair_action.header.is_repeated = is_repeated; - ddr_pair_action.h2d_engine_index = h2d_vdma_channel_id.engine_index; - ddr_pair_action.h2d_vdma_channel_index = h2d_vdma_channel_id.channel_index; - ddr_pair_action.d2h_engine_index = d2h_vdma_channel_id.engine_index; - ddr_pair_action.d2h_vdma_channel_index = d2h_vdma_channel_id.channel_index; - ddr_pair_action.descriptors_per_frame = descriptors_per_frame; - ddr_pair_action.programmed_descriptors_count = programmed_descriptors_count; - - status = hef_metadata__update_slicing_info(context_info, - action_data_current_offset, - sizeof(ddr_pair_action), - true); - CHECK_SUCCESS(status); - - memcpy((*action_data_current_offset), &ddr_pair_action, sizeof(ddr_pair_action)); - *(action_data_current_offset) += sizeof(ddr_pair_action); - - return HAILO_SUCCESS; -} - -hailo_status HEF_METADATA__add_ddr_buffering_start( - CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **action_data_current_offset, - bool is_repeated) -{ - hailo_status status = HAILO_UNINITIALIZED; - CONTROL_PROTOCOL__ADD_DDR_BUFFERING_START_ACTION_t ddr_buffering_start{}; - - CHECK_ARG_NOT_NULL(action_data_current_offset); - CHECK_ARG_NOT_NULL(*action_data_current_offset); - - ddr_buffering_start.header.action_type = CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_ADD_DDR_BUFFERING_START; - ddr_buffering_start.header.is_repeated = is_repeated; - - status = hef_metadata__update_slicing_info(context_info, - action_data_current_offset, - sizeof(ddr_buffering_start), - true); - CHECK_SUCCESS(status); - - memcpy((*action_data_current_offset), &ddr_buffering_start, sizeof(ddr_buffering_start)); - *(action_data_current_offset) += sizeof(ddr_buffering_start); - - return HAILO_SUCCESS; -} - -hailo_status HEF_METADATA__burst_credits_task_start( - CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **action_data_current_offset, - bool is_repeated) -{ - hailo_status status = HAILO_UNINITIALIZED; - CONTROL_PROTOCOL__BURST_CREDITS_TASK_START_ACTION_T burst_credits_task_start{}; - - CHECK_ARG_NOT_NULL(action_data_current_offset); - CHECK_ARG_NOT_NULL(*action_data_current_offset); - - burst_credits_task_start.header.action_type = CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_BURST_CREDITS_TASK_START; - burst_credits_task_start.header.is_repeated = is_repeated; - - status = hef_metadata__update_slicing_info(context_info, - action_data_current_offset, - sizeof(burst_credits_task_start), - true); - CHECK_SUCCESS(status); - - memcpy((*action_data_current_offset), &burst_credits_task_start, sizeof(burst_credits_task_start)); - *(action_data_current_offset) += sizeof(burst_credits_task_start); - - return HAILO_SUCCESS; -} - -hailo_status HEF_METADATA__edge_layer_activation_actions_position_marker( - CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **action_data_current_offset, - bool is_repeated) -{ - hailo_status status = HAILO_UNINITIALIZED; - CONTROL_PROTOCOL__EDGE_LAYER_ACTIVATION_ACTIONS_POSITION_MARKER_T marker{}; - - CHECK_ARG_NOT_NULL(action_data_current_offset); - CHECK_ARG_NOT_NULL(*action_data_current_offset); - - marker.header.action_type = CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_EDGE_LAYER_ACTIVATION_ACTIONS_POSITION; - marker.header.is_repeated = is_repeated; - - status = hef_metadata__update_slicing_info(context_info, - action_data_current_offset, - sizeof(marker), - true); - CHECK_SUCCESS(status); - - memcpy((*action_data_current_offset), &marker, sizeof(marker)); - *(action_data_current_offset) += sizeof(marker); - - return HAILO_SUCCESS; -} - -/* End of context switch info build functions */ - -} /* namespace hailort */ diff --git a/hailort/libhailort/src/context_switch/hef_metadata.hpp b/hailort/libhailort/src/context_switch/hef_metadata.hpp deleted file mode 100644 index 6a3b5de..0000000 --- a/hailort/libhailort/src/context_switch/hef_metadata.hpp +++ /dev/null @@ -1,474 +0,0 @@ -#ifndef __CONTEXT_SWITCH_HPP__ -#define __CONTEXT_SWITCH_HPP__ - -#include -#include "common/utils.hpp" -#include "control_protocol.h" -#include "control_protocol.hpp" -#include "vdma/channel_id.hpp" - -namespace hailort -{ - -/** - * Build context switch none trigger - * - */ -CONTROL_PROTOCOL__TRIGGER_t HEF_METADATA__build_none_trigger(); - -/** - * Build context switch input stream trigger - * - * @param[in] stream_index - input stream index - * - */ -CONTROL_PROTOCOL__TRIGGER_t HEF_METADATA__build_input_stream_trigger(uint8_t stream_index); - -/** - * Build context switch output stream trigger - * - * @param[in] stream_index - output stream index - * - */ -CONTROL_PROTOCOL__TRIGGER_t HEF_METADATA__build_output_stream_trigger(uint8_t stream_index); - -/** - * Build context switch lcu trigger - * - * @param[in] cluster_index - cluster index - * @param[in] lcu_index - lcu index - * - */ -CONTROL_PROTOCOL__TRIGGER_t HEF_METADATA__build_lcu_trigger(uint8_t cluster_index, uint8_t lcu_index); - -/** - * Build context switch nms trigger - * - * @param[in] aggregator_index - ppu aggregator index running the nms transformation - * @param[in] pred_cluster_ob_index - index of the preceding output buffer connected to the ppu - * @param[in] pred_cluster_ob_cluster_index - index of the preceding cluster whose output buffer - * is connected to the ppu - * @param[in] pred_cluster_ob_interface - the interface of the preceding output buffer - * @param[in] succ_prepost_ob_index - index of the succeeding output buffer connected to the ppu - * @param[in] succ_prepost_ob_interface - the interface of the succeeding output buffer - * - */ -CONTROL_PROTOCOL__TRIGGER_t HEF_METADATA__build_nms_trigger(uint8_t aggregator_index, - uint8_t pred_cluster_ob_index, uint8_t pred_cluster_ob_cluster_index, uint8_t pred_cluster_ob_interface, - uint8_t succ_prepost_ob_index, uint8_t succ_prepost_ob_interface); - -/** - * Build context switch dma idle trigger - * - * @param[in] stream_index - the dma checked as idle is connected to this stream - * - */ -CONTROL_PROTOCOL__TRIGGER_t HEF_METADATA__build_dma_idle_trigger(uint8_t stream_index); - -/** - * Build context switch trigger group header - * - * @param[in] context_info - struct holding all the context info - * @param[in/out] trigger_group_data_current_offset - pointer to the trigger group header - * @param[in] trigger - pointer to the trigger to be added (it's contents will be copied) - * - */ -hailo_status HEF_METADATA__add_trigger_to_trigger_group( - CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **trigger_group_data_current_offset, - const CONTROL_PROTOCOL__TRIGGER_t *trigger); - -/** - * Build read vdma action - * - * @param[in] context_info - struct holding all the context info - * @param[out] action - pointer to the action - * @param[in] descriptors_count - descriptors_count to fetch - * @param[in] config_stream_index - index of the cfg channel (not the vDMA channel number!) - * @param[in] is_repeated - 'true' if the action is part of a "repeated sequence" (a group of consecutive actions - * with the same type) - * - */ -hailo_status HEF_METADATA__add_read_vdma_action( - CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **action_data_current_offset, - uint16_t descriptors_count, - uint8_t config_stream_index, - bool is_repeated); - -/** - * Build add ccw bursts action - * - * @param[in] context_info - struct holding all the context info - * @param[out] action - pointer to the action - * @param[in] ccw_bursts - ccw bursts to fetch - * @param[in] config_stream_index - index of the cfg channel (not the vDMA channel number!) - * @param[in] is_repeated - 'true' if the action is part of a "repeated sequence" (a group of consecutive actions - * with the same type) - * - */ -hailo_status HEF_METADATA__add_ccw_bursts_action( - CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **action_data_current_offset, - uint16_t ccw_bursts, - uint8_t config_stream_index, - bool is_repeated); - -/** - * Build repeated (header) action - * - * @param[in] context_info - struct holding all the context info - * @param[out] action - pointer to the action - * @param[in] sub_action - sub action type - * @param[in] num_actions - number of actions in the repeated group - */ -hailo_status HEF_METADATA__add_repeated_header_action( - CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **action_data_current_offset, - CONTROL_PROTOCOL__ACTION_TYPE_t sub_action_type, - uint8_t num_actions -); - -/** - * Build wait for sequencer action - * - * @param[in] context_info - struct holding all the context info - * @param[out] action - pointer to the action - * @param[in] sequencer_index - sequencer index - * @param[in] is_repeated - 'true' if the action is part of a "repeated sequence" (a group of consecutive actions - * with the same type) - * - */ -hailo_status HEF_METADATA__add_wait_for_sequencer_action( - CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **action_data_current_offset, - uint8_t sequencer_index, - bool is_repeated); - -/** - * Build fetch new data action - * - * @param[in] context_info - struct holding all the context info - * @param[out] action - pointer to the action - * @param[in] shmifo_index - shmifo index - * @param[in] is_repeated - 'true' if the action is part of a "repeated sequence" (a group of consecutive actions - * with the same type) - * - */ -hailo_status HEF_METADATA__add_fetch_new_data_action( - CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **action_data_current_offset, - uint8_t shmifo_index, - bool is_repeated); - -/** - * Build context switch trigger sequencer action - * - * @param[in] context_info - struct holding all the context info - * @param[out] action - pointer to the action - * @param[in] cluster_index - cluster index - * @param[in] initial_l3_cut - initial l3 cut - * @param[in] initial_l3_offset - initial_l3_offset - * @param[in] active_apu - bit map of active APUs - * @param[in] active_ia - bit map of active input aligners - * @param[in] active_sc - bit map of active subclusters - * @param[in] active_l2 - bit map of active l2 cuts - * @param[in] l2_offset_0 - offsets of write start for each active L2 cut (for first 32 subclusters) - * @param[in] l2_offset_1 - offsets of write start for each active L2 cut (for last 32 subclusters) - * @param[in] is_repeated - 'true' if the action is part of a "repeated sequence" (a group of consecutive actions - * with the same type) - * - */ -hailo_status HEF_METADATA__add_enable_sequencer_action( - CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **action_data_current_offset, - uint8_t cluster_index, - uint8_t initial_l3_cut, - uint16_t initial_l3_offset, - uint32_t active_apu, - uint32_t active_ia, - uint64_t active_sc, - uint64_t active_l2, - uint64_t l2_offset_0, - uint64_t l2_offset_1, - bool is_repeated); - -/** - * build non default enable lcu action - * - * @param[in] context_info - struct holding all the context info - * @param[out] action - pointer to the action - * @param[in] cluster_index - cluster index - * @param[in] lcu_index - lcu_index - * @param[in] kernel_done_address - kernel done address - * @param[in] kernel_done_count - kernel done count - * @param[in] network_index - network index - * @param[in] batch_size - batch size - * @param[in] is_repeated - 'true' if the action is part of a "repeated sequence" (a group of consecutive actions - * with the same type) - * - */ -hailo_status HEF_METADATA__add_enable_lcu_non_default_action( - CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **action_data_current_offset, - uint8_t cluster_index, - uint8_t lcu_index, - uint16_t kernel_done_address, - uint32_t kernel_done_count, - uint8_t network_index, - bool is_repeated); - -/** - * build non default enable lcu action - * - * @param[in] context_info - struct holding all the context info - * @param[out] action - pointer to the action - * @param[in] cluster_index - cluster index - * @param[in] lcu_index - lcu_index - * @param[in] network_index - network index - * @param[in] is_repeated - 'true' if the action is part of a "repeated sequence" (a group of consecutive actions - * with the same type) - * - */ -hailo_status HEF_METADATA__add_enable_lcu_default_action( - CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **action_data_current_offset, - uint8_t cluster_index, - uint8_t lcu_index, - uint8_t network_index, - bool is_repeated); - -/** - * build disable lcu action - * - * @param[in] context_info - struct holding all the context info - * @param[out] action - pointer to the action - * @param[in] cluster_index - cluster index - * @param[in] lcu_index - lcu_index - * @param[in] is_repeated - 'true' if the action is part of a "repeated sequence" (a group of consecutive actions - * with the same type) - * - */ -hailo_status HEF_METADATA__add_disable_lcu_action( - CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **action_data_current_offset, - uint8_t cluster_index, - uint8_t lcu_index, - bool is_repeated); - -/** - * build wait for module config done - * - * @param[in] context_info - struct holding all the context info - * @param[out] action - pointer to the action - * @param[in] module_index - module index - * @param[in] is_repeated - 'true' if the action is part of a "repeated sequence" (a group of consecutive actions - * with the same type) - * - */ -hailo_status HEF_METADATA__add_wait_for_module_config_done_action( - CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **action_data_current_offset, - uint8_t module_index, - bool is_repeated); - -/** - * build edge layer - vdma network boundary - * - * @param[in] context_info - struct holding all the context info - * @param[out] edge_layer_current_offset - pointer to the location of the edge layer struct - * @param[in] channel_id - vdma channel id - * @param[in] stream_index - stream index - * @param[in] network_index - network index - * @param[in] nn_stream_config - * @param[in] host_buffer_info - info about host buffer - * - */ -hailo_status HEF_METADATA__add_network_boundary_output_edge_layer( - CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **edge_layer_current_offset, - vdma::ChannelId channel_id, - uint8_t stream_index, - uint8_t network_index, - const CONTROL_PROTOCOL__nn_stream_config_t &nn_stream_config, - const CONTROL_PROTOCOL__host_buffer_info_t &host_buffer_info); -/** - * build edge layer - vdma intermediate buffer output - * - * @param[in] context_info - struct holding all the context info - * @param[out] edge_layer_current_offset - pointer to the location of the edge layer struct - * @param[in] channel_id - vdma channel id - * @param[in] stream_index - stream index - * @param[in] network_index - network index - * @param[in] nn_stream_config - * @param[in] host_buffer_info - info about host buffer - */ -hailo_status HEF_METADATA__add_inter_context_output_edge_layer( - CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **edge_layer_current_offset, - vdma::ChannelId channel_id, - uint8_t stream_index, - uint8_t network_index, - const CONTROL_PROTOCOL__nn_stream_config_t &nn_stream_config, - const CONTROL_PROTOCOL__host_buffer_info_t &host_buffer_info); - -/** - * build edge layer - vdma DDR buffer output - * - * @param[in] context_info - struct holding all the context info - * @param[out] edge_layer_current_offset - pointer to the location of the edge layer struct - * @param[in] channel_id - vdma channel id - * @param[in] stream_index - stream index - * @param[in] network_index - network index - * @param[in] nn_stream_config - * @param[in] host_buffer_info - info about host buffer - * @param[in] buffered_rows_count - amount of rows to buffer. - * - */ -hailo_status HEF_METADATA__add_ddr_buffer_output_edge_layer( - CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **edge_layer_current_offset, - vdma::ChannelId channel_id, - uint8_t stream_index, - uint8_t network_index, - const CONTROL_PROTOCOL__nn_stream_config_t &nn_stream_config, - const CONTROL_PROTOCOL__host_buffer_info_t &host_buffer_info, - uint32_t buffered_rows_count); - -/** - * build edge layer - vdma network boundary input - * - * @param[in] context_info - struct holding all the context info - * @param[out] edge_layer_current_offset - pointer to the location of the edge layer struct - * @param[in] channel_id - vdma channel id - * @param[in] stream_index - stream index - * @param[in] network_index - network index - * @param[in] nn_stream_config - * @param[in] host_buffer_info - info about host buffer - * @param[in] initial_credit_size - initial credit size, if 0 is set the firmware takes its default value. - * - */ -hailo_status HEF_METADATA__add_network_boundary_input_edge_layer( - CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **edge_layer_current_offset, - vdma::ChannelId channel_id, - uint8_t stream_index, - uint8_t network_index, - const CONTROL_PROTOCOL__nn_stream_config_t &nn_stream_config, - const CONTROL_PROTOCOL__host_buffer_info_t &host_buffer_info, - uint32_t initial_credit_size); - -/** - * build edge layer - vdma intermediate buffer input - * - * @param[in] context_info - struct holding all the context info - * @param[out] edge_layer_current_offset - pointer to the location of the edge layer struct - * @param[in] channel_id - vdma channel id - * @param[in] stream_index - stream index - * @param[in] network_index - network index - * @param[in] nn_stream_config - * @param[in] host_buffer_info - info about host buffer - * @param[in] initial_credit_size - initial credit size, if 0 is set the firmware takes its default value. - * - */ -hailo_status HEF_METADATA__add_inter_context_input_edge_layer( - CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **edge_layer_current_offset, - vdma::ChannelId channel_id, - uint8_t stream_index, - uint8_t network_index, - const CONTROL_PROTOCOL__nn_stream_config_t &nn_stream_config, - const CONTROL_PROTOCOL__host_buffer_info_t &host_buffer_info, - uint32_t initial_credit_size); - -/** - * build edge layer - vdma ddr buffer input - * - * @param[in] context_info - struct holding all the context info - * @param[out] edge_layer_current_offset - pointer to the location of the edge layer struct - * @param[in] channel_id - vdma channel id - * @param[in] stream_index - stream index - * @param[in] network_index - network index - * @param[in] nn_stream_config - * @param[in] host_buffer_info - info about host buffer. - * @param[in] initial_credit_size - initial credit size, if 0 is set the firmware takes its default value. - * @param[in] connected_d2h_channel_id - vdma channel id of the connected d2h channel. - */ -hailo_status HEF_METADATA__add_ddr_buffer_input_edge_layer( - CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **edge_layer_current_offset, - vdma::ChannelId channel_id, - uint8_t stream_index, - uint8_t network_index, - const CONTROL_PROTOCOL__nn_stream_config_t &nn_stream_config, - const CONTROL_PROTOCOL__host_buffer_info_t &host_buffer_info, - uint32_t initial_credit_size, - vdma::ChannelId connected_d2h_channel_id); - -/** - * Build add ddr pair info action - * - * @param[in] context_info - struct holding all the context info - * @param[out] action_data_current_offset - pointer to the action - * @param[in] h2d_vdma_channel_id - DDR pair host to device channel ind - * @param[in] d2h_vdma_channel_id - DDR pair device to host channel id - * @param[in] descriptors_per_frame - expected total descritors transfered (per one frame) - * @param[in] programmed_descriptors_count - total size of the programed descriptors list - * @param[in] is_repeated - 'true' if the action is part of a "repeated sequence" (a group of consecutive actions - * with the same type) - * - */ -hailo_status HEF_METADATA__add_ddr_pair_info( - CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **action_data_current_offset, - const vdma::ChannelId h2d_vdma_channel_id, - const vdma::ChannelId d2h_vdma_channel_id, - const uint32_t descriptors_per_frame, - const uint16_t programmed_descriptors_count, - bool is_repeated); - -/** - * Build add ddr buffering start - * - * @param[in] context_info - struct holding all the context info - * @param[out] action_data_current_offset - pointer to the action - * @param[in] is_repeated - 'true' if the action is part of a "repeated sequence" (a group of consecutive actions - * with the same type) - * - */ -hailo_status HEF_METADATA__add_ddr_buffering_start( - CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **action_data_current_offset, - bool is_repeated); - -/** - * Build add burst credits task start - * - * @param[in] context_info - struct holding all the context info - * @param[out] action_data_current_offset - pointer to the action - * @param[in] is_repeated - 'true' if the action is part of a "repeated sequence" (a group of consecutive actions - * with the same type) - * - */ -hailo_status HEF_METADATA__burst_credits_task_start( - CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **action_data_current_offset, - bool is_repeated); - -/** - * Build edge layer activation actions position marker - * - * @param[in] context_info - struct holding all the context info - * @param[out] action_data_current_offset - pointer to the action - * @param[in] is_repeated - 'true' if the action is part of a "repeated sequence" (a group of consecutive actions - * with the same type) - * - */ -hailo_status HEF_METADATA__edge_layer_activation_actions_position_marker( - CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **action_data_current_offset, - bool is_repeated); - -} /* namespace hailort */ - -#endif /* __CONTEXT_SWITCH__ */ diff --git a/hailort/libhailort/src/context_switch/multi_context/resource_manager.hpp b/hailort/libhailort/src/context_switch/multi_context/resource_manager.hpp index a93e936..140592b 100644 --- a/hailort/libhailort/src/context_switch/multi_context/resource_manager.hpp +++ b/hailort/libhailort/src/context_switch/multi_context/resource_manager.hpp @@ -10,17 +10,17 @@ * * !-Working with physical device-! * VdmaDevice (either PcieDevice or CoreDevice) - * |-- VdmaConfigManager - * |--vector of VdmaConfigNetworkGroup - * |--ResourceManager - * |--reference to physical device + * |--vector of VdmaConfigNetworkGroup + * |--ResourceManager + * |--reference to physical device * * !-Working with virtual device-! * VDevice * |--vector of VdmaDevice (either PcieDevice or CoreDevice) - * |--vector of VdmaConfigNetworkGroup - * |-- vector of ResourceManager - * |--reference to physical device + * |--vector of VDeviceNetworkGroup + * |-- vector of VdmaConfigNetworkGroup + * |--ResourceManager + * |--reference to physical device **/ #ifndef _HAILO_CONTEXT_SWITCH_RESOURCE_MANAGER_HPP_ @@ -34,88 +34,117 @@ #include "control_protocol.hpp" #include "pcie_device.hpp" #include "channel_allocator.hpp" +#include "context_switch/context_switch_buffer_builder.hpp" namespace hailort { -class ResourcesManager final -{ -public: - static Expected create(VdmaDevice &vdma_device, HailoRTDriver &driver, - const ConfigureNetworkParams &config_params, const ProtoHEFNetworkGroup &network_group_proto, - std::shared_ptr network_group_metadata, const HefParsingInfo &parsing_info, - uint8_t net_group_index); +#define DEFAULT_ACTUAL_BATCH_SIZE (1) - ~ResourcesManager() = default; - ResourcesManager(const ResourcesManager &other) = delete; - ResourcesManager &operator=(const ResourcesManager &other) = delete; - ResourcesManager &operator=(ResourcesManager &&other) = delete; - ResourcesManager(ResourcesManager &&other) noexcept : - m_contexts(std::move(other.m_contexts)), - m_channel_allocator(std::move(other.m_channel_allocator)), - m_vdma_device(other.m_vdma_device), - m_driver(other.m_driver), m_config_params(other.m_config_params), - m_preliminary_config(std::move(other.m_preliminary_config)), - m_dynamic_config(std::move(other.m_dynamic_config)), - m_inter_context_buffers(std::move(other.m_inter_context_buffers)), - m_ddr_channels_pairs(std::move(other.m_ddr_channels_pairs)), - m_fw_managed_channels(std::move(other.m_fw_managed_channels)), - m_network_group_metadata(std::move(other.m_network_group_metadata)), m_net_group_index(other.m_net_group_index), - m_network_index_map(std::move(other.m_network_index_map)), - m_latency_meters(std::move(other.m_latency_meters)), - m_boundary_channels(std::move(other.m_boundary_channels)) {} - ExpectedRef create_inter_context_buffer(uint32_t transfer_size, uint8_t src_stream_index, - uint8_t src_context_index, const std::string &network_name); - ExpectedRef get_inter_context_buffer(const IntermediateBufferKey &key); - Expected> create_boundary_vdma_channel(const vdma::ChannelId &channel_id, - uint32_t transfer_size, const std::string &network_name, const std::string &stream_name, - VdmaChannel::Direction channel_direction); +struct BoundaryEdgeLayer { + LayerInfo layer_info; + vdma::ChannelId channel_id; + CONTROL_PROTOCOL__host_buffer_info_t buffer_info; +}; - ExpectedRef create_ddr_channels_pair(const DdrChannelsInfo &ddr_info, uint8_t context_index); - ExpectedRef get_ddr_channels_pair(uint8_t context_index, uint8_t d2h_stream_index); +struct InterContextEdgeLayer { + LayerInfo layer_info; + vdma::ChannelId channel_id; + CONTROL_PROTOCOL__host_buffer_info_t buffer_info; +}; - Expected get_control_network_group_header(); +struct DdrChannelEdgeLayer { + LayerInfo layer_info; + vdma::ChannelId channel_id; + CONTROL_PROTOCOL__host_buffer_info_t buffer_info; +}; - using context_info_t = CONTROL_PROTOCOL__context_switch_context_info_t; +class ContextResources final { +public: + static Expected create(HailoRTDriver &driver, CONTROL_PROTOCOL__context_switch_context_type_t context_type, + const std::vector &config_channels_ids, const ConfigBufferInfoMap &config_buffer_infos); - Expected> add_new_context() - { - return std::ref(*m_contexts.emplace(m_contexts.end())); - } + const std::vector &get_controls() const; + ContextSwitchBufferBuilder &builder(); - const std::vector& get_contexts() + void add_edge_layer(const BoundaryEdgeLayer &edge_layer) { - return m_contexts; + m_boundary_layers.emplace_back(std::move(edge_layer)); } - std::vector &preliminary_config() + void add_edge_layer(const InterContextEdgeLayer &edge_layer) { - return m_preliminary_config; + m_inter_context_layers.emplace_back(std::move(edge_layer)); } - std::vector &dynamic_config(uint8_t context_index) + void add_edge_layer(const DdrChannelEdgeLayer &edge_layer) { - assert(context_index < m_dynamic_config.size()); - return m_dynamic_config[context_index]; + m_ddr_channel_layers.emplace_back(std::move(edge_layer)); } - std::vector> get_ddr_channel_pairs_per_context(uint8_t context_index) const; + const std::vector &get_boundary_layers() const; + const std::vector &get_inter_context_layers() const; + const std::vector &get_ddr_channel_layers() const; - hailo_power_mode_t get_power_mode() - { - return m_config_params.power_mode; - } + ExpectedRef create_ddr_channels_pair(const DdrChannelsInfo &ddr_info); + ExpectedRef get_ddr_channels_pair(uint8_t d2h_stream_index) const; + const std::vector &get_ddr_channels_pairs() const; - const NetworkGroupSupportedFeatures &get_supported_features() const - { - return m_network_group_metadata->supported_features(); - } + // Gets edge layer for a specific direction + std::vector get_boundary_layers(hailo_stream_direction_t direction) const; + std::vector get_inter_context_layers(hailo_stream_direction_t direction) const; + std::vector get_ddr_channel_layers(hailo_stream_direction_t direction) const; + + hailo_status validate_edge_layers(); - uint8_t get_network_group_index() + std::vector &get_config_buffers(); + +private: + explicit ContextResources(HailoRTDriver &driver, CONTROL_PROTOCOL__context_switch_context_type_t context_type, + std::vector &&config_buffers) : + m_driver(std::ref(driver)), + m_builder(context_type), + m_config_buffers(std::move(config_buffers)) + {} + + std::reference_wrapper m_driver; + ContextSwitchBufferBuilder m_builder; + std::vector m_config_buffers; + std::vector m_ddr_channels_pairs; + + std::vector m_boundary_layers; + std::vector m_inter_context_layers; + std::vector m_ddr_channel_layers; +}; + +class ResourcesManager final +{ +public: + static Expected create(VdmaDevice &vdma_device, HailoRTDriver &driver, + const ConfigureNetworkParams &config_params, std::shared_ptr network_group_metadata, + uint8_t net_group_index); + + ~ResourcesManager() = default; + ResourcesManager(const ResourcesManager &other) = delete; + ResourcesManager &operator=(const ResourcesManager &other) = delete; + ResourcesManager &operator=(ResourcesManager &&other) = delete; + ResourcesManager(ResourcesManager &&other) noexcept; + + ExpectedRef create_inter_context_buffer(uint32_t transfer_size, uint8_t src_stream_index, + uint8_t src_context_index, const std::string &network_name); + ExpectedRef get_inter_context_buffer(const IntermediateBufferKey &key); + hailo_status create_boundary_vdma_channel(const LayerInfo &layer_info); + + Expected get_control_network_group_header(); + + Expected> add_new_context(CONTROL_PROTOCOL__context_switch_context_type_t type, + const ConfigBufferInfoMap &config_info={}); + + const SupportedFeatures &get_supported_features() const { - return m_net_group_index; + return m_network_group_metadata->supported_features(); } VdmaDevice &get_device() @@ -141,59 +170,50 @@ public: Expected read_intermediate_buffer(const IntermediateBufferKey &key); - void update_preliminary_config_buffer_info(); - void update_dynamic_contexts_buffer_info(); - - hailo_status create_fw_managed_vdma_channels(); + hailo_status create_internal_vdma_channels(); hailo_status register_fw_managed_vdma_channels(); hailo_status unregister_fw_managed_vdma_channels(); hailo_status set_inter_context_channels_dynamic_batch_size(uint16_t dynamic_batch_size); hailo_status open_ddr_channels(); void abort_ddr_channels(); void close_ddr_channels(); + hailo_status configure(); hailo_status enable_state_machine(uint16_t dynamic_batch_size); hailo_status reset_state_machine(bool keep_nn_config_during_reset = false); Expected get_network_batch_size(const std::string &network_name) const; Expected> get_boundary_vdma_channel_by_stream_name(const std::string &stream_name); + Expected> get_boundary_vdma_channel_by_stream_name(const std::string &stream_name) const; + hailo_power_mode_t get_power_mode() const; private: - void update_config_buffer_info(std::vector &config_buffers, - CONTROL_PROTOCOL__context_switch_context_info_t &context); hailo_status fill_infer_features(CONTROL_PROTOCOL__application_header_t &app_header); hailo_status fill_validation_features(CONTROL_PROTOCOL__application_header_t &app_header); hailo_status fill_network_batch_size(CONTROL_PROTOCOL__application_header_t &app_header); - static Expected get_cfg_channel_engine(HailoRTDriver &driver, uint8_t config_stream_index, - const ProtoHEFNetworkGroupMetadata &proto_metadata); - - std::vector m_contexts; + std::vector m_contexts_resources; ChannelAllocator m_channel_allocator; VdmaDevice &m_vdma_device; HailoRTDriver &m_driver; const ConfigureNetworkParams m_config_params; - std::vector m_preliminary_config; - // m_dynamic_config[context_index][config_index] - std::vector> m_dynamic_config; std::map m_inter_context_buffers; - std::map m_ddr_channels_pairs; - std::vector m_fw_managed_channels; + std::vector m_internal_channels; std::shared_ptr m_network_group_metadata; uint8_t m_net_group_index; + uint8_t m_dynamic_context_count; + uint8_t m_total_context_count; const std::vector m_network_index_map; LatencyMetersMap m_latency_meters; // Latency meter per network std::map> m_boundary_channels; //map of string name and connected vDMA channel + bool m_is_configured; + // Config channels ids are shared between all context. The following vector contains the channel id for each + // config_stream_index. + std::vector m_config_channels_ids; ResourcesManager(VdmaDevice &vdma_device, HailoRTDriver &driver, ChannelAllocator &&channel_allocator, const ConfigureNetworkParams config_params, - std::vector &&preliminary_config, std::vector> &&dynamic_config, std::shared_ptr &&network_group_metadata, uint8_t net_group_index, - const std::vector &&network_index_map, LatencyMetersMap &&latency_meters) : - m_channel_allocator(std::move(channel_allocator)), - m_vdma_device(vdma_device), m_driver(driver), m_config_params(config_params), - m_preliminary_config(std::move(preliminary_config)), m_dynamic_config(std::move(dynamic_config)), - m_network_group_metadata(std::move(network_group_metadata)), m_net_group_index(net_group_index), m_network_index_map(std::move(network_index_map)), - m_latency_meters(std::move(latency_meters)) {}; - + const std::vector &&network_index_map, LatencyMetersMap &&latency_meters, + std::vector &&config_channels_ids); }; } /* namespace hailort */ diff --git a/hailort/libhailort/src/context_switch/multi_context/vdma_config_activated_network_group.hpp b/hailort/libhailort/src/context_switch/multi_context/vdma_config_activated_network_group.hpp index 330d699..2c698e0 100644 --- a/hailort/libhailort/src/context_switch/multi_context/vdma_config_activated_network_group.hpp +++ b/hailort/libhailort/src/context_switch/multi_context/vdma_config_activated_network_group.hpp @@ -29,15 +29,16 @@ class VdmaConfigActivatedNetworkGroup : public ActivatedNetworkGroupBase public: static Expected create( - VdmaConfigActiveAppHolder &active_net_group_holder, + ActiveNetGroupHolder &active_net_group_holder, const std::string &network_group_name, - std::vector> resources_managers, + std::shared_ptr resources_manager, const hailo_activate_network_group_params_t &network_group_params, uint16_t dynamic_batch_size, - std::map> &input_streams, - std::map> &output_streams, + std::map> &input_streams, + std::map> &output_streams, EventPtr network_group_activated_event, - AccumulatorPtr deactivation_time_accumulator); + AccumulatorPtr deactivation_time_accumulator, + ConfiguredNetworkGroupBase &network_group); virtual ~VdmaConfigActivatedNetworkGroup(); @@ -55,28 +56,18 @@ private: const std::string &network_group_name, const hailo_activate_network_group_params_t &network_group_params, uint16_t dynamic_batch_size, - std::map> &input_streams, - std::map> &output_streams, - std::vector> &&resources_managers, - VdmaConfigActiveAppHolder &active_net_group_holder, + std::map> &input_streams, + std::map> &output_streams, + std::shared_ptr &&resources_manager, + ActiveNetGroupHolder &active_net_group_holder, EventPtr &&network_group_activated_event, - AccumulatorPtr deactivation_time_accumulator, hailo_status &status); - - hailo_status init_ddr_resources(); - hailo_status cleanup_ddr_resources(); - - static void ddr_recv_thread_main(DdrChannelsInfo ddr_info, - std::shared_ptr> desc_list_num_ready); - static void ddr_send_thread_main(DdrChannelsInfo ddr_info, - std::shared_ptr> desc_list_num_ready); + AccumulatorPtr deactivation_time_accumulator, + ConfiguredNetworkGroupBase &network_group, hailo_status &status); std::string m_network_group_name; bool m_should_reset_network_group; - VdmaConfigActiveAppHolder &m_active_net_group_holder; - // One ResourcesManager per connected physical device. Currently only one device is supported. - std::vector> m_resources_managers; - std::vector m_ddr_send_threads; - std::vector m_ddr_recv_threads; + ActiveNetGroupHolder &m_active_net_group_holder; + std::shared_ptr m_resources_manager; AccumulatorPtr m_deactivation_time_accumulator; bool m_keep_nn_config_during_reset; }; diff --git a/hailort/libhailort/src/context_switch/multi_context/vdma_config_manager.hpp b/hailort/libhailort/src/context_switch/multi_context/vdma_config_manager.hpp index 3b61762..f9fff52 100644 --- a/hailort/libhailort/src/context_switch/multi_context/vdma_config_manager.hpp +++ b/hailort/libhailort/src/context_switch/multi_context/vdma_config_manager.hpp @@ -11,58 +11,46 @@ #ifndef HAILO_VDMA_CONFIG_MANAGER_HPP_ #define HAILO_VDMA_CONFIG_MANAGER_HPP_ -#include "context_switch/config_manager.hpp" -#include "context_switch/network_group_wrapper.hpp" #include "context_switch/multi_context/vdma_config_network_group.hpp" #include "hailo/hailort.h" -#include "hailo/device.hpp" -#include "hailo/vdevice.hpp" -#include "hailo/expected.hpp" #include "common/utils.hpp" -#include "hlpcie.hpp" -#include "vdma_channel.hpp" -#include "network_group_scheduler.hpp" -#include -#include -#include -#include namespace hailort { -#define DISABLE_MULTIPLEXER_ENV_VAR "HAILO_DISABLE_MULTIPLEXER" - -class VDeviceBase; - -class VdmaConfigManager : public ConfigManager +class VdmaConfigManager final { public: - // Note: Each manager created on a device clears the network groups configured to that device - static Expected create(VdmaDevice &device); - static Expected create(VDeviceBase &vdevice); - virtual ConfigManagerType get_manager_type(); - virtual Expected add_hef(Hef &hef, const NetworkGroupsParamsMap &configure_params); - - static hailo_status update_network_batch_size(ConfigureNetworkParams &network_group_config_params); - - virtual ~VdmaConfigManager(); - VdmaConfigManager(const VdmaConfigManager &other) noexcept = delete; - VdmaConfigManager &operator=(const VdmaConfigManager &other) = delete; - VdmaConfigManager &operator=(VdmaConfigManager &&other) = delete; - VdmaConfigManager(VdmaConfigManager &&other) noexcept = default; - -private: - VdmaConfigManager(std::vector> &&devices, bool is_vdevice, - NetworkGroupSchedulerWeakPtr network_group_scheduler, hailo_status &status); - - // TODO: (SDK-16665) Dont need is_active flag for dtor? - std::vector> m_devices; - std::vector> m_net_groups; - std::vector> m_net_group_wrappers; - VdmaConfigActiveAppHolder m_active_net_group_holder; - bool m_is_vdevice; - NetworkGroupSchedulerWeakPtr m_network_group_scheduler; + VdmaConfigManager() = delete; + + static hailo_status switch_network_group(std::shared_ptr current_active_ng, + std::shared_ptr next_ng, const uint16_t batch_size) + { + auto status = HAILO_UNINITIALIZED; + // If current_active_ng is nullptr - we are activating first network group + if (nullptr != current_active_ng) { + status = current_active_ng->deactivate_impl(); + CHECK_SUCCESS(status, "Failed deactivating current network group"); + + // TODO: MSW-762 - In mercury we need to reset after deactivate in case of mercury - this will be fixed and the + // If will be removed when we make the nn_manager responsible to reset the nn-core + // And if switching to nullptr (which is final deactivate - we must also reset state machine) + if (Device::Type::CORE == current_active_ng->get_resources_manager()->get_device().get_type() || + (nullptr == next_ng)) { + status = current_active_ng->get_resources_manager()->reset_state_machine(false); + CHECK_SUCCESS(status, "Failed to reset state machine in switch network group"); + } + } + + // If next_ng is nullptr we are deactivating last network group + if (nullptr != next_ng) { + status = next_ng->activate_impl(batch_size); + CHECK_SUCCESS(status, "Failed activating network group"); + } + + return HAILO_SUCCESS; + } }; } /* namespace hailort */ diff --git a/hailort/libhailort/src/context_switch/multi_context/vdma_config_network_group.hpp b/hailort/libhailort/src/context_switch/multi_context/vdma_config_network_group.hpp index eda6d20..494a08f 100644 --- a/hailort/libhailort/src/context_switch/multi_context/vdma_config_network_group.hpp +++ b/hailort/libhailort/src/context_switch/multi_context/vdma_config_network_group.hpp @@ -13,16 +13,14 @@ #define _HAILO_CONTEXT_SWITCH_VDMA_CONFIG_NETWORK_GROUP_HPP_ #include "hailo/hailort.h" -#include "vdma_channel.hpp" #include "common/utils.hpp" -#include "context_switch/multi_context/vdma_config_activated_network_group.hpp" #include "control_protocol.h" -#include "context_switch/active_network_group_holder.hpp" #include "hailort_defaults.hpp" +#include "vdma_channel.hpp" #include "context_switch/network_group_internal.hpp" #include "context_switch/multi_context/resource_manager.hpp" -#include "network_group_scheduler.hpp" -#include "context_switch/pipeline_multiplexer.hpp" +#include "context_switch/multi_context/vdma_config_activated_network_group.hpp" +#include "context_switch/active_network_group_holder.hpp" #include #include @@ -32,33 +30,26 @@ namespace hailort { -#define MAX_CONTEXTS_COUNT (CONTROL_PROTOCOL__MAX_TOTAL_CONTEXTS) class VdmaConfigNetworkGroup : public ConfiguredNetworkGroupBase { public: - static Expected create(VdmaConfigActiveAppHolder &active_net_group_holder, + static Expected create(ActiveNetGroupHolder &active_net_group_holder, const ConfigureNetworkParams &config_params, - std::vector> resources_managers, const std::string &hef_hash, - std::shared_ptr network_group_metadata, NetworkGroupSchedulerWeakPtr network_group_scheduler); + std::shared_ptr resources_managers, const std::string &hef_hash, + std::shared_ptr network_group_metadata, + std::vector> &&net_flow_ops); - std::vector> &get_resources_managers() + std::shared_ptr &get_resources_manager() { - return m_resources_managers; + return m_resources_manager; } - hailo_status create_vdevice_streams_from_config_params(std::shared_ptr multiplexer, - scheduler_ng_handle_t scheduler_handle); - hailo_status create_input_vdevice_stream_from_config_params( - const hailo_stream_parameters_t &stream_params, const std::string &stream_name, - std::shared_ptr multiplexer, scheduler_ng_handle_t scheduler_handle); - hailo_status create_output_vdevice_stream_from_config_params( - const hailo_stream_parameters_t &stream_params, const std::string &stream_name, - std::shared_ptr multiplexer, scheduler_ng_handle_t scheduler_handle); - - hailo_status create_vdevice_streams_from_duplicate(std::shared_ptr other); + // Functions to activate and deactivate network group for scheduler - dont create ActivatedNetworkGroup objects + virtual hailo_status activate_impl(uint16_t dynamic_batch_size) override; + virtual hailo_status deactivate_impl() override; - virtual Expected> activate_impl( + virtual Expected> create_activated_network_group( const hailo_activate_network_group_params_t &network_group_params, uint16_t dynamic_batch_size) override; virtual Expected get_default_streams_interface() override; @@ -67,8 +58,6 @@ public: virtual Expected> get_boundary_vdma_channel_by_stream_name( const std::string &stream_name) override; - void set_network_group_handle(scheduler_ng_handle_t handle); - scheduler_ng_handle_t network_group_handle() const; virtual hailo_status set_scheduler_timeout(const std::chrono::milliseconds &timeout, const std::string &network_name) override; virtual hailo_status set_scheduler_threshold(uint32_t threshold, const std::string &network_name) override; @@ -78,36 +67,26 @@ public: VdmaConfigNetworkGroup &operator=(VdmaConfigNetworkGroup &&other) = delete; VdmaConfigNetworkGroup(VdmaConfigNetworkGroup &&other) noexcept : ConfiguredNetworkGroupBase(std::move(other)), m_active_net_group_holder(other.m_active_net_group_holder), - m_resources_managers(std::move(other.m_resources_managers)), m_network_group_scheduler(std::move(other.m_network_group_scheduler)), - m_scheduler_handle(std::move(other.m_scheduler_handle)), m_multiplexer_handle(std::move(other.m_multiplexer_handle)), - m_multiplexer(std::move(other.m_multiplexer)), m_hef_hash(std::move(other.m_hef_hash)) + m_resources_manager(std::move(other.m_resources_manager)), + m_hef_hash(std::move(other.m_hef_hash)) {} bool equals(const Hef &hef, const std::string &network_group_name) { return (network_group_name == name()) && (hef.hash() == m_hef_hash); } - uint32_t multiplexer_duplicates_count() - { - assert(m_multiplexer->instances_count() > 0); - return static_cast(m_multiplexer->instances_count() - 1); - } - - virtual Expected> create_output_vstreams(const std::map &outputs_params) override; - private: - VdmaConfigNetworkGroup(VdmaConfigActiveAppHolder &active_net_group_holder, - const ConfigureNetworkParams &config_params, - std::vector> &&resources_managers, const std::string &hef_hash, - const NetworkGroupMetadata &network_group_metadata, NetworkGroupSchedulerWeakPtr network_group_scheduler, hailo_status &status); - - VdmaConfigActiveAppHolder &m_active_net_group_holder; - std::vector> m_resources_managers; - NetworkGroupSchedulerWeakPtr m_network_group_scheduler; - scheduler_ng_handle_t m_scheduler_handle; - multiplexer_ng_handle_t m_multiplexer_handle; - std::shared_ptr m_multiplexer; + VdmaConfigNetworkGroup(ActiveNetGroupHolder &active_net_group_holder, + const ConfigureNetworkParams &config_params, + std::shared_ptr &&resources_manager, const std::string &hef_hash, + const NetworkGroupMetadata &network_group_metadata, hailo_status &status, + std::vector> &&net_flow_ops); + + ActiveNetGroupHolder &m_active_net_group_holder; + std::shared_ptr m_resources_manager; std::string m_hef_hash; + + friend class VDeviceNetworkGroupWrapper; }; } /* namespace hailort */ diff --git a/hailort/libhailort/src/context_switch/network_group.cpp b/hailort/libhailort/src/context_switch/network_group.cpp index 6de284d..53f94c5 100644 --- a/hailort/libhailort/src/context_switch/network_group.cpp +++ b/hailort/libhailort/src/context_switch/network_group.cpp @@ -20,51 +20,25 @@ #include "control.hpp" #include "common/runtime_statistics_internal.hpp" #include "vstream_internal.hpp" +#include "context_switch/multi_context/resource_manager.hpp" namespace hailort { ActivatedNetworkGroupBase::ActivatedNetworkGroupBase(const hailo_activate_network_group_params_t &network_group_params, - uint16_t dynamic_batch_size, - std::map> &input_streams, - std::map> &output_streams, + std::map> &input_streams, + std::map> &output_streams, EventPtr &&network_group_activated_event, hailo_status &status) : m_network_group_params(network_group_params), + m_network_group_activated_event(std::move(network_group_activated_event)), m_input_streams(input_streams), - m_output_streams(output_streams), - m_network_group_activated_event(std::move(network_group_activated_event)) + m_output_streams(output_streams) { status = validate_network_group_params(network_group_params); if (HAILO_SUCCESS != status) { LOGGER__ERROR("Failed to validate network_group params"); return; } - - status = activate_low_level_streams(dynamic_batch_size); - if (HAILO_SUCCESS != status) { - LOGGER__ERROR("Failed to activate low level streams"); - return; - } - - status = m_network_group_activated_event->signal(); - if (HAILO_SUCCESS != status) { - LOGGER__ERROR("Failed to signal network activation event"); - return; - } -} - -hailo_status ActivatedNetworkGroupBase::activate_low_level_streams(uint16_t dynamic_batch_size) -{ - for (auto &name_pair : m_input_streams) { - auto status = name_pair.second->activate_stream(dynamic_batch_size); - CHECK_SUCCESS(status); - } - for (auto &name_pair : m_output_streams) { - auto status = name_pair.second->activate_stream(dynamic_batch_size); - CHECK_SUCCESS(status); - } - - return HAILO_SUCCESS; } uint32_t ActivatedNetworkGroupBase::get_invalid_frames_count() @@ -76,27 +50,6 @@ uint32_t ActivatedNetworkGroupBase::get_invalid_frames_count() return total_invalid_frames_count; } -void ActivatedNetworkGroupBase::deactivate_resources() -{ - if (nullptr != m_network_group_activated_event) { - for (auto &name_pair : m_input_streams) { - auto status = name_pair.second->deactivate_stream(); - if (HAILO_SUCCESS != status) { - LOGGER__ERROR("Failed to deactivate input stream name {}", name_pair.first); - } - } - - for (auto &name_pair : m_output_streams) { - auto status = name_pair.second->deactivate_stream(); - if (HAILO_SUCCESS != status) { - LOGGER__ERROR("Failed to deactivate output stream name {}", name_pair.first); - } - } - m_network_group_activated_event->reset(); - } - -} - // TODO: Implement function (HRT-3174) hailo_status ActivatedNetworkGroupBase::validate_network_group_params( const hailo_activate_network_group_params_t &/*network_group_params*/) @@ -113,9 +66,7 @@ Expected> ConfiguredNetworkGroup::activat Expected> ConfiguredNetworkGroupBase::activate( const hailo_activate_network_group_params_t &network_group_params) { - CHECK_AS_EXPECTED(!m_is_scheduling, HAILO_INVALID_OPERATION, - "Manually activating a network group is not allowed when the network group scheduler is active!"); - return activate_internal(network_group_params, CONTROL_PROTOCOL__IGNORE_DYNAMIC_BATCH_SIZE); + return create_activated_network_group(network_group_params, CONTROL_PROTOCOL__IGNORE_DYNAMIC_BATCH_SIZE); } Expected get_latency(LatencyMeterPtr &latency_meter, bool clear) @@ -180,15 +131,14 @@ Expected ConfiguredNetworkGroupBase::get_output_st CHECK_EXPECTED(stream_names); for (auto &stream_name : stream_names.value()) { - auto output_stream = get_output_stream_by_name(stream_name); - CHECK_EXPECTED(output_stream); - - if (output_stream->get().get_info().is_mux) { + CHECK_AS_EXPECTED(contains(m_output_streams, stream_name), HAILO_NOT_FOUND); + auto output_stream = m_output_streams.at(stream_name); + if (output_stream->get_info().is_mux) { outputs_edges_params.emplace(name_params_pair); } else { NameToVStreamParamsMap name_to_params = {name_params_pair}; - results.emplace_back(output_stream.release(), name_to_params); + results.emplace_back(output_stream, name_to_params); } } } @@ -218,7 +168,7 @@ hailo_status ConfiguredNetworkGroupBase::add_mux_streams_by_edges_names(OutputSt auto output_stream = output_streams.release()[0]; // TODO: Find a better way to get the mux edges without creating OutputDemuxer - auto expected_demuxer = OutputDemuxer::create(output_stream.get()); + auto expected_demuxer = OutputDemuxer::create(*output_stream); CHECK_EXPECTED_AS_STATUS(expected_demuxer); NameToVStreamParamsMap name_to_params; @@ -235,18 +185,16 @@ hailo_status ConfiguredNetworkGroupBase::add_mux_streams_by_edges_names(OutputSt return HAILO_SUCCESS; } -Expected ConfiguredNetworkGroupBase::get_output_streams_by_vstream_name(const std::string &name) +Expected ConfiguredNetworkGroupBase::get_output_streams_by_vstream_name(const std::string &name) { auto stream_names = m_network_group_metadata.get_stream_names_from_vstream_name(name); CHECK_EXPECTED(stream_names); - OutputStreamRefVector output_streams; + OutputStreamPtrVector output_streams; output_streams.reserve(stream_names->size()); for (const auto &stream_name : stream_names.value()) { - auto output_stream = get_output_stream_by_name(stream_name); - CHECK_EXPECTED(output_stream); - - output_streams.emplace_back(output_stream.release()); + CHECK_AS_EXPECTED(contains(m_output_streams, stream_name), HAILO_NOT_FOUND); + output_streams.emplace_back(m_output_streams.at(stream_name)); } return output_streams; @@ -254,9 +202,7 @@ Expected ConfiguredNetworkGroupBase::get_output_streams_b Expected ConfiguredNetworkGroupBase::get_layer_info(const std::string &stream_name) { - auto layer_infos = m_network_group_metadata.get_all_layer_infos(); - CHECK_EXPECTED(layer_infos); - for (auto layer_info : layer_infos.release()) { + for (auto layer_info : m_network_group_metadata.get_all_layer_infos()) { if (layer_info.name == stream_name) { return layer_info; } @@ -266,21 +212,15 @@ Expected ConfiguredNetworkGroupBase::get_layer_info(const std::string } ConfiguredNetworkGroupBase::ConfiguredNetworkGroupBase( - const ConfigureNetworkParams &config_params, const uint8_t net_group_index, - const NetworkGroupMetadata &network_group_metadata, hailo_status &status) : - ConfiguredNetworkGroupBase(config_params, net_group_index, network_group_metadata, false, status) -{} - -ConfiguredNetworkGroupBase::ConfiguredNetworkGroupBase( - const ConfigureNetworkParams &config_params, const uint8_t net_group_index, - const NetworkGroupMetadata &network_group_metadata, bool is_scheduling, hailo_status &status) : + const ConfigureNetworkParams &config_params, const NetworkGroupMetadata &network_group_metadata, + std::vector> &&net_flow_ops, + hailo_status &status) : m_config_params(config_params), m_min_configured_batch_size(get_smallest_configured_batch_size(config_params)), - m_net_group_index(net_group_index), m_network_group_metadata(network_group_metadata), m_activation_time_accumulator(), m_deactivation_time_accumulator(), - m_is_scheduling(is_scheduling) + m_net_flow_ops(std::move(net_flow_ops)) { auto event = Event::create_shared(Event::State::not_signalled); if (nullptr == event) { @@ -316,22 +256,23 @@ uint16_t ConfiguredNetworkGroupBase::get_smallest_configured_batch_size(const Co // using dynamic_batch_sizes, all networks will use the same dynamic_batch_size (until HRT-6535 is done). // Hence, we must not set a dynamic_batch_size to a value greater than the smallest configured network // batch_size (e.g. all the resources allocated are for at most the configured network batch_size). - return std::min_element(config_params.network_params_by_name.begin(), config_params.network_params_by_name.end(), - [](const auto& lhs, const auto& rhs) { return lhs.second.batch_size < rhs.second.batch_size; })->second.batch_size; -} -Expected> ConfiguredNetworkGroupBase::activate_internal( - const hailo_activate_network_group_params_t &network_group_params, uint16_t dynamic_batch_size) -{ - CHECK_AS_EXPECTED(dynamic_batch_size <= m_min_configured_batch_size, HAILO_INVALID_ARGUMENT, - "Dynamic batch size ({}) must be less than/equal to the smallest configured batch size ({})", - dynamic_batch_size, m_min_configured_batch_size); - return activate_impl(network_group_params, dynamic_batch_size); + /* We iterate over all network's batch_sizes to get the non-default min. + Ignoring HAILO_DEFAULT_BATCH_SIZE as it is not a real batch-value, + but indicating the scheduler should optimize batches by himself */ + uint16_t min_batch_size = UINT16_MAX; + for (const auto &network_params_pair : config_params.network_params_by_name) { + if ((HAILO_DEFAULT_BATCH_SIZE != network_params_pair.second.batch_size) && + (network_params_pair.second.batch_size < min_batch_size)) { + min_batch_size = network_params_pair.second.batch_size; + } + } + return (UINT16_MAX == min_batch_size) ? DEFAULT_ACTUAL_BATCH_SIZE : min_batch_size; } -Expected> ConfiguredNetworkGroupBase::force_activate(uint16_t dynamic_batch_size) +Expected> ConfiguredNetworkGroupBase::activate_with_batch(uint16_t dynamic_batch_size) { - return activate_internal(HailoRTDefaults::get_network_group_params(), dynamic_batch_size); + return create_activated_network_group(HailoRTDefaults::get_network_group_params(), dynamic_batch_size); } const std::string &ConfiguredNetworkGroupBase::get_network_group_name() const @@ -344,11 +285,46 @@ const std::string &ConfiguredNetworkGroupBase::name() const return m_network_group_metadata.network_group_name(); } +hailo_status ConfiguredNetworkGroupBase::activate_low_level_streams(uint16_t dynamic_batch_size) +{ + for (auto &name_pair : m_input_streams) { + auto status = name_pair.second->activate_stream(dynamic_batch_size); + CHECK_SUCCESS(status); + } + for (auto &name_pair : m_output_streams) { + auto status = name_pair.second->activate_stream(dynamic_batch_size); + CHECK_SUCCESS(status); + } + + return HAILO_SUCCESS; +} + +hailo_status ConfiguredNetworkGroupBase::deactivate_low_level_streams() +{ + // Best effort + auto status = HAILO_SUCCESS; + auto deactivate_status = HAILO_UNINITIALIZED; + for (auto &name_pair : m_input_streams) { + deactivate_status = name_pair.second->deactivate_stream(); + if (HAILO_SUCCESS != deactivate_status) { + LOGGER__ERROR("Failed to deactivate input stream {}", name_pair.first); + status = deactivate_status; + } + } + for (auto &name_pair : m_output_streams) { + deactivate_status = name_pair.second->deactivate_stream(); + if (HAILO_SUCCESS != deactivate_status) { + LOGGER__ERROR("Failed to deactivate output stream {}", name_pair.first); + status = deactivate_status; + } + } + + return status; +} + Expected ConfiguredNetworkGroupBase::get_stream_batch_size(const std::string &stream_name) { - auto layer_infos = m_network_group_metadata.get_all_layer_infos(); - CHECK_EXPECTED(layer_infos); - for (const auto &layer_info : layer_infos.release()) { + for (const auto &layer_info : m_network_group_metadata.get_all_layer_infos()) { if (layer_info.name == stream_name) { for (auto const &network_params_pair : m_config_params.network_params_by_name) { if (network_params_pair.first == layer_info.network_name) { @@ -618,8 +594,6 @@ std::vector> ConfiguredNetworkGroupBase::ge hailo_status ConfiguredNetworkGroupBase::wait_for_activation(const std::chrono::milliseconds &timeout) { - CHECK(!m_is_scheduling, HAILO_INVALID_OPERATION, - "Waiting for network group activation is not allowed when the network group scheduler is active!"); return m_network_group_activated_event->wait(timeout); } @@ -680,7 +654,6 @@ Expected> ConfiguredNetworkGroupBa { auto output_vstream_infos = m_network_group_metadata.get_output_vstream_infos(network_name); CHECK_EXPECTED(output_vstream_infos); - std::map res; auto status = Hef::Impl::fill_missing_vstream_params_with_default(res, output_vstream_infos.value(), quantized, format_type, timeout_ms, queue_size); @@ -755,15 +728,15 @@ Expected> ConfiguredNetworkGroupBase::create_input_vst std::vector vstreams; vstreams.reserve(inputs_params.size()); for (const auto &name_params_pair : inputs_params) { - auto input_stream_ref = get_input_stream_by_name(name_params_pair.first); - CHECK_EXPECTED(input_stream_ref); + CHECK_AS_EXPECTED(contains(m_input_streams, name_params_pair.first), HAILO_NOT_FOUND); + auto input_stream = m_input_streams.at(name_params_pair.first); const auto vstream_info = input_vstream_infos_map.find(name_params_pair.first); CHECK_AS_EXPECTED(vstream_info != input_vstream_infos_map.end(), HAILO_NOT_FOUND, "Failed to find vstream info of {}", name_params_pair.first); - const auto vstream_params = expand_vstream_params_autos(input_stream_ref->get().get_info(), name_params_pair.second); - auto inputs = VStreamsBuilderUtils::create_inputs(input_stream_ref->get(), vstream_info->second, vstream_params); + const auto vstream_params = expand_vstream_params_autos(input_stream->get_info(), name_params_pair.second); + auto inputs = VStreamsBuilderUtils::create_inputs(input_stream, vstream_info->second, vstream_params); CHECK_EXPECTED(inputs); vstreams.insert(vstreams.end(), std::make_move_iterator(inputs->begin()), std::make_move_iterator(inputs->end())); @@ -784,17 +757,37 @@ Expected> ConfiguredNetworkGroupBase::create_output_v // We iterate through all output streams, and if they are nms, we collect them together by their original stream name. // We need this step because all nms output streams of the same original stream need to be fused together - std::map> nms_output_streams; - for (auto &stream_params_pair: output_streams.value()) { - auto &out_stream = stream_params_pair.first.get(); - if ((HAILO_FORMAT_ORDER_HAILO_NMS == out_stream.get_info().format.order && out_stream.get_info().nms_info.is_defused) && - (outputs_params.end() != outputs_params.find(out_stream.get_info().nms_info.defuse_info.original_name))) { - auto original_name = stream_params_pair.first.get().get_info().nms_info.defuse_info.original_name; - nms_output_streams.emplace(original_name, std::pair( - OutputStreamRefVector(), outputs_params.at(original_name))); - nms_output_streams[original_name].first.push_back(stream_params_pair.first.get()); + + std::unordered_map> post_process_nms_ops; + std::set post_process_stream_inputs; + for (auto &op : m_net_flow_ops) { + CHECK_AS_EXPECTED(op->type == NetFlowElement::Type::YoloNmsOp, HAILO_INVALID_ARGUMENT, + "Unexpected operation: {}", op->name); + post_process_nms_ops.insert({op->name, op}); + post_process_stream_inputs.insert(op->input_streams.begin(), op->input_streams.end()); + } + std::map> nms_op_output_streams; + std::map> nms_output_streams; + for (auto &stream_params_pair : output_streams.value()) { + if ((HAILO_FORMAT_ORDER_HAILO_NMS == stream_params_pair.first->get_info().format.order && stream_params_pair.first->get_info().nms_info.is_defused) && + (outputs_params.end() != outputs_params.find(stream_params_pair.first->get_info().nms_info.defuse_info.original_name))) { + auto original_name = stream_params_pair.first->get_info().nms_info.defuse_info.original_name; + nms_output_streams.emplace(original_name, std::pair( + OutputStreamPtrVector(), outputs_params.at(original_name))); + nms_output_streams[original_name].first.push_back(stream_params_pair.first); + } else if (post_process_stream_inputs.count(stream_params_pair.first->get_info().name)) { + for (auto &op : m_net_flow_ops) { + if (op->input_streams.count(stream_params_pair.first->get_info().name)) { + CHECK_AS_EXPECTED(op->type == NetFlowElement::Type::YoloNmsOp, + HAILO_INVALID_ARGUMENT, "Expected post-process YOLO-NMS operation"); + assert(op->output_pads.size() == 1); + nms_op_output_streams.emplace(op->name, std::pair( + OutputStreamPtrVector(), outputs_params.at(op->output_pads[0].name))); + nms_op_output_streams[op->name].first.push_back(stream_params_pair.first); + } + } } else { - auto outputs = VStreamsBuilderUtils::create_outputs(stream_params_pair.first.get(), stream_params_pair.second, output_vstream_infos_map); + auto outputs = VStreamsBuilderUtils::create_outputs(stream_params_pair.first, stream_params_pair.second, output_vstream_infos_map); CHECK_EXPECTED(outputs); vstreams.insert(vstreams.end(), std::make_move_iterator(outputs->begin()), std::make_move_iterator(outputs->end())); } @@ -805,6 +798,16 @@ Expected> ConfiguredNetworkGroupBase::create_output_v CHECK_EXPECTED(outputs); vstreams.insert(vstreams.end(), std::make_move_iterator(outputs->begin()), std::make_move_iterator(outputs->end())); } + for (auto &nms_output_stream_pair : nms_op_output_streams) { + auto op = post_process_nms_ops.at(nms_output_stream_pair.first); + assert(op->type == NetFlowElement::Type::YoloNmsOp); + auto nms_op = std::static_pointer_cast(op); + auto outputs = VStreamsBuilderUtils::create_output_post_process_nms(nms_output_stream_pair.second.first, + nms_output_stream_pair.second.second, output_vstream_infos_map, + *nms_op); + CHECK_EXPECTED(outputs); + vstreams.insert(vstreams.end(), std::make_move_iterator(outputs->begin()), std::make_move_iterator(outputs->end())); + } return vstreams; } diff --git a/hailort/libhailort/src/context_switch/network_group_internal.hpp b/hailort/libhailort/src/context_switch/network_group_internal.hpp index 9e26cab..cd2233f 100644 --- a/hailort/libhailort/src/context_switch/network_group_internal.hpp +++ b/hailort/libhailort/src/context_switch/network_group_internal.hpp @@ -11,17 +11,22 @@ * -------------------------------------------------------------------------------------------------------------- * | ConfiguredNetworkGroup | (External "interface") * | ________________________________|________________________________ | - * | / | \ | - * | ConfiguredNetworkGroupBase ConfiguredNetworkGroupWrapper ConfiguredNetworkGroupClient | (Base classes) - * | / \ | - * | VdmaConfigNetworkGroup HcpConfigNetworkGroup | (Actual implementations) + * | / \ | + * | ConfiguredNetworkGroupBase ConfiguredNetworkGroupClient | (Base classes) + * | / | \ | + * | VdmaConfigNetworkGroup | HcpConfigNetworkGroup | (Actual implementations) + * | VDeviceNetworkGroup | + * | | | + * | vector of VdmaConfigNetworkGroup | * -------------------------------------------------------------------------------------------------------------| * | ActivatedNetworkGroup | (External "interface") * | | | * | ActivatedNetworkGroupBase | (Base classes) - * | __________________|__________________ | - * | / \ | - * | VdmaConfigActivatedNetworkGroup HcpConfigActivatedNetworkGroup | (Actual implementations) + * | __________________|_____________________________________________________ | + * | / | \ | + * | VdmaConfigActivatedNetworkGroup VDeviceActivatedNetworkGroup HcpConfigActivatedNetworkGroup | (Actual implementations) + * | | | + * | vector of VdmaConfigActivatedNetworkGroup | * -------------------------------------------------------------------------------------------------------------- **/ @@ -34,6 +39,7 @@ #include "common/latency_meter.hpp" #include "control_protocol.h" #include "vdma_channel.hpp" +#include "context_switch/active_network_group_holder.hpp" #ifdef HAILO_SUPPORT_MULTI_PROCESS #include "hailort_rpc_client.hpp" @@ -42,6 +48,12 @@ namespace hailort { +/** Represents a vector of InputStream ptrs */ +using InputStreamPtrVector = std::vector>; + +/** Represents a vector of OutputStream ptrs */ +using OutputStreamPtrVector = std::vector>; + class ActivatedNetworkGroupBase : public ActivatedNetworkGroup { public: @@ -52,25 +64,21 @@ public: ActivatedNetworkGroupBase(ActivatedNetworkGroupBase &&other) = default; virtual uint32_t get_invalid_frames_count() override; - // Must be called on d'tor of derived class - void deactivate_resources(); protected: hailo_activate_network_group_params_t m_network_group_params; ActivatedNetworkGroupBase(const hailo_activate_network_group_params_t &network_group_params, - uint16_t dynamic_batch_size, - std::map> &input_streams, - std::map> &output_streams, + std::map> &input_streams, + std::map> &output_streams, EventPtr &&network_group_activated_event, hailo_status &status); + EventPtr m_network_group_activated_event; + std::map> &m_input_streams; + std::map> &m_output_streams; + private: - hailo_status activate_low_level_streams(uint16_t dynamic_batch_size); hailo_status validate_network_group_params(const hailo_activate_network_group_params_t &network_group_params); - - std::map> &m_input_streams; - std::map> &m_output_streams; - EventPtr m_network_group_activated_event; }; class ConfiguredNetworkGroupBase : public ConfiguredNetworkGroup @@ -82,7 +90,7 @@ public: ConfiguredNetworkGroupBase &operator=(ConfiguredNetworkGroupBase &&other) = delete; ConfiguredNetworkGroupBase(ConfiguredNetworkGroupBase &&other) = default; - Expected> force_activate( + Expected> activate_with_batch( uint16_t dynamic_batch_size = CONTROL_PROTOCOL__IGNORE_DYNAMIC_BATCH_SIZE); virtual Expected> activate(const hailo_activate_network_group_params_t &network_group_params) override; virtual hailo_status wait_for_activation(const std::chrono::milliseconds &timeout) override; @@ -114,6 +122,9 @@ public: virtual Expected>> get_output_vstream_groups() override; + virtual hailo_status activate_impl(uint16_t dynamic_batch_size) = 0; + virtual hailo_status deactivate_impl() = 0; + virtual Expected> get_network_infos() const override; virtual Expected> get_all_stream_infos(const std::string &network_name="") const override; virtual Expected> get_input_vstream_infos(const std::string &network_name="") const override; @@ -134,7 +145,7 @@ public: return m_network_group_metadata.get_vstream_names_from_stream_name(stream_name); } - const NetworkGroupSupportedFeatures &get_supported_features() + const SupportedFeatures &get_supported_features() { return m_network_group_metadata.supported_features(); } @@ -144,15 +155,14 @@ public: virtual Expected> create_input_vstreams(const std::map &inputs_params); virtual Expected> create_output_vstreams(const std::map &outputs_params); + std::map> m_input_streams; + std::map> m_output_streams; + protected: - ConfiguredNetworkGroupBase(const ConfigureNetworkParams &config_params, const uint8_t m_net_group_index, - const NetworkGroupMetadata &network_group_metadata, hailo_status &status); - ConfiguredNetworkGroupBase(const ConfigureNetworkParams &config_params, const uint8_t m_net_group_index, - const NetworkGroupMetadata &network_group_metadata, bool is_scheduling, hailo_status &status); - - virtual Expected> activate_internal( - const hailo_activate_network_group_params_t &network_group_params, uint16_t dynamic_batch_size) override; - virtual Expected> activate_impl( + ConfiguredNetworkGroupBase(const ConfigureNetworkParams &config_params, + const NetworkGroupMetadata &network_group_metadata, std::vector> &&net_flow_ops, hailo_status &status); + + virtual Expected> create_activated_network_group( const hailo_activate_network_group_params_t &network_group_params, uint16_t dynamic_batch_size) = 0; hailo_status create_output_stream_from_config_params(Device &device, @@ -161,7 +171,10 @@ protected: const hailo_stream_parameters_t &stream_params, const std::string &stream_name); hailo_status add_mux_streams_by_edges_names(OutputStreamWithParamsVector &result, const std::unordered_map &outputs_edges_params); - Expected get_output_streams_by_vstream_name(const std::string &name); + Expected get_output_streams_by_vstream_name(const std::string &name); + + hailo_status activate_low_level_streams(uint16_t dynamic_batch_size); + hailo_status deactivate_low_level_streams(); Expected get_layer_info(const std::string &stream_name); @@ -170,22 +183,21 @@ protected: const ConfigureNetworkParams m_config_params; const uint16_t m_min_configured_batch_size; // TODO: remove after HRT-6535 - uint8_t m_net_group_index; - std::map> m_input_streams; - std::map> m_output_streams; EventPtr m_network_group_activated_event; const NetworkGroupMetadata m_network_group_metadata; AccumulatorPtr m_activation_time_accumulator; AccumulatorPtr m_deactivation_time_accumulator; private: - friend class ConfiguredNetworkGroupWrapper; + friend class VDeviceNetworkGroup; static uint16_t get_smallest_configured_batch_size(const ConfigureNetworkParams &config_params); - bool m_is_scheduling; + std::vector> m_net_flow_ops; }; +using ActiveNetGroupHolder = ActiveNetworkGroupHolder; + #ifdef HAILO_SUPPORT_MULTI_PROCESS class ConfiguredNetworkGroupClient : public ConfiguredNetworkGroup { @@ -244,10 +256,6 @@ public: virtual Expected> create_input_vstreams(const std::map &inputs_params); virtual Expected> create_output_vstreams(const std::map &outputs_params); -protected: - virtual Expected> activate_internal( - const hailo_activate_network_group_params_t &network_group_params, uint16_t dynamic_batch_size) override; - private: std::unique_ptr m_client; uint32_t m_handle; diff --git a/hailort/libhailort/src/context_switch/network_group_wrapper.cpp b/hailort/libhailort/src/context_switch/network_group_wrapper.cpp deleted file mode 100644 index 77dbfb9..0000000 --- a/hailort/libhailort/src/context_switch/network_group_wrapper.cpp +++ /dev/null @@ -1,204 +0,0 @@ -/** - * Copyright (c) 2022 Hailo Technologies Ltd. All rights reserved. - * Distributed under the MIT license (https://opensource.org/licenses/MIT) - **/ -/** - * @file network_group_wrapper.cpp - * @brief: Network Group Wrapper - **/ - -#include "network_group_wrapper.hpp" - -namespace hailort -{ - -const std::string &ConfiguredNetworkGroupWrapper::get_network_group_name() const -{ - return m_configured_network_group->get_network_group_name(); -} - -const std::string &ConfiguredNetworkGroupWrapper::name() const -{ - return m_configured_network_group->name(); -} - -Expected ConfiguredNetworkGroupWrapper::get_default_streams_interface() -{ - return m_configured_network_group->get_default_streams_interface(); -} - -std::vector> ConfiguredNetworkGroupWrapper::get_input_streams_by_interface(hailo_stream_interface_t stream_interface) -{ - return m_configured_network_group->get_input_streams_by_interface(stream_interface); -} - -std::vector> ConfiguredNetworkGroupWrapper::get_output_streams_by_interface(hailo_stream_interface_t stream_interface) -{ - return m_configured_network_group->get_output_streams_by_interface(stream_interface); -} - -ExpectedRef ConfiguredNetworkGroupWrapper::get_input_stream_by_name(const std::string& name) -{ - return m_configured_network_group->get_input_stream_by_name(name); -} -ExpectedRef ConfiguredNetworkGroupWrapper::get_output_stream_by_name(const std::string& name) -{ - return m_configured_network_group->get_output_stream_by_name(name); -} - -Expected ConfiguredNetworkGroupWrapper::get_input_streams_by_network(const std::string &network_name) -{ - return m_configured_network_group->get_input_streams_by_network(network_name); -} - -Expected ConfiguredNetworkGroupWrapper::get_output_streams_by_network(const std::string &network_name) -{ - return m_configured_network_group->get_output_streams_by_network(network_name); -} - -InputStreamRefVector ConfiguredNetworkGroupWrapper::get_input_streams() -{ - return m_configured_network_group->get_input_streams(); -} - -OutputStreamRefVector ConfiguredNetworkGroupWrapper::get_output_streams() -{ - return m_configured_network_group->get_output_streams(); -} - -Expected ConfiguredNetworkGroupWrapper::get_latency_measurement(const std::string &network_name) -{ - return m_configured_network_group->get_latency_measurement(network_name); -} - -Expected ConfiguredNetworkGroupWrapper::get_output_streams_from_vstream_names( - const std::map &outputs_params) -{ - return m_configured_network_group->get_output_streams_from_vstream_names(outputs_params); -} - -Expected> ConfiguredNetworkGroupWrapper::activate_internal(const hailo_activate_network_group_params_t &network_group_params, uint16_t dynamic_batch_size) -{ - return m_configured_network_group->activate_internal(network_group_params, dynamic_batch_size); -} - -hailo_status ConfiguredNetworkGroupWrapper::wait_for_activation(const std::chrono::milliseconds &timeout) -{ - return m_configured_network_group->wait_for_activation(timeout); -} - -Expected> ConfiguredNetworkGroupWrapper::make_input_vstream_params( - bool quantized, hailo_format_type_t format_type, uint32_t timeout_ms, uint32_t queue_size, - const std::string &network_name) -{ - return m_configured_network_group->make_input_vstream_params(quantized, format_type, timeout_ms, queue_size, network_name); -} -Expected> ConfiguredNetworkGroupWrapper::make_output_vstream_params( - bool quantized, hailo_format_type_t format_type, uint32_t timeout_ms, uint32_t queue_size, - const std::string &network_name) -{ - return m_configured_network_group->make_output_vstream_params(quantized, format_type, timeout_ms, queue_size, network_name); -} - -Expected>> ConfiguredNetworkGroupWrapper::make_output_vstream_params_groups( - bool quantized, hailo_format_type_t format_type, uint32_t timeout_ms, uint32_t queue_size) -{ - return m_configured_network_group->make_output_vstream_params_groups(quantized, format_type, timeout_ms, queue_size); -} - -Expected>> ConfiguredNetworkGroupWrapper::get_output_vstream_groups() -{ - return m_configured_network_group->get_output_vstream_groups(); -} - -Expected> ConfiguredNetworkGroupWrapper::get_network_infos() const -{ - return m_configured_network_group->get_network_infos(); -} - -Expected> ConfiguredNetworkGroupWrapper::get_all_stream_infos(const std::string &network_name) const -{ - return m_configured_network_group->get_all_stream_infos(network_name); -} - -Expected> ConfiguredNetworkGroupWrapper::get_input_vstream_infos(const std::string &network_name) const -{ - return m_configured_network_group->get_input_vstream_infos(network_name); -} - -Expected> ConfiguredNetworkGroupWrapper::get_output_vstream_infos(const std::string &network_name) const -{ - return m_configured_network_group->get_output_vstream_infos(network_name); -} - -Expected> ConfiguredNetworkGroupWrapper::get_all_vstream_infos(const std::string &network_name) const -{ - return m_configured_network_group->get_all_vstream_infos(network_name); -} - -hailo_status ConfiguredNetworkGroupWrapper::set_scheduler_timeout(const std::chrono::milliseconds &timeout, const std::string &network_name) -{ - return m_configured_network_group->set_scheduler_timeout(timeout, network_name); -} -hailo_status ConfiguredNetworkGroupWrapper::set_scheduler_threshold(uint32_t threshold, const std::string &network_name) -{ - return m_configured_network_group->set_scheduler_threshold(threshold, network_name); -} - -AccumulatorPtr ConfiguredNetworkGroupWrapper::get_activation_time_accumulator() const -{ - return m_configured_network_group->get_activation_time_accumulator(); -} - -AccumulatorPtr ConfiguredNetworkGroupWrapper::get_deactivation_time_accumulator() const -{ - return m_configured_network_group->get_deactivation_time_accumulator(); -} - -bool ConfiguredNetworkGroupWrapper::is_multi_context() const -{ - return m_configured_network_group->is_multi_context(); -} -const ConfigureNetworkParams ConfiguredNetworkGroupWrapper::get_config_params() const -{ - return m_configured_network_group->get_config_params(); -} - -std::shared_ptr ConfiguredNetworkGroupWrapper::get_configured_network() const -{ - return m_configured_network_group; -} - -ConfiguredNetworkGroupWrapper::ConfiguredNetworkGroupWrapper(std::shared_ptr configured_network_group) : - m_configured_network_group(configured_network_group) -{} - -Expected ConfiguredNetworkGroupWrapper::create(std::shared_ptr configured_network_group) -{ - return ConfiguredNetworkGroupWrapper(configured_network_group); -} - -Expected ConfiguredNetworkGroupWrapper::clone() -{ - auto wrapper = create(m_configured_network_group); - CHECK_EXPECTED(wrapper); - - return wrapper; -} - -Expected> ConfiguredNetworkGroupWrapper::activate(const hailo_activate_network_group_params_t &network_group_params) -{ - return m_configured_network_group->activate(network_group_params); -} - -Expected> ConfiguredNetworkGroupWrapper::create_input_vstreams(const std::map &inputs_params) -{ - return m_configured_network_group->create_input_vstreams(inputs_params); -} - -Expected> ConfiguredNetworkGroupWrapper::create_output_vstreams(const std::map &outputs_params) -{ - return m_configured_network_group->create_output_vstreams(outputs_params); -} - -} /* namespace hailort */ diff --git a/hailort/libhailort/src/context_switch/network_group_wrapper.hpp b/hailort/libhailort/src/context_switch/network_group_wrapper.hpp deleted file mode 100644 index 9c352c8..0000000 --- a/hailort/libhailort/src/context_switch/network_group_wrapper.hpp +++ /dev/null @@ -1,94 +0,0 @@ -/** - * Copyright (c) 2022 Hailo Technologies Ltd. All rights reserved. - * Distributed under the MIT license (https://opensource.org/licenses/MIT) - **/ -/** - * @file network_group_wrapper.hpp - * @brief Class declaration for ConfiguredNetworkGroupWrapper, a wrapper around ConfiguredNetworkGroupBase which is used - * to support multiple ConfiguredNetworkGroup objects that encapsulate the same actual configured network group. - **/ - -#ifndef _HAILO_NETWORK_GROUP_WRAPPER_HPP_ -#define _HAILO_NETWORK_GROUP_WRAPPER_HPP_ - -#include "hailo/hailort.h" -#include "hailo/network_group.hpp" -#include "hailo/vstream.hpp" -#include "network_group_internal.hpp" - -namespace hailort -{ - -class ConfiguredNetworkGroupWrapper : public ConfiguredNetworkGroup -{ -public: - virtual ~ConfiguredNetworkGroupWrapper() = default; - ConfiguredNetworkGroupWrapper(const ConfiguredNetworkGroupWrapper &other) = delete; - ConfiguredNetworkGroupWrapper &operator=(const ConfiguredNetworkGroupWrapper &other) = delete; - ConfiguredNetworkGroupWrapper &operator=(ConfiguredNetworkGroupWrapper &&other) = delete; - ConfiguredNetworkGroupWrapper(ConfiguredNetworkGroupWrapper &&other) = default; - - static Expected create(std::shared_ptr configured_network_group); - Expected clone(); - - virtual const std::string &get_network_group_name() const override; - virtual const std::string &name() const override; - virtual Expected get_default_streams_interface() override; - - virtual std::vector> get_input_streams_by_interface(hailo_stream_interface_t stream_interface) override; - virtual std::vector> get_output_streams_by_interface(hailo_stream_interface_t stream_interface) override; - virtual ExpectedRef get_input_stream_by_name(const std::string& name) override; - virtual ExpectedRef get_output_stream_by_name(const std::string& name) override; - virtual Expected get_input_streams_by_network(const std::string &network_name="") override; - virtual Expected get_output_streams_by_network(const std::string &network_name="") override; - virtual InputStreamRefVector get_input_streams() override; - virtual OutputStreamRefVector get_output_streams() override; - virtual Expected get_latency_measurement(const std::string &network_name="") override; - virtual Expected get_output_streams_from_vstream_names( - const std::map &outputs_params) override; - - virtual Expected> activate(const hailo_activate_network_group_params_t &network_group_params) override; - virtual hailo_status wait_for_activation(const std::chrono::milliseconds &timeout) override; - - virtual Expected> make_input_vstream_params( - bool quantized, hailo_format_type_t format_type, uint32_t timeout_ms, uint32_t queue_size, - const std::string &network_name="") override; - virtual Expected> make_output_vstream_params( - bool quantized, hailo_format_type_t format_type, uint32_t timeout_ms, uint32_t queue_size, - const std::string &network_name="") override; - virtual Expected>> make_output_vstream_params_groups( - bool quantized, hailo_format_type_t format_type, uint32_t timeout_ms, uint32_t queue_size) override; - virtual Expected>> get_output_vstream_groups() override; - - virtual Expected> get_network_infos() const override; - virtual Expected> get_all_stream_infos(const std::string &network_name="") const override; - virtual Expected> get_input_vstream_infos(const std::string &network_name="") const override; - virtual Expected> get_output_vstream_infos(const std::string &network_name="") const override; - virtual Expected> get_all_vstream_infos(const std::string &network_name="") const override; - - virtual hailo_status set_scheduler_timeout(const std::chrono::milliseconds &timeout, const std::string &network_name) override; - virtual hailo_status set_scheduler_threshold(uint32_t threshold, const std::string &network_name) override; - - virtual AccumulatorPtr get_activation_time_accumulator() const override; - virtual AccumulatorPtr get_deactivation_time_accumulator() const override; - virtual bool is_multi_context() const override; - virtual const ConfigureNetworkParams get_config_params() const override; - - std::shared_ptr get_configured_network() const; - - virtual Expected> create_input_vstreams(const std::map &inputs_params); - virtual Expected> create_output_vstreams(const std::map &outputs_params); - -protected: - virtual Expected> activate_internal( - const hailo_activate_network_group_params_t &network_group_params, uint16_t dynamic_batch_size) override; - -private: - ConfiguredNetworkGroupWrapper(std::shared_ptr configured_network_group); - - std::shared_ptr m_configured_network_group; -}; - -} - -#endif /* _HAILO_NETWORK_GROUP_WRAPPER_HPP_ */ \ No newline at end of file diff --git a/hailort/libhailort/src/context_switch/resource_manager.cpp b/hailort/libhailort/src/context_switch/resource_manager.cpp index 1e4cd53..7345772 100644 --- a/hailort/libhailort/src/context_switch/resource_manager.cpp +++ b/hailort/libhailort/src/context_switch/resource_manager.cpp @@ -6,33 +6,145 @@ namespace hailort { -static Expected> build_network_index_map(const ProtoHEFNetworkGroup &network_group_proto, - const NetworkGroupSupportedFeatures &supported_features) -{ - std::vector network_names_vector; - if (supported_features.multi_network_support) { - auto network_count = network_group_proto.networks_names_size(); - CHECK_AS_EXPECTED((network_count > 0), HAILO_INTERNAL_FAILURE, - "Hef support multiple networks, but no networks found in the proto"); - network_names_vector.reserve(network_count); - for (uint8_t network_index = 0; network_index < network_count; network_index++) { - auto partial_network_name = network_group_proto.networks_names(network_index); - auto network_name = HefUtils::get_network_name(network_group_proto, partial_network_name); - network_names_vector.push_back(network_name); + +Expected ContextResources::create(HailoRTDriver &driver, + CONTROL_PROTOCOL__context_switch_context_type_t context_type, const std::vector &config_channels_ids, + const ConfigBufferInfoMap &config_buffer_infos) +{ + CHECK_AS_EXPECTED(context_type < CONTROL_PROTOCOL__CONTEXT_SWITCH_CONTEXT_TYPE_COUNT, HAILO_INVALID_ARGUMENT); + + CHECK_AS_EXPECTED(config_buffer_infos.size() <= config_channels_ids.size(), HAILO_INTERNAL_FAILURE, + "config_buffer_infos size ({}) is bigger than config_channels_id count ({})", + config_buffer_infos.size(), config_channels_ids.size()); + + std::vector config_buffers; + config_buffers.reserve(config_buffer_infos.size()); + for (uint8_t config_stream_index = 0; config_stream_index < config_buffer_infos.size(); config_stream_index++) { + auto buffer_resource = ConfigBuffer::create(driver, config_channels_ids[config_stream_index], + config_buffer_infos.at(config_stream_index)); + CHECK_EXPECTED(buffer_resource); + config_buffers.emplace_back(buffer_resource.release()); + } + + return ContextResources(driver, context_type, std::move(config_buffers)); +} + +const std::vector &ContextResources::get_controls() const +{ + return m_builder.get_controls(); +} + +ContextSwitchBufferBuilder &ContextResources::builder() +{ + return m_builder; +} + +const std::vector &ContextResources::get_boundary_layers() const +{ + return m_boundary_layers; +} + +const std::vector &ContextResources::get_inter_context_layers() const +{ + return m_inter_context_layers; +} + +const std::vector &ContextResources::get_ddr_channel_layers() const +{ + return m_ddr_channel_layers; +} + +ExpectedRef ContextResources::create_ddr_channels_pair(const DdrChannelsInfo &ddr_info) +{ + auto buffer = DdrChannelsPair::create(m_driver, ddr_info); + CHECK_EXPECTED(buffer); + + m_ddr_channels_pairs.emplace_back(buffer.release()); + return std::ref(m_ddr_channels_pairs.back()); +} + +ExpectedRef ContextResources::get_ddr_channels_pair(uint8_t d2h_stream_index) const +{ + for (auto &ddr_channels_pair : m_ddr_channels_pairs) { + if (ddr_channels_pair.info().d2h_stream_index == d2h_stream_index) { + return std::ref(ddr_channels_pair); } - } else { - /* In case there is no defines networks, add single network with the same name as the network group */ - network_names_vector.reserve(1); - auto net_group_name = network_group_proto.network_group_metadata().network_group_name(); - network_names_vector.push_back(HailoRTDefaults::get_network_name(net_group_name)); } - return network_names_vector; + LOGGER__ERROR("Couldn't find ddr channels pair for {}", d2h_stream_index); + return make_unexpected(HAILO_INTERNAL_FAILURE); +} + +const std::vector &ContextResources::get_ddr_channels_pairs() const +{ + return m_ddr_channels_pairs; +} + +std::vector ContextResources::get_boundary_layers(hailo_stream_direction_t direction) const +{ + std::vector edge_layers; + for (const auto &edge_layer : m_boundary_layers) { + if (edge_layer.layer_info.direction == direction) { + edge_layers.push_back(edge_layer); + } + } + return edge_layers; +} + +std::vector ContextResources::get_inter_context_layers(hailo_stream_direction_t direction) const +{ + std::vector edge_layers; + for (const auto &edge_layer : m_inter_context_layers) { + if (edge_layer.layer_info.direction == direction) { + edge_layers.push_back(edge_layer); + } + } + return edge_layers; +} + +std::vector ContextResources::get_ddr_channel_layers(hailo_stream_direction_t direction) const +{ + std::vector edge_layers; + for (const auto &edge_layer : m_ddr_channel_layers) { + if (edge_layer.layer_info.direction == direction) { + edge_layers.push_back(edge_layer); + } + } + return edge_layers; +} + +hailo_status ContextResources::validate_edge_layers() +{ + std::set used_channel_ids; + for (const auto &edge_layer : get_boundary_layers()) { + CHECK(used_channel_ids.find(edge_layer.channel_id) == used_channel_ids.end(), HAILO_INTERNAL_FAILURE, + "Same stream use the same channel id {}", edge_layer.channel_id); + used_channel_ids.insert(edge_layer.channel_id); + } + + for (const auto &edge_layer : get_inter_context_layers()) { + CHECK(used_channel_ids.find(edge_layer.channel_id) == used_channel_ids.end(), HAILO_INTERNAL_FAILURE, + "Same stream use the same channel id {}", edge_layer.channel_id); + used_channel_ids.insert(edge_layer.channel_id); + } + + for (const auto &edge_layer : get_ddr_channel_layers()) { + CHECK(used_channel_ids.find(edge_layer.channel_id) == used_channel_ids.end(), HAILO_INTERNAL_FAILURE, + "Same stream use the same channel id {}", edge_layer.channel_id); + used_channel_ids.insert(edge_layer.channel_id); + } + + return HAILO_SUCCESS; +} + +std::vector &ContextResources::get_config_buffers() +{ + return m_config_buffers; } static Expected create_hw_latency_meter(const std::vector &layers) { - std::set d2h_channel_indexes; + std::set d2h_channel_names; size_t h2d_streams_count = 0; for (const auto &layer : layers) { @@ -42,7 +154,7 @@ static Expected create_hw_latency_meter(const std::vector create_hw_latency_meter(const std::vector(d2h_channel_indexes, MAX_IRQ_TIMESTAMPS_SIZE); + return make_shared_nothrow(d2h_channel_names, MAX_IRQ_TIMESTAMPS_SIZE); } static Expected create_latency_meters_from_config_params( @@ -80,85 +192,77 @@ static Expected create_latency_meters_from_config_params( } Expected ResourcesManager::create(VdmaDevice &vdma_device, HailoRTDriver &driver, - const ConfigureNetworkParams &config_params, const ProtoHEFNetworkGroup &network_group_proto, - std::shared_ptr network_group_metadata, const HefParsingInfo &parsing_info, + const ConfigureNetworkParams &config_params, std::shared_ptr network_group_metadata, uint8_t net_group_index) { - const auto &proto_metadata = network_group_proto.network_group_metadata(); - - // Backwards compatibility for HEFs without this field - CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(proto_metadata.cfg_channels_count()), - HAILO_INVALID_HEF, "Invalid cfg channels count"); - uint8_t cfg_channels_count = (0 == proto_metadata.cfg_channels_count()) ? - 1u : static_cast(proto_metadata.cfg_channels_count()); - // Allocate config channels. In order to use the same channel ids for config channels in all contexts, // we allocate all of them here, and use in preliminary/dynamic context. ChannelAllocator allocator(driver.dma_engines_count()); - std::vector cfg_channel_ids; - cfg_channel_ids.reserve(cfg_channels_count); - for (uint8_t cfg_index = 0; cfg_index < cfg_channels_count; cfg_index++) { - const auto cfg_layer_identifier = std::make_tuple(LayerType::CFG, "", cfg_index); - const auto engine_index = get_cfg_channel_engine(driver, cfg_index, proto_metadata); - CHECK_EXPECTED(engine_index); - auto channel_id = allocator.get_available_channel_id(cfg_layer_identifier, VdmaChannel::Direction::H2D, - engine_index.value()); + std::vector config_channels_ids; + const auto &config_channels_info = network_group_metadata->config_channels_info(); + config_channels_ids.reserve(config_channels_info.size()); + for (uint8_t cfg_index = 0; cfg_index < config_channels_info.size(); cfg_index++) { + const auto layer_identifier = std::make_tuple(LayerType::CFG, "", cfg_index); + const auto engine_index = config_channels_info[cfg_index].engine_index; + auto channel_id = allocator.get_available_channel_id(layer_identifier, VdmaChannel::Direction::H2D, engine_index); CHECK_EXPECTED(channel_id); - cfg_channel_ids.push_back(channel_id.release()); - } - - std::vector preliminary_configs_vector; - auto cfg_count_preliminary = parsing_info.cfg_infos_preliminary_config.size(); - CHECK_AS_EXPECTED(cfg_channels_count >= cfg_count_preliminary, HAILO_INTERNAL_FAILURE, - "preliminary cfg count ({}) is bigger than the size passed to the network_group ({})", - cfg_count_preliminary, cfg_channels_count); - preliminary_configs_vector.reserve(cfg_count_preliminary); - for (uint8_t cfg_index = MIN_H2D_CHANNEL_INDEX; cfg_index < cfg_count_preliminary; cfg_index++) { - CHECK_AS_EXPECTED(contains(parsing_info.cfg_infos_preliminary_config, cfg_index), HAILO_INTERNAL_FAILURE, - "Mismatch for cfg index {}", cfg_index); - auto buffer_resource = ConfigBuffer::create(driver, cfg_channel_ids[cfg_index], - parsing_info.cfg_infos_preliminary_config.at(cfg_index)); - CHECK_EXPECTED(buffer_resource); - - preliminary_configs_vector.emplace_back(buffer_resource.release()); - } - - std::vector> dynamic_cfg_vectors; - dynamic_cfg_vectors.reserve(network_group_proto.contexts_size()); - - for (int ctxt_index = 0; ctxt_index < network_group_proto.contexts_size(); ctxt_index++) { - std::vector dynamic_cfg_vector_per_context; - auto cfg_count_ctxt = parsing_info.cfg_infos_per_context[ctxt_index].size(); - - CHECK_AS_EXPECTED(cfg_channels_count >= cfg_count_ctxt, HAILO_INTERNAL_FAILURE, - "dynamic context cfg count ({}) (context {}) is bigger than the size passed to the network_group ({})", - cfg_count_ctxt, ctxt_index, cfg_channels_count); - - dynamic_cfg_vector_per_context.reserve(cfg_count_ctxt); - for (uint8_t cfg_index = MIN_H2D_CHANNEL_INDEX; cfg_index < cfg_count_ctxt; cfg_index++) { - CHECK_AS_EXPECTED(contains(parsing_info.cfg_infos_per_context[ctxt_index], cfg_index), - HAILO_INTERNAL_FAILURE, "Mismatch for cfg index {}", cfg_index); - auto buffer_resource = ConfigBuffer::create(driver, cfg_channel_ids[cfg_index], - parsing_info.cfg_infos_per_context[ctxt_index].at(cfg_index)); - CHECK_EXPECTED(buffer_resource); - - dynamic_cfg_vector_per_context.emplace_back(buffer_resource.release()); - } - dynamic_cfg_vectors.emplace_back(std::move(dynamic_cfg_vector_per_context)); + config_channels_ids.push_back(channel_id.release()); } - auto network_index_map = build_network_index_map(network_group_proto, network_group_metadata->supported_features()); - CHECK_EXPECTED(network_index_map); + auto network_index_map = network_group_metadata->get_network_names(); auto latency_meters = create_latency_meters_from_config_params(config_params, network_group_metadata); CHECK_EXPECTED(latency_meters); ResourcesManager resources_manager(vdma_device, driver, std::move(allocator), config_params, - std::move(preliminary_configs_vector), std::move(dynamic_cfg_vectors), std::move(network_group_metadata), net_group_index, - std::move(network_index_map.release()), latency_meters.release()); + std::move(network_group_metadata), net_group_index, + std::move(network_index_map), latency_meters.release(), std::move(config_channels_ids)); return resources_manager; } +ResourcesManager::ResourcesManager(VdmaDevice &vdma_device, HailoRTDriver &driver, + ChannelAllocator &&channel_allocator, const ConfigureNetworkParams config_params, + std::shared_ptr &&network_group_metadata, + uint8_t net_group_index, const std::vector &&network_index_map, + LatencyMetersMap &&latency_meters, + std::vector &&config_channels_ids) : + m_contexts_resources(), + m_channel_allocator(std::move(channel_allocator)), + m_vdma_device(vdma_device), + m_driver(driver), + m_config_params(config_params), + m_inter_context_buffers(), + m_internal_channels(), + m_network_group_metadata(std::move(network_group_metadata)), + m_net_group_index(net_group_index), + m_dynamic_context_count(0), + m_total_context_count(0), + m_network_index_map(std::move(network_index_map)), + m_latency_meters(std::move(latency_meters)), + m_boundary_channels(), + m_is_configured(false), + m_config_channels_ids(std::move(config_channels_ids)) +{} + +ResourcesManager::ResourcesManager(ResourcesManager &&other) noexcept : + m_contexts_resources(std::move(other.m_contexts_resources)), + m_channel_allocator(std::move(other.m_channel_allocator)), + m_vdma_device(other.m_vdma_device), + m_driver(other.m_driver), + m_config_params(other.m_config_params), + m_inter_context_buffers(std::move(other.m_inter_context_buffers)), + m_internal_channels(std::move(other.m_internal_channels)), + m_network_group_metadata(std::move(other.m_network_group_metadata)), + m_net_group_index(other.m_net_group_index), + m_dynamic_context_count(std::exchange(other.m_dynamic_context_count, static_cast(0))), + m_total_context_count(std::exchange(other.m_total_context_count, static_cast(0))), + m_network_index_map(std::move(other.m_network_index_map)), + m_latency_meters(std::move(other.m_latency_meters)), + m_boundary_channels(std::move(other.m_boundary_channels)), + m_is_configured(std::exchange(other.m_is_configured, false)), + m_config_channels_ids(std::move(other.m_config_channels_ids)) +{} + hailo_status ResourcesManager::fill_infer_features(CONTROL_PROTOCOL__application_header_t &app_header) { app_header.infer_features.preliminary_run_asap = m_network_group_metadata->supported_features().preliminary_run_asap; @@ -203,60 +307,63 @@ hailo_status ResourcesManager::fill_network_batch_size(CONTROL_PROTOCOL__applica return HAILO_SUCCESS; } -hailo_status ResourcesManager::create_fw_managed_vdma_channels() +hailo_status ResourcesManager::create_internal_vdma_channels() { - auto fw_managed_channel_ids = m_channel_allocator.get_fw_managed_channel_ids(); + auto internal_channel_ids = m_channel_allocator.get_internal_channel_ids(); - m_fw_managed_channels.reserve(fw_managed_channel_ids.size()); - for (const auto &ch : fw_managed_channel_ids) { + m_internal_channels.reserve(internal_channel_ids.size()); + for (const auto &ch : internal_channel_ids) { auto direction = (ch.channel_index < MIN_D2H_CHANNEL_INDEX) ? VdmaChannel::Direction::H2D : VdmaChannel::Direction::D2H; auto vdma_channel = VdmaChannel::create(ch, direction, m_driver, m_vdma_device.get_default_desc_page_size()); CHECK_EXPECTED_AS_STATUS(vdma_channel); - m_fw_managed_channels.emplace_back(vdma_channel.release()); + m_internal_channels.emplace_back(vdma_channel.release()); } return HAILO_SUCCESS; } -Expected> ResourcesManager::create_boundary_vdma_channel( - const vdma::ChannelId &channel_id, uint32_t transfer_size, const std::string &network_name, - const std::string &stream_name, VdmaChannel::Direction channel_direction) +hailo_status ResourcesManager::create_boundary_vdma_channel(const LayerInfo &layer_info) { - auto network_batch_size = get_network_batch_size(network_name); - CHECK_EXPECTED(network_batch_size); + // TODO: put in layer info + const auto channel_direction = layer_info.direction == HAILO_H2D_STREAM ? VdmaChannel::Direction::H2D : + VdmaChannel::Direction::D2H; + const auto channel_id = get_available_channel_id(to_layer_identifier(layer_info), + channel_direction, layer_info.dma_engine_index); + CHECK_EXPECTED_AS_STATUS(channel_id); + + auto network_batch_size = get_network_batch_size(layer_info.network_name); + CHECK_EXPECTED_AS_STATUS(network_batch_size); + uint32_t min_active_trans = MIN_ACTIVE_TRANSFERS_SCALE * network_batch_size.value(); uint32_t max_active_trans = MAX_ACTIVE_TRANSFERS_SCALE * network_batch_size.value(); - CHECK_AS_EXPECTED(IS_FIT_IN_UINT16(min_active_trans), HAILO_INVALID_ARGUMENT, + CHECK(IS_FIT_IN_UINT16(min_active_trans), HAILO_INVALID_ARGUMENT, "calculated min_active_trans for vdma descriptor list is out of UINT16 range"); - - CHECK_AS_EXPECTED(IS_FIT_IN_UINT16(max_active_trans), HAILO_INVALID_ARGUMENT, + CHECK(IS_FIT_IN_UINT16(max_active_trans), HAILO_INVALID_ARGUMENT, "calculated min_active_trans for vdma descriptor list is out of UINT16 range"); - - auto edge_layer = m_network_group_metadata->get_layer_info_by_stream_name(stream_name); - CHECK_EXPECTED(edge_layer); - auto latency_meter = (contains(m_latency_meters, edge_layer->network_name)) ? m_latency_meters.at(edge_layer->network_name) : nullptr; - auto stream_index = edge_layer.value().stream_index; + + auto latency_meter = (contains(m_latency_meters, layer_info.network_name)) ? m_latency_meters.at(layer_info.network_name) : nullptr; /* TODO - HRT-6829- page_size should be calculated inside the vDMA channel class create function */ + const auto transfer_size = (layer_info.nn_stream_config.periph_bytes_per_buffer * + layer_info.nn_stream_config.core_buffers_per_frame); auto desc_sizes_pair = VdmaDescriptorList::get_desc_buffer_sizes_for_single_transfer(m_driver, static_cast(min_active_trans), static_cast(max_active_trans), transfer_size); - CHECK_EXPECTED(desc_sizes_pair); + CHECK_EXPECTED_AS_STATUS(desc_sizes_pair); const auto page_size = desc_sizes_pair->first; const auto descs_count = desc_sizes_pair->second; - auto channel = VdmaChannel::create(channel_id, channel_direction, m_driver, page_size, - stream_index, latency_meter, network_batch_size.value()); - CHECK_EXPECTED(channel); + auto channel = VdmaChannel::create(channel_id.value(), channel_direction, m_driver, page_size, + layer_info.name, latency_meter, network_batch_size.value()); + CHECK_EXPECTED_AS_STATUS(channel); const auto status = channel->allocate_resources(descs_count); - CHECK_SUCCESS_AS_EXPECTED(status); + CHECK_SUCCESS(status); auto channel_ptr = make_shared_nothrow(channel.release()); - CHECK_NOT_NULL_AS_EXPECTED(channel_ptr, HAILO_OUT_OF_HOST_MEMORY); - - m_boundary_channels.emplace(stream_name, channel_ptr); + CHECK_NOT_NULL(channel_ptr, HAILO_OUT_OF_HOST_MEMORY); - return channel_ptr; + m_boundary_channels.emplace(layer_info.name, channel_ptr); + return HAILO_SUCCESS; } Expected> ResourcesManager::get_boundary_vdma_channel_by_stream_name(const std::string &stream_name) @@ -266,7 +373,22 @@ Expected> ResourcesManager::get_boundary_vdma_chann return make_unexpected(HAILO_NOT_FOUND); } - return std::shared_ptr(m_boundary_channels[stream_name]); + return std::shared_ptr(boundary_channel_it->second); +} + +Expected> ResourcesManager::get_boundary_vdma_channel_by_stream_name(const std::string &stream_name) const +{ + auto boundary_channel_it = m_boundary_channels.find(stream_name); + if (std::end(m_boundary_channels) == boundary_channel_it) { + return make_unexpected(HAILO_NOT_FOUND); + } + + return std::shared_ptr(boundary_channel_it->second); +} + +hailo_power_mode_t ResourcesManager::get_power_mode() const +{ + return m_config_params.power_mode; } ExpectedRef ResourcesManager::create_inter_context_buffer(uint32_t transfer_size, @@ -296,23 +418,9 @@ ExpectedRef ResourcesManager::get_inter_context_buffer(const Expected ResourcesManager::get_control_network_group_header() { - CONTROL_PROTOCOL__application_header_t app_header{}; - app_header.dynamic_contexts_count = static_cast(m_contexts.size() - 1); + CONTROL_PROTOCOL__application_header_t app_header{}; + app_header.dynamic_contexts_count = m_dynamic_context_count; - /* Bitmask of all boundary channels (per engine) */ - std::array host_boundary_channels_bitmap{}; - - for (const auto &ch : m_channel_allocator.get_boundary_channel_ids()) { - CHECK_AS_EXPECTED(ch.engine_index < host_boundary_channels_bitmap.size(), HAILO_INTERNAL_FAILURE, - "Invalid engine index {}", static_cast(ch.engine_index)); - - host_boundary_channels_bitmap[ch.engine_index] |= (1 << ch.channel_index); - } - - std::copy(host_boundary_channels_bitmap.begin(), host_boundary_channels_bitmap.end(), - app_header.host_boundary_channels_bitmap); - - app_header.power_mode = static_cast(m_config_params.power_mode); auto status = fill_infer_features(app_header); CHECK_SUCCESS_AS_EXPECTED(status, "Invalid infer features"); status = fill_validation_features(app_header); @@ -323,17 +431,21 @@ Expected ResourcesManager::get_control_n return app_header; } -std::vector> -ResourcesManager::get_ddr_channel_pairs_per_context(uint8_t context_index) const +Expected> ResourcesManager::add_new_context(CONTROL_PROTOCOL__context_switch_context_type_t type, + const ConfigBufferInfoMap &config_info) { - std::vector> ddr_channels_pairs; - for (auto &ddr_channels_pair : m_ddr_channels_pairs) { - if (ddr_channels_pair.first.first == context_index) { - ddr_channels_pairs.push_back(std::ref(ddr_channels_pair.second)); - } + CHECK_AS_EXPECTED(m_total_context_count < std::numeric_limits::max(), HAILO_INVALID_CONTEXT_COUNT); + + auto context_resources = ContextResources::create(m_driver, type, m_config_channels_ids, config_info); + CHECK_EXPECTED(context_resources); + + m_contexts_resources.emplace_back(context_resources.release()); + m_total_context_count++; + if (CONTROL_PROTOCOL__CONTEXT_SWITCH_CONTEXT_TYPE_DYNAMIC == type) { + m_dynamic_context_count++; } - return ddr_channels_pairs; + return std::ref(m_contexts_resources.back()); } Expected ResourcesManager::get_available_channel_id(const LayerIdentifier &layer_identifier, @@ -352,45 +464,6 @@ hailo_status ResourcesManager::free_channel_index(const LayerIdentifier &layer_i return m_channel_allocator.free_channel_index(layer_identifier); } -void ResourcesManager::update_preliminary_config_buffer_info() -{ - // Preliminary_config is the first 'context' m_contexts vector - update_config_buffer_info(m_preliminary_config, m_contexts[0]); -} - -void ResourcesManager::update_dynamic_contexts_buffer_info() -{ - // Preliminary_config is the first 'context' m_contexts vector - assert((m_dynamic_config.size() + 1) == m_contexts.size()); - int ctxt_index = 1; - for (auto &cfg_context : m_dynamic_config) { - update_config_buffer_info(cfg_context, m_contexts[ctxt_index]); - ctxt_index++; - } -} - -ExpectedRef ResourcesManager::create_ddr_channels_pair(const DdrChannelsInfo &ddr_info, uint8_t context_index) -{ - auto buffer = DdrChannelsPair::create(m_driver, ddr_info); - CHECK_EXPECTED(buffer); - - const auto key = std::make_pair(context_index, ddr_info.d2h_stream_index); - auto emplace_res = m_ddr_channels_pairs.emplace(key, buffer.release()); - return std::ref(emplace_res.first->second); -} - -ExpectedRef ResourcesManager::get_ddr_channels_pair(uint8_t context_index, uint8_t d2h_stream_index) -{ - const auto key = std::make_pair(context_index, d2h_stream_index); - auto ddr_channels_pair = m_ddr_channels_pairs.find(key); - - if (m_ddr_channels_pairs.end() == ddr_channels_pair) { - return make_unexpected(HAILO_NOT_FOUND); - } - - return std::ref(ddr_channels_pair->second); -} - Expected ResourcesManager::get_default_streams_interface() { return m_vdma_device.get_default_streams_interface(); @@ -400,11 +473,16 @@ hailo_status ResourcesManager::register_fw_managed_vdma_channels() { hailo_status status = HAILO_UNINITIALIZED; - for (auto &ch : m_fw_managed_channels) { + for (auto &ch : m_internal_channels) { status = ch.register_fw_controlled_channel(); CHECK_SUCCESS(status); } + for (auto &ch : m_boundary_channels) { + status = ch.second->register_fw_controlled_channel(); + CHECK_SUCCESS(status); + } + return HAILO_SUCCESS; } @@ -412,8 +490,10 @@ hailo_status ResourcesManager::unregister_fw_managed_vdma_channels() { hailo_status status = HAILO_UNINITIALIZED; + // Note: We don't "unregister" the m_boundary_channels here, beacuse the Vdma*Stream objects will unregister their + // own channels. // TODO: Add one icotl to stop all channels at once (HRT-6097) - for (auto &ch : m_fw_managed_channels) { + for (auto &ch : m_internal_channels) { status = ch.unregister_fw_controlled_channel(); CHECK_SUCCESS(status); } @@ -433,10 +513,14 @@ hailo_status ResourcesManager::set_inter_context_channels_dynamic_batch_size(uin Expected ResourcesManager::get_network_batch_size(const std::string &network_name) const { - for (auto const &network_map: m_config_params.network_params_by_name) { + for (auto const &network_map : m_config_params.network_params_by_name) { auto const network_name_from_params = network_map.first; if (network_name_from_params == network_name) { - return Expected(network_map.second.batch_size); + auto actual_batch_size = network_map.second.batch_size; + if (HAILO_DEFAULT_BATCH_SIZE == actual_batch_size) { + actual_batch_size = DEFAULT_ACTUAL_BATCH_SIZE; + } + return actual_batch_size; } } @@ -452,9 +536,13 @@ Expected ResourcesManager::read_intermediate_buffer(const IntermediateBu return inter_context_buffer_it->second.read(); } - auto ddr_channels_pair_it = m_ddr_channels_pairs.find(key); - if (std::end(m_ddr_channels_pairs) != ddr_channels_pair_it) { - return ddr_channels_pair_it->second.read(); + const auto dynamic_context_index = key.first; + const size_t context_index = dynamic_context_index + CONTROL_PROTOCOL__CONTEXT_SWITCH_NUMBER_OF_NON_DYNAMIC_CONTEXTS; + CHECK_AS_EXPECTED(context_index < m_contexts_resources.size(), HAILO_NOT_FOUND, "Context index {} out of range", + dynamic_context_index); + const auto d2h_stream_index = key.second; + if (auto ddr_channels_pair = m_contexts_resources[context_index].get_ddr_channels_pair(d2h_stream_index)) { + return ddr_channels_pair->get().read(); } LOGGER__ERROR("Failed to find intermediate buffer for src_context {}, src_stream_index {}", key.first, @@ -463,6 +551,25 @@ Expected ResourcesManager::read_intermediate_buffer(const IntermediateBu } +hailo_status ResourcesManager::configure() +{ + CHECK(!m_is_configured, HAILO_INTERNAL_FAILURE, "Can't configure the same network group twice"); + m_is_configured = true; + + auto net_group_header = get_control_network_group_header(); + CHECK_EXPECTED_AS_STATUS(net_group_header); + + auto status = Control::context_switch_set_network_group_header(m_vdma_device, net_group_header.release()); + CHECK_SUCCESS(status); + + for (const auto &context : m_contexts_resources) { + status = Control::context_switch_set_context_info(m_vdma_device, context.get_controls()); + CHECK_SUCCESS(status); + } + + return HAILO_SUCCESS; +} + hailo_status ResourcesManager::enable_state_machine(uint16_t dynamic_batch_size) { return Control::enable_network_group(m_vdma_device, m_net_group_index, dynamic_batch_size); @@ -483,41 +590,4 @@ hailo_status ResourcesManager::reset_state_machine(bool keep_nn_config_during_re return HAILO_SUCCESS; } -void ResourcesManager::update_config_buffer_info(std::vector &config_buffers, - CONTROL_PROTOCOL__context_switch_context_info_t &context) -{ - assert(CONTROL_PROTOCOL__MAX_CFG_CHANNELS >= config_buffers.size()); - context.cfg_channels_count = static_cast(config_buffers.size()); - - auto i = 0; - for (const auto &config : config_buffers) { - context.config_channel_infos[i] = config.get_config_channel_info(); - i++; - } -} - -Expected ResourcesManager::get_cfg_channel_engine(HailoRTDriver &driver, uint8_t config_stream_index, - const ProtoHEFNetworkGroupMetadata &proto_metadata) -{ - if (driver.dma_type() == HailoRTDriver::DmaType::PCIE) { - // On PCIe we have only 1 engine. To support the same HEF with both PCIe and DRAM, we use default engine here. - return uint8_t(vdma::DEFAULT_ENGINE_INDEX); - } - - const auto &cfg_channels_config = proto_metadata.cfg_channels_config(); - if (cfg_channels_config.empty()) { - // Old hef, return default value - return uint8_t(vdma::DEFAULT_ENGINE_INDEX); - } - - auto cfg_info = std::find_if(cfg_channels_config.begin(), cfg_channels_config.end(), - [config_stream_index](const auto &cfg_info) - { - return cfg_info.cfg_channel_index() == config_stream_index; - }); - CHECK_AS_EXPECTED(cfg_info != cfg_channels_config.end(), HAILO_INVALID_HEF, "Cfg channel {} not found", config_stream_index); - CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(cfg_info->engine_id()), HAILO_INVALID_HEF, "Invalid dma engine index"); - return static_cast(cfg_info->engine_id()); -} - } /* namespace hailort */ diff --git a/hailort/libhailort/src/context_switch/resource_manager_builder.cpp b/hailort/libhailort/src/context_switch/resource_manager_builder.cpp new file mode 100644 index 0000000..cea5408 --- /dev/null +++ b/hailort/libhailort/src/context_switch/resource_manager_builder.cpp @@ -0,0 +1,1217 @@ +/** + * Copyright (c) 2022 Hailo Technologies Ltd. All rights reserved. + * Distributed under the MIT license (https://opensource.org/licenses/MIT) +**/ +/** + * @file resource_manager_builder.cpp + * @brief Builds a ResourcesManager object for the given CoreOp. + **/ + +#include "resource_manager_builder.hpp" +#include "control.hpp" + +namespace hailort +{ + + +static uint16_t calculate_periph_buffers_per_frame(const CONTROL_PROTOCOL__hw_consts_t &hw_consts, + uint16_t min_periph_buffers_per_frame, uint32_t frame_size, uint16_t periph_buffers_per_frame) +{ + const auto max_periph_buffers_per_frame = MIN(frame_size, static_cast(hw_consts.max_periph_buffers_per_frame)); + // Fifo copies FIFO_WORD_GRANULARITY_IN_BYTES each time from/to the fifo + const uint32_t frame_size_words_count = frame_size / hw_consts.fifo_word_granularity_bytes; + // Look for the highest periph_bytes_per_buffer (frame_size / periph_buffers_per_frame) that is a multiple of FIFO_WORD_GRANULARITY_IN_BYTES + for (uint16_t i = min_periph_buffers_per_frame; i < max_periph_buffers_per_frame; i++) { + // (0 == (frame_size_words_count % i) ensures periph_bytes_per_buffer will be a multiple of FIFO_WORD_GRANULARITY_IN_BYTES + if ((0 == (frame_size_words_count % i)) && (hw_consts.max_periph_bytes_per_buffer >= (frame_size / i))) { + return i; + } + } + + // Fallback to frame_size unless it exceeds MAX_PERIPH_BUFFERS_PER_FRAME + if (hw_consts.max_periph_buffers_per_frame < frame_size) { + return periph_buffers_per_frame; + } else { + return static_cast(frame_size); + } +} + +static hailo_status calculate_credit_params(const CONTROL_PROTOCOL__hw_consts_t &hw_consts, uint16_t desc_page_size, + hailo_stream_direction_t direction, bool should_optimize_credits, uint16_t *periph_bytes_per_buffer, + uint16_t *periph_buffers_per_frame) +{ + // Next parameters differ between RX and TX + + auto local_periph_bytes_per_buffer = (*periph_bytes_per_buffer); + auto local_periph_buffers_per_frame = (*periph_buffers_per_frame); + uint32_t periph_frame_size = (*periph_bytes_per_buffer) * (*periph_buffers_per_frame); + const auto max_bytes_per_buffer = MAX(hw_consts.max_acceptable_bytes_per_buffer, (*periph_bytes_per_buffer)); + + if (0 != (local_periph_bytes_per_buffer % hw_consts.fifo_word_granularity_bytes)) { + return HAILO_INTERNAL_FAILURE; + } + + if (should_optimize_credits) { + // If credits optimizations flag is on, assuming periph_buffers_per_frame * periph_bytes_per_buffer == periph_frame_size + // Find the lowest periph_buffers_per_frame that divides periph_frame_size and is bigger than periph_frame_size / max_bytes_per_buffer + // Also, periph_bytes_per_buffer must be a multiple of 8 + const auto min_periph_buffers_per_frame = DIV_ROUND_UP(periph_frame_size, max_bytes_per_buffer); + local_periph_buffers_per_frame = calculate_periph_buffers_per_frame(hw_consts, static_cast(min_periph_buffers_per_frame), + periph_frame_size, local_periph_buffers_per_frame); + assert(IS_FIT_IN_UINT16(periph_frame_size / local_periph_buffers_per_frame)); + local_periph_bytes_per_buffer = static_cast(periph_frame_size / local_periph_buffers_per_frame); // Must be integer according to last function + } + // Periph credits size must be lower than the following value to make sure that the credit size allows + // for at least desc_page_size bytes left in the FIFO for the last descriptor in the pattern + if ((direction == HAILO_D2H_STREAM) && + (static_cast(local_periph_bytes_per_buffer) > (hw_consts.outbound_data_stream_size - 8 - desc_page_size))) { + LOGGER__ERROR("Current periph_bytes_per_buffer is {} which is too high. Exiting.", local_periph_bytes_per_buffer); + return HAILO_INTERNAL_FAILURE; + } + + *periph_bytes_per_buffer = local_periph_bytes_per_buffer; + *periph_buffers_per_frame = local_periph_buffers_per_frame; + return HAILO_SUCCESS; +} + +static Expected update_layer_info(const LayerInfo &original_layer_info, + const CONTROL_PROTOCOL__host_buffer_info_t &buffer_info, + const CONTROL_PROTOCOL__hw_consts_t &hw_consts, bool should_optimize_credits) +{ + LayerInfo local_layer_info = original_layer_info; + + auto status = calculate_credit_params(hw_consts, buffer_info.desc_page_size, local_layer_info.direction, + should_optimize_credits, &local_layer_info.nn_stream_config.periph_bytes_per_buffer, + &local_layer_info.nn_stream_config.periph_buffers_per_frame); + CHECK_SUCCESS_AS_EXPECTED(status); + + if (local_layer_info.max_shmifo_size == 0) { + local_layer_info.max_shmifo_size = hw_consts.default_initial_credit_size; + } + + return local_layer_info; +} + +static hailo_status fill_boundary_input_layer(ContextResources &context_resources, + ResourcesManager &resources_manager, const LayerInfo layer_info, const CONTROL_PROTOCOL__hw_consts_t &hw_consts, + bool should_optimize_credits) +{ + const auto transfer_size = (layer_info.nn_stream_config.periph_bytes_per_buffer * + layer_info.nn_stream_config.core_buffers_per_frame); + + auto vdma_channel = resources_manager.get_boundary_vdma_channel_by_stream_name(layer_info.name); + CHECK_EXPECTED_AS_STATUS(vdma_channel); + + auto buffer_info = vdma_channel.value()->get_boundary_buffer_info(transfer_size); + CHECK_EXPECTED_AS_STATUS(buffer_info); + + auto local_layer_info = update_layer_info(layer_info, *buffer_info, hw_consts, should_optimize_credits); + CHECK_EXPECTED_AS_STATUS(local_layer_info); + + BoundaryEdgeLayer edge_layer{}; + edge_layer.layer_info = local_layer_info.release(); + edge_layer.channel_id = vdma_channel.value()->get_channel_id(); + edge_layer.buffer_info = buffer_info.value(); + context_resources.add_edge_layer(edge_layer); + + LOGGER__DEBUG("Boundary input stream: {} h2d_channel: {}.", layer_info.stream_index, edge_layer.channel_id); + return HAILO_SUCCESS; +} + +static hailo_status fill_inter_context_input_layer(ContextResources &context_resources, + ResourcesManager &resources_manager, const LayerInfo &layer_info, const CONTROL_PROTOCOL__hw_consts_t &hw_consts, + bool should_optimize_credits) +{ + const auto channel_id = resources_manager.get_available_channel_id(to_layer_identifier(layer_info), + VdmaChannel::Direction::H2D, layer_info.dma_engine_index); + CHECK_EXPECTED_AS_STATUS(channel_id); + + /* Get inter context buffer previously created */ + const auto &connected_context = layer_info.connected_context_info; + auto intermediate_buffer_key = std::make_pair(connected_context.context_index, connected_context.stream_index); + auto inter_context_buffer_exp = resources_manager.get_inter_context_buffer(intermediate_buffer_key); + CHECK_EXPECTED_AS_STATUS(inter_context_buffer_exp, "Failed to find inter context buffer for src context {}, src_stream_index {}", + connected_context.context_index, connected_context.stream_index); + auto &inter_context_buffer = inter_context_buffer_exp->get(); + + auto local_layer_info = update_layer_info(layer_info, inter_context_buffer.get_host_buffer_info(), hw_consts, + should_optimize_credits); + CHECK_EXPECTED_AS_STATUS(local_layer_info); + + InterContextEdgeLayer edge_layer{}; + edge_layer.layer_info = local_layer_info.release(); + edge_layer.channel_id = channel_id.value(); + edge_layer.buffer_info = inter_context_buffer.get_host_buffer_info(); + context_resources.add_edge_layer(edge_layer); + + LOGGER__DEBUG("Intermediate input stream {}, src_context:{}, dst_context: {}, h2d_channel {}.", + layer_info.stream_index, layer_info.context_index, layer_info.connected_context_info.context_index, + channel_id.value()); + + return HAILO_SUCCESS; +} + +static hailo_status fill_boundary_output_layer(ContextResources &context_resources, + ResourcesManager &resources_manager, const LayerInfo &layer_info, const CONTROL_PROTOCOL__hw_consts_t &hw_consts, + bool should_optimize_credits) +{ + const auto transfer_size = (layer_info.nn_stream_config.periph_bytes_per_buffer * + layer_info.nn_stream_config.core_buffers_per_frame); + + auto vdma_channel = resources_manager.get_boundary_vdma_channel_by_stream_name(layer_info.name); + CHECK_EXPECTED_AS_STATUS(vdma_channel); + + auto buffer_info = vdma_channel.value()->get_boundary_buffer_info(transfer_size); + CHECK_EXPECTED_AS_STATUS(buffer_info); + + auto local_layer_info = update_layer_info(layer_info, *buffer_info, hw_consts, should_optimize_credits); + CHECK_EXPECTED_AS_STATUS(local_layer_info); + + BoundaryEdgeLayer edge_layer{}; + edge_layer.layer_info = local_layer_info.release(); + edge_layer.channel_id = vdma_channel.value()->get_channel_id(); + edge_layer.buffer_info = buffer_info.value(); + context_resources.add_edge_layer(edge_layer); + + LOGGER__DEBUG("Boundary output stream: {} d2h_channel: {}.", layer_info.stream_index, edge_layer.channel_id); + return HAILO_SUCCESS; +} + +static hailo_status fill_inter_context_output_layer(ContextResources &context_resources, + ResourcesManager &resources_manager, const LayerInfo &layer_info, + const CONTROL_PROTOCOL__hw_consts_t &hw_consts, bool should_optimize_credits) +{ + const auto channel_id = resources_manager.get_available_channel_id(to_layer_identifier(layer_info), + VdmaChannel::Direction::D2H, layer_info.dma_engine_index); + CHECK_EXPECTED_AS_STATUS(channel_id); + + const auto frame_credits_in_bytes = (layer_info.nn_stream_config.periph_bytes_per_buffer * + layer_info.nn_stream_config.core_buffers_per_frame); + + auto inter_context_buffer_exp = resources_manager.create_inter_context_buffer(frame_credits_in_bytes, + layer_info.stream_index, layer_info.context_index, layer_info.network_name); + CHECK_EXPECTED_AS_STATUS(inter_context_buffer_exp); + auto &inter_context_buffer = inter_context_buffer_exp->get(); + + auto local_layer_info = update_layer_info(layer_info, inter_context_buffer.get_host_buffer_info(), hw_consts, + should_optimize_credits); + CHECK_EXPECTED_AS_STATUS(local_layer_info); + + InterContextEdgeLayer edge_layer{}; + edge_layer.layer_info = local_layer_info.release(); + edge_layer.channel_id = channel_id.value(); + edge_layer.buffer_info = inter_context_buffer.get_host_buffer_info(); + context_resources.add_edge_layer(edge_layer); + + LOGGER__DEBUG("Inter-context output stream {}, src_context:{}, d2h_channel {}.", + layer_info.stream_index, layer_info.context_index, channel_id.value()); + return HAILO_SUCCESS; +} + +static hailo_status fill_ddr_output_layer(ContextResources &context_resources, + ResourcesManager &resources_manager, const LayerInfo &layer_info, + const CONTROL_PROTOCOL__hw_consts_t &hw_consts) +{ + CHECK(resources_manager.get_supported_features().padded_ddr_buffers, HAILO_INVALID_HEF, + "Failed opening non-compatible HEF that uses the following deprecated features: host-managed DDR buffers." + "Please re-compile the HEF using a newer Dataflow Compiler version (v3.11.0 or newer)"); + // Allocate resources and prepare ddr_info + + DdrChannelsInfo ddr_pair_info = {}; + ddr_pair_info.h2d_stream_index = layer_info.connected_context_info.stream_index; + ddr_pair_info.d2h_stream_index = layer_info.stream_index; + ddr_pair_info.network_index = layer_info.network_index; + + // It is assumed that output channels are parsed before input channels. + // Allocate vdma channel index for both edges + const auto h2d_layer_identifier = std::make_tuple(LayerType::DDR, layer_info.name, ddr_pair_info.h2d_stream_index); + const auto h2d_channel_id = resources_manager.get_available_channel_id(h2d_layer_identifier, + VdmaChannel::Direction::H2D, layer_info.connected_context_info.dma_engine_index); + CHECK_EXPECTED_AS_STATUS(h2d_channel_id); + ddr_pair_info.h2d_channel_id = h2d_channel_id.value(); + + const auto d2h_layer_identifier = std::make_tuple(LayerType::DDR, layer_info.name, ddr_pair_info.d2h_stream_index); + const auto d2h_channel_id = resources_manager.get_available_channel_id(d2h_layer_identifier, + VdmaChannel::Direction::D2H, layer_info.dma_engine_index); + CHECK_EXPECTED_AS_STATUS(d2h_channel_id); + ddr_pair_info.d2h_channel_id = d2h_channel_id.value(); + + ddr_pair_info.row_size = layer_info.nn_stream_config.core_bytes_per_buffer; + ddr_pair_info.min_buffered_rows = layer_info.ddr_info.min_buffered_rows; + ddr_pair_info.total_buffers_per_frame = layer_info.ddr_info.total_buffers_per_frame; + + // Create the ddr buffer + auto ddr_channels_pair = context_resources.create_ddr_channels_pair(ddr_pair_info); + CHECK_EXPECTED_AS_STATUS(ddr_channels_pair); + + // On ddr layers, we assume the periph credit size is aligned to the size of descriptor, so we don't want to + // optimize the credits. + const bool should_optimize_credits = false; + auto local_layer_info = update_layer_info(layer_info, ddr_channels_pair->get().get_host_buffer_info(), hw_consts, + should_optimize_credits); + CHECK_EXPECTED_AS_STATUS(local_layer_info); + + DdrChannelEdgeLayer edge_layer{}; + edge_layer.layer_info = local_layer_info.release(); + edge_layer.channel_id = ddr_pair_info.d2h_channel_id; + edge_layer.buffer_info = ddr_channels_pair->get().get_host_buffer_info(); + context_resources.add_edge_layer(edge_layer); + + return HAILO_SUCCESS; +} + +static hailo_status fill_ddr_input_layer(ContextResources &context_resources, + const LayerInfo &layer_info, const CONTROL_PROTOCOL__hw_consts_t &hw_consts) +{ + auto connected_stream_index = layer_info.connected_context_info.stream_index; + auto ddr_channels_pair = context_resources.get_ddr_channels_pair(connected_stream_index); + CHECK(ddr_channels_pair, HAILO_INVALID_HEF, "Matching DDR layer as not found for context {} src stream {}", + layer_info.context_index, connected_stream_index); + + const auto ddr_info = ddr_channels_pair->get().info(); + LOGGER__DEBUG("DDR layer: input stream_index: {}, output stream_index: {}, h2d_channel {}, d2h_channel: {}.", + ddr_info.h2d_stream_index, ddr_info.d2h_stream_index, ddr_info.h2d_channel_id, ddr_info.d2h_channel_id); + + CHECK(layer_info.stream_index == ddr_info.h2d_stream_index, HAILO_INVALID_HEF, "DDR channel pair mismatch in h2d channel"); + CHECK(layer_info.connected_context_info.stream_index == ddr_info.d2h_stream_index, HAILO_INVALID_HEF, "DDR channel pair mismatch in d2h channel"); + CHECK(layer_info.network_index == ddr_info.network_index, HAILO_INVALID_HEF, "DDR channel pair mismatch network_index"); + + // On ddr layers, we assume the periph credit size is aligned to the size of descriptor, so we don't want to + // optimize the credits. + const bool should_optimize_credits = false; + auto local_layer_info = update_layer_info(layer_info, ddr_channels_pair->get().get_host_buffer_info(), hw_consts, + should_optimize_credits); + CHECK_EXPECTED_AS_STATUS(local_layer_info); + + DdrChannelEdgeLayer edge_layer{}; + edge_layer.layer_info = local_layer_info.release(); + edge_layer.channel_id = ddr_info.h2d_channel_id; + edge_layer.buffer_info = ddr_channels_pair->get().get_host_buffer_info(); + context_resources.add_edge_layer(edge_layer); + + return HAILO_SUCCESS; +} + +static hailo_status add_ddr_buffers_info(std::vector &configuration_actions, + const ContextResources &context_resources) +{ + bool start_fw_ddr_buffer_task = false; + for (auto& ddr_channels_pair : context_resources.get_ddr_channels_pairs()) { + if (ddr_channels_pair.need_manual_credit_management()) { + const auto ddr_info = ddr_channels_pair.info(); + auto ddr_pair_action = DdrPairInfoAction::create(ddr_info.h2d_channel_id, ddr_info.d2h_channel_id, + ddr_info.network_index, ddr_channels_pair.descriptors_per_frame(), ddr_channels_pair.descs_count()); + CHECK_EXPECTED_AS_STATUS(ddr_pair_action); + configuration_actions.emplace_back(ddr_pair_action.release()); + + start_fw_ddr_buffer_task = true; + } + } + + if (start_fw_ddr_buffer_task) { + auto start_ddr_buffering_action = StartDdrBufferingTaskAction::create(); + CHECK_EXPECTED_AS_STATUS(start_ddr_buffering_action); + configuration_actions.emplace_back(start_ddr_buffering_action.release()); + } + + return HAILO_SUCCESS; +} + +static hailo_status parse_and_fill_edge_layers_mapping( + ContextResources &context_resources, + const ContextMetadata &context_metadata, + ResourcesManager &resources_manager) +{ + hailo_status status = HAILO_UNINITIALIZED; + + auto hw_consts = Control::get_hw_consts(resources_manager.get_device()); + CHECK_EXPECTED_AS_STATUS(hw_consts); + const bool should_optimize_credits = hw_consts->should_optimize_credits && + (HAILO_POWER_MODE_PERFORMANCE == resources_manager.get_power_mode()); + + // Parse the edge layer by order - first output edge layers, then ddr inputs and only then the input edge layers + // In order to insure that input data can enter the chip only after all other elements are configured. + // We parse ddr inputs before boundary/inter-context because otherwise on C2C mode we may lose some credit. + + for (const auto &output_layer_info : context_metadata.get_ddr_output_layers()) { + status = fill_ddr_output_layer(context_resources, resources_manager, output_layer_info, *hw_consts); + CHECK_SUCCESS(status); + } + + for (const auto &output_layer_info : context_metadata.get_boundary_output_layers()) { + status = fill_boundary_output_layer(context_resources, resources_manager, output_layer_info, + *hw_consts, should_optimize_credits); + CHECK_SUCCESS(status); + } + + for (const auto &output_layer_info : context_metadata.get_inter_context_output_layers()) { + status = fill_inter_context_output_layer(context_resources, resources_manager, output_layer_info, + *hw_consts, should_optimize_credits); + CHECK_SUCCESS(status); + } + + for (const auto &input_layer_info : context_metadata.get_ddr_input_layers()) { + status = fill_ddr_input_layer(context_resources, input_layer_info, *hw_consts); + CHECK_SUCCESS(status); + } + + for (const auto &input_layer_info : context_metadata.get_boundary_input_layers()) { + status = fill_boundary_input_layer(context_resources, resources_manager, input_layer_info, + *hw_consts, should_optimize_credits); + CHECK_SUCCESS(status); + } + + for (const auto &input_layer_info : context_metadata.get_inter_context_input_layers()) { + status = fill_inter_context_input_layer(context_resources, resources_manager, input_layer_info, + *hw_consts, should_optimize_credits); + CHECK_SUCCESS(status); + } + + status = context_resources.validate_edge_layers(); + CHECK_SUCCESS(status); + + /* UN-Lock resources at the end of the context - + h2d inter-context, d2h inter-context and DDR buffer channels */ + for (const auto &input_layer_info : context_metadata.get_inter_context_input_layers()) { + status = resources_manager.free_channel_index(to_layer_identifier(input_layer_info)); + CHECK_SUCCESS(status); + } + + for (const auto &output_layer_info : context_metadata.get_inter_context_output_layers()) { + status = resources_manager.free_channel_index(to_layer_identifier(output_layer_info)); + CHECK_SUCCESS(status); + } + + for (const auto &output_layer_info : context_metadata.get_ddr_output_layers()) { + const auto h2d_layer_identifier = std::make_tuple(LayerType::DDR, output_layer_info.name, + output_layer_info.connected_context_info.stream_index); + status = resources_manager.free_channel_index(h2d_layer_identifier); + CHECK_SUCCESS(status); + + const auto d2h_layer_identifier = std::make_tuple(LayerType::DDR, output_layer_info.name, + output_layer_info.stream_index); + status = resources_manager.free_channel_index(d2h_layer_identifier); + CHECK_SUCCESS(status); + } + + return HAILO_SUCCESS; +} + +// Returns pairs of form [start, end] (inclusive) of repeated 'ContextSwitchConfigAction's in the given vector +static std::vector> get_repreated_actions_boundary_indices( + const std::vector &actions) +{ + const uint32_t num_actions = static_cast(actions.size()); + + std::vector> repeated_indexes; + uint32_t start_index = 0; + while (start_index < num_actions) { + auto end_index = start_index + 1; + do + { + if (end_index == num_actions) { + break; + } + if (actions[start_index]->get_type() != actions[end_index]->get_type()) { + break; + } + end_index++; + } while (true); + + repeated_indexes.emplace_back(start_index, end_index - 1); + start_index = end_index; + } + + return repeated_indexes; +} + +// Returns a map from start indexes of repeated actions to the size of the chunk (number of repeated actions) +static std::map get_start_indexes_of_repeated_actions( + const std::vector &actions, + const std::vector> &repeated_indexes, + // TODO: get this from HardCoded config (HRT-5352) + const std::set &action_types_denylist = {}) +{ + std::map result; + for (const auto &index_pair : repeated_indexes) { + if (!actions[index_pair.first]->supports_repeated_block()) { + continue; + } + + if (contains(action_types_denylist, actions[index_pair.first]->get_type())) { + continue; + } + + // TODO: Move merge calculation to HRT-5352 + // Merge calculation (see also - CONTEXT_SWITCH_DEFS__repeated_action_header_t in common/include/context_switch_defs.h): + // * Assume there are x repeated actions that can be merged + // * Let a := sizeof(action_to_be_merged) [without CONTEXT_SWITCH_DEFS__common_action_header_t] + // * sizeof(CONTEXT_SWITCH_DEFS__common_action_header_t) is 5 + // * sizeof(CONTEXT_SWITCH_DEFS__repeated_action_header_t) is 3 + // Then: + // * original_size = x * (5 + a) = 5x + ax + // * new_size = 5 + 3 + ax = 8 + ax + // * new_size < original_size <=> 8 + ax < 5x + ax <=> 8 < 5x <=> 1.6 < x + // Hence we merge for x >= 2 + static_assert(sizeof(CONTEXT_SWITCH_DEFS__common_action_header_t) == 5, + "Merge calculation assumes that 'sizeof(CONTEXT_SWITCH_DEFS__common_action_header_t) == 5'"); + static_assert(sizeof(CONTEXT_SWITCH_DEFS__repeated_action_header_t) == 3, + "Merge calculation assumes that 'sizeof(CONTEXT_SWITCH_DEFS__repeated_action_header_t) == 3'"); + static const uint32_t MIN_REQUIRED_FOR_MERGING = 2; + + uint32_t start_index = index_pair.first; + const uint32_t end_index = index_pair.second; + while (start_index < end_index) { + const auto curr_chunk_size = static_cast(std::min( + static_cast(std::numeric_limits::max()), + end_index - start_index + 1)); + if (curr_chunk_size < MIN_REQUIRED_FOR_MERGING) { + break; + } + + result.emplace(start_index, curr_chunk_size); + + start_index += curr_chunk_size; + } + } + + return result; +} + +static std::set> get_indexes_of_action_type( + const std::vector &actions, + const std::vector> &repeated_indexes, + const ContextSwitchConfigAction::Type &required_action_type) +{ + std::set> result; + for (const auto &index_pair : repeated_indexes) { + const auto curr_action_type = actions[index_pair.first]->get_type(); + if (required_action_type != curr_action_type) { + continue; + } + + result.emplace(index_pair); + } + + return result; +} + +static std::set get_end_indexes_of_action_type( + const std::vector &actions, + const std::vector> &repeated_indexes, + const ContextSwitchConfigAction::Type &required_action_type) +{ + std::set result; + for (const auto &index_pair : get_indexes_of_action_type(actions, repeated_indexes, required_action_type)) { + result.insert(index_pair.second); + } + + return result; +} + +static hailo_status push_fetch_config_actions( + std::vector &config_resources, const std::set &pending_config_stream_indexes, + std::vector &total_ccw_bursts, const bool support_pre_fetch, + std::vector &processed_configuration_actions) +{ + CHECK(total_ccw_bursts.size() == config_resources.size(), HAILO_INTERNAL_FAILURE, "Invalid cfg channels count"); + for (const auto config_stream_index : pending_config_stream_indexes) { + CHECK(config_stream_index < config_resources.size(), HAILO_INTERNAL_FAILURE, "Invalid cfg channel index"); + + if (support_pre_fetch) { + auto action = AddCcwBurstAction::create(config_stream_index, total_ccw_bursts[config_stream_index]); + CHECK_EXPECTED_AS_STATUS(action); + processed_configuration_actions.emplace_back(action.release()); + } else { + const auto desc_count = config_resources[config_stream_index].program_descriptors(); + CHECK_EXPECTED_AS_STATUS(desc_count); + CHECK(IS_FIT_IN_UINT16(desc_count.value()), HAILO_INVALID_OPERATION, + "On cfg with continuous mode, max descriptors size must fit in uint16_t"); + + auto action = FetchCfgChannelDescriptorsAction::create(config_resources[config_stream_index].channel_id(), + static_cast(desc_count.value())); + CHECK_EXPECTED_AS_STATUS(action); + processed_configuration_actions.emplace_back(action.release()); + } + } + + return HAILO_SUCCESS; +} + +static hailo_status write_ccw_to_buffer(ConfigBuffer& config_buffer, const WriteDataCcwAction &ccw_action, + bool support_pre_fetch) +{ + const bool is_last_write = config_buffer.size_left() == ccw_action.data().size(); + if (support_pre_fetch && is_last_write) { + auto status = config_buffer.pad_with_nops(); + CHECK_SUCCESS(status); + } + + auto status = config_buffer.write(ccw_action.data()); + CHECK_SUCCESS(status); + + if (support_pre_fetch && is_last_write) { + auto desc_count = config_buffer.program_descriptors(); + CHECK_EXPECTED_AS_STATUS(desc_count); + } + + return HAILO_SUCCESS; +} + +static hailo_status proccess_write_ccw_action(const ContextSwitchConfigActionPtr &configuration_action, + std::vector &config_resources, std::set &pending_config_stream_indexes, + std::vector &total_ccw_bursts, const std::set &end_indexes_of_write_ccw_actions, + const uint32_t &action_index, const bool support_pre_fetch, + std::vector &processed_configuration_actions) +{ + assert(ContextSwitchConfigAction::Type::WriteDataCcw == configuration_action->get_type()); + const auto &write_ccw_action = *static_cast(configuration_action.get()); + + // Add the config stream index of the current WriteDataCcwAction + const auto config_stream_index = write_ccw_action.config_stream_index(); + pending_config_stream_indexes.insert(config_stream_index); + + // TODO: get CCW headers from proto (need to add it into the proto) + const uint16_t ccw_bursts = 1; + auto accum_ccw_bursts = total_ccw_bursts[config_stream_index] + ccw_bursts; + CHECK(IS_FIT_IN_UINT16(accum_ccw_bursts), HAILO_INTERNAL_FAILURE, + "Failed to parse HEF. action fetch ccw burst supports only to 2^16 bursts."); + assert(config_stream_index < total_ccw_bursts.size()); + total_ccw_bursts[config_stream_index] = static_cast(accum_ccw_bursts); + + assert(config_stream_index < config_resources.size()); + auto status = write_ccw_to_buffer(config_resources[config_stream_index], write_ccw_action, support_pre_fetch); + CHECK_SUCCESS(status); + + // At the end of a consecutive group of WriteDataCcwActions, we program the + // descriptors for all the config channels used. + if (contains(end_indexes_of_write_ccw_actions, action_index)) { + // Add the last CCW write into the buffer + processed_configuration_actions.emplace_back(configuration_action); + + status = push_fetch_config_actions(config_resources, pending_config_stream_indexes, total_ccw_bursts, + support_pre_fetch, processed_configuration_actions); + CHECK_SUCCESS(status); + + // Cleanups + pending_config_stream_indexes.clear(); + for (uint8_t cleanup_ch_index = 0; cleanup_ch_index < total_ccw_bursts.size(); cleanup_ch_index++) { + total_ccw_bursts[cleanup_ch_index] = 0; + } + } else { + // Add the current action + processed_configuration_actions.emplace_back(configuration_action); + } + + return HAILO_SUCCESS; +} + +static Expected find_dummy_stream(const LayerInfo &layer_info, const ContextResources &context_resources) +{ + // TODO: HRT-8611 use one loop for all edge layers + for (const auto &edge_layer : context_resources.get_boundary_layers()) { + if (edge_layer.layer_info.direction != layer_info.direction) { + return Expected(edge_layer.layer_info.stream_index); + } + } + for (const auto &edge_layer : context_resources.get_inter_context_layers()) { + if (edge_layer.layer_info.direction != layer_info.direction) { + return Expected(edge_layer.layer_info.stream_index); + } + } + for (const auto &edge_layer : context_resources.get_ddr_channel_layers()) { + if (edge_layer.layer_info.direction != layer_info.direction) { + return Expected(edge_layer.layer_info.stream_index); + } + } + + LOGGER__ERROR("Couldn't find dummy stream from context"); + return make_unexpected(HAILO_INTERNAL_FAILURE); +} + +static hailo_status add_change_vdma_to_stream_mapping( + const NetworkGroupMetadata &network_group_metadata, const ResourcesManager &resources_manager, + ContextResources &context_resources, uint8_t context_index, + std::vector &processed_configuration_actions) +{ + for (const auto &layer_info : network_group_metadata.get_all_layer_infos()) { + auto vdma_channel = resources_manager.get_boundary_vdma_channel_by_stream_name(layer_info.name); + CHECK_EXPECTED_AS_STATUS(vdma_channel); + + const auto channel_id = vdma_channel.value()->get_channel_id(); + const bool is_dummy_stream = layer_info.context_index != context_index; + uint8_t stream_index = layer_info.stream_index; + if (is_dummy_stream) { + auto dummy_stream_index = find_dummy_stream(layer_info, context_resources); + CHECK_EXPECTED_AS_STATUS(dummy_stream_index); + stream_index = *dummy_stream_index; + } + + auto action = ChangeVdmaToStreamMapping::create(channel_id, stream_index, is_dummy_stream); + CHECK_EXPECTED_AS_STATUS(action); + processed_configuration_actions.emplace_back(action.release()); + } + + return HAILO_SUCCESS; +} + +static hailo_status push_edge_layer_activation_actions( + const ContextResources &context_resources, + std::vector &actions) +{ + // Activate the edge layer by order - first output edge layers, then ddr inputs and only then the input edge layers + // In order to insure that input data can enter the chip only after all other elements are configured. + // We parse ddr inputs before boundary/inter-context because otherwise on C2C mode we may lose some credit. + + for (const auto &edge_layer : context_resources.get_ddr_channel_layers(HAILO_D2H_STREAM)) { + auto activate_action = ActivateDdrOutputChannelAction::create(edge_layer.channel_id, + edge_layer.layer_info.stream_index, edge_layer.layer_info.nn_stream_config, edge_layer.buffer_info, + edge_layer.layer_info.ddr_info.min_buffered_rows); + CHECK_EXPECTED_AS_STATUS(activate_action); + actions.emplace_back(activate_action.release()); + } + + for (const auto &edge_layer : context_resources.get_boundary_layers(HAILO_D2H_STREAM)) { + auto activate_action = ActivateBoundaryOutputChannelAction::create(edge_layer.channel_id, + edge_layer.layer_info.stream_index, edge_layer.layer_info.nn_stream_config, edge_layer.buffer_info); + CHECK_EXPECTED_AS_STATUS(activate_action); + actions.emplace_back(activate_action.release()); + } + + for (const auto &edge_layer : context_resources.get_inter_context_layers(HAILO_D2H_STREAM)) { + auto activate_action = ActivateInterContextOutputChannelAction::create(edge_layer.channel_id, + edge_layer.layer_info.stream_index, edge_layer.layer_info.network_index, + edge_layer.layer_info.nn_stream_config, edge_layer.buffer_info); + CHECK_EXPECTED_AS_STATUS(activate_action); + actions.emplace_back(activate_action.release()); + } + + for (const auto &edge_layer : context_resources.get_ddr_channel_layers(HAILO_H2D_STREAM)) { + const auto d2h_stream_index = edge_layer.layer_info.connected_context_info.stream_index; + auto pair = context_resources.get_ddr_channels_pair(d2h_stream_index); + CHECK_EXPECTED_AS_STATUS(pair); + const auto d2h_channel_id = pair->get().info().d2h_channel_id; + + auto activate_action = ActivateDdrInputChannelAction::create(edge_layer.channel_id, + edge_layer.layer_info.stream_index, edge_layer.layer_info.nn_stream_config, edge_layer.buffer_info, + edge_layer.layer_info.max_shmifo_size, d2h_channel_id); + CHECK_EXPECTED_AS_STATUS(activate_action); + actions.emplace_back(activate_action.release()); + } + + for (const auto &edge_layer : context_resources.get_boundary_layers(HAILO_H2D_STREAM)) { + auto activate_action = ActivateBoundaryInputChannelAction::create(edge_layer.channel_id, + edge_layer.layer_info.stream_index, edge_layer.layer_info.nn_stream_config, edge_layer.buffer_info, + edge_layer.layer_info.max_shmifo_size); + CHECK_EXPECTED_AS_STATUS(activate_action); + actions.emplace_back(activate_action.release()); + } + + for (const auto &edge_layer : context_resources.get_inter_context_layers(HAILO_H2D_STREAM)) { + auto activate_action = ActivateInterContextInputChannelAction::create(edge_layer.channel_id, + edge_layer.layer_info.stream_index, edge_layer.layer_info.nn_stream_config, edge_layer.buffer_info, + edge_layer.layer_info.max_shmifo_size); + CHECK_EXPECTED_AS_STATUS(activate_action); + actions.emplace_back(activate_action.release()); + } + + return HAILO_SUCCESS; +} + +static hailo_status proccess_trigger_new_data_input_action(const ContextSwitchConfigActionPtr &configuration_action, + uint32_t trigger_new_data_from_input_group_start, + uint32_t trigger_new_data_from_input_group_end, + const uint32_t &action_index, + const NetworkGroupMetadata &network_group_metadata, + const ResourcesManager &resources_manager, + ContextResources &context_resources, + uint8_t context_index, + std::vector &processed_configuration_actions, bool is_single_context) +{ + if (trigger_new_data_from_input_group_start == action_index) { + auto status = push_edge_layer_activation_actions(context_resources, processed_configuration_actions); + CHECK_SUCCESS(status); + + if (!is_single_context) { + status = add_change_vdma_to_stream_mapping(network_group_metadata, resources_manager, + context_resources, context_index, processed_configuration_actions); + CHECK_SUCCESS(status); + } + + // DDR buffer info actions need to happen after the edge layer activation actions. + status = add_ddr_buffers_info(processed_configuration_actions, context_resources); + CHECK_SUCCESS(status); + } + + // Add the current action + processed_configuration_actions.emplace_back(configuration_action); + + // At the end of a consecutive group of TriggerNewDataFromDataInput actions, we can trigger the BurstCreditsTask + // in the FW, via StartBurstCreditsTaskAction. + if (trigger_new_data_from_input_group_end == action_index) { + auto start_burst_credits_task_action = StartBurstCreditsTaskAction::create(); + CHECK_EXPECTED_AS_STATUS(start_burst_credits_task_action); + processed_configuration_actions.emplace_back(start_burst_credits_task_action.release()); + } + + return HAILO_SUCCESS; +} + +// At the end of each consecutive group of WriteDataCcwAction, a FetchCfgChannelDescriptorsAction is added. +static hailo_status add_fetch_config_actions(std::vector &configuration_actions, + std::vector &config_resources, bool support_pre_fetch) +{ + const auto repeated_indexes = get_repreated_actions_boundary_indices(configuration_actions); + const auto end_indexes_of_write_ccws = get_end_indexes_of_action_type(configuration_actions, + repeated_indexes, ContextSwitchConfigAction::Type::WriteDataCcw); + + std::set pending_config_stream_indexes; + std::vector total_ccw_bursts(config_resources.size(), 0); + std::vector processed_configuration_actions; + for (uint32_t action_index = 0; action_index < configuration_actions.size(); action_index++) { + const auto &configuration_action = configuration_actions[action_index]; + if (ContextSwitchConfigAction::Type::WriteDataCcw == configuration_action->get_type()) { + auto status = proccess_write_ccw_action(configuration_action, config_resources, pending_config_stream_indexes, + total_ccw_bursts, end_indexes_of_write_ccws, action_index, support_pre_fetch, processed_configuration_actions); + CHECK_SUCCESS(status); + } else { + // Add the current action + processed_configuration_actions.emplace_back(configuration_action); + } + } + + // Replace the original configuration actions with the processed ones. + configuration_actions = processed_configuration_actions; + + return HAILO_SUCCESS; +} + +// Push activate config channels in the beginning of the context, and deactivation on end of context. +static hailo_status add_config_channel_activation_actions(std::vector &actions, + const std::vector &config_resources) +{ + std::vector processed_actions; + const size_t new_actions_count = 2 * config_resources.size(); + processed_actions.reserve(actions.size() + new_actions_count); + + for (uint8_t config_stream_index = 0; config_stream_index < config_resources.size(); config_stream_index++) { + const auto &config_buffer = config_resources[config_stream_index]; + auto activate_action = ActivateConfigChannelAction::create(config_stream_index, config_buffer.channel_id(), + config_buffer.get_host_buffer_info()); + CHECK_EXPECTED_AS_STATUS(activate_action); + processed_actions.push_back(activate_action.release()); + } + + processed_actions.insert(processed_actions.end(), actions.begin(), actions.end()); + + for (uint8_t config_stream_index = 0; config_stream_index < config_resources.size(); config_stream_index++) { + const auto &config_buffer = config_resources[config_stream_index]; + auto deactivate_action = DeactivateConfigChannelAction::create(config_stream_index, config_buffer.channel_id()); + CHECK_EXPECTED_AS_STATUS(deactivate_action); + processed_actions.push_back(deactivate_action.release()); + } + + actions = processed_actions; + return HAILO_SUCCESS; +} + +// For any context with edge layers (the preliminary context when in preliminary_run_asap mode or dynamic contexts), +// we need to add the following: +// * Activate*Channel actions (activation order is documented in push_edge_layer_activation_actions) +// * ChangeVdmaToStreamMapping for each boundary stream in the network group (even for boundaries not activated in the +// current context). +// * DdrPairInfoActions for each ddr, followed by StartDdrBufferingTaskAction. +// * TriggerNewDataFromDataInput for each input layer (inter context/ boundary) in the context. This action is given +// from the HEF. +// * Finally StartBurstCreditsTaskAction +static hailo_status handle_edge_layer_activation_actions(std::vector &configuration_actions, + const NetworkGroupMetadata &network_group_metadata, + const ResourcesManager &resources_manager, ContextResources &context_resources, uint8_t context_index, + bool is_preliminary_context, bool is_first_operation, bool is_single_context) +{ + if (is_preliminary_context && !resources_manager.get_supported_features().preliminary_run_asap) { + // Nothing to do - no edge layers in the preliminary context if not running in preliminary_run_asap mode. + return HAILO_SUCCESS; + } + if (!is_preliminary_context && !is_first_operation) { + // Nothing to do - edge layers in dynamic contexts only appear in the first operation. + return HAILO_SUCCESS; + } + + const auto repeated_indexes = get_repreated_actions_boundary_indices(configuration_actions); + const auto trigger_new_data_from_input_group_indexes = get_indexes_of_action_type( + configuration_actions, repeated_indexes, ContextSwitchConfigAction::Type::TriggerNewDataFromDataInput); + CHECK(trigger_new_data_from_input_group_indexes.size() == 1, HAILO_INTERNAL_FAILURE, + "Expected only one group of TriggerNewDataFromDataInput actions"); + const auto trigger_new_data_from_input_group_start = trigger_new_data_from_input_group_indexes.cbegin()->first; + const auto trigger_new_data_from_input_group_end = trigger_new_data_from_input_group_indexes.cbegin()->second; + + std::vector processed_configuration_actions; + for (uint32_t action_index = 0; action_index < configuration_actions.size(); action_index++) { + const auto &configuration_action = configuration_actions[action_index]; + if (ContextSwitchConfigAction::Type::TriggerNewDataFromDataInput == configuration_action->get_type()) { + auto status = proccess_trigger_new_data_input_action(configuration_action, + trigger_new_data_from_input_group_start, trigger_new_data_from_input_group_end, action_index, + network_group_metadata, resources_manager, context_resources, context_index, processed_configuration_actions, is_single_context); + CHECK_SUCCESS(status); + } else { + // Add the current action + processed_configuration_actions.emplace_back(configuration_action); + } + } + + // Replace the original configuration actions with the processed ones. + configuration_actions = processed_configuration_actions; + + return HAILO_SUCCESS; +} + +// If groups of consecutive actions can be "merged" as repeated actions (saving room the FW's +// action list) a RepeatedAction is placed before the relevant actions. +// See also: CONTEXT_SWITCH_DEFS__repeated_action_header_t's documenting in context_switch_defs.h. +static hailo_status handle_repeated_actions(std::vector &configuration_actions) +{ + const auto repeated_indexes = get_repreated_actions_boundary_indices(configuration_actions); + const auto start_indexes_of_repeated_actions = get_start_indexes_of_repeated_actions( + configuration_actions, repeated_indexes); + + std::vector processed_configuration_actions; + processed_configuration_actions.reserve(configuration_actions.size() + start_indexes_of_repeated_actions.size()); + + uint32_t action_index = 0; + while (action_index < configuration_actions.size()){ + if (contains(start_indexes_of_repeated_actions, action_index)) { + // A group of actions can be "merged" as repeated actions. + // Add a RepeatedAction + const auto num_repeated = start_indexes_of_repeated_actions.at(action_index); + + std::vector repeated_block; + repeated_block.reserve(num_repeated); + for (uint32_t repeated_offset = 0; repeated_offset < num_repeated; repeated_offset++) { + repeated_block.emplace_back(configuration_actions[action_index]); + action_index++; + } + + auto repeated_header_action = RepeatedAction::create(std::move(repeated_block)); + CHECK_EXPECTED_AS_STATUS(repeated_header_action); + processed_configuration_actions.emplace_back(repeated_header_action.value()); + } + else { + processed_configuration_actions.emplace_back(configuration_actions[action_index]); + action_index++; + } + } + + // Replace the original configuration actions with the processed ones. + configuration_actions = processed_configuration_actions; + + return HAILO_SUCCESS; +} + +static bool is_mercury_device_type(const ProtoHEFHwArch &hw_arch) +{ + /* TODO - HRT-5067 - use one hw_arch for mercury */ + return (PROTO__HW_ARCH__MERCURY == hw_arch) || (PROTO__HW_ARCH__GINGER == hw_arch) || + (PROTO__HW_ARCH__LAVENDER == hw_arch); +} + +static Expected> process_operation(const ContextSwitchOperation &operation, + const NetworkGroupMetadata &network_group_metadata, + const ProtoHEFHwArch &hw_arch, uint8_t context_index, bool is_preliminary_context, + bool is_first_operation, bool is_single_context, std::vector &config_resources, + ResourcesManager &resources_manager, + ContextResources &context_resources) +{ + auto configuration_actions = operation.actions(); + + // Next, we process the actions from the HEF. The resulting vector contains the configuration actions to be + // executed in chronological order. + const auto support_pre_fetch = is_mercury_device_type(hw_arch); + auto status = add_fetch_config_actions(configuration_actions, config_resources, support_pre_fetch); + CHECK_SUCCESS_AS_EXPECTED(status); + + status = handle_edge_layer_activation_actions(configuration_actions, network_group_metadata, resources_manager, + context_resources, context_index, is_preliminary_context, is_first_operation, is_single_context); + CHECK_SUCCESS_AS_EXPECTED(status); + + status = handle_repeated_actions(configuration_actions); + CHECK_SUCCESS_AS_EXPECTED(status); + + return configuration_actions; +} + +static hailo_status write_action_list(const ContextResources & context_resources, ContextSwitchBufferBuilder &builder, + const std::vector &actions) +{ + for (const auto &action : actions) { + auto action_buffers = action->serialize(context_resources); + CHECK_EXPECTED_AS_STATUS(action_buffers); + + for (auto &action_buffer : action_buffers.value()) { + builder.write_action(MemoryView(action_buffer)); + } + } + + return HAILO_SUCCESS; +} + +static hailo_status add_edge_layer_end_of_context_actions(const ContextResources &context_resources, + std::vector &actions) +{ + + for (const auto &edge_layer : context_resources.get_boundary_layers()) { + const bool is_inter_context = false; + // Validate boundary channels of current context. + auto validate_action = ValidateChannelAction::create(edge_layer.channel_id, edge_layer.layer_info.direction, + is_inter_context, static_cast(edge_layer.buffer_info.buffer_type), + edge_layer.layer_info.max_shmifo_size); + CHECK_EXPECTED_AS_STATUS(validate_action); + actions.push_back(validate_action.release()); + } + + for (const auto &edge_layer : context_resources.get_inter_context_layers()) { + const bool is_inter_context = true; + auto deactivate_action = DeactivateChannelAction::create(edge_layer.channel_id, edge_layer.layer_info.direction, + is_inter_context, static_cast(edge_layer.buffer_info.buffer_type), + edge_layer.layer_info.max_shmifo_size); + CHECK_EXPECTED_AS_STATUS(deactivate_action); + actions.push_back(deactivate_action.release()); + } + + for (const auto &edge_layer : context_resources.get_ddr_channel_layers()) { + const bool is_inter_context = false; + auto deactivate_action = DeactivateChannelAction::create(edge_layer.channel_id, edge_layer.layer_info.direction, + is_inter_context, static_cast(edge_layer.buffer_info.buffer_type), + edge_layer.layer_info.max_shmifo_size); + CHECK_EXPECTED_AS_STATUS(deactivate_action); + actions.push_back(deactivate_action.release()); + } + + return HAILO_SUCCESS; +} + +static hailo_status fill_context_recipes_for_multi_context(const ProtoHEFHwArch &hw_arch, + ContextResources &context_resources, ResourcesManager &resources_manager, + uint8_t context_index, const NetworkGroupMetadata &network_group_metadata, const ContextMetadata &context_metadata, + bool is_single_context) +{ + hailo_status status = HAILO_UNINITIALIZED; + + // Add edge layers mapping + status = parse_and_fill_edge_layers_mapping(context_resources, context_metadata, resources_manager); + CHECK_SUCCESS(status); + + // Parse context + bool first_operation = true; + std::vector actions; + for (const auto &operation : context_metadata.get_operations()) { + static const auto NOT_PRELIMINARY_CONTEXT = false; + auto new_actions = process_operation(operation, network_group_metadata, hw_arch, context_index, NOT_PRELIMINARY_CONTEXT, + first_operation, is_single_context, context_resources.get_config_buffers(), resources_manager, + context_resources); + CHECK_EXPECTED_AS_STATUS(new_actions); + + actions.insert(actions.end(), new_actions->begin(), new_actions->end()); + first_operation = false; + } + + status = add_config_channel_activation_actions(actions, context_resources.get_config_buffers()); + CHECK_SUCCESS(status); + + if (is_single_context) { + // Single context network must wait for network group change event after they finish the dynamic context. + auto wait_action = WaitForNetworkGroupChangeAction::create(); + CHECK_EXPECTED_AS_STATUS(wait_action); + actions.emplace_back(wait_action.release()); + } + else { + status = add_edge_layer_end_of_context_actions(context_resources, actions); + } + + return write_action_list(context_resources, context_resources.builder(), actions); +} + +static hailo_status create_boundary_channels(ResourcesManager &resources_manager, + NetworkGroupMetadata &network_group_metadata) +{ + for (const auto &layer_info : network_group_metadata.get_all_layer_infos()) { + auto status = resources_manager.create_boundary_vdma_channel(layer_info); + CHECK_SUCCESS(status); + } + return HAILO_SUCCESS; +} + +static hailo_status fill_activation_config_recepies_for_multi_context( + ContextResources &context_resources, ResourcesManager &resources_manager, + std::shared_ptr network_group_metadata) +{ + auto hw_consts = Control::get_hw_consts(resources_manager.get_device()); + CHECK_EXPECTED_AS_STATUS(hw_consts); + const bool should_optimize_credits = hw_consts->should_optimize_credits && + (HAILO_POWER_MODE_PERFORMANCE == resources_manager.get_power_mode()); + + for (const auto &layer_info : network_group_metadata->get_output_layer_infos()){ + auto status = fill_boundary_output_layer(context_resources, resources_manager, layer_info, *hw_consts, + should_optimize_credits); + CHECK_SUCCESS(status); + } + + for (const auto &layer_info : network_group_metadata->get_input_layer_infos()) { + auto status = fill_boundary_input_layer(context_resources, resources_manager, layer_info, *hw_consts, + should_optimize_credits); + CHECK_SUCCESS(status); + } + + auto status = context_resources.validate_edge_layers(); + CHECK_SUCCESS(status); + + std::vector actions; + for (const auto &edge_layer : context_resources.get_boundary_layers()) { + auto action = edge_layer.layer_info.direction == HAILO_H2D_STREAM ? + OpenBoundaryInputChannelAction::create(edge_layer.channel_id, edge_layer.buffer_info) : + OpenBoundaryOutputChannelAction::create(edge_layer.channel_id, edge_layer.buffer_info); + CHECK_EXPECTED_AS_STATUS(action); + actions.emplace_back(action.release()); + } + + return write_action_list(context_resources, context_resources.builder(), actions); +} + +static hailo_status fill_batch_switching_context_config_recepies_for_multi_context( + ContextResources &context_resources, const NetworkGroupMetadata &network_group_metadata) +{ + std::vector actions; + + // We need to reset the ddr buffering task when we change the batch_size (since it depends on the batch_size param) + auto reset_ddr_action = ResetDdrBufferingTaskAction::create(); + CHECK_EXPECTED_AS_STATUS(reset_ddr_action); + actions.emplace_back(reset_ddr_action.release()); + + // We need to re-enable all the lcus of the first context since some of their config regs are batch dependent. + // => We'll filter out all of the "enable lcu" actions from the preliminary context + static const std::set BATCH_SWITCHING_ACTIONS = { + ContextSwitchConfigAction::Type::EnableLcuDefault, + ContextSwitchConfigAction::Type::EnableLcuNonDefault + }; + for (const auto &operation : network_group_metadata.preliminary_context().get_operations()) { + auto operation_actions = operation.get_actions_of_type(BATCH_SWITCHING_ACTIONS); + + // Allowing repeated actions + auto status = handle_repeated_actions(operation_actions); + CHECK_SUCCESS(status); + + actions.insert(actions.end(), operation_actions.begin(), operation_actions.end()); + } + + return write_action_list(context_resources, context_resources.builder(), actions); +} + +static hailo_status fill_preliminary_config_recepies_for_multi_context(const ProtoHEFHwArch &hw_arch, + ContextResources &context_resources, ResourcesManager &resources_manager, + std::shared_ptr network_group_metadata, const PreliminaryContextMetadata &preliminary_context, + bool is_single_context) +{ + + if (resources_manager.get_supported_features().preliminary_run_asap) { + // Add edge layers mapping (only preliminary_run_asap networks have edge layers in the preliminary context) + static const auto PRELIMINARY_CONTEXT_INDEX = 0; + assert(PRELIMINARY_CONTEXT_INDEX < network_group_metadata->dynamic_contexts().size()); + auto status = parse_and_fill_edge_layers_mapping(context_resources, + network_group_metadata->dynamic_contexts()[PRELIMINARY_CONTEXT_INDEX], resources_manager); + CHECK_SUCCESS(status); + } + + // Parse preliminary config + std::vector actions; + bool first_operation = true; + for (const auto &operation : preliminary_context.get_operations()) { + static const auto PRELIMINARY_CONTEXT_INDEX = 0; // First context in the hef + static const auto PRELIMINARY_CONTEXT = true; + auto new_actions = process_operation(operation, *network_group_metadata, hw_arch, PRELIMINARY_CONTEXT_INDEX, + PRELIMINARY_CONTEXT, first_operation, is_single_context, context_resources.get_config_buffers(), resources_manager, + context_resources); + CHECK_EXPECTED_AS_STATUS(new_actions); + + actions.insert(actions.end(), new_actions->begin(), new_actions->end()); + first_operation = false; + } + + auto status = add_config_channel_activation_actions(actions, context_resources.get_config_buffers()); + CHECK_SUCCESS(status); + + return write_action_list(context_resources, context_resources.builder(), actions); +} + + + +Expected> ResourcesManagerBuilder::build(uint8_t net_group_index, VdmaDevice &device, + HailoRTDriver &driver, const ConfigureNetworkParams &config_params, + std::shared_ptr network_group_metadata, const ProtoHEFHwArch &hw_arch) +{ + const auto num_contexts = network_group_metadata->dynamic_contexts().size() + + CONTROL_PROTOCOL__CONTEXT_SWITCH_NUMBER_OF_NON_DYNAMIC_CONTEXTS; + CHECK_AS_EXPECTED(CONTROL_PROTOCOL__MAX_CONTEXTS_PER_NETWORK_GROUP >= num_contexts, HAILO_INVALID_HEF, + "App '{}' contains more contexts than allowed ({} > {})", + network_group_metadata->network_group_name(), num_contexts, CONTROL_PROTOCOL__MAX_CONTEXTS_PER_NETWORK_GROUP); + + for (auto &network_params : config_params.network_params_by_name) { + CHECK(HAILO_MAX_BATCH_SIZE >= network_params.second.batch_size, make_unexpected(HAILO_INVALID_ARGUMENT), + "Given batch size ({}) for network group {}, network {} is bigger than max allowed ({})", network_params.second.batch_size, + network_group_metadata->network_group_name(), network_params.first, HAILO_MAX_BATCH_SIZE); + } + + auto resources_manager = ResourcesManager::create(device, driver, config_params, network_group_metadata, + net_group_index); + CHECK_EXPECTED(resources_manager); + + auto status = create_boundary_channels(resources_manager.value(), *network_group_metadata); + CHECK_SUCCESS_AS_EXPECTED(status); + + auto activation_context = resources_manager->add_new_context(CONTROL_PROTOCOL__CONTEXT_SWITCH_CONTEXT_TYPE_ACTIVATION); + CHECK_EXPECTED(activation_context); + status = fill_activation_config_recepies_for_multi_context(activation_context.value().get(), + resources_manager.value(), network_group_metadata); + CHECK_SUCCESS_AS_EXPECTED(status); + + auto batch_switching_context = resources_manager->add_new_context(CONTROL_PROTOCOL__CONTEXT_SWITCH_CONTEXT_TYPE_BATCH_SWITCHING); + CHECK_EXPECTED(batch_switching_context); + status = fill_batch_switching_context_config_recepies_for_multi_context(batch_switching_context.value().get(), + *network_group_metadata); + CHECK_SUCCESS_AS_EXPECTED(status); + + const bool is_single_context = network_group_metadata->dynamic_contexts().size() == 1; + + auto preliminary_context = resources_manager->add_new_context(CONTROL_PROTOCOL__CONTEXT_SWITCH_CONTEXT_TYPE_PRELIMINARY, + network_group_metadata->preliminary_context().config_buffers_info()); + CHECK_EXPECTED(preliminary_context); + status = fill_preliminary_config_recepies_for_multi_context(hw_arch, preliminary_context.value().get(), + resources_manager.value(), network_group_metadata, network_group_metadata->preliminary_context(), is_single_context); + CHECK_SUCCESS_AS_EXPECTED(status); + + uint8_t context_index = 0; + for (const auto &context_metadata : network_group_metadata->dynamic_contexts()) { + auto new_context = resources_manager->add_new_context(CONTROL_PROTOCOL__CONTEXT_SWITCH_CONTEXT_TYPE_DYNAMIC, + context_metadata.config_buffers_info()); + CHECK_EXPECTED(new_context); + + status = fill_context_recipes_for_multi_context(hw_arch, new_context.value().get(), resources_manager.value(), + context_index, *network_group_metadata, + context_metadata, is_single_context); + CHECK_SUCCESS_AS_EXPECTED(status); + + context_index++; + } + + status = resources_manager->create_internal_vdma_channels(); + CHECK_SUCCESS_AS_EXPECTED(status); + + status = resources_manager->configure(); + CHECK_SUCCESS_AS_EXPECTED(status); + + auto resources_manager_ptr = make_shared_nothrow(resources_manager.release()); + CHECK_NOT_NULL_AS_EXPECTED(resources_manager_ptr, HAILO_OUT_OF_HOST_MEMORY); + + return resources_manager_ptr; +} + +} /* namespace hailort */ diff --git a/hailort/libhailort/src/context_switch/resource_manager_builder.hpp b/hailort/libhailort/src/context_switch/resource_manager_builder.hpp new file mode 100644 index 0000000..4ce2f26 --- /dev/null +++ b/hailort/libhailort/src/context_switch/resource_manager_builder.hpp @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2022 Hailo Technologies Ltd. All rights reserved. + * Distributed under the MIT license (https://opensource.org/licenses/MIT) +**/ +/** + * @file resource_manager_builder.hpp + * @brief Builds a ResourcesManager object for the given CoreOp. + **/ + +#ifndef _HAILO_RESOURCE_MANAGER_BUILDER_HPP_ +#define _HAILO_RESOURCE_MANAGER_BUILDER_HPP_ + +#include "hef_internal.hpp" +#include "context_switch/multi_context/resource_manager.hpp" + + +namespace hailort +{ + +class ResourcesManagerBuilder final { +public: + ResourcesManagerBuilder() = delete; + + /* TODO HRT-5067 - work with hailo_device_architecture_t instead of ProtoHEFHwArch */ + static Expected> build(uint8_t net_group_index, VdmaDevice &device, + HailoRTDriver &driver, const ConfigureNetworkParams &config_params, + std::shared_ptr network_group_metadata, const ProtoHEFHwArch &hw_arch); + +}; + +} /* namespace hailort */ + +#endif /* _HAILO_RESOURCE_MANAGER_BUILDER_HPP_ */ diff --git a/hailort/libhailort/src/context_switch/single_context/hcp_config_activated_network_group.hpp b/hailort/libhailort/src/context_switch/single_context/hcp_config_activated_network_group.hpp index 4393f3d..2b058e3 100644 --- a/hailort/libhailort/src/context_switch/single_context/hcp_config_activated_network_group.hpp +++ b/hailort/libhailort/src/context_switch/single_context/hcp_config_activated_network_group.hpp @@ -29,19 +29,17 @@ struct WriteMemoryInfo Buffer data; }; -class HcpConfigActivatedNetworkGroup; -using HcpConfigActiveAppHolder = ActiveNetworkGroupHolder; - class HcpConfigActivatedNetworkGroup : public ActivatedNetworkGroupBase { public: static Expected create(Device &device, std::vector &config, const std::string &network_group_name, const hailo_activate_network_group_params_t &network_group_params, - std::map> &input_streams, - std::map> &output_streams, - HcpConfigActiveAppHolder &active_net_group_holder, - hailo_power_mode_t power_mode, EventPtr network_group_activated_event); + std::map> &input_streams, + std::map> &output_streams, + ActiveNetGroupHolder &active_net_group_holder, + hailo_power_mode_t power_mode, EventPtr network_group_activated_event, + ConfiguredNetworkGroupBase &network_group); virtual ~HcpConfigActivatedNetworkGroup(); HcpConfigActivatedNetworkGroup(const HcpConfigActivatedNetworkGroup &) = delete; @@ -67,14 +65,15 @@ class HcpConfigActivatedNetworkGroup : public ActivatedNetworkGroupBase } private: - HcpConfigActivatedNetworkGroup(Device &device, HcpConfigActiveAppHolder &active_net_group_holder, + HcpConfigActivatedNetworkGroup(Device &device, ActiveNetGroupHolder &active_net_group_holder, const std::string &network_group_name, const hailo_activate_network_group_params_t &network_group_params, - std::map> &input_streams, - std::map> &output_streams, - hailo_power_mode_t power_mode, EventPtr &&network_group_activated_event, hailo_status &status); + std::map> &input_streams, + std::map> &output_streams, + hailo_power_mode_t power_mode, EventPtr &&network_group_activated_event, + ConfiguredNetworkGroupBase &network_group, hailo_status &status); - HcpConfigActiveAppHolder &m_active_net_group_holder; + ActiveNetGroupHolder &m_active_net_group_holder; bool m_is_active; hailo_power_mode_t m_power_mode; Device &m_device; diff --git a/hailort/libhailort/src/context_switch/single_context/hcp_config_manager.hpp b/hailort/libhailort/src/context_switch/single_context/hcp_config_manager.hpp deleted file mode 100644 index 8cd0b5d..0000000 --- a/hailort/libhailort/src/context_switch/single_context/hcp_config_manager.hpp +++ /dev/null @@ -1,53 +0,0 @@ -/** - * Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved. - * Distributed under the MIT license (https://opensource.org/licenses/MIT) - **/ -/** - * @file hcp_config_manager.hpp - * @brief Manager of HEF parsing for control-configured network groups (Pcie and Etherent support) - * - * - **/ - -#ifndef HAILO_HCP_CONFIG_MANAGER_HPP_ -#define HAILO_HCP_CONFIG_MANAGER_HPP_ - -#include "context_switch/config_manager.hpp" -#include "context_switch/network_group_wrapper.hpp" -#include "context_switch/single_context/hcp_config_network_group.hpp" -#include "hailo/hailort.h" -#include "hailo/device.hpp" -#include "hailo/expected.hpp" -#include "common/utils.hpp" - -#include -#include -#include - -namespace hailort -{ - -class HcpConfigManager : public ConfigManager { -public: - HcpConfigManager(Device &device) : m_device(device) {} - virtual ~HcpConfigManager() = default; - virtual ConfigManagerType get_manager_type(); - - virtual Expected add_hef(Hef &hef, const NetworkGroupsParamsMap &configure_params); - - HcpConfigManager(const HcpConfigManager &other) = delete; - HcpConfigManager &operator=(const HcpConfigManager &other) = delete; - HcpConfigManager &operator=(HcpConfigManager &&other) = delete; - HcpConfigManager(HcpConfigManager &&other) noexcept = default; - -private: - // TODO: (SDK-16665) Dont need is_active flag for dtor? - std::vector> m_net_groups; - std::vector> m_net_group_wrappers; - Device &m_device; - HcpConfigActiveAppHolder m_active_net_group_holder; -}; - -} /* namespace hailort */ - -#endif /* HAILO_HCP_CONFIG_MANAGER_HPP_ */ diff --git a/hailort/libhailort/src/context_switch/single_context/hcp_config_network_group.hpp b/hailort/libhailort/src/context_switch/single_context/hcp_config_network_group.hpp index 2b24ba6..7645735 100644 --- a/hailort/libhailort/src/context_switch/single_context/hcp_config_network_group.hpp +++ b/hailort/libhailort/src/context_switch/single_context/hcp_config_network_group.hpp @@ -25,17 +25,15 @@ namespace hailort { -using HcpConfigActiveAppHolder = ActiveNetworkGroupHolder; - class HcpConfigNetworkGroup : public ConfiguredNetworkGroupBase { public: HcpConfigNetworkGroup( - Device &device, HcpConfigActiveAppHolder &active_net_group_holder, std::vector &&config, - const ConfigureNetworkParams &config_params, uint8_t net_group_index, - NetworkGroupMetadata &&network_group_metadata, hailo_status &status); + Device &device, ActiveNetGroupHolder &active_net_group_holder, std::vector &&config, + const ConfigureNetworkParams &config_params, NetworkGroupMetadata &&network_group_metadata, hailo_status &status, + std::vector> &&net_flow_ops); - virtual Expected> activate_impl( + virtual Expected> create_activated_network_group( const hailo_activate_network_group_params_t &network_group_params, uint16_t dynamic_batch_size) override; virtual Expected get_default_streams_interface() override; @@ -45,6 +43,9 @@ public: virtual hailo_status set_scheduler_timeout(const std::chrono::milliseconds &timeout, const std::string &network_name) override; virtual hailo_status set_scheduler_threshold(uint32_t threshold, const std::string &network_name) override; + virtual hailo_status activate_impl(uint16_t dynamic_batch_size) override; + virtual hailo_status deactivate_impl() override; + virtual ~HcpConfigNetworkGroup() = default; HcpConfigNetworkGroup(const HcpConfigNetworkGroup &other) = delete; HcpConfigNetworkGroup &operator=(const HcpConfigNetworkGroup &other) = delete; @@ -55,7 +56,7 @@ public: private: std::vector m_config; - HcpConfigActiveAppHolder &m_active_net_group_holder; + ActiveNetGroupHolder &m_active_net_group_holder; Device &m_device; }; diff --git a/hailort/libhailort/src/context_switch/vdevice_network_group.cpp b/hailort/libhailort/src/context_switch/vdevice_network_group.cpp new file mode 100644 index 0000000..11ff46c --- /dev/null +++ b/hailort/libhailort/src/context_switch/vdevice_network_group.cpp @@ -0,0 +1,368 @@ +/** + * Copyright (c) 2022 Hailo Technologies Ltd. All rights reserved. + * Distributed under the MIT license (https://opensource.org/licenses/MIT) + **/ +/** + * @file vdevice_network_group.cpp + * @brief: Network Group Wrapper + **/ + +#include "vdevice_network_group.hpp" +#include "vdevice_stream.hpp" +#include "vdevice_stream_multiplexer_wrapper.hpp" +#include "vstream_internal.hpp" +#include "tracer_macros.hpp" + +namespace hailort +{ + +Expected> VDeviceActivatedNetworkGroup::create( + std::vector> configured_network_groups, + std::map> &input_streams, + std::map> &output_streams, + const hailo_activate_network_group_params_t &network_group_params, + EventPtr network_group_activated_event, uint16_t dynamic_batch_size, + AccumulatorPtr deactivation_time_accumulator) +{ + auto status = HAILO_UNINITIALIZED; + std::vector> activated_network_groups; + activated_network_groups.reserve(configured_network_groups.size()); + for (auto cng : configured_network_groups) { + auto ang = cng->create_activated_network_group(network_group_params, dynamic_batch_size); + CHECK_EXPECTED(ang); + activated_network_groups.emplace_back(ang.release()); + } + auto ang = VDeviceActivatedNetworkGroup(std::move(activated_network_groups), input_streams, output_streams, + network_group_params, network_group_activated_event, deactivation_time_accumulator, status); + + CHECK_SUCCESS_AS_EXPECTED(status); + std::unique_ptr activated_net_group_ptr = + make_unique_nothrow(std::move(ang)); + CHECK_AS_EXPECTED(nullptr != activated_net_group_ptr, HAILO_OUT_OF_HOST_MEMORY); + + status = network_group_activated_event->signal(); + CHECK_SUCCESS_AS_EXPECTED(status, "Failed to signal network activation event"); + + return activated_net_group_ptr; +} + +const std::string &VDeviceActivatedNetworkGroup::get_network_group_name() const +{ + // network_group_name is same across all NGs + return m_activated_network_groups[0]->get_network_group_name(); +} + +Expected VDeviceActivatedNetworkGroup::get_intermediate_buffer(const IntermediateBufferKey &key) +{ + CHECK_AS_EXPECTED(1 == m_activated_network_groups.size(), HAILO_INVALID_OPERATION, "getting intermediate buffer is supported only over single device"); + return m_activated_network_groups[0]->get_intermediate_buffer(key); +} + +hailo_status VDeviceActivatedNetworkGroup::set_keep_nn_config_during_reset(const bool keep_nn_config_during_reset) +{ + for (auto &activated_network_group : m_activated_network_groups) { + auto status = activated_network_group->set_keep_nn_config_during_reset(keep_nn_config_during_reset); + CHECK_SUCCESS(status); + } + return HAILO_SUCCESS; +} + +VDeviceActivatedNetworkGroup::VDeviceActivatedNetworkGroup(std::vector> &&activated_network_groups, + std::map> &input_streams, std::map> &output_streams, + const hailo_activate_network_group_params_t &network_group_params, EventPtr network_group_activated_event, AccumulatorPtr deactivation_time_accumulator, hailo_status &status) + : ActivatedNetworkGroupBase(network_group_params, input_streams, output_streams, std::move(network_group_activated_event), status), + m_activated_network_groups(std::move(activated_network_groups)), m_should_reset_network_group(true), m_deactivation_time_accumulator(deactivation_time_accumulator) +{ +} + +VDeviceActivatedNetworkGroup::VDeviceActivatedNetworkGroup(VDeviceActivatedNetworkGroup &&other) noexcept : + ActivatedNetworkGroupBase(std::move(other)), + m_activated_network_groups(std::move(other.m_activated_network_groups)), + m_should_reset_network_group(std::exchange(other.m_should_reset_network_group, false)), + m_deactivation_time_accumulator(std::move(other.m_deactivation_time_accumulator)) +{ +} + + +Expected> VDeviceNetworkGroup::create(std::vector> configured_network_group, + NetworkGroupSchedulerWeakPtr network_group_scheduler) +{ + auto status = HAILO_UNINITIALIZED; + std::vector> vdma_config_ngs; + vdma_config_ngs.reserve(configured_network_group.size()); + for (auto &network_group : configured_network_group) { + auto vdma_ng = std::dynamic_pointer_cast(network_group); + assert(nullptr != vdma_ng); + vdma_config_ngs.push_back(vdma_ng); + } + + auto net_flow_ops_copy = vdma_config_ngs[0]->m_net_flow_ops; + + VDeviceNetworkGroup object(std::move(vdma_config_ngs), network_group_scheduler, std::move(net_flow_ops_copy), status); + CHECK_SUCCESS_AS_EXPECTED(status); + + auto obj_ptr = make_shared_nothrow(std::move(object)); + CHECK_NOT_NULL_AS_EXPECTED(obj_ptr, HAILO_OUT_OF_HOST_MEMORY); + + return obj_ptr; +} + +Expected> VDeviceNetworkGroup::duplicate(std::shared_ptr other) +{ + auto status = HAILO_UNINITIALIZED; + auto net_flow_ops_copy = other->m_net_flow_ops; + + VDeviceNetworkGroup object(other->m_configured_network_groups, other->m_network_group_scheduler, std::move(net_flow_ops_copy), status); + CHECK_SUCCESS_AS_EXPECTED(status); + + auto obj_ptr = make_shared_nothrow(std::move(object)); + CHECK_NOT_NULL_AS_EXPECTED(obj_ptr, HAILO_OUT_OF_HOST_MEMORY); + + return obj_ptr; +} + + +VDeviceNetworkGroup::VDeviceNetworkGroup(std::vector> configured_network_group, + NetworkGroupSchedulerWeakPtr network_group_scheduler, std::vector> &&net_flow_ops, hailo_status &status) : + ConfiguredNetworkGroupBase(configured_network_group[0]->m_config_params, + configured_network_group[0]->m_network_group_metadata, std::move(net_flow_ops), status), + m_configured_network_groups(std::move(configured_network_group)), + m_network_group_scheduler(network_group_scheduler), + m_scheduler_handle(INVALID_NETWORK_GROUP_HANDLE), + m_multiplexer_handle(0), + m_multiplexer() +{} + +Expected VDeviceNetworkGroup::get_default_streams_interface() +{ + auto first_streams_interface = m_configured_network_groups[0]->get_default_streams_interface(); + CHECK_EXPECTED(first_streams_interface); +#ifndef NDEBUG + // Check that all physical devices has the same interface + for (auto &network_group : m_configured_network_groups) { + auto iface = network_group->get_default_streams_interface(); + CHECK_EXPECTED(iface); + CHECK_AS_EXPECTED(iface.value() == first_streams_interface.value(), HAILO_INTERNAL_FAILURE, + "Not all default stream interfaces are the same"); + } +#endif + return first_streams_interface; +} + +hailo_status VDeviceNetworkGroup::create_vdevice_streams_from_config_params(std::shared_ptr multiplexer, scheduler_ng_handle_t scheduler_handle) +{ + // TODO - HRT-6931 - raise error on this case + if (((m_config_params.latency & HAILO_LATENCY_MEASURE) == HAILO_LATENCY_MEASURE) && (1 < m_configured_network_groups.size())) { + LOGGER__WARNING("Latency measurement is not supported on more than 1 physical device."); + } + + m_multiplexer = multiplexer; + + for (const auto &stream_parameters_pair : m_config_params.stream_params_by_name) { + switch (stream_parameters_pair.second.direction) { + case HAILO_H2D_STREAM: + { + auto status = create_input_vdevice_stream_from_config_params(stream_parameters_pair.second, + stream_parameters_pair.first, multiplexer, scheduler_handle); + CHECK_SUCCESS(status); + } + break; + case HAILO_D2H_STREAM: + { + auto status = create_output_vdevice_stream_from_config_params(stream_parameters_pair.second, + stream_parameters_pair.first, multiplexer, scheduler_handle); + CHECK_SUCCESS(status); + } + break; + default: + LOGGER__ERROR("stream name {} direction is invalid.", stream_parameters_pair.first); + return HAILO_INVALID_ARGUMENT; + } + } + + for (const auto &input_stream : m_input_streams) { + auto expected_queue_size = static_cast(*input_stream.second).get_buffer_frames_size(); + CHECK_EXPECTED_AS_STATUS(expected_queue_size); + TRACE(CreateNetworkGroupInputStreamsTrace, "", name(), input_stream.first, (uint32_t)expected_queue_size.value()); + } + for (const auto &output_stream : m_output_streams) { + if (static_cast(*output_stream.second).get_layer_info().format.order == hailo_format_order_t::HAILO_FORMAT_ORDER_HAILO_NMS) { + continue; + } + auto expected_queue_size = static_cast(*output_stream.second).get_buffer_frames_size(); + CHECK_EXPECTED_AS_STATUS(expected_queue_size); + TRACE(CreateNetworkGroupOutputStreamsTrace, "", name(), output_stream.first, (uint32_t)expected_queue_size.value()); + } + + auto status = m_multiplexer->add_network_group_instance(m_multiplexer_handle, *this); + CHECK_SUCCESS(status); + + return HAILO_SUCCESS; +} + +hailo_status VDeviceNetworkGroup::create_input_vdevice_stream_from_config_params(const hailo_stream_parameters_t &stream_params, + const std::string &stream_name, std::shared_ptr multiplexer, scheduler_ng_handle_t scheduler_handle) +{ + auto edge_layer = get_layer_info(stream_name); + CHECK_EXPECTED_AS_STATUS(edge_layer); + + CHECK(HailoRTCommon::is_vdma_stream_interface(stream_params.stream_interface), HAILO_INVALID_OPERATION, + "Stream {} not supported on VDevice usage. {} has {} interface.", stream_name, stream_params.stream_interface); + + std::vector> low_level_streams; + low_level_streams.reserve(m_configured_network_groups.size()); + for (auto &net_group : m_configured_network_groups) { + auto stream = net_group->get_input_stream_by_name(stream_name); + CHECK(stream, HAILO_INTERNAL_FAILURE); + low_level_streams.emplace_back(dynamic_cast(stream.release().get())); + } + auto input_stream = InputVDeviceBaseStream::create(std::move(low_level_streams), edge_layer.value(), + scheduler_handle, m_network_group_activated_event, m_network_group_scheduler); + CHECK_EXPECTED_AS_STATUS(input_stream); + auto input_stream_wrapper = VDeviceInputStreamMultiplexerWrapper::create(input_stream.release(), edge_layer->network_name, multiplexer, scheduler_handle); + CHECK_EXPECTED_AS_STATUS(input_stream_wrapper); + m_input_streams.insert(make_pair(stream_name, input_stream_wrapper.release())); + + return HAILO_SUCCESS; +} + +hailo_status VDeviceNetworkGroup::create_output_vdevice_stream_from_config_params(const hailo_stream_parameters_t &stream_params, + const std::string &stream_name, std::shared_ptr multiplexer, scheduler_ng_handle_t scheduler_handle) +{ + auto edge_layer = get_layer_info(stream_name); + CHECK_EXPECTED_AS_STATUS(edge_layer); + + CHECK(HailoRTCommon::is_vdma_stream_interface(stream_params.stream_interface), HAILO_INVALID_OPERATION, + "Stream {} not supported on VDevice usage. {} has {} interface.", stream_name, stream_params.stream_interface); + + std::vector> low_level_streams; + low_level_streams.reserve(m_configured_network_groups.size()); + for (auto &net_group : m_configured_network_groups) { + auto stream = net_group->get_output_stream_by_name(stream_name); + CHECK(stream, HAILO_INTERNAL_FAILURE); + low_level_streams.emplace_back(dynamic_cast(stream.release().get())); + } + auto output_stream = OutputVDeviceBaseStream::create(std::move(low_level_streams), edge_layer.value(), + scheduler_handle, m_network_group_activated_event, m_network_group_scheduler); + CHECK_EXPECTED_AS_STATUS(output_stream); + auto output_stream_wrapper = VDeviceOutputStreamMultiplexerWrapper::create(output_stream.release(), edge_layer->network_name, multiplexer, scheduler_handle); + CHECK_EXPECTED_AS_STATUS(output_stream_wrapper); + m_output_streams.insert(make_pair(stream_name, output_stream_wrapper.release())); + + return HAILO_SUCCESS; +} + +hailo_status VDeviceNetworkGroup::create_vdevice_streams_from_duplicate(std::shared_ptr other) +{ + // TODO - HRT-6931 - raise error on this case + if (((m_config_params.latency & HAILO_LATENCY_MEASURE) == HAILO_LATENCY_MEASURE) && (1 < m_configured_network_groups.size())) { + LOGGER__WARNING("Latency measurement is not supported on more than 1 physical device."); + } + + m_multiplexer = other->m_multiplexer; + m_multiplexer_handle = other->multiplexer_duplicates_count() + 1; + + for (auto &name_stream_pair : other->m_input_streams) { + auto input_stream = static_cast(name_stream_pair.second.get()); + auto copy = input_stream->clone(m_multiplexer_handle); + CHECK_EXPECTED_AS_STATUS(copy); + + m_input_streams.insert(make_pair(name_stream_pair.first, copy.release())); + } + + for (auto &name_stream_pair : other->m_output_streams) { + auto output_stream = static_cast(name_stream_pair.second.get()); + auto copy = output_stream->clone(m_multiplexer_handle); + CHECK_EXPECTED_AS_STATUS(copy); + + m_output_streams.insert(make_pair(name_stream_pair.first, copy.release())); + } + + auto status = other->m_multiplexer->add_network_group_instance(m_multiplexer_handle, *this); + CHECK_SUCCESS(status); + + return HAILO_SUCCESS; +} + +void VDeviceNetworkGroup::set_network_group_handle(scheduler_ng_handle_t handle) +{ + m_scheduler_handle = handle; +} + +scheduler_ng_handle_t VDeviceNetworkGroup::network_group_handle() const +{ + return m_scheduler_handle; +} + +hailo_status VDeviceNetworkGroup::set_scheduler_timeout(const std::chrono::milliseconds &timeout, const std::string &network_name) +{ + auto network_group_scheduler = m_network_group_scheduler.lock(); + CHECK(network_group_scheduler, HAILO_INVALID_OPERATION, + "Cannot set scheduler timeout for network group {}, as it is configured on a vdevice which does not have scheduling enabled", name()); + if (network_name != HailoRTDefaults::get_network_name(name())) { + CHECK(network_name.empty(), HAILO_NOT_IMPLEMENTED, "Setting scheduler timeout for a specific network is currently not supported"); + } + auto status = network_group_scheduler->set_timeout(m_scheduler_handle, timeout, network_name); + CHECK_SUCCESS(status); + return HAILO_SUCCESS; +} + +hailo_status VDeviceNetworkGroup::set_scheduler_threshold(uint32_t threshold, const std::string &network_name) +{ + auto network_group_scheduler = m_network_group_scheduler.lock(); + CHECK(network_group_scheduler, HAILO_INVALID_OPERATION, + "Cannot set scheduler threshold for network group {}, as it is configured on a vdevice which does not have scheduling enabled", name()); + if (network_name != HailoRTDefaults::get_network_name(name())) { + CHECK(network_name.empty(), HAILO_NOT_IMPLEMENTED, "Setting scheduler threshold for a specific network is currently not supported"); + } + auto status = network_group_scheduler->set_threshold(m_scheduler_handle, threshold, network_name); + CHECK_SUCCESS(status); + return HAILO_SUCCESS; +} + +Expected> VDeviceNetworkGroup::get_latency_meters() +{ + return m_configured_network_groups[0]->get_latency_meters(); +} + +Expected> VDeviceNetworkGroup::get_boundary_vdma_channel_by_stream_name(const std::string &stream_name) +{ + if (1 < m_configured_network_groups.size()) { + LOGGER__ERROR("get_boundary_vdma_channel_by_stream_name function is not supported on more than 1 physical device."); + return make_unexpected(HAILO_INVALID_OPERATION); + } + + return m_configured_network_groups[0]->get_boundary_vdma_channel_by_stream_name(stream_name); +} + +Expected> VDeviceNetworkGroup::create_output_vstreams(const std::map &outputs_params) +{ + auto expected = ConfiguredNetworkGroupBase::create_output_vstreams(outputs_params); + CHECK_EXPECTED(expected); + + if (nullptr == m_multiplexer) { + return expected.release(); + } + + m_multiplexer->set_output_vstreams_names(m_multiplexer_handle, expected.value()); + + for (auto &vstream : expected.value()) { + static_cast(*vstream.m_vstream).set_on_vstream_cant_read_callback([this, name = vstream.name()] () { + m_multiplexer->set_can_output_vstream_read(m_multiplexer_handle, name, false); + }); + static_cast(*vstream.m_vstream).set_on_vstream_can_read_callback([this, name = vstream.name()] () { + m_multiplexer->set_can_output_vstream_read(m_multiplexer_handle, name, true); + }); + } + + return expected.release(); +} + +Expected> VDeviceNetworkGroup::get_network_group_by_device_index(uint32_t device_index) +{ + CHECK_AS_EXPECTED(device_index + +namespace hailort +{ + +class VDeviceActivatedNetworkGroup : public ActivatedNetworkGroupBase +{ +public: + static Expected> create(std::vector> configured_network_groups, + std::map> &input_streams, + std::map> &output_streams, + const hailo_activate_network_group_params_t &network_group_params, EventPtr network_group_activated_event, + uint16_t dynamic_batch_size, AccumulatorPtr deactivation_time_accumulator); + + virtual ~VDeviceActivatedNetworkGroup() + { + if (!m_should_reset_network_group) { + return; + } + const auto start_time = std::chrono::steady_clock::now(); + + m_network_group_activated_event->reset(); + m_activated_network_groups.clear(); + + const auto elapsed_time_ms = std::chrono::duration( + std::chrono::steady_clock::now() - start_time).count(); + LOGGER__INFO("Deactivating took {} ms", elapsed_time_ms); + m_deactivation_time_accumulator->add_data_point(elapsed_time_ms); + } + + VDeviceActivatedNetworkGroup(const VDeviceActivatedNetworkGroup &other) = delete; + VDeviceActivatedNetworkGroup &operator=(const VDeviceActivatedNetworkGroup &other) = delete; + VDeviceActivatedNetworkGroup &operator=(VDeviceActivatedNetworkGroup &&other) = delete; + VDeviceActivatedNetworkGroup(VDeviceActivatedNetworkGroup &&other) noexcept; + + virtual const std::string &get_network_group_name() const override; + virtual Expected get_intermediate_buffer(const IntermediateBufferKey &key) override; + virtual hailo_status set_keep_nn_config_during_reset(const bool keep_nn_config_during_reset) override; + +private: + VDeviceActivatedNetworkGroup( + std::vector> &&activated_network_groups, + std::map> &input_streams, + std::map> &output_streams, + const hailo_activate_network_group_params_t &network_group_params, EventPtr network_group_activated_event, + AccumulatorPtr deactivation_time_accumulator, hailo_status &status); + + std::vector> m_activated_network_groups; + bool m_should_reset_network_group; + AccumulatorPtr m_deactivation_time_accumulator; +}; + +class VDeviceNetworkGroup : public ConfiguredNetworkGroupBase +{ +public: + // TODO (HRT-8751): remove duplicate members from this class or from vdma_config_network _group + static Expected> create(std::vector> configured_network_group, + NetworkGroupSchedulerWeakPtr network_group_scheduler); + + static Expected> duplicate(std::shared_ptr other); + + virtual ~VDeviceNetworkGroup() = default; + VDeviceNetworkGroup(const VDeviceNetworkGroup &other) = delete; + VDeviceNetworkGroup &operator=(const VDeviceNetworkGroup &other) = delete; + VDeviceNetworkGroup &operator=(VDeviceNetworkGroup &&other) = delete; + VDeviceNetworkGroup(VDeviceNetworkGroup &&other) = default; + + // Function from vdma network group + hailo_status create_vdevice_streams_from_config_params(std::shared_ptr multiplexer, + scheduler_ng_handle_t scheduler_handle); + hailo_status create_input_vdevice_stream_from_config_params( + const hailo_stream_parameters_t &stream_params, const std::string &stream_name, + std::shared_ptr multiplexer, scheduler_ng_handle_t scheduler_handle); + hailo_status create_output_vdevice_stream_from_config_params( + const hailo_stream_parameters_t &stream_params, const std::string &stream_name, + std::shared_ptr multiplexer, scheduler_ng_handle_t scheduler_handle); + + hailo_status create_vdevice_streams_from_duplicate(std::shared_ptr other); + + bool equals(const Hef &hef, const std::string &network_group_name) + { + return m_configured_network_groups[0]->equals(hef, network_group_name); + } + + uint32_t multiplexer_duplicates_count() + { + assert(m_multiplexer->instances_count() > 0); + return static_cast(m_multiplexer->instances_count() - 1); + } + + virtual Expected get_default_streams_interface() override; + + virtual Expected> get_latency_meters() override; + virtual Expected> get_boundary_vdma_channel_by_stream_name( + const std::string &stream_name) override; + + void set_network_group_handle(scheduler_ng_handle_t handle); + scheduler_ng_handle_t network_group_handle() const; + virtual hailo_status set_scheduler_timeout(const std::chrono::milliseconds &timeout, const std::string &network_name) override; + virtual hailo_status set_scheduler_threshold(uint32_t threshold, const std::string &network_name) override; + + virtual Expected> create_output_vstreams(const std::map &outputs_params) override; + + virtual hailo_status wait_for_activation(const std::chrono::milliseconds &timeout) override + { + CHECK(!m_network_group_scheduler.lock(), HAILO_INVALID_OPERATION, + "Waiting for network group activation is not allowed when the network group scheduler is active!"); + + return m_network_group_activated_event->wait(timeout); + } + + virtual hailo_status activate_impl(uint16_t /*dynamic_batch_size*/) override + { + return HAILO_INTERNAL_FAILURE; + } + + virtual hailo_status deactivate_impl() override + { + return HAILO_INTERNAL_FAILURE; + } + + virtual Expected> create_activated_network_group( + const hailo_activate_network_group_params_t &network_group_params, uint16_t dynamic_batch_size) override + { + auto start_time = std::chrono::steady_clock::now(); + + CHECK_AS_EXPECTED(!m_network_group_scheduler.lock(), HAILO_INVALID_OPERATION, + "Manually activating a network group is not allowed when the network group scheduler is active!"); + + auto res = VDeviceActivatedNetworkGroup::create(m_configured_network_groups, m_input_streams, m_output_streams, + network_group_params, m_network_group_activated_event, dynamic_batch_size, m_deactivation_time_accumulator); + const auto elapsed_time_ms = std::chrono::duration( + std::chrono::steady_clock::now() - start_time).count(); + CHECK_EXPECTED(res); + + LOGGER__INFO("Activating {} on VDevice took {} milliseconds. Note that the function is asynchronous and" + " thus the network is not fully activated yet.", name(), elapsed_time_ms); + m_activation_time_accumulator->add_data_point(elapsed_time_ms); + + return res; + } + + Expected> get_network_group_by_device_index(uint32_t device_index); + +private: + VDeviceNetworkGroup(std::vector> configured_network_group, + NetworkGroupSchedulerWeakPtr network_group_scheduler, std::vector> &&net_flow_ops, + hailo_status &status); + + std::vector> m_configured_network_groups; + NetworkGroupSchedulerWeakPtr m_network_group_scheduler; + scheduler_ng_handle_t m_scheduler_handle; + multiplexer_ng_handle_t m_multiplexer_handle; + std::shared_ptr m_multiplexer; +}; + +} + +#endif /* _HAILO_VDEVICE_NETWORK_GROUP_WRAPPER_HPP_ */ \ No newline at end of file diff --git a/hailort/libhailort/src/context_switch/vdma_config_activated_network_group.cpp b/hailort/libhailort/src/context_switch/vdma_config_activated_network_group.cpp index 9344556..a7e8a6e 100644 --- a/hailort/libhailort/src/context_switch/vdma_config_activated_network_group.cpp +++ b/hailort/libhailort/src/context_switch/vdma_config_activated_network_group.cpp @@ -15,15 +15,16 @@ namespace hailort { Expected VdmaConfigActivatedNetworkGroup::create( - VdmaConfigActiveAppHolder &active_net_group_holder, + ActiveNetGroupHolder &active_net_group_holder, const std::string &network_group_name, - std::vector> resources_managers, + std::shared_ptr resources_manager, const hailo_activate_network_group_params_t &network_group_params, uint16_t dynamic_batch_size, - std::map> &input_streams, - std::map> &output_streams, + std::map> &input_streams, + std::map> &output_streams, EventPtr network_group_activated_event, - AccumulatorPtr deactivation_time_accumulator) + AccumulatorPtr deactivation_time_accumulator, + ConfiguredNetworkGroupBase &network_group) { CHECK(!active_net_group_holder.is_any_active(), make_unexpected(HAILO_INVALID_OPERATION), "network group is currently active. You must deactivate before activating another network_group"); @@ -32,8 +33,8 @@ Expected VdmaConfigActivatedNetworkGroup::creat auto status = HAILO_UNINITIALIZED; VdmaConfigActivatedNetworkGroup object(network_group_name, network_group_params, dynamic_batch_size, input_streams, output_streams, - std::move(resources_managers), active_net_group_holder, std::move(network_group_activated_event), - deactivation_time_accumulator, status); + std::move(resources_manager), active_net_group_holder, std::move(network_group_activated_event), + deactivation_time_accumulator, network_group, status); CHECK_SUCCESS_AS_EXPECTED(status); return object; @@ -43,21 +44,20 @@ VdmaConfigActivatedNetworkGroup::VdmaConfigActivatedNetworkGroup( const std::string &network_group_name, const hailo_activate_network_group_params_t &network_group_params, uint16_t dynamic_batch_size, - std::map> &input_streams, - std::map> &output_streams, - std::vector> &&resources_managers, - VdmaConfigActiveAppHolder &active_net_group_holder, + std::map> &input_streams, + std::map> &output_streams, + std::shared_ptr &&resources_manager, + ActiveNetGroupHolder &active_net_group_holder, EventPtr &&network_group_activated_event, AccumulatorPtr deactivation_time_accumulator, + ConfiguredNetworkGroupBase &network_group, hailo_status &status) : - ActivatedNetworkGroupBase(network_group_params, dynamic_batch_size, input_streams, - output_streams, std::move(network_group_activated_event), status), + ActivatedNetworkGroupBase(network_group_params, input_streams, output_streams, + std::move(network_group_activated_event), status), m_network_group_name(network_group_name), m_should_reset_network_group(true), m_active_net_group_holder(active_net_group_holder), - m_resources_managers(std::move(resources_managers)), - m_ddr_send_threads(), - m_ddr_recv_threads(), + m_resources_manager(std::move(resources_manager)), m_deactivation_time_accumulator(deactivation_time_accumulator), m_keep_nn_config_during_reset(false) { @@ -65,28 +65,12 @@ VdmaConfigActivatedNetworkGroup::VdmaConfigActivatedNetworkGroup( if (HAILO_SUCCESS != status) { return; } - m_active_net_group_holder.set(*this); - - for (auto &resources_manager : m_resources_managers) { - status = resources_manager->register_fw_managed_vdma_channels(); - if (HAILO_SUCCESS != status) { - LOGGER__ERROR("Failed to start fw managed vdma channels."); - return; - } - - status = resources_manager->set_inter_context_channels_dynamic_batch_size(dynamic_batch_size); - if (HAILO_SUCCESS != status) { - LOGGER__ERROR("Failed to set inter-context channels dynamic batch size."); - return; - } - } - - for (auto &resources_manager : m_resources_managers) { - status = resources_manager->enable_state_machine(dynamic_batch_size); - if (HAILO_SUCCESS != status) { - LOGGER__ERROR("Failed to activate state-machine"); - return; - } + + // We know network_group is a VdmaConfigNetworkGroup + status = network_group.activate_impl(dynamic_batch_size); + if (HAILO_SUCCESS != status) { + LOGGER__ERROR("Error activating network group"); + return; } } @@ -95,9 +79,7 @@ VdmaConfigActivatedNetworkGroup::VdmaConfigActivatedNetworkGroup(VdmaConfigActiv m_network_group_name(std::move(other.m_network_group_name)), m_should_reset_network_group(std::exchange(other.m_should_reset_network_group, false)), m_active_net_group_holder(other.m_active_net_group_holder), - m_resources_managers(std::move(other.m_resources_managers)), - m_ddr_send_threads(std::move(other.m_ddr_send_threads)), - m_ddr_recv_threads(std::move(other.m_ddr_recv_threads)), + m_resources_manager(std::move(other.m_resources_manager)), m_deactivation_time_accumulator(std::move(other.m_deactivation_time_accumulator)), m_keep_nn_config_during_reset(std::move(other.m_keep_nn_config_during_reset)) {} @@ -111,21 +93,22 @@ VdmaConfigActivatedNetworkGroup::~VdmaConfigActivatedNetworkGroup() auto status = HAILO_UNINITIALIZED; const auto start_time = std::chrono::steady_clock::now(); - m_active_net_group_holder.clear(); - deactivate_resources(); + auto config_network_group_ref = m_active_net_group_holder.get(); + if (!config_network_group_ref.has_value()) { + LOGGER__ERROR("Error getting configured network group"); + return; + } + + auto vdma_config_network_group = config_network_group_ref.value(); - for (auto &resources_manager : m_resources_managers) { - status = resources_manager->reset_state_machine(m_keep_nn_config_during_reset); - if (HAILO_SUCCESS != status) { - LOGGER__ERROR("Failed to reset context switch status"); - } + status = vdma_config_network_group.get().deactivate_impl(); + if (HAILO_SUCCESS != status) { + LOGGER__ERROR("Failed deactivating network group"); } - for (auto &resources_manager : m_resources_managers) { - status = resources_manager->unregister_fw_managed_vdma_channels(); - if (HAILO_SUCCESS != status) { - LOGGER__ERROR("Failed to stop fw managed vdma channels"); - } + status = m_resources_manager->reset_state_machine(m_keep_nn_config_during_reset); + if (HAILO_SUCCESS != status) { + LOGGER__ERROR("Failed to reset context switch with status {}", status); } const auto elapsed_time_ms = std::chrono::duration( @@ -141,10 +124,7 @@ const std::string &VdmaConfigActivatedNetworkGroup::get_network_group_name() con Expected VdmaConfigActivatedNetworkGroup::get_intermediate_buffer(const IntermediateBufferKey &key) { - CHECK_AS_EXPECTED(1 == m_resources_managers.size(), HAILO_INVALID_OPERATION, - "'get_intermediate_buffer' function works only when working with 1 physical device. number of physical devices: {}", - m_resources_managers.size()); - return m_resources_managers[0]->read_intermediate_buffer(key); + return m_resources_manager->read_intermediate_buffer(key); } hailo_status VdmaConfigActivatedNetworkGroup::set_keep_nn_config_during_reset(const bool keep_nn_config_during_reset) diff --git a/hailort/libhailort/src/context_switch/vdma_config_manager.cpp b/hailort/libhailort/src/context_switch/vdma_config_manager.cpp deleted file mode 100644 index c4d3398..0000000 --- a/hailort/libhailort/src/context_switch/vdma_config_manager.cpp +++ /dev/null @@ -1,380 +0,0 @@ - -// https://github.com/protocolbuffers/protobuf/tree/master/cmake#notes-on-compiler-warnings -#if defined(_MSC_VER) -#pragma warning(push) -#pragma warning(disable: 4244 4267 4127) -#else -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wconversion" -#endif -#include "hef.pb.h" -#if defined(_MSC_VER) -#pragma warning( pop ) -#else -#pragma GCC diagnostic pop -#endif - -#include "context_switch/multi_context/vdma_config_manager.hpp" -#include "network_group_internal.hpp" -#include "hailo/hailort.h" -#include "common/utils.hpp" -#include "hailo/device.hpp" -#include "hailo/vdevice.hpp" -#include "hailo/hef.hpp" -#include "control.hpp" -#include "hailort_defaults.hpp" -#include "vdevice_internal.hpp" -#include "pipeline_multiplexer.hpp" - -#include "pcie_device.hpp" -#include "hlpcie.hpp" - -#include -#include - -namespace hailort -{ - -Expected VdmaConfigManager::create(VdmaDevice &device) -{ - const bool is_vdevice = false; - std::vector> devices; - devices.push_back(device); - - auto empty_weak_ptr = NetworkGroupSchedulerWeakPtr(); - hailo_status status = HAILO_UNINITIALIZED; - VdmaConfigManager manager(std::move(devices), is_vdevice, empty_weak_ptr, status); - CHECK_SUCCESS_AS_EXPECTED(status); - - return manager; -} - -Expected VdmaConfigManager::create(VDeviceBase &vdevice) -{ - const bool is_vdevice = true; - auto devices = vdevice.get_physical_devices(); - CHECK_EXPECTED(devices); - - const auto device_type = vdevice.get_device_type(); - CHECK_EXPECTED(device_type); - - // Down casting Device to VdmaDevice - std::vector> vdma_devices; - for (auto &dev : devices.release()) { - assert(device_type.value() == dev.get().get_type()); - vdma_devices.emplace_back(static_cast(dev.get())); - } - - hailo_status status = HAILO_UNINITIALIZED; - VdmaConfigManager manager(std::move(vdma_devices), is_vdevice, vdevice.network_group_scheduler(), status); - CHECK_SUCCESS_AS_EXPECTED(status); - - return manager; -} - -VdmaConfigManager::VdmaConfigManager(std::vector> &&devices, - bool is_vdevice, - NetworkGroupSchedulerWeakPtr network_group_scheduler, - hailo_status &status) : - m_devices(std::move(devices)), - m_net_groups(), - m_net_group_wrappers(), - m_is_vdevice(is_vdevice), - m_network_group_scheduler(network_group_scheduler) -{ - for (auto &device : m_devices) { - // TODO: Do we need this control after fixing HRT-7519? - // Reset context_switch state machine - it may have been in an active state if the previous VdmaConfigManager - // wasn't dtor'd (due to SIGKILL for example) - static const auto REMOVE_NN_CONFIG_DURING_RESET = false; - status = Control::reset_context_switch_state_machine(device.get(), REMOVE_NN_CONFIG_DURING_RESET); - if (HAILO_SUCCESS != status) { - return; - } - - // Remove the previously configured network groups - status = Control::clear_configured_apps(device.get()); - if (HAILO_SUCCESS != status) { - return; - } - } - - status = HAILO_SUCCESS; -} - -VdmaConfigManager::~VdmaConfigManager() -{ - for (auto &device : m_devices) { - // Remove the previously configured network groups - const auto status = Control::clear_configured_apps(device.get()); - if (HAILO_SUCCESS != status) { - LOGGER__ERROR("Failed to clear conigured network groups with status {}", status); - } - - // Note: We don't call Control::reset_context_switch_state_machine in the dtor, since this isn't a resource - // managed by this class. The call to Control::reset_context_switch_state_machine in the ctor is - // present only due to possiblly active fw state machine (leaked if VdmaConfigActivatedNetworkGroup - // wasn't dtor'd, due to SIGKILL for example) - } -} - -Expected VdmaConfigManager::add_hef(Hef &hef, - const NetworkGroupsParamsMap &configure_params) -{ - /* We assume all devices under VDevice has the same device_arch and partial_clusters_layout_bitmap. - May be changed in SDK-28729 */ - auto device_arch_exp = m_devices[0].get().get_architecture(); - CHECK_EXPECTED(device_arch_exp); - auto device_arch = device_arch_exp.release(); - - auto partial_clusters_layout_bitmap_exp = Control::get_partial_clusters_layout_bitmap(m_devices[0].get()); - CHECK_EXPECTED(partial_clusters_layout_bitmap_exp); - auto partial_clusters_layout_bitmap = partial_clusters_layout_bitmap_exp.release(); - - auto &hef_network_groups = hef.pimpl->network_groups(); - const auto prev_network_group_count = m_net_groups.size(); - const auto total_network_group_count = prev_network_group_count + hef_network_groups.size(); - CHECK_AS_EXPECTED(CONTROL_PROTOCOL__MAX_CONTEXT_SWITCH_APPLICATIONS >= total_network_group_count, - HAILO_INVALID_OPERATION, - "Can't add {} network groups from HEF. Currently {} network groups are configured; maximum allowed network groups: {}.", - hef_network_groups.size(), prev_network_group_count, CONTROL_PROTOCOL__MAX_CONTEXT_SWITCH_APPLICATIONS); - - bool was_hef_already_configured = false; - - ConfiguredNetworkGroupVector added_network_groups; - added_network_groups.reserve(hef_network_groups.size()); - - auto hef_arch = hef.pimpl->get_device_arch(); - - auto current_net_group_index = static_cast(prev_network_group_count); - auto configure_params_copy = configure_params; - const ProtoHEFNetworkGroup *network_group_ptr = nullptr; - for (const auto &network_group_proto : hef_network_groups) { - CHECK_NOT_NULL_AS_EXPECTED(network_group_proto, HAILO_INTERNAL_FAILURE); - - if (ProtoHEFHwArch::PROTO__HW_ARCH__HAILO8L == hef_arch) { - // Hailo8 can work with Hailo8L configurations. in that case we choose one of the configurations - for (auto &partial_network_group : network_group_proto->partial_network_groups()) { - if ((partial_clusters_layout_bitmap == partial_network_group.layout().partial_clusters_layout_bitmap()) || - ((HAILO_ARCH_HAILO8 == device_arch))) { - network_group_ptr = &partial_network_group.network_group(); - break; - } - } - CHECK_AS_EXPECTED(nullptr != network_group_ptr, HAILO_INTERNAL_FAILURE, "There is no matching partial_clusters_layout_bitmap configuration in the given HEF"); - } else { - network_group_ptr = network_group_proto.get(); - } - CHECK_NOT_NULL_AS_EXPECTED(network_group_ptr, HAILO_INTERNAL_FAILURE); - std::string network_group_name = network_group_ptr->network_group_metadata().network_group_name(); - - auto status = Hef::Impl::validate_net_group_unique_layer_names(*network_group_ptr); - CHECK_SUCCESS_AS_EXPECTED(status); - - static_assert(HAILO_DEFAULT_BATCH_SIZE <= std::numeric_limits::max(), - "Invalid HAILO_DEFAULT_BATCH_SIZE"); - - ConfigureNetworkParams config_params{}; - if (contains(configure_params, network_group_name)) { - config_params = configure_params_copy.at(network_group_name); - configure_params_copy.erase(network_group_name); - } else { - auto first_streams_interface = m_devices[0].get().get_default_streams_interface(); - CHECK_EXPECTED(first_streams_interface); -#ifndef NDEBUG - // Check that all physicall devices has the same interface - for (auto &device : m_devices) { - auto interface = device.get().get_default_streams_interface(); - CHECK_EXPECTED(interface); - CHECK_AS_EXPECTED(interface.value() == first_streams_interface.value(), HAILO_INTERNAL_FAILURE, - "Not all default stream interfaces are the same"); - } -#endif - auto config_params_exp = hef.create_configure_params(first_streams_interface.value(), network_group_name); - CHECK_EXPECTED(config_params_exp); - config_params = config_params_exp.release(); - } - - /* Validate batch size (network group batch size vs network batch size) */ - status = update_network_batch_size(config_params); - CHECK_SUCCESS_AS_EXPECTED(status); - - auto network_group_metadata = hef.pimpl->get_network_group_metadata(network_group_name, partial_clusters_layout_bitmap); - CHECK_EXPECTED(network_group_metadata); - - auto network_group_metadata_ptr = make_shared_nothrow(network_group_metadata.release()); - CHECK_AS_EXPECTED(nullptr != network_group_metadata_ptr, HAILO_OUT_OF_HOST_MEMORY); - - std::shared_ptr identical_network_group = nullptr; - std::vector> resources_managers; - bool should_create_resources_managers = true; - - auto network_group_scheduler = m_network_group_scheduler.lock(); - - bool should_use_multiplexer = true; - auto disable_multiplexer_env = std::getenv(DISABLE_MULTIPLEXER_ENV_VAR); - if ((nullptr != disable_multiplexer_env) && (strnlen(disable_multiplexer_env, 2) == 1) && (strncmp(disable_multiplexer_env, "1", 1) == 0)) { - should_use_multiplexer = false; - } - - if (m_is_vdevice && network_group_scheduler && should_use_multiplexer) { - for (auto &network_group : m_net_groups) { - if (network_group->equals(hef, network_group_name)) { - identical_network_group = network_group; - LOGGER__INFO("Network group {} was already configured. Using its resources instead of creating new ones...", network_group_name); - break; - } - } - - if (nullptr != identical_network_group) { - should_create_resources_managers = false; - resources_managers = identical_network_group->get_resources_managers(); - was_hef_already_configured = true; - - if (config_params != identical_network_group->get_config_params()) { - LOGGER__WARNING("Configured network group was already configured but has different parameters which will not take effect!"); - } - } - } - - if (should_create_resources_managers) { - /* build HEF supported features */ - for (auto device : m_devices) { - auto resource_manager = Hef::Impl::create_resources_manager(*network_group_ptr, current_net_group_index, - device.get(), device.get().get_driver(), config_params, network_group_metadata_ptr, hef.pimpl->get_device_arch()); - CHECK_EXPECTED(resource_manager); - resources_managers.push_back(resource_manager.release()); - } - } - - auto net_group = VdmaConfigNetworkGroup::create(m_active_net_group_holder, config_params, - resources_managers, hef.hash(), network_group_metadata_ptr, m_network_group_scheduler); - current_net_group_index++; - - auto net_group_ptr = make_shared_nothrow(net_group.release()); - CHECK_AS_EXPECTED(nullptr != net_group_ptr, HAILO_OUT_OF_HOST_MEMORY); - - // TODO: move this func into VdmaConfigNetworkGroup c'tor - if (m_is_vdevice) { - if (network_group_scheduler && (nullptr != identical_network_group)) { - status = net_group_ptr->create_vdevice_streams_from_duplicate(identical_network_group); - CHECK_SUCCESS_AS_EXPECTED(status); - - net_group_ptr->set_network_group_handle(identical_network_group->network_group_handle()); - } else { - auto network_group_handle = INVALID_NETWORK_GROUP_HANDLE; - if (network_group_scheduler) { - auto network_group_handle_exp = network_group_scheduler->add_network_group(net_group_ptr); - CHECK_EXPECTED(network_group_handle_exp); - - network_group_handle = network_group_handle_exp.value(); - net_group_ptr->set_network_group_handle(network_group_handle); - } - - auto multiplexer = make_shared_nothrow(); - CHECK_AS_EXPECTED(nullptr != multiplexer, HAILO_OUT_OF_HOST_MEMORY, "Failed to create PipelineMultiplexer"); - - status = net_group_ptr->create_vdevice_streams_from_config_params(multiplexer, network_group_handle); - CHECK_SUCCESS_AS_EXPECTED(status); - - m_net_groups.emplace_back(net_group_ptr); - } - } else { - status = net_group_ptr->create_streams_from_config_params(net_group_ptr->get_resources_managers()[0]->get_device()); - CHECK_SUCCESS_AS_EXPECTED(status); - - m_net_groups.emplace_back(net_group_ptr); - } - - // Check that all boundary streams were created - status = validate_boundary_streams_were_created(hef, network_group_name, *net_group_ptr); - CHECK_SUCCESS_AS_EXPECTED(status); - - auto net_group_wrapper = ConfiguredNetworkGroupWrapper::create(net_group_ptr); - CHECK_EXPECTED(net_group_wrapper); - - auto net_group_wrapper_ptr = make_shared_nothrow(net_group_wrapper.release()); - CHECK_AS_EXPECTED(nullptr != net_group_wrapper_ptr, HAILO_OUT_OF_HOST_MEMORY); - - m_net_group_wrappers.emplace_back(net_group_wrapper_ptr); - added_network_groups.emplace_back(std::static_pointer_cast(net_group_wrapper_ptr)); - } - std::string unmatched_keys = ""; - for (const auto &pair : configure_params_copy) { - unmatched_keys.append(" "); - unmatched_keys.append(pair.first); - } - CHECK_AS_EXPECTED(unmatched_keys.size() == 0, HAILO_INVALID_ARGUMENT, - "Some network group names in the configuration are not found in the hef file:{}", unmatched_keys); - - if (was_hef_already_configured) { - return added_network_groups; - } - - for (auto device : m_devices) { - // Allocate context_switch_info on the heap (to avoid stack overflows) - auto context_switch_info = make_unique_nothrow(); - CHECK_NOT_NULL_AS_EXPECTED(context_switch_info, HAILO_OUT_OF_HOST_MEMORY); - memset(context_switch_info.get(), 0, sizeof(CONTROL_PROTOCOL__context_switch_info_t)); - - context_switch_info->context_switch_main_header.context_switch_version = CONTROL_PROTOCOL__CONTEXT_SWITCH_VER_V1_0_0; - context_switch_info->context_switch_main_header.application_count = static_cast(added_network_groups.size()); - for (size_t index_in_hef = 0, context_index = 0; index_in_hef < added_network_groups.size(); index_in_hef++) { - for (auto &resource_manager : m_net_groups[prev_network_group_count + index_in_hef]->get_resources_managers()) { - if (std::string(device.get().get_dev_id()) != std::string(resource_manager->get_dev_id())) { - continue; - } - auto net_group_header_exp = resource_manager->get_control_network_group_header(); - CHECK_EXPECTED(net_group_header_exp); - context_switch_info->context_switch_main_header.application_header[index_in_hef] = net_group_header_exp.value(); - auto net_group_contexts = resource_manager->get_contexts(); - - CHECK_AS_EXPECTED(ARRAY_ENTRIES(context_switch_info->context) > context_index + net_group_contexts.size(), HAILO_INVALID_OPERATION, - "Can't add {} contexts. Currently {} contexts are configured; maximum allowed contexts: {}.", - net_group_contexts.size(), context_index, ARRAY_ENTRIES(context_switch_info->context)); - std::memcpy(&context_switch_info->context[context_index], net_group_contexts.data(), - net_group_contexts.size() * sizeof(context_switch_info->context[0])); - context_index += net_group_contexts.size(); - } - } - - // Write context_switch info - const auto status = Control::write_context_switch_info(device.get(), context_switch_info.get()); - CHECK_SUCCESS_AS_EXPECTED(status); - } - - return added_network_groups; -} - -hailo_status VdmaConfigManager::update_network_batch_size(ConfigureNetworkParams &network_group_config_params) -{ - auto single_network_default_batch = (HAILO_DEFAULT_BATCH_SIZE == network_group_config_params.batch_size); - auto multi_network_default_batch = true; - /* Batch size overide logic - if user modifies network group batch size - and not the network batch size, */ - - for (auto const &network_params : network_group_config_params.network_params_by_name) { - if (HAILO_DEFAULT_BATCH_SIZE != network_params.second.batch_size) { - multi_network_default_batch = false; - } - } - - CHECK((single_network_default_batch || multi_network_default_batch), HAILO_INVALID_OPERATION, - "User provided batch size for network group and for network as well. User is adviced to work with network's batch size only"); - - if (!single_network_default_batch && multi_network_default_batch) { - /* In case user works with network group, overide the network batch size.*/ - for (auto &network_params : network_group_config_params.network_params_by_name) { - network_params.second.batch_size = network_group_config_params.batch_size; - } - } - - return HAILO_SUCCESS; -} - -ConfigManagerType VdmaConfigManager::get_manager_type() -{ - return ConfigManagerType::VdmaConfigManager; -} - -} /* namespace hailort */ diff --git a/hailort/libhailort/src/context_switch/vdma_config_network_group.cpp b/hailort/libhailort/src/context_switch/vdma_config_network_group.cpp index 3eac9b9..42f500d 100644 --- a/hailort/libhailort/src/context_switch/vdma_config_network_group.cpp +++ b/hailort/libhailort/src/context_switch/vdma_config_network_group.cpp @@ -1,262 +1,143 @@ +#include "tracer_macros.hpp" #include "context_switch/multi_context/vdma_config_network_group.hpp" #include "network_group_internal.hpp" #include "eth_stream.hpp" #include "pcie_stream.hpp" #include "mipi_stream.hpp" -#include "vdevice_stream.hpp" -#include "vdevice_stream_wrapper.hpp" #include "vstream_internal.hpp" namespace hailort { -Expected VdmaConfigNetworkGroup::create(VdmaConfigActiveAppHolder &active_net_group_holder, +Expected VdmaConfigNetworkGroup::create(ActiveNetGroupHolder &active_net_group_holder, const ConfigureNetworkParams &config_params, - std::vector> resources_managers, const std::string &hef_hash, - std::shared_ptr network_group_metadata, NetworkGroupSchedulerWeakPtr network_group_scheduler) + std::shared_ptr resources_manager, const std::string &hef_hash, + std::shared_ptr network_group_metadata, + std::vector> &&net_flow_ops) { auto status = HAILO_UNINITIALIZED; VdmaConfigNetworkGroup object(active_net_group_holder, config_params, - std::move(resources_managers), hef_hash, *network_group_metadata, network_group_scheduler, status); + std::move(resources_manager), hef_hash, *network_group_metadata, status, std::move(net_flow_ops)); CHECK_SUCCESS_AS_EXPECTED(status); return object; } -VdmaConfigNetworkGroup::VdmaConfigNetworkGroup(VdmaConfigActiveAppHolder &active_net_group_holder, +VdmaConfigNetworkGroup::VdmaConfigNetworkGroup(ActiveNetGroupHolder &active_net_group_holder, const ConfigureNetworkParams &config_params, - std::vector> &&resources_managers, const std::string &hef_hash, - const NetworkGroupMetadata &network_group_metadata, NetworkGroupSchedulerWeakPtr network_group_scheduler, hailo_status &status) : + std::shared_ptr &&resources_manager, const std::string &hef_hash, + const NetworkGroupMetadata &network_group_metadata, hailo_status &status, + std::vector> &&net_flow_ops) : ConfiguredNetworkGroupBase(config_params, - resources_managers[0]->get_network_group_index(), // All ResourceManagers shares the same net_group_index - network_group_metadata, !network_group_scheduler.expired(), status), + network_group_metadata, std::move(net_flow_ops), status), m_active_net_group_holder(active_net_group_holder), - m_resources_managers(std::move(resources_managers)), - m_network_group_scheduler(network_group_scheduler), - m_scheduler_handle(INVALID_NETWORK_GROUP_HANDLE), - m_multiplexer_handle(0), + m_resources_manager(std::move(resources_manager)), m_hef_hash(hef_hash) {} -Expected> VdmaConfigNetworkGroup::activate_impl( - const hailo_activate_network_group_params_t &network_group_params, uint16_t dynamic_batch_size) +hailo_status VdmaConfigNetworkGroup::activate_impl(uint16_t dynamic_batch_size) { - auto start_time = std::chrono::steady_clock::now(); - auto activated_net_group = VdmaConfigActivatedNetworkGroup::create( - m_active_net_group_holder, name(), m_resources_managers, network_group_params, dynamic_batch_size, - m_input_streams, m_output_streams, m_network_group_activated_event, m_deactivation_time_accumulator); - const auto elapsed_time_ms = std::chrono::duration( - std::chrono::steady_clock::now() - start_time).count(); - CHECK_EXPECTED(activated_net_group); + auto status = HAILO_UNINITIALIZED; - LOGGER__INFO("Activating {} took {} milliseconds. Note that the function is asynchronous and" - " thus the network is not fully activated yet.", name(), elapsed_time_ms); - m_activation_time_accumulator->add_data_point(elapsed_time_ms); + // Check that no network is currently activated + CHECK(!m_active_net_group_holder.is_any_active(), HAILO_INTERNAL_FAILURE, + "Cant activate network because a network is already activated"); - std::unique_ptr activated_net_group_ptr = - make_unique_nothrow(activated_net_group.release()); - CHECK_AS_EXPECTED(nullptr != activated_net_group_ptr, HAILO_OUT_OF_HOST_MEMORY); - - return activated_net_group_ptr; -} + m_active_net_group_holder.set(*this); -Expected VdmaConfigNetworkGroup::get_default_streams_interface() -{ - auto first_streams_interface = m_resources_managers[0]->get_default_streams_interface(); - CHECK_EXPECTED(first_streams_interface); -#ifndef NDEBUG - // Check that all physicall devices has the same interface - for (auto &resoucres_manager : m_resources_managers) { - auto iface = resoucres_manager->get_default_streams_interface(); - CHECK_EXPECTED(iface); - CHECK_AS_EXPECTED(iface.value() == first_streams_interface.value(), HAILO_INTERNAL_FAILURE, - "Not all default stream interfaces are the same"); - } -#endif - return first_streams_interface; -} + status = m_resources_manager->register_fw_managed_vdma_channels(); + CHECK_SUCCESS(status, "Failed to start fw managed vdma channels."); -hailo_status VdmaConfigNetworkGroup::create_vdevice_streams_from_config_params(std::shared_ptr multiplexer, scheduler_ng_handle_t scheduler_handle) -{ - // TODO - HRT-6931 - raise error on this case - if (((m_config_params.latency & HAILO_LATENCY_MEASURE) == HAILO_LATENCY_MEASURE) && (1 < m_resources_managers.size())) { - LOGGER__WARNING("Latency measurement is not supported on more than 1 physical device."); - } + status = m_resources_manager->set_inter_context_channels_dynamic_batch_size(dynamic_batch_size); + CHECK_SUCCESS(status, "Failed to set inter-context channels dynamic batch size."); - m_multiplexer = multiplexer; + status = m_resources_manager->enable_state_machine(dynamic_batch_size); + CHECK_SUCCESS(status, "Failed to activate state-machine"); - for (const auto &stream_parameters_pair : m_config_params.stream_params_by_name) { - switch (stream_parameters_pair.second.direction) { - case HAILO_H2D_STREAM: - { - auto status = create_input_vdevice_stream_from_config_params(stream_parameters_pair.second, - stream_parameters_pair.first, multiplexer, scheduler_handle); - CHECK_SUCCESS(status); - } - break; - case HAILO_D2H_STREAM: - { - auto status = create_output_vdevice_stream_from_config_params(stream_parameters_pair.second, - stream_parameters_pair.first, multiplexer, scheduler_handle); - CHECK_SUCCESS(status); - } - break; - default: - LOGGER__ERROR("stream name {} direction is invalid.", stream_parameters_pair.first); - return HAILO_INVALID_ARGUMENT; - } - } + status = activate_low_level_streams(dynamic_batch_size); + CHECK_SUCCESS(status, "Failed to activate low level streams"); - auto status = m_multiplexer->add_network_group_instance(m_multiplexer_handle, *this); - CHECK_SUCCESS(status); + status = m_network_group_activated_event->signal(); + CHECK_SUCCESS(status, "Failed to signal network activation event"); return HAILO_SUCCESS; } -hailo_status VdmaConfigNetworkGroup::create_input_vdevice_stream_from_config_params(const hailo_stream_parameters_t &stream_params, - const std::string &stream_name, std::shared_ptr multiplexer, scheduler_ng_handle_t scheduler_handle) +hailo_status VdmaConfigNetworkGroup::deactivate_impl() { - auto edge_layer = get_layer_info(stream_name); - CHECK_EXPECTED_AS_STATUS(edge_layer); + auto status = HAILO_UNINITIALIZED; - CHECK(HailoRTCommon::is_vdma_stream_interface(stream_params.stream_interface), HAILO_INVALID_OPERATION, - "Stream {} not supported on VDevice usage. {} has {} interface.", stream_name, stream_params.stream_interface); - auto input_stream = VDeviceInputStream::create(m_resources_managers, edge_layer.value(), - stream_name, scheduler_handle, m_network_group_activated_event, - m_network_group_scheduler); - CHECK_EXPECTED_AS_STATUS(input_stream); - auto input_stream_wrapper = VDeviceInputStreamWrapper::create(input_stream.release(), edge_layer->network_name, multiplexer, scheduler_handle); - CHECK_EXPECTED_AS_STATUS(input_stream_wrapper); - m_input_streams.insert(make_pair(stream_name, input_stream_wrapper.release())); + // Check that network is currently activated + CHECK(m_active_net_group_holder.is_any_active(), HAILO_INTERNAL_FAILURE, + "Cant Deactivate network because no network is already activated"); - return HAILO_SUCCESS; -} + // Make sure the network group we are deactivating is this object + auto config_network_group_ref = m_active_net_group_holder.get().value(); + CHECK(this == std::addressof(config_network_group_ref.get()), HAILO_INTERNAL_FAILURE, + "Trying to deactivate different network goup"); -hailo_status VdmaConfigNetworkGroup::create_output_vdevice_stream_from_config_params(const hailo_stream_parameters_t &stream_params, - const std::string &stream_name, std::shared_ptr multiplexer, scheduler_ng_handle_t scheduler_handle) -{ - auto edge_layer = get_layer_info(stream_name); - CHECK_EXPECTED_AS_STATUS(edge_layer); + m_active_net_group_holder.clear(); + + m_network_group_activated_event->reset(); + + status = deactivate_low_level_streams(); + CHECK_SUCCESS(status, "Failed to deactivate low level streams"); - CHECK(HailoRTCommon::is_vdma_stream_interface(stream_params.stream_interface), HAILO_INVALID_OPERATION, - "Stream {} not supported on VDevice usage. {} has {} interface.", stream_name, stream_params.stream_interface); - auto output_stream = VDeviceOutputStream::create(m_resources_managers, edge_layer.value(), - stream_name, scheduler_handle, m_network_group_activated_event, - m_network_group_scheduler); - CHECK_EXPECTED_AS_STATUS(output_stream); - auto output_stream_wrapper = VDeviceOutputStreamWrapper::create(output_stream.release(), edge_layer->network_name, multiplexer, scheduler_handle); - CHECK_EXPECTED_AS_STATUS(output_stream_wrapper); - m_output_streams.insert(make_pair(stream_name, output_stream_wrapper.release())); + status = m_resources_manager->unregister_fw_managed_vdma_channels(); + CHECK_SUCCESS(status, "Failed to stop fw managed vdma channels"); return HAILO_SUCCESS; } -hailo_status VdmaConfigNetworkGroup::create_vdevice_streams_from_duplicate(std::shared_ptr other) +Expected> VdmaConfigNetworkGroup::create_activated_network_group( + const hailo_activate_network_group_params_t &network_group_params, uint16_t dynamic_batch_size) { - // TODO - HRT-6931 - raise error on this case - if (((m_config_params.latency & HAILO_LATENCY_MEASURE) == HAILO_LATENCY_MEASURE) && (1 < m_resources_managers.size())) { - LOGGER__WARNING("Latency measurement is not supported on more than 1 physical device."); - } - - m_multiplexer = other->m_multiplexer; - m_multiplexer_handle = other->multiplexer_duplicates_count() + 1; - - for (auto &name_stream_pair : other->m_input_streams) { - auto input_stream = static_cast(name_stream_pair.second.get()); - auto copy = input_stream->clone(m_multiplexer_handle); - CHECK_EXPECTED_AS_STATUS(copy); - - m_input_streams.insert(make_pair(name_stream_pair.first, copy.release())); - } - - for (auto &name_stream_pair : other->m_output_streams) { - auto output_stream = static_cast(name_stream_pair.second.get()); - auto copy = output_stream->clone(m_multiplexer_handle); - CHECK_EXPECTED_AS_STATUS(copy); - - m_output_streams.insert(make_pair(name_stream_pair.first, copy.release())); - } + auto start_time = std::chrono::steady_clock::now(); + auto activated_net_group = VdmaConfigActivatedNetworkGroup::create( + m_active_net_group_holder, name(), m_resources_manager, network_group_params, dynamic_batch_size, + m_input_streams, m_output_streams, m_network_group_activated_event, m_deactivation_time_accumulator, (*this)); + const auto elapsed_time_ms = std::chrono::duration( + std::chrono::steady_clock::now() - start_time).count(); + CHECK_EXPECTED(activated_net_group); - auto status = other->m_multiplexer->add_network_group_instance(m_multiplexer_handle, *this); - CHECK_SUCCESS(status); + LOGGER__INFO("Activating {} took {} milliseconds. Note that the function is asynchronous and" + " thus the network is not fully activated yet.", name(), elapsed_time_ms); + m_activation_time_accumulator->add_data_point(elapsed_time_ms); - return HAILO_SUCCESS; -} + std::unique_ptr activated_net_group_ptr = + make_unique_nothrow(activated_net_group.release()); + CHECK_AS_EXPECTED(nullptr != activated_net_group_ptr, HAILO_OUT_OF_HOST_MEMORY); -void VdmaConfigNetworkGroup::set_network_group_handle(scheduler_ng_handle_t handle) -{ - m_scheduler_handle = handle; + return activated_net_group_ptr; } -scheduler_ng_handle_t VdmaConfigNetworkGroup::network_group_handle() const +Expected VdmaConfigNetworkGroup::get_default_streams_interface() { - return m_scheduler_handle; + return m_resources_manager->get_default_streams_interface(); } -hailo_status VdmaConfigNetworkGroup::set_scheduler_timeout(const std::chrono::milliseconds &timeout, const std::string &network_name) +hailo_status VdmaConfigNetworkGroup::set_scheduler_timeout(const std::chrono::milliseconds &/*timeout*/, const std::string &/*network_name*/) { - auto network_group_scheduler = m_network_group_scheduler.lock(); - CHECK(network_group_scheduler, HAILO_INVALID_OPERATION, - "Cannot set scheduler timeout for network group {}, as it is configured on a vdevice which does not have scheduling enabled", name()); - if (network_name != HailoRTDefaults::get_network_name(name())) { - CHECK(network_name.empty(), HAILO_NOT_IMPLEMENTED, "Setting scheduler timeout for a specific network is currently not supported"); - } - auto status = network_group_scheduler->set_timeout(m_scheduler_handle, timeout, network_name); - CHECK_SUCCESS(status); - return HAILO_SUCCESS; + LOGGER__ERROR("Setting scheduler's timeout is only allowed when working with VDevice and scheduler enabled"); + return HAILO_INVALID_OPERATION; } -hailo_status VdmaConfigNetworkGroup::set_scheduler_threshold(uint32_t threshold, const std::string &network_name) +hailo_status VdmaConfigNetworkGroup::set_scheduler_threshold(uint32_t /*threshold*/, const std::string &/*network_name*/) { - auto network_group_scheduler = m_network_group_scheduler.lock(); - CHECK(network_group_scheduler, HAILO_INVALID_OPERATION, - "Cannot set scheduler threshold for network group {}, as it is configured on a vdevice which does not have scheduling enabled", name()); - if (network_name != HailoRTDefaults::get_network_name(name())) { - CHECK(network_name.empty(), HAILO_NOT_IMPLEMENTED, "Setting scheduler threshold for a specific network is currently not supported"); - } - auto status = network_group_scheduler->set_threshold(m_scheduler_handle, threshold, network_name); - CHECK_SUCCESS(status); - return HAILO_SUCCESS; + LOGGER__ERROR("Setting scheduler's threshold is only allowed when working with VDevice and scheduler enabled"); + return HAILO_INVALID_OPERATION; } Expected> VdmaConfigNetworkGroup::get_latency_meters() { - auto latency_meters = m_resources_managers[0]->get_latency_meters(); + auto latency_meters = m_resources_manager->get_latency_meters(); return make_shared_nothrow(latency_meters); } Expected> VdmaConfigNetworkGroup::get_boundary_vdma_channel_by_stream_name(const std::string &stream_name) { - if (1 < m_resources_managers.size()) { - LOGGER__ERROR("get_boundary_vdma_channel_by_stream_name function is not supported on more than 1 physical device."); - return make_unexpected(HAILO_INVALID_OPERATION); - } - - return m_resources_managers[0]->get_boundary_vdma_channel_by_stream_name(stream_name); -} - -Expected> VdmaConfigNetworkGroup::create_output_vstreams(const std::map &outputs_params) -{ - auto expected = ConfiguredNetworkGroupBase::create_output_vstreams(outputs_params); - CHECK_EXPECTED(expected); - - if (nullptr == m_multiplexer) { - return expected.release(); - } - - m_multiplexer->set_output_vstreams_names(m_multiplexer_handle, expected.value()); - - for (auto &vstream : expected.value()) { - static_cast(*vstream.m_vstream).set_on_vstream_cant_read_callback([this, name = vstream.name()] () { - m_multiplexer->set_can_output_vstream_read(m_multiplexer_handle, name, false); - }); - static_cast(*vstream.m_vstream).set_on_vstream_can_read_callback([this, name = vstream.name()] () { - m_multiplexer->set_can_output_vstream_read(m_multiplexer_handle, name, true); - }); - } - - return expected.release(); + return m_resources_manager->get_boundary_vdma_channel_by_stream_name(stream_name); } } /* namespace hailort */ diff --git a/hailort/libhailort/src/control.cpp b/hailort/libhailort/src/control.cpp index 7bb2105..23a3da5 100644 --- a/hailort/libhailort/src/control.cpp +++ b/hailort/libhailort/src/control.cpp @@ -30,7 +30,7 @@ namespace hailort (static_cast((__sample_period) / 1000.0 * (__average_factor) * 2 * 1.2)) #define OVERCURRENT_PROTECTION_WARNING ( \ - "Using the overcurrent protection dvm for power measurement will disable the ovecurrent protection.\n" \ + "Using the overcurrent protection dvm for power measurement will disable the overcurrent protection.\n" \ "If only taking one measurement, the protection will resume automatically.\n" \ "If doing continuous measurement, to enable overcurrent protection again you have to stop the power measurement on this dvm." \ ) @@ -44,7 +44,7 @@ Expected control__parse_identify_results(CONTROL_PROTOC CHECK_AS_EXPECTED(nullptr != identify_response, HAILO_INVALID_ARGUMENT); - /* Store identify response inside control */ + // Store identify response inside control board_info.protocol_version = BYTE_ORDER__ntohl(identify_response->protocol_version); board_info.logger_version = BYTE_ORDER__ntohl(identify_response->logger_version); (void)memcpy(&(board_info.fw_version), @@ -67,14 +67,17 @@ Expected control__parse_identify_results(CONTROL_PROTOC &(identify_response->product_name), BYTE_ORDER__ntohl(identify_response->product_name_length)); - /* Check if firmware is at debug/release */ + // Check if the firmware is debug or release board_info.is_release = (!IS_REVISION_DEV(board_info.fw_version.revision)); + // Check if the firmware was compiled with EXTENDED_CONTEXT_SWITCH_BUFFER + board_info.extended_context_switch_buffer = IS_REVISION_EXTENDED_CONTEXT_SWITCH_BUFFER(board_info.fw_version.revision); + // Make sure response was from app CPU CHECK_AS_EXPECTED((0 == (board_info.fw_version.revision & REVISION_APP_CORE_FLAG_BIT_MASK)), HAILO_INVALID_FIRMWARE, "Got invalid app FW type, which means the FW was not marked correctly. unmaked FW revision {}", board_info.fw_version.revision); - /* Clear debug/release bit */ + // Keep the revision number only board_info.fw_version.revision = GET_REVISION_NUMBER_VALUE(board_info.fw_version.revision); board_info.device_architecture = static_cast(BYTE_ORDER__ntohl(identify_response->device_architecture)); @@ -163,22 +166,25 @@ hailo_status control__parse_core_identify_results(CONTROL_PROTOCOL__core_identif CHECK_ARG_NOT_NULL(core_info); CHECK_ARG_NOT_NULL(identify_response); - /* Store identify response inside control */ + // Store identify response inside control (void)memcpy(&(core_info->fw_version), &(identify_response->fw_version), sizeof(core_info->fw_version)); - /* Check if firmware is at debug/release */ + // Check if firmware is at debug/release core_info->is_release = !(IS_REVISION_DEV(core_info->fw_version.revision)); - /* Make sure response was from core CPU */ + // Check if the firmware was compiled with EXTENDED_CONTEXT_SWITCH_BUFFER + core_info->extended_context_switch_buffer = IS_REVISION_EXTENDED_CONTEXT_SWITCH_BUFFER(core_info->fw_version.revision); + + // Make sure response was from core CPU CHECK((REVISION_APP_CORE_FLAG_BIT_MASK == (core_info->fw_version.revision & REVISION_APP_CORE_FLAG_BIT_MASK)), HAILO_INVALID_FIRMWARE, "Got invalid core FW type, which means the FW was not marked correctly. unmaked FW revision {}", core_info->fw_version.revision); - /* Clear debug/release bit */ + // Keep the revision number only core_info->fw_version.revision = GET_REVISION_NUMBER_VALUE(core_info->fw_version.revision); - /* Write identify results to log */ + // Write identify results to log LOGGER__INFO("core firmware_version is: {}.{}.{}", core_info->fw_version.major, core_info->fw_version.minor, @@ -489,6 +495,28 @@ Expected Control::get_overcurrent_state(Device &device) return std::move(get_overcurrent_state_response->is_required); } +Expected Control::get_hw_consts(Device &device) +{ + size_t request_size = 0; + CONTROL_PROTOCOL__request_t request = {}; + auto common_status = CONTROL_PROTOCOL__pack_get_hw_consts_request(&request, &request_size, device.get_control_sequence()); + auto status = (HAILO_COMMON_STATUS__SUCCESS == common_status) ? HAILO_SUCCESS : HAILO_INTERNAL_FAILURE; + CHECK_SUCCESS_AS_EXPECTED(status); + + uint8_t response_buffer[RESPONSE_MAX_BUFFER_SIZE] = {}; + size_t response_size = RESPONSE_MAX_BUFFER_SIZE; + status = device.fw_interact((uint8_t*)(&request), request_size, (uint8_t*)&response_buffer, &response_size); + CHECK_SUCCESS_AS_EXPECTED(status); + + CONTROL_PROTOCOL__response_header_t *header = NULL; + CONTROL_PROTOCOL__payload_t *payload = NULL; + status = parse_and_validate_response(response_buffer, (uint32_t)(response_size), &header, &payload, &request); + CHECK_SUCCESS_AS_EXPECTED(status); + + const auto &response = *reinterpret_cast(payload->parameters); + return Expected(response.hw_consts); +} + hailo_status Control::write_memory_chunk(Device &device, uint32_t address, const uint8_t *data, uint32_t chunk_size) { hailo_status status = HAILO_UNINITIALIZED; @@ -2289,8 +2317,8 @@ exit: return status; } -hailo_status Control::context_switch_set_main_header(Device &device, - CONTROL_PROTOCOL__context_switch_main_header_t *context_switch_header) +hailo_status Control::context_switch_set_network_group_header(Device &device, + const CONTROL_PROTOCOL__application_header_t &network_group_header) { hailo_status status = HAILO_UNINITIALIZED; HAILO_COMMON_STATUS_t common_status = HAILO_COMMON_STATUS__UNINITIALIZED; @@ -2301,11 +2329,8 @@ hailo_status Control::context_switch_set_main_header(Device &device, CONTROL_PROTOCOL__response_header_t *header = NULL; CONTROL_PROTOCOL__payload_t *payload = NULL; - /* Validate arguments */ - CHECK_ARG_NOT_NULL(context_switch_header); - - common_status = CONTROL_PROTOCOL__pack_context_switch_set_main_header_request(&request, &request_size, device.get_control_sequence(), - context_switch_header); + common_status = CONTROL_PROTOCOL__pack_context_switch_set_network_group_header_request(&request, &request_size, + device.get_control_sequence(), &network_group_header); status = (HAILO_COMMON_STATUS__SUCCESS == common_status) ? HAILO_SUCCESS : HAILO_INTERNAL_FAILURE; if (HAILO_SUCCESS != status) { goto exit; @@ -2329,7 +2354,7 @@ exit: } hailo_status Control::context_switch_set_context_info_chunk(Device &device, - CONTROL_PROTOCOL__context_switch_context_info_single_control_t *context_info) + const CONTROL_PROTOCOL__context_switch_context_info_single_control_t &context_info) { hailo_status status = HAILO_UNINITIALIZED; HAILO_COMMON_STATUS_t common_status = HAILO_COMMON_STATUS__UNINITIALIZED; @@ -2340,11 +2365,8 @@ hailo_status Control::context_switch_set_context_info_chunk(Device &device, CONTROL_PROTOCOL__response_header_t *header = NULL; CONTROL_PROTOCOL__payload_t *payload = NULL; - /* Validate arguments */ - CHECK_ARG_NOT_NULL(context_info); - common_status = CONTROL_PROTOCOL__pack_context_switch_set_context_info_request(&request, &request_size, device.get_control_sequence(), - context_info); + &context_info); status = (HAILO_COMMON_STATUS__SUCCESS == common_status) ? HAILO_SUCCESS : HAILO_INTERNAL_FAILURE; if (HAILO_SUCCESS != status) { goto exit; @@ -2372,126 +2394,13 @@ exit: } hailo_status Control::context_switch_set_context_info(Device &device, - CONTROL_PROTOCOL__context_switch_context_info_t *context_info) + const std::vector &context_infos) { - hailo_status status = HAILO_UNINITIALIZED; - CONTROL_PROTOCOL__context_switch_context_info_single_control_t context_info_single_control = {}; - uint8_t slice_index = 0; - bool is_first_control_per_context = false; - bool is_last_control_per_context = false; - uint16_t slice_start_offset = 0; - uint16_t slice_end_offset = 0; - - /* Validate arguments */ - CHECK_ARG_NOT_NULL(context_info); - - do { - if (0 == slice_index) { - is_first_control_per_context = true; - } else { - is_first_control_per_context = false; - } - if (0 == context_info->control_slicing_data.control_slicing_offsets[slice_index]) { - is_last_control_per_context = true; - } else { - is_last_control_per_context = false; - } - - /* Build single control struct from context info */ - - context_info_single_control.is_first_control_per_context = is_first_control_per_context; - context_info_single_control.is_last_control_per_context = is_last_control_per_context; - static_assert(sizeof(context_info_single_control.config_channel_infos) == sizeof(context_info->config_channel_infos), - "mismatch in sizes of config_channel_infos"); - static_assert(sizeof(context_info_single_control.context_stream_remap_data) == sizeof(context_info->context_stream_remap_data), - "mismatch in sizes of context_stream_remap_data"); - context_info_single_control.cfg_channels_count = context_info->cfg_channels_count; - memcpy(context_info_single_control.config_channel_infos, - context_info->config_channel_infos, - sizeof(context_info_single_control.config_channel_infos)); - - memcpy(&(context_info_single_control.context_stream_remap_data), - &(context_info->context_stream_remap_data), - sizeof(context_info_single_control.context_stream_remap_data)); - - context_info_single_control.number_of_edge_layers = - context_info->control_slicing_data.slice_edge_layers[slice_index]; - context_info_single_control.number_of_trigger_groups = - context_info->control_slicing_data.slice_triggers[slice_index]; - - if (is_first_control_per_context) { - slice_start_offset = 0; - } else { - slice_start_offset = context_info->control_slicing_data.control_slicing_offsets[slice_index-1]; - } - if (is_last_control_per_context) { - slice_end_offset = (uint16_t)context_info->context_network_data_length; - } else { - slice_end_offset = context_info->control_slicing_data.control_slicing_offsets[slice_index]; - } - - /* Validation on the memory before memcpy. Should not fail */ - if ((CONTROL_PROTOCOL__CONTEXT_NETWORK_DATA_MAX_SIZE < slice_end_offset) || - (CONTROL_PROTOCOL__CONTEXT_NETWORK_DATA_SINGLE_CONTROL_MAX_SIZE < - (uint16_t)(slice_end_offset - slice_start_offset))) { - status = HAILO_OUT_OF_HOST_MEMORY; - goto exit; - } - - context_info_single_control.context_network_data_length = (slice_end_offset - slice_start_offset); - memcpy(context_info_single_control.context_network_data, - (uint8_t *)((uintptr_t)context_info->context_network_data + slice_start_offset), - context_info_single_control.context_network_data_length); - - status = Control::context_switch_set_context_info_chunk(device, &context_info_single_control); + for (const auto &context_info : context_infos) { + auto status = context_switch_set_context_info_chunk(device, context_info); CHECK_SUCCESS(status); - - /* Advance control slice index */ - slice_index++; - } while (!is_last_control_per_context); - - status = HAILO_SUCCESS; -exit: - return status; -} - -hailo_status Control::write_context_switch_info(Device &device, - CONTROL_PROTOCOL__context_switch_info_t *context_switch_info) -{ - hailo_status status = HAILO_UNINITIALIZED; - uint8_t network_group_index = 0; - uint8_t total_context_counter = 0; - uint8_t dynamic_contexts_index = 0; - - /* Validate arguments */ - CHECK_ARG_NOT_NULL(context_switch_info); - - status = Control::context_switch_set_main_header(device, &(context_switch_info->context_switch_main_header)); - CHECK_SUCCESS(status); - - /* For each network_group */ - for (network_group_index = 0; network_group_index < context_switch_info->context_switch_main_header.application_count; - network_group_index++) { - /* number of contexts in network_group - all dynamic contexts +1 for the additional preliminary context */ - uint8_t total_contexts_in_app = (uint8_t)( - context_switch_info->context_switch_main_header.application_header[network_group_index].dynamic_contexts_count + 1); - /* For each context in network_group */ - for (dynamic_contexts_index = 0; dynamic_contexts_index < total_contexts_in_app; dynamic_contexts_index++) { - if (CONTROL_PROTOCOL__MAX_TOTAL_CONTEXTS <= total_context_counter) { - status = HAILO_INVALID_CONTEXT_COUNT; - goto exit; - } - - /* Send context info */ - status = context_switch_set_context_info(device, &(context_switch_info->context[total_context_counter])); - CHECK_SUCCESS(status); - total_context_counter++; - } } - - status = HAILO_SUCCESS; -exit: - return status; + return HAILO_SUCCESS; } hailo_status Control::idle_time_get_measurement(Device &device, uint64_t *measurement) @@ -2609,9 +2518,10 @@ hailo_status Control::set_pause_frames(Device &device, uint8_t rx_pause_frames_e return HAILO_SUCCESS; } -hailo_status Control::download_context_action_list_chunk(Device &device, uint8_t context_index, uint16_t action_list_offset, - size_t action_list_max_size, uint32_t *base_address, uint8_t *action_list, uint16_t *action_list_length, - bool *is_action_list_end, uint32_t *batch_counter) +hailo_status Control::download_context_action_list_chunk(Device &device, uint32_t network_group_id, + CONTROL_PROTOCOL__context_switch_context_type_t context_type, uint8_t context_index, + uint16_t action_list_offset, size_t action_list_max_size, uint32_t *base_address, uint8_t *action_list, + uint16_t *action_list_length, bool *is_action_list_end, uint32_t *batch_counter) { hailo_status status = HAILO_UNINITIALIZED; HAILO_COMMON_STATUS_t common_status = HAILO_COMMON_STATUS__UNINITIALIZED; @@ -2623,14 +2533,13 @@ hailo_status Control::download_context_action_list_chunk(Device &device, uint8_t CONTROL_PROTOCOL__payload_t *payload = NULL; CONTROL_PROTOCOL__download_context_action_list_response_t *context_action_list_response = NULL; - /* Validate arguments */ CHECK_ARG_NOT_NULL(base_address); CHECK_ARG_NOT_NULL(action_list); CHECK_ARG_NOT_NULL(action_list_length); common_status = CONTROL_PROTOCOL__pack_download_context_action_list_request(&request, &request_size, device.get_control_sequence(), - context_index, action_list_offset); + network_group_id, context_type, context_index, action_list_offset); status = (HAILO_COMMON_STATUS__SUCCESS == common_status) ? HAILO_SUCCESS : HAILO_INTERNAL_FAILURE; if (HAILO_SUCCESS != status) { @@ -2680,8 +2589,9 @@ exit: return status; } -hailo_status Control::download_context_action_list(Device &device, uint8_t context_index, size_t action_list_max_size, - uint32_t *base_address, uint8_t *action_list, uint16_t *action_list_length, uint32_t *batch_counter) +hailo_status Control::download_context_action_list(Device &device, uint32_t network_group_id, + CONTROL_PROTOCOL__context_switch_context_type_t context_type, uint8_t context_index, size_t action_list_max_size, + uint32_t *base_address, uint8_t *action_list, uint16_t *action_list_length, uint32_t *batch_counter) { hailo_status status = HAILO_UNINITIALIZED; bool is_action_list_end = false; @@ -2701,9 +2611,9 @@ hailo_status Control::download_context_action_list(Device &device, uint8_t conte remaining_action_list_max_size = action_list_max_size; do { - status = download_context_action_list_chunk(device, context_index, accumulated_action_list_length, - remaining_action_list_max_size, &chunk_base_address, action_list_current_offset, - &chunk_action_list_length, &is_action_list_end, &batch_counter_local); + status = download_context_action_list_chunk(device, network_group_id, context_type, context_index, + accumulated_action_list_length, remaining_action_list_max_size, &chunk_base_address, + action_list_current_offset, &chunk_action_list_length, &is_action_list_end, &batch_counter_local); CHECK_SUCCESS(status); accumulated_action_list_length = (uint16_t)(accumulated_action_list_length + chunk_action_list_length); @@ -2940,7 +2850,8 @@ hailo_status Control::d2h_notification_manager_set_host_info(Device &device, uin size_t response_size = sizeof(response_buffer); CONTROL_PROTOCOL__response_header_t *header = NULL; CONTROL_PROTOCOL__payload_t *payload = NULL; - auto connection_type = (Device::Type::PCIE == device.get_type() ? D2H_EVENT_COMMUNICATION_TYPE_PCIE : D2H_EVENT_COMMUNICATION_TYPE_UDP); + auto connection_type = ((Device::Type::PCIE == device.get_type() || Device::Type::CORE == device.get_type()) ? + D2H_EVENT_COMMUNICATION_TYPE_VDMA : D2H_EVENT_COMMUNICATION_TYPE_UDP); LOGGER__DEBUG("Set d2h notification manager new host info : connection_type {}, remote_port {}, remote_ip_address {}", connection_type, host_port, host_ip_address); @@ -3405,4 +3316,29 @@ hailo_status Control::run_bist_test(Device &device, bool is_top_test, uint32_t t return HAILO_SUCCESS; } +hailo_status Control::set_sleep_state(Device &device, hailo_sleep_state_t sleep_state) +{ + CONTROL_PROTOCOL__request_t request = {}; + size_t request_size = 0; + uint8_t response_buffer[RESPONSE_MAX_BUFFER_SIZE] = {}; + size_t response_size = sizeof(response_buffer); + CONTROL_PROTOCOL__response_header_t *header = NULL; + CONTROL_PROTOCOL__payload_t *payload = NULL; + + auto common_status = CONTROL_PROTOCOL__pack_set_sleep_state_request( + &request, &request_size, device.get_control_sequence(), static_cast(sleep_state)); + auto status = (HAILO_COMMON_STATUS__SUCCESS == common_status) ? HAILO_SUCCESS : HAILO_INTERNAL_FAILURE; + CHECK_SUCCESS(status); + + status = device.fw_interact((uint8_t*)(&request), request_size, (uint8_t*)&response_buffer, &response_size); + CHECK_SUCCESS(status); + + /* Parse response */ + status = parse_and_validate_response(response_buffer, (uint32_t)(response_size), &header, &payload, + &request); + CHECK_SUCCESS(status); + + return HAILO_SUCCESS; +} + } /* namespace hailort */ diff --git a/hailort/libhailort/src/control.hpp b/hailort/libhailort/src/control.hpp index 3e7e149..dd768af 100644 --- a/hailort/libhailort/src/control.hpp +++ b/hailort/libhailort/src/control.hpp @@ -261,20 +261,15 @@ public: static hailo_status sensor_reset(Device &device, uint32_t section_index); static hailo_status sensor_set_generic_i2c_slave(Device &device, uint16_t slave_address, uint8_t register_address_size, uint8_t bus_index, uint8_t should_hold_bus, uint8_t endianness); static hailo_status sensor_get_sections_info(Device &device, uint8_t *data); - /** - * Send to FW the context switch header details - * - * @param[in] device - The Hailo device. - * @param[in] context_switch_info - struct including all the data relevant for the fw - * - * @return Upon success, returns @a HAILO_SUCCESS. Otherwise, returns an @a static hailo_status error. - */ - static hailo_status write_context_switch_info(Device &device, CONTROL_PROTOCOL__context_switch_info_t *context_switch_info); + /** * Download generated context switch action list per single context * * @param[in] device - The Hailo device. - * @param[in] context_index - context index of the context the user wishes to download the action list + * @param[in] network_group_id - Unique identifier for the network group. + * @param[in] context_type - type of context + * @param[in] context_index - context index of the context the user wishes to download the action list. Should + * be 0 for non-dynamic contexts. * @param[out] base address - base address of the context action list in the FW memory * @param[out] action list - buffer of the action list * @param[out] action_list_length - size of the action list buffer @@ -282,8 +277,10 @@ public: * @return Upon success, returns @a HAILO_SUCCESS. Otherwise, returns an @a static hailo_status error. */ // TODO: fix - static hailo_status download_context_action_list(Device &device, uint8_t context_index, size_t action_list_max_size, - uint32_t *base_address, uint8_t *action_list, uint16_t *action_list_length, uint32_t *batch_counter); + static hailo_status download_context_action_list(Device &device, uint32_t network_group_id, + CONTROL_PROTOCOL__context_switch_context_type_t context_type, uint8_t context_index, + size_t action_list_max_size, uint32_t *base_address, uint8_t *action_list, uint16_t *action_list_length, + uint32_t *batch_counter); /** * Enable network group @@ -344,9 +341,9 @@ public: static hailo_status write_memory(Device &device, uint32_t address, const uint8_t *data, uint32_t data_length); static hailo_status read_memory(Device &device, uint32_t address, uint8_t *data, uint32_t data_length); static hailo_status context_switch_set_context_info(Device &device, - CONTROL_PROTOCOL__context_switch_context_info_t *context_info); - static hailo_status context_switch_set_main_header(Device &device, - CONTROL_PROTOCOL__context_switch_main_header_t *context_switch_header); + const std::vector &context_infos); + static hailo_status context_switch_set_network_group_header(Device &device, + const CONTROL_PROTOCOL__application_header_t &network_group_header); static hailo_status wd_enable(Device &device, uint8_t cpu_id, bool should_enable); static hailo_status wd_config(Device &device, uint8_t cpu_id, uint32_t wd_cycles, CONTROL_PROTOCOL__WATCHDOG_MODE_t wd_mode); static hailo_status previous_system_state(Device &device, uint8_t cpu_id, CONTROL_PROTOCOL__system_state_t *system_state); @@ -371,6 +368,8 @@ public: static Expected get_throttling_state(Device &device); static hailo_status set_overcurrent_state(Device &device, bool should_activate); static Expected get_overcurrent_state(Device &device); + static Expected get_hw_consts(Device &device); + static hailo_status set_sleep_state(Device &device, hailo_sleep_state_t sleep_state); // TODO: needed? static hailo_status power_measurement(Device &device, CONTROL_PROTOCOL__dvm_options_t dvm, @@ -391,11 +390,12 @@ private: static hailo_status read_user_config_chunk(Device &device, uint32_t read_offset, uint32_t read_length, uint8_t *buffer, uint32_t *actual_read_data_length); static hailo_status write_user_config_chunk(Device &device, uint32_t offset, const uint8_t *data, uint32_t chunk_size); - static hailo_status download_context_action_list_chunk(Device &device, uint8_t context_index, uint16_t action_list_offset, - size_t action_list_max_size, uint32_t *base_address, uint8_t *action_list, uint16_t *action_list_length, - bool *is_action_list_end, uint32_t *batch_counter); + static hailo_status download_context_action_list_chunk(Device &device, uint32_t network_group_id, + CONTROL_PROTOCOL__context_switch_context_type_t context_type, uint8_t context_index, uint16_t action_list_offset, + size_t action_list_max_size, uint32_t *base_address, uint8_t *action_list, uint16_t *action_list_length, + bool *is_action_list_end, uint32_t *batch_counter); static hailo_status context_switch_set_context_info_chunk(Device &device, - CONTROL_PROTOCOL__context_switch_context_info_single_control_t *context_info); + const CONTROL_PROTOCOL__context_switch_context_info_single_control_t &context_info); static hailo_status change_context_switch_status(Device &device, CONTROL_PROTOCOL__CONTEXT_SWITCH_STATUS_t state_machine_status, uint8_t network_group_index, uint16_t dynamic_batch_size, bool keep_nn_config_during_reset); diff --git a/hailort/libhailort/src/control_protocol.cpp b/hailort/libhailort/src/control_protocol.cpp index ee0c668..6d35440 100644 --- a/hailort/libhailort/src/control_protocol.cpp +++ b/hailort/libhailort/src/control_protocol.cpp @@ -333,6 +333,11 @@ HAILO_COMMON_STATUS_t CONTROL_PROTOCOL__pack_get_overcurrent_state_request(CONTR return control_protocol__pack_empty_request(request, request_size, sequence, HAILO_CONTROL_OPCODE_GET_OVERCURRENT_STATE); } +HAILO_COMMON_STATUS_t CONTROL_PROTOCOL__pack_get_hw_consts_request(CONTROL_PROTOCOL__request_t *request, size_t *request_size, uint32_t sequence) +{ + return control_protocol__pack_empty_request(request, request_size, sequence, HAILO_CONTROL_OPCODE_GET_HW_CONSTS); +} + HAILO_COMMON_STATUS_t CONTROL_PROTOCOL__pack_set_clock_freq_request(CONTROL_PROTOCOL__request_t *request, size_t *request_size, uint32_t sequence, uint32_t clock_freq) { @@ -497,6 +502,7 @@ HAILO_COMMON_STATUS_t control_protocol__pack_config_stream_base_request(CONTROL_ request->parameters.config_stream_request.nn_stream_config.core_bytes_per_buffer = BYTE_ORDER__htons(params->nn_stream_config.core_bytes_per_buffer); request->parameters.config_stream_request.nn_stream_config.core_buffers_per_frame = BYTE_ORDER__htons(params->nn_stream_config.core_buffers_per_frame); request->parameters.config_stream_request.nn_stream_config.periph_bytes_per_buffer = BYTE_ORDER__htons(params->nn_stream_config.periph_bytes_per_buffer); + request->parameters.config_stream_request.nn_stream_config.periph_buffers_per_frame = BYTE_ORDER__htons(params->nn_stream_config.periph_buffers_per_frame); request->parameters.config_stream_request.nn_stream_config.feature_padding_payload = BYTE_ORDER__htons(params->nn_stream_config.feature_padding_payload); request->parameters.config_stream_request.nn_stream_config.buffer_padding_payload = BYTE_ORDER__htons(params->nn_stream_config.buffer_padding_payload); request->parameters.config_stream_request.nn_stream_config.buffer_padding = BYTE_ORDER__htons(params->nn_stream_config.buffer_padding); @@ -1621,40 +1627,29 @@ HAILO_COMMON_STATUS_t CONTROL_PROTOCOL__pack_sensor_get_sections_info_request(CO return control_protocol__pack_empty_request(request, request_size, sequence, HAILO_CONTROL_OPCODE_SENSOR_GET_SECTIONS_INFO); } -HAILO_COMMON_STATUS_t CONTROL_PROTOCOL__pack_context_switch_set_main_header_request( - CONTROL_PROTOCOL__request_t *request, size_t *request_size, uint32_t sequence, - CONTROL_PROTOCOL__context_switch_main_header_t *context_switch_header) +HAILO_COMMON_STATUS_t CONTROL_PROTOCOL__pack_context_switch_set_network_group_header_request( + CONTROL_PROTOCOL__request_t *request, size_t *request_size, uint32_t sequence, + const CONTROL_PROTOCOL__application_header_t *network_group_header) { HAILO_COMMON_STATUS_t status = HAILO_COMMON_STATUS__UNINITIALIZED; size_t local_request_size = 0; - if ((NULL == request) || (NULL == request_size) || (NULL == context_switch_header)) { + if ((NULL == request) || (NULL == request_size) || (NULL == network_group_header)) { status = HAILO_STATUS__CONTROL_PROTOCOL__NULL_ARGUMENT_PASSED; goto exit; } /* Header */ - local_request_size = CONTROL_PROTOCOL__REQUEST_BASE_SIZE + sizeof(CONTROL_PROTOCOL__context_switch_set_main_header_request_t); - control_protocol__pack_request_header(request, sequence, HAILO_CONTROL_OPCODE_CONTEXT_SWITCH_SET_MAIN_HEADER, 3); - - /* context_switch_version */ - request->parameters.context_switch_set_main_header_request.context_switch_version_length = - BYTE_ORDER__htonl(sizeof(request->parameters.context_switch_set_main_header_request.context_switch_version)); - request->parameters.context_switch_set_main_header_request.context_switch_version = - context_switch_header->context_switch_version; - - /* application_count */ - request->parameters.context_switch_set_main_header_request.application_count_length = - BYTE_ORDER__htonl(sizeof(request->parameters.context_switch_set_main_header_request.application_count)); - request->parameters.context_switch_set_main_header_request.application_count = - context_switch_header->application_count; + local_request_size = CONTROL_PROTOCOL__REQUEST_BASE_SIZE + sizeof(CONTROL_PROTOCOL__context_switch_set_network_group_header_request_t); + control_protocol__pack_request_header(request, sequence, + HAILO_CONTROL_OPCODE_CONTEXT_SWITCH_SET_NETWORK_GROUP_HEADER, 1); /* application_header */ - request->parameters.context_switch_set_main_header_request.application_header_length = - BYTE_ORDER__htonl(sizeof(request->parameters.context_switch_set_main_header_request.application_header)); - memcpy(&(request->parameters.context_switch_set_main_header_request.application_header), - &(context_switch_header->application_header), - sizeof(request->parameters.context_switch_set_main_header_request.application_header)); + request->parameters.context_switch_set_network_group_header_request.application_header_length = + BYTE_ORDER__htonl(sizeof(request->parameters.context_switch_set_network_group_header_request.application_header)); + memcpy(&(request->parameters.context_switch_set_network_group_header_request.application_header), + network_group_header, + sizeof(request->parameters.context_switch_set_network_group_header_request.application_header)); *request_size = local_request_size; status = HAILO_COMMON_STATUS__SUCCESS; @@ -1663,8 +1658,8 @@ exit: } HAILO_COMMON_STATUS_t CONTROL_PROTOCOL__pack_context_switch_set_context_info_request( - CONTROL_PROTOCOL__request_t *request, size_t *request_size, uint32_t sequence, - CONTROL_PROTOCOL__context_switch_context_info_single_control_t *context_info) + CONTROL_PROTOCOL__request_t *request, size_t *request_size, uint32_t sequence, + const CONTROL_PROTOCOL__context_switch_context_info_single_control_t *context_info) { HAILO_COMMON_STATUS_t status = HAILO_COMMON_STATUS__UNINITIALIZED; size_t local_request_size = 0; @@ -1677,7 +1672,7 @@ HAILO_COMMON_STATUS_t CONTROL_PROTOCOL__pack_context_switch_set_context_info_req /* Header */ local_request_size = CONTROL_PROTOCOL__REQUEST_BASE_SIZE + sizeof(CONTROL_PROTOCOL__context_switch_set_context_info_request_t) + context_info->context_network_data_length; - control_protocol__pack_request_header(request, sequence, HAILO_CONTROL_OPCODE_CONTEXT_SWITCH_SET_CONTEXT_INFO, 8); + control_protocol__pack_request_header(request, sequence, HAILO_CONTROL_OPCODE_CONTEXT_SWITCH_SET_CONTEXT_INFO, 5); /* is_first_control_per_context */ request->parameters.context_switch_set_context_info_request.is_first_control_per_context_length = @@ -1691,37 +1686,20 @@ HAILO_COMMON_STATUS_t CONTROL_PROTOCOL__pack_context_switch_set_context_info_req request->parameters.context_switch_set_context_info_request.is_last_control_per_context = context_info->is_last_control_per_context; - /* cfg_channels_count */ - request->parameters.context_switch_set_context_info_request.cfg_channels_count_length = - BYTE_ORDER__htonl(sizeof(request->parameters.context_switch_set_context_info_request.cfg_channels_count)); - request->parameters.context_switch_set_context_info_request.cfg_channels_count = context_info->cfg_channels_count; - - /* context cfg buffer info */ - request->parameters.context_switch_set_context_info_request.config_channel_infos_length = - BYTE_ORDER__htonl(sizeof(request->parameters.context_switch_set_context_info_request.config_channel_infos)); - memcpy(&(request->parameters.context_switch_set_context_info_request.config_channel_infos), - &(context_info->config_channel_infos), - sizeof(request->parameters.context_switch_set_context_info_request.config_channel_infos)); - - /* context unused stream index */ - request->parameters.context_switch_set_context_info_request.context_stream_remap_data_length = - BYTE_ORDER__htonl(sizeof(request->parameters.context_switch_set_context_info_request.context_stream_remap_data)); - request->parameters.context_switch_set_context_info_request.context_stream_remap_data = - context_info->context_stream_remap_data; - - /* number of edge layer */ - request->parameters.context_switch_set_context_info_request.number_of_edge_layers_length = - BYTE_ORDER__htonl(sizeof(request->parameters.context_switch_set_context_info_request.number_of_edge_layers)); - request->parameters.context_switch_set_context_info_request.number_of_edge_layers = context_info->number_of_edge_layers; - - /* number of trigger groups */ - request->parameters.context_switch_set_context_info_request.number_of_trigger_groups_length = - BYTE_ORDER__htonl(sizeof(request->parameters.context_switch_set_context_info_request.number_of_trigger_groups)); - request->parameters.context_switch_set_context_info_request.number_of_trigger_groups = - context_info->number_of_trigger_groups; + /* context_type */ + request->parameters.context_switch_set_context_info_request.context_type_length = + BYTE_ORDER__htonl(sizeof(request->parameters.context_switch_set_context_info_request.context_type)); + request->parameters.context_switch_set_context_info_request.context_type = + context_info->context_type; + + /* actions_count */ + request->parameters.context_switch_set_context_info_request.actions_count_length = + BYTE_ORDER__htonl(sizeof(request->parameters.context_switch_set_context_info_request.actions_count)); + request->parameters.context_switch_set_context_info_request.actions_count = + BYTE_ORDER__htonl(context_info->actions_count); /* Network data (edge layers + Trigger groups) */ - if (CONTROL_PROTOCOL__CONTEXT_NETWORK_DATA_MAX_SIZE < context_info->context_network_data_length) { + if (CONTROL_PROTOCOL__CONTEXT_NETWORK_DATA_SINGLE_CONTROL_MAX_SIZE < context_info->context_network_data_length) { status = HAILO_STATUS__CONTROL_PROTOCOL__INVALID_BUFFER_SIZE; goto exit; } @@ -1793,7 +1771,8 @@ HAILO_COMMON_STATUS_t CONTROL_PROTOCOL__pack_set_pause_frames_request(CONTROL_PR } HAILO_COMMON_STATUS_t CONTROL_PROTOCOL__pack_download_context_action_list_request(CONTROL_PROTOCOL__request_t *request, - size_t *request_size, uint32_t sequence, uint8_t context_index, uint16_t action_list_offset) + size_t *request_size, uint32_t sequence, uint32_t network_group_id, + CONTROL_PROTOCOL__context_switch_context_type_t context_type, uint8_t context_index, uint16_t action_list_offset) { HAILO_COMMON_STATUS_t status = HAILO_COMMON_STATUS__UNINITIALIZED; size_t local_request_size = 0; @@ -1805,19 +1784,27 @@ HAILO_COMMON_STATUS_t CONTROL_PROTOCOL__pack_download_context_action_list_reques /* Header */ local_request_size = CONTROL_PROTOCOL__REQUEST_BASE_SIZE + sizeof(CONTROL_PROTOCOL__download_context_action_list_request_t); - control_protocol__pack_request_header(request, sequence, HAILO_CONTROL_OPCODE_DOWNLOAD_CONTEXT_ACTION_LIST, 2); + control_protocol__pack_request_header(request, sequence, HAILO_CONTROL_OPCODE_DOWNLOAD_CONTEXT_ACTION_LIST, 4); + + /* network_group_id */ + request->parameters.download_context_action_list_request.network_group_id_length = + BYTE_ORDER__htonl(sizeof(request->parameters.download_context_action_list_request.network_group_id)); + request->parameters.download_context_action_list_request.network_group_id = BYTE_ORDER__htonl(network_group_id); + + /* context_type */ + request->parameters.download_context_action_list_request.context_type_length = + BYTE_ORDER__htonl(sizeof(request->parameters.download_context_action_list_request.context_type)); + request->parameters.download_context_action_list_request.context_type = static_cast(context_type); /* context_index */ request->parameters.download_context_action_list_request.context_index_length = BYTE_ORDER__htonl(sizeof(request->parameters.download_context_action_list_request.context_index)); - memcpy(&(request->parameters.download_context_action_list_request.context_index), - &(context_index), sizeof(request->parameters.download_context_action_list_request.context_index)); + request->parameters.download_context_action_list_request.context_index = context_index; /* action_list_offset */ request->parameters.download_context_action_list_request.action_list_offset_length = BYTE_ORDER__htonl(sizeof(request->parameters.download_context_action_list_request.action_list_offset)); - memcpy(&(request->parameters.download_context_action_list_request.action_list_offset), - &(action_list_offset), sizeof(request->parameters.download_context_action_list_request.action_list_offset)); + request->parameters.download_context_action_list_request.action_list_offset = BYTE_ORDER__htons(action_list_offset); *request_size = local_request_size; status = HAILO_COMMON_STATUS__SUCCESS; @@ -2376,4 +2363,32 @@ HAILO_COMMON_STATUS_t CONTROL_PROTOCOL__pack_run_bist_test_request( return HAILO_COMMON_STATUS__SUCCESS; } +HAILO_COMMON_STATUS_t CONTROL_PROTOCOL__pack_set_sleep_state_request( + CONTROL_PROTOCOL__request_t *request, size_t *request_size, uint32_t sequence, + uint8_t sleep_state) +{ + HAILO_COMMON_STATUS_t status = HAILO_COMMON_STATUS__UNINITIALIZED; + size_t local_request_size = 0; + + if ((NULL == request) || (NULL == request_size)) { + status = HAILO_STATUS__CONTROL_PROTOCOL__NULL_ARGUMENT_PASSED; + goto exit; + } + + /* Header */ + local_request_size = CONTROL_PROTOCOL__REQUEST_BASE_SIZE + + sizeof(CONTROL_PROTOCOL__set_sleep_state_request_t); + control_protocol__pack_request_header(request, sequence, HAILO_CONTROL_OPCODE_SET_SLEEP_STATE, 1); + + /* sleep_state */ + request->parameters.set_sleep_state_request.sleep_state_length = + BYTE_ORDER__htonl(sizeof(request->parameters.set_sleep_state_request.sleep_state)); + request->parameters.set_sleep_state_request.sleep_state = sleep_state; + + *request_size = local_request_size; + status = HAILO_COMMON_STATUS__SUCCESS; +exit: + return status; +} + #endif /* FIRMWARE_ARCH */ diff --git a/hailort/libhailort/src/control_protocol.hpp b/hailort/libhailort/src/control_protocol.hpp index 26e18d0..9092cd8 100644 --- a/hailort/libhailort/src/control_protocol.hpp +++ b/hailort/libhailort/src/control_protocol.hpp @@ -30,35 +30,9 @@ typedef struct { CONTROL_PROTOCOL__communication_config_prams_t communication_params; } CONTROL_PROTOCOL__config_stream_params_t; -/* Context switch user structs */ -#define CONTROL_PROTCOL__CONTEXT_SLICING_OFFSETS \ - ((CONTROL_PROTOCOL__CONTEXT_NETWORK_DATA_MAX_SIZE / CONTROL_PROTOCOL__CONTEXT_NETWORK_DATA_SINGLE_CONTROL_MAX_SIZE) + 1) +static_assert(sizeof(CONTROL_PROTOCOL__context_switch_context_index_t) <= UINT8_MAX, + "CONTROL_PROTOCOL__context_switch_context_index_t must fit in uint8_t"); -typedef struct { - /* Tempurary building info, used when creating meta data*/ - CONTROL_PROTOCOL__trigger_group_t *current_building_trigger; - uint8_t current_building_slice_index; - uint16_t current_buillding_offset_inside_slice; - /* Control slicing information */ - uint16_t control_slicing_offsets[CONTROL_PROTCOL__CONTEXT_SLICING_OFFSETS]; - uint8_t slice_edge_layers[CONTROL_PROTCOL__CONTEXT_SLICING_OFFSETS]; - uint8_t slice_triggers[CONTROL_PROTCOL__CONTEXT_SLICING_OFFSETS]; -} CONTEXT_SWITCH__context_control_slicing_data_t; - -typedef struct { - uint8_t cfg_channels_count; - CONTROL_PROTOCOL__config_channel_info_t config_channel_infos[CONTROL_PROTOCOL__MAX_CFG_CHANNELS]; - uint32_t context_network_data_length; - CONTROL_PROTOCOL__stream_remap_data_t context_stream_remap_data; - uint8_t context_network_data[CONTROL_PROTOCOL__CONTEXT_NETWORK_DATA_MAX_SIZE]; - /* control_slicing_data is used in internal hef_metadata.cpp functions only */ - CONTEXT_SWITCH__context_control_slicing_data_t control_slicing_data; -} CONTROL_PROTOCOL__context_switch_context_info_t; - -typedef struct { - CONTROL_PROTOCOL__context_switch_main_header_t context_switch_main_header; - CONTROL_PROTOCOL__context_switch_context_info_t context[CONTROL_PROTOCOL__MAX_TOTAL_CONTEXTS]; -} CONTROL_PROTOCOL__context_switch_info_t; /* End of context switch structs */ const char *CONTROL_PROTOCOL__get_textual_opcode(CONTROL_PROTOCOL__OPCODE_t opcode); @@ -118,16 +92,17 @@ HAILO_COMMON_STATUS_t CONTROL_PROTOCOL__pack_sensor_reset_request(CONTROL_PROTOC HAILO_COMMON_STATUS_t CONTROL_PROTOCOL__pack_sensor_set_generic_i2c_slave_request(CONTROL_PROTOCOL__request_t *request, size_t *request_size, uint32_t sequence, uint16_t slave_address, uint8_t register_address_size, uint8_t bus_index, uint8_t should_hold_bus, uint8_t endianness); HAILO_COMMON_STATUS_t CONTROL_PROTOCOL__pack_sensor_get_sections_info_request(CONTROL_PROTOCOL__request_t *request, size_t *request_size, uint32_t sequence); -HAILO_COMMON_STATUS_t CONTROL_PROTOCOL__pack_context_switch_set_main_header_request( - CONTROL_PROTOCOL__request_t *request, size_t *request_size, uint32_t sequence, - CONTROL_PROTOCOL__context_switch_main_header_t *context_switch_header); +HAILO_COMMON_STATUS_t CONTROL_PROTOCOL__pack_context_switch_set_network_group_header_request( + CONTROL_PROTOCOL__request_t *request, size_t *request_size, uint32_t sequence, + const CONTROL_PROTOCOL__application_header_t *network_group_header); HAILO_COMMON_STATUS_t CONTROL_PROTOCOL__pack_context_switch_set_context_info_request( CONTROL_PROTOCOL__request_t *request, size_t *request_size, uint32_t sequence, - CONTROL_PROTOCOL__context_switch_context_info_single_control_t *context_info); + const CONTROL_PROTOCOL__context_switch_context_info_single_control_t *context_info); HAILO_COMMON_STATUS_t CONTROL_PROTOCOL__pack_idle_time_set_measuremment_request(CONTROL_PROTOCOL__request_t *request, size_t *request_size, uint32_t sequence, uint8_t measurement_enable); HAILO_COMMON_STATUS_t CONTROL_PROTOCOL__pack_idle_time_get_measuremment_request(CONTROL_PROTOCOL__request_t *request, size_t *request_size, uint32_t sequence); -HAILO_COMMON_STATUS_t CONTROL_PROTOCOL__pack_download_context_action_list_request(CONTROL_PROTOCOL__request_t *request, - size_t *request_size, uint32_t sequence, uint8_t context_index, uint16_t action_list_offset); +HAILO_COMMON_STATUS_t CONTROL_PROTOCOL__pack_download_context_action_list_request(CONTROL_PROTOCOL__request_t *request, + size_t *request_size, uint32_t sequence, uint32_t network_group_id, + CONTROL_PROTOCOL__context_switch_context_type_t context_type, uint8_t context_index, uint16_t action_list_offset); HAILO_COMMON_STATUS_t CONTROL_PROTOCOL__pack_change_context_switch_status_request( CONTROL_PROTOCOL__request_t *request, size_t *request_size, uint32_t sequence, CONTROL_PROTOCOL__CONTEXT_SWITCH_STATUS_t state_machine_status, uint8_t application_index, @@ -193,5 +168,7 @@ HAILO_COMMON_STATUS_t CONTROL_PROTOCOL__pack_set_throttling_state_request(CONTRO HAILO_COMMON_STATUS_t CONTROL_PROTOCOL__pack_get_throttling_state_request(CONTROL_PROTOCOL__request_t *request, size_t *request_size, uint32_t sequence); HAILO_COMMON_STATUS_t CONTROL_PROTOCOL__pack_set_overcurrent_state_request(CONTROL_PROTOCOL__request_t *request, size_t *request_size, uint32_t sequence, bool should_activate); HAILO_COMMON_STATUS_t CONTROL_PROTOCOL__pack_get_overcurrent_state_request(CONTROL_PROTOCOL__request_t *request, size_t *request_size, uint32_t sequence); +HAILO_COMMON_STATUS_t CONTROL_PROTOCOL__pack_get_hw_consts_request(CONTROL_PROTOCOL__request_t *request, size_t *request_size, uint32_t sequence); +HAILO_COMMON_STATUS_t CONTROL_PROTOCOL__pack_set_sleep_state_request(CONTROL_PROTOCOL__request_t *request, size_t *request_size, uint32_t sequence, uint8_t sleep_state); #endif /* _CONTROL_PROTOCOL_HPP_ */ \ No newline at end of file diff --git a/hailort/libhailort/src/core_device.cpp b/hailort/libhailort/src/core_device.cpp index 2a15606..12d8ff7 100644 --- a/hailort/libhailort/src/core_device.cpp +++ b/hailort/libhailort/src/core_device.cpp @@ -7,7 +7,6 @@ #include -static const std::chrono::milliseconds CORE_DEFAULT_TIMEOUT = std::chrono::milliseconds(1000); static const std::string CORE_DRIVER_PATH = "/dev/hailo_core"; namespace hailort @@ -30,7 +29,7 @@ Expected> CoreDevice::create() auto driver = HailoRTDriver::create(CORE_DRIVER_PATH); CHECK_EXPECTED(driver, "Failed to initialize HailoRTDriver"); - auto device = std::unique_ptr(new (std::nothrow) CoreDevice(driver.release(), status)); + auto device = std::unique_ptr(new (std::nothrow) CoreDevice(driver.release(), status, DEVICE_ID)); CHECK_AS_EXPECTED((nullptr != device), HAILO_OUT_OF_HOST_MEMORY); CHECK_SUCCESS_AS_EXPECTED(status, "Failed creating CoreDevice"); @@ -38,9 +37,8 @@ Expected> CoreDevice::create() } -CoreDevice::CoreDevice(HailoRTDriver &&driver, hailo_status &status) : - VdmaDevice::VdmaDevice(std::move(driver), Device::Type::CORE), - m_context_switch_manager(nullptr) +CoreDevice::CoreDevice(HailoRTDriver &&driver, hailo_status &status, const std::string &device_id) : + VdmaDevice::VdmaDevice(std::move(driver), Device::Type::CORE, device_id) { status = update_fw_state(); if (HAILO_SUCCESS != status) { @@ -51,45 +49,10 @@ CoreDevice::CoreDevice(HailoRTDriver &&driver, hailo_status &status) : status = HAILO_SUCCESS; } -CoreDevice::~CoreDevice() {} - Expected CoreDevice::get_architecture() const { return Expected(m_device_architecture); } -hailo_status CoreDevice::fw_interact_impl(uint8_t *request_buffer, size_t request_size, - uint8_t *response_buffer, size_t *response_size, hailo_cpu_id_t cpu_id) -{ - // TODO: HRT-7535 - uint8_t request_md5[PCIE_EXPECTED_MD5_LENGTH]; - MD5_CTX ctx; - - // TODO HRT-5358 - Unify MD5 functions. Use by pcie and core driver (and FW) - MD5_Init(&ctx); - MD5_Update(&ctx, request_buffer, request_size); - MD5_Final(request_md5, &ctx); - - uint8_t response_md5[PCIE_EXPECTED_MD5_LENGTH]; - uint8_t expected_response_md5[PCIE_EXPECTED_MD5_LENGTH]; - - auto status = m_driver.fw_control(request_buffer, request_size, request_md5, - response_buffer, response_size, response_md5, - CORE_DEFAULT_TIMEOUT, cpu_id); - CHECK_SUCCESS(status, "Failed to send fw control"); - - MD5_Init(&ctx); - MD5_Update(&ctx, response_buffer, (*response_size)); - MD5_Final(expected_response_md5, &ctx); - - auto memcmp_result = memcmp(expected_response_md5, response_md5, sizeof(response_md5)); - if (0 != memcmp_result) { - LOGGER__ERROR("MD5 validation of control reesponse failed."); - return HAILO_INTERNAL_FAILURE; - } - - return HAILO_SUCCESS; -} - hailo_status CoreDevice::reset_impl(CONTROL_PROTOCOL__reset_type_t reset_type) { if (CONTROL_PROTOCOL__RESET_TYPE__NN_CORE == reset_type) { @@ -100,22 +63,6 @@ hailo_status CoreDevice::reset_impl(CONTROL_PROTOCOL__reset_type_t reset_type) return HAILO_NOT_IMPLEMENTED; } -ExpectedRef CoreDevice::get_config_manager() -{ - auto status = mark_as_used(); - CHECK_SUCCESS_AS_EXPECTED(status); - - if (!m_context_switch_manager) { - auto local_context_switch_manager = VdmaConfigManager::create(*this); - CHECK_EXPECTED(local_context_switch_manager); - - m_context_switch_manager = make_unique_nothrow(local_context_switch_manager.release()); - CHECK_AS_EXPECTED(nullptr != m_context_switch_manager, HAILO_OUT_OF_HOST_MEMORY); - } - - return std::ref(*m_context_switch_manager); -} - Expected CoreDevice::read_log(MemoryView &buffer, hailo_cpu_id_t cpu_id) { if (hailo_cpu_id_t::HAILO_CPU_ID_0 == cpu_id) { diff --git a/hailort/libhailort/src/core_device.hpp b/hailort/libhailort/src/core_device.hpp index f7e97fd..05014fc 100644 --- a/hailort/libhailort/src/core_device.hpp +++ b/hailort/libhailort/src/core_device.hpp @@ -22,7 +22,7 @@ namespace hailort class CoreDevice : public VdmaDevice { public: - virtual ~CoreDevice(); + virtual ~CoreDevice() = default; static bool is_loaded(); static Expected> create(); @@ -48,20 +48,10 @@ public: static constexpr const char *DEVICE_ID = "[core]"; protected: - virtual hailo_status fw_interact_impl(uint8_t *request_buffer, size_t request_size, - uint8_t *response_buffer, size_t *response_size, hailo_cpu_id_t cpu_id) override; virtual hailo_status reset_impl(CONTROL_PROTOCOL__reset_type_t reset_type) override; - virtual ExpectedRef get_config_manager() override; private: - CoreDevice(HailoRTDriver &&driver, hailo_status &status); - - // TODO: (HRT-7535) This member needs to be held in the object that impls fw_interact_impl func, - // because VdmaConfigManager calls a control (which in turn calls fw_interact_impl). - // (otherwise we'll get a "pure virtual method called" runtime error in the Device's dtor) - // Once we merge CoreDevice::fw_interact_impl and PcieDevice::fw_interact_impl we can - // move the m_context_switch_manager member and get_config_manager() func to VdmaDevice. - std::unique_ptr m_context_switch_manager; + CoreDevice(HailoRTDriver &&driver, hailo_status &status, const std::string &device_id); }; diff --git a/hailort/libhailort/src/ddr_channels_pair.cpp b/hailort/libhailort/src/ddr_channels_pair.cpp index 82edbd6..68c99b2 100644 --- a/hailort/libhailort/src/ddr_channels_pair.cpp +++ b/hailort/libhailort/src/ddr_channels_pair.cpp @@ -45,7 +45,7 @@ uint32_t DdrChannelsPair::descriptors_per_frame() const return (m_info.row_size / m_buffer->desc_page_size()) * m_info.total_buffers_per_frame; } -Expected DdrChannelsPair::read() +Expected DdrChannelsPair::read() const { const auto size = m_buffer->size(); auto res = Buffer::create(size); diff --git a/hailort/libhailort/src/ddr_channels_pair.hpp b/hailort/libhailort/src/ddr_channels_pair.hpp index ec87533..25f0214 100644 --- a/hailort/libhailort/src/ddr_channels_pair.hpp +++ b/hailort/libhailort/src/ddr_channels_pair.hpp @@ -23,6 +23,7 @@ struct DdrChannelsInfo uint8_t d2h_stream_index; vdma::ChannelId h2d_channel_id; uint8_t h2d_stream_index; + uint8_t network_index; uint16_t row_size; uint16_t min_buffered_rows; // total_buffers_per_frame not same as core_buffer_per frame. @@ -37,7 +38,7 @@ public: uint16_t descs_count() const; uint32_t descriptors_per_frame() const; - Expected read(); + Expected read() const; const DdrChannelsInfo & info() const; // Checks if the credits are automaticaly going from d2h channel to its h2d channel, or it needs to be done manually diff --git a/hailort/libhailort/src/device.cpp b/hailort/libhailort/src/device.cpp index 530e59e..a14bec8 100644 --- a/hailort/libhailort/src/device.cpp +++ b/hailort/libhailort/src/device.cpp @@ -295,30 +295,6 @@ Expected Device::power_measurement(hailo_dvm_options_t dvm, hailo_pow return res; } -hailo_status Device::start_power_measurement(uint32_t /*unused*/, hailo_averaging_factor_t averaging_factor, hailo_sampling_period_t sampling_period) -{ - // TODO: Remove deprecated function - LOGGER__WARNING("'Device::start_power_measurement(uint32_t unused, hailo_averaging_factor_t averaging_factor, hailo_sampling_period_t sampling_period)' is deprecated. "\ - "One should use ''Device::start_power_measurement(hailo_averaging_factor_t averaging_factor, hailo_sampling_period_t sampling_period)"); - return start_power_measurement(averaging_factor, sampling_period); -} - -hailo_status Device::set_power_measurement(uint32_t index, hailo_dvm_options_t dvm, hailo_power_measurement_types_t measurement_type) -{ - // TODO: Remove deprecated function - LOGGER__WARNING("'Device::set_power_measurement(uint32_t index, hailo_dvm_options_t dvm, hailo_power_measurement_types_t measurement_type)' is deprecated. "\ - "One should use ''Device::set_power_measurement(hailo_measurement_buffer_index_t buffer_index, hailo_dvm_options_t dvm, hailo_power_measurement_types_t measurement_type)"); - return set_power_measurement(static_cast(index), dvm, measurement_type); -} - -Expected Device::get_power_measurement(uint32_t index, bool should_clear) -{ - // TODO: Remove deprecated function - LOGGER__WARNING("'Device::get_power_measurement(uint32_t index, bool should_clear)' is deprecated. "\ - "One should use ''Device::set_power_measurement(hailo_measurement_buffer_index_t buffer_index, bool should_clear)"); - return get_power_measurement(static_cast(index), should_clear); -} - hailo_status Device::start_power_measurement(hailo_averaging_factor_t averaging_factor, hailo_sampling_period_t sampling_period) { return Control::start_power_measurement(*this, static_cast(averaging_factor), @@ -356,6 +332,11 @@ hailo_status Device::test_chip_memories() return Control::test_chip_memories(*this); } +hailo_status Device::set_sleep_state(hailo_sleep_state_t sleep_state) +{ + return Control::set_sleep_state(*this, sleep_state); +} + hailo_status Device::direct_write_memory(uint32_t address, const void *buffer, uint32_t size) { (void) address; @@ -467,31 +448,24 @@ Expected Device::get_health_information() return Control::get_health_information(*this); } -Expected> Device::get_number_of_contexts_per_network_group() +Expected> Device::get_number_of_dynamic_contexts_per_network_group() { CONTROL_PROTOCOL__context_switch_main_header_t context_switch_main_header{}; const auto status = Control::get_context_switch_main_header(*this, &context_switch_main_header); CHECK_SUCCESS_AS_EXPECTED(status); - uint32_t total_number_of_contexts = 0; std::vector number_of_contexts_per_network_group; for (auto network_group_index = 0; network_group_index < context_switch_main_header.application_count; network_group_index++) { - // # of contexts in a network group = # of non preliminary contexts + 1 for the preliminary context - const uint32_t num_contexts = context_switch_main_header.application_header[network_group_index].dynamic_contexts_count + 1; + const uint32_t num_contexts = context_switch_main_header.application_header[network_group_index].dynamic_contexts_count; CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(num_contexts), HAILO_INTERNAL_FAILURE, "num_contexts must fit in one byte"); number_of_contexts_per_network_group.emplace_back(static_cast(num_contexts)); - total_number_of_contexts += number_of_contexts_per_network_group.back(); } - // Total number of contexts need to fit in 1B - checking for overflow - CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(total_number_of_contexts), HAILO_INTERNAL_FAILURE, - "Context indexes are expected to fit in 1B. actual size is {}", total_number_of_contexts); - return number_of_contexts_per_network_group; } -Expected Device::download_context_action_list(uint8_t context_index, uint32_t *base_address, - uint32_t *batch_counter, uint16_t max_size) +Expected Device::download_context_action_list(uint32_t network_group_id, uint8_t context_type, + uint8_t context_index, uint32_t *base_address, uint32_t *batch_counter, uint16_t max_size) { CHECK_ARG_NOT_NULL_AS_EXPECTED(base_address); CHECK_ARG_NOT_NULL_AS_EXPECTED(batch_counter); @@ -503,7 +477,8 @@ Expected Device::download_context_action_list(uint8_t context_index, uin uint32_t base_address_local = 0; uint32_t batch_counter_local = 0; uint16_t actual_size = 0; - const auto status = Control::download_context_action_list(*this, context_index, action_list->size(), + const auto status = Control::download_context_action_list(*this, network_group_id, + (CONTROL_PROTOCOL__context_switch_context_type_t)context_type, context_index, action_list->size(), &base_address_local, action_list->data(), &actual_size, &batch_counter_local); CHECK_SUCCESS_AS_EXPECTED(status); CHECK_AS_EXPECTED(actual_size <= max_size, HAILO_INTERNAL_FAILURE); @@ -525,6 +500,61 @@ hailo_status Device::set_context_action_list_timestamp_batch(uint16_t batch_inde return Control::config_context_switch_timestamp(*this, batch_index, ENABLE_USER_CONFIG); } +hailo_status Device::set_context_switch_breakpoint(uint8_t breakpoint_id, bool break_at_any_network_group_index, + uint8_t network_group_index, bool break_at_any_batch_index, uint16_t batch_index, bool break_at_any_context_index, + uint8_t context_index, bool break_at_any_action_index, uint16_t action_index) +{ + CONTROL_PROTOCOL__context_switch_breakpoint_data_t breakpoint_data = { + break_at_any_network_group_index, + network_group_index, + break_at_any_batch_index, + batch_index, + break_at_any_context_index, + context_index, + break_at_any_action_index, + action_index}; + + auto status = Control::config_context_switch_breakpoint(*this, breakpoint_id, + CONTROL_PROTOCOL__CONTEXT_SWITCH_BREAKPOINT_CONTROL_SET, &breakpoint_data); + CHECK_SUCCESS(status, "Failed Setting context switch breakpoint in continue breakpoint"); + + return HAILO_SUCCESS; +} + +hailo_status Device::continue_context_switch_breakpoint(uint8_t breakpoint_id) +{ + CONTROL_PROTOCOL__context_switch_breakpoint_data_t breakpoint_data = {false, 0, false, 0, false, 0, false, 0}; + + auto status = Control::config_context_switch_breakpoint(*this, breakpoint_id, + CONTROL_PROTOCOL__CONTEXT_SWITCH_BREAKPOINT_CONTROL_CONTINUE, &breakpoint_data); + CHECK_SUCCESS(status, "Failed Setting context switch breakpoint in continue breakpoint"); + + return HAILO_SUCCESS; +} + +hailo_status Device::clear_context_switch_breakpoint(uint8_t breakpoint_id) +{ + CONTROL_PROTOCOL__context_switch_breakpoint_data_t breakpoint_data = {false, 0, false, 0, false, 0, false, 0}; + + auto status = Control::config_context_switch_breakpoint(*this, breakpoint_id, + CONTROL_PROTOCOL__CONTEXT_SWITCH_BREAKPOINT_CONTROL_CLEAR, &breakpoint_data); + CHECK_SUCCESS(status, "Failed Setting context switch breakpoint in clear breakpoint"); + + return HAILO_SUCCESS; +} + +Expected Device::get_context_switch_breakpoint_status(uint8_t breakpoint_id) +{ + CONTROL_PROTOCOL__context_switch_debug_sys_status_t breakpoint_status = + CONTROL_PROTOCOL__CONTEXT_SWITCH_DEBUG_SYS_STATUS_COUNT; + + auto status = Control::get_context_switch_breakpoint_status(*this, breakpoint_id, + &breakpoint_status); + CHECK_SUCCESS_AS_EXPECTED(status, "Failed getting context switch breakpoint"); + + return static_cast(breakpoint_status); +} + Expected> Device::create_core() { auto core_device = CoreDevice::create(); diff --git a/hailort/libhailort/src/device_internal.cpp b/hailort/libhailort/src/device_internal.cpp index 1b0a3a4..c4ea862 100644 --- a/hailort/libhailort/src/device_internal.cpp +++ b/hailort/libhailort/src/device_internal.cpp @@ -45,10 +45,7 @@ Expected DeviceBase::configure(Hef &hef, auto status = check_hef_is_compatible(hef); CHECK_SUCCESS_AS_EXPECTED(status); - auto context_switch_manager = get_config_manager(); - CHECK_EXPECTED(context_switch_manager); - - auto network_groups = context_switch_manager->get().add_hef(hef, configure_params); + auto network_groups = add_hef(hef, configure_params); CHECK_EXPECTED(network_groups); auto elapsed_time_ms = std::chrono::duration(std::chrono::steady_clock::now() - start_time).count(); @@ -226,6 +223,12 @@ hailo_status DeviceBase::firmware_update(const MemoryView &firmware_binary, bool CHECK_SUCCESS(status, "Invalid APP firmware binary was supplied"); status = validate_fw_version_for_platform(board_info_before_update, new_core_fw_version, FW_BINARY_TYPE_CORE_FIRMWARE); CHECK_SUCCESS(status, "Invalid CORE firmware binary was supplied"); + + if (IS_REVISION_EXTENDED_CONTEXT_SWITCH_BUFFER(new_app_firmware_header->firmware_revision) || + IS_REVISION_EXTENDED_CONTEXT_SWITCH_BUFFER(new_core_firmware_header->firmware_revision)) { + LOGGER__ERROR("Can't update to \"extended context switch buffer\" firmware (no ethernet support)."); + return HAILO_INVALID_FIRMWARE; + } // TODO: Fix cast, we are assuming they are the same (HRT-3177) current_fw_version = reinterpret_cast(&(board_info_before_update.fw_version)); diff --git a/hailort/libhailort/src/device_internal.hpp b/hailort/libhailort/src/device_internal.hpp index c0b0668..20df820 100644 --- a/hailort/libhailort/src/device_internal.hpp +++ b/hailort/libhailort/src/device_internal.hpp @@ -26,7 +26,6 @@ #include "firmware_header.h" #include "firmware_header_utils.h" #include "control_protocol.h" -#include "context_switch/config_manager.hpp" #include "hef_internal.hpp" #include @@ -101,7 +100,7 @@ protected: void d2h_notification_thread_main(const std::string &device_id); hailo_status check_hef_is_compatible(Hef &hef); - virtual ExpectedRef get_config_manager() = 0; + virtual Expected add_hef(Hef &hef, const NetworkGroupsParamsMap &configure_params) = 0; D2hEventQueue m_d2h_notification_queue; std::thread m_d2h_notification_thread; diff --git a/hailort/libhailort/src/eth_device.cpp b/hailort/libhailort/src/eth_device.cpp index 66a74b0..2e54e56 100644 --- a/hailort/libhailort/src/eth_device.cpp +++ b/hailort/libhailort/src/eth_device.cpp @@ -109,8 +109,7 @@ Expected> EthernetDevice::create(const std::stri EthernetDevice::EthernetDevice(const hailo_eth_device_info_t &device_info, Udp &&control_udp, hailo_status &status) : DeviceBase::DeviceBase(Device::Type::ETH), m_device_info(device_info), - m_control_udp(std::move(control_udp)), - m_context_switch_manager() + m_control_udp(std::move(control_udp)) { char ip_buffer[INET_ADDRSTRLEN]; status = Socket::ntop(AF_INET, &(device_info.device_address.sin_addr), ip_buffer, INET_ADDRSTRLEN); @@ -385,15 +384,103 @@ hailo_status EthernetDevice::disable_notifications() return HAILO_NOT_IMPLEMENTED; } -ExpectedRef EthernetDevice::get_config_manager() +Expected EthernetDevice::add_hef(Hef &hef, const NetworkGroupsParamsMap &configure_params) { - if (!m_context_switch_manager) { - m_context_switch_manager = make_unique_nothrow(*this); - CHECK_AS_EXPECTED(nullptr != m_context_switch_manager, HAILO_OUT_OF_HOST_MEMORY); + auto device_arch_exp = get_architecture(); + CHECK_EXPECTED(device_arch_exp); + auto device_arch = device_arch_exp.release(); + + auto partial_clusters_layout_bitmap_exp = Control::get_partial_clusters_layout_bitmap(*this); + CHECK_EXPECTED(partial_clusters_layout_bitmap_exp); + auto partial_clusters_layout_bitmap = partial_clusters_layout_bitmap_exp.release(); + + auto &hef_network_groups = hef.pimpl->network_groups(); + ConfiguredNetworkGroupVector added_network_groups; + // TODO: can be optimized (add another loop the allocate the network group we're adding) + added_network_groups.reserve(hef_network_groups.size()); + auto configure_params_copy = configure_params; + auto hef_arch = hef.pimpl->get_device_arch(); + + // Reset FW state_machine status - can be removed? + static const auto REMOVE_NN_CONFIG_DURING_RESET = false; + auto status = Control::reset_context_switch_state_machine(*this, REMOVE_NN_CONFIG_DURING_RESET); + CHECK_SUCCESS_AS_EXPECTED(status); + + for (const auto &base_network_group_proto : hef_network_groups) { + const std::string &network_group_name = base_network_group_proto->network_group_metadata().network_group_name(); + auto &hef_core_ops = hef.pimpl->core_ops(network_group_name); + assert(hef_core_ops.size() == 1); + const auto &core_op = hef_core_ops[0]; + + auto expected_partial_core_op = Hef::Impl::get_core_op_per_arch(core_op, hef_arch, device_arch, + partial_clusters_layout_bitmap); + CHECK_EXPECTED(expected_partial_core_op); + auto partial_core_op = expected_partial_core_op.release(); + + // TODO: decide about core_op names - align with the Compiler + + /* If NG params are present, use them + If no configure params are given, use default*/ + ConfigureNetworkParams config_params{}; + if (contains(configure_params, network_group_name)) { + config_params = configure_params_copy.at(network_group_name); + configure_params_copy.erase(network_group_name); + } else if (configure_params.empty()) { + auto interface = get_default_streams_interface(); + CHECK_EXPECTED(interface); + auto config_params_exp = hef.create_configure_params(interface.value(), network_group_name); + CHECK_EXPECTED(config_params_exp); + config_params = config_params_exp.release(); + } else { + continue; + } + + /* Validate that all network_groups are single context */ + CHECK(1 == partial_core_op->contexts.size(), make_unexpected(HAILO_INTERNAL_FAILURE), + "Only single_context network_groups is supported!. Network group {} has {} contexts.", + network_group_name, partial_core_op->contexts.size()); + CHECK_AS_EXPECTED(!(Hef::Impl::contains_ddr_layers(*partial_core_op)), HAILO_INVALID_OPERATION, + "DDR layers are only supported for PCIe device. Network group {} contains DDR layers.", + network_group_name); + status = Hef::Impl::validate_core_op_unique_layer_names(*partial_core_op); + CHECK_SUCCESS_AS_EXPECTED(status); + + /* Update preliminary_config and dynamic_contexts recepies */ + auto &proto_preliminary_config = partial_core_op->preliminary_config; + auto net_group_config = Hef::Impl::create_single_context_network_group_config(proto_preliminary_config); + CHECK_EXPECTED(net_group_config); + + auto network_group_metadata = hef.pimpl->get_network_group_metadata(network_group_name); + CHECK_EXPECTED(network_group_metadata); + + auto net_flow_ops = hef.pimpl->post_process_ops(network_group_metadata->network_group_name()); + + auto single_context_app = HcpConfigNetworkGroup(*this, m_active_net_group_holder, net_group_config.release(), + config_params, network_group_metadata.release(), status, std::move(net_flow_ops)); + CHECK_SUCCESS_AS_EXPECTED(status); + + auto net_group_shared_ptr = make_shared_nothrow(std::move(single_context_app)); + CHECK_AS_EXPECTED(nullptr != net_group_shared_ptr, HAILO_OUT_OF_HOST_MEMORY); + m_network_groups.emplace_back(net_group_shared_ptr); + added_network_groups.emplace_back(std::static_pointer_cast(net_group_shared_ptr)); + + // TODO: move this func into HcpConfigNetworkGroup c'tor + status = net_group_shared_ptr->create_streams_from_config_params(*this); + CHECK_SUCCESS_AS_EXPECTED(status); + + // Check that all boundary streams were created + status = hef.pimpl->validate_boundary_streams_were_created(network_group_name, *net_group_shared_ptr); + CHECK_SUCCESS_AS_EXPECTED(status); + } + std::string unmatched_keys = ""; + for (const auto &pair : configure_params_copy) { + unmatched_keys.append(" "); + unmatched_keys.append(pair.first); } + CHECK_AS_EXPECTED(unmatched_keys.size() == 0, HAILO_INVALID_ARGUMENT, + "Some network group names in the configuration are not found in the hef file:{}", unmatched_keys); - return std::ref(*m_context_switch_manager); + return added_network_groups; } - } /* namespace hailort */ diff --git a/hailort/libhailort/src/eth_device.hpp b/hailort/libhailort/src/eth_device.hpp index 662b7f0..f840136 100644 --- a/hailort/libhailort/src/eth_device.hpp +++ b/hailort/libhailort/src/eth_device.hpp @@ -16,7 +16,7 @@ #include "hailo/hailort.h" #include "device_internal.hpp" #include "udp.hpp" -#include "context_switch/single_context/hcp_config_manager.hpp" +#include "context_switch/single_context/hcp_config_network_group.hpp" namespace hailort { @@ -61,7 +61,7 @@ public: protected: virtual Expected read_notification() override; virtual hailo_status disable_notifications() override; - virtual ExpectedRef get_config_manager() override; + virtual Expected add_hef(Hef &hef, const NetworkGroupsParamsMap &configure_params) override; private: EthernetDevice(const hailo_eth_device_info_t &device_info, Udp &&control_udp, hailo_status &status); @@ -69,7 +69,8 @@ private: const hailo_eth_device_info_t m_device_info; std::string m_device_id; Udp m_control_udp; - std::unique_ptr m_context_switch_manager; + std::vector> m_network_groups; + ActiveNetGroupHolder m_active_net_group_holder; }; } /* namespace hailort */ diff --git a/hailort/libhailort/src/eth_stream.cpp b/hailort/libhailort/src/eth_stream.cpp index 30b0e53..a6938ce 100644 --- a/hailort/libhailort/src/eth_stream.cpp +++ b/hailort/libhailort/src/eth_stream.cpp @@ -124,11 +124,11 @@ Expected EthernetInputStream::sync_write_raw_buffer(const MemoryView &bu size_t size = buffer.size(); status = m_udp.send((uint8_t*)buffer.data(), &size, this->configuration.use_dataflow_padding, this->configuration.max_payload_size); - if (HAILO_STREAM_INTERNAL_ABORT == status) { + if (HAILO_STREAM_ABORTED_BY_USER == status) { LOGGER__INFO("Udp send was aborted!"); return make_unexpected(status); } - CHECK_SUCCESS_AS_EXPECTED(status); + CHECK_SUCCESS_AS_EXPECTED(status, "{} (H2D) failed with status={}", name(), status); return size; } @@ -148,7 +148,7 @@ hailo_status EthernetInputStream::sync_write_all_raw_buffer_no_transform_impl(vo } else { status = eth_stream__write_all_no_sync(buffer, offset, size); } - if (HAILO_STREAM_INTERNAL_ABORT == status) { + if (HAILO_STREAM_ABORTED_BY_USER == status) { LOGGER__INFO("eth_stream__write_all was aborted!"); return status; } @@ -182,7 +182,7 @@ hailo_status EthernetInputStream::eth_stream__write_with_remainder(void *buffer, while (offset < offset_end_without_remainder) { transfer_size = offset_end_without_remainder - offset; auto expected_bytes_written = sync_write_raw_buffer(MemoryView(static_cast(buffer) + offset, transfer_size)); - if (HAILO_STREAM_INTERNAL_ABORT == expected_bytes_written.status()) { + if (HAILO_STREAM_ABORTED_BY_USER == expected_bytes_written.status()) { LOGGER__INFO("sync_write_raw_buffer was aborted!"); return expected_bytes_written.status(); } @@ -191,7 +191,7 @@ hailo_status EthernetInputStream::eth_stream__write_with_remainder(void *buffer, } if (0 < remainder_size) { auto expected_bytes_written = sync_write_raw_buffer(MemoryView(static_cast(buffer) + offset, remainder_size)); - if (HAILO_STREAM_INTERNAL_ABORT == expected_bytes_written.status()) { + if (HAILO_STREAM_ABORTED_BY_USER == expected_bytes_written.status()) { LOGGER__INFO("sync_write_raw_buffer was aborted!"); return expected_bytes_written.status(); } @@ -237,7 +237,7 @@ hailo_status TokenBucketEthernetInputStream::eth_stream__write_with_remainder(vo transfer_size = offset_end_without_remainder - offset; auto expected_bytes_written = sync_write_raw_buffer(MemoryView(static_cast(buffer) + offset, transfer_size)); - if (HAILO_STREAM_INTERNAL_ABORT == expected_bytes_written.status()) { + if (HAILO_STREAM_ABORTED_BY_USER == expected_bytes_written.status()) { LOGGER__INFO("sync_write_raw_buffer was aborted!"); return expected_bytes_written.status(); } @@ -250,7 +250,7 @@ hailo_status TokenBucketEthernetInputStream::eth_stream__write_with_remainder(vo (void)token_bucket.consumeWithBorrowAndWait(static_cast(remainder_size), rate_bytes_per_sec, BURST_SIZE); auto expected_bytes_written = sync_write_raw_buffer(MemoryView(static_cast(buffer) + offset, remainder_size)); - if (HAILO_STREAM_INTERNAL_ABORT == expected_bytes_written.status()) { + if (HAILO_STREAM_ABORTED_BY_USER == expected_bytes_written.status()) { LOGGER__INFO("sync_write_raw_buffer was aborted!"); return expected_bytes_written.status(); } @@ -317,7 +317,7 @@ hailo_status EthernetInputStream::eth_stream__write_all_with_sync(void *buffer, for (size_t i = 0; i < number_of_frames; i++) { // Write frame by frame, whereas the remainder packet is the sync packet status = eth_stream__write_with_remainder(buffer, offset, frame_size, this->configuration.sync_size); - if (HAILO_STREAM_INTERNAL_ABORT == status) { + if (HAILO_STREAM_ABORTED_BY_USER == status) { LOGGER__INFO("eth_stream__write_with_remainder was aborted!"); return status; } @@ -510,7 +510,7 @@ hailo_status EthernetOutputStream::read_all_no_sync(void *buffer, size_t offset, transfer_size = offset_end - offset; MemoryView buffer_view(static_cast(buffer) + offset, transfer_size); auto expected_bytes_read = this->sync_read_raw_buffer(buffer_view); - if (HAILO_STREAM_INTERNAL_ABORT == expected_bytes_read.status()) { + if (HAILO_STREAM_ABORTED_BY_USER == expected_bytes_read.status()) { LOGGER__INFO("sync_read_raw_buffer was aborted!"); return expected_bytes_read.status(); } @@ -550,7 +550,7 @@ hailo_status EthernetOutputStream::read_all_with_sync(void *buffer, size_t offse status = expected_bytes_read.status(); if (HAILO_TIMEOUT == status) { return handle_timeout(buffer, offset, initial_offset, frame_size); - } else if (HAILO_STREAM_INTERNAL_ABORT == status) { + } else if (HAILO_STREAM_ABORTED_BY_USER == status) { LOGGER__INFO("sync_read_raw_buffer was aborted"); return status; } else if (HAILO_SUCCESS != status) { @@ -620,7 +620,7 @@ hailo_status EthernetOutputStream::handle_timeout(const void* buffer, size_t off size_t initial_offset, const size_t frame_size) { // In case data a timeout has occurred, and data was received, try filling missing in frame if (this->encountered_timeout || (offset == initial_offset)) { - LOGGER__ERROR("Got timeout, unable to complete the frame"); + LOGGER__ERROR("{} (D2H) got timeout (timeout={}ms), unable to complete the frame", name(), get_timeout().count()); return HAILO_TIMEOUT; } LOGGER__ERROR("Received timeout. Continuing logic as if a sync packet was received"); @@ -653,7 +653,7 @@ hailo_status EthernetOutputStream::read_all(MemoryView &buffer) } else { status = this->read_all_no_sync(buffer.data(), 0, buffer.size()); } - if (HAILO_STREAM_INTERNAL_ABORT == status) { + if (HAILO_STREAM_ABORTED_BY_USER == status) { LOGGER__INFO("read_all was aborted!"); return status; } @@ -671,11 +671,11 @@ Expected EthernetOutputStream::sync_read_raw_buffer(MemoryView &buffer) auto buffer_size = buffer.size(); status = m_udp.recv((uint8_t*)buffer.data(),&buffer_size); - if (HAILO_STREAM_INTERNAL_ABORT == status) { + if (HAILO_STREAM_ABORTED_BY_USER == status) { LOGGER__INFO("Udp recv was aborted!"); return make_unexpected(status); } - CHECK_SUCCESS_AS_EXPECTED(status); + CHECK_SUCCESS_AS_EXPECTED(status, "{} (D2H) failed with status={}", name(), status); return buffer_size; } @@ -684,7 +684,7 @@ hailo_status EthernetOutputStream::fill_output_stream_ptr_with_info(const hailo_ { if ((HAILO_FORMAT_ORDER_HAILO_NMS == stream->m_stream_info.format.order) && (params.is_sync_enabled)) { - LOGGER__ERROR("NMS is not supported with sync enabled. Setting sync flag to false"); + LOGGER__WARNING("NMS is not supported with sync enabled. Setting sync flag to false"); stream->configuration.is_sync_enabled = false; } else { stream->configuration.is_sync_enabled = params.is_sync_enabled; diff --git a/hailort/libhailort/src/hailort.cpp b/hailort/libhailort/src/hailort.cpp index ed3ce33..5f8b592 100644 --- a/hailort/libhailort/src/hailort.cpp +++ b/hailort/libhailort/src/hailort.cpp @@ -31,6 +31,7 @@ #include "hailort_logger.hpp" #include "shared_resource_manager.hpp" #include "vdevice_internal.hpp" +#include "tracer_macros.hpp" #include @@ -41,6 +42,7 @@ COMPAT__INITIALIZER(hailort__initialize_logger) // Init logger singleton if compiling only HailoRT (void) HailoRTLogger::get_instance(); (void) SharedResourceManager::get_instance(); + TRACE(InitTrace); } hailo_status hailo_get_library_version(hailo_version_t *version) @@ -557,39 +559,9 @@ hailo_status hailo_init_configure_params(hailo_hef hef, hailo_stream_interface_t params->network_group_params_count = network_groups_names.size(); uint8_t net_group = 0; for (const auto &net_group_name : network_groups_names) { - CHECK(HAILO_MAX_NETWORK_GROUP_NAME_SIZE > net_group_name.length(), HAILO_INTERNAL_FAILURE, - "Network group '{}' name is too long (max is HAILO_MAX_NETWORK_GROUP_NAME_SIZE, including NULL terminator)", - net_group_name); - strncpy(params->network_group_params[net_group].name, net_group_name.c_str(), net_group_name.length() + 1); - - auto config_params = HailoRTDefaults::get_configure_params(); - params->network_group_params[net_group].batch_size = config_params.batch_size; - params->network_group_params[net_group].power_mode = config_params.power_mode; - - auto stream_params_by_name = reinterpret_cast(hef)->create_stream_parameters_by_name(net_group_name, stream_interface); - CHECK_EXPECTED_AS_STATUS(stream_params_by_name); - CHECK(HAILO_MAX_STREAMS_COUNT >= stream_params_by_name->size(), HAILO_INTERNAL_FAILURE, - "Too many streams in HEF"); - params->network_group_params[net_group].stream_params_by_name_count = stream_params_by_name->size(); - - uint8_t stream = 0; - for (const auto &stream_params_pair : stream_params_by_name.release()) { - CHECK(stream_params_pair.first.length() < HAILO_MAX_STREAM_NAME_SIZE, HAILO_INTERNAL_FAILURE, - "Stream '{}' has a too long name (max is HAILO_MAX_STREAM_NAME_SIZE)", stream_params_pair.first); - - hailo_stream_parameters_by_name_t params_by_name = {}; - strncpy(params_by_name.name, stream_params_pair.first.c_str(), stream_params_pair.first.length() + 1); - params_by_name.stream_params = stream_params_pair.second; - params->network_group_params[net_group].stream_params_by_name[stream] = params_by_name; - stream++; - } - - /* Fill network params */ - auto status = hailo_init_network_params(hef, net_group_name, - params->network_group_params[net_group].network_params_by_name, - params->network_group_params[net_group].network_params_by_name_count); + auto status = hailo_init_configure_network_group_params(hef, stream_interface, net_group_name.c_str(), + &(params->network_group_params[net_group])); CHECK_SUCCESS(status); - net_group++; } @@ -610,35 +582,8 @@ hailo_status hailo_init_configure_params_mipi_input(hailo_hef hef, hailo_stream_ params->network_group_params_count = network_groups_names.size(); uint8_t net_group = 0; for (const auto &net_group_name : network_groups_names) { - auto config_params = HailoRTDefaults::get_configure_params(); - strncpy(params->network_group_params[net_group].name, net_group_name.c_str(), net_group_name.length() + 1); - params->network_group_params[net_group].power_mode = config_params.power_mode; - - auto stream_params_by_name = reinterpret_cast(hef)->create_stream_parameters_by_name_mipi_input(net_group_name, - output_interface, *mipi_params); - CHECK_EXPECTED_AS_STATUS(stream_params_by_name); - CHECK(HAILO_MAX_STREAMS_COUNT >= stream_params_by_name->size(), HAILO_INTERNAL_FAILURE, - "Too many streams in HEF. There are {} streams for network_group {}", stream_params_by_name->size(), - net_group_name); - params->network_group_params[net_group].stream_params_by_name_count = stream_params_by_name->size(); - - uint8_t stream = 0; - for (const auto &stream_params_pair : stream_params_by_name.release()) { - CHECK(stream_params_pair.first.length() < HAILO_MAX_STREAM_NAME_SIZE, HAILO_INTERNAL_FAILURE, - "Stream '{}' has a too long name (max is HAILO_MAX_STREAM_NAME_SIZE)", stream_params_pair.first); - - hailo_stream_parameters_by_name_t params_by_name = {}; - strncpy(params_by_name.name, stream_params_pair.first.c_str(), stream_params_pair.first.length() + 1); - params_by_name.stream_params = stream_params_pair.second; - params->network_group_params[net_group].stream_params_by_name[stream] = params_by_name; - stream++; - } - - /* Fill network params */ - auto status = hailo_init_network_params(hef, net_group_name, - params->network_group_params[net_group].network_params_by_name, - params->network_group_params[net_group].network_params_by_name_count); - + auto status = hailo_init_configure_network_group_params_mipi_input(hef, output_interface, mipi_params, + net_group_name.c_str(), &(params->network_group_params[net_group])); CHECK_SUCCESS(status); net_group++; } @@ -646,6 +591,106 @@ hailo_status hailo_init_configure_params_mipi_input(hailo_hef hef, hailo_stream_ return HAILO_SUCCESS; } +hailo_status fill_configured_network_params_with_default(hailo_hef hef, const char *network_group_name, hailo_configure_network_group_params_t ¶ms) +{ + std::string network_group_name_str; + if (nullptr == network_group_name) { + auto network_groups_names = reinterpret_cast(hef)->get_network_groups_names(); + CHECK(HAILO_MAX_NETWORK_GROUPS >= network_groups_names.size(), HAILO_INVALID_HEF, + "Too many network_groups on a given HEF"); + network_group_name_str = network_groups_names[0]; + + LOGGER__INFO("No network_group name was given. Addressing default network_group: {}", + network_group_name_str); + } else { + network_group_name_str = std::string(network_group_name); + } + + CHECK(HAILO_MAX_NETWORK_GROUP_NAME_SIZE > network_group_name_str.length(), HAILO_INTERNAL_FAILURE, + "Network group '{}' name is too long (max is HAILO_MAX_NETWORK_GROUP_NAME_SIZE, including NULL terminator)", + network_group_name_str); + strncpy(params.name, network_group_name_str.c_str(), network_group_name_str.length() + 1); + + auto config_params = HailoRTDefaults::get_configure_params(); + params.batch_size = config_params.batch_size; + params.power_mode = config_params.power_mode; + + return HAILO_SUCCESS; +} + +hailo_status fill_configured_network_params_with_stream_params(const std::map &stream_params_by_name, + hailo_configure_network_group_params_t ¶ms) +{ + CHECK(HAILO_MAX_STREAMS_COUNT >= stream_params_by_name.size(), HAILO_INTERNAL_FAILURE, + "Too many streams in HEF. found {} streams.", stream_params_by_name.size()); + params.stream_params_by_name_count = stream_params_by_name.size(); + + uint8_t stream = 0; + for (const auto &stream_params_pair : stream_params_by_name) { + CHECK(stream_params_pair.first.length() < HAILO_MAX_STREAM_NAME_SIZE, HAILO_INTERNAL_FAILURE, + "Stream '{}' has a too long name (max is HAILO_MAX_STREAM_NAME_SIZE)", stream_params_pair.first); + + hailo_stream_parameters_by_name_t params_by_name = {}; + strncpy(params_by_name.name, stream_params_pair.first.c_str(), stream_params_pair.first.length() + 1); + params_by_name.stream_params = stream_params_pair.second; + params.stream_params_by_name[stream] = params_by_name; + stream++; + } + + return HAILO_SUCCESS; +} + +hailo_status hailo_init_configure_network_group_params(hailo_hef hef, hailo_stream_interface_t stream_interface, + const char *network_group_name, hailo_configure_network_group_params_t *params) +{ + CHECK_ARG_NOT_NULL(hef); + CHECK_ARG_NOT_NULL(params); + + auto status = fill_configured_network_params_with_default(hef, network_group_name, *params); + CHECK_SUCCESS(status); + + auto stream_params_by_name = reinterpret_cast(hef)->create_stream_parameters_by_name(network_group_name, stream_interface); + CHECK_EXPECTED_AS_STATUS(stream_params_by_name); + + status = fill_configured_network_params_with_stream_params(stream_params_by_name.value(), *params); + CHECK_SUCCESS(status); + + /* Fill network params */ + status = hailo_init_network_params(hef, network_group_name, + params->network_params_by_name, + params->network_params_by_name_count); + CHECK_SUCCESS(status); + + return HAILO_SUCCESS; +} + +hailo_status hailo_init_configure_network_group_params_mipi_input(hailo_hef hef, hailo_stream_interface_t output_interface, + hailo_mipi_input_stream_params_t *mipi_params, const char *network_group_name, hailo_configure_network_group_params_t *params) +{ + CHECK_ARG_NOT_NULL(hef); + CHECK_ARG_NOT_NULL(mipi_params); + CHECK_ARG_NOT_NULL(params); + + auto status = fill_configured_network_params_with_default(hef, network_group_name, *params); + CHECK_SUCCESS(status); + + auto stream_params_by_name = reinterpret_cast(hef)->create_stream_parameters_by_name_mipi_input(network_group_name, + output_interface, *mipi_params); + CHECK_EXPECTED_AS_STATUS(stream_params_by_name); + + status = fill_configured_network_params_with_stream_params(stream_params_by_name.value(), *params); + CHECK_SUCCESS(status); + + /* Fill network params */ + status = hailo_init_network_params(hef, network_group_name, + params->network_params_by_name, + params->network_params_by_name_count); + + CHECK_SUCCESS(status); + + return HAILO_SUCCESS; +} + NetworkGroupsParamsMap get_configure_params_map(hailo_configure_params_t *params) { NetworkGroupsParamsMap configure_params; @@ -1118,6 +1163,14 @@ hailo_status hailo_test_chip_memories(hailo_device device) return HAILO_SUCCESS; } +hailo_status hailo_set_sleep_state(hailo_device device, hailo_sleep_state_t sleep_state) +{ + CHECK_ARG_NOT_NULL(device); + auto status = (reinterpret_cast(device))->set_sleep_state(sleep_state); + CHECK_SUCCESS(status); + return HAILO_SUCCESS; +} + hailo_status hailo_create_input_transform_context(const hailo_stream_info_t *stream_info, const hailo_transform_params_t *transform_params, hailo_input_transform_context *transform_context) { @@ -1869,33 +1922,6 @@ hailo_status hailo_get_physical_devices(hailo_vdevice vdevice, hailo_device *dev return HAILO_SUCCESS; } -hailo_status hailo_get_physical_devices_infos(hailo_vdevice vdevice, hailo_pcie_device_info_t *devices_infos, - size_t *number_of_devices) -{ - CHECK_ARG_NOT_NULL(vdevice); - CHECK_ARG_NOT_NULL(devices_infos); - CHECK_ARG_NOT_NULL(number_of_devices); - -IGNORE_DEPRECATION_WARNINGS_BEGIN - auto phys_devices_infos = (reinterpret_cast(vdevice))->get_physical_devices_infos(); - CHECK_EXPECTED_AS_STATUS(phys_devices_infos); -IGNORE_DEPRECATION_WARNINGS_END - - if (*number_of_devices < phys_devices_infos->size()) { - LOGGER__ERROR("Can't return all physical devices infos. There are {} physical devices infos under the vdevice, but output array is of size {}", - phys_devices_infos->size(), *number_of_devices); - *number_of_devices = phys_devices_infos->size(); - return HAILO_INSUFFICIENT_BUFFER; - } - *number_of_devices = phys_devices_infos->size(); - - for (size_t i = 0; i < phys_devices_infos->size(); i++) { - devices_infos[i] = phys_devices_infos.value()[i]; - } - - return HAILO_SUCCESS; -} - hailo_status hailo_vdevice_get_physical_devices_ids(hailo_vdevice vdevice, hailo_device_id_t *devices_ids, size_t *number_of_devices) { diff --git a/hailort/libhailort/src/hailort_defaults.hpp b/hailort/libhailort/src/hailort_defaults.hpp index 0787fad..8cbe348 100644 --- a/hailort/libhailort/src/hailort_defaults.hpp +++ b/hailort/libhailort/src/hailort_defaults.hpp @@ -37,7 +37,8 @@ constexpr hailo_format_order_t DEFAULT_FORMAT_ORDER_MAP[] = { HAILO_FORMAT_ORDER_MAX_ENUM, // Not used in device side - HAILO_FORMAT_ORDER_NV12, HAILO_FORMAT_ORDER_MAX_ENUM, // Not used in device side - HAILO_FORMAT_ORDER_NV21, HAILO_FORMAT_ORDER_NV12, // HAILO_FORMAT_ORDER_HAILO_YYUV, - HAILO_FORMAT_ORDER_NV21 // HAILO_FORMAT_ORDER_HAILO_YYVU + HAILO_FORMAT_ORDER_NV21, // HAILO_FORMAT_ORDER_HAILO_YYVU, + HAILO_FORMAT_ORDER_MAX_ENUM // Not used in device side - HAILO_FORMAT_ORDER_RGB4 }; constexpr hailo_format_order_t DEFAULT_FORMAT_ARGMAX_ORDER_MAP[] = { @@ -58,7 +59,8 @@ constexpr hailo_format_order_t DEFAULT_FORMAT_ARGMAX_ORDER_MAP[] = { HAILO_FORMAT_ORDER_MAX_ENUM, // Not used in device side - HAILO_FORMAT_ORDER_NV12, HAILO_FORMAT_ORDER_MAX_ENUM, // Not used in device side - HAILO_FORMAT_ORDER_NV21, HAILO_FORMAT_ORDER_NV12, // HAILO_FORMAT_ORDER_HAILO_YYUV, - HAILO_FORMAT_ORDER_NV21 // HAILO_FORMAT_ORDER_HAILO_YYVU + HAILO_FORMAT_ORDER_NV21, // HAILO_FORMAT_ORDER_HAILO_YYVU, + HAILO_FORMAT_ORDER_MAX_ENUM // Not used in device side - HAILO_FORMAT_ORDER_RGB4 }; @@ -71,9 +73,9 @@ public: HailoRTDefaults() = delete; // This func must be aligned to SDK! - static Expected get_device_format_order(uint32_t allocator_format_order) + static Expected get_device_format_order(uint32_t compiler_format_order) { - switch (allocator_format_order) { + switch (compiler_format_order) { case 0: return std::move(HAILO_FORMAT_ORDER_NHWC); break; @@ -111,7 +113,7 @@ public: return std::move(HAILO_FORMAT_ORDER_HAILO_YYVU); break; default: - LOGGER__ERROR("Invalid allocator_format_order ({})", allocator_format_order); + LOGGER__ERROR("Invalid compiler_format_order ({})", compiler_format_order); return make_unexpected(HAILO_INTERNAL_FAILURE); } } @@ -348,7 +350,7 @@ public: { auto host_format_copy = host_format; if (HAILO_FORMAT_TYPE_AUTO == host_format_copy.type) { - host_format_copy.type = hw_format.type; + host_format_copy.type = hw_format.type; } if (HAILO_FORMAT_ORDER_AUTO == host_format_copy.order) { host_format_copy.order = get_default_host_format_order(hw_format); @@ -360,11 +362,7 @@ public: { hailo_vdevice_params_t params = {}; params.device_count = HAILO_DEFAULT_DEVICE_COUNT; - -IGNORE_DEPRECATION_WARNINGS_BEGIN - params.device_infos = nullptr; -IGNORE_DEPRECATION_WARNINGS_END - + params.scheduling_algorithm = HAILO_SCHEDULING_ALGORITHM_ROUND_ROBIN; params.device_ids = nullptr; params.group_id = HAILO_DEFAULT_VDEVICE_GROUP_ID; params.multi_process_service = false; diff --git a/hailort/libhailort/src/hailort_logger.cpp b/hailort/libhailort/src/hailort_logger.cpp index 6bd7268..4e29c26 100644 --- a/hailort/libhailort/src/hailort_logger.cpp +++ b/hailort/libhailort/src/hailort_logger.cpp @@ -9,7 +9,9 @@ #include "hailort_logger.hpp" #include "common/utils.hpp" +#include "common/filesystem.hpp" +#include #include #include #include @@ -17,9 +19,10 @@ #include #include #include +#include #ifdef _WIN32 -#include -#include +#include +#include #endif namespace hailort @@ -27,137 +30,128 @@ namespace hailort #define MAX_LOG_FILE_SIZE (1024 * 1024) // 1MB -#define HAILORT_NAME "HailoRT" -#define HAILORT_LOGGER_FILENAME "hailort.log" +#define HAILORT_NAME ("HailoRT") +#define HAILORT_LOGGER_FILENAME ("hailort.log") #define HAILORT_MAX_NUMBER_OF_LOG_FILES (1) // There will be 2 log files - 1 spare -#define HAILORT_CONSOLE_LOGGER_PATTERN "[%n] [%^%l%$] %v" // Console logger will print: [hailort logger file name] [log level] msg -#define HAILORT_FILE_LOGGER_PATTERN "[%Y-%m-%d %X.%e] [%n] [%l] [%s:%#] [%!] %v" //File logger will print: [timestamp] [hailort] [log level] [source file:line number] [function name] msg -#define HAILORT_ANDROID_LOGGER_PATTERN "%v" // Android logger will print only message (additional info are built-in) +#define HAILORT_CONSOLE_LOGGER_PATTERN ("[%n] [%^%l%$] %v") // Console logger will print: [hailort logger file name] [log level] msg +#define HAILORT_MAIN_FILE_LOGGER_PATTERN ("[%Y-%m-%d %X.%e] [%P] [%n] [%l] [%s:%#] [%!] %v") //File logger will print: [timestamp] [PID] [hailort] [log level] [source file:line number] [function name] msg +#define HAILORT_LOCAL_FILE_LOGGER_PATTERN ("[%Y-%m-%d %X.%e] [%n] [%l] [%s:%#] [%!] %v") //File logger will print: [timestamp] [hailort] [log level] [source file:line number] [function name] msg +#define HAILORT_ANDROID_LOGGER_PATTERN ("%v") // Android logger will print only message (additional info are built-in) -#define HAILORT_LOGGER_PATH "HAILORT_LOGGER_PATH" +#define HAILORT_LOGGER_PATH_ENV_VAR ("HAILORT_LOGGER_PATH") #ifdef _WIN32 #define PATH_SEPARATOR "\\" +#else +#define PATH_SEPARATOR "/" +#endif -bool is_dir_accesible(const std::string &dir) +std::string HailoRTLogger::parse_log_path(const char *log_path) { - // The code is based on examples from: https://cpp.hotexamples.com/examples/-/-/AccessCheck/cpp-accesscheck-function-examples.html - bool return_val = false; - SECURITY_INFORMATION security_Info = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION; - PSECURITY_DESCRIPTOR security_desc = NULL; - DWORD access_mask = GENERIC_WRITE; - GENERIC_MAPPING mapping = {0xFFFFFFFF}; - mapping.GenericRead = FILE_GENERIC_READ; - mapping.GenericWrite = FILE_GENERIC_WRITE; - mapping.GenericExecute = FILE_GENERIC_EXECUTE; - mapping.GenericAll = FILE_ALL_ACCESS; - HANDLE h_token = NULL; - HANDLE h_impersonated_token = NULL; - PRIVILEGE_SET privilege_set = {0}; - DWORD privilege_set_size = sizeof(privilege_set); - DWORD granted_access = 0; - BOOL access_status = FALSE; - - // Retrieves a copy of the security descriptor for current dir. - DWORD result = GetNamedSecurityInfo(dir.c_str(), SE_FILE_OBJECT, security_Info, NULL, NULL, NULL, NULL, &security_desc); - if (result != ERROR_SUCCESS) { - std::cerr << "Failed to get security information for local directory with error = " << result << std::endl; - return_val = false; - goto l_exit; + if ((nullptr == log_path) || (std::strlen(log_path) == 0)) { + return "."; } - MapGenericMask(&access_mask, &mapping); - if (OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &h_token) == 0) { - return_val = false; - std::cerr << "OpenProcessToken() Failed. Cannot check directory's access permissions, last_error = " << GetLastError() << std::endl; - goto l_release_security_desc; + std::string log_path_str(log_path); + if (log_path_str == "NONE") { + return ""; } - // Getting a handle to an impersonation token. It will represent the client that is attempting to gain access. - if (DuplicateToken(h_token, SecurityImpersonation, &h_impersonated_token) == 0) { - std::cerr << "DuplicateToken() Failed. Cannot check directory's access permissions, last_error = " << GetLastError() << std::endl; - return_val = false; - goto l_close_token; - } + return log_path_str; +} + +std::string HailoRTLogger::get_log_path(const std::string &path_env_var) +{ + auto log_path_c_str = std::getenv(path_env_var.c_str()); + return parse_log_path(log_path_c_str); +} - if (AccessCheck(security_desc, h_impersonated_token, access_mask, &mapping, &privilege_set, &privilege_set_size, &granted_access, &access_status) == 0) { - std::cerr << "AccessCheck Failed. Cannot check directory's access permissions, last_error = " << GetLastError() << std::endl; - return_val = false; - goto l_close_impersonated_token; +std::string HailoRTLogger::get_main_log_path() +{ + std::string local_log_path = get_log_path(HAILORT_LOGGER_PATH_ENV_VAR); + if (local_log_path.length() == 0) { + return ""; } - return_val = (access_status == TRUE); +#ifdef _WIN32 + // See https://stackoverflow.com/questions/2899013/how-do-i-get-the-application-data-path-in-windows-using-c + TCHAR local_app_data_path[MAX_PATH]; + auto result = SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, local_app_data_path); + if (!SUCCEEDED(result)) { + std::cerr << "Cannot resolve Local Application Data directory path" << std::endl; + return ""; + } + + const auto hailo_dir_path = std::string(local_app_data_path) + PATH_SEPARATOR + "Hailo"; + const auto full_path = hailo_dir_path + PATH_SEPARATOR + "HailoRT"; +#else + const auto hailo_dir_path = Filesystem::get_home_directory() + PATH_SEPARATOR + ".hailo"; + const auto full_path = hailo_dir_path + PATH_SEPARATOR + "hailort"; +#endif -l_close_impersonated_token: - if (NULL != h_impersonated_token) { - (void)CloseHandle(h_impersonated_token); + auto status = Filesystem::create_directory(hailo_dir_path); + if (HAILO_SUCCESS != status) { + std::cerr << "Cannot create directory at path " << hailo_dir_path << std::endl; + return ""; } -l_close_token: - if (NULL != h_token) { - (void)CloseHandle(h_token); + status = Filesystem::create_directory(full_path); + if (HAILO_SUCCESS != status) { + std::cerr << "Cannot create directory at path " << full_path << std::endl; + return ""; } -l_release_security_desc: - if (NULL != security_desc) { - (void)LocalFree(security_desc); - } -l_exit: - return return_val; + return full_path; } -#else -#define PATH_SEPARATOR "/" -bool is_dir_accesible(const std::string &dir) +std::shared_ptr HailoRTLogger::create_file_sink(const std::string &dir_path, const std::string &filename, bool rotate) { - auto ret = access(dir.c_str(), W_OK); - if (ret == 0) { - return true; - } - else if (EACCES == errno) { - return false; - } - else { - std::cerr << "Failed checking directory's access permissions, errno = " << errno << std::endl; - return false; + if ("" == dir_path) { + return make_shared_nothrow(); } -} -#endif -std::shared_ptr HailoRTLogger::create_file_sink() -{ - auto dir_env_var = std::getenv(HAILORT_LOGGER_PATH); - std::string dir = ((nullptr == dir_env_var) || (0 == std::strlen(dir_env_var))) ? "." : dir_env_var; // defaulted to current directory - if (dir == "NONE") { + if (!Filesystem::is_path_accesible(dir_path)) { + std::cerr << "HailoRT warning: Cannot create log file " << filename + << "! Please check the directory " << dir_path << " write permissions." << std::endl; + // Create null sink instead (Will throw away its log) return make_shared_nothrow(); - } else if (is_dir_accesible(dir)) { - return make_shared_nothrow((dir + PATH_SEPARATOR + HAILORT_LOGGER_FILENAME), MAX_LOG_FILE_SIZE, - HAILORT_MAX_NUMBER_OF_LOG_FILES); - } else { - std::cerr << "HailoRT warning: Cannot create HailoRT log file! Please check the current directory's write permissions." << std::endl; + } + + const auto file_path = dir_path + PATH_SEPARATOR + filename; + if (Filesystem::does_file_exists(file_path) && !Filesystem::is_path_accesible(file_path)) { + std::cerr << "HailoRT warning: Cannot create log file " << filename + << "! Please check the file " << file_path << " write permissions." << std::endl; // Create null sink instead (Will throw away its log) return make_shared_nothrow(); } + + if (rotate) { + return make_shared_nothrow(file_path, MAX_LOG_FILE_SIZE, HAILORT_MAX_NUMBER_OF_LOG_FILES); + } + + return make_shared_nothrow(file_path); } HailoRTLogger::HailoRTLogger() : m_console_sink(make_shared_nothrow()), #ifdef __ANDROID__ - m_file_sink(make_shared_nothrow(HAILORT_NAME)) + m_main_log_file_sink(make_shared_nothrow(HAILORT_NAME)) #else - m_file_sink(create_file_sink()) + m_main_log_file_sink(create_file_sink(get_main_log_path(), HAILORT_LOGGER_FILENAME, true)), + m_local_log_file_sink(create_file_sink(get_log_path(HAILORT_LOGGER_PATH_ENV_VAR), HAILORT_LOGGER_FILENAME, true)) #endif { #ifdef __ANDROID__ - m_file_sink->set_pattern(HAILORT_ANDROID_LOGGER_PATTERN); + m_main_log_file_sink->set_pattern(HAILORT_ANDROID_LOGGER_PATTERN); #else - m_file_sink->set_pattern(HAILORT_FILE_LOGGER_PATTERN); + m_main_log_file_sink->set_pattern(HAILORT_MAIN_FILE_LOGGER_PATTERN); + m_local_log_file_sink->set_pattern(HAILORT_LOCAL_FILE_LOGGER_PATTERN); #endif // TODO: Handle null pointers for logger and sinks m_console_sink->set_pattern(HAILORT_CONSOLE_LOGGER_PATTERN); - spdlog::sinks_init_list sink_list = { m_console_sink, m_file_sink }; + spdlog::sinks_init_list sink_list = { m_console_sink, m_main_log_file_sink, m_local_log_file_sink }; m_hailort_logger = make_shared_nothrow(HAILORT_NAME, sink_list.begin(), sink_list.end()); #ifdef NDEBUG @@ -177,8 +171,10 @@ void HailoRTLogger::set_levels(spdlog::level::level_enum console_level, spdlog::level::level_enum file_level, spdlog::level::level_enum flush_level) { m_console_sink->set_level(console_level); - m_file_sink->set_level(file_level); + m_main_log_file_sink->set_level(file_level); + m_local_log_file_sink->set_level(file_level); m_hailort_logger->flush_on(flush_level); } + } /* namespace hailort */ diff --git a/hailort/libhailort/src/hailort_logger.hpp b/hailort/libhailort/src/hailort_logger.hpp index b8544b1..5552d00 100644 --- a/hailort/libhailort/src/hailort_logger.hpp +++ b/hailort/libhailort/src/hailort_logger.hpp @@ -34,15 +34,24 @@ public: std::shared_ptr logger(); void set_levels(spdlog::level::level_enum console_level, spdlog::level::level_enum file_level, spdlog::level::level_enum flush_level); - static std::shared_ptr create_file_sink(); + static std::string get_log_path(const std::string &path_env_var); + static std::string get_main_log_path(); + static std::shared_ptr create_file_sink(const std::string &dir_path, const std::string &filename, bool rotate); + private: HailoRTLogger(); + static std::string parse_log_path(const char *log_path); std::shared_ptr m_console_sink; - std::shared_ptr m_file_sink; + + // The main log will written to a centralized directory (home directory) + // The local log will be written to the local directory or to the path the user has chosen (via $HAILORT_LOGGER_PATH) + std::shared_ptr m_main_log_file_sink; + std::shared_ptr m_local_log_file_sink; std::shared_ptr m_hailort_logger; }; + } /* namespace hailort */ #endif /* _HAILORT_LOGGER_HPP_ */ diff --git a/hailort/libhailort/src/hailort_rpc_client.cpp b/hailort/libhailort/src/hailort_rpc_client.cpp index 4dbd731..4dc03cb 100644 --- a/hailort/libhailort/src/hailort_rpc_client.cpp +++ b/hailort/libhailort/src/hailort_rpc_client.cpp @@ -87,7 +87,7 @@ Expected> HailoRtRpcClient::InputVStreams_create(uint32_t request.set_pid(pid); auto proto_vstreams_params = request.mutable_vstreams_params(); for (const auto &name_params_pair : inputs_params) { - NamedVStreamParams proto_name_param_pair; + ProtoNamedVStreamParams proto_name_param_pair; auto vstream_params = name_params_pair.second; proto_name_param_pair.set_name(name_params_pair.first); @@ -144,7 +144,7 @@ Expected> HailoRtRpcClient::OutputVStreams_create(uint32_t request.set_pid(pid); auto proto_vstreams_params = request.mutable_vstreams_params(); for (const auto &name_params_pair : output_params) { - NamedVStreamParams proto_name_param_pair; + ProtoNamedVStreamParams proto_name_param_pair; auto vstream_params = name_params_pair.second; proto_name_param_pair.set_name(name_params_pair.first); @@ -264,6 +264,22 @@ Expected> HailoRtRpcClient::VDevice_get_physical_device return result; } +Expected HailoRtRpcClient::VDevice_get_default_streams_interface(uint32_t handle) +{ + VDevice_get_default_streams_interface_Request request; + request.set_handle(handle); + + VDevice_get_default_streams_interface_Reply reply; + grpc::ClientContext context; + grpc::Status status = m_stub->VDevice_get_default_streams_interface(&context, request, &reply); + CHECK_GRPC_STATUS_AS_EXPECTED(status); + assert(reply.status() < HAILO_STATUS_COUNT); + CHECK_SUCCESS_AS_EXPECTED(static_cast(reply.status())); + CHECK_AS_EXPECTED(reply.stream_interface() < HAILO_STREAM_INTERFACE_MAX_ENUM, HAILO_INTERNAL_FAILURE, + "stream_interface {} out of range", reply.stream_interface()); + return static_cast(reply.stream_interface()); +} + hailo_status HailoRtRpcClient::ConfiguredNetworkGroup_release(uint32_t handle) { Release_Request request; @@ -278,6 +294,30 @@ hailo_status HailoRtRpcClient::ConfiguredNetworkGroup_release(uint32_t handle) return HAILO_SUCCESS; } +std::map get_group(const ProtoNamedVStreamParamsMap &named_params_map) +{ + std::map result; + for (auto &named_params : named_params_map.vstream_params_map()) { + auto name = named_params.name(); + auto proto_params = named_params.params(); + auto proto_user_buffer_format = proto_params.user_buffer_format(); + hailo_format_t user_buffer_format = { + .type = static_cast(proto_user_buffer_format.type()), + .order = static_cast(proto_user_buffer_format.order()), + .flags = static_cast(proto_user_buffer_format.flags()) + }; + hailo_vstream_params_t params = { + .user_buffer_format = user_buffer_format, + .timeout_ms = proto_params.timeout_ms(), + .queue_size = proto_params.queue_size(), + .vstream_stats_flags = static_cast(proto_params.vstream_stats_flags()), + .pipeline_elements_stats_flags = static_cast(proto_params.pipeline_elements_stats_flags()) + }; + result.insert({name, params}); + } + return result; +} + Expected> HailoRtRpcClient::ConfiguredNetworkGroup_make_input_vstream_params( uint32_t handle, bool quantized, hailo_format_type_t format_type, uint32_t timeout_ms, uint32_t queue_size, const std::string &network_name) @@ -296,24 +336,29 @@ Expected> HailoRtRpcClient::Config CHECK_GRPC_STATUS_AS_EXPECTED(status); assert(reply.status() < HAILO_STATUS_COUNT); CHECK_SUCCESS_AS_EXPECTED(static_cast(reply.status())); - std::map result; - for (int i = 0; i < reply.vstream_params_map_size(); ++i) { - auto name = reply.vstream_params_map(i).name(); - auto proto_params = reply.vstream_params_map(i).params(); - auto proto_user_buffer_format = proto_params.user_buffer_format(); - hailo_format_t user_buffer_format = { - .type = static_cast(proto_user_buffer_format.type()), - .order = static_cast(proto_user_buffer_format.order()), - .flags = static_cast(proto_user_buffer_format.flags()) - }; - hailo_vstream_params_t params = { - .user_buffer_format = user_buffer_format, - .timeout_ms = proto_params.timeout_ms(), - .queue_size = proto_params.queue_size(), - .vstream_stats_flags = static_cast(proto_params.vstream_stats_flags()), - .pipeline_elements_stats_flags = static_cast(proto_params.pipeline_elements_stats_flags()) - }; - result.insert({name, params}); + return get_group(reply.vstream_params_map()); +} + +Expected>> HailoRtRpcClient::ConfiguredNetworkGroup_make_output_vstream_params_groups( + uint32_t handle, bool quantized, hailo_format_type_t format_type, uint32_t timeout_ms, uint32_t queue_size) +{ + ConfiguredNetworkGroup_make_output_vstream_params_groups_Request request; + request.set_handle(handle); + request.set_quantized(quantized); + request.set_format_type(format_type); + request.set_timeout_ms(timeout_ms); + request.set_queue_size(queue_size); + + ConfiguredNetworkGroup_make_output_vstream_params_groups_Reply reply; + grpc::ClientContext context; + grpc::Status status = m_stub->ConfiguredNetworkGroup_make_output_vstream_params_groups(&context, request, &reply); + CHECK_GRPC_STATUS_AS_EXPECTED(status); + assert(reply.status() < HAILO_STATUS_COUNT); + CHECK_SUCCESS_AS_EXPECTED(static_cast(reply.status())); + std::vector> result; + for (auto &map_proto : reply.vstream_params_groups()) { + auto group = get_group(map_proto); + result.push_back(group); } return result; } @@ -337,9 +382,9 @@ Expected> HailoRtRpcClient::Config assert(reply.status() < HAILO_STATUS_COUNT); CHECK_SUCCESS_AS_EXPECTED(static_cast(reply.status())); std::map result; - for (int i = 0; i < reply.vstream_params_map_size(); ++i) { - auto name = reply.vstream_params_map(i).name(); - auto proto_params = reply.vstream_params_map(i).params(); + for (int i = 0; i < reply.vstream_params_map().vstream_params_map_size(); ++i) { + auto name = reply.vstream_params_map().vstream_params_map(i).name(); + auto proto_params = reply.vstream_params_map().vstream_params_map(i).params(); auto proto_user_buffer_format = proto_params.user_buffer_format(); hailo_format_t user_buffer_format = { .type = static_cast(proto_user_buffer_format.type()), @@ -360,17 +405,17 @@ Expected> HailoRtRpcClient::Config Expected HailoRtRpcClient::ConfiguredNetworkGroup_get_network_group_name(uint32_t handle) { - return ConfiguredNetworkGroup_get_name(handle); + return ConfiguredNetworkGroup_name(handle); } -Expected HailoRtRpcClient::ConfiguredNetworkGroup_get_name(uint32_t handle) +Expected HailoRtRpcClient::ConfiguredNetworkGroup_name(uint32_t handle) { - ConfiguredNetworkGroup_get_name_Request request; + ConfiguredNetworkGroup_name_Request request; request.set_handle(handle); - ConfiguredNetworkGroup_get_name_Reply reply; + ConfiguredNetworkGroup_name_Reply reply; grpc::ClientContext context; - grpc::Status status = m_stub->ConfiguredNetworkGroup_get_name(&context, request, &reply); + grpc::Status status = m_stub->ConfiguredNetworkGroup_name(&context, request, &reply); CHECK_GRPC_STATUS_AS_EXPECTED(status); assert(reply.status() < HAILO_STATUS_COUNT); CHECK_SUCCESS_AS_EXPECTED(static_cast(reply.status())); @@ -510,42 +555,48 @@ Expected>> HailoRtRpcClient::ConfiguredNetw return result; } +hailo_vstream_info_t deserialize_vstream_info(const ProtoVStreamInfo &info_proto) +{ + hailo_vstream_info_t info; + strcpy(info.name, info_proto.name().c_str()); + strcpy(info.network_name, info_proto.network_name().c_str()); + info.direction = static_cast(info_proto.direction()); + hailo_format_t format = { + .type = static_cast(info_proto.format().type()), + .order = static_cast(info_proto.format().order()), + .flags = static_cast(info_proto.format().flags()) + }; + info.format = format; + if (format.order == HAILO_FORMAT_ORDER_HAILO_NMS) { + hailo_nms_shape_t nms_shape = { + .number_of_classes = info_proto.nms_shape().number_of_classes(), + .max_bboxes_per_class = info_proto.nms_shape().max_bbox_per_class() + }; + info.nms_shape = nms_shape; + } else { + hailo_3d_image_shape_t shape = { + .height = info_proto.shape().height(), + .width = info_proto.shape().width(), + .features = info_proto.shape().features() + }; + info.shape = shape; + } + hailo_quant_info_t quant_info = { + .qp_zp = info_proto.quant_info().qp_zp(), + .qp_scale = info_proto.quant_info().qp_scale(), + .limvals_min = info_proto.quant_info().limvals_min(), + .limvals_max = info_proto.quant_info().limvals_max() + }; + info.quant_info = quant_info; + return info; +} + Expected> deserialize_vstream_infos(const ConfiguredNetworkGroup_get_vstream_infos_Reply &reply) { std::vector result; result.reserve(reply.vstream_infos().size()); for (auto& info_proto : reply.vstream_infos()) { - hailo_vstream_info_t info; - strcpy(info.name, info_proto.name().c_str()); - strcpy(info.network_name, info_proto.network_name().c_str()); - info.direction = static_cast(info_proto.direction()); - hailo_format_t format = { - .type = static_cast(info_proto.format().type()), - .order = static_cast(info_proto.format().order()), - .flags = static_cast(info_proto.format().flags()) - }; - info.format = format; - if (format.order == HAILO_FORMAT_ORDER_HAILO_NMS) { - hailo_nms_shape_t nms_shape = { - .number_of_classes = info_proto.nms_shape().number_of_classes(), - .max_bboxes_per_class = info_proto.nms_shape().max_bbox_per_class() - }; - info.nms_shape = nms_shape; - } else { - hailo_3d_image_shape_t shape = { - .height = info_proto.shape().height(), - .width = info_proto.shape().width(), - .features = info_proto.shape().features() - }; - info.shape = shape; - } - hailo_quant_info_t quant_info = { - .qp_zp = info_proto.quant_info().qp_zp(), - .qp_scale = info_proto.quant_info().qp_scale(), - .limvals_min = info_proto.quant_info().limvals_min(), - .limvals_max = info_proto.quant_info().limvals_max() - }; - info.quant_info = quant_info; + auto info = deserialize_vstream_info(info_proto); result.push_back(info); } return result; @@ -649,6 +700,68 @@ Expected HailoRtRpcClient::ConfiguredNetworkGroup_get_ return result; } +Expected HailoRtRpcClient::ConfiguredNetworkGroup_is_multi_context(uint32_t handle) +{ + ConfiguredNetworkGroup_is_multi_context_Request request; + ConfiguredNetworkGroup_is_multi_context_Reply reply; + request.set_handle(handle); + grpc::ClientContext context; + grpc::Status status = m_stub->ConfiguredNetworkGroup_is_multi_context(&context, request, &reply); + CHECK_GRPC_STATUS_AS_EXPECTED(status); + assert(reply.status() < HAILO_STATUS_COUNT); + CHECK_SUCCESS_AS_EXPECTED(static_cast(reply.status())); + return reply.is_multi_context(); +} + +Expected HailoRtRpcClient::ConfiguredNetworkGroup_get_config_params(uint32_t handle) +{ + ConfiguredNetworkGroup_get_config_params_Request request; + ConfiguredNetworkGroup_get_config_params_Reply reply; + request.set_handle(handle); + grpc::ClientContext context; + grpc::Status status = m_stub->ConfiguredNetworkGroup_get_config_params(&context, request, &reply); + CHECK_GRPC_STATUS_AS_EXPECTED(status); + assert(reply.status() < HAILO_STATUS_COUNT); + CHECK_SUCCESS_AS_EXPECTED(static_cast(reply.status())); + auto proto_configure_params = reply.params(); + ConfigureNetworkParams network_configure_params; + network_configure_params.batch_size = static_cast(proto_configure_params.batch_size()); + network_configure_params.power_mode = static_cast(proto_configure_params.power_mode()); + network_configure_params.latency = static_cast(proto_configure_params.latency()); + for (auto &proto_name_streams_params_pair : proto_configure_params.stream_params_map()) { + auto proto_streams_params = proto_name_streams_params_pair.params(); + auto stream_direction = static_cast(proto_streams_params.direction()); + hailo_stream_parameters_t stream_params; + if (stream_direction == HAILO_H2D_STREAM) { + stream_params = { + .stream_interface = static_cast(proto_streams_params.stream_interface()), + .direction = stream_direction, + {.pcie_input_params = { + .reserved = 0 + }} + }; + } else { + stream_params = { + .stream_interface = static_cast(proto_streams_params.stream_interface()), + .direction = stream_direction, + {.pcie_output_params = { + .reserved = 0 + }} + }; + } + network_configure_params.stream_params_by_name.insert({proto_name_streams_params_pair.name(), stream_params}); + } + for (auto &proto_name_network_params_pair : proto_configure_params.network_params_map()) { + auto proto_network_params = proto_name_network_params_pair.params(); + hailo_network_parameters_t net_params { + .batch_size = static_cast(proto_network_params.batch_size()) + }; + + network_configure_params.network_params_by_name.insert({proto_name_network_params_pair.name(), net_params}); + } + return network_configure_params; +} + hailo_status HailoRtRpcClient::InputVStream_write(uint32_t handle, const MemoryView &buffer) { InputVStream_write_Request request; @@ -659,7 +772,7 @@ hailo_status HailoRtRpcClient::InputVStream_write(uint32_t handle, const MemoryV grpc::Status status = m_stub->InputVStream_write(&context, request, &reply); CHECK_GRPC_STATUS(status); assert(reply.status() < HAILO_STATUS_COUNT); - if (reply.status() == HAILO_STREAM_INTERNAL_ABORT) { + if (reply.status() == HAILO_STREAM_ABORTED_BY_USER) { return static_cast(reply.status()); } CHECK_SUCCESS(static_cast(reply.status())); @@ -676,7 +789,7 @@ hailo_status HailoRtRpcClient::OutputVStream_read(uint32_t handle, MemoryView bu grpc::Status status = m_stub->OutputVStream_read(&context, request, &reply); CHECK_GRPC_STATUS(status); assert(reply.status() < HAILO_STATUS_COUNT); - if (reply.status() == HAILO_STREAM_INTERNAL_ABORT) { + if (reply.status() == HAILO_STREAM_ABORTED_BY_USER) { return static_cast(reply.status()); } CHECK_SUCCESS(static_cast(reply.status())); @@ -750,6 +863,34 @@ Expected HailoRtRpcClient::OutputVStream_name(uint32_t handle) return name; } +Expected HailoRtRpcClient::InputVStream_network_name(uint32_t handle) +{ + VStream_network_name_Request request; + request.set_handle(handle); + grpc::ClientContext context; + VStream_network_name_Reply reply; + grpc::Status status = m_stub->InputVStream_network_name(&context, request, &reply); + CHECK_GRPC_STATUS_AS_EXPECTED(status); + assert(reply.status() < HAILO_STATUS_COUNT); + CHECK_SUCCESS_AS_EXPECTED(static_cast(reply.status())); + auto name = reply.network_name(); + return name; +} + +Expected HailoRtRpcClient::OutputVStream_network_name(uint32_t handle) +{ + VStream_network_name_Request request; + request.set_handle(handle); + grpc::ClientContext context; + VStream_network_name_Reply reply; + grpc::Status status = m_stub->OutputVStream_network_name(&context, request, &reply); + CHECK_GRPC_STATUS_AS_EXPECTED(status); + assert(reply.status() < HAILO_STATUS_COUNT); + CHECK_SUCCESS_AS_EXPECTED(static_cast(reply.status())); + auto name = reply.network_name(); + return name; +} + hailo_status HailoRtRpcClient::InputVStream_abort(uint32_t handle) { VStream_abort_Request request; @@ -757,7 +898,7 @@ hailo_status HailoRtRpcClient::InputVStream_abort(uint32_t handle) grpc::ClientContext context; VStream_abort_Reply reply; grpc::Status status = m_stub->InputVStream_abort(&context, request, &reply); - CHECK(status.ok(), HAILO_RPC_FAILED, "InputVStream_abort: RPC failed"); + CHECK_GRPC_STATUS(status); assert(reply.status() < HAILO_STATUS_COUNT); return static_cast(reply.status()); } @@ -769,7 +910,7 @@ hailo_status HailoRtRpcClient::OutputVStream_abort(uint32_t handle) grpc::ClientContext context; VStream_abort_Reply reply; grpc::Status status = m_stub->OutputVStream_abort(&context, request, &reply); - CHECK(status.ok(), HAILO_RPC_FAILED, "OutputVStream_abort: RPC failed"); + CHECK_GRPC_STATUS(status); assert(reply.status() < HAILO_STATUS_COUNT); return static_cast(reply.status()); } @@ -781,7 +922,7 @@ hailo_status HailoRtRpcClient::InputVStream_resume(uint32_t handle) grpc::ClientContext context; VStream_resume_Reply reply; grpc::Status status = m_stub->InputVStream_resume(&context, request, &reply); - CHECK(status.ok(), HAILO_RPC_FAILED, "InputVStream_resume: RPC failed"); + CHECK_GRPC_STATUS(status); assert(reply.status() < HAILO_STATUS_COUNT); return static_cast(reply.status()); } @@ -793,9 +934,78 @@ hailo_status HailoRtRpcClient::OutputVStream_resume(uint32_t handle) grpc::ClientContext context; VStream_resume_Reply reply; grpc::Status status = m_stub->OutputVStream_resume(&context, request, &reply); - CHECK(status.ok(), HAILO_RPC_FAILED, "OutputVStream_resume: RPC failed"); + CHECK_GRPC_STATUS(status); assert(reply.status() < HAILO_STATUS_COUNT); return static_cast(reply.status()); } +Expected HailoRtRpcClient::InputVStream_get_user_buffer_format(uint32_t handle) +{ + VStream_get_user_buffer_format_Request request; + request.set_handle(handle); + grpc::ClientContext context; + VStream_get_user_buffer_format_Reply reply; + grpc::Status status = m_stub->InputVStream_get_user_buffer_format(&context, request, &reply); + CHECK_GRPC_STATUS_AS_EXPECTED(status); + assert(reply.status() < HAILO_STATUS_COUNT); + CHECK_SUCCESS_AS_EXPECTED(static_cast(reply.status())); + + auto user_buffer_format_proto = reply.user_buffer_format(); + hailo_format_t format{ + .type = static_cast(user_buffer_format_proto.type()), + .order = static_cast(user_buffer_format_proto.order()), + .flags = static_cast(user_buffer_format_proto.flags()) + }; + + return format; +} + +Expected HailoRtRpcClient::OutputVStream_get_user_buffer_format(uint32_t handle) +{ + VStream_get_user_buffer_format_Request request; + request.set_handle(handle); + grpc::ClientContext context; + VStream_get_user_buffer_format_Reply reply; + grpc::Status status = m_stub->OutputVStream_get_user_buffer_format(&context, request, &reply); + CHECK_GRPC_STATUS_AS_EXPECTED(status); + assert(reply.status() < HAILO_STATUS_COUNT); + CHECK_SUCCESS_AS_EXPECTED(static_cast(reply.status())); + + auto user_buffer_format_proto = reply.user_buffer_format(); + hailo_format_t format{ + .type = static_cast(user_buffer_format_proto.type()), + .order = static_cast(user_buffer_format_proto.order()), + .flags = static_cast(user_buffer_format_proto.flags()) + }; + + return format; +} + +Expected HailoRtRpcClient::InputVStream_get_info(uint32_t handle) +{ + VStream_get_info_Request request; + request.set_handle(handle); + grpc::ClientContext context; + VStream_get_info_Reply reply; + grpc::Status status = m_stub->InputVStream_get_info(&context, request, &reply); + CHECK_GRPC_STATUS_AS_EXPECTED(status); + assert(reply.status() < HAILO_STATUS_COUNT); + CHECK_SUCCESS_AS_EXPECTED(static_cast(reply.status())); + auto info_proto = reply.vstream_info(); + return deserialize_vstream_info(info_proto); +} +Expected HailoRtRpcClient::OutputVStream_get_info(uint32_t handle) +{ + VStream_get_info_Request request; + request.set_handle(handle); + grpc::ClientContext context; + VStream_get_info_Reply reply; + grpc::Status status = m_stub->OutputVStream_get_info(&context, request, &reply); + CHECK_GRPC_STATUS_AS_EXPECTED(status); + assert(reply.status() < HAILO_STATUS_COUNT); + CHECK_SUCCESS_AS_EXPECTED(static_cast(reply.status())); + auto info_proto = reply.vstream_info(); + return deserialize_vstream_info(info_proto); +} + } \ No newline at end of file diff --git a/hailort/libhailort/src/hailort_rpc_client.hpp b/hailort/libhailort/src/hailort_rpc_client.hpp index 638309c..eaafbc7 100644 --- a/hailort/libhailort/src/hailort_rpc_client.hpp +++ b/hailort/libhailort/src/hailort_rpc_client.hpp @@ -34,7 +34,7 @@ namespace hailort class HailoRtRpcClient final { public: HailoRtRpcClient(std::shared_ptr channel) - : m_stub(HailoRtRpc::NewStub(channel)) {} + : m_stub(ProtoHailoRtRpc::NewStub(channel)) {} hailo_status client_keep_alive(uint32_t process_id); Expected get_service_version(); @@ -42,6 +42,7 @@ public: Expected VDevice_create(const hailo_vdevice_params_t ¶ms, uint32_t pid); hailo_status VDevice_release(uint32_t handle); Expected> VDevice_get_physical_devices_ids(uint32_t handle); + Expected VDevice_get_default_streams_interface(uint32_t handle); Expected> VDevice_configure(uint32_t vdevice_handle, const Hef &hef, uint32_t pid, const NetworkGroupsParamsMap &configure_params={}); hailo_status ConfiguredNetworkGroup_release(uint32_t handle); Expected> ConfiguredNetworkGroup_make_input_vstream_params(uint32_t handle, @@ -51,10 +52,12 @@ public: bool quantized, hailo_format_type_t format_type, uint32_t timeout_ms, uint32_t queue_size, const std::string &network_name); Expected ConfiguredNetworkGroup_get_network_group_name(uint32_t handle); - Expected ConfiguredNetworkGroup_get_name(uint32_t handle); + Expected ConfiguredNetworkGroup_name(uint32_t handle); Expected> ConfiguredNetworkGroup_get_network_infos(uint32_t handle); Expected> ConfiguredNetworkGroup_get_all_stream_infos(uint32_t handle, const std::string &network_name); Expected ConfiguredNetworkGroup_get_default_stream_interface(uint32_t handle); + Expected>> ConfiguredNetworkGroup_make_output_vstream_params_groups(uint32_t handle, + bool quantized, hailo_format_type_t format_type, uint32_t timeout_ms, uint32_t queue_size); Expected>> ConfiguredNetworkGroup_get_output_vstream_groups(uint32_t handle); Expected> ConfiguredNetworkGroup_get_input_vstream_infos(uint32_t handle, std::string network_name); Expected> ConfiguredNetworkGroup_get_output_vstream_infos(uint32_t handle, std::string network_name); @@ -63,6 +66,8 @@ public: const std::string &network_name); hailo_status ConfiguredNetworkGroup_set_scheduler_threshold(uint32_t handle, uint32_t threshold, const std::string &network_name); Expected ConfiguredNetworkGroup_get_latency_measurement(uint32_t handle, const std::string &network_name); + Expected ConfiguredNetworkGroup_is_multi_context(uint32_t handle); + Expected ConfiguredNetworkGroup_get_config_params(uint32_t handle); Expected> InputVStreams_create(uint32_t net_group_handle, const std::map &inputs_params, uint32_t pid); @@ -80,14 +85,22 @@ public: Expected InputVStream_name(uint32_t handle); Expected OutputVStream_name(uint32_t handle); + Expected InputVStream_network_name(uint32_t handle); + Expected OutputVStream_network_name(uint32_t handle); + hailo_status InputVStream_abort(uint32_t handle); hailo_status OutputVStream_abort(uint32_t handle); - hailo_status InputVStream_resume(uint32_t handle); hailo_status OutputVStream_resume(uint32_t handle); + Expected InputVStream_get_user_buffer_format(uint32_t handle); + Expected OutputVStream_get_user_buffer_format(uint32_t handle); + + Expected InputVStream_get_info(uint32_t handle); + Expected OutputVStream_get_info(uint32_t handle); + private: - std::unique_ptr m_stub; + std::unique_ptr m_stub; }; } diff --git a/hailort/libhailort/src/hef.cpp b/hailort/libhailort/src/hef.cpp index b2b2657..aa0ee84 100644 --- a/hailort/libhailort/src/hef.cpp +++ b/hailort/libhailort/src/hef.cpp @@ -19,16 +19,14 @@ #include "hailort_defaults.hpp" #include "common/string_utils.hpp" -#include "hlpcie.hpp" #include "pcie_device.hpp" #include "context_switch/multi_context/vdma_config_manager.hpp" -#include "context_switch/single_context/hcp_config_manager.hpp" #include "context_switch/single_context/hcp_config_network_group.hpp" #include "byte_order.h" #include "common/logger_macros.hpp" -#include "context_switch/hef_metadata.hpp" #include "common/file_utils.hpp" #include "layer_info.hpp" +#include "control.hpp" #include "context_switch_defs.h" #include @@ -45,20 +43,10 @@ namespace hailort { #define HEF__MD5_BUFFER_SIZE (1024) -#define CCW_BYTES_IN_WORD (4) -#define CCW_DATA_OFFSET (CCW_BYTES_IN_WORD * 2) -#define CCW_HEADER_SIZE (CCW_DATA_OFFSET) #define DEFAULT_BATCH_SIZE (1) static const uint8_t ENABLE_LCU_CONTROL_WORD[4] = {1, 0, 0, 0}; -// Parse initial_l3 register from old hef -constexpr uint32_t HAILO8_INITIAL_L3_CUT_MASK = 0x0000007F; -constexpr uint32_t HAILO8_INITIAL_L3_OFFSET_MASK = 0x0007FF80L; -constexpr uint32_t HAILO8_INITIAL_L3_OFFSET_SHIFT = 7; -constexpr uint32_t HAILO8_INITIAL_L3_OFFSET_BYTES_GRANULARITY_SHIFT = 3; -constexpr uint64_t CCW_NOP = 0x0; - #pragma pack(push, 1) typedef struct { uint32_t words_count; @@ -66,7 +54,7 @@ typedef struct { } CcwHeader; #pragma pack(pop) -bool ConfigureNetworkParams::operator==(const ConfigureNetworkParams &other) +bool ConfigureNetworkParams::operator==(const ConfigureNetworkParams &other) const { for (auto &name_param_pair : network_params_by_name) { if ((other.network_params_by_name.find(name_param_pair.first) == other.network_params_by_name.end()) || @@ -77,7 +65,7 @@ bool ConfigureNetworkParams::operator==(const ConfigureNetworkParams &other) return (batch_size == other.batch_size) && (power_mode == other.power_mode) && (latency == other.latency); } -bool ConfigureNetworkParams::operator!=(const ConfigureNetworkParams &other) +bool ConfigureNetworkParams::operator!=(const ConfigureNetworkParams &other) const { return !(*this == other); } @@ -368,6 +356,8 @@ hailo_status Hef::Impl::parse_hef_file(const std::string &hef_path) status = transfer_protobuf_field_ownership(hef_message); CHECK_SUCCESS(status); + fill_core_ops(); + status = fill_networks_metadata(); CHECK_SUCCESS(status); @@ -409,6 +399,8 @@ hailo_status Hef::Impl::parse_hef_memview(const MemoryView &hef_memview) status = transfer_protobuf_field_ownership(hef_message); CHECK_SUCCESS(status); + fill_core_ops(); + status = fill_networks_metadata(); CHECK_SUCCESS(status); @@ -422,28 +414,57 @@ hailo_status Hef::Impl::parse_hef_memview(const MemoryView &hef_memview) hailo_status Hef::Impl::fill_networks_metadata() { fill_extensions_bitset(); - auto supported_features = get_supported_features(m_header, m_hef_extensions, m_included_features, - m_hef_optional_extensions); NetworkGroupMetadataPerArch metadata; uint32_t partial_clusters_layout_bitmap = 0; - std::string network_group_name; for (auto &network_group : m_groups) { + auto network_group_name = HefUtils::get_network_group_name(*network_group, m_supported_features); + // TODO: keep metadata per core_op (HRT-8639) + const auto &core_ops = m_core_ops_per_group[network_group_name]; + assert(core_ops.size() == 1); + const auto &core_op = core_ops[0]; if (ProtoHEFHwArch::PROTO__HW_ARCH__HAILO8L == get_device_arch()) { - for (auto &partial_network_group : network_group->partial_network_groups()) { - partial_clusters_layout_bitmap = partial_network_group.layout().partial_clusters_layout_bitmap(); - network_group_name = partial_network_group.network_group().network_group_metadata().network_group_name(); - auto metadata_per_arch = create_metadata_per_arch(partial_network_group.network_group(), supported_features); - CHECK_EXPECTED_AS_STATUS(metadata_per_arch); - metadata.add_metadata(metadata_per_arch.release(), partial_clusters_layout_bitmap); + if (m_supported_features.hailo_net_flow) { + for (auto &partial_core_op : core_op.partial_core_ops) { + partial_clusters_layout_bitmap = partial_core_op->layout.partial_clusters_layout_bitmap(); + auto metadata_per_arch = create_metadata_per_arch(*(partial_core_op->core_op)); + CHECK_EXPECTED_AS_STATUS(metadata_per_arch); + auto &&arch_metadata = metadata_per_arch.release(); + auto expected_net_flow_ops = create_network_group_ops(*network_group, arch_metadata); + CHECK_EXPECTED_AS_STATUS(expected_net_flow_ops); + m_post_process_ops_per_group.insert({arch_metadata.network_group_name(), expected_net_flow_ops.value()}); + metadata.add_metadata(arch_metadata, partial_clusters_layout_bitmap); + } + } else { + for (auto &partial_network_group : network_group->partial_network_groups()) { + partial_clusters_layout_bitmap = partial_network_group.layout().partial_clusters_layout_bitmap(); + ProtoHEFCoreOpMock partial_core_op{ + partial_network_group.network_group().network_group_metadata(), + partial_network_group.network_group().preliminary_config(), + partial_network_group.network_group().contexts(), + partial_network_group.network_group().sorted_outputs_order(), + partial_network_group.network_group().fused_layers_metadata(), + partial_network_group.network_group().networks_names(), + {} + }; + auto metadata_per_arch = create_metadata_per_arch(partial_core_op); + CHECK_EXPECTED_AS_STATUS(metadata_per_arch); + auto &&arch_metadata = metadata_per_arch.release(); + std::vector> empty_ops; + m_post_process_ops_per_group.insert({arch_metadata.network_group_name(), empty_ops}); + metadata.add_metadata(arch_metadata, partial_clusters_layout_bitmap); + } } } else { partial_clusters_layout_bitmap = PARTIAL_CLUSTERS_LAYOUT_IGNORE; - network_group_name = network_group->network_group_metadata().network_group_name(); - auto metadata_per_arch = create_metadata_per_arch(*network_group, supported_features); + auto metadata_per_arch = create_metadata_per_arch(core_op); CHECK_EXPECTED_AS_STATUS(metadata_per_arch); - metadata.add_metadata(metadata_per_arch.release(), partial_clusters_layout_bitmap); + auto &&arch_metadata = metadata_per_arch.release(); + auto expected_net_flow_ops = create_network_group_ops(*network_group, arch_metadata); + CHECK_EXPECTED_AS_STATUS(expected_net_flow_ops); + m_post_process_ops_per_group.insert({arch_metadata.network_group_name(), expected_net_flow_ops.value()}); + metadata.add_metadata(arch_metadata, partial_clusters_layout_bitmap); } CHECK(!contains(m_network_group_metadata_per_arch, network_group_name), HAILO_INVALID_OPERATION, "Network group with the name {} is already configured on the device", network_group_name); @@ -452,42 +473,144 @@ hailo_status Hef::Impl::fill_networks_metadata() return HAILO_SUCCESS; } -Expected Hef::Impl::create_metadata_per_arch(const ProtoHEFNetworkGroup &network_group, NetworkGroupSupportedFeatures &supported_features) +static Expected> parse_config_channels_info(const ProtoHEFCoreOpMock &core_op) { - std::vector> boundary_input_layers; - std::vector> boundary_output_layers; - std::vector> inter_context_input_layers; - std::vector> inter_context_output_layers; - std::vector> ddr_input_layers; - std::vector> ddr_output_layers; - auto status = HefUtils::get_all_layers_info(network_group, supported_features, - boundary_input_layers, boundary_output_layers, - inter_context_input_layers, inter_context_output_layers, - ddr_input_layers, ddr_output_layers); - CHECK_SUCCESS_AS_EXPECTED(status); + const auto &metadata = core_op.network_group_metadata; + // Backwards compatibility for HEFs without the cfg_channels_count field + CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(metadata.cfg_channels_count()), + HAILO_INVALID_HEF, "Invalid cfg channels count"); + const uint8_t cfg_channels_count = (0 == metadata.cfg_channels_count()) ? + 1 : static_cast(metadata.cfg_channels_count()); + + + std::vector config_channels_info; + config_channels_info.reserve(cfg_channels_count); + const auto &cfg_channels_config = metadata.cfg_channels_config(); + for (uint8_t config_stream_index = 0; config_stream_index < cfg_channels_count; config_stream_index++) { + auto cfg_info = std::find_if(cfg_channels_config.begin(), cfg_channels_config.end(), + [config_stream_index](const auto &cfg_info) + { + return cfg_info.cfg_channel_index() == config_stream_index; + }); - auto sorted_output_names = HefUtils::get_sorted_output_names(network_group); + if (cfg_info != cfg_channels_config.end()) { + CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(cfg_info->engine_id()), HAILO_INVALID_HEF, "Invalid dma engine index"); + config_channels_info.emplace_back(ConfigChannelInfo{static_cast(cfg_info->engine_id())}); + } + else { + // Not found - can happen on old HEF or hailo8. In those case we want to use the default engine + config_channels_info.emplace_back(ConfigChannelInfo{vdma::DEFAULT_ENGINE_INDEX}); + } + } + + return config_channels_info; +} + +Expected Hef::Impl::create_metadata_per_arch(const ProtoHEFCoreOpMock &core_op) +{ + auto preliminary_context = HefUtils::parse_preliminary_context(core_op.preliminary_config, m_supported_features); + CHECK_EXPECTED(preliminary_context); + + auto dynamic_contexts = HefUtils::parse_dynamic_contexts(core_op, m_supported_features); + CHECK_EXPECTED(dynamic_contexts); + + auto config_channels_info = parse_config_channels_info(core_op); + CHECK_EXPECTED(config_channels_info); + + auto sorted_output_names = HefUtils::get_sorted_output_names(core_op); CHECK_EXPECTED(sorted_output_names); std::vector sorted_network_names; - if (supported_features.multi_network_support) { - sorted_network_names.reserve(network_group.networks_names().size()); - for (auto &partial_network_name : network_group.networks_names()) { - auto network_name = HefUtils::get_network_name(network_group, partial_network_name); + if (m_supported_features.multi_network_support) { + sorted_network_names.reserve(core_op.networks_names.size()); + for (auto &partial_network_name : core_op.networks_names) { + auto network_name = HefUtils::get_network_name(core_op, partial_network_name); sorted_network_names.push_back(network_name); } } else { - sorted_network_names.push_back(HailoRTDefaults::get_network_name(network_group.network_group_metadata().network_group_name())); + sorted_network_names.push_back(HailoRTDefaults::get_network_name(core_op.network_group_metadata.network_group_name())); } - NetworkGroupMetadata metadata_per_arch(network_group.network_group_metadata().network_group_name(), - std::move(boundary_input_layers), std::move(boundary_output_layers), - std::move(inter_context_input_layers), std::move(inter_context_output_layers), - std::move(ddr_input_layers), std::move(ddr_output_layers), - sorted_output_names.release(), supported_features, sorted_network_names); + NetworkGroupMetadata metadata_per_arch(core_op.network_group_metadata.network_group_name(), + preliminary_context.release(), dynamic_contexts.release(), config_channels_info.release(), + sorted_output_names.release(), m_supported_features, sorted_network_names); return metadata_per_arch; } +void Hef::Impl::fill_core_ops() +{ + if (m_supported_features.hailo_net_flow) { + for (const auto &net_group : m_groups) { + auto core_op_iter = std::find_if(net_group->ops().begin(), net_group->ops().end(), + [](auto &op) { + return op.op_case() == ProtoHEFOp::kCoreOp; + }); + assert(core_op_iter != m_groups[0]->ops().end()); + std::vector> partial_core_ops; + partial_core_ops.reserve(core_op_iter->core_op().partial_core_ops().size()); + for (auto &partial_core_op : core_op_iter->core_op().partial_core_ops()) { + ProtoHEFCoreOpMock core_op{ + partial_core_op.core_op().network_group_metadata(), + partial_core_op.core_op().preliminary_config(), + partial_core_op.core_op().contexts(), + partial_core_op.core_op().sorted_outputs_order(), + partial_core_op.core_op().fused_layers_metadata(), + partial_core_op.core_op().networks_names(), + {} + }; + ProtoHEFPartialCoreOpMock partial_core_op_mock{ + std::make_shared(core_op), + partial_core_op.layout() + }; + partial_core_ops.push_back(std::make_shared(partial_core_op_mock)); + } + ProtoHEFCoreOpMock core_op{ + core_op_iter->core_op().network_group_metadata(), + core_op_iter->core_op().preliminary_config(), + core_op_iter->core_op().contexts(), + core_op_iter->core_op().sorted_outputs_order(), + core_op_iter->core_op().fused_layers_metadata(), + core_op_iter->core_op().networks_names(), + partial_core_ops + }; + auto net_group_name = HefUtils::get_network_group_name(*net_group, m_supported_features); + m_core_ops_per_group[net_group_name].push_back(std::move(core_op)); + } + } else { + for (const auto &net_group : m_groups) { + std::vector> partial_core_ops; + partial_core_ops.reserve(net_group->partial_network_groups().size()); + for (auto &partial_network_group : net_group->partial_network_groups()) { + ProtoHEFCoreOpMock core_op{ + partial_network_group.network_group().network_group_metadata(), + partial_network_group.network_group().preliminary_config(), + partial_network_group.network_group().contexts(), + partial_network_group.network_group().sorted_outputs_order(), + partial_network_group.network_group().fused_layers_metadata(), + partial_network_group.network_group().networks_names(), + {} + }; + ProtoHEFPartialCoreOpMock partial_core_op{ + std::make_shared(core_op), + partial_network_group.layout() + }; + partial_core_ops.push_back(std::make_shared(partial_core_op)); + } + ProtoHEFCoreOpMock core_op{ + net_group->network_group_metadata(), + net_group->preliminary_config(), + net_group->contexts(), + net_group->sorted_outputs_order(), + net_group->fused_layers_metadata(), + net_group->networks_names(), + partial_core_ops + }; + auto net_group_name = HefUtils::get_network_group_name(*net_group, m_supported_features); + m_core_ops_per_group[net_group_name].push_back(std::move(core_op)); + } + } +} + hailo_status Hef::Impl::transfer_protobuf_field_ownership(ProtoHEFHef &hef_message) { m_groups.reserve(hef_message.network_groups().size()); @@ -512,6 +635,9 @@ hailo_status Hef::Impl::transfer_protobuf_field_ownership(ProtoHEFHef &hef_messa m_hef_optional_extensions.emplace_back(optional_extension); } + m_supported_features = get_supported_features(m_header, m_hef_extensions, m_included_features, + m_hef_optional_extensions); + return HAILO_SUCCESS; } @@ -557,23 +683,124 @@ void Hef::Impl::fill_extensions_bitset() } } -NetworkGroupSupportedFeatures Hef::Impl::get_supported_features(const ProtoHEFHeader &header, +SupportedFeatures Hef::Impl::get_supported_features(const ProtoHEFHeader &header, const std::vector &hef_extensions, const ProtoHEFIncludedFeatures &included_features, const std::vector &hef_optional_extensions) { - NetworkGroupSupportedFeatures supported_features{}; - supported_features.padded_ddr_buffers = check_hef_extension(ProtoHEFExtensionType::PADDED_DDR_BUFFERS, header, - hef_extensions, included_features); + SupportedFeatures supported_features{}; + supported_features.padded_ddr_buffers = check_hef_extension(ProtoHEFExtensionType::PADDED_DDR_BUFFERS, + header, hef_extensions, included_features); supported_features.multi_network_support = check_hef_optional_extension(ProtoHEFExtensionType::MULTI_NETWORK_VARIABLE_BATCH_SIZE, header, hef_optional_extensions); - supported_features.multi_context = check_hef_extension(ProtoHEFExtensionType::IS_MULTI_CONTEXTS, header, - hef_extensions, included_features); + supported_features.multi_context = check_hef_extension(ProtoHEFExtensionType::IS_MULTI_CONTEXTS, + header, hef_extensions, included_features); supported_features.preliminary_run_asap = check_hef_extension(ProtoHEFExtensionType::KO_RUN_ASAP, header, hef_extensions, included_features); + supported_features.hailo_net_flow = check_hef_extension(ProtoHEFExtensionType::HAILO_NET_FLOW, + header, hef_extensions, included_features); return supported_features; } +Expected>> Hef::Impl::create_network_group_ops(const ProtoHEFNetworkGroup &network_group_proto, + NetworkGroupMetadata &network_group_meta_data) const +{ + std::vector> result; + if (!m_supported_features.hailo_net_flow) { + return result; + } + auto output_layer_infos = network_group_meta_data.get_output_layer_infos(); + std::map pad_index_to_streams_info; + for (auto &output_layer_info : output_layer_infos) { + if (output_layer_info.pad_index != INVALID_PAD_INDEX) { + pad_index_to_streams_info.insert({output_layer_info.pad_index, output_layer_info}); + } + } + std::map input_to_output_pads; + for (auto &pad_edge : network_group_proto.pad_edges()) { + input_to_output_pads.insert({pad_edge.dst(), pad_edge.src()}); + } + for (auto &op_proto : network_group_proto.ops()) { + switch (op_proto.op_case()) { + case ProtoHEFOp::kCoreOp: { + break; + } + case ProtoHEFOp::kNmsOp: { + NetFlowYoloNmsElement nms_op{}; + nms_op.type = NetFlowElement::Type::YoloNmsOp; + nms_op.name = "YOLO_NMS"; + nms_op.nms_score_th = (float32_t)op_proto.nms_op().nms_score_th(); + nms_op.nms_iou_th = (float32_t)op_proto.nms_op().nms_iou_th(); + nms_op.max_proposals_per_class = op_proto.nms_op().max_proposals_per_class(); + nms_op.classes = op_proto.nms_op().classes(); + nms_op.background_removal = op_proto.nms_op().background_removal(); + nms_op.background_removal_index = op_proto.nms_op().background_removal_index(); + nms_op.image_height = (float32_t)op_proto.nms_op().yolo_nms_op().image_height(); + nms_op.image_width = (float32_t)op_proto.nms_op().yolo_nms_op().image_width(); + nms_op.input_division_factor = op_proto.nms_op().yolo_nms_op().input_division_factor(); + if (!nms_op.input_division_factor) { + nms_op.input_division_factor = 1; + } + nms_op.bbox_decoders.reserve(op_proto.nms_op().yolo_nms_op().bbox_decoders().size()); + for (auto &bbox_proto : op_proto.nms_op().yolo_nms_op().bbox_decoders()) { + YoloBboxDecoder yolo_bbox_decoder; + for (auto h : bbox_proto.h()) { + yolo_bbox_decoder.h.push_back(h); + } + for (auto w : bbox_proto.w()) { + yolo_bbox_decoder.w.push_back(w); + } + yolo_bbox_decoder.stride = bbox_proto.stride(); + yolo_bbox_decoder.stream_name = pad_index_to_streams_info[input_to_output_pads[bbox_proto.pad_index()]].name; + nms_op.bbox_decoders.push_back(yolo_bbox_decoder); + } + std::set input_pads; + std::transform(op_proto.input_pads().begin(), op_proto.input_pads().end(), std::inserter(input_pads, input_pads.begin()), + [](auto &pad) { + return pad.index(); + }); + for (auto &input_pad : op_proto.input_pads()) { + CHECK_AS_EXPECTED(input_to_output_pads.count(input_pad.index()), HAILO_INVALID_HEF, + "NMS op is not connected to core op"); + auto output_pad_index = input_to_output_pads[input_pad.index()]; + CHECK_AS_EXPECTED(pad_index_to_streams_info.count(output_pad_index), HAILO_INVALID_HEF, + "Pad {} of post-process {} is not connected to any core output stream", + input_pad.index(), op_proto.name()); + const auto &op_input_stream = pad_index_to_streams_info[output_pad_index]; + nms_op.input_pads.push_back(NetFlowPad{input_pad.name(), op_input_stream.format, op_input_stream.quant_info, 0}); + nms_op.input_streams.insert(op_input_stream.name); + } + hailo_format_t format; + format.type = HAILO_FORMAT_TYPE_FLOAT32; + format.order = HAILO_FORMAT_ORDER_HAILO_NMS; + format.flags = HAILO_FORMAT_FLAGS_QUANTIZED; + assert(op_proto.output_pads().size() == 1); + auto proto_output_pad = op_proto.output_pads()[0]; + nms_op.output_pads.push_back(NetFlowPad{proto_output_pad.name(), format, hailo_quant_info_t(), nms_op.classes}); + result.push_back(std::shared_ptr(std::make_shared(nms_op))); + + // Fill meta-data output vstream info + auto net_group_name = HefUtils::get_network_group_name(network_group_proto, m_supported_features); + auto network_name = HailoRTDefaults::get_network_name(net_group_name); + hailo_vstream_info_t net_flow_output_vstream_info{}; + strncpy(net_flow_output_vstream_info.name, proto_output_pad.name().c_str(), proto_output_pad.name().length() + 1); + strncpy(net_flow_output_vstream_info.network_name, network_name.c_str(), network_name.length() + 1); + net_flow_output_vstream_info.direction = HAILO_D2H_STREAM; + net_flow_output_vstream_info.format = format; + net_flow_output_vstream_info.nms_shape.number_of_classes = nms_op.classes; + net_flow_output_vstream_info.nms_shape.max_bboxes_per_class = nms_op.max_proposals_per_class; + network_group_meta_data.add_output_vstream_info(net_flow_output_vstream_info); + break; + } + default: { + LOGGER__ERROR("Unsupported Net-Flow Op"); + return make_unexpected(HAILO_INTERNAL_FAILURE); + } + } + } + return result; +} + hailo_status get_hw_padding_params(hailo_format_order_t format_order, uint32_t width, uint32_t features, uint32_t hw_data_bytes, uint16_t &feature_padding_payload, uint16_t &periph_bytes_per_buffer) { @@ -621,6 +848,9 @@ Expected HefConfigurator::parse_nn_stream_ stream_config.core_buffers_per_frame = core_buffers_per_frame; stream_config.core_bytes_per_buffer = core_bytes_per_buffer; + stream_config.periph_buffers_per_frame = core_buffers_per_frame; // periph buffers per frame is the same (even if + // for hw padding each buffer is smaller). + /* For DDR buffering - core buffers is depended on the amount of buffers per PCIe interrupt. No HW padding required */ if (is_ddr) { @@ -701,7 +931,7 @@ bool HefConfigurator::is_hw_padding_supported(bool is_boundary, bool is_mux, hai return false; } - if((width * features * hw_data_bytes) > + if ((width * features * hw_data_bytes) > (HAILO8_INBOUND_DATA_STREAM_SIZE - 1)) { // TODO: HRT-4177 LOGGER__DEBUG("HW padding is supported only on layers with features * width * data size > stream size"); @@ -735,14 +965,13 @@ bool HefConfigurator::is_hw_padding_supported(const ProtoHEFEdgeLayer &edge_laye LOGGER__DEBUG("Failed to get format order. Not enabling hw padding"); return false; } - CHECK_EXPECTED_AS_STATUS(format_order_exp); - auto format_order = format_order_exp.release(); if (!IS_FIT_IN_UINT16(edge_layer_base.core_buffers_per_frame())) { LOGGER__DEBUG("Invalid core_buffers_per_frame. Not enabling hw padding"); return false; } + auto format_order = format_order_exp.release(); return is_hw_padding_supported(is_boundary, is_mux, format_order, static_cast(edge_layer_base.core_buffers_per_frame()), edge_layer_base.height(), edge_layer_base.width(), edge_layer_base.features(), edge_layer_base.data_bytes()); } @@ -834,6 +1063,18 @@ const std::vector& Hef::Impl::network_groups() const return m_groups; }; +const std::vector& Hef::Impl::core_ops(const std::string &net_group_name) const +{ + assert(contains(m_core_ops_per_group, net_group_name)); + return m_core_ops_per_group.at(net_group_name); +}; + +const std::vector> Hef::Impl::post_process_ops(const std::string &net_group_name) const +{ + assert(contains(m_post_process_ops_per_group, net_group_name)); + return m_post_process_ops_per_group.at(net_group_name); +} + bool Hef::Impl::check_hef_extension(const ProtoHEFExtensionType &extension, const ProtoHEFHeader &header, const std::vector &hef_extensions, const ProtoHEFIncludedFeatures &included_features) { @@ -891,6 +1132,7 @@ Expected> Hef::Impl::get_network_group_and_n } else { const ProtoHEFNetworkGroup *network_group_ptr = nullptr; for (const auto &network_group : m_groups) { + // TODO: Handle new HEFs network_group_ptr = (ProtoHEFHwArch::PROTO__HW_ARCH__HAILO8L == get_device_arch()) ? &network_group->partial_network_groups(0).network_group() : network_group.get(); @@ -920,36 +1162,28 @@ Expected> Hef::Impl::get_network_group_and_n return make_unexpected(HAILO_NOT_FOUND); } -Expected Hef::Impl::get_net_group_by_name(const std::string &net_group_name) +// TODO: core_ops names? +Expected> Hef::Impl::get_core_op_by_net_group_name(const std::string &net_group_name) { - const ProtoHEFNetworkGroup *network_group_ptr = nullptr; if ("" == net_group_name) { - network_group_ptr = (ProtoHEFHwArch::PROTO__HW_ARCH__HAILO8L == get_device_arch()) ? - &m_groups[0]->partial_network_groups(0).network_group() : m_groups[0].get(); - - LOGGER__INFO("No network_group name was given. Addressing default network_group: {}", - network_group_ptr->network_group_metadata().network_group_name()); - - ProtoHEFNetworkGroupPtr network_group_shared_ptr = make_shared_nothrow(*network_group_ptr); - CHECK_NOT_NULL_AS_EXPECTED(network_group_shared_ptr, HAILO_OUT_OF_HOST_MEMORY); - return Expected(network_group_shared_ptr); - } - for (auto const &net_group : m_groups) { - CHECK_AS_EXPECTED(nullptr != net_group, HAILO_INTERNAL_FAILURE, "null netwrok group"); + auto network_group_ptr = m_groups[0]; + auto network_group_name = HefUtils::get_network_group_name(*network_group_ptr, m_supported_features); + LOGGER__INFO("No network_group name was given. Addressing default network_group: {}", network_group_name); + const auto &core_op = m_core_ops_per_group[network_group_name][0]; if (ProtoHEFHwArch::PROTO__HW_ARCH__HAILO8L == get_device_arch()) { - if (net_group_name == - net_group->partial_network_groups(0).network_group().network_group_metadata().network_group_name()) { - ProtoHEFNetworkGroupPtr network_group_shared_ptr = - make_shared_nothrow(m_groups[0]->partial_network_groups(0).network_group()); - CHECK_NOT_NULL_AS_EXPECTED(network_group_shared_ptr, HAILO_OUT_OF_HOST_MEMORY); - return Expected(network_group_shared_ptr); - } - } else if (net_group_name == net_group->network_group_metadata().network_group_name()) { - return Expected(net_group); + auto partial_core_op = core_op.partial_core_ops[0]; + return std::make_shared(*(partial_core_op->core_op)); } + return std::make_shared(core_op); } - LOGGER__ERROR("HEF does not contain network_group with name {}", net_group_name); - return make_unexpected(HAILO_NOT_FOUND); + CHECK_AS_EXPECTED(contains(m_core_ops_per_group, net_group_name), HAILO_NOT_FOUND, + "HEF does not contain network_group with name {}", net_group_name); + const auto &core_op = m_core_ops_per_group[net_group_name][0]; + if (ProtoHEFHwArch::PROTO__HW_ARCH__HAILO8L == get_device_arch()) { + auto partial_core_op = core_op.partial_core_ops[0]; + return std::make_shared(*(partial_core_op->core_op)); + } + return std::make_shared(core_op); } Expected Hef::Impl::get_number_of_input_streams(const std::string &net_group_name) @@ -958,8 +1192,7 @@ Expected Hef::Impl::get_number_of_input_streams(const std::string &net_g CHECK_EXPECTED(network_group_metadata); auto input_layer_infos = network_group_metadata->get_input_layer_infos(); - CHECK_EXPECTED(input_layer_infos); - return input_layer_infos->size(); + return input_layer_infos.size(); } Expected Hef::Impl::get_number_of_output_streams(const std::string &net_group_name) @@ -968,8 +1201,22 @@ Expected Hef::Impl::get_number_of_output_streams(const std::string &net_ CHECK_EXPECTED(network_group_metadata); auto output_layer_infos = network_group_metadata->get_output_layer_infos(); - CHECK_EXPECTED(output_layer_infos); - return output_layer_infos->size(); + return output_layer_infos.size(); +} + +static Expected get_layer_type(const ProtoHEFEdgeConnectionType &edge_connection_type) +{ + switch (edge_connection_type) { + case PROTO__EDGE_CONNECTION_TYPE__BOUNDARY: + return LayerType::BOUNDARY; + case PROTO__EDGE_CONNECTION_TYPE__INTERMEDIATE: + return LayerType::INTER_CONTEXT; + case PROTO__EDGE_CONNECTION_TYPE__DDR: + return LayerType::DDR; + default: + LOGGER__ERROR("Not supported edge connection type {}", edge_connection_type); + return make_unexpected(HAILO_INVALID_HEF); + } } hailo_status HefUtils::fill_layer_info_with_base_info(const ProtoHEFEdgeLayerBase &base_info, @@ -982,6 +1229,10 @@ hailo_status HefUtils::fill_layer_info_with_base_info(const ProtoHEFEdgeLayerBas auto format_oder = format_order_exp.release(); + auto layer_type = get_layer_type(edge_connection_type); + CHECK_EXPECTED_AS_STATUS(layer_type); + layer_info.type = layer_type.value(); + if (HEF__FORMAT__NMS != base_info.format()) { layer_info.shape.height = base_info.height(); layer_info.shape.width = base_info.width(); @@ -992,7 +1243,6 @@ hailo_status HefUtils::fill_layer_info_with_base_info(const ProtoHEFEdgeLayerBas layer_info.shape.features = static_cast(base_info.additional_info().nms_info().max_output_size() * base_info.additional_info().nms_info().input_division_factor()); } - if (hw_padding_supported) { layer_info.hw_shape.height = base_info.height(); layer_info.hw_shape.width = base_info.width(); @@ -1050,12 +1300,12 @@ hailo_status HefUtils::fill_layer_info_with_base_info(const ProtoHEFEdgeLayerBas } hailo_status HefUtils::fill_layer_info(const ProtoHEFEdgeLayerInfo &info, - const ProtoHEFEdgeConnectionType &edge_connection_type, - const ProtoHEFNetworkGroup &net_group, hailo_stream_direction_t direction, + const ProtoHEFEdgeConnectionType &edge_connection_type, + const ProtoHEFCoreOpMock &core_op, hailo_stream_direction_t direction, bool hw_padding_supported, const uint8_t context_index, const std::string &partial_network_name, uint8_t network_index, LayerInfo &layer_info) { - auto status = fill_layer_info_with_base_info(info.edge_layer_base(), edge_connection_type, net_group.network_group_metadata(), + auto status = fill_layer_info_with_base_info(info.edge_layer_base(), edge_connection_type, core_op.network_group_metadata, hw_padding_supported, info.transposed(), context_index, network_index, layer_info); CHECK_SUCCESS(status); @@ -1069,7 +1319,7 @@ hailo_status HefUtils::fill_layer_info(const ProtoHEFEdgeLayerInfo &info, } layer_info.name = info.name(); - layer_info.network_name = HefUtils::get_network_name(net_group, partial_network_name); + layer_info.network_name = HefUtils::get_network_name(core_op, partial_network_name); layer_info.is_mux = false; layer_info.direction = direction; layer_info.quant_info.limvals_max = info.numeric_info().limvals_max(); @@ -1081,11 +1331,11 @@ hailo_status HefUtils::fill_layer_info(const ProtoHEFEdgeLayerInfo &info, layer_info.buffer_indices.cluster_index = info.edge_layer_base().buffer_indices(0).cluster_index(); layer_info.buffer_indices.index = info.edge_layer_base().buffer_indices(0).index(); - layer_info.is_defused_nms = net_group.has_fused_layers_metadata() && + layer_info.is_defused_nms = core_op.fused_layers_metadata.network_has_fused_layers() && (HAILO_FORMAT_ORDER_HAILO_NMS == layer_info.format.order) && layer_info.nms_info.is_defused; if (layer_info.is_defused_nms) { - for (const auto &fused_layer : net_group.fused_layers_metadata().fused_layers()) { + for (const auto &fused_layer : core_op.fused_layers_metadata.fused_layers()) { if (fused_layer.layer_info().name() == layer_info.nms_info.defuse_info.original_name) { // This creates a new LayerInfo for the fused layer *for each defused layer*, even though they all share the same fused layer. // TODO Make it so all defused layer reference the same LayerInfo of the fused layer. @@ -1147,12 +1397,12 @@ hailo_status HefUtils::fill_fused_nms_info(const ProtoHEFEdgeLayerFused &info, L hailo_status HefUtils::fill_mux_info(const ProtoHEFEdgeLayerMux &info, const ProtoHEFEdgeConnectionType &edge_connection_type, - const ProtoHEFNetworkGroup &net_group, hailo_stream_direction_t direction, + const ProtoHEFCoreOpMock &core_op, hailo_stream_direction_t direction, bool hw_padding_supported, const uint8_t context_index, const std::string &partial_network_name, uint8_t network_index, LayerInfo &layer_info) { const bool transposed = false; - auto status = fill_layer_info_with_base_info(info.edge_layer_base(), edge_connection_type, net_group.network_group_metadata(), + auto status = fill_layer_info_with_base_info(info.edge_layer_base(), edge_connection_type, core_op.network_group_metadata, hw_padding_supported, transposed, context_index, network_index, layer_info); CHECK_SUCCESS(status); @@ -1166,7 +1416,7 @@ hailo_status HefUtils::fill_mux_info(const ProtoHEFEdgeLayerMux &info, } layer_info.name = info.name(); - layer_info.network_name = HefUtils::get_network_name(net_group, partial_network_name); + layer_info.network_name = HefUtils::get_network_name(core_op, partial_network_name); layer_info.is_mux = true; layer_info.predecessor.reserve(info.mux_data().number_of_predecessors()); layer_info.height_gcd = info.mux_data().height_gcd(); @@ -1183,7 +1433,7 @@ hailo_status HefUtils::fill_mux_info(const ProtoHEFEdgeLayerMux &info, LayerInfo temp_layer = {}; switch (info.predecessors(i).edge_case()) { case ProtoHefEdge::kLayerInfo: - status = fill_layer_info(info.predecessors(i).layer_info(), edge_connection_type, net_group, + status = fill_layer_info(info.predecessors(i).layer_info(), edge_connection_type, core_op, direction, hw_padding_supported, context_index, partial_network_name, network_index, temp_layer); if (HAILO_SUCCESS != status) { return status; @@ -1191,7 +1441,7 @@ hailo_status HefUtils::fill_mux_info(const ProtoHEFEdgeLayerMux &info, layer_info.predecessor.push_back(temp_layer); break; case ProtoHefEdge::kLayerMux: - status = fill_mux_info(info.predecessors(i).layer_mux(), edge_connection_type, net_group, + status = fill_mux_info(info.predecessors(i).layer_mux(), edge_connection_type, core_op, direction, hw_padding_supported, context_index, partial_network_name, network_index, temp_layer); if (HAILO_SUCCESS != status) { return status; @@ -1209,85 +1459,58 @@ hailo_status HefUtils::fill_mux_info(const ProtoHEFEdgeLayerMux &info, } hailo_status HefUtils::fill_boundary_layers_info( - const ProtoHEFNetworkGroup &network_group_proto, + const ProtoHEFCoreOpMock &core_op, const uint8_t context_index, const ProtoHEFEdgeLayer &layer, - const NetworkGroupSupportedFeatures &supported_features, - std::vector &layer_name, - std::vector &context_boundary_input_layers, - std::vector &context_boundary_output_layers) + const SupportedFeatures &supported_features, + ContextMetadata &context_metadata) { - auto layer_info = get_boundary_layer_info(network_group_proto, context_index, layer, supported_features); + auto layer_info = get_boundary_layer_info(core_op, context_index, layer, supported_features); CHECK_EXPECTED_AS_STATUS(layer_info); - // Validate unique layer names - for (const auto &parsed_layer_name : layer_name) { - CHECK((parsed_layer_name != layer_info->name), HAILO_INVALID_HEF, - "Layer name should be unique. name '{}' appears more than once", layer_info->name); - } - - // Temp vector for validation - layer_name.emplace_back(layer_info.value().name); - - if (HAILO_H2D_STREAM == layer_info->direction) { - context_boundary_input_layers.emplace_back(layer_info.release()); - } else { - context_boundary_output_layers.emplace_back(layer_info.release()); - } + context_metadata.add_boundary_layer(layer_info.release()); return HAILO_SUCCESS; } hailo_status HefUtils::fill_inter_context_layers_info( - const ProtoHEFNetworkGroup &network_group_proto, + const ProtoHEFCoreOpMock &core_op, const uint8_t context_index, const ProtoHEFEdgeLayer &layer, - const NetworkGroupSupportedFeatures &supported_features, - std::vector &context_inter_context_input_layers, - std::vector &context_inter_context_output_layers) + const SupportedFeatures &supported_features, + ContextMetadata &context_metadata) { - auto layer_info = get_inter_context_layer_info(network_group_proto, context_index, layer, supported_features); + auto layer_info = get_inter_context_layer_info(core_op, context_index, layer, supported_features); CHECK_EXPECTED_AS_STATUS(layer_info); - if (HAILO_H2D_STREAM == layer_info->direction) { - context_inter_context_input_layers.emplace_back(layer_info.release()); - } else { - context_inter_context_output_layers.emplace_back(layer_info.release()); - } - + context_metadata.add_inter_context_layer(layer_info.release()); return HAILO_SUCCESS; } hailo_status HefUtils::fill_ddr_layers_info( - const ProtoHEFNetworkGroup &network_group_proto, + const ProtoHEFCoreOpMock &core_op, const uint8_t context_index, const ProtoHEFEdgeLayer &layer, - const NetworkGroupSupportedFeatures &supported_features, - std::vector &context_ddr_input_layers, - std::vector &context_ddr_output_layers) + const SupportedFeatures &supported_features, + ContextMetadata &context_metadata) { - auto layer_info = get_ddr_layer_info(network_group_proto, context_index, layer, supported_features); + auto layer_info = get_ddr_layer_info(core_op, context_index, layer, supported_features); CHECK_EXPECTED_AS_STATUS(layer_info); - if (HAILO_H2D_STREAM == layer_info->direction) { - context_ddr_input_layers.emplace_back(layer_info.release()); - } else { - context_ddr_output_layers.emplace_back(layer_info.release()); - } - + context_metadata.add_ddr_layer(layer_info.release()); return HAILO_SUCCESS; } hailo_status HefUtils::check_ddr_pairs_match( - const std::vector &context_ddr_input_layers, - const std::vector &context_ddr_output_layers, + const std::vector &context_ddr_input_layers, + const std::vector &context_ddr_output_layers, const uint8_t context_index) { CHECK(context_ddr_input_layers.size() == context_ddr_output_layers.size(), HAILO_INVALID_HEF, "DDR pairs must be equal in size for context {}" ,context_index); for (auto const &ddr_output_layer : context_ddr_output_layers) { - auto matching_input_stream = ddr_output_layer.dst_stream_index; + auto matching_input_stream = ddr_output_layer.connected_context_info.stream_index; bool found_mathing_layer = false; for (auto const &ddr_input_layer : context_ddr_input_layers) { if (ddr_input_layer.stream_index == matching_input_stream) { @@ -1299,12 +1522,12 @@ hailo_status HefUtils::check_ddr_pairs_match( "input stream index {}.input size core_bytes_per_buffer - {}", context_index, ddr_output_layer.stream_index, ddr_output_layer.nn_stream_config.core_bytes_per_buffer, ddr_input_layer.stream_index, ddr_input_layer.nn_stream_config.core_bytes_per_buffer); - CHECK(ddr_output_layer.total_buffers_per_frame == ddr_input_layer.total_buffers_per_frame, + CHECK(ddr_output_layer.ddr_info.total_buffers_per_frame == ddr_input_layer.ddr_info.total_buffers_per_frame, HAILO_INVALID_HEF, "both sides for DDR pair must have the same total_buffers_per_frame.\n" "context index {}. Output stream index - {} output side total_buffers_per_frame - {}." "input stream index {}. input size total_buffers_per_frame - {}", - context_index, ddr_output_layer.stream_index, ddr_output_layer.total_buffers_per_frame, - ddr_input_layer.stream_index, ddr_input_layer.total_buffers_per_frame); + context_index, ddr_output_layer.stream_index, ddr_output_layer.ddr_info.total_buffers_per_frame, + ddr_input_layer.stream_index, ddr_input_layer.ddr_info.total_buffers_per_frame); } } CHECK(found_mathing_layer, HAILO_INVALID_HEF, "didn't find any match for context {} output stream {}", context_index, ddr_output_layer.stream_index); @@ -1313,57 +1536,377 @@ hailo_status HefUtils::check_ddr_pairs_match( return HAILO_SUCCESS; } -hailo_status HefUtils::get_all_layers_info(const ProtoHEFNetworkGroup &network_group_proto, - const NetworkGroupSupportedFeatures &supported_features, - std::vector> &boundary_input_layers, - std::vector> &boundary_output_layers, - std::vector> &inter_context_input_layers, - std::vector> &inter_context_output_layers, - std::vector> &ddr_input_layers, - std::vector> &ddr_output_layers) -{ - std::vector boundary_layers_name; - for (uint8_t context_index = 0; context_index < network_group_proto.contexts_size(); context_index++) { - auto &context_metadata = network_group_proto.contexts(context_index).metadata(); - std::vector context_boundary_input_layers; - std::vector context_boundary_output_layers; - std::vector context_inter_context_input_layers; - std::vector context_inter_context_output_layers; - std::vector context_ddr_input_layers; - std::vector context_ddr_output_layers; - for (int i = 0; i < context_metadata.edge_layers_size(); i++) { - if (ProtoHEFEdgeConnectionType::PROTO__EDGE_CONNECTION_TYPE__BOUNDARY == - context_metadata.edge_layers(i).context_switch_info().edge_connection_type()) { - auto status = fill_boundary_layers_info(network_group_proto, context_index, context_metadata.edge_layers(i), - supported_features, boundary_layers_name, context_boundary_input_layers, context_boundary_output_layers); - CHECK_SUCCESS(status); - } else if (ProtoHEFEdgeConnectionType::PROTO__EDGE_CONNECTION_TYPE__INTERMEDIATE == - context_metadata.edge_layers(i).context_switch_info().edge_connection_type()) { - auto status = fill_inter_context_layers_info(network_group_proto, context_index, context_metadata.edge_layers(i), - supported_features, context_inter_context_input_layers, context_inter_context_output_layers); - CHECK_SUCCESS(status); - } else if (ProtoHEFEdgeConnectionType::PROTO__EDGE_CONNECTION_TYPE__DDR == - context_metadata.edge_layers(i).context_switch_info().edge_connection_type()) { - auto status = fill_ddr_layers_info(network_group_proto, context_index, context_metadata.edge_layers(i), - supported_features, context_ddr_input_layers, context_ddr_output_layers); - CHECK_SUCCESS(status); +static Expected parse_trigger_action(const ProtoHEFTrigger &trigger_proto) +{ + switch (trigger_proto.trigger_case()) { + case ProtoHEFTrigger::kTriggerLcu: + { + const auto cluster_index = trigger_proto.trigger_lcu().cluster_index(); + const auto lcu_index = trigger_proto.trigger_lcu().lcu_index(); + CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(cluster_index), HAILO_INVALID_HEF, + "Failed to parse HEF. Invalid cluster_index: {}.", cluster_index); + CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(lcu_index), HAILO_INVALID_HEF, + "Failed to parse HEF. Invalid lcu_index: {}.", lcu_index); + return WaitForLcuAction::create(static_cast(cluster_index), static_cast(lcu_index)); + } + case ProtoHEFTrigger::kTriggerAllDataWasSent: + { + const auto stream_index = trigger_proto.trigger_all_data_was_sent().shmifo_index(); + CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(stream_index), HAILO_INVALID_HEF, + "Failed to parse HEF. Invalid stream_index: {}.", stream_index); + return WaitOutputTransferDoneAction::create(static_cast(stream_index)); + } + case ProtoHEFTrigger::kTriggerDmaIdle: + { + const auto stream_index = trigger_proto.trigger_dma_idle().shmifo_index(); + CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(stream_index), HAILO_INVALID_HEF, + "Failed to parse HEF. Invalid stream_index: {}.", stream_index); + return WaitDmaIdleAction::create(static_cast(stream_index)); + } + case ProtoHEFTrigger::kTriggerNms: + { + const auto aggregator_index = trigger_proto.trigger_nms().aggregator_index(); + const auto pred_cluster_ob_index = trigger_proto.trigger_nms().pred_cluster_ob_index(); + const auto pred_cluster_ob_cluster_index = trigger_proto.trigger_nms().pred_cluster_ob_cluster_index(); + const auto pred_cluster_ob_interface = trigger_proto.trigger_nms().pred_cluster_ob_interface(); + const auto succ_prepost_ob_index = trigger_proto.trigger_nms().succ_prepost_ob_index(); + const auto succ_prepost_ob_interface = trigger_proto.trigger_nms().succ_prepost_ob_interface(); + CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(aggregator_index), HAILO_INVALID_HEF, + "Failed to parse HEF. Invalid aggregator_index: {}.", aggregator_index); + CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(pred_cluster_ob_index), HAILO_INVALID_HEF, + "Failed to parse HEF. Invalid pred_cluster_ob_index: {}.", pred_cluster_ob_index); + CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(pred_cluster_ob_cluster_index), HAILO_INVALID_HEF, + "Failed to parse HEF. Invalid pred_cluster_ob_cluster_index: {}.", pred_cluster_ob_cluster_index); + CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(pred_cluster_ob_interface), HAILO_INVALID_HEF, + "Failed to parse HEF. Invalid pred_cluster_ob_interface: {}.", pred_cluster_ob_interface); + CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(succ_prepost_ob_index), HAILO_INVALID_HEF, + "Failed to parse HEF. Invalid succ_prepost_ob_index: {}.", succ_prepost_ob_index); + CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(succ_prepost_ob_interface), HAILO_INVALID_HEF, + "Failed to parse HEF. Invalid succ_prepost_ob_interface: {}.", succ_prepost_ob_interface); + + return WaitNmsIdleAction::create(static_cast(aggregator_index), + static_cast(pred_cluster_ob_index), static_cast(pred_cluster_ob_cluster_index), + static_cast(pred_cluster_ob_interface), static_cast(succ_prepost_ob_index), + static_cast(succ_prepost_ob_interface)); + } + case ProtoHEFTrigger::kTriggerAllDataWasReceived: + { + LOGGER__ERROR("kTriggerAllDataWasReceived trigger is not supported"); + return make_unexpected(HAILO_NOT_IMPLEMENTED); + } + case ProtoHEFTrigger::kTriggerNone: + { + return NoneAction::create(); + } + default: + LOGGER__ERROR("Unsupported trigger given {}", trigger_proto.trigger_case()); + return make_unexpected(HAILO_INVALID_HEF); + } +} + +// Parse initial_l3 register from old hef +constexpr uint32_t HAILO8_INITIAL_L3_CUT_MASK = 0x0000007F; +constexpr uint32_t HAILO8_INITIAL_L3_OFFSET_MASK = 0x0007FF80L; +constexpr uint32_t HAILO8_INITIAL_L3_OFFSET_SHIFT = 7; +constexpr uint32_t HAILO8_INITIAL_L3_OFFSET_BYTES_GRANULARITY_SHIFT = 3; + + +static std::pair old_hef_parse_initial_l3(uint32_t initial_l3) +{ + // parse initial l3 as written in hailo8 initial_l3 format - + // 7 bits of initial_l3_cut + // 12 bits of initial_l3_offset, offset in 256 bits (8 bytes) granularity. + const uint8_t initial_l3_cut = static_cast(initial_l3 & HAILO8_INITIAL_L3_CUT_MASK); + const uint32_t initial_l3_offset_256 = (initial_l3 & HAILO8_INITIAL_L3_OFFSET_MASK) >> HAILO8_INITIAL_L3_OFFSET_SHIFT; + const uint16_t initial_l3_offset = static_cast(initial_l3_offset_256 << HAILO8_INITIAL_L3_OFFSET_BYTES_GRANULARITY_SHIFT); + return std::make_pair(initial_l3_cut, initial_l3_offset); +} + +static Expected parse_action(const ProtoHEFAction &proto_action, + const SupportedFeatures &supported_features) +{ + switch (proto_action.action_case()) { + case ProtoHEFAction::kWriteDataCcw:\ + { + CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(proto_action.write_data_ccw().cfg_channel_index()), HAILO_INVALID_HEF, + "Invalid cfg channel index"); + const auto config_stream_index = static_cast(proto_action.write_data_ccw().cfg_channel_index()); + + auto data = Buffer::create( + reinterpret_cast(proto_action.write_data_ccw().data().data()), + proto_action.write_data_ccw().data().length()); + CHECK_EXPECTED(data); + + return WriteDataCcwAction::create(data.release(), config_stream_index); + } + case ProtoHEFAction::kDisableLcu: + CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(proto_action.disable_lcu().cluster_index()), HAILO_INVALID_HEF, + "Failed to parse HEF. Invalid cluster_index: {}.", proto_action.disable_lcu().cluster_index()); + CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(proto_action.disable_lcu().lcu_index()), HAILO_INVALID_HEF, + "Failed to parse HEF. Invalid lcu_index: {}", proto_action.disable_lcu().lcu_index()); + return DisableLcuAction::create(static_cast(proto_action.disable_lcu().cluster_index()), + static_cast(proto_action.disable_lcu().lcu_index())); + case ProtoHEFAction::kEnableLcu: + { + CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(proto_action.enable_lcu().cluster_index()), HAILO_INVALID_HEF, + "Failed to parse HEF. Invalid cluster_index: {}.", proto_action.enable_lcu().cluster_index()); + CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(proto_action.enable_lcu().lcu_index()), HAILO_INVALID_HEF, + "Failed to parse HEF. Invalid lcu_index: {}.", proto_action.enable_lcu().lcu_index()); + CHECK_AS_EXPECTED(IS_FIT_IN_UINT16(proto_action.enable_lcu().lcu_kernel_done_address()), HAILO_INVALID_HEF, + "Failed to parse HEF. Invalid lcu_kernel_done_address: {}.", proto_action.enable_lcu().lcu_kernel_done_address()); + + auto support_multi_networks = supported_features.multi_network_support; + auto network_index = static_cast((support_multi_networks) ? proto_action.enable_lcu().network_index() : 0); + + const auto cluster_index = static_cast(proto_action.enable_lcu().cluster_index()); + const auto lcu_index = static_cast(proto_action.enable_lcu().lcu_index()); + const auto kernel_done_address = static_cast(proto_action.enable_lcu().lcu_kernel_done_address()); + const auto kernel_done_count = static_cast(proto_action.enable_lcu().lcu_kernel_done_count()); + + return EnableLcuAction::create(cluster_index, lcu_index, network_index, kernel_done_address, + kernel_done_count); + } + case ProtoHEFAction::kEnableSequencer: + { + CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(proto_action.enable_sequencer().cluster_index()), HAILO_INVALID_HEF, + "Failed to parse HEF. Invalid cluster_index: {}.", proto_action.enable_sequencer().cluster_index()); + + // TODO: Remove when impolemeted in the hef.proto + uint64_t l2_offset_0 = 0; + uint64_t l2_offset_1 = 0; + // TODO: Change the CONTEXT_SWITCH__add_enable_sequencer_proto_action func to receive 4 'l2_offset' params + l2_offset_0 |= (uint64_t)(proto_action.enable_sequencer().l2_write_0()); + l2_offset_0 |= ((uint64_t)(proto_action.enable_sequencer().l2_write_1()) << 32); + l2_offset_1 |= (uint64_t)(proto_action.enable_sequencer().l2_write_2()); + l2_offset_1 |= ((uint64_t)(proto_action.enable_sequencer().l2_write_3()) << 32); + + uint8_t initial_l3_cut = 0; + uint16_t initial_l3_offset = 0; + if (proto_action.enable_sequencer().initial_l3_info().includes_initial_l3_info()) { + const auto &initial_l3_info = proto_action.enable_sequencer().initial_l3_info(); + CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(initial_l3_info.initial_l3_index()), HAILO_INVALID_HEF, + "Initial l3 cut {} is out of range", initial_l3_info.initial_l3_index()); + CHECK_AS_EXPECTED(IS_FIT_IN_UINT16(initial_l3_info.initial_l3_offset()), HAILO_INVALID_HEF, + "Initial l3 offset {} is out of range", initial_l3_info.initial_l3_offset()); + initial_l3_cut = static_cast(initial_l3_info.initial_l3_index()); + initial_l3_offset = static_cast(initial_l3_info.initial_l3_offset()); + } + else { + // Legacy mode should work only on hailo8 + std::tie(initial_l3_cut, initial_l3_offset) = old_hef_parse_initial_l3(proto_action.enable_sequencer().initial_l3_legacy()); + } + + return EnableSequencerAction::create( + static_cast(proto_action.enable_sequencer().cluster_index()), + initial_l3_cut, initial_l3_offset, + proto_action.enable_sequencer().active_apu_bitmap(), + proto_action.enable_sequencer().active_ia_bitmap(), + proto_action.enable_sequencer().active_sc_bitmap(), + proto_action.enable_sequencer().active_l2_bitmap(), + l2_offset_0, + l2_offset_1); + } + case ProtoHEFAction::kNone: + return NoneAction::create(); + + case ProtoHEFAction::kWaitForSeqeuncer: + CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(proto_action.wait_for_seqeuncer().cluster_index()), HAILO_INVALID_HEF, + "Failed to parse HEF. Invalid cluster_index: {}.", proto_action.wait_for_seqeuncer().cluster_index()); + + return WaitForSequencerAction::create( + static_cast(proto_action.wait_for_seqeuncer().cluster_index())); + + case ProtoHEFAction::kAllowInputDataflow: + CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(proto_action.allow_input_dataflow().sys_index()), HAILO_INVALID_HEF, + "Failed to parse HEF. Invalid sys_index: {}.", proto_action.allow_input_dataflow().sys_index()); + return AllowInputDataflowAction::create( + static_cast(proto_action.allow_input_dataflow().sys_index())); + + case ProtoHEFAction::kWaitForModuleConfigDone: + CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(proto_action.wait_for_module_config_done().index()), HAILO_INVALID_HEF, + "Failed to parse HEF. Invalid index: {}", proto_action.wait_for_module_config_done().index()); + return WaitForModuleConfigDoneAction::create( + static_cast(proto_action.wait_for_module_config_done().index())); + + case ProtoHEFAction::kEnableNms: + { + CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(proto_action.enable_nms().nms_unit_index()), HAILO_INVALID_HEF, + "Failed to parse HEF. Invalid nms_unit_index: {}.", proto_action.enable_nms().nms_unit_index()); + CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(proto_action.enable_nms().network_index()), HAILO_INVALID_HEF, + "Failed to parse HEF. Invalid network_index: {}.", proto_action.enable_nms().network_index()); + + auto support_multi_networks = supported_features.multi_network_support; + auto network_index = static_cast((support_multi_networks) ? proto_action.enable_nms().network_index() : 0); + + const auto nms_unit_index = static_cast(proto_action.enable_nms().nms_unit_index()); + + return EnableNmsAction::create(network_index, nms_unit_index); + } + + default: + LOGGER__ERROR("Action {} not implemented", proto_action.action_case()); + break; + } + + // Default case + return make_unexpected(HAILO_INTERNAL_FAILURE); +} + +static Expected parse_operation(const ProtoHEFOperation &operation_proto, + const SupportedFeatures &supported_features) +{ + std::vector actions; + actions.reserve(operation_proto.actions_size() + 1); // +1 for the trigger action + + auto trigger_action = parse_trigger_action(operation_proto.trigger()); + CHECK_EXPECTED(trigger_action); + actions.emplace_back(trigger_action.release()); + + actions.reserve(operation_proto.actions_size()); + for (const auto &proto_action : operation_proto.actions()) { + auto action = parse_action(proto_action, supported_features); + CHECK_EXPECTED(action); + actions.emplace_back(action.release()); + } + + return ContextSwitchOperation(std::move(actions)); +} + +static Expected> parse_operations( + const google::protobuf::RepeatedPtrField &operations_proto, + const SupportedFeatures &supported_features) +{ + CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(operations_proto.size()), HAILO_INVALID_HEF, + "Failed to parse HEF. Invalid operations_count: {}.", operations_proto.size()); + std::vector operations; + operations.reserve(operations_proto.size()); + for (const auto &operation_proto : operations_proto) { + auto operation = parse_operation(operation_proto, supported_features); + CHECK_EXPECTED(operation); + operations.emplace_back(operation.release()); + } + return operations; +} + +static hailo_status update_parsing_info(uint8_t cfg_index, uint32_t data_length, ConfigBufferInfoMap &results) +{ + CHECK(cfg_index < CONTROL_PROTOCOL__MAX_CFG_CHANNELS, HAILO_INVALID_HEF, "Invalid cfg_index"); + + if (contains(results, cfg_index)) { + results.at(cfg_index).push_back(data_length); + return HAILO_SUCCESS; + } + + // If we got here, the current cfg_index's info is parsed for the first time + results.emplace(cfg_index, std::vector(1, data_length)); + return HAILO_SUCCESS; +} + +static Expected get_config_buffer_info( + const google::protobuf::RepeatedPtrField &operations) +{ + auto status = HAILO_UNINITIALIZED; + ConfigBufferInfoMap results; + + for (const auto &operation : operations) { + for (const auto &action : operation.actions()) { + if (ProtoHEFAction::kWriteDataCcw == action.action_case()) { + CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(action.write_data_ccw().cfg_channel_index()), HAILO_INVALID_HEF, + "Invalid cfg index {}", action.write_data_ccw().cfg_channel_index()); + status = update_parsing_info(static_cast(action.write_data_ccw().cfg_channel_index()), + static_cast(action.write_data_ccw().data().length()), results); + CHECK_SUCCESS_AS_EXPECTED(status); } } + } + return results; +} + +Expected HefUtils::parse_preliminary_context(const ProtoHEFPreliminaryConfig &preliminary_proto, + const SupportedFeatures &supported_features) +{ + auto operations = parse_operations(preliminary_proto.operation(), supported_features); + CHECK_EXPECTED(operations); + + auto config_buffer_infos = get_config_buffer_info(preliminary_proto.operation()); + CHECK_EXPECTED(config_buffer_infos); + + return PreliminaryContextMetadata(operations.release(), config_buffer_infos.release()); +} + +Expected HefUtils::parse_single_dynamic_context(const ProtoHEFCoreOpMock &core_op, + const ProtoHEFContext &context_proto, uint8_t context_index, const SupportedFeatures &supported_features) +{ + auto operations = parse_operations(context_proto.operations(), supported_features); + CHECK_EXPECTED(operations); + + auto config_buffer_infos = get_config_buffer_info(context_proto.operations()); + CHECK_EXPECTED(config_buffer_infos); + + ContextMetadata context_metadata(operations.release(), config_buffer_infos.release()); + + for (const auto &edge_layer : context_proto.metadata().edge_layers()) { + if (ProtoHEFEdgeConnectionType::PROTO__EDGE_CONNECTION_TYPE__BOUNDARY == + edge_layer.context_switch_info().edge_connection_type()) { + auto status = fill_boundary_layers_info(core_op, context_index, edge_layer, + supported_features, context_metadata); + CHECK_SUCCESS_AS_EXPECTED(status); + } else if (ProtoHEFEdgeConnectionType::PROTO__EDGE_CONNECTION_TYPE__INTERMEDIATE == + edge_layer.context_switch_info().edge_connection_type()) { + auto status = fill_inter_context_layers_info(core_op, context_index, edge_layer, + supported_features, context_metadata); + CHECK_SUCCESS_AS_EXPECTED(status); + } else if (ProtoHEFEdgeConnectionType::PROTO__EDGE_CONNECTION_TYPE__DDR == + edge_layer.context_switch_info().edge_connection_type()) { + auto status = fill_ddr_layers_info(core_op, context_index, edge_layer, + supported_features, context_metadata); + CHECK_SUCCESS_AS_EXPECTED(status); + } + } + + auto status = check_ddr_pairs_match(context_metadata.get_ddr_input_layers(), context_metadata.get_ddr_output_layers(), + context_index); + CHECK_SUCCESS_AS_EXPECTED(status); + + + return context_metadata; +} + +static hailo_status validate_unique_boundary_names(const std::vector &contexts_metadata) +{ + std::unordered_set names; + for (const auto &context_metadata : contexts_metadata) { + for (const auto &layer_info : context_metadata.get_boundary_input_layers()) { + CHECK(names.find(layer_info.name) == names.end(), HAILO_INVALID_HEF, + "Layer name should be unique. name '{}' appears more than once", layer_info.name); + names.insert(layer_info.name); + } - auto status = check_ddr_pairs_match(context_ddr_input_layers, context_ddr_output_layers, context_index); - CHECK_SUCCESS(status); - - // Finished parsing all context's edge layer. Add results to output params - boundary_input_layers.emplace_back(std::move(context_boundary_input_layers)); - boundary_output_layers.emplace_back(std::move(context_boundary_output_layers)); - inter_context_input_layers.emplace_back(std::move(context_inter_context_input_layers)); - inter_context_output_layers.emplace_back(std::move(context_inter_context_output_layers)); - ddr_input_layers.emplace_back(std::move(context_ddr_input_layers)); - ddr_output_layers.emplace_back(std::move(context_ddr_output_layers)); + for (const auto &layer_info : context_metadata.get_boundary_output_layers()) { + CHECK(names.find(layer_info.name) == names.end(), HAILO_INVALID_HEF, + "Layer name should be unique. name '{}' appears more than once", layer_info.name); + names.insert(layer_info.name); + } } return HAILO_SUCCESS; } +Expected> HefUtils::parse_dynamic_contexts(const ProtoHEFCoreOpMock &core_op, const SupportedFeatures &supported_features) +{ + std::vector contexts_metadata; + for (uint8_t context_index = 0; context_index < core_op.contexts.size(); context_index++) { + auto &context_proto = core_op.contexts[context_index]; + auto context_metadata = parse_single_dynamic_context(core_op, context_proto, context_index, supported_features); + CHECK_EXPECTED(context_metadata); + contexts_metadata.emplace_back(context_metadata.release()); + } + + const auto status = validate_unique_boundary_names(contexts_metadata); + CHECK_SUCCESS_AS_EXPECTED(status); + + return contexts_metadata; +} + Expected HefUtils::parse_proto_nms_info(const ProtoHEFNmsInfo &proto_nms_info) { hailo_nms_info_t nms_info = {}; @@ -1390,8 +1933,8 @@ Expected HefUtils::parse_proto_nms_info(const ProtoHEFNmsInfo return nms_info; } -Expected HefUtils::get_boundary_layer_info(const ProtoHEFNetworkGroup &net_group, const uint8_t context_index, - const ProtoHEFEdgeLayer &layer, const NetworkGroupSupportedFeatures &supported_features) +Expected HefUtils::get_boundary_layer_info(const ProtoHEFCoreOpMock &core_op, + const uint8_t context_index, const ProtoHEFEdgeLayer &layer, const SupportedFeatures &supported_features) { // We parse only boundary layers for user usage CHECK_AS_EXPECTED( @@ -1404,18 +1947,18 @@ Expected HefUtils::get_boundary_layer_info(const ProtoHEFNetworkGroup HAILO_D2H_STREAM : HAILO_H2D_STREAM; auto support_multi_networks = supported_features.multi_network_support; auto network_index = static_cast((support_multi_networks) ? layer.network_index() : 0); - auto partial_network_name = HefUtils::get_partial_network_name_by_index(net_group, network_index, supported_features); + auto partial_network_name = HefUtils::get_partial_network_name_by_index(core_op, network_index, supported_features); CHECK_EXPECTED(partial_network_name); const bool hw_padding_supported = HefConfigurator::is_hw_padding_supported(layer); if (ProtoHEFEdgeLayerType::PROTO__EDGE_LAYER_TYPE__INFO == layer.edge_layer_type()) { // TODO: return LayerInfo auto status = fill_layer_info(layer.layer_info(), layer.context_switch_info().edge_connection_type(), - net_group, direction, hw_padding_supported, context_index, partial_network_name.value(), network_index, result); + core_op, direction, hw_padding_supported, context_index, partial_network_name.value(), network_index, result); CHECK_SUCCESS_AS_EXPECTED(status); } else if (ProtoHEFEdgeLayerType::PROTO__EDGE_LAYER_TYPE__MUX == layer.edge_layer_type()) { // TODO: return LayerInfo auto status = fill_mux_info(layer.layer_mux(), layer.context_switch_info().edge_connection_type(), - net_group, direction, hw_padding_supported, context_index, partial_network_name.value(), network_index, result); + core_op, direction, hw_padding_supported, context_index, partial_network_name.value(), network_index, result); CHECK_SUCCESS_AS_EXPECTED(status); } else { LOGGER__ERROR("Invalid layer type"); @@ -1425,20 +1968,42 @@ Expected HefUtils::get_boundary_layer_info(const ProtoHEFNetworkGroup result.direction = (ProtoHEFEdgeLayerDirection::PROTO__EDGE_LAYER_DIRECTION__DEVICE_TO_HOST == layer.direction()) ? HAILO_D2H_STREAM : HAILO_H2D_STREAM; + if (layer.has_pad_index()) { + result.pad_index = layer.pad_index(); + } + return result; } -Expected HefUtils::get_inter_context_layer_info(const ProtoHEFNetworkGroup &net_group, const uint8_t context_index, - const ProtoHEFEdgeLayer &layer, const NetworkGroupSupportedFeatures &supported_features) +static Expected parse_connected_context_info( + const ProtoHEFConnectedContextInfo &connected_context_proto) +{ + CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(connected_context_proto.sys_index()), HAILO_INVALID_HEF, + "Failed to parse HEF. Invalid connected_sys_index: {}.", connected_context_proto.sys_index()); + CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(connected_context_proto.engine_id()), HAILO_INVALID_HEF, + "Failed to parse HEF. Invalid engine_id: {}. in connected_contexts", connected_context_proto.engine_id()); + CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(connected_context_proto.index()), HAILO_INVALID_HEF, + "Failed to parse HEF. Invalid connected_context_index: {}.", connected_context_proto.index()); + + ConnectedContextInfo connected_context{}; + connected_context.context_index = static_cast(connected_context_proto.index()); + connected_context.stream_index = static_cast(connected_context_proto.sys_index()); + connected_context.dma_engine_index = static_cast(connected_context_proto.engine_id()); + return connected_context; +} + +Expected HefUtils::get_inter_context_layer_info(const ProtoHEFCoreOpMock &core_op, + const uint8_t context_index, const ProtoHEFEdgeLayer &layer, const SupportedFeatures &supported_features) { - InterContextLayerInfo result = {}; + LayerInfo result = {}; CHECK_AS_EXPECTED(PROTO__EDGE_LAYER_TYPE__INFO == layer.edge_layer_type(), HAILO_INVALID_HEF, "Inter-context layer can't be mux."); + result.type = LayerType::INTER_CONTEXT; auto support_multi_networks = supported_features.multi_network_support; result.network_index = static_cast((support_multi_networks) ? layer.network_index() : 0); - auto partial_network_name = HefUtils::get_partial_network_name_by_index(net_group, result.network_index, supported_features); + auto partial_network_name = HefUtils::get_partial_network_name_by_index(core_op, result.network_index, supported_features); CHECK_EXPECTED(partial_network_name); - result.network_name = HefUtils::get_network_name(net_group, partial_network_name.release()); + result.network_name = HefUtils::get_network_name(core_op, partial_network_name.release()); result.context_index = context_index; const bool hw_padding_supported = HefConfigurator::is_hw_padding_supported(layer); result.name = layer.layer_info().name(); @@ -1455,39 +2020,32 @@ Expected HefUtils::get_inter_context_layer_info(const Pro result.max_shmifo_size = layer.layer_info().edge_layer_base().max_shmifo_size(); - CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(layer.context_switch_info().connected_sys_index()), HAILO_INVALID_HEF, - "Failed to parse HEF. Invalid connected_sys_index: {}.", layer.context_switch_info().connected_sys_index()); - CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(layer.context_switch_info().connected_context_index()), HAILO_INVALID_HEF, - "Failed to parse HEF. Invalid connected_context_index: {}.", layer.context_switch_info().connected_context_index()); result.direction = (ProtoHEFEdgeLayerDirection::PROTO__EDGE_LAYER_DIRECTION__DEVICE_TO_HOST == layer.direction()) ? HAILO_D2H_STREAM : HAILO_H2D_STREAM; - if ((ProtoHEFEdgeLayerDirection::PROTO__EDGE_LAYER_DIRECTION__HOST_TO_DEVICE == layer.direction())) { - result.src_stream_index = static_cast(layer.context_switch_info().connected_sys_index()); - result.src_context_index = static_cast(layer.context_switch_info().connected_context_index()); - result.dst_stream_index = result.stream_index; - result.dst_context_index = result.context_index; - } else { - result.src_stream_index = result.stream_index; - result.src_context_index = result.context_index; - // HRT-7201 - The system supports one src and multiple dstinations. Right now we're saving only one dstination - result.dst_stream_index = static_cast(layer.context_switch_info().connected_sys_index()); - result.dst_context_index = static_cast(layer.context_switch_info().connected_context_index()); - } - - return result; + + // HRT-7201 - The system supports one src and multiple dstinations. Right now we're saving only one dstination + CHECK_AS_EXPECTED(layer.context_switch_info().connected_contexts_size() >= 1, HAILO_INVALID_HEF, + "Inter context layer info must contain connected_context"); + auto connected_context = parse_connected_context_info(layer.context_switch_info().connected_contexts(0)); + CHECK_EXPECTED(connected_context); + result.connected_context_info = connected_context.release(); + + return result; } -Expected HefUtils::get_ddr_layer_info(const ProtoHEFNetworkGroup &net_group, const uint8_t context_index, - const ProtoHEFEdgeLayer &layer, const NetworkGroupSupportedFeatures &supported_features) +Expected HefUtils::get_ddr_layer_info(const ProtoHEFCoreOpMock &core_op, + const uint8_t context_index, const ProtoHEFEdgeLayer &layer, const SupportedFeatures &supported_features) { - DdrLayerInfo result = {}; + LayerInfo result = {}; CHECK_AS_EXPECTED(PROTO__EDGE_LAYER_TYPE__INFO == layer.edge_layer_type(), HAILO_INVALID_HEF, "DDR layer can't be mux."); + result.type = LayerType::DDR; + auto support_multi_networks = supported_features.multi_network_support; result.network_index = static_cast((support_multi_networks) ? layer.network_index() : 0); - auto partial_network_name = HefUtils::get_partial_network_name_by_index(net_group, result.network_index, supported_features); - CHECK_EXPECTED(partial_network_name); - result.network_name = HefUtils::get_network_name(net_group, partial_network_name.release()); + auto partial_network_name = HefUtils::get_partial_network_name_by_index(core_op, result.network_index, supported_features); + CHECK_EXPECTED(partial_network_name); + result.network_name = HefUtils::get_network_name(core_op, partial_network_name.release()); result.context_index = context_index; const bool hw_padding_supported = HefConfigurator::is_hw_padding_supported(layer); result.name = layer.layer_info().name(); @@ -1500,60 +2058,44 @@ Expected HefUtils::get_ddr_layer_info(const ProtoHEFNetworkGroup & result.stream_index = static_cast(layer.layer_info().edge_layer_base().sys_index()); CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(layer.layer_info().edge_layer_base().engine_id()), HAILO_INVALID_HEF, "Failed to parse HEF. Invalid engine_id: {}.", layer.layer_info().edge_layer_base().engine_id()); + result.dma_engine_index = static_cast(layer.layer_info().edge_layer_base().engine_id()); result.max_shmifo_size = layer.layer_info().edge_layer_base().max_shmifo_size(); - CHECK_AS_EXPECTED(IS_FIT_IN_UINT16(layer.layer_info().edge_layer_base().core_buffers_per_frame()), HAILO_INVALID_HEF, - "Failed to parse HEF. Invalid core_buffers_per_frame: {}.", layer.layer_info().edge_layer_base().core_buffers_per_frame()); - result.total_buffers_per_frame = static_cast(layer.layer_info().edge_layer_base().core_buffers_per_frame()); CHECK_AS_EXPECTED(layer.context_switch_info().connected_contexts_size() == 1, HAILO_INVALID_HEF, "Only single connected context is supported on DDR channels"); - const auto& connected_context = layer.context_switch_info().connected_contexts(0); - CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(layer.context_switch_info().connected_sys_index()), HAILO_INVALID_HEF, - "Failed to parse HEF. Invalid connected_sys_index: {}.", layer.context_switch_info().connected_sys_index()); - CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(connected_context.engine_id()), HAILO_INVALID_HEF, - "Failed to parse HEF. Invalid engine_id: {}. in connected_contexts", connected_context.engine_id()); - CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(layer.context_switch_info().connected_context_index()), HAILO_INVALID_HEF, - "Failed to parse HEF. Invalid connected_context_index: {}.", layer.context_switch_info().connected_context_index()); + auto connected_context = parse_connected_context_info(layer.context_switch_info().connected_contexts(0)); + CHECK_EXPECTED(connected_context); + CHECK_AS_EXPECTED(context_index == connected_context->context_index, + HAILO_INVALID_HEF, "for ddr layer, connected_context_index must be same to the edge layer's context"); + result.connected_context_info = connected_context.release(); + result.direction = (ProtoHEFEdgeLayerDirection::PROTO__EDGE_LAYER_DIRECTION__DEVICE_TO_HOST == layer.direction()) ? HAILO_D2H_STREAM : HAILO_H2D_STREAM; - CHECK_AS_EXPECTED(context_index == static_cast(layer.context_switch_info().connected_context_index()), - HAILO_INVALID_HEF, "for ddr layer, connected_context_index must be same to the edge layer's context"); - if ((ProtoHEFEdgeLayerDirection::PROTO__EDGE_LAYER_DIRECTION__HOST_TO_DEVICE == layer.direction())) { - result.src_stream_index = static_cast(layer.context_switch_info().connected_sys_index()); - result.src_dma_engine_index = static_cast(connected_context.engine_id()); - result.src_context_index = static_cast(layer.context_switch_info().connected_context_index()); - result.dst_stream_index = result.stream_index; - result.dst_dma_engine_index = static_cast(layer.layer_info().edge_layer_base().engine_id()); - result.dst_context_index = result.context_index; - } else { - result.src_stream_index = result.stream_index; - result.src_dma_engine_index = static_cast(layer.layer_info().edge_layer_base().engine_id()); - result.src_context_index = result.context_index; - result.dst_stream_index = static_cast(layer.context_switch_info().connected_sys_index()); - result.dst_dma_engine_index = static_cast(connected_context.engine_id()); - result.dst_context_index = static_cast(layer.context_switch_info().connected_context_index()); - } + + CHECK_AS_EXPECTED(IS_FIT_IN_UINT16(layer.layer_info().edge_layer_base().core_buffers_per_frame()), HAILO_INVALID_HEF, + "Failed to parse HEF. Invalid core_buffers_per_frame: {}.", layer.layer_info().edge_layer_base().core_buffers_per_frame()); + result.ddr_info.total_buffers_per_frame = static_cast(layer.layer_info().edge_layer_base().core_buffers_per_frame()); CHECK_AS_EXPECTED(IS_FIT_IN_UINT16(layer.context_switch_info().buffers()), HAILO_INVALID_HEF, "calculated number of transfers for DDR buffer is out of UINT16_T range"); - result.min_buffered_rows = static_cast(layer.context_switch_info().buffers()); - + result.ddr_info.min_buffered_rows = static_cast(layer.context_switch_info().buffers()); + return result; } -Expected> HefUtils::get_sorted_output_names(const ProtoHEFNetworkGroup &net_group) +Expected> HefUtils::get_sorted_output_names(const ProtoHEFCoreOpMock &core_op) { - if (net_group.fused_layers_metadata().network_has_fused_layers()) { - return std::vector(std::begin(net_group.fused_layers_metadata().updated_sorted_output_names()), - std::end(net_group.fused_layers_metadata().updated_sorted_output_names())); - } else if (0 != net_group.sorted_outputs_order_size()) { + if (core_op.fused_layers_metadata.network_has_fused_layers()) { + return std::vector(std::begin(core_op.fused_layers_metadata.updated_sorted_output_names()), + std::end(core_op.fused_layers_metadata.updated_sorted_output_names())); + } else if (0 != core_op.sorted_outputs_order.size()) { // For backwards compatibility before we've added updated_sorted_output_names - return std::vector(std::begin(net_group.sorted_outputs_order()), - std::end(net_group.sorted_outputs_order())); + return std::vector(std::begin(core_op.sorted_outputs_order), + std::end(core_op.sorted_outputs_order)); } else { // For backwards compatibility before we've added this field - uint32_t number_of_contexts = net_group.contexts_size(); - const auto& context_metadata = net_group.contexts(number_of_contexts - 1).metadata(); + uint32_t number_of_contexts = core_op.contexts.size(); + const auto& context_metadata = core_op.contexts[number_of_contexts - 1].metadata(); CHECK_AS_EXPECTED(0 < context_metadata.sorted_outputs_order_size(), HAILO_INVALID_HEF, "Sorted output names is not set up in the HEF."); @@ -1563,869 +2105,119 @@ Expected> HefUtils::get_sorted_output_names(const Proto } } -/* VdmaConfigNetworkGroup funcs */ - -inline std::pair old_hef_parse_initial_l3(uint32_t initial_l3) -{ - // parse initial l3 as written in hailo8 initial_l3 format - - // 7 bits of initial_l3_cut - // 12 bits of initial_l3_offset, offset in 256 bits (8 bytes) granularity. - const uint8_t initial_l3_cut = static_cast(initial_l3 & HAILO8_INITIAL_L3_CUT_MASK); - const uint32_t initial_l3_offset_256 = (initial_l3 & HAILO8_INITIAL_L3_OFFSET_MASK) >> HAILO8_INITIAL_L3_OFFSET_SHIFT; - const uint16_t initial_l3_offset = static_cast(initial_l3_offset_256 << HAILO8_INITIAL_L3_OFFSET_BYTES_GRANULARITY_SHIFT); - return std::make_pair(initial_l3_cut, initial_l3_offset); -} - -static hailo_status fill_boundary_input_layer(CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **context_meta_data_head_pointer, ResourcesManager &resources_manager, const LayerInfo layer_info) -{ - const auto channel_id = resources_manager.get_available_channel_id(to_layer_identifier(layer_info), - VdmaChannel::Direction::H2D, layer_info.dma_engine_index); - CHECK_EXPECTED_AS_STATUS(channel_id); - - const auto frame_credits_in_bytes = (layer_info.nn_stream_config.periph_bytes_per_buffer * - layer_info.nn_stream_config.core_buffers_per_frame); - - auto vdma_channel = resources_manager.create_boundary_vdma_channel(channel_id.value(), frame_credits_in_bytes, - layer_info.network_name, layer_info.name, VdmaChannel::Direction::H2D); - CHECK_EXPECTED_AS_STATUS(vdma_channel); - auto buffer_info = vdma_channel.value()->get_boundary_buffer_info(frame_credits_in_bytes); - CHECK_EXPECTED_AS_STATUS(buffer_info); - - LOGGER__DEBUG("Boundary input stream: {} h2d_channel: {}.", layer_info.stream_index, channel_id.value()); - - /* Update metadata */ - auto status = HEF_METADATA__add_network_boundary_input_edge_layer(context_info, - context_meta_data_head_pointer, channel_id.value(), layer_info.stream_index, layer_info.network_index, - layer_info.nn_stream_config, buffer_info.value(), layer_info.max_shmifo_size); - CHECK_SUCCESS(status); - - return HAILO_SUCCESS; -} - -static hailo_status fill_inter_context_input_layer(CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **context_meta_data_head_pointer, ResourcesManager &resources_manager, const InterContextLayerInfo &layer_info) -{ - const auto channel_id = resources_manager.get_available_channel_id(to_layer_identifier(layer_info), - VdmaChannel::Direction::H2D, layer_info.dma_engine_index); - CHECK_EXPECTED_AS_STATUS(channel_id); - - /* Get inter context buffer previously created */ - auto intermediate_buffer_key = std::make_pair(layer_info.src_context_index, layer_info.src_stream_index); - auto inter_context_buffer_exp = resources_manager.get_inter_context_buffer(intermediate_buffer_key); - CHECK_EXPECTED_AS_STATUS(inter_context_buffer_exp, "Failed to find inter context buffer for src context {}, src_stream_index {}", - layer_info.src_context_index, layer_info.src_stream_index); - auto &inter_context_buffer = inter_context_buffer_exp->get(); - - LOGGER__DEBUG("Intermediate input stream {}, src_context:{}, dst_context: {}, h2d_channel {}.", - layer_info.stream_index, layer_info.src_context_index, layer_info.dst_context_index, channel_id.value()); - - /* Update metadata */ - return HEF_METADATA__add_inter_context_input_edge_layer(context_info, context_meta_data_head_pointer, - channel_id.value(), layer_info.stream_index, layer_info.network_index, layer_info.nn_stream_config, - inter_context_buffer.get_host_buffer_info(), layer_info.max_shmifo_size); -} - -static hailo_status fill_boundary_output_layer(CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **context_meta_data_head_pointer, ResourcesManager &resources_manager, const LayerInfo &layer_info) -{ - const auto channel_id = resources_manager.get_available_channel_id(to_layer_identifier(layer_info), - VdmaChannel::Direction::D2H, layer_info.dma_engine_index); - CHECK_EXPECTED_AS_STATUS(channel_id); - - const auto frame_credits_in_bytes = (layer_info.nn_stream_config.periph_bytes_per_buffer * - layer_info.nn_stream_config.core_buffers_per_frame); - - auto vdma_channel = resources_manager.create_boundary_vdma_channel(channel_id.value(), frame_credits_in_bytes, - layer_info.network_name, layer_info.name, VdmaChannel::Direction::D2H); - CHECK_EXPECTED_AS_STATUS(vdma_channel); - auto buffer_info = vdma_channel.value()->get_boundary_buffer_info(frame_credits_in_bytes); - CHECK_EXPECTED_AS_STATUS(buffer_info); - - LOGGER__DEBUG("Boundary output stream: {} d2h_channel: {}.", layer_info.stream_index, channel_id.value()); - - /* Update metadata */ - auto status = HEF_METADATA__add_network_boundary_output_edge_layer(context_info, - context_meta_data_head_pointer, channel_id.value(), layer_info.stream_index, layer_info.network_index, - layer_info.nn_stream_config, buffer_info.value()); - CHECK_SUCCESS(status); - - return HAILO_SUCCESS; -} - -static hailo_status fill_inter_context_output_layer(CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **context_meta_data_head_pointer, ResourcesManager &resources_manager, const InterContextLayerInfo &layer_info) -{ - const auto channel_id = resources_manager.get_available_channel_id(to_layer_identifier(layer_info), - VdmaChannel::Direction::D2H, layer_info.dma_engine_index); - CHECK_EXPECTED_AS_STATUS(channel_id); - - const auto frame_credits_in_bytes = (layer_info.nn_stream_config.periph_bytes_per_buffer * - layer_info.nn_stream_config.core_buffers_per_frame); - - auto inter_context_buffer_exp = resources_manager.create_inter_context_buffer(frame_credits_in_bytes, - layer_info.stream_index, layer_info.src_context_index, layer_info.network_name); - CHECK_EXPECTED_AS_STATUS(inter_context_buffer_exp); - auto &inter_context_buffer = inter_context_buffer_exp->get(); - - LOGGER__DEBUG("Inter-context output stream {}, src_context:{}, d2h_channel {}.", - layer_info.stream_index, layer_info.src_context_index, channel_id.value()); - - /* Update metadata */ - auto status = HEF_METADATA__add_inter_context_output_edge_layer(context_info, context_meta_data_head_pointer, - channel_id.value(), layer_info.stream_index, layer_info.network_index, layer_info.nn_stream_config, - inter_context_buffer.get_host_buffer_info()); - CHECK_SUCCESS(status); - - return HAILO_SUCCESS; -} - -static hailo_status fill_ddr_output_layer(CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **context_meta_data_head_pointer, ResourcesManager &resources_manager, const DdrLayerInfo &layer_info) -{ - CHECK(resources_manager.get_supported_features().padded_ddr_buffers, HAILO_INVALID_HEF, - "Failed opening non-compatible HEF that uses the following deprecated features: host-managed DDR buffers." - "Please re-compile the HEF using a newer Dataflow Compiler version (v3.11.0 or newer)"); - // Allocate resources and prepare ddr_info - - DdrChannelsInfo ddr_pair_info = {}; - ddr_pair_info.h2d_stream_index = layer_info.dst_stream_index; - ddr_pair_info.d2h_stream_index = layer_info.src_stream_index; - - // It is assumed that output channels are parsed before input channels. - // Allocate vdma channel index for both edges - const LayerIdentifier h2d_layer_identifier = to_layer_identifier(layer_info, VdmaChannel::Direction::H2D); - const auto h2d_channel_id = resources_manager.get_available_channel_id(h2d_layer_identifier, - VdmaChannel::Direction::H2D, layer_info.src_dma_engine_index); - CHECK_EXPECTED_AS_STATUS(h2d_channel_id); - ddr_pair_info.h2d_channel_id = h2d_channel_id.value(); - - const LayerIdentifier d2h_layer_identifier = to_layer_identifier(layer_info, VdmaChannel::Direction::D2H); - const auto d2h_channel_id = resources_manager.get_available_channel_id(d2h_layer_identifier, - VdmaChannel::Direction::D2H, layer_info.dst_context_index); - CHECK_EXPECTED_AS_STATUS(d2h_channel_id); - ddr_pair_info.d2h_channel_id = d2h_channel_id.value(); - - ddr_pair_info.row_size = layer_info.nn_stream_config.core_bytes_per_buffer; - ddr_pair_info.min_buffered_rows = layer_info.min_buffered_rows; - ddr_pair_info.total_buffers_per_frame = layer_info.total_buffers_per_frame; - - // Create the ddr buffer - auto ddr_channels_pair = resources_manager.create_ddr_channels_pair(ddr_pair_info, layer_info.context_index); - CHECK_EXPECTED_AS_STATUS(ddr_channels_pair); - - return HEF_METADATA__add_ddr_buffer_output_edge_layer(context_info, - context_meta_data_head_pointer, d2h_channel_id.value(), layer_info.stream_index, - layer_info.network_index, layer_info.nn_stream_config, ddr_channels_pair->get().get_host_buffer_info(), - layer_info.min_buffered_rows); -} - -static hailo_status fill_ddr_input_layer(CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **context_meta_data_head_pointer, ResourcesManager &resources_manager, const DdrLayerInfo &layer_info) -{ - auto ddr_channels_pair = resources_manager.get_ddr_channels_pair(layer_info.context_index, layer_info.src_stream_index); - CHECK(ddr_channels_pair, HAILO_INVALID_HEF, "Mathing DDR layer as not found for context {} src stream {}", - layer_info.context_index, layer_info.src_stream_index); - - const auto ddr_info = ddr_channels_pair->get().info(); - LOGGER__DEBUG("DDR layer: input stream_index: {}, output stream_index: {}, h2d_channel {}, d2h_channel: {}.", - ddr_info.h2d_stream_index, ddr_info.d2h_stream_index, ddr_info.h2d_channel_id, ddr_info.d2h_channel_id); - - CHECK(layer_info.dst_stream_index == ddr_info.h2d_stream_index, HAILO_INVALID_HEF, "DDR channel pair mismatch in h2d channel"); - CHECK(layer_info.src_stream_index == ddr_info.d2h_stream_index, HAILO_INVALID_HEF, "DDR channel pair mismatch in d2h channel"); - - return HEF_METADATA__add_ddr_buffer_input_edge_layer(context_info, - context_meta_data_head_pointer, ddr_info.h2d_channel_id, ddr_info.h2d_stream_index, layer_info.network_index, - layer_info.nn_stream_config, ddr_channels_pair->get().get_host_buffer_info(), layer_info.max_shmifo_size, - ddr_info.d2h_channel_id); -} - -Expected HefUtils::get_partial_network_name_by_index(const ProtoHEFNetworkGroup &network_group_proto, uint8_t network_index, - const NetworkGroupSupportedFeatures &supported_features) +Expected HefUtils::get_partial_network_name_by_index(const ProtoHEFCoreOpMock &core_op, uint8_t network_index, + const SupportedFeatures &supported_features) { if (supported_features.multi_network_support) { - CHECK_AS_EXPECTED(network_index < network_group_proto.networks_names_size(), HAILO_INVALID_ARGUMENT, + CHECK_AS_EXPECTED(network_index < core_op.networks_names.size(), HAILO_INVALID_ARGUMENT, "Requested name for network_index={}, however there are only {} networks in the network group", - network_index, network_group_proto.networks_names_size()); - return std::string(network_group_proto.networks_names(network_index)); + network_index, core_op.networks_names.size()); + return std::string(core_op.networks_names[network_index]); } else { - auto partial_network_name = network_group_proto.network_group_metadata().network_group_name(); + auto partial_network_name = core_op.network_group_metadata.network_group_name(); return partial_network_name; } } -std::string HefUtils::get_network_name(const std::string &net_group_name, const std::string &partial_network_name) -{ - return net_group_name + HAILO_DEFAULT_NETWORK_NAME_QUALIFIER + partial_network_name; -} - -std::string HefUtils::get_network_name(const ProtoHEFNetworkGroup &net_group, const std::string &partial_network_name) -{ - return HefUtils::get_network_name(net_group.network_group_metadata().network_group_name(), partial_network_name); -} - -static hailo_status add_ddr_buffers_info(std::vector &configuration_actions, - const ResourcesManager &resources_manager, uint8_t context_index) +std::string HefUtils::get_network_group_name(const ProtoHEFNetworkGroup &net_group, const SupportedFeatures &/*supported_features*/) { - bool start_fw_ddr_buffer_task = false; - for (auto& ddr_channels_pair : resources_manager.get_ddr_channel_pairs_per_context(context_index)) { - if (ddr_channels_pair.get().need_manual_credit_management()) { - const auto ddr_info = ddr_channels_pair.get().info(); - auto ddr_pair_action = DdrPairInfoAction::create(ddr_info.h2d_channel_id, ddr_info.d2h_channel_id, - ddr_channels_pair.get().descriptors_per_frame(), ddr_channels_pair.get().descs_count()); - CHECK_EXPECTED_AS_STATUS(ddr_pair_action); - configuration_actions.emplace_back(ddr_pair_action.release()); - - start_fw_ddr_buffer_task = true; - } + if (!net_group.partial_network_groups().empty()) { + return net_group.partial_network_groups(0).network_group().network_group_metadata().network_group_name(); } - - if (start_fw_ddr_buffer_task) { - auto start_ddr_buffering_action = StartDdrBufferingTaskAction::create(); - CHECK_EXPECTED_AS_STATUS(start_ddr_buffering_action); - configuration_actions.emplace_back(start_ddr_buffering_action.release()); - } - - return HAILO_SUCCESS; + return net_group.network_group_metadata().network_group_name(); } -static hailo_status parse_and_fill_edge_layers_mapping( - CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **context_meta_data_head_pointer, const ProtoHEFContextMetadata *context_metadata, - ResourcesManager &resources_manager, std::shared_ptr network_group_metadata, - uint8_t context_index) +std::string HefUtils::get_network_name(const std::string &net_group_name, const std::string &partial_network_name) { - hailo_status status = HAILO_UNINITIALIZED; - - const auto number_of_edge_layers = context_metadata->edge_layers_size(); - CHECK(0 < number_of_edge_layers, HAILO_INVALID_HEF, "No edge layers in this context"); - CHECK(IS_FIT_IN_UINT8(number_of_edge_layers), HAILO_INVALID_HEF, - "Failed to parse HEF. Invalid edge_layers_size: {}.", number_of_edge_layers); - - auto boundary_output_layers = network_group_metadata->get_boundary_output_layer_infos(context_index); - auto boundary_input_layers = network_group_metadata->get_boundary_input_layer_infos(context_index); - auto inter_context_output_layers = network_group_metadata->get_inter_context_output_layer_infos(context_index); - auto inter_context_input_layers = network_group_metadata->get_inter_context_input_layer_infos(context_index); - auto ddr_output_layers = network_group_metadata->get_ddr_output_layer_infos(context_index); - auto ddr_input_layers = network_group_metadata->get_ddr_input_layer_infos(context_index); - - // Parse the edge layer by order - first output edge layers, then ddr inputs and only then the input edge layers - // In order to insure that input data can enter the chip only after all other elements are configured. - // We parse ddr inputs before boundary/inter-context because otherwise on C2C mode we may lose some credit. - - for (const auto &output_layer_info : ddr_output_layers) { - status = fill_ddr_output_layer(context_info, context_meta_data_head_pointer, - resources_manager, output_layer_info); - CHECK_SUCCESS(status); - } - - for (const auto &output_layer_info : boundary_output_layers) { - status = fill_boundary_output_layer(context_info, context_meta_data_head_pointer, - resources_manager, output_layer_info); - CHECK_SUCCESS(status); - } - - for (const auto &output_layer_info : inter_context_output_layers) { - status = fill_inter_context_output_layer(context_info, context_meta_data_head_pointer, - resources_manager, output_layer_info); - CHECK_SUCCESS(status); - } - - for (const auto &input_layer_info : ddr_input_layers) { - status = fill_ddr_input_layer(context_info, context_meta_data_head_pointer, - resources_manager, input_layer_info); - CHECK_SUCCESS(status); - } - - for (const auto &input_layer_info : boundary_input_layers) { - status = fill_boundary_input_layer(context_info, context_meta_data_head_pointer, - resources_manager, input_layer_info); - CHECK_SUCCESS(status); - } - - for (const auto &input_layer_info : inter_context_input_layers) { - status = fill_inter_context_input_layer(context_info, context_meta_data_head_pointer, - resources_manager, input_layer_info); - CHECK_SUCCESS(status); - } - - /* UN-Lock resources at the end of the context - - h2d inter-context, d2h inter-context and DDR buffer channels */ - for (const auto &input_layer_info : inter_context_input_layers) { - status = resources_manager.free_channel_index(to_layer_identifier(input_layer_info)); - CHECK_SUCCESS(status); - } - - for (const auto &output_layer_info : inter_context_output_layers) { - status = resources_manager.free_channel_index(to_layer_identifier(output_layer_info)); - CHECK_SUCCESS(status); - } - - for (const auto &output_layer_info : ddr_output_layers) { - status = resources_manager.free_channel_index(to_layer_identifier(output_layer_info, VdmaChannel::Direction::H2D)); - CHECK_SUCCESS(status); - - status = resources_manager.free_channel_index(to_layer_identifier(output_layer_info, VdmaChannel::Direction::D2H)); - CHECK_SUCCESS(status); - } - - return HAILO_SUCCESS; + return net_group_name + HAILO_DEFAULT_NETWORK_NAME_QUALIFIER + partial_network_name; } -// Returns pairs of form [start, end] (inclusive) of repeated 'ContextSwitchConfigAction's in the given vector -static std::vector> get_repreated_actions_boundary_indices( - const std::vector &actions) +std::string HefUtils::get_network_name(const ProtoHEFCoreOpMock &core_op, const std::string &partial_network_name) { - const uint32_t num_actions = static_cast(actions.size()); - - std::vector> repeated_indexes; - uint32_t start_index = 0; - while (start_index < num_actions) { - auto end_index = start_index + 1; - do - { - if (end_index == num_actions) { - break; - } - if (actions[start_index]->get_type() != actions[end_index]->get_type()) { - break; - } - end_index++; - } while (true); - - - repeated_indexes.emplace_back(start_index, end_index - 1); - start_index = end_index; - } - - return repeated_indexes; + return HefUtils::get_network_name(core_op.network_group_metadata.network_group_name(), partial_network_name); } -// Returns a map from start indexes of repeated actions to the size of the chunk (number of repeated actions) -static std::map get_start_indexes_of_repeated_actions( - const std::vector &actions, - const std::vector> &repeated_indexes, - // TODO: get this from HardCoded config (HRT-5352) - const std::set &action_types_denylist = {}) +Expected> Hef::Impl::get_core_op_per_arch(const ProtoHEFCoreOpMock &core_op, + ProtoHEFHwArch hef_arch, hailo_device_architecture_t device_arch, uint32_t partial_clusters_layout_bitmap) { - std::map result; - for (const auto &index_pair : repeated_indexes) { - if (!actions[index_pair.first]->supports_repeated_block()) { - continue; - } - - if (contains(action_types_denylist, actions[index_pair.first]->get_type())) { - continue; - } - - // TODO: Move merge calculation to HRT-5352 - // Merge calculation (see also - CONTEXT_SWITCH_DEFS__repeated_action_header_t in common/include/context_switch_defs.h): - // * Assume there are x repeated actions that can be merged - // * Let a := sizeof(action_to_be_merged) [without CONTEXT_SWITCH_DEFS__common_action_header_t] - // * sizeof(CONTEXT_SWITCH_DEFS__common_action_header_t) is 5 - // * sizeof(CONTEXT_SWITCH_DEFS__repeated_action_header_t) is 3 - // Then: - // * original_size = x * (5 + a) = 5x + ax - // * new_size = 5 + 3 + ax = 8 + ax - // * new_size < original_size <=> 8 + ax < 5x + ax <=> 8 < 5x <=> 1.6 < x - // Hence we merge for x >= 2 - static_assert(sizeof(CONTEXT_SWITCH_DEFS__common_action_header_t) == 5, - "Merge calculation assumes that 'sizeof(CONTEXT_SWITCH_DEFS__common_action_header_t) == 5'"); - static_assert(sizeof(CONTEXT_SWITCH_DEFS__repeated_action_header_t) == 3, - "Merge calculation assumes that 'sizeof(CONTEXT_SWITCH_DEFS__repeated_action_header_t) == 3'"); - static const uint32_t MIN_REQUIRED_FOR_MERGING = 2; - - uint32_t start_index = index_pair.first; - const uint32_t end_index = index_pair.second; - while (start_index < end_index) { - const auto curr_chunk_size = static_cast(std::min( - static_cast(std::numeric_limits::max()), - end_index - start_index + 1)); - if (curr_chunk_size < MIN_REQUIRED_FOR_MERGING) { - break; + if (ProtoHEFHwArch::PROTO__HW_ARCH__HAILO8L == hef_arch) { + // Hailo8 can work with Hailo8L configurations. in that case we choose one of the configurations + for (auto &partial_core_op : core_op.partial_core_ops) { + if (partial_clusters_layout_bitmap == partial_core_op->layout.partial_clusters_layout_bitmap() + || (HAILO_ARCH_HAILO8 == device_arch)) { + return std::make_shared(*(partial_core_op->core_op)); } - - result.emplace(start_index, curr_chunk_size); - - start_index += curr_chunk_size; } + LOGGER__ERROR("There is no matching partial_clusters_layout_bitmap configuration in the given HEF"); + return make_unexpected(HAILO_INVALID_HEF); + } else { + return std::make_shared(core_op); } - - return result; } -static std::set> get_indexes_of_action_type( - const std::vector &actions, - const std::vector> &repeated_indexes, - const ContextSwitchConfigAction::Type &required_action_type) +Expected> Hef::Impl::get_sorted_output_names(const std::string &net_group_name) { - std::set> result; - for (const auto &index_pair : repeated_indexes) { - const auto curr_action_type = actions[index_pair.first]->get_type(); - if (required_action_type != curr_action_type) { - continue; + if (m_supported_features.hailo_net_flow) { + std::vector res; + for (const auto &net_group : m_groups) { + auto curr_name = HefUtils::get_network_group_name(*net_group, m_supported_features); + if (curr_name == net_group_name) { + res.reserve(net_group->sorted_outputs_order().size()); + for (auto &name : net_group->sorted_outputs_order()) { + res.push_back(name); + } + return res; + } } - - result.emplace(index_pair); - } - - return result; -} - -static std::set get_end_indexes_of_action_type( - const std::vector &actions, - const std::vector> &repeated_indexes, - const ContextSwitchConfigAction::Type &required_action_type) -{ - std::set result; - for (const auto &index_pair : get_indexes_of_action_type(actions, repeated_indexes, required_action_type)) { - result.insert(index_pair.second); + LOGGER__ERROR("Did not find network group of name {}", net_group_name); + return make_unexpected(HAILO_INVALID_HEF); } + auto network_group_metadata = get_network_group_metadata(net_group_name); + CHECK_EXPECTED(network_group_metadata); - return result; + auto res = network_group_metadata->get_sorted_output_names(); + return res; } -static hailo_status push_fetch_config_actions( - std::vector &config_resources, const std::set &pending_config_stream_indexes, - std::vector &total_ccw_bursts, const bool support_pre_fetch, - std::vector &processed_configuration_actions) +static Expected parse_ccw_buffer(const std::string &ccw_buffer) { - CHECK(total_ccw_bursts.size() == config_resources.size(), HAILO_INTERNAL_FAILURE, "Invalid cfg channels count"); - for (const auto config_stream_index : pending_config_stream_indexes) { - CHECK(config_stream_index < config_resources.size(), HAILO_INTERNAL_FAILURE, "Invalid cfg channel index"); + WriteMemoryInfo write_memory_info = {}; + CHECK_AS_EXPECTED(ccw_buffer.size() > CCW_DATA_OFFSET, HAILO_INVALID_HEF, "ccw buffer is too small"); + CcwHeader *header = (CcwHeader*)(ccw_buffer.data()); - auto fetch_config_action = support_pre_fetch ? - AddCcwBurstAction::create(config_stream_index, total_ccw_bursts[config_stream_index]) : - CreateConfigDescAndFetchAction::create(config_stream_index, config_resources[config_stream_index]); - CHECK_EXPECTED_AS_STATUS(fetch_config_action); + uint32_t words_count = header->words_count + 1; + auto data_length = words_count * CCW_BYTES_IN_WORD; + write_memory_info.address = header->address; - // Add the current action - processed_configuration_actions.emplace_back(fetch_config_action.release()); + // Validation for ccw size + size_t expected_ccw_data_length = (ccw_buffer.length() - CCW_DATA_OFFSET); + if (0 != (words_count % 2)) { + expected_ccw_data_length -= CCW_BYTES_IN_WORD; } + CHECK_AS_EXPECTED(data_length == expected_ccw_data_length, HAILO_INVALID_HEF, + "Invalid ccw buffer was parsed from HEF"); - return HAILO_SUCCESS; -} - -static hailo_status proccess_write_ccw_action(const ContextSwitchConfigActionPtr &configuration_action, - std::vector &config_resources, std::set &pending_config_stream_indexes, - std::vector &total_ccw_bursts, const std::set &end_indexes_of_write_ccw_actions, - const uint32_t &action_index, const bool support_pre_fetch, - std::vector &processed_configuration_actions) -{ - // Add the config stream index of the current WriteDataCcwAction - const auto config_stream_index = configuration_action->get_proto_action().write_data_ccw().cfg_channel_index(); - CHECK(IS_FIT_IN_UINT8(config_stream_index), HAILO_INVALID_HEF, - "Failed to parse HEF. Invalid config_stream_index: {}.", config_stream_index); - pending_config_stream_indexes.insert(static_cast(config_stream_index)); - - // TODO: get CCW headers from proto (need to add it into the proto) - // const auto ccw_bursts = configuration_action->get_proto_action().write_data_ccw().ccw_bursts(); - const uint16_t ccw_bursts = 1; - auto accum_ccw_bursts = total_ccw_bursts[config_stream_index] + ccw_bursts; - CHECK(IS_FIT_IN_UINT16(accum_ccw_bursts), HAILO_INTERNAL_FAILURE, - "Failed to parse HEF. action fetch ccw burst supports only to 2^16 bursts."); - total_ccw_bursts[config_stream_index] = static_cast(accum_ccw_bursts); - - // At the end of a consecutive group of WriteDataCcwActions, we program the - // descriptors for all the config channels used. - if (contains(end_indexes_of_write_ccw_actions, action_index)) { - // Add the last CCW write into the buffer - processed_configuration_actions.emplace_back(configuration_action); - - auto status = push_fetch_config_actions(config_resources, pending_config_stream_indexes, total_ccw_bursts, - support_pre_fetch, processed_configuration_actions); - CHECK_SUCCESS(status); - - // Cleanups - pending_config_stream_indexes.clear(); - for (uint8_t cleanup_ch_index = 0; cleanup_ch_index < total_ccw_bursts.size(); cleanup_ch_index++) { - total_ccw_bursts[cleanup_ch_index] = 0; - } - } else { - // Add the current action - processed_configuration_actions.emplace_back(configuration_action); - } + auto data_buff = Buffer::create(reinterpret_cast(ccw_buffer.data() + CCW_DATA_OFFSET), data_length); + CHECK_EXPECTED(data_buff); + write_memory_info.data = data_buff.release(); - return HAILO_SUCCESS; + return write_memory_info; } -static hailo_status proccess_trigger_new_data_input_action(const ContextSwitchConfigActionPtr &configuration_action, - uint32_t trigger_new_data_from_input_group_start, - uint32_t trigger_new_data_from_input_group_end, - const uint32_t &action_index, - const ResourcesManager &resources_manager, - uint8_t context_index, - std::vector &processed_configuration_actions) -{ - if (trigger_new_data_from_input_group_start == action_index) { - auto action = EdgeLayerActivationActionsPositionMarker::create(); - CHECK_EXPECTED_AS_STATUS(action); - processed_configuration_actions.emplace_back(action.release()); - - // DDR buffer info actions need to happen after the edge layer activation actions. - const auto status = add_ddr_buffers_info(processed_configuration_actions, resources_manager, context_index); - CHECK_SUCCESS(status); - } - - // Add the current action - processed_configuration_actions.emplace_back(configuration_action); - - // At the end of a consecutive group of TriggerNewDataFromDataInput actions, we can trigger the BurstCreditsTask - // in the FW, via StartBurstCreditsTaskAction. - if (trigger_new_data_from_input_group_end == action_index) { - auto start_burst_credits_task_action = StartBurstCreditsTaskAction::create(); - CHECK_EXPECTED_AS_STATUS(start_burst_credits_task_action); - processed_configuration_actions.emplace_back(start_burst_credits_task_action.release()); - } - - return HAILO_SUCCESS; -} +/* HcpConfigNetworkGroup funcs */ -// At the end of each consecutive group of WriteDataCcwAction, a CreateConfigDescAndFetchAction is added. -static hailo_status add_fetch_config_actions(std::vector &configuration_actions, - std::vector &config_resources, bool support_pre_fetch) +Expected> Hef::Impl::create_single_context_network_group_config(const ProtoHEFPreliminaryConfig& proto_config) { - const auto repeated_indexes = get_repreated_actions_boundary_indices(configuration_actions); - const auto end_indexes_of_write_ccws = get_end_indexes_of_action_type(configuration_actions, - repeated_indexes, ContextSwitchConfigAction::Type::WriteDataCcw); - - std::set pending_config_stream_indexes; - std::vector total_ccw_bursts(config_resources.size(), 0); - std::vector processed_configuration_actions; - for (uint32_t action_index = 0; action_index < configuration_actions.size(); action_index++) { - const auto &configuration_action = configuration_actions[action_index]; - if (ContextSwitchConfigAction::Type::WriteDataCcw == configuration_action->get_type()) { - auto status = proccess_write_ccw_action(configuration_action, config_resources, pending_config_stream_indexes, - total_ccw_bursts, end_indexes_of_write_ccws, action_index, support_pre_fetch, processed_configuration_actions); - CHECK_SUCCESS(status); - } else { - // Add the current action - processed_configuration_actions.emplace_back(configuration_action); - } - } - - // Replace the original configuration actions with the processed ones. - configuration_actions = processed_configuration_actions; - - return HAILO_SUCCESS; -} - -// For any context with edge layers (the preliminary context when in preliminary_run_asap mode or dynamic contexts), -// we need to add the following: -// * Edge layer activation actions - the fw places the edge layer activation actions in the action list based on the -// postion marked by the EdgeLayerActivationActionsPositionMarker. In both dynamic and preliminary contexts, these -// actions should ocurr right before the first TriggerNewDataFromDataInput action. Hence, the -// EdgeLayerActivationActionsPositionMarker will be placed at the first occurence of a TriggerNewDataFromDataInput action. -// * DdrPairInfoActions - need to happen after the edge layer activation actions. We'll place them right after the -// EdgeLayerActivationActionsPositionMarker. -// * StartBurstCreditsTaskAction - needs to happen after all the DdrPairInfoActions -static hailo_status handle_edge_layer_activation_actions(std::vector &configuration_actions, - const ResourcesManager &resources_manager, uint8_t context_index, bool is_preliminary_context, bool is_first_operation) -{ - if (is_preliminary_context && !resources_manager.get_supported_features().preliminary_run_asap) { - // Nothing to do - no edge layers in the preliminary context if not running in preliminary_run_asap mode. - return HAILO_SUCCESS; - } - if (!is_preliminary_context && !is_first_operation) { - // Nothing to do - edge layers in dynamic contexts only appear in the first operation. - return HAILO_SUCCESS; - } - - const auto repeated_indexes = get_repreated_actions_boundary_indices(configuration_actions); - const auto trigger_new_data_from_input_group_indexes = get_indexes_of_action_type( - configuration_actions, repeated_indexes, ContextSwitchConfigAction::Type::TriggerNewDataFromDataInput); - CHECK(trigger_new_data_from_input_group_indexes.size() == 1, HAILO_INTERNAL_FAILURE, - "Expected only one group of TriggerNewDataFromDataInput actions"); - const auto trigger_new_data_from_input_group_start = trigger_new_data_from_input_group_indexes.cbegin()->first; - const auto trigger_new_data_from_input_group_end = trigger_new_data_from_input_group_indexes.cbegin()->second; - - std::vector processed_configuration_actions; - for (uint32_t action_index = 0; action_index < configuration_actions.size(); action_index++) { - const auto &configuration_action = configuration_actions[action_index]; - if (ContextSwitchConfigAction::Type::TriggerNewDataFromDataInput == configuration_action->get_type()) { - auto status = proccess_trigger_new_data_input_action(configuration_action, - trigger_new_data_from_input_group_start, trigger_new_data_from_input_group_end, action_index, - resources_manager, context_index, processed_configuration_actions); - CHECK_SUCCESS(status); - } else { - // Add the current action - processed_configuration_actions.emplace_back(configuration_action); - } - } - - // Replace the original configuration actions with the processed ones. - configuration_actions = processed_configuration_actions; - - return HAILO_SUCCESS; -} + std::vector config_buffers; -// If groups of consecutive actions can be "merged" as repeated actions (saving room the FW's -// action list) a RepeatedHeaderAction is placed before the relevant actions. -// See also: CONTROL_PROTOCOL__REPEATED_ACTION_t's documnetion in control_protocol.h. -static hailo_status handle_repeated_actions(std::vector &configuration_actions) -{ - const auto repeated_indexes = get_repreated_actions_boundary_indices(configuration_actions); - const auto start_indexes_of_repeated_actions = get_start_indexes_of_repeated_actions( - configuration_actions, repeated_indexes); - - std::vector processed_configuration_actions; - processed_configuration_actions.reserve(configuration_actions.size() + start_indexes_of_repeated_actions.size()); - for (uint32_t action_index = 0; action_index < configuration_actions.size(); action_index++) { - if (contains(start_indexes_of_repeated_actions, action_index)) { - // A group of actions can be "merged" as repeated actions. - // Add a RepeatedHeaderAction - const auto num_repeates = start_indexes_of_repeated_actions.at(action_index); - const auto sub_action_type = configuration_actions[action_index]->get_action_list_type(); - auto repeated_header_action = RepeatedHeaderAction::create(sub_action_type, num_repeates); - CHECK_EXPECTED_AS_STATUS(repeated_header_action); - processed_configuration_actions.emplace_back(repeated_header_action.release()); - // Mark all the actions in this group as "reapted" - for (uint32_t repeated_offset = 0; repeated_offset < num_repeates; repeated_offset++) { - configuration_actions[action_index + repeated_offset]->set_is_in_repeated_block(true); - } - } - - // Add the current action - processed_configuration_actions.emplace_back(configuration_actions[action_index]); - } - - // Replace the original configuration actions with the processed ones. - configuration_actions = processed_configuration_actions; - - return HAILO_SUCCESS; -} - -static bool is_mercury_device_type(const ProtoHEFHwArch &hw_arch) -{ - /* TODO - HRT-5067 - use one hw_arch for mercury */ - return (PROTO__HW_ARCH__MERCURY == hw_arch) || (PROTO__HW_ARCH__GINGER == hw_arch) || - (PROTO__HW_ARCH__LAVENDER == hw_arch); -} - -static hailo_status parse_actions_in_operation(const ProtoHEFOperation &operation, - Device &device, const ProtoHEFHwArch &hw_arch, uint8_t context_index, bool is_preliminary_context, - bool is_first_operation, std::vector &config_resources, - const ResourcesManager &resources_manager, - const ProtoHEFNetworkGroup &network_group_proto, - CONTROL_PROTOCOL__context_switch_context_info_t &context_info, uint8_t **context_meta_data_head_pointer) -{ - const auto support_pre_fetch = is_mercury_device_type(hw_arch); - // First, the context switch configuration actions from the HEF are added in their order of - // appearance (which is chronological). - std::vector configuration_actions; - configuration_actions.reserve(operation.actions_size()); - for (const auto &proto_action : operation.actions()) { - auto configuration_action = ContextSwitchConfigAction::create(proto_action, device, config_resources, - resources_manager, network_group_proto, support_pre_fetch); - CHECK_EXPECTED_AS_STATUS(configuration_action); - configuration_actions.emplace_back(configuration_action.release()); - } - - // Next, we process the actions from the HEF. The resulting vector contains the configuration actions to be - // executed in chronological order. - auto status = add_fetch_config_actions(configuration_actions, config_resources, support_pre_fetch); - CHECK_SUCCESS(status); - status = handle_edge_layer_activation_actions(configuration_actions, resources_manager, context_index, - is_preliminary_context, is_first_operation); - CHECK_SUCCESS(status); - status = handle_repeated_actions(configuration_actions); - CHECK_SUCCESS(status); - - // Finally, we execute the context switch configuration actions. - for (const auto &configuration_action : configuration_actions) { - status = configuration_action->execute(&context_info, context_meta_data_head_pointer); - CHECK_SUCCESS(status); - } - - return HAILO_SUCCESS; -} - -static hailo_status fill_context_recepies_for_multi_context(const ProtoHEFNetworkGroup &network_group_proto, - const ProtoHEFHwArch &hw_arch, CONTROL_PROTOCOL__context_switch_context_info_t &context_info, - ResourcesManager &resources_manager, uint8_t context_index, const ProtoHEFContext &proto_context, - std::shared_ptr network_group_metadata, - Device &device) -{ - hailo_status status = HAILO_UNINITIALIZED; - uint8_t *context_meta_data_head_pointer = context_info.context_network_data; - - // Add edge layers mapping - status = parse_and_fill_edge_layers_mapping(&context_info, &context_meta_data_head_pointer, - &proto_context.metadata(), resources_manager, network_group_metadata, context_index); - CHECK_SUCCESS(status); - - CHECK(IS_FIT_IN_UINT8(proto_context.operations_size()), HAILO_INVALID_HEF, - "Failed to parse HEF. Invalid operations_count: {}.", proto_context.operations_size()); - - context_info.context_stream_remap_data.should_use_stream_remap = static_cast( - proto_context.metadata().shmiglue_info().should_use_shmiglue()); - - // Parse context - bool first_operation = true; - for (const auto &operation : proto_context.operations()) { - const auto operation_trigger = ContextSwitchTrigger::create(operation.trigger()); - CHECK_EXPECTED_AS_STATUS(operation_trigger); - operation_trigger->add_to_trigger_group(&context_info, &context_meta_data_head_pointer); - - static const auto NOT_PRELIMINARY_CONTEXT = false; - status = parse_actions_in_operation(operation, device, hw_arch, context_index, NOT_PRELIMINARY_CONTEXT, - first_operation, resources_manager.dynamic_config(context_index), resources_manager, network_group_proto, - context_info, &context_meta_data_head_pointer); - CHECK_SUCCESS(status); - - first_operation = false; - } - - // update context_network_data_length per context, and dynamic_contexts_descriptors count in main header - context_info.context_network_data_length = - static_cast(context_meta_data_head_pointer - context_info.context_network_data); - - return HAILO_SUCCESS; -} - -static hailo_status fill_preliminary_config_recepies_for_multi_context(const ProtoHEFHwArch &hw_arch, - CONTROL_PROTOCOL__context_switch_context_info_t &context_info, ResourcesManager &resources_manager, - const ProtoHEFNetworkGroup &network_group_proto, - const ProtoHEFPreliminaryConfig &proto_preliminary_config, - std::shared_ptr network_group_metadata, Device &device) -{ - uint8_t *context_meta_data_head_pointer = context_info.context_network_data; - - CHECK(IS_FIT_IN_UINT8(proto_preliminary_config.operation_size()), HAILO_INVALID_HEF, - "Failed to parse HEF. Invalid operations_count: {}.", proto_preliminary_config.operation_size()); - - if (resources_manager.get_supported_features().preliminary_run_asap) { - // Add edge layers mapping (only preliminary_run_asap networks have edge layers in the preliminary context) - static const auto PRELIMINARY_CONTEXT_INDEX = 0; - auto status = parse_and_fill_edge_layers_mapping(&context_info, &context_meta_data_head_pointer, - &(network_group_proto.contexts(PRELIMINARY_CONTEXT_INDEX).metadata()), resources_manager, - network_group_metadata, PRELIMINARY_CONTEXT_INDEX); - CHECK_SUCCESS(status); - } - - // Parse preliminary config - bool first_operation = true; - for (const auto &operation_proto : proto_preliminary_config.operation()) { - const auto operation_trigger = ContextSwitchTrigger::create(operation_proto.trigger()); - CHECK_EXPECTED_AS_STATUS(operation_trigger); - operation_trigger->add_to_trigger_group(&context_info, &context_meta_data_head_pointer); - - static const auto PRELIMINARY_CONTEXT_INDEX = 0; - static const auto PRELIMINARY_CONTEXT = true; - const auto status = parse_actions_in_operation(operation_proto, device, hw_arch, PRELIMINARY_CONTEXT_INDEX, - PRELIMINARY_CONTEXT, first_operation, resources_manager.preliminary_config(), resources_manager, - network_group_proto, context_info, &context_meta_data_head_pointer); - CHECK_SUCCESS(status); - - first_operation = false; - } - - // Update context_network_data_length per context, and preliminary_context_descriptors count in main header - context_info.context_network_data_length = - static_cast(context_meta_data_head_pointer - context_info.context_network_data); - - return HAILO_SUCCESS; -} - -Expected> Hef::Impl::create_resources_manager( - const ProtoHEFNetworkGroup &network_group_proto, uint8_t net_group_index, - VdmaDevice &device, HailoRTDriver &driver, const ConfigureNetworkParams &config_params, - std::shared_ptr network_group_metadata, - const ProtoHEFHwArch &hw_arch) -{ - CHECK(network_group_proto.contexts_size() <= MAX_CONTEXTS_COUNT, make_unexpected(HAILO_INVALID_HEF), - "App '{}' contains more contexts than allowed ({} > {})", network_group_proto.network_group_metadata().network_group_name(), - network_group_proto.contexts_size(), MAX_CONTEXTS_COUNT); - - for (auto &network_params : config_params.network_params_by_name) { - CHECK(HAILO_MAX_BATCH_SIZE >= network_params.second.batch_size, make_unexpected(HAILO_INVALID_ARGUMENT), - "Given batch size ({}) for network group {}, network {} is bigger than max allowed ({})", network_params.second.batch_size, - network_group_proto.network_group_metadata().network_group_name(), network_params.first, HAILO_MAX_BATCH_SIZE); - } - - auto parsing_info = Hef::Impl::get_parsing_info(network_group_proto); - CHECK_EXPECTED(parsing_info); - - auto resources_manager = ResourcesManager::create(device, driver, config_params, network_group_proto, network_group_metadata, - parsing_info.release(), net_group_index); - CHECK_EXPECTED(resources_manager); - - auto preliminary_context = resources_manager->add_new_context(); - CHECK_EXPECTED(preliminary_context); - - auto status = fill_preliminary_config_recepies_for_multi_context(hw_arch, preliminary_context.value().get(), - resources_manager.value(), network_group_proto, network_group_proto.preliminary_config(), - network_group_metadata, device); - CHECK_SUCCESS_AS_EXPECTED(status); - resources_manager->update_preliminary_config_buffer_info(); - - for (uint8_t context_index = 0; context_index < network_group_proto.contexts_size(); ++context_index) { - auto new_context = resources_manager->add_new_context(); - CHECK_EXPECTED(new_context); - - status = fill_context_recepies_for_multi_context(network_group_proto, hw_arch, new_context.value().get(), resources_manager.value(), - context_index, network_group_proto.contexts(context_index), network_group_metadata, device); - CHECK_SUCCESS_AS_EXPECTED(status); - } - resources_manager->update_dynamic_contexts_buffer_info(); - - status = resources_manager->create_fw_managed_vdma_channels(); - CHECK_SUCCESS_AS_EXPECTED(status); - - auto resources_manager_ptr = make_shared_nothrow(resources_manager.release()); - CHECK_NOT_NULL_AS_EXPECTED(resources_manager_ptr, HAILO_OUT_OF_HOST_MEMORY); - - return resources_manager_ptr; -} - -Expected> Hef::Impl::get_sorted_output_names(const std::string &net_group_name) -{ - auto network_group_metadata = get_network_group_metadata(net_group_name); - CHECK_EXPECTED(network_group_metadata); - - auto res = network_group_metadata->get_sorted_output_names(); - return res; -} - -static Expected parse_ccw_buffer(const std::string &ccw_buffer) -{ - WriteMemoryInfo write_memory_info = {}; - CHECK_AS_EXPECTED(ccw_buffer.size() > CCW_DATA_OFFSET, HAILO_INVALID_HEF, "ccw buffer is too small"); - CcwHeader *header = (CcwHeader*)(ccw_buffer.data()); - - uint32_t words_count = header->words_count + 1; - auto data_length = words_count * CCW_BYTES_IN_WORD; - write_memory_info.address = header->address; - - // Validation for ccw size - size_t expected_ccw_data_length = (ccw_buffer.length() - CCW_DATA_OFFSET); - if (0 != (words_count % 2)) { - expected_ccw_data_length -= CCW_BYTES_IN_WORD; - } - CHECK_AS_EXPECTED(data_length == expected_ccw_data_length, HAILO_INVALID_HEF, - "Invalid ccw buffer was parsed from HEF"); - - auto data_buff = Buffer::create(reinterpret_cast(ccw_buffer.data() + CCW_DATA_OFFSET), data_length); - CHECK_EXPECTED(data_buff); - write_memory_info.data = data_buff.release(); - - return write_memory_info; -} - -/* HcpConfigNetworkGroup funcs */ - -Expected> Hef::Impl::create_single_context_network_group_config(const ProtoHEFPreliminaryConfig& proto_config) -{ - std::vector config_buffers; - - for (const auto &operation : proto_config.operation()) { - switch (operation.trigger().trigger_case()) { - case ProtoHEFTrigger::kTriggerNone: { - break; - } - default: { - LOGGER__ERROR("Triggers different from 'ProtoHEFTriggerNone' are not supported"); - return make_unexpected(HAILO_INTERNAL_FAILURE); + for (const auto &operation : proto_config.operation()) { + switch (operation.trigger().trigger_case()) { + case ProtoHEFTrigger::kTriggerNone: { + break; + } + default: { + LOGGER__ERROR("Triggers different from 'ProtoHEFTriggerNone' are not supported"); + return make_unexpected(HAILO_INTERNAL_FAILURE); } } @@ -2451,897 +2243,84 @@ Expected> Hef::Impl::create_single_context_network_ config_buffers.emplace_back(config_buffer.release()); break; } - case ProtoHEFAction::kDisableLcu: { - // We ignore this action. the lcu_disable will happen in the nn_core reset before configuring specific network_group - break; - } - case ProtoHEFAction::kEnableLcu: { - WriteMemoryInfo write_memory_info = {}; - write_memory_info.address = action.enable_lcu().lcu_enable_address(); - auto data_buff = Buffer::create(ENABLE_LCU_CONTROL_WORD, sizeof(ENABLE_LCU_CONTROL_WORD)); - CHECK_EXPECTED(data_buff); - write_memory_info.data = data_buff.release(); - config_buffers.emplace_back(std::move(write_memory_info)); - break; - } - case ProtoHEFAction::kAllowInputDataflow: { - case ProtoHEFAction::kWaitForModuleConfigDone: - // We ignore the 'wait_for_interrupt' actions. After writing the configurations we can be sure everything is configured and dont need to wait for interrupts - break; - } - case ProtoHEFAction::kWaitForSeqeuncer: { - case ProtoHEFAction::kEnableSequencer: - LOGGER__ERROR("Parsing error. Sequencer related actions are not supported over Ethernet. " - "If you use the Ethernet interface, please disable the Sequencer in the Dataflow Compiler (SDK) and then re-create the HEF. " - "Disabling the Sequencer is done using the hef_param command in the model script (ALLS file). " - "See the Dataflow Compiler user guide for more information."); - return make_unexpected(HAILO_INVALID_HEF); - } - default: { - LOGGER__ERROR("Invalid action"); - return make_unexpected(HAILO_INTERNAL_FAILURE); - } - } - } - } - - return config_buffers; -} - -ProtoHEFHwArch Hef::Impl::get_device_arch() -{ - return m_header.hw_arch(); -} - -Expected Hef::Impl::get_bottleneck_fps(const std::string &net_group_name) -{ - auto net_group = get_net_group_by_name(net_group_name); - CHECK_EXPECTED(net_group); - return net_group.value()->network_group_metadata().bottleneck_fps(); -} - -bool Hef::Impl::contains_ddr_layers(const ProtoHEFNetworkGroup& net_group) -{ - for (auto &context : net_group.contexts()) { - for (auto &layer : context.metadata().edge_layers()) { - if (ProtoHEFEdgeConnectionType::PROTO__EDGE_CONNECTION_TYPE__DDR == - layer.context_switch_info().edge_connection_type()) { - return true; - } - } - } - return false; -} - -bool is_edge_under_mux(const LayerInfo &info, const std::string &edge_name) -{ - if (!info.is_mux) { - return edge_name == info.name; - } - for (const auto &pred : info.predecessor) { - if (info.is_mux) { - if (is_edge_under_mux(pred, edge_name)) { - return true; - } - } else { - if (edge_name == pred.name) { - return true; - } - } - } - return false; -} - -Expected> Hef::Impl::get_stream_names_from_vstream_name(const std::string &vstream_name, - const std::string &net_group_name) -{ - auto network_group_metadata = get_network_group_metadata(net_group_name); - CHECK_EXPECTED(network_group_metadata); - - return network_group_metadata->get_stream_names_from_vstream_name(vstream_name); -} - -void get_demuxes_names_impl(const LayerInfo &info, std::vector &res) -{ - if (!info.is_mux) { - res.push_back(info.name); - } else { - for (auto &pred : info.predecessor) { - get_demuxes_names_impl(pred, res); - } - } -} - -std::vector get_demuxes_names(const LayerInfo &info) -{ - std::vector res; - get_demuxes_names_impl(info, res); - return res; -} - -Expected> Hef::Impl::get_vstream_names_from_stream_name(const std::string &stream_name, - const std::string &net_group_name) -{ - auto network_group_metadata = get_network_group_metadata(net_group_name); - CHECK_EXPECTED(network_group_metadata); - - return network_group_metadata->get_vstream_names_from_stream_name(stream_name); -} - -Expected ContextSwitchTrigger::serialize(const ProtoHEFTrigger &proto_trigger) -{ - switch (proto_trigger.trigger_case()) { - case ProtoHEFTrigger::kTriggerNone: - return HEF_METADATA__build_none_trigger(); - case ProtoHEFTrigger::kTriggerAllDataWasReceived: - { - const auto stream_index = proto_trigger.trigger_all_data_was_received().shmifo_index(); - CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(stream_index), HAILO_INVALID_HEF, - "Failed to parse HEF. Invalid stream_index: {}.", stream_index); - return HEF_METADATA__build_input_stream_trigger(static_cast(stream_index)); - } - case ProtoHEFTrigger::kTriggerAllDataWasSent: - { - const auto stream_index = proto_trigger.trigger_all_data_was_sent().shmifo_index(); - CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(stream_index), HAILO_INVALID_HEF, - "Failed to parse HEF. Invalid stream_index: {}.", stream_index); - return HEF_METADATA__build_output_stream_trigger(static_cast(stream_index)); - } - case ProtoHEFTrigger::kTriggerLcu: - { - const auto cluster_index = proto_trigger.trigger_lcu().cluster_index(); - const auto lcu_index = proto_trigger.trigger_lcu().lcu_index(); - CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(cluster_index), HAILO_INVALID_HEF, - "Failed to parse HEF. Invalid cluster_index: {}.", cluster_index); - CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(lcu_index), HAILO_INVALID_HEF, - "Failed to parse HEF. Invalid lcu_index: {}.", lcu_index); - return HEF_METADATA__build_lcu_trigger(static_cast(cluster_index), - static_cast(lcu_index)); - } - case ProtoHEFTrigger::kTriggerNms: - { - const auto aggregator_index = proto_trigger.trigger_nms().aggregator_index(); - const auto pred_cluster_ob_index = proto_trigger.trigger_nms().pred_cluster_ob_index(); - const auto pred_cluster_ob_cluster_index = proto_trigger.trigger_nms().pred_cluster_ob_cluster_index(); - const auto pred_cluster_ob_interface = proto_trigger.trigger_nms().pred_cluster_ob_interface(); - const auto succ_prepost_ob_index = proto_trigger.trigger_nms().succ_prepost_ob_index(); - const auto succ_prepost_ob_interface = proto_trigger.trigger_nms().succ_prepost_ob_interface(); - CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(aggregator_index), HAILO_INVALID_HEF, - "Failed to parse HEF. Invalid aggregator_index: {}.", aggregator_index); - CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(pred_cluster_ob_index), HAILO_INVALID_HEF, - "Failed to parse HEF. Invalid pred_cluster_ob_index: {}.", pred_cluster_ob_index); - CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(pred_cluster_ob_cluster_index), HAILO_INVALID_HEF, - "Failed to parse HEF. Invalid pred_cluster_ob_cluster_index: {}.", pred_cluster_ob_cluster_index); - CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(pred_cluster_ob_interface), HAILO_INVALID_HEF, - "Failed to parse HEF. Invalid pred_cluster_ob_interface: {}.", pred_cluster_ob_interface); - CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(succ_prepost_ob_index), HAILO_INVALID_HEF, - "Failed to parse HEF. Invalid succ_prepost_ob_index: {}.", succ_prepost_ob_index); - CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(succ_prepost_ob_interface), HAILO_INVALID_HEF, - "Failed to parse HEF. Invalid succ_prepost_ob_interface: {}.", succ_prepost_ob_interface); - - return HEF_METADATA__build_nms_trigger(static_cast(aggregator_index), - static_cast(pred_cluster_ob_index), static_cast(pred_cluster_ob_cluster_index), - static_cast(pred_cluster_ob_interface), static_cast(succ_prepost_ob_index), - static_cast(succ_prepost_ob_interface)); - } - case ProtoHEFTrigger::kTriggerDmaIdle: - { - const auto stream_index = proto_trigger.trigger_dma_idle().shmifo_index(); - CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(stream_index), HAILO_INVALID_HEF, - "Failed to parse HEF. Invalid stream_index: {}.", stream_index); - return HEF_METADATA__build_dma_idle_trigger(static_cast(stream_index)); - } - default: - LOGGER__ERROR("Invalid trigger"); - break; - } - - // Deafult case - return make_unexpected(HAILO_INTERNAL_FAILURE); -} - -Expected ContextSwitchTrigger::create(const ProtoHEFTrigger &proto_trigger) -{ - auto serialized_trigger = serialize(proto_trigger); - CHECK_EXPECTED(serialized_trigger); - return ContextSwitchTrigger(serialized_trigger.release()); -} - -ContextSwitchTrigger::ContextSwitchTrigger(CONTROL_PROTOCOL__TRIGGER_t &&serialized_trigger) : - m_serialized_trigger(std::move(serialized_trigger)) -{} - -CONTROL_PROTOCOL__TRIGGER_t ContextSwitchTrigger::get_serialized() const -{ - return m_serialized_trigger; -} - -hailo_status ContextSwitchTrigger::add_to_trigger_group(CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **context_meta_data_head_pointer) const -{ - return HEF_METADATA__add_trigger_to_trigger_group(context_info, context_meta_data_head_pointer, - &m_serialized_trigger); -} - -Expected ContextSwitchConfigAction::create(const ProtoHEFAction &proto_action, Device &device, - std::vector &config, const ResourcesManager &resources_manager, const ProtoHEFNetworkGroup &net_group, - bool support_pre_fetch) -{ - switch (proto_action.action_case()) { - case ProtoHEFAction::kWriteDataCcw: - return WriteDataCcwAction::create(proto_action, config, support_pre_fetch); - - case ProtoHEFAction::kWriteData: - return WriteDataAction::create(proto_action, device); - - case ProtoHEFAction::kDisableLcu: - return DisableLcuAction::create(proto_action); - - case ProtoHEFAction::kEnableLcu: - return EnableLcuAction::create(proto_action, resources_manager, net_group); - - case ProtoHEFAction::kEnableSequencer: - return EnableSequencerAction::create(proto_action); - - case ProtoHEFAction::kNone: - return NoneAction::create(); - - case ProtoHEFAction::kWaitForSeqeuncer: - return WaitForSeqeuncerAction::create(proto_action); - - case ProtoHEFAction::kWriteCompressedData: - LOGGER__ERROR("Action 'WriteCompressedData' is not supported"); - return make_unexpected(HAILO_NOT_IMPLEMENTED); - - case ProtoHEFAction::kAllowInputDataflow: - return AllowInputDataflowAction::create(proto_action); - - case ProtoHEFAction::kWaitForModuleConfigDone: - return WaitForModuleConfigDoneAction::create(proto_action); - - default: - LOGGER__ERROR("Invalid action"); - break; - } - - // Default case - return make_unexpected(HAILO_INTERNAL_FAILURE); -} - -ContextSwitchConfigAction::ContextSwitchConfigAction(Type type) : - ContextSwitchConfigAction(type, CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_COUNT, ProtoHEFAction::default_instance()) -{} - -ContextSwitchConfigAction::ContextSwitchConfigAction(Type type, const ProtoHEFAction& proto_action) : - ContextSwitchConfigAction(type, CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_COUNT, proto_action) -{} - -ContextSwitchConfigAction::ContextSwitchConfigAction(Type type, CONTROL_PROTOCOL__ACTION_TYPE_t action_list_type) : - ContextSwitchConfigAction(type, action_list_type, ProtoHEFAction::default_instance()) -{} - -ContextSwitchConfigAction::ContextSwitchConfigAction(Type type, - CONTROL_PROTOCOL__ACTION_TYPE_t action_list_type, - const ProtoHEFAction& proto_action) : - m_type(type), - m_action_list_type(action_list_type), - m_is_in_repeated_block(false), - m_proto_action(proto_action) -{} - -ContextSwitchConfigAction::Type ContextSwitchConfigAction::get_type() const -{ - return m_type; -} - -CONTROL_PROTOCOL__ACTION_TYPE_t ContextSwitchConfigAction::get_action_list_type() const -{ - return m_action_list_type; -} - -const ProtoHEFAction &ContextSwitchConfigAction::get_proto_action() const -{ - return m_proto_action; -} - -void ContextSwitchConfigAction::set_is_in_repeated_block(bool is_repeated) -{ - m_is_in_repeated_block = is_repeated; -} - -Expected NoneAction::create() -{ - auto result = ContextSwitchConfigActionPtr(new (std::nothrow) NoneAction()); - CHECK_AS_EXPECTED((nullptr != result), HAILO_OUT_OF_HOST_MEMORY); - return result; -} - -NoneAction::NoneAction() : - ContextSwitchConfigAction(Type::None) -{} - -hailo_status NoneAction::execute(CONTROL_PROTOCOL__context_switch_context_info_t *, uint8_t **) -{ - // Do nothing - return HAILO_SUCCESS; -} - -bool NoneAction::supports_repeated_block() const -{ - // None actions are ignored and aren't written to the FW's action list. Hence they can't be part of a repeated block. - return false; -} - -Expected WriteDataAction::create(const ProtoHEFAction& proto_action, Device &device) -{ - auto result = ContextSwitchConfigActionPtr(new (std::nothrow) WriteDataAction(proto_action, device)); - CHECK_AS_EXPECTED((nullptr != result), HAILO_OUT_OF_HOST_MEMORY); - return result; -} - -WriteDataAction::WriteDataAction(const ProtoHEFAction& proto_action, Device &device) : - ContextSwitchConfigAction(Type::WriteData, proto_action), - m_device(device) -{} - -hailo_status WriteDataAction::execute(CONTROL_PROTOCOL__context_switch_context_info_t *, uint8_t **) -{ - return m_device.write_memory(static_cast(m_proto_action.write_data().address()), - MemoryView::create_const(m_proto_action.write_data().data().data(), m_proto_action.write_data().data().length())); -} - -bool WriteDataAction::supports_repeated_block() const -{ - // WriteDataActions aren't written to the FW's action list. Hence they can't be part of a repeated block. - return false; -} - -Expected WriteDataCcwAction::create(const ProtoHEFAction& proto_action, - std::vector &config, bool support_pre_fetch) -{ - // Add buffer to cfg_ch buffer without making descriptors (saving offset as the total data so far) - CHECK_AS_EXPECTED(proto_action.write_data_ccw().cfg_channel_index() < config.size(), HAILO_INVALID_HEF, - "cfg_channel index {} is bigger than config channels count {}", - proto_action.write_data_ccw().cfg_channel_index(), config.size()); - CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(proto_action.write_data_ccw().cfg_channel_index()), HAILO_INVALID_HEF, - "Invalid cfg channel index"); - - auto result = ContextSwitchConfigActionPtr(new (std::nothrow) WriteDataCcwAction(proto_action, - config[proto_action.write_data_ccw().cfg_channel_index()], support_pre_fetch)); - CHECK_AS_EXPECTED((nullptr != result), HAILO_OUT_OF_HOST_MEMORY); - return result; -} - -WriteDataCcwAction::WriteDataCcwAction(const ProtoHEFAction& proto_action, ConfigBuffer &config, - bool support_pre_fetch) : - ContextSwitchConfigAction(Type::WriteDataCcw, proto_action), - m_config(config), - m_support_pre_fetch(support_pre_fetch) -{} - -bool WriteDataCcwAction::is_last_ccw_write() -{ - auto write_size = m_proto_action.write_data_ccw().data().length(); - /* If last operation in context - Add nops to fill the buffer */ - if ((write_size + m_config.get_current_buffer_size()) != m_config.get_total_cfg_size()) { - return false; - } - - return true; -} - -hailo_status WriteDataCcwAction::pad_with_nops() -{ - auto page_size = m_config.desc_page_size(); - auto buffer_size = m_config.get_total_cfg_size(); - auto buffer_residue = buffer_size % page_size; - if (0 != buffer_residue % CCW_HEADER_SIZE) { - LOGGER__ERROR("CFG channel buffer size must be a multiple of CCW header size ({})", CCW_HEADER_SIZE); - return HAILO_INTERNAL_FAILURE; - } - /* If buffer does not fit info descriptor, the host must pad the buffer with CCW NOPs. */ - auto nop_count = (buffer_residue == 0) ? 0 : ((page_size - buffer_residue) / CCW_HEADER_SIZE); - for (uint8_t nop_index = 0; nop_index < nop_count; nop_index++) { - /* Generate nop transaction. - CCW of all zeros (64'h0) should be treated as NOP - ignore CCW and expect CCW in next 64b word. - When CSM recognize it is a NOP it pops it from the channel FIFO without forward any address/data/command, - does not contribute to CRC calculations but return credits to the peripheral as usual. */ - m_config.write(reinterpret_cast(&CCW_NOP), sizeof(CCW_NOP)); - } - - return HAILO_SUCCESS; - -} - -hailo_status WriteDataCcwAction::execute(CONTROL_PROTOCOL__context_switch_context_info_t *, uint8_t **) -{ - const bool is_last_write = is_last_ccw_write(); - if (m_support_pre_fetch && is_last_write) { - auto status = pad_with_nops(); - CHECK_SUCCESS(status); - } - - auto status = m_config.write(m_proto_action.write_data_ccw().data().data(), - m_proto_action.write_data_ccw().data().length()); - CHECK_SUCCESS(status); - - if (m_support_pre_fetch && is_last_write) { - auto desc_count = m_config.program_descriptors(); - CHECK_EXPECTED_AS_STATUS(desc_count); - } - - return HAILO_SUCCESS; -} - -bool WriteDataCcwAction::supports_repeated_block() const -{ - // WriteDataCcwActions aren't written to the FW's action list. Hence they can't be part of a repeated block. - return false; -} - -Expected AddCcwBurstAction::create(uint8_t config_stream_index, uint16_t ccw_bursts) -{ - auto result = ContextSwitchConfigActionPtr(new (std::nothrow) AddCcwBurstAction(config_stream_index, ccw_bursts)); - CHECK_AS_EXPECTED((nullptr != result), HAILO_OUT_OF_HOST_MEMORY); - return result; -} - -AddCcwBurstAction::AddCcwBurstAction(uint8_t config_stream_index, uint16_t ccw_bursts) : - ContextSwitchConfigAction(Type::AddCcwBurst), - m_config_stream_index(config_stream_index), - m_ccw_bursts(ccw_bursts) -{} - -hailo_status AddCcwBurstAction::execute(CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **context_meta_data_head_pointer) -{ - return HEF_METADATA__add_ccw_bursts_action(context_info, context_meta_data_head_pointer, - m_ccw_bursts, m_config_stream_index, m_is_in_repeated_block); -} - -bool AddCcwBurstAction::supports_repeated_block() const -{ - return false; -} - -Expected CreateConfigDescAndFetchAction::create(uint8_t config_stream_index, - ConfigBuffer &config_buffer) -{ - auto result = ContextSwitchConfigActionPtr(new (std::nothrow) CreateConfigDescAndFetchAction(config_stream_index, - config_buffer)); - CHECK_AS_EXPECTED((nullptr != result), HAILO_OUT_OF_HOST_MEMORY); - return result; -} - -CreateConfigDescAndFetchAction::CreateConfigDescAndFetchAction(uint8_t config_stream_index, ConfigBuffer &config_buffer) : - ContextSwitchConfigAction(Type::CreateDescForCcw), - m_config_stream_index(config_stream_index), - m_config_buffer(config_buffer) -{} - -hailo_status CreateConfigDescAndFetchAction::execute(CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **context_meta_data_head_pointer) -{ - const auto desc_count = m_config_buffer.program_descriptors(); - CHECK_EXPECTED_AS_STATUS(desc_count); - - CHECK(IS_FIT_IN_UINT16(desc_count.value()), HAILO_INVALID_OPERATION, - "On cfg with continuous mode, max descriptors size must fit in uint16_t"); - return HEF_METADATA__add_read_vdma_action(context_info, context_meta_data_head_pointer, - static_cast(desc_count.value()), m_config_stream_index, m_is_in_repeated_block); -} - -bool CreateConfigDescAndFetchAction::supports_repeated_block() const -{ - // TODO: Each CreateConfigDescAndFetchAction may contain multiple HEF_METADATA__add_read_vdma_action. - // They could be part of a repated block, but the curent logic in the hef module assumes that - // only one context switch action is written to the fw per ContextSwitchConfigAction instance. - // Hence this isn't supported. - return false; -} - -Expected StartBurstCreditsTaskAction::create() -{ - auto result = ContextSwitchConfigActionPtr(new (std::nothrow) StartBurstCreditsTaskAction()); - CHECK_AS_EXPECTED((nullptr != result), HAILO_OUT_OF_HOST_MEMORY); - return result; -} - -StartBurstCreditsTaskAction::StartBurstCreditsTaskAction() : - ContextSwitchConfigAction(Type::StartBurstCreditsTask) -{} - -hailo_status StartBurstCreditsTaskAction::execute(CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **context_meta_data_head_pointer) -{ - return HEF_METADATA__burst_credits_task_start(context_info, context_meta_data_head_pointer, - m_is_in_repeated_block); -} - -bool StartBurstCreditsTaskAction::supports_repeated_block() const -{ - // We don't support repeated blocks for this action, since only one is added per group of consecutive - // TriggerNewDataFromDataInput actions. - return false; -} - -Expected RepeatedHeaderAction::create( - CONTROL_PROTOCOL__ACTION_TYPE_t sub_action_type, uint8_t num_actions) -{ - CHECK_AS_EXPECTED(sub_action_type != CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_ADD_REPEATED, HAILO_INVALID_HEF, - "Invalid repeated sub-action type (can't have sub-action with type CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_ADD_REPEATED)"); - CHECK_AS_EXPECTED(sub_action_type != CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_COUNT, HAILO_INVALID_HEF, - "Invalid repeated sub-action type (can't have sub-action with type CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_COUNT)"); - CHECK_AS_EXPECTED(num_actions != 0, HAILO_INVALID_HEF, "Invalid sub-action count (must be greater than zero)"); - - auto result = ContextSwitchConfigActionPtr(new (std::nothrow) RepeatedHeaderAction( - sub_action_type, num_actions)); - CHECK_AS_EXPECTED((nullptr != result), HAILO_OUT_OF_HOST_MEMORY); - return result; -} - -RepeatedHeaderAction::RepeatedHeaderAction(CONTROL_PROTOCOL__ACTION_TYPE_t sub_action_type, - uint8_t num_actions) : - ContextSwitchConfigAction(Type::AddRrepeated, CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_ADD_REPEATED), - m_sub_action_type(sub_action_type), - m_num_actions(num_actions) -{} - -hailo_status RepeatedHeaderAction::execute(CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **context_meta_data_head_pointer) -{ - return HEF_METADATA__add_repeated_header_action(context_info, context_meta_data_head_pointer, - m_sub_action_type, m_num_actions); -} - -bool RepeatedHeaderAction::supports_repeated_block() const -{ - // RepeatedHeaderActions can't be part of a repated block themselves - return false; -} - -Expected DisableLcuAction::create(const ProtoHEFAction& proto_action) -{ - CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(proto_action.disable_lcu().cluster_index()), HAILO_INVALID_HEF, - "Failed to parse HEF. Invalid cluster_index: {}.", proto_action.disable_lcu().cluster_index()); - CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(proto_action.disable_lcu().lcu_index()), HAILO_INVALID_HEF, - "Failed to parse HEF. Invalid lcu_index: {}", proto_action.disable_lcu().lcu_index()); - - auto result = ContextSwitchConfigActionPtr(new (std::nothrow) DisableLcuAction(proto_action)); - CHECK_AS_EXPECTED((nullptr != result), HAILO_OUT_OF_HOST_MEMORY); - return result; -} - -DisableLcuAction::DisableLcuAction(const ProtoHEFAction& proto_action) : - ContextSwitchConfigAction(Type::DisableLcu, CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_DISABLE_LCU, proto_action) -{} - -hailo_status DisableLcuAction::execute(CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **context_meta_data_head_pointer) -{ - return HEF_METADATA__add_disable_lcu_action(context_info, context_meta_data_head_pointer, - static_cast(m_proto_action.disable_lcu().cluster_index()), - static_cast(m_proto_action.disable_lcu().lcu_index()), m_is_in_repeated_block); -} - -bool DisableLcuAction::supports_repeated_block() const -{ - return true; -} - -Expected EnableLcuAction::create(const ProtoHEFAction& proto_action, - const ResourcesManager &resources_manager, const ProtoHEFNetworkGroup &net_group) -{ - CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(proto_action.enable_lcu().cluster_index()), HAILO_INVALID_HEF, - "Failed to parse HEF. Invalid cluster_index: {}.", proto_action.enable_lcu().cluster_index()); - CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(proto_action.enable_lcu().lcu_index()), HAILO_INVALID_HEF, - "Failed to parse HEF. Invalid lcu_index: {}.", proto_action.enable_lcu().lcu_index()); - CHECK_AS_EXPECTED(IS_FIT_IN_UINT16(proto_action.enable_lcu().lcu_kernel_done_address()), HAILO_INVALID_HEF, - "Failed to parse HEF. Invalid lcu_kernel_done_address: {}.", proto_action.enable_lcu().lcu_kernel_done_address()); - - auto support_multi_networks = resources_manager.get_supported_features().multi_network_support; - auto network_index = static_cast((support_multi_networks) ? proto_action.enable_lcu().network_index() : 0); - auto partial_network_name = HefUtils::get_partial_network_name_by_index(net_group, network_index, - resources_manager.get_supported_features()); - CHECK_EXPECTED(partial_network_name); - - auto network_name = HefUtils::get_network_name(net_group, partial_network_name.value()); - - auto batch_size = resources_manager.get_network_batch_size(network_name); - CHECK_EXPECTED(batch_size); - const auto kernel_done_address = static_cast(proto_action.enable_lcu().lcu_kernel_done_address()); - const auto kernel_done_count = static_cast(proto_action.enable_lcu().lcu_kernel_done_count()); - const auto is_default = (CONTEXT_SWITCH_DEFS__ENABLE_LCU_DEFAULT_KERNEL_ADDRESS == kernel_done_address) && - (CONTEXT_SWITCH_DEFS__ENABLE_LCU_DEFAULT_KERNEL_COUNT == kernel_done_count); - - auto result = ContextSwitchConfigActionPtr(new (std::nothrow) EnableLcuAction(proto_action, is_default, network_index)); - CHECK_AS_EXPECTED((nullptr != result), HAILO_OUT_OF_HOST_MEMORY); - return result; -} - -CONTROL_PROTOCOL__ACTION_TYPE_t EnableLcuAction::get_enable_lcu_action_type(bool is_default) -{ - return is_default ? static_cast(CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_ENABLE_LCU_DEFAULT) : - static_cast(CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_ENABLE_LCU_NON_DEFAULT); -} - -ContextSwitchConfigAction::Type EnableLcuAction::get_enable_lcu_type(bool is_default) -{ - return is_default ? Type::EnableLcuDefault : Type::EnableLcuNonDefault; -} - -EnableLcuAction::EnableLcuAction(const ProtoHEFAction& proto_action, bool is_default, uint8_t network_index) : - ContextSwitchConfigAction(get_enable_lcu_type(is_default), get_enable_lcu_action_type(is_default), proto_action), - m_network_index(network_index), - m_is_default(is_default) -{} - -hailo_status EnableLcuAction::execute(CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **context_meta_data_head_pointer) -{ - const auto cluster_index = static_cast(m_proto_action.enable_lcu().cluster_index()); - const auto lcu_index = static_cast(m_proto_action.enable_lcu().lcu_index()); - if (m_is_default) { - return HEF_METADATA__add_enable_lcu_default_action(context_info, context_meta_data_head_pointer, - cluster_index, lcu_index, m_network_index, m_is_in_repeated_block); - } else { - const auto kernel_done_address = static_cast(m_proto_action.enable_lcu().lcu_kernel_done_address()); - const auto kernel_done_count = static_cast(m_proto_action.enable_lcu().lcu_kernel_done_count()); - return HEF_METADATA__add_enable_lcu_non_default_action(context_info, context_meta_data_head_pointer, - cluster_index, lcu_index, kernel_done_address, kernel_done_count, m_network_index, m_is_in_repeated_block); - } -} - -bool EnableLcuAction::supports_repeated_block() const -{ - return true; -} - -Expected EnableSequencerAction::create(const ProtoHEFAction& proto_action) -{ - CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(proto_action.enable_sequencer().cluster_index()), HAILO_INVALID_HEF, - "Failed to parse HEF. Invalid cluster_index: {}.", proto_action.enable_sequencer().cluster_index()); - - // TODO: Remove when impolemeted in the hef.proto - uint64_t l2_offset_0 = 0; - uint64_t l2_offset_1 = 0; - // TODO: Change the CONTEXT_SWITCH__add_enable_sequencer_proto_action func to receive 4 'l2_offset' params - l2_offset_0 |= (uint64_t)(proto_action.enable_sequencer().l2_write_0()); - l2_offset_0 |= ((uint64_t)(proto_action.enable_sequencer().l2_write_1()) << 32); - l2_offset_1 |= (uint64_t)(proto_action.enable_sequencer().l2_write_2()); - l2_offset_1 |= ((uint64_t)(proto_action.enable_sequencer().l2_write_3()) << 32); - - uint8_t initial_l3_cut = 0; - uint16_t initial_l3_offset = 0; - if (proto_action.enable_sequencer().initial_l3_info().includes_initial_l3_info()) { - const auto &initial_l3_info = proto_action.enable_sequencer().initial_l3_info(); - CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(initial_l3_info.initial_l3_index()), HAILO_INVALID_HEF, - "Initial l3 cut {} is out of range", initial_l3_info.initial_l3_index()); - CHECK_AS_EXPECTED(IS_FIT_IN_UINT16(initial_l3_info.initial_l3_offset()), HAILO_INVALID_HEF, - "Initial l3 offset {} is out of range", initial_l3_info.initial_l3_offset()); - initial_l3_cut = static_cast(initial_l3_info.initial_l3_index()); - initial_l3_offset = static_cast(initial_l3_info.initial_l3_offset()); - } - else { - // Legacy mode should work only on hailo8 - std::tie(initial_l3_cut, initial_l3_offset) = old_hef_parse_initial_l3(proto_action.enable_sequencer().initial_l3_legacy()); - } - - auto result = ContextSwitchConfigActionPtr(new (std::nothrow) EnableSequencerAction( - proto_action, - initial_l3_cut, - initial_l3_offset, - l2_offset_0, - l2_offset_1 - )); - CHECK_AS_EXPECTED((nullptr != result), HAILO_OUT_OF_HOST_MEMORY); - return result; -} - -EnableSequencerAction::EnableSequencerAction(const ProtoHEFAction& proto_action, uint8_t initial_l3_cut, uint16_t initial_l3_offset, - uint64_t l2_offset_0, uint64_t l2_offset_1) : - ContextSwitchConfigAction(Type::TriggerSequencer, CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_TRIGGER_SEQUENCER, proto_action), - m_initial_l3_cut(initial_l3_cut), - m_initial_l3_offset(initial_l3_offset), - m_l2_offset_0(l2_offset_0), - m_l2_offset_1(l2_offset_1) -{} - -hailo_status EnableSequencerAction::execute(CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **context_meta_data_head_pointer) -{ - const auto cluster_index = static_cast(m_proto_action.enable_sequencer().cluster_index()); - const auto active_apu_bitmap = static_cast(m_proto_action.enable_sequencer().active_apu_bitmap()); - const auto active_ia_bitmap = static_cast(m_proto_action.enable_sequencer().active_ia_bitmap()); - const auto active_sc_bitmap = static_cast(m_proto_action.enable_sequencer().active_sc_bitmap()); - const auto active_l2_bitmap = static_cast(m_proto_action.enable_sequencer().active_l2_bitmap()); - return HEF_METADATA__add_enable_sequencer_action(context_info, context_meta_data_head_pointer, - cluster_index, m_initial_l3_cut, m_initial_l3_offset, active_apu_bitmap, active_ia_bitmap, - active_sc_bitmap, active_l2_bitmap, m_l2_offset_0, m_l2_offset_1, m_is_in_repeated_block); -} - -bool EnableSequencerAction::supports_repeated_block() const -{ - return true; -} - -Expected WaitForSeqeuncerAction::create(const ProtoHEFAction& proto_action) -{ - CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(proto_action.wait_for_seqeuncer().cluster_index()), HAILO_INVALID_HEF, - "Failed to parse HEF. Invalid cluster_index: {}.", proto_action.wait_for_seqeuncer().cluster_index()); - - auto result = ContextSwitchConfigActionPtr(new (std::nothrow) WaitForSeqeuncerAction(proto_action)); - CHECK_AS_EXPECTED((nullptr != result), HAILO_OUT_OF_HOST_MEMORY); - return result; -} - -WaitForSeqeuncerAction::WaitForSeqeuncerAction(const ProtoHEFAction& proto_action) : - ContextSwitchConfigAction(Type::WaitForSequencerDone, CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_WAIT_FOR_SEQUENCER_DONE, proto_action) -{} - -hailo_status WaitForSeqeuncerAction::execute(CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **context_meta_data_head_pointer) -{ - return HEF_METADATA__add_wait_for_sequencer_action(context_info, context_meta_data_head_pointer, - static_cast(m_proto_action.wait_for_seqeuncer().cluster_index()), m_is_in_repeated_block); -} - -bool WaitForSeqeuncerAction::supports_repeated_block() const -{ - // Wait actions shouldn't be repeated (for easier debugging) - return false; -} - -Expected AllowInputDataflowAction::create(const ProtoHEFAction& proto_action) -{ - CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(proto_action.allow_input_dataflow().sys_index()), HAILO_INVALID_HEF, - "Failed to parse HEF. Invalid sys_index: {}.", proto_action.allow_input_dataflow().sys_index()); - - auto result = ContextSwitchConfigActionPtr(new (std::nothrow) AllowInputDataflowAction(proto_action)); - CHECK_AS_EXPECTED((nullptr != result), HAILO_OUT_OF_HOST_MEMORY); - return result; -} - -ContextSwitchConfigAction::Type AllowInputDataflowAction::get_input_dataflow_action_type(const ProtoHEFAction& proto_action) -{ - if (ProtoHEFEdgeConnectionType::PROTO__EDGE_CONNECTION_TYPE__DDR == proto_action.allow_input_dataflow().connection_type()) { - return Type::TriggerNewDataFromDataInputDdr; - } - return Type::TriggerNewDataFromDataInput; -} - -AllowInputDataflowAction::AllowInputDataflowAction(const ProtoHEFAction& proto_action) : - ContextSwitchConfigAction(get_input_dataflow_action_type(proto_action), - CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_TRIGGER_NEW_DATA_FROM_DATA_INPUT, proto_action) -{} - -hailo_status AllowInputDataflowAction::execute(CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **context_meta_data_head_pointer) -{ - // DDR threads are implemented on HailoRT so no FW action is required - if (Type::TriggerNewDataFromDataInputDdr == m_type) { - return HAILO_SUCCESS; - } - - return HEF_METADATA__add_fetch_new_data_action(context_info, context_meta_data_head_pointer, - static_cast(m_proto_action.allow_input_dataflow().sys_index()), m_is_in_repeated_block); -} - -bool AllowInputDataflowAction::supports_repeated_block() const -{ - // DDR threads are implemented on HailoRT so no FW action is required. Hence they can't be part of a repeated block. - if (Type::TriggerNewDataFromDataInputDdr == m_type) { - return false; + case ProtoHEFAction::kDisableLcu: { + // We ignore this action. the lcu_disable will happen in the nn_core reset before configuring specific network_group + break; + } + case ProtoHEFAction::kEnableLcu: { + WriteMemoryInfo write_memory_info = {}; + write_memory_info.address = action.enable_lcu().lcu_enable_address(); + auto data_buff = Buffer::create(ENABLE_LCU_CONTROL_WORD, sizeof(ENABLE_LCU_CONTROL_WORD)); + CHECK_EXPECTED(data_buff); + write_memory_info.data = data_buff.release(); + config_buffers.emplace_back(std::move(write_memory_info)); + break; + } + case ProtoHEFAction::kAllowInputDataflow: { + case ProtoHEFAction::kWaitForModuleConfigDone: + // We ignore the 'wait_for_interrupt' actions. After writing the configurations we can be sure everything is configured and dont need to wait for interrupts + break; + } + case ProtoHEFAction::kWaitForSeqeuncer: { + case ProtoHEFAction::kEnableSequencer: + LOGGER__ERROR("Parsing error. Sequencer related actions are not supported over Ethernet. " + "If you use the Ethernet interface, please disable the Sequencer in the Dataflow Compiler (SDK) and then re-create the HEF. " + "Disabling the Sequencer is done using the hef_param command in the model script (ALLS file). " + "See the Dataflow Compiler user guide for more information."); + return make_unexpected(HAILO_INVALID_HEF); + } + default: { + LOGGER__ERROR("Invalid action"); + return make_unexpected(HAILO_INTERNAL_FAILURE); + } + } + } } - return true; + return config_buffers; } -Expected WaitForModuleConfigDoneAction::create(const ProtoHEFAction& proto_action) +ProtoHEFHwArch Hef::Impl::get_device_arch() { - CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(proto_action.wait_for_module_config_done().index()), HAILO_INVALID_HEF, - "Failed to parse HEF. Invalid index: {}", proto_action.wait_for_module_config_done().index()); - - auto result = ContextSwitchConfigActionPtr(new (std::nothrow) WaitForModuleConfigDoneAction(proto_action)); - CHECK_AS_EXPECTED((nullptr != result), HAILO_OUT_OF_HOST_MEMORY); - return result; + return m_header.hw_arch(); } -WaitForModuleConfigDoneAction::WaitForModuleConfigDoneAction(const ProtoHEFAction& proto_action) : - ContextSwitchConfigAction(Type::WaitForModuleConfigDone, CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_WAIT_FOR_MODULE_CONFIG_DONE, proto_action) -{} - -hailo_status WaitForModuleConfigDoneAction::execute(CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **context_meta_data_head_pointer) +Expected Hef::Impl::get_bottleneck_fps(const std::string &net_group_name) { - return HEF_METADATA__add_wait_for_module_config_done_action(context_info, context_meta_data_head_pointer, - static_cast(m_proto_action.wait_for_module_config_done().index()), m_is_in_repeated_block); + auto core_op = get_core_op_by_net_group_name(net_group_name); + CHECK_EXPECTED(core_op); + return core_op.value()->network_group_metadata.bottleneck_fps(); } -bool WaitForModuleConfigDoneAction::supports_repeated_block() const +bool Hef::Impl::contains_ddr_layers(const ProtoHEFCoreOpMock& core_op) { - // Wait actions shouldn't be repeated (for easier debugging) + for (auto &context : core_op.contexts) { + for (auto &layer : context.metadata().edge_layers()) { + if (ProtoHEFEdgeConnectionType::PROTO__EDGE_CONNECTION_TYPE__DDR == + layer.context_switch_info().edge_connection_type()) { + return true; + } + } + } return false; } -Expected DdrPairInfoAction::create(const vdma::ChannelId &h2d_channel_id, - const vdma::ChannelId &d2h_channel_id, uint32_t descriptors_per_frame, uint16_t descs_count) -{ - auto result = ContextSwitchConfigActionPtr(new (std::nothrow) DdrPairInfoAction( - h2d_channel_id, d2h_channel_id, descriptors_per_frame, descs_count)); - CHECK_AS_EXPECTED((nullptr != result), HAILO_OUT_OF_HOST_MEMORY); - return result; -} - -DdrPairInfoAction::DdrPairInfoAction(const vdma::ChannelId &h2d_channel_id, const vdma::ChannelId &d2h_channel_id, - uint32_t descriptors_per_frame, uint16_t descs_count) : - ContextSwitchConfigAction(Type::DdrPairInfo, CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_ADD_DDR_PAIR_INFO), - m_h2d_channel_id(h2d_channel_id), - m_d2h_channel_id(d2h_channel_id), - m_descriptors_per_frame(descriptors_per_frame), - m_descs_count(descs_count) -{} - -hailo_status DdrPairInfoAction::execute(CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **context_meta_data_head_pointer) -{ - return HEF_METADATA__add_ddr_pair_info(context_info, context_meta_data_head_pointer, m_h2d_channel_id, - m_d2h_channel_id, m_descriptors_per_frame, m_descs_count, m_is_in_repeated_block); -} - -bool DdrPairInfoAction::supports_repeated_block() const -{ - return true; -} - -Expected StartDdrBufferingTaskAction::create() -{ - auto result = ContextSwitchConfigActionPtr(new (std::nothrow) StartDdrBufferingTaskAction()); - CHECK_AS_EXPECTED((nullptr != result), HAILO_OUT_OF_HOST_MEMORY); - return result; -} - -StartDdrBufferingTaskAction::StartDdrBufferingTaskAction() : - ContextSwitchConfigAction(Type::StartDdrBufferingTask, CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_ADD_DDR_BUFFERING_START) -{} - -hailo_status StartDdrBufferingTaskAction::execute(CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **context_meta_data_head_pointer) -{ - return HEF_METADATA__add_ddr_buffering_start(context_info, context_meta_data_head_pointer, m_is_in_repeated_block); -} - -bool StartDdrBufferingTaskAction::supports_repeated_block() const +Expected> Hef::Impl::get_stream_names_from_vstream_name(const std::string &vstream_name, + const std::string &net_group_name) { - // There should only be one "start ddr buffering task action" per context, - // so there's no need to support repeated blocks. - return false; -} + auto network_group_metadata = get_network_group_metadata(net_group_name); + CHECK_EXPECTED(network_group_metadata); -Expected EdgeLayerActivationActionsPositionMarker::create() -{ - auto result = ContextSwitchConfigActionPtr(new (std::nothrow) EdgeLayerActivationActionsPositionMarker()); - CHECK_AS_EXPECTED((nullptr != result), HAILO_OUT_OF_HOST_MEMORY); - return result; + return network_group_metadata->get_stream_names_from_vstream_name(vstream_name); } -EdgeLayerActivationActionsPositionMarker::EdgeLayerActivationActionsPositionMarker() : - ContextSwitchConfigAction(Type::EdgeLayerActivationActionsPositionMarker, - CONTROL_PROTOCOL__CONTEXT_SWITCH_ACTION_EDGE_LAYER_ACTIVATION_ACTIONS_POSITION) -{} - -hailo_status EdgeLayerActivationActionsPositionMarker::execute( - CONTROL_PROTOCOL__context_switch_context_info_t *context_info, uint8_t **context_meta_data_head_pointer) +Expected> Hef::Impl::get_vstream_names_from_stream_name(const std::string &stream_name, + const std::string &net_group_name) { - return HEF_METADATA__edge_layer_activation_actions_position_marker(context_info, context_meta_data_head_pointer, - m_is_in_repeated_block); -} + auto network_group_metadata = get_network_group_metadata(net_group_name); + CHECK_EXPECTED(network_group_metadata); -bool EdgeLayerActivationActionsPositionMarker::supports_repeated_block() const -{ - // There should only be one "edge layer activation actions position marker" per context, - // so there's no need to support repeated blocks. - return false; + return network_group_metadata->get_vstream_names_from_stream_name(stream_name); } Expected Hef::Impl::get_vstream_name_from_original_name_mux(const std::string &original_name, const ProtoHefEdge &layer) @@ -3371,12 +2350,12 @@ Expected Hef::Impl::get_vstream_name_from_original_name_mux(const s Expected Hef::Impl::get_vstream_name_from_original_name(const std::string &original_name, const std::string &net_group_name) { - auto net_group = get_net_group_by_name(net_group_name); - CHECK_EXPECTED(net_group); + auto core_op = get_core_op_by_net_group_name(net_group_name); + CHECK_EXPECTED(core_op); std::string results; - for (const auto &context : net_group.value()->contexts()) { + for (const auto &context : core_op.value()->contexts) { for (const auto &layer_info : context.metadata().edge_layers()) { if ((is_h2d_boundary_info_layer(layer_info)) || (is_d2h_boundary_info_layer(layer_info))) { for (auto &name : layer_info.layer_info().original_names()) { @@ -3431,12 +2410,12 @@ Expected> Hef::Impl::get_original_names_from_vstream_na Expected> Hef::Impl::get_original_names_from_vstream_name(const std::string &vstream_name, const std::string &net_group_name) { - auto net_group = get_net_group_by_name(net_group_name); - CHECK_EXPECTED(net_group); + auto copre_op = get_core_op_by_net_group_name(net_group_name); + CHECK_EXPECTED(copre_op); std::vector results; - for (const auto &context : net_group.value()->contexts()) { + for (const auto &context : copre_op.value()->contexts) { for (const auto &layer_info : context.metadata().edge_layers()) { if ((is_h2d_boundary_info_layer(layer_info)) || (is_d2h_boundary_info_layer(layer_info))) { if (vstream_name == layer_info.layer_info().name()) { @@ -3458,11 +2437,11 @@ Expected> Hef::Impl::get_original_names_from_vstream_na return make_unexpected(HAILO_NOT_FOUND); } -hailo_status Hef::Impl::validate_net_group_unique_layer_names(const ProtoHEFNetworkGroup &net_group) +hailo_status Hef::Impl::validate_core_op_unique_layer_names(const ProtoHEFCoreOpMock &core_op) { std::set edge_layer_names; std::string layer_name; - for (auto &context : net_group.contexts()) { + for (auto &context : core_op.contexts) { for (auto &layer : context.metadata().edge_layers()) { // TODO: remove check for boundary layer after fix will be pushed in SDK if (ProtoHEFEdgeConnectionType::PROTO__EDGE_CONNECTION_TYPE__BOUNDARY == @@ -3485,60 +2464,6 @@ hailo_status Hef::Impl::validate_net_group_unique_layer_names(const ProtoHEFNetw return HAILO_SUCCESS; } -hailo_status update_parsing_info(uint8_t cfg_index, uint32_t data_length, ConfigBufferInfoMap &results) -{ - CHECK(cfg_index < CONTROL_PROTOCOL__MAX_CFG_CHANNELS, HAILO_INVALID_HEF, "Invalid cfg_index"); - - if (contains(results, cfg_index)) { - results.at(cfg_index).push_back(data_length); - return HAILO_SUCCESS; - } - - // If we got here, the current cfg_index's info is parsed for the first time - results.emplace(cfg_index, std::vector(1, data_length)); - return HAILO_SUCCESS; -} - -Expected get_config_buffer_info( - const google::protobuf::RepeatedPtrField &operations) -{ - auto status = HAILO_UNINITIALIZED; - ConfigBufferInfoMap results; - - for (const auto &operation : operations) { - for (const auto &action : operation.actions()) { - if (ProtoHEFAction::kWriteDataCcw == action.action_case()) { - CHECK_AS_EXPECTED(IS_FIT_IN_UINT8(action.write_data_ccw().cfg_channel_index()), HAILO_INVALID_HEF, - "Invalid cfg index {}", action.write_data_ccw().cfg_channel_index()); - status = update_parsing_info(static_cast(action.write_data_ccw().cfg_channel_index()), - static_cast(action.write_data_ccw().data().length()), results); - CHECK_SUCCESS_AS_EXPECTED(status); - } - } - } - return results; -} - -Expected Hef::Impl::get_parsing_info(const ProtoHEFNetworkGroup &net_group) -{ - // Parse preliminary config - auto preliminary_config_buffer_infos = get_config_buffer_info(net_group.preliminary_config().operation()); - CHECK_EXPECTED(preliminary_config_buffer_infos); - - HefParsingInfo parsing_info; - parsing_info.cfg_infos_preliminary_config = preliminary_config_buffer_infos.release(); - - // Parse dynamic contexts - for (const auto &context : net_group.contexts()) { - auto dynamic_ctxt_config_buffer_infos = get_config_buffer_info(context.operations()); - CHECK_EXPECTED(dynamic_ctxt_config_buffer_infos); - - parsing_info.cfg_infos_per_context.emplace_back(dynamic_ctxt_config_buffer_infos.release()); - } - - return parsing_info; -} - std::vector Hef::get_network_groups_names() { return pimpl->get_network_groups_names(); @@ -3608,17 +2533,18 @@ Expected> Hef::get_network_groups_infos( Expected> Hef::Impl::get_network_groups_infos() { std::vector results; - results.reserve(m_groups.size()); + results.reserve(m_core_ops_per_group.size()); - for (const auto &net_group : m_groups) { + for (const auto &group_name_to_core_op : m_core_ops_per_group) { + const auto &core_op = group_name_to_core_op.second[0]; hailo_network_group_info_t info = {}; auto &network_group_name = (ProtoHEFHwArch::PROTO__HW_ARCH__HAILO8L == get_device_arch()) ? - net_group->partial_network_groups(0).network_group().network_group_metadata().network_group_name() - : net_group->network_group_metadata().network_group_name(); + core_op.partial_core_ops[0]->core_op->network_group_metadata.network_group_name() + : core_op.network_group_metadata.network_group_name(); CHECK_AS_EXPECTED(HAILO_MAX_NETWORK_GROUP_NAME_SIZE >= (network_group_name.length() + 1), HAILO_INTERNAL_FAILURE, "The network group '{}' has a too long name (max is HAILO_MAX_NETWORK_GROUP_NAME_SIZE)", network_group_name); strncpy(info.name, network_group_name.c_str(), network_group_name.length() + 1); - info.is_multi_context = (1 < net_group->contexts_size()); + info.is_multi_context = (1 < core_op.contexts.size()); results.push_back(info); } return results; @@ -3764,16 +2690,12 @@ Expected> Hef::Impl::create_str CHECK_EXPECTED(network_group_metadata); std::map results; - auto input_layers_info = network_group_metadata->get_input_layer_infos(); - CHECK_EXPECTED(input_layers_info); - for (auto &input_layer : input_layers_info.value()) { + for (auto &input_layer : network_group_metadata->get_input_layer_infos()) { auto params = HailoRTDefaults::get_stream_parameters(stream_interface, HAILO_H2D_STREAM); CHECK_EXPECTED(params); results.emplace(std::make_pair(input_layer.name, params.release())); } - auto output_layers_info = network_group_metadata->get_output_layer_infos(); - CHECK_EXPECTED(output_layers_info); - for (auto &output_layer : output_layers_info.value()) { + for (auto &output_layer : network_group_metadata->get_output_layer_infos()) { auto params = HailoRTDefaults::get_stream_parameters(stream_interface, HAILO_D2H_STREAM); CHECK_EXPECTED(params); results.emplace(std::make_pair(output_layer.name, params.release())); @@ -3791,18 +2713,18 @@ Expected> Hef::create_network_ Expected> Hef::Impl::create_network_parameters_by_name( const std::string &net_group_name) { - auto net_group = get_net_group_by_name(net_group_name); - CHECK_EXPECTED(net_group); + auto core_op = get_core_op_by_net_group_name(net_group_name); + CHECK_EXPECTED(core_op); - auto network_gorup_metadata = get_network_group_metadata(net_group_name); - CHECK_EXPECTED(network_gorup_metadata); + auto network_group_metadata = get_network_group_metadata(net_group_name); + CHECK_EXPECTED(network_group_metadata); std::map results; - if (network_gorup_metadata->supported_features().multi_network_support) { - CHECK_AS_EXPECTED((net_group.value()->networks_names_size() != 0), HAILO_INTERNAL_FAILURE, + if (network_group_metadata->supported_features().multi_network_support) { + CHECK_AS_EXPECTED((core_op.value()->networks_names.size() != 0), HAILO_INTERNAL_FAILURE, "Hef support multiple networks, but no networks found in the proto"); - for (const auto &partial_network_name : net_group.value()->networks_names()) { + for (const auto &partial_network_name : core_op.value()->networks_names) { auto network_name = HefUtils::get_network_name(net_group_name, partial_network_name); auto params = HailoRTDefaults::get_network_parameters(); results.emplace(std::make_pair(network_name, params)); @@ -3836,18 +2758,14 @@ Expected> Hef::Impl::create_str CHECK_EXPECTED(network_group_metadata); std::map results; - auto input_layers_info = network_group_metadata->get_input_layer_infos(); - CHECK_EXPECTED(input_layers_info); - for (auto &input_layer : input_layers_info.value()) { + for (auto &input_layer : network_group_metadata->get_input_layer_infos()) { hailo_stream_parameters_t params = {}; params.direction = HAILO_H2D_STREAM; params.stream_interface = HAILO_STREAM_INTERFACE_MIPI; params.mipi_input_params = mipi_params; results.emplace(std::make_pair(input_layer.name, params)); } - auto output_layers_info = network_group_metadata->get_output_layer_infos(); - CHECK_EXPECTED(output_layers_info); - for (auto &output_layer : output_layers_info.value()) { + for (auto &output_layer : network_group_metadata->get_output_layer_infos()) { auto params = HailoRTDefaults::get_stream_parameters(output_interface, HAILO_D2H_STREAM); CHECK_EXPECTED(params); results.emplace(std::make_pair(output_layer.name, params.release())); @@ -3856,285 +2774,4 @@ Expected> Hef::Impl::create_str return results; } -NetworkGroupMetadata::NetworkGroupMetadata(const std::string &network_group_name, - std::vector> &&boundary_input_layers, - std::vector> &&boundary_output_layers, - std::vector> &&inter_context_input_layers, - std::vector> &&inter_context_output_layers, - std::vector> &&ddr_input_layers, - std::vector> &&ddr_output_layers, - std::vector &&sorted_output_names, - NetworkGroupSupportedFeatures &supported_features, const std::vector &sorted_network_names) - : m_boundary_input_layers(std::move(boundary_input_layers)), - m_boundary_output_layers(std::move(boundary_output_layers)), - m_inter_context_input_layers(std::move(inter_context_input_layers)), - m_inter_context_output_layers(std::move(inter_context_output_layers)), - m_ddr_input_layers(std::move(ddr_input_layers)), - m_ddr_output_layers(std::move(ddr_output_layers)), - m_network_group_name(network_group_name), m_sorted_output_names(std::move(sorted_output_names)), - m_supported_features(supported_features), m_sorted_network_names(sorted_network_names) {} - -Expected NetworkGroupMetadata::get_layer_info_by_stream_name(const std::string &stream_name) const -{ - auto layer_infos = get_all_layer_infos(); - CHECK_EXPECTED(layer_infos); - for (auto layer_info : layer_infos.release()) { - if (layer_info.name == stream_name) { - return layer_info; - } - } - LOGGER__ERROR("Failed to find layer with name {}", stream_name); - return make_unexpected(HAILO_NOT_FOUND); -} - -Expected> NetworkGroupMetadata::get_input_layer_infos(const std::string &network_name) const -{ - std::vector res; - for (auto &context_layer_infos : m_boundary_input_layers) { - for (auto &layer_info : context_layer_infos) { - if ((layer_info.network_name == network_name) || (network_name.empty()) || (network_name == default_network_name())) { - res.emplace_back(layer_info); - } - } - } - CHECK_AS_EXPECTED(res.size() > 0, HAILO_NOT_FOUND, "Network name {} is not found in networks metadata", network_name); - return res; -} - -Expected> NetworkGroupMetadata::get_output_layer_infos(const std::string &network_name) const -{ - std::vector res; - for (auto &context_layer_infos : m_boundary_output_layers) { - for (auto &layer_info : context_layer_infos) { - if ((layer_info.network_name == network_name) || (network_name.empty()) || (network_name == default_network_name())) { - res.emplace_back(layer_info); - } - } - } - CHECK_AS_EXPECTED(res.size() > 0, HAILO_NOT_FOUND, "Network name {} is not found in networks metadata", network_name); - return res; -} - -std::vector NetworkGroupMetadata::get_boundary_input_layer_infos(const uint8_t context_index) const -{ - return m_boundary_input_layers[context_index]; -} - -std::vector NetworkGroupMetadata::get_boundary_output_layer_infos(const uint8_t context_index) const -{ - return m_boundary_output_layers[context_index]; -} - -std::vector NetworkGroupMetadata::get_inter_context_input_layer_infos(const uint8_t context_index) const -{ - return m_inter_context_input_layers[context_index]; -} - -std::vector NetworkGroupMetadata::get_inter_context_output_layer_infos(const uint8_t context_index) const -{ - return m_inter_context_output_layers[context_index]; -} - -std::vector NetworkGroupMetadata::get_ddr_input_layer_infos(const uint8_t context_index) const -{ - return m_ddr_input_layers[context_index]; -} - -std::vector NetworkGroupMetadata::get_ddr_output_layer_infos(const uint8_t context_index) const -{ - return m_ddr_output_layers[context_index]; -} - -Expected> NetworkGroupMetadata::get_all_layer_infos(const std::string &network_name) const -{ - auto input_layer_infos = get_input_layer_infos(network_name); - CHECK_EXPECTED(input_layer_infos); - - auto output_layer_infos = get_output_layer_infos(network_name); - CHECK_EXPECTED(output_layer_infos); - - std::vector res; - res.reserve(input_layer_infos->size() + output_layer_infos->size()); - res.insert(res.end(), input_layer_infos->begin(), input_layer_infos->end()); - res.insert(res.end(), output_layer_infos->begin(), output_layer_infos->end()); - - return res; -} - -Expected> NetworkGroupMetadata::get_input_stream_infos(const std::string &network_name) const -{ - auto input_layer_infos = get_input_layer_infos(network_name); - CHECK_EXPECTED(input_layer_infos); - - return convert_layer_infos_to_stream_infos(input_layer_infos.value()); -} - -Expected> NetworkGroupMetadata::get_output_stream_infos(const std::string &network_name) const -{ - auto output_layer_infos = get_output_layer_infos(network_name); - CHECK_EXPECTED(output_layer_infos); - - return convert_layer_infos_to_stream_infos(output_layer_infos.value()); -} - -Expected> NetworkGroupMetadata::get_all_stream_infos(const std::string &network_name) const -{ - auto input_stream_infos = get_input_stream_infos(network_name); - CHECK_EXPECTED(input_stream_infos); - - auto output_stream_infos = get_output_stream_infos(network_name); - CHECK_EXPECTED(output_stream_infos); - - std::vector res; - res.reserve(input_stream_infos->size() + output_stream_infos->size()); - res.insert(res.end(), input_stream_infos->begin(), input_stream_infos->end()); - res.insert(res.end(), output_stream_infos->begin(), output_stream_infos->end()); - - return res; -} - -Expected> NetworkGroupMetadata::get_input_vstream_infos(const std::string &network_name) const -{ - auto input_layer_infos = get_input_layer_infos(network_name); - CHECK_EXPECTED(input_layer_infos); - - return convert_layer_infos_to_vstream_infos(input_layer_infos.value()); -} - -Expected> NetworkGroupMetadata::get_output_vstream_infos(const std::string &network_name) const -{ - auto output_layer_infos = get_output_layer_infos(network_name); - CHECK_EXPECTED(output_layer_infos); - - auto res = convert_layer_infos_to_vstream_infos(output_layer_infos.value()); - - hailo_status status = HAILO_SUCCESS; - std::sort(res.begin(), res.end(), - [this, &status](const auto &info1, const auto &info2) - { - const auto index1 = std::find(m_sorted_output_names.begin(), m_sorted_output_names.end(), std::string(info1.name)); - const auto index2 = std::find(m_sorted_output_names.begin(), m_sorted_output_names.end(), std::string(info2.name)); - - if (m_sorted_output_names.end() == index1) { - LOGGER__ERROR("Stream {} not found in sorted output names", info1.name); - status = HAILO_INTERNAL_FAILURE; - return false; - } - - if (m_sorted_output_names.end() == index2) { - LOGGER__ERROR("Stream {} not found in sorted output names", info2.name); - status = HAILO_INTERNAL_FAILURE; - return false; - } - - return index1 < index2; - }); - CHECK_SUCCESS_AS_EXPECTED(status); - - return res; -} - -Expected> NetworkGroupMetadata::get_all_vstream_infos(const std::string &network_name) const -{ - auto input_vstream_infos = get_input_vstream_infos(network_name); - CHECK_EXPECTED(input_vstream_infos); - - auto output_vstream_infos = get_output_vstream_infos(network_name); - CHECK_EXPECTED(output_vstream_infos); - - std::vector res; - res.reserve(input_vstream_infos->size() + output_vstream_infos->size()); - res.insert(res.end(), input_vstream_infos->begin(), input_vstream_infos->end()); - res.insert(res.end(), output_vstream_infos->begin(), output_vstream_infos->end()); - - return res; -} - -Expected> NetworkGroupMetadata::get_vstream_names_from_stream_name(const std::string &stream_name) const -{ - std::vector results; - auto all_layer_infos = get_all_layer_infos(); - CHECK_EXPECTED(all_layer_infos); - - for (auto &layer_info : all_layer_infos.value()) { - if (stream_name == layer_info.name) { - if (layer_info.is_defused_nms) { - return std::vector (1, layer_info.fused_nms_layer[0].name); - } else if (layer_info.is_mux) { - return get_demuxes_names(layer_info); - } else { - return std::vector (1, layer_info.name); - } - } - } - return make_unexpected(HAILO_NOT_FOUND); -} - -Expected> NetworkGroupMetadata::get_stream_names_from_vstream_name(const std::string &vstream_name) const -{ - std::vector results; - auto all_layer_infos = get_all_layer_infos(); - CHECK_EXPECTED(all_layer_infos); - - for (auto &layer_info : all_layer_infos.value()) { - if (layer_info.is_mux) { - if (is_edge_under_mux(layer_info, vstream_name)) { - // vstream_name is a demux of the layer info - results.push_back(layer_info.name); - } - } else if (layer_info.is_defused_nms) { - if (vstream_name == layer_info.fused_nms_layer[0].name) { - // vstream_name is the fused-layer of the layer info - results.push_back(layer_info.name); - } - } else if (vstream_name == layer_info.name) { - // vstream_name is a regular stream - results.push_back(layer_info.name); - } - } - CHECK_AS_EXPECTED(0 < results.size(), HAILO_NOT_FOUND); - return results; -} - -std::vector NetworkGroupMetadata::convert_layer_infos_to_stream_infos(const std::vector &layer_infos) const -{ - std::vector res; - for (auto &layer_info : layer_infos) { - res.push_back(LayerInfoUtils::get_stream_info_from_layer_info(layer_info)); - } - return res; -} - -std::vector NetworkGroupMetadata::convert_layer_infos_to_vstream_infos(const std::vector &layer_infos) const -{ - std::vector res; - for (auto &layer_info : layer_infos) { - auto vstream_infos = LayerInfoUtils::get_vstream_infos_from_layer_info(layer_info); - for (const auto &vstream_info : vstream_infos) { - // In case of fused nms layers, several LayerInfos will contain data about the same fused layer - if (!LayerInfoUtils::vstream_info_already_in_vector(res, vstream_info.name)) { - res.push_back(vstream_info); - } - } - } - return res; -} - -Expected> NetworkGroupMetadata::get_network_infos() const -{ - std::vector network_infos; - auto net_group_name = network_group_name(); - network_infos.reserve(m_sorted_network_names.size()); - for (auto const &network_name : m_sorted_network_names) { - hailo_network_info_t network_info = {}; - CHECK_AS_EXPECTED(HAILO_MAX_NETWORK_NAME_SIZE >= (network_name.length() + 1), HAILO_INTERNAL_FAILURE, - "The network '{}' has a too long name (max is HAILO_MAX_NETWORK_NAME_SIZE)", network_name); - memcpy(network_info.name, network_name.c_str(), network_name.length() + 1); - - network_infos.push_back(network_info); - } - - return network_infos; -} - } /* namespace hailort */ diff --git a/hailort/libhailort/src/hef_internal.hpp b/hailort/libhailort/src/hef_internal.hpp index 0fb83ad..f73882b 100644 --- a/hailort/libhailort/src/hef_internal.hpp +++ b/hailort/libhailort/src/hef_internal.hpp @@ -29,10 +29,12 @@ #include "hailo/expected.hpp" #include "hailo/hef.hpp" #include "hailo/network_group.hpp" -#include "context_switch/active_network_group_holder.hpp" +#include "context_switch/context_switch_actions.hpp" #include "layer_info.hpp" +#include "network_group_metadata.hpp" #include "hailort_defaults.hpp" #include "control_protocol.h" +#include "pipeline.hpp" #include "control_protocol.hpp" @@ -49,10 +51,61 @@ namespace hailort class ResourcesManager; class ConfigBuffer; -class VdmaConfigActivatedNetworkGroup; -using VdmaConfigActiveAppHolder = ActiveNetworkGroupHolder; using ProtoHEFNetworkGroupPtr = std::shared_ptr; +struct ProtoHEFCoreOpMock; +struct ProtoHEFPartialCoreOpMock { + ProtoHEFPartialCoreOpMock(std::shared_ptr core_op, const ProtoHEFPhysicalLayout &layout) + : core_op(core_op) + , layout(layout) + {} + + ProtoHEFPartialCoreOpMock(const ProtoHEFPartialCoreOpMock &partial_core_op) + : core_op(partial_core_op.core_op) + , layout(partial_core_op.layout) + {} + + std::shared_ptr core_op; + const ProtoHEFPhysicalLayout &layout; +}; + +struct ProtoHEFCoreOpMock { + ProtoHEFCoreOpMock( + const ProtoHEFNetworkGroupMetadata &network_group_metadata, + const ProtoHEFPreliminaryConfig &preliminary_config, + const google::protobuf::RepeatedPtrField &contexts, + const google::protobuf::RepeatedPtrField &sorted_outputs_order, + const ProtoHEFFusedLayersMetadata &fused_layers_metadata, + const google::protobuf::RepeatedPtrField &networks_names, + const std::vector> &partial_core_ops) + : network_group_metadata(network_group_metadata), + preliminary_config(preliminary_config), + contexts(contexts), + sorted_outputs_order(sorted_outputs_order), + fused_layers_metadata(fused_layers_metadata), + networks_names(networks_names), + partial_core_ops(partial_core_ops) + {} + + ProtoHEFCoreOpMock(const ProtoHEFCoreOpMock &core_op) + : network_group_metadata(core_op.network_group_metadata), + preliminary_config(core_op.preliminary_config), + contexts(core_op.contexts), + sorted_outputs_order(core_op.sorted_outputs_order), + fused_layers_metadata(core_op.fused_layers_metadata), + networks_names(core_op.networks_names), + partial_core_ops(core_op.partial_core_ops) + {} + + const ProtoHEFNetworkGroupMetadata &network_group_metadata; + const ProtoHEFPreliminaryConfig &preliminary_config; + const google::protobuf::RepeatedPtrField &contexts; + const google::protobuf::RepeatedPtrField &sorted_outputs_order; + const ProtoHEFFusedLayersMetadata &fused_layers_metadata; + const google::protobuf::RepeatedPtrField &networks_names; + std::vector> partial_core_ops; +}; + #pragma pack(push, 1) typedef struct { uint32_t magic; @@ -75,7 +128,6 @@ typedef enum { } HEF__net_io_formatter_type_t; -using ConfigBufferInfoMap = std::unordered_map>; const static uint32_t SUPPORTED_EXTENSIONS_BITSET_SIZE = 1000; static const std::vector SUPPORTED_EXTENSIONS = { ABBALE, @@ -87,27 +139,11 @@ static const std::vector SUPPORTED_EXTENSIONS = { TRANSPOSE_COMPONENT, IS_NMS_MULTI_CONTEXT, OFFLOAD_ARGMAX, - KO_RUN_ASAP // Extention added in platform 4.8 release + KO_RUN_ASAP, + HAILO_NET_FLOW, + HAILO_NET_FLOW_YOLO_NMS // Extention added in platform 4.12 release }; -struct HefParsingInfo -{ - ConfigBufferInfoMap cfg_infos_preliminary_config; - // cfg_count_per_context[ctxt_index][cfg_index] - std::vector cfg_infos_per_context; - // TODO: add information about boundary channels here, so they can be allocated in init time instead of activation time - // TODO: Save this struct inside network_group class -}; - -struct NetworkGroupSupportedFeatures { - bool padded_ddr_buffers; - bool multi_network_support; - bool multi_context; - bool preliminary_run_asap; -}; - -static uint32_t PARTIAL_CLUSTERS_LAYOUT_IGNORE = static_cast(-1); - static inline bool is_h2d_boundary_info_layer(const ProtoHEFEdgeLayer& layer) { return ((ProtoHEFEdgeLayerDirection::PROTO__EDGE_LAYER_DIRECTION__HOST_TO_DEVICE == layer.direction()) && @@ -151,114 +187,6 @@ class VdmaConfigNetworkGroup; class VdmaDevice; class HailoRTDriver; -class NetworkGroupMetadata { -public: - NetworkGroupMetadata() = default; - NetworkGroupMetadata(const std::string &network_group_name, - std::vector> &&boundary_input_layers, - std::vector> &&boundary_output_layers, - std::vector> &&inter_context_input_layers, - std::vector> &&inter_context_output_layers, - std::vector> &&ddr_input_layers, - std::vector> &&ddr_output_layers, - std::vector &&sorted_output_names, - NetworkGroupSupportedFeatures &supported_features, - const std::vector &sorted_network_names); - - Expected> get_input_layer_infos(const std::string &network_name = "") const; - Expected> get_output_layer_infos(const std::string &network_name = "") const; - Expected> get_all_layer_infos(const std::string &network_name = "") const; - Expected get_layer_info_by_stream_name(const std::string &stream_name) const; - - std::vector get_boundary_input_layer_infos(const uint8_t context_index) const; - std::vector get_boundary_output_layer_infos(const uint8_t context_index) const; - std::vector get_inter_context_input_layer_infos(const uint8_t context_index) const; - std::vector get_inter_context_output_layer_infos(const uint8_t context_index) const; - std::vector get_ddr_input_layer_infos(const uint8_t context_index) const; - std::vector get_ddr_output_layer_infos(const uint8_t context_index) const; - - Expected> get_input_stream_infos(const std::string &network_name = "") const; - Expected> get_output_stream_infos(const std::string &network_name = "") const; - Expected> get_all_stream_infos(const std::string &network_name = "") const; - - Expected> get_input_vstream_infos(const std::string &network_name = "") const; - Expected> get_output_vstream_infos(const std::string &network_name = "") const; - Expected> get_all_vstream_infos(const std::string &network_name = "") const; - - Expected> get_vstream_names_from_stream_name(const std::string &stream_name) const; - Expected> get_stream_names_from_vstream_name(const std::string &vstream_name) const; - - Expected> get_network_infos() const; - - const std::string &network_group_name() const - { - return m_network_group_name; - } - - const std::string default_network_name() const - { - return HailoRTDefaults::get_network_name(m_network_group_name); - } - - const std::vector get_sorted_output_names() const - { - return m_sorted_output_names; - } - - const NetworkGroupSupportedFeatures &supported_features() const - { - return m_supported_features; - } - - const std::vector get_network_names() const - { - return m_sorted_network_names; - } - -private: - std::vector convert_layer_infos_to_stream_infos(const std::vector &layer_infos) const; - std::vector convert_layer_infos_to_vstream_infos(const std::vector &layer_infos) const; - - // vector of edge layers Per context - std::vector> m_boundary_input_layers; - std::vector> m_boundary_output_layers; - std::vector> m_inter_context_input_layers; - std::vector> m_inter_context_output_layers; - std::vector> m_ddr_input_layers; - std::vector> m_ddr_output_layers; - - std::string m_network_group_name; - std::vector m_sorted_output_names; - NetworkGroupSupportedFeatures m_supported_features; - std::vector m_sorted_network_names; -}; - -class NetworkGroupMetadataPerArch -{ -public: - NetworkGroupMetadataPerArch() = default; - Expected get_metadata(uint32_t partial_clusters_layout_bitmap) - { - if (PARTIAL_CLUSTERS_LAYOUT_IGNORE == partial_clusters_layout_bitmap) { - // Passing PARTIAL_CLUSTERS_LAYOUT_IGNORE is magic for getting one of the metadata - assert(0 != m_metadata_per_arch.size()); - auto result = m_metadata_per_arch.begin()->second; - return result; - } - if (contains(m_metadata_per_arch, partial_clusters_layout_bitmap)) { - auto result = m_metadata_per_arch[partial_clusters_layout_bitmap]; - return result; - } - LOGGER__ERROR("NetworkGroupMetadataPerArch does not contain metadata for partial_clusters_layout_bitmap {}", partial_clusters_layout_bitmap); - return make_unexpected(HAILO_INTERNAL_FAILURE); - } - void add_metadata(const NetworkGroupMetadata &metadata, uint32_t partial_clusters_layout_bitmap) - { - m_metadata_per_arch[partial_clusters_layout_bitmap] = metadata; - } -private: - std::map m_metadata_per_arch; -}; class Hef::Impl final { @@ -270,10 +198,12 @@ public: static Expected create(const MemoryView &hef_buffer); const std::vector& network_groups() const; + const std::vector& core_ops(const std::string &net_group_name) const; + const std::vector> post_process_ops(const std::string &net_group_name) const; Expected> get_network_group_and_network_name(const std::string &name); - Expected get_net_group_by_name(const std::string &net_group_name=""); + Expected> get_core_op_by_net_group_name(const std::string &net_group_name=""); Expected> get_network_infos(const std::string &net_group_name=""); Expected> get_input_stream_infos(const std::string &net_group_name="", @@ -296,8 +226,8 @@ public: Expected get_number_of_output_streams(const std::string &net_group_name=""); ProtoHEFHwArch get_device_arch(); Expected get_bottleneck_fps(const std::string &net_group_name=""); - static bool contains_ddr_layers(const ProtoHEFNetworkGroup& net_group); - static hailo_status validate_net_group_unique_layer_names(const ProtoHEFNetworkGroup &net_group); + static bool contains_ddr_layers(const ProtoHEFCoreOpMock &net_group); + static hailo_status validate_core_op_unique_layer_names(const ProtoHEFCoreOpMock &core_op); Expected> get_network_input_vstream_infos(const std::string &net_group_name="", const std::string &network_name=""); @@ -321,12 +251,8 @@ public: static Expected> create_single_context_network_group_config( const ProtoHEFPreliminaryConfig& proto_config); - /* TODO HRT-5067 - work with hailo_device_architecture_t instead of ProtoHEFHwArch */ - static Expected> create_resources_manager( - const ProtoHEFNetworkGroup &network_group_proto, uint8_t net_group_index, - VdmaDevice &device, HailoRTDriver &driver, const ConfigureNetworkParams &network_group_params, - std::shared_ptr network_group_metadata, - const ProtoHEFHwArch &hw_arch); + static Expected> get_core_op_per_arch(const ProtoHEFCoreOpMock &base_net_group, + ProtoHEFHwArch hef_arch, hailo_device_architecture_t device_arch, uint32_t partial_clusters_layout_bitmap); Expected> create_stream_parameters_by_name( const std::string &net_group_name, hailo_stream_interface_t stream_interface); @@ -353,6 +279,10 @@ public: static hailo_status fill_missing_vstream_params_with_default(std::map &vstream_params, std::vector &name_to_format_info, bool quantized, hailo_format_type_t format_type, uint32_t timeout_ms, uint32_t queue_size); + // Also adds information to NetworkGroupMetadata + Expected>> create_network_group_ops(const ProtoHEFNetworkGroup &network_group_proto, + NetworkGroupMetadata &network_group_meta_data) const; + Expected get_network_group_metadata(const std::string &network_group_name, uint32_t partial_clusters_layout_bitmap = PARTIAL_CLUSTERS_LAYOUT_IGNORE) { @@ -368,6 +298,49 @@ public: return m_md5; } + static hailo_status update_network_batch_size(ConfigureNetworkParams &network_group_config_params) + { + static_assert(HAILO_DEFAULT_BATCH_SIZE == 0, "Invalid HAILO_DEFAULT_BATCH_SIZE"); + + auto single_network_default_batch = (HAILO_DEFAULT_BATCH_SIZE == network_group_config_params.batch_size); + auto multi_network_default_batch = true; + /* Batch size overide logic - if user modifies network group batch size + and not the network batch size, */ + + for (auto const &network_params : network_group_config_params.network_params_by_name) { + if (HAILO_DEFAULT_BATCH_SIZE != network_params.second.batch_size) { + multi_network_default_batch = false; + } + } + + CHECK((single_network_default_batch || multi_network_default_batch), HAILO_INVALID_OPERATION, + "User provided batch size for network group and for network as well. User is adviced to work with network's batch size only"); + + if (!single_network_default_batch && multi_network_default_batch) { + /* In case user works with network group, overide the network batch size.*/ + for (auto &network_params : network_group_config_params.network_params_by_name) { + network_params.second.batch_size = network_group_config_params.batch_size; + } + } + + return HAILO_SUCCESS; + } + + hailo_status validate_boundary_streams_were_created(const std::string &network_group_name, ConfiguredNetworkGroup &network_group) + { + auto number_of_inputs = get_number_of_input_streams(network_group_name); + CHECK_EXPECTED_AS_STATUS(number_of_inputs); + CHECK((number_of_inputs.value() == network_group.get_input_streams().size()), + HAILO_INVALID_ARGUMENT, "passed configure_params for network group {} did not contain all input streams", network_group_name); + + auto number_of_outputs = get_number_of_output_streams(network_group_name); + CHECK_EXPECTED_AS_STATUS(number_of_inputs); + CHECK((number_of_outputs.value() == network_group.get_output_streams().size()), + HAILO_INVALID_ARGUMENT, "passed configure_params for network group {} did not contain all output streams", network_group_name); + + return HAILO_SUCCESS; + } + #ifdef HAILO_SUPPORT_MULTI_PROCESS const MemoryView get_hef_memview(); #endif // HAILO_SUPPORT_MULTI_PROCESS @@ -379,6 +352,7 @@ private: hailo_status parse_hef_file(const std::string &hef_path); hailo_status parse_hef_memview(const MemoryView &hef_memview); hailo_status transfer_protobuf_field_ownership(ProtoHEFHef &hef_message); + void fill_core_ops(); hailo_status fill_networks_metadata(); void fill_extensions_bitset(); void init_md5(MD5_SUM_t &calculated_md5); @@ -388,13 +362,12 @@ private: // Note: If the network group is found, i.e has_value() is true on the returned object, then the underlying pointer is not null static bool check_hef_optional_extension(const ProtoHEFExtensionType &extension, const ProtoHEFHeader &header, const std::vector &hef_optional_extensions); - static NetworkGroupSupportedFeatures get_supported_features(const ProtoHEFHeader &header, + static SupportedFeatures get_supported_features(const ProtoHEFHeader &header, const std::vector &hef_extensions, const ProtoHEFIncludedFeatures &included_features, const std::vector &hef_optional_extensions); hailo_status validate_hef_extensions(); static hailo_status validate_hef_header(const hef__header_t &header, MD5_SUM_t &calculated_md5, size_t proto_size); - static Expected get_parsing_info(const ProtoHEFNetworkGroup &net_group); Expected> get_inputs_vstream_names_and_format_info( const std::string &net_group_name, const std::string &network_name); @@ -404,12 +377,15 @@ private: static Expected get_vstream_name_from_original_name_mux(const std::string &original_name, const ProtoHefEdge &layer); static Expected> get_original_names_from_vstream_name_mux(const std::string &vstream_name, const ProtoHefEdge &layer); - Expected create_metadata_per_arch(const ProtoHEFNetworkGroup &network_group, NetworkGroupSupportedFeatures &supported_features); + Expected create_metadata_per_arch(const ProtoHEFCoreOpMock &core_op); // Hef information ProtoHEFHeader m_header; ProtoHEFIncludedFeatures m_included_features; + SupportedFeatures m_supported_features; std::vector m_groups; + std::map> m_core_ops_per_group; + std::map>> m_post_process_ops_per_group; std::vector m_hef_extensions; std::vector m_hef_optional_extensions; std::bitset m_supported_extensions_bitset; @@ -420,7 +396,7 @@ private: #endif // HAILO_SUPPORT_MULTI_PROCESS // NetworkGroups information - std::map m_network_group_metadata_per_arch; + std::map m_network_group_metadata_per_arch; // TODO: keep meta data per core_op (HRT-8639) }; // TODO: Make this part of a namespace? (HRT-2881) @@ -453,57 +429,51 @@ public: HefUtils() = delete; static hailo_status fill_boundary_layers_info( - const ProtoHEFNetworkGroup &network_group_proto, + const ProtoHEFCoreOpMock &core_op, const uint8_t context_index, const ProtoHEFEdgeLayer &layer, - const NetworkGroupSupportedFeatures &supported_features, - std::vector &layer_name, - std::vector &context_boundary_input_layers, - std::vector &context_boundary_output_layers); - static Expected get_inter_context_layer_info( - const ProtoHEFNetworkGroup &net_group, const uint8_t context_index, - const ProtoHEFEdgeLayer &layer, const NetworkGroupSupportedFeatures &supported_features); + const SupportedFeatures &supported_features, + ContextMetadata &context_metadata); + static Expected get_inter_context_layer_info( + const ProtoHEFCoreOpMock &core_op, const uint8_t context_index, + const ProtoHEFEdgeLayer &layer, const SupportedFeatures &supported_features); static hailo_status fill_inter_context_layers_info( - const ProtoHEFNetworkGroup &network_group_proto, + const ProtoHEFCoreOpMock &core_op, const uint8_t context_index, const ProtoHEFEdgeLayer &layer, - const NetworkGroupSupportedFeatures &supported_features, - std::vector &context_inter_context_input_layers, - std::vector &context_inter_context_output_layers); - static Expected get_ddr_layer_info( - const ProtoHEFNetworkGroup &net_group, const uint8_t context_index, - const ProtoHEFEdgeLayer &layer, const NetworkGroupSupportedFeatures &supported_features); + const SupportedFeatures &supported_features, + ContextMetadata &context_metadata); + static Expected get_ddr_layer_info( + const ProtoHEFCoreOpMock &core_op, const uint8_t context_index, + const ProtoHEFEdgeLayer &layer, const SupportedFeatures &supported_features); static hailo_status fill_ddr_layers_info( - const ProtoHEFNetworkGroup &network_group_proto, + const ProtoHEFCoreOpMock &core_op, const uint8_t context_index, const ProtoHEFEdgeLayer &layer, - const NetworkGroupSupportedFeatures &supported_features, - std::vector &context_ddr_input_layers, - std::vector &context_ddr_output_layers); + const SupportedFeatures &supported_features, + ContextMetadata &context_metadata); static hailo_status check_ddr_pairs_match( - const std::vector &context_ddr_input_layers, - const std::vector &context_ddr_output_layers, + const std::vector &context_ddr_input_layers, + const std::vector &context_ddr_output_layers, const uint8_t context_index); - static hailo_status get_all_layers_info(const ProtoHEFNetworkGroup &network_group_proto, - const NetworkGroupSupportedFeatures &supported_features, - std::vector> &boundary_input_layers, - std::vector> &boundary_output_layers, - std::vector> &inter_context_input_layers, - std::vector> &inter_context_output_layers, - std::vector> &ddr_input_layers, - std::vector> &ddr_output_layers); + static Expected parse_preliminary_context(const ProtoHEFPreliminaryConfig &preliminary_proto, + const SupportedFeatures &supported_features); + static Expected parse_single_dynamic_context(const ProtoHEFCoreOpMock &core_op, + const ProtoHEFContext &context_proto, uint8_t context_index, const SupportedFeatures &supported_features); + static Expected> parse_dynamic_contexts(const ProtoHEFCoreOpMock &core_op, + const SupportedFeatures &supported_features); static Expected parse_proto_nms_info(const ProtoHEFNmsInfo &proto_nms_info); - static Expected get_boundary_layer_info(const ProtoHEFNetworkGroup &net_group, const uint8_t context_index, - const ProtoHEFEdgeLayer &layer, const NetworkGroupSupportedFeatures &supported_features); - static Expected> get_sorted_output_names(const ProtoHEFNetworkGroup &net_group); + static Expected get_boundary_layer_info(const ProtoHEFCoreOpMock &core_op, + const uint8_t context_index, const ProtoHEFEdgeLayer &layer, const SupportedFeatures &supported_features); + static Expected> get_sorted_output_names(const ProtoHEFCoreOpMock &core_op); - static Expected get_partial_network_name_by_index(const ProtoHEFNetworkGroup &network_group_proto, uint8_t network_index, - const NetworkGroupSupportedFeatures &supported_features); + static Expected get_partial_network_name_by_index(const ProtoHEFCoreOpMock &core_op, uint8_t network_index, const SupportedFeatures &supported_features); static Expected> get_network_infos(const ProtoHEFNetworkGroup &net_group, - const std::string &net_group_name, const NetworkGroupSupportedFeatures &supported_features); + const std::string &net_group_name, const SupportedFeatures &supported_features); - static std::string get_network_name(const ProtoHEFNetworkGroup &net_group, const std::string &partial_network_name); + static std::string get_network_group_name(const ProtoHEFNetworkGroup &net_group, const SupportedFeatures &supported_features); + static std::string get_network_name(const ProtoHEFCoreOpMock &net_group, const std::string &partial_network_name); static std::string get_network_name(const std::string &net_group_name, const std::string &partial_network_name); private: @@ -513,423 +483,18 @@ private: const uint8_t context_index, const uint8_t network_index, LayerInfo &layer_info); static hailo_status fill_layer_info(const ProtoHEFEdgeLayerInfo &info, const ProtoHEFEdgeConnectionType &edge_connection_type, - const ProtoHEFNetworkGroup &net_group, hailo_stream_direction_t direction, + const ProtoHEFCoreOpMock &core_op, hailo_stream_direction_t direction, bool hw_padding_supported, const uint8_t context_index, const std::string &partial_network_name, uint8_t network_index, LayerInfo &layer_info); static hailo_status fill_fused_nms_info(const ProtoHEFEdgeLayerFused &info, LayerInfo &layer_info, hailo_quant_info_t &defuse_quant_info, const std::string &network_name); static hailo_status fill_mux_info(const ProtoHEFEdgeLayerMux &info, const ProtoHEFEdgeConnectionType &edge_connection_type, - const ProtoHEFNetworkGroup &net_group, hailo_stream_direction_t direction, + const ProtoHEFCoreOpMock &core_op, hailo_stream_direction_t direction, bool hw_padding_supported, const uint8_t context_index, const std::string &partial_network_name, uint8_t network_index, LayerInfo &layer_info); }; -class ContextSwitchTrigger final -{ -public: - static Expected create(const ProtoHEFTrigger &proto_trigger); - ContextSwitchTrigger(ContextSwitchTrigger &&) = default; - ContextSwitchTrigger(const ContextSwitchTrigger &) = delete; - ContextSwitchTrigger &operator=(ContextSwitchTrigger &&) = delete; - ContextSwitchTrigger &operator=(const ContextSwitchTrigger &) = delete; - ~ContextSwitchTrigger() = default; - - CONTROL_PROTOCOL__TRIGGER_t get_serialized() const; - hailo_status add_to_trigger_group(CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **context_meta_data_head_pointer) const; - -private: - static Expected serialize(const ProtoHEFTrigger &proto_trigger); - ContextSwitchTrigger(CONTROL_PROTOCOL__TRIGGER_t &&serialized_trigger); - - const CONTROL_PROTOCOL__TRIGGER_t m_serialized_trigger; -}; - -class ContextSwitchConfigAction; -using ContextSwitchConfigActionPtr = std::shared_ptr; -class ContextSwitchConfigAction -{ -public: - enum class Type - { - None, - WriteData, - WriteDataCcw, - AddCcwBurst, - CreateDescForCcw, - ReadVdma, - TriggerSequencer, - WaitForSequencerDone, - TriggerNewDataFromDataInput, - TriggerNewDataFromDataInputDdr, - EnableLcuNonDefault, - EnableLcuDefault, - DisableLcu, - WaitForModuleConfigDone, - DdrPairInfo, - StartDdrBufferingTask, - AddRrepeated, - StartBurstCreditsTask, - EdgeLayerActivationActionsPositionMarker - }; - - static Expected create(const ProtoHEFAction &proto_action, Device &device, - std::vector &config, const ResourcesManager &resources_manager, const ProtoHEFNetworkGroup &net_group, - bool support_pre_fetch); - - ContextSwitchConfigAction(ContextSwitchConfigAction &&) = default; - ContextSwitchConfigAction(const ContextSwitchConfigAction &) = delete; - ContextSwitchConfigAction &operator=(ContextSwitchConfigAction &&) = delete; - ContextSwitchConfigAction &operator=(const ContextSwitchConfigAction &) = delete; - virtual ~ContextSwitchConfigAction() = default; - - virtual hailo_status execute(CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **context_meta_data_head_pointer) = 0; - virtual bool supports_repeated_block() const = 0; - void set_is_in_repeated_block(bool is_repeated); - Type get_type() const; - CONTROL_PROTOCOL__ACTION_TYPE_t get_action_list_type() const; - const ProtoHEFAction &get_proto_action() const; - -protected: - ContextSwitchConfigAction(Type type); - ContextSwitchConfigAction(Type type, const ProtoHEFAction& proto_action); - ContextSwitchConfigAction(Type type, CONTROL_PROTOCOL__ACTION_TYPE_t action_list_type); - ContextSwitchConfigAction(Type type, CONTROL_PROTOCOL__ACTION_TYPE_t action_list_type, const ProtoHEFAction& proto_action); - - const Type m_type; - const CONTROL_PROTOCOL__ACTION_TYPE_t m_action_list_type; - bool m_is_in_repeated_block; - // Note: This references the action in the hef Protobuf - const ProtoHEFAction &m_proto_action; -}; - -class NoneAction : public ContextSwitchConfigAction -{ -public: - static Expected create(); - NoneAction(NoneAction &&) = default; - NoneAction(const NoneAction &) = delete; - NoneAction &operator=(NoneAction &&) = delete; - NoneAction &operator=(const NoneAction &) = delete; - virtual ~NoneAction() = default; - - virtual hailo_status execute(CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **context_meta_data_head_pointer) override; - virtual bool supports_repeated_block() const override; - -private: - NoneAction(); -}; - -class WriteDataAction : public ContextSwitchConfigAction -{ -public: - static Expected create(const ProtoHEFAction& proto_action, Device &device); - WriteDataAction(WriteDataAction &&) = default; - WriteDataAction(const WriteDataAction &) = delete; - WriteDataAction &operator=(WriteDataAction &&) = delete; - WriteDataAction &operator=(const WriteDataAction &) = delete; - virtual ~WriteDataAction() = default; - - virtual hailo_status execute(CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **context_meta_data_head_pointer) override; - virtual bool supports_repeated_block() const override; - -private: - WriteDataAction(const ProtoHEFAction& proto_action, Device &device); - - Device &m_device; -}; - -class WriteDataCcwAction : public ContextSwitchConfigAction -{ -public: - static Expected create(const ProtoHEFAction& proto_action, - std::vector &config, bool support_pre_fetch); - WriteDataCcwAction(WriteDataCcwAction &&) = default; - WriteDataCcwAction(const WriteDataCcwAction &) = delete; - WriteDataCcwAction &operator=(WriteDataCcwAction &&) = delete; - WriteDataCcwAction &operator=(const WriteDataCcwAction &) = delete; - virtual ~WriteDataCcwAction() = default; - - virtual hailo_status execute(CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **context_meta_data_head_pointer) override; - virtual bool supports_repeated_block() const override; - -private: - WriteDataCcwAction(const ProtoHEFAction& proto_action, ConfigBuffer &config, - bool support_pre_fetch); - - bool is_last_ccw_write(); - hailo_status pad_with_nops(); - - ConfigBuffer &m_config; - const bool m_support_pre_fetch; -}; - -class AddCcwBurstAction : public ContextSwitchConfigAction -{ -public: - static Expected create(uint8_t config_stream_index, uint16_t ccw_bursts); - - virtual hailo_status execute(CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **context_meta_data_head_pointer) override; - virtual bool supports_repeated_block() const override; - -private: - AddCcwBurstAction(uint8_t config_stream_index, uint16_t ccw_bursts); - - const uint8_t m_config_stream_index; - const uint16_t m_ccw_bursts; -}; - -class CreateConfigDescAndFetchAction : public ContextSwitchConfigAction -{ -public: - static Expected create(uint8_t config_stream_index, ConfigBuffer &config_buffer); - - CreateConfigDescAndFetchAction(CreateConfigDescAndFetchAction &&) = default; - CreateConfigDescAndFetchAction(const CreateConfigDescAndFetchAction &) = delete; - CreateConfigDescAndFetchAction &operator=(CreateConfigDescAndFetchAction &&) = delete; - CreateConfigDescAndFetchAction &operator=(const CreateConfigDescAndFetchAction &) = delete; - virtual ~CreateConfigDescAndFetchAction() = default; - - virtual hailo_status execute(CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **context_meta_data_head_pointer) override; - virtual bool supports_repeated_block() const override; - -private: - CreateConfigDescAndFetchAction(uint8_t config_stream_index, ConfigBuffer &config_buffer); - - const uint8_t m_config_stream_index; - ConfigBuffer &m_config_buffer; -}; - -class StartBurstCreditsTaskAction : public ContextSwitchConfigAction -{ -public: - static Expected create(); - - StartBurstCreditsTaskAction(StartBurstCreditsTaskAction &&) = default; - StartBurstCreditsTaskAction(const StartBurstCreditsTaskAction &) = delete; - StartBurstCreditsTaskAction &operator=(StartBurstCreditsTaskAction &&) = delete; - StartBurstCreditsTaskAction &operator=(const StartBurstCreditsTaskAction &) = delete; - virtual ~StartBurstCreditsTaskAction() = default; - - virtual hailo_status execute(CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **context_meta_data_head_pointer) override; - virtual bool supports_repeated_block() const override; - -private: - StartBurstCreditsTaskAction(); -}; - -class RepeatedHeaderAction : public ContextSwitchConfigAction -{ -public: - static Expected create(CONTROL_PROTOCOL__ACTION_TYPE_t sub_action_type, uint8_t num_actions); - RepeatedHeaderAction(RepeatedHeaderAction &&) = default; - RepeatedHeaderAction(const RepeatedHeaderAction &) = delete; - RepeatedHeaderAction &operator=(RepeatedHeaderAction &&) = delete; - RepeatedHeaderAction &operator=(const RepeatedHeaderAction &) = delete; - virtual ~RepeatedHeaderAction() = default; - - virtual hailo_status execute(CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **context_meta_data_head_pointer) override; - virtual bool supports_repeated_block() const override; - -private: - RepeatedHeaderAction(CONTROL_PROTOCOL__ACTION_TYPE_t sub_action_type, uint8_t num_actions); - - const CONTROL_PROTOCOL__ACTION_TYPE_t m_sub_action_type; - const uint8_t m_num_actions; -}; - -class DisableLcuAction : public ContextSwitchConfigAction -{ -public: - static Expected create(const ProtoHEFAction& proto_action); - DisableLcuAction(DisableLcuAction &&) = default; - DisableLcuAction(const DisableLcuAction &) = delete; - DisableLcuAction &operator=(DisableLcuAction &&) = delete; - DisableLcuAction &operator=(const DisableLcuAction &) = delete; - virtual ~DisableLcuAction() = default; - - virtual hailo_status execute(CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **context_meta_data_head_pointer) override; - virtual bool supports_repeated_block() const override; - -private: - DisableLcuAction(const ProtoHEFAction& proto_action); -}; - -class EnableLcuAction : public ContextSwitchConfigAction -{ -public: - static Expected create(const ProtoHEFAction& proto_action, - const ResourcesManager &resources_manager, const ProtoHEFNetworkGroup &net_group); - EnableLcuAction(EnableLcuAction &&) = default; - EnableLcuAction(const EnableLcuAction &) = delete; - EnableLcuAction &operator=(EnableLcuAction &&) = delete; - EnableLcuAction &operator=(const EnableLcuAction &) = delete; - virtual ~EnableLcuAction() = default; - - virtual hailo_status execute(CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **context_meta_data_head_pointer) override; - virtual bool supports_repeated_block() const override; - -private: - static CONTROL_PROTOCOL__ACTION_TYPE_t get_enable_lcu_action_type(bool is_default); - static Type get_enable_lcu_type(bool is_default); - - EnableLcuAction(const ProtoHEFAction& proto_action, bool is_default, uint8_t network_index); - const uint8_t m_network_index; - const bool m_is_default; -}; - -class EnableSequencerAction : public ContextSwitchConfigAction -{ -public: - static Expected create(const ProtoHEFAction& proto_action); - EnableSequencerAction(EnableSequencerAction &&) = default; - EnableSequencerAction(const EnableSequencerAction &) = delete; - EnableSequencerAction &operator=(EnableSequencerAction &&) = delete; - EnableSequencerAction &operator=(const EnableSequencerAction &) = delete; - virtual ~EnableSequencerAction() = default; - - virtual hailo_status execute(CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **context_meta_data_head_pointer) override; - virtual bool supports_repeated_block() const override; - -private: - EnableSequencerAction(const ProtoHEFAction& proto_action, uint8_t initial_l3_cut, - uint16_t initial_l3_offset, uint64_t l2_offset_0, uint64_t l2_offset_1); - - const uint8_t m_initial_l3_cut; - const uint16_t m_initial_l3_offset; - const uint64_t m_l2_offset_0; - const uint64_t m_l2_offset_1; -}; - -class WaitForSeqeuncerAction : public ContextSwitchConfigAction -{ -public: - static Expected create(const ProtoHEFAction& proto_action); - WaitForSeqeuncerAction(WaitForSeqeuncerAction &&) = default; - WaitForSeqeuncerAction(const WaitForSeqeuncerAction &) = delete; - WaitForSeqeuncerAction &operator=(WaitForSeqeuncerAction &&) = delete; - WaitForSeqeuncerAction &operator=(const WaitForSeqeuncerAction &) = delete; - virtual ~WaitForSeqeuncerAction() = default; - - virtual hailo_status execute(CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **context_meta_data_head_pointer) override; - virtual bool supports_repeated_block() const override; - -private: - WaitForSeqeuncerAction(const ProtoHEFAction& proto_action); -}; - -class AllowInputDataflowAction : public ContextSwitchConfigAction -{ -public: - static Expected create(const ProtoHEFAction& proto_action); - AllowInputDataflowAction(AllowInputDataflowAction &&) = default; - AllowInputDataflowAction(const AllowInputDataflowAction &) = delete; - AllowInputDataflowAction &operator=(AllowInputDataflowAction &&) = delete; - AllowInputDataflowAction &operator=(const AllowInputDataflowAction &) = delete; - virtual ~AllowInputDataflowAction() = default; - - virtual hailo_status execute(CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **context_meta_data_head_pointer) override; - virtual bool supports_repeated_block() const override; - -private: - static ContextSwitchConfigAction::Type get_input_dataflow_action_type(const ProtoHEFAction& proto_action); - - AllowInputDataflowAction(const ProtoHEFAction& proto_action); -}; - -class WaitForModuleConfigDoneAction : public ContextSwitchConfigAction -{ -public: - static Expected create(const ProtoHEFAction& proto_action); - WaitForModuleConfigDoneAction(WaitForModuleConfigDoneAction &&) = default; - WaitForModuleConfigDoneAction(const WaitForModuleConfigDoneAction &) = delete; - WaitForModuleConfigDoneAction &operator=(WaitForModuleConfigDoneAction &&) = delete; - WaitForModuleConfigDoneAction &operator=(const WaitForModuleConfigDoneAction &) = delete; - virtual ~WaitForModuleConfigDoneAction() = default; - - virtual hailo_status execute(CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **context_meta_data_head_pointer) override; - virtual bool supports_repeated_block() const override; - -private: - WaitForModuleConfigDoneAction(const ProtoHEFAction& proto_action); -}; - -class DdrPairInfoAction : public ContextSwitchConfigAction -{ -public: - static Expected create(const vdma::ChannelId &h2d_channel_id, - const vdma::ChannelId &d2h_channel_id, uint32_t descriptors_per_frame, uint16_t descs_count); - DdrPairInfoAction(DdrPairInfoAction &&) = default; - DdrPairInfoAction(const DdrPairInfoAction &) = delete; - DdrPairInfoAction &operator=(DdrPairInfoAction &&) = delete; - DdrPairInfoAction &operator=(const DdrPairInfoAction &) = delete; - virtual ~DdrPairInfoAction() = default; - - virtual hailo_status execute(CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **context_meta_data_head_pointer) override; - virtual bool supports_repeated_block() const override; - -private: - DdrPairInfoAction(const vdma::ChannelId &h2d_channel_id, const vdma::ChannelId &d2h_channel_id, - uint32_t descriptors_per_frame, uint16_t descs_count); - - const vdma::ChannelId m_h2d_channel_id; - const vdma::ChannelId m_d2h_channel_id; - const uint32_t m_descriptors_per_frame; - const uint16_t m_descs_count; -}; - -class StartDdrBufferingTaskAction : public ContextSwitchConfigAction -{ -public: - static Expected create(); - StartDdrBufferingTaskAction(StartDdrBufferingTaskAction &&) = default; - StartDdrBufferingTaskAction(const StartDdrBufferingTaskAction &) = delete; - StartDdrBufferingTaskAction &operator=(StartDdrBufferingTaskAction &&) = delete; - StartDdrBufferingTaskAction &operator=(const StartDdrBufferingTaskAction &) = delete; - virtual ~StartDdrBufferingTaskAction() = default; - - virtual hailo_status execute(CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **context_meta_data_head_pointer) override; - virtual bool supports_repeated_block() const override; - -private: - StartDdrBufferingTaskAction(); -}; - -class EdgeLayerActivationActionsPositionMarker : public ContextSwitchConfigAction -{ -public: - static Expected create(); - EdgeLayerActivationActionsPositionMarker(EdgeLayerActivationActionsPositionMarker &&) = default; - EdgeLayerActivationActionsPositionMarker(const EdgeLayerActivationActionsPositionMarker &) = delete; - EdgeLayerActivationActionsPositionMarker &operator=(EdgeLayerActivationActionsPositionMarker &&) = delete; - EdgeLayerActivationActionsPositionMarker &operator=(const EdgeLayerActivationActionsPositionMarker &) = delete; - virtual ~EdgeLayerActivationActionsPositionMarker() = default; - - virtual hailo_status execute(CONTROL_PROTOCOL__context_switch_context_info_t *context_info, - uint8_t **context_meta_data_head_pointer) override; - virtual bool supports_repeated_block() const override; - -private: - EdgeLayerActivationActionsPositionMarker(); -}; - } /* namespace hailort */ #endif /* _HEF_INTERNAL_HPP_ */ diff --git a/hailort/libhailort/src/hlpcie.cpp b/hailort/libhailort/src/hlpcie.cpp deleted file mode 100644 index 634f68c..0000000 --- a/hailort/libhailort/src/hlpcie.cpp +++ /dev/null @@ -1,405 +0,0 @@ -#include -#include -#include -#include -#include -#include "hw_consts.hpp" -#include "hlpcie.hpp" -#include "common/circular_buffer.hpp" -#include "common/logger_macros.hpp" -#include "d2h_events.h" -#include "firmware_header.h" -#include "os/hailort_driver.hpp" -#include "md5.h" - -namespace hailort -{ - -/******************************************************************************* - * pcie control configurations -********************************************************************************/ -typedef enum { - ATR_PARAM_SIZE_4KB = 11, - ATR_PARAM_SIZE_8KB -} ATR_PARAM_SIZE_t; - -typedef enum { - ATR0 = 0, - ATR1 -} ATR_TABLES_t; - -typedef enum { - TRSL_ID_AXI4_MASTER_0 = 4, - TRSL_ID_AXI4_MASTER_1, - TRSL_ID_AXI4_MASTER_2, - TRSL_ID_AXI4_MASTER_3, -} TRSL_ID_t; - -#define PCIE_SRAM_TABLE_SIZE (4*1024) -#define PCIE_SRAM_BAR_4_OFFSET (0) -#define PCIE_BLOCK_BAR_4_OFFSET (PCIE_SRAM_BAR_4_OFFSET + PCIE_SRAM_TABLE_SIZE) - -#define PCIE_REQUEST_SIZE (0x640) -#define PCIE_RESPONSE_SIZE (0x640) -#define PCIE_D2H_EVENT_MESSAGE_SRAM_OFFSET (PCIE_REQUEST_SIZE + PCIE_RESPONSE_SIZE) - -/* SRC_ADDR needs to be shifted by 12 since it takes only bits [31:12] from it. */ -#define PCI_BIT_SHIFT_FOR_4KB_GRANULARITY (12) -#define PCIE_SRAM_BAR_4_SRC_ADDR (PCIE_SRAM_BAR_4_OFFSET >> PCI_BIT_SHIFT_FOR_4KB_GRANULARITY) -#define PCIE_BLOCK_BAR_4_SRC_ADDR (PCIE_BLOCK_BAR_4_OFFSET >> PCI_BIT_SHIFT_FOR_4KB_GRANULARITY) - -#define ATR0_TABLE_SIZE (PCIE_SRAM_TABLE_SIZE) -#define ATR1_OFFSET (ATR0_TABLE_SIZE) -#define ATR0_PCIE_BRIDGE_OFFSET (0x700) -#define ATR1_PCIE_BRIDGE_OFFSET (ATR0_PCIE_BRIDGE_OFFSET + 0x20) - -/* atr0 table is configured to the SRAM */ -#define ATR0_SRC_ADDR (0x0) -#define HAILO_MERCURY_FW_CONTROL_ADDRESS (0x000BE000) -#define HAILO8_FW_CONTROL_ADDRESS (0x60000000) -#define ATR0_TRSL_ADDR2 (0x0) - -/* atr1 table is configured to the PCIe block */ -#define ATR1_SRC_ADDR (0x0) -// The address macro uses __VA_ARGS__ that doesn't expand correctly with C++ if no args were given, so we must pass the default values explicitly. -#define ATR1_TRSL_ADDR1 (PCIE_CONFIG_BASE_ADDRESS) -#define ATR1_TRSL_ADDR2 (0x0) - -typedef struct { - uint32_t atr_param; - uint32_t atr_src; - uint32_t atr_trsl_addr_1; - uint32_t atr_trsl_addr_2; - uint32_t atr_trsl_param; -} hailo_pcie_atr_config_t; - -static uint32_t fw_control_ram_address_by_board_type(HailoRTDriver::BoardType board_type) { - switch (board_type) { - case HailoRTDriver::BoardType::HAILO8: - return HAILO8_FW_CONTROL_ADDRESS; - case HailoRTDriver::BoardType::MERCURY: - return HAILO_MERCURY_FW_CONTROL_ADDRESS; - default: - assert(true); - return 0; - } -} - -// TODO HRT-6392: validate atr in driver, remove hw-consts -inline void get_atr_param_config(HailoRTDriver &driver, ATR_TABLES_t atr_table, hailo_pcie_atr_config_t *atr_config) - { - uint64_t param = 0; - assert(atr_config != NULL); - memset(atr_config, 0, sizeof(hailo_pcie_atr_config_t)); - - switch(atr_table) { - case ATR0: - PCIE_BRIDGE_CONFIG__ATR_PARAM_ATR0_PCIE_WIN1__ATR_IMPL__SET(param); - PCIE_BRIDGE_CONFIG__ATR_PARAM_ATR0_PCIE_WIN1__ATR_SIZE__MODIFY(param, ATR_PARAM_SIZE_4KB); - PCIE_BRIDGE_CONFIG__ATR_PARAM_ATR0_PCIE_WIN1__SOURCE_ADDR__MODIFY(param, PCIE_SRAM_BAR_4_SRC_ADDR); - atr_config->atr_param = (uint32_t)param; - atr_config->atr_src = ATR0_SRC_ADDR; - atr_config->atr_trsl_addr_1 = fw_control_ram_address_by_board_type(driver.board_type()); - atr_config->atr_trsl_addr_2 = ATR0_TRSL_ADDR2; - atr_config->atr_trsl_param = TRSL_ID_AXI4_MASTER_2; - break; - - case ATR1: - PCIE_BRIDGE_CONFIG__ATR_PARAM_ATR1_PCIE_WIN1__ATR_IMPL__SET(param); - PCIE_BRIDGE_CONFIG__ATR_PARAM_ATR1_PCIE_WIN1__ATR_SIZE__MODIFY(param, ATR_PARAM_SIZE_4KB); - PCIE_BRIDGE_CONFIG__ATR_PARAM_ATR1_PCIE_WIN1__SOURCE_ADDR__MODIFY(param, PCIE_BLOCK_BAR_4_SRC_ADDR); - atr_config->atr_param = (uint32_t)param; - atr_config->atr_src = ATR1_SRC_ADDR; - atr_config->atr_trsl_addr_1 = ATR1_TRSL_ADDR1; - atr_config->atr_trsl_addr_2 = ATR1_TRSL_ADDR2; - atr_config->atr_trsl_param = TRSL_ID_AXI4_MASTER_2; - break; - - default: - LOGGER__ERROR("table param configuration not supoorted"); - } - -} -/******************************************************************************* - * Private Functions -*******************************************************************************/ -// TODO HRT-5358 - Unify MD5 functions. Use by pcie and core driver (and FW) -void hailo_pcie__set_MD5( const uint8_t *buffer, uint32_t buffer_length, unsigned char expected_md5[16]) -{ - MD5_CTX ctx; - - MD5_Init(&ctx); - MD5_Update(&ctx, buffer, buffer_length); - MD5_Final(expected_md5, &ctx); -} - -hailo_status hailo_pcie__check_atr_configuration(HailoRTDriver &driver, hailo_pcie_atr_config_t *atr_config_to_validate, ATR_TABLES_t atr_table) -{ - uint32_t offset = 0; - hailo_pcie_atr_config_t pcie_atr_table; - - if (NULL == atr_config_to_validate) { - return HAILO_INVALID_ARGUMENT; - } - - switch(atr_table) { - case ATR0: - offset = ATR0_PCIE_BRIDGE_OFFSET; - break; - - case ATR1: - offset = ATR1_PCIE_BRIDGE_OFFSET; - break; - - default: - LOGGER__ERROR("table param configuration not supported"); - } - - hailo_status status = driver.read_bar(PciBar::bar0, offset , sizeof(pcie_atr_table), &pcie_atr_table); - if (HAILO_SUCCESS != status) { - LOGGER__ERROR("Reading SRAM table Failed"); - return status; - } - /* Check that ATR was configured to as the wanted configuration */ - if (0 != memcmp(atr_config_to_validate, &pcie_atr_table, sizeof(pcie_atr_table))){ - LOGGER__ERROR("|==================+================+===============|"); - LOGGER__ERROR("| ATR{} is misconfigured |", atr_table); - LOGGER__ERROR("|------------------+----------------+---------------|"); - LOGGER__ERROR("| Field + Expected + Read |"); - LOGGER__ERROR("|------------------+----------------+---------------|"); - LOGGER__ERROR("| ATR_PARM | 0x{:08X} | 0x{:08X} |", atr_config_to_validate->atr_param, pcie_atr_table.atr_param); - LOGGER__ERROR("| ATR_SRC_ADDR | 0x{:08X} | 0x{:08X} |", atr_config_to_validate->atr_src, pcie_atr_table.atr_src); - LOGGER__ERROR("| ATR_TRSL_ADDR1 | 0x{:08X} | 0x{:08X} |", atr_config_to_validate->atr_trsl_addr_1, pcie_atr_table.atr_trsl_addr_1); - LOGGER__ERROR("| ATR_TRSL_ADDR2 | 0x{:08X} | 0x{:08X} |", atr_config_to_validate->atr_trsl_addr_2, pcie_atr_table.atr_trsl_addr_2); - LOGGER__ERROR("| ATR_TRSL_PARAM | 0x{:08X} | 0x{:08X} |", atr_config_to_validate->atr_trsl_param, pcie_atr_table.atr_trsl_param); - LOGGER__ERROR("|==================+================+===============|"); - return HAILO_ATR_TABLES_CONF_VALIDATION_FAIL; - } - return HAILO_SUCCESS; -} - -hailo_status restore_atr_config(HailoRTDriver &driver, hailo_pcie_atr_config_t *old_atr_config) -{ - hailo_status status = HAILO_UNINITIALIZED; - - status = driver.write_bar(PciBar::bar0, ATR0_PCIE_BRIDGE_OFFSET, sizeof(*old_atr_config), old_atr_config); - if (HAILO_SUCCESS != status) { - goto l_exit; - } - status = hailo_pcie__check_atr_configuration(driver, old_atr_config, ATR0); - if (HAILO_SUCCESS != status) { - LOGGER__ERROR("BAR_4 wasn't configured correctly"); - goto l_exit; - } -l_exit: - return status; -} - -hailo_status config_atr_for_direct_memory_access(HailoRTDriver &driver, uint32_t base_address) -{ - hailo_status status = HAILO_UNINITIALIZED; - hailo_pcie_atr_config_t new_atr_config = {}; - - get_atr_param_config(driver, ATR0, &new_atr_config); - new_atr_config.atr_trsl_addr_1 = base_address; - - // Config BAR0 to the new ATR-configuration, and validate configuration - status = driver.write_bar(PciBar::bar0, ATR0_PCIE_BRIDGE_OFFSET, sizeof(new_atr_config), &new_atr_config); - if (HAILO_SUCCESS != status) { - goto l_exit; - } - - status = hailo_pcie__check_atr_configuration(driver, &new_atr_config, ATR0); - if (HAILO_SUCCESS != status) { - LOGGER__ERROR("BAR_4 wasn't configured correctly"); - goto l_exit; - } - - status = HAILO_SUCCESS; -l_exit: - return status; -} - -// HRT-6393 move read/write memory to driver -hailo_status hailo_pcie__write_memory(HailoRTDriver &driver, uint32_t base_address, uint32_t offset, - const void *buffer, uint32_t size) -{ - hailo_status status = HAILO_UNINITIALIZED; - - assert(0 == (base_address & (ATR0_TABLE_SIZE - 1))); - assert((offset + size) <= ATR0_TABLE_SIZE); - - status = config_atr_for_direct_memory_access(driver, base_address); - if (HAILO_SUCCESS != status) { - goto l_exit; - } - - status = driver.write_bar(PciBar::bar4, offset, size, buffer); - if (HAILO_SUCCESS != status) { - goto l_exit; - } - - status = HAILO_SUCCESS; -l_exit: - return status; -} - -hailo_status HAILO_PCIE__write_memory(HailoRTDriver &driver, hailo_ptr_t address, const void *buffer, uint32_t size) -{ - hailo_status status = HAILO_UNINITIALIZED; - uint32_t offset = 0; - uint32_t chunk_size = 0; - hailo_pcie_atr_config_t old_atr_config = {}; - uint32_t base_address = address & ~(ATR0_TABLE_SIZE - 1); - - - // Save the old ATR-configuration to old_atr_config - status = driver.read_bar(PciBar::bar0, ATR0_PCIE_BRIDGE_OFFSET , sizeof(old_atr_config), &old_atr_config); - if (HAILO_SUCCESS != status) { - goto l_exit; - } - - // Write memory - offset = 0; - if (base_address != address) { - chunk_size = MIN(base_address + ATR0_TABLE_SIZE - address, size); - status = hailo_pcie__write_memory(driver, base_address, address - base_address, buffer, chunk_size); - if (HAILO_SUCCESS != status) { - goto l_cleanup; - } - offset += chunk_size; - } - while (offset < size) { - chunk_size = MIN((size - offset), ATR0_TABLE_SIZE); - status = hailo_pcie__write_memory(driver, address + offset, 0, (void*)((uintptr_t)buffer + offset), chunk_size); - if (HAILO_SUCCESS != status) { - goto l_cleanup; - } - offset += chunk_size; - } - - status = HAILO_SUCCESS; -l_cleanup: - status = restore_atr_config(driver, &old_atr_config); - if (HAILO_SUCCESS != status) { - LOGGER__ERROR("Failed to reconfigure BAR_4 after direct memory access"); - } -l_exit: - return status; -} - -hailo_status HAILO_PCIE__read_atr_to_validate_fw_is_up(HailoRTDriver &driver, bool *is_fw_up) -{ - hailo_pcie_atr_config_t atr_config = {}; - - hailo_status status = driver.read_bar(PciBar::bar0, ATR0_PCIE_BRIDGE_OFFSET , sizeof(atr_config), &atr_config); - if (HAILO_SUCCESS != status) { - LOGGER__ERROR("Reading SRAM table Failed\n"); - *is_fw_up = false; - return status; - } - - *is_fw_up = (fw_control_ram_address_by_board_type(driver.board_type()) == atr_config.atr_trsl_addr_1); - return HAILO_SUCCESS; -} - -hailo_status hailo_pcie__read_memory(HailoRTDriver &driver, uint32_t base_address, uint32_t offset, void *buffer, - uint32_t size) -{ - hailo_status status = HAILO_UNINITIALIZED; - - assert(0 == (base_address & (ATR0_TABLE_SIZE - 1))); - assert((offset + size) <= ATR0_TABLE_SIZE); - - status = config_atr_for_direct_memory_access(driver, base_address); - if (HAILO_SUCCESS != status) { - goto l_exit; - } - - status = driver.read_bar(PciBar::bar4, offset, size, buffer); - if (HAILO_SUCCESS != status) { - goto l_exit; - } - - status = HAILO_SUCCESS; -l_exit: - return status; -} - -hailo_status HAILO_PCIE__read_memory(HailoRTDriver &driver, hailo_ptr_t address, void *buffer, uint32_t size) -{ - hailo_status status = HAILO_UNINITIALIZED; - uint32_t offset = 0; - uint32_t chunk_size = 0; - uint32_t base_address = address & ~(ATR0_TABLE_SIZE - 1); - hailo_pcie_atr_config_t old_atr_config = {}; - - // Save the old ATR-configuration to old_atr_config - status = driver.read_bar(PciBar::bar0, ATR0_PCIE_BRIDGE_OFFSET , sizeof(old_atr_config), - &old_atr_config); - if (HAILO_SUCCESS != status) { - goto l_exit; - } - - // Read memory - offset = 0; - if (base_address != address) { - chunk_size = MIN(base_address + ATR0_TABLE_SIZE - address, size); - status = hailo_pcie__read_memory(driver, base_address, address - base_address, buffer, chunk_size); - if (HAILO_SUCCESS != status) { - goto l_cleanup; - } - offset += chunk_size; - } - while (offset < size) { - chunk_size = MIN((size - offset), ATR0_TABLE_SIZE); - status = hailo_pcie__read_memory(driver, address + offset, 0, (void*)((uintptr_t)buffer + offset), chunk_size); - if (HAILO_SUCCESS != status) { - goto l_cleanup; - } - offset += chunk_size; - } - - status = HAILO_SUCCESS; -l_cleanup: - status = restore_atr_config(driver, &old_atr_config); - if (HAILO_SUCCESS != status) { - LOGGER__ERROR("Failed to reconfigure BAR_4 after direct memory access"); - } -l_exit: - return status; -} - -hailo_status HAILO_PCIE__fw_interact(HailoRTDriver &driver, const void *request, size_t request_len, - void *response_buf, size_t *response_buf_size, uint32_t timeout_ms, hailo_cpu_id_t cpu_id) -{ - /* Validate ATR0 configuration before writing to BAR4 SRAM*/ - hailo_pcie_atr_config_t atr_config; - get_atr_param_config(driver, ATR0, &atr_config); - auto status = hailo_pcie__check_atr_configuration(driver, &atr_config, ATR0); - CHECK_SUCCESS(status, "Validate address translation tables Failed, For FW control use."); - - /* Validate ATR1 configuration before writing to BAR4 PCIe bridge block */ - get_atr_param_config(driver, ATR1, &atr_config); - status = hailo_pcie__check_atr_configuration(driver, &atr_config, ATR1); - CHECK_SUCCESS(status, "Validate address translation tables Failed, For FW control use."); - - /* Send control */ - uint8_t request_md5[PCIE_EXPECTED_MD5_LENGTH]; - hailo_pcie__set_MD5((uint8_t *)request, static_cast(request_len), request_md5); - uint8_t response_md5[PCIE_EXPECTED_MD5_LENGTH]; - status = driver.fw_control(request, request_len, request_md5, - response_buf, response_buf_size, response_md5, - std::chrono::milliseconds(timeout_ms), cpu_id); - CHECK_SUCCESS(status, "Failed to send fw control"); - - /* Validate response MD5 */ - uint8_t calculated_md5_sum[PCIE_EXPECTED_MD5_LENGTH]; - hailo_pcie__set_MD5((uint8_t *)response_buf, static_cast(*response_buf_size), calculated_md5_sum); - auto memcmp_result = memcmp(calculated_md5_sum, response_md5, sizeof(calculated_md5_sum)); - CHECK(0 == memcmp_result, HAILO_CONTROL_RESPONSE_MD5_MISMATCH, "Control response md5 not valid"); - - return HAILO_SUCCESS; -} - -} /* namespace hailort */ diff --git a/hailort/libhailort/src/hlpcie.hpp b/hailort/libhailort/src/hlpcie.hpp deleted file mode 100644 index 7136342..0000000 --- a/hailort/libhailort/src/hlpcie.hpp +++ /dev/null @@ -1,71 +0,0 @@ -/** - * @file pcie.h - */ - -#ifndef __HLPCIE_HEADER__ -#define __HLPCIE_HEADER__ - -#include -#include -#include - -#include "hailo/hailort.h" -#include "hailo/device.hpp" -#include "control_protocol.h" -#include "d2h_event_queue.hpp" -#include "os/hailort_driver.hpp" - -namespace hailort -{ - -#define FW_CODE_MAX_SIZE (0x40000) -#define FW_CODE_MIN_SIZE (20*4) -#define FW_KEY_CERTIFICATE_SIZE (0x348) -#define FW_CONTENT_CERTIFICATE_SIZE (0x5f0) - - -typedef uint32_t hailo_ptr_t; //Core address space is 32bit - -/** - * Writes data to device memory. - * - * @param[in] dev - A handle to the PCIe device. - * @param[in] address - The device address to write to. - * @param[in] buffer - A pointer to the buffer containing the data to transfer. - * @param[in] size - The amount of bytes to write. - * @return hailo_status - */ -hailo_status HAILO_PCIE__write_memory(HailoRTDriver &driver, hailo_ptr_t address, const void *buffer, uint32_t size); - -/** - * Reads data from device memory. - * - * @param[in] dev - A handle to the PCIe device. - * @param[in] address - The device address to read from. - * @param[out] buffer - A pointer to the buffer that will contain the transferred data. - * @param[in] size - The amount of bytes to be read. - * @return hailo_status - */ -hailo_status HAILO_PCIE__read_memory(HailoRTDriver &driver, hailo_ptr_t address, void *buffer, uint32_t size); - -hailo_status HAILO_PCIE__read_atr_to_validate_fw_is_up(HailoRTDriver &driver, bool *is_fw_up); - -/** - * Interact with the firmware. - * - * @param[in] dev - A handle to the PCIe device to interact with. - * @param[in] request_buf - A pointer to the request buffer to send to the firmware. - * @param[in] request_buf_size - The size in bytes of the request buffer. - * @param[out] response_buf - A pointer to the response buffer to recv from the firmware.//TODO: limitations? - * @param[in/out] response_buf_size - A pointer to the size in bytes to recv. The number of bytes received may be less than @response_buf_size. - * Upon success, receives the number of bytes that was read; otherwise, untouched. - * @param[in] timeout_ms - Time in milliseconds to wait till response will be recived from the firmware - * @param[in] cpu_id - The CPU that will handle the control - * @return hailo_status - */ -hailo_status HAILO_PCIE__fw_interact(HailoRTDriver &driver, const void *request, size_t request_len, void *response_buf, - size_t *response_buf_size, uint32_t timeout_ms, hailo_cpu_id_t cpu_id); - -} /* namespace hailort */ - -#endif /* __HLPCIE_HEADER__ */ diff --git a/hailort/libhailort/src/inference_pipeline.cpp b/hailort/libhailort/src/inference_pipeline.cpp index 173a0cf..5910104 100644 --- a/hailort/libhailort/src/inference_pipeline.cpp +++ b/hailort/libhailort/src/inference_pipeline.cpp @@ -12,7 +12,7 @@ #include "vstream_internal.hpp" #include "hailort_defaults.hpp" #include "context_switch/network_group_internal.hpp" -#include "context_switch/network_group_wrapper.hpp" +#include "context_switch/multi_context/resource_manager.hpp" #include @@ -124,6 +124,10 @@ Expected InferVStreams::create(ConfiguredNetworkGroup &net_group, } } + if (HAILO_DEFAULT_BATCH_SIZE == batch_size) { + batch_size = DEFAULT_ACTUAL_BATCH_SIZE; + } + for (const auto &network_info : network_infos.value()) { auto input_vstream_infos_per_network = net_group.get_input_vstream_infos(network_info.name); CHECK_EXPECTED(input_vstream_infos_per_network); @@ -166,7 +170,7 @@ Expected InferVStreams::create(ConfiguredNetworkGroup &net_group, CHECK_SUCCESS_AS_EXPECTED(status); } if (total_outputs_found != output_params.size()) { - auto all_output_vstream_infos = net_group.get_input_vstream_infos(); + auto all_output_vstream_infos = net_group.get_output_vstream_infos(); CHECK_EXPECTED(all_output_vstream_infos); auto status = verify_vstream_params_in_vstream_infos(output_params, all_output_vstream_infos.release()); @@ -209,7 +213,7 @@ hailo_status InferVStreams::infer(const std::map& input auto status = input_vstream.write(MemoryView::create_const( input_buffer.data() + offset, input_vstream.get_frame_size())); - if (HAILO_STREAM_INTERNAL_ABORT == status) { + if (HAILO_STREAM_ABORTED_BY_USER == status) { LOGGER__DEBUG("Input stream was aborted!"); return status; } @@ -240,7 +244,7 @@ hailo_status InferVStreams::infer(const std::map& input auto error_status = HAILO_SUCCESS; for (auto& result : results) { status = result->get(); - if (HAILO_STREAM_INTERNAL_ABORT == status) { + if (HAILO_STREAM_ABORTED_BY_USER == status) { continue; } if (HAILO_SUCCESS != status) { diff --git a/hailort/libhailort/src/layer_info.hpp b/hailort/libhailort/src/layer_info.hpp index ff55337..140fdc2 100644 --- a/hailort/libhailort/src/layer_info.hpp +++ b/hailort/libhailort/src/layer_info.hpp @@ -23,6 +23,8 @@ namespace hailort { +#define INVALID_PAD_INDEX (UINT32_MAX) + enum class LayerType { NOT_SET = 0, @@ -37,70 +39,58 @@ struct BufferIndices { uint32_t cluster_index; }; +struct ConnectedContextInfo { + uint8_t context_index; + uint8_t dma_engine_index; + uint8_t stream_index; +}; + +struct DdrInfo { + // total_buffers_per_frame not same as core_buffer_per frame. + //(In DDR core buffer per frame is 1). Used to calc total host descriptors_per_frame. + uint16_t total_buffers_per_frame; + uint16_t min_buffered_rows; +}; + + struct LayerInfo { - bool is_mux; - std::vector predecessor; - bool is_defused_nms; - // TODO HRT-4441 change fused_layer from vector. - std::vector fused_nms_layer; - hailo_3d_image_shape_t shape; - hailo_3d_image_shape_t hw_shape; - uint32_t hw_data_bytes; - hailo_format_t format; + LayerType type = LayerType::NOT_SET; hailo_stream_direction_t direction; uint8_t stream_index; uint8_t dma_engine_index; std::string name; - hailo_quant_info_t quant_info; - hailo_nms_info_t nms_info; - uint32_t height_gcd; - std::vector height_ratios; std::string network_name; uint8_t network_index; CONTROL_PROTOCOL__nn_stream_config_t nn_stream_config; uint32_t max_shmifo_size; uint8_t context_index; + uint32_t pad_index = INVALID_PAD_INDEX; + + // Transformation and shape info + hailo_3d_image_shape_t shape; + hailo_3d_image_shape_t hw_shape; + uint32_t hw_data_bytes; + hailo_format_t format; + hailo_quant_info_t quant_info; + hailo_nms_info_t nms_info; + + // Mux info + bool is_mux; + std::vector predecessor; + uint32_t height_gcd; + std::vector height_ratios; + + // Defused nms info + bool is_defused_nms; + // TODO HRT-4441 change fused_layer from vector. + std::vector fused_nms_layer; // Simulation Info BufferIndices buffer_indices; -}; - -struct InterContextLayerInfo { - std::string name; - uint8_t stream_index; - uint8_t dma_engine_index; - uint8_t context_index; - hailo_stream_direction_t direction; - CONTROL_PROTOCOL__nn_stream_config_t nn_stream_config; - std::string network_name; - uint8_t network_index; - uint32_t max_shmifo_size; - uint8_t src_context_index; - uint8_t src_stream_index; - // HRT-7201 - The system supports one src and multiple dstinations. Right now we're saving only one dstination - uint8_t dst_context_index; - uint8_t dst_stream_index; -}; -struct DdrLayerInfo { - std::string name; - uint8_t stream_index; - uint8_t context_index; - hailo_stream_direction_t direction; - CONTROL_PROTOCOL__nn_stream_config_t nn_stream_config; - std::string network_name; - uint8_t network_index; - uint32_t max_shmifo_size; - uint16_t min_buffered_rows; - // total_buffers_per_frame not same as core_buffer_per frame. - //(In DDR core buffer per frame is 1). Used to calc total host descriptors_per_frame. - uint16_t total_buffers_per_frame; - uint8_t src_context_index; - uint8_t src_dma_engine_index; - uint8_t src_stream_index; - uint8_t dst_context_index; - uint8_t dst_dma_engine_index; - uint8_t dst_stream_index; + // Context switch info TODO: we should use std::optional for this structures (or implement our self). + ConnectedContextInfo connected_context_info; + DdrInfo ddr_info; }; // LayerIdentifier = @@ -108,19 +98,7 @@ using LayerIdentifier = std::tuple; inline LayerIdentifier to_layer_identifier(const LayerInfo &info) { - return std::make_tuple(LayerType::BOUNDARY, info.name, info.stream_index); -} - -inline LayerIdentifier to_layer_identifier(const InterContextLayerInfo &info) -{ - return std::make_tuple(LayerType::INTER_CONTEXT, info.name, info.stream_index); -} - -inline LayerIdentifier to_layer_identifier(const DdrLayerInfo &info, HailoRTDriver::DmaDirection direction) -{ - const auto stream_index = (direction == HailoRTDriver::DmaDirection::H2D) ? info.src_stream_index : - info.dst_stream_index; - return std::make_tuple(LayerType::DDR, info.name, stream_index); + return std::make_tuple(info.type, info.name, info.stream_index); } class LayerInfoUtils { diff --git a/hailort/libhailort/src/multi_device_scheduled_stream.cpp b/hailort/libhailort/src/multi_device_scheduled_stream.cpp new file mode 100644 index 0000000..3f8949a --- /dev/null +++ b/hailort/libhailort/src/multi_device_scheduled_stream.cpp @@ -0,0 +1,126 @@ +/** + * Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved. + * Distributed under the MIT license (https://opensource.org/licenses/MIT) + **/ +/** + * @file multi_device_scheduled_stream.cpp + * @brief TODO: brief + * + * TODO: doc + **/ + +#include "multi_device_scheduled_stream.hpp" + +namespace hailort +{ + +hailo_status MultiDeviceScheduledInputStream::send_pending_buffer(size_t device_index) +{ + auto buffer = dequeue(); + CHECK_EXPECTED_AS_STATUS(buffer); + auto status = m_streams[device_index].get().write_buffer_only(buffer.value()); + CHECK_SUCCESS(status); + + VdmaInputStream &vdma_input = static_cast(m_streams[device_index].get()); + return vdma_input.send_pending_buffer(); +} + +Expected MultiDeviceScheduledInputStream::sync_write_raw_buffer(const MemoryView &buffer, + const std::function &should_cancel) +{ + auto network_group_scheduler = m_network_group_scheduler.lock(); + CHECK_AS_EXPECTED(network_group_scheduler, HAILO_INTERNAL_FAILURE); + + auto status = network_group_scheduler->wait_for_write(m_network_group_handle, name(), get_timeout(), should_cancel); + if (HAILO_STREAM_ABORTED_BY_USER == status) { + LOGGER__INFO("Write to stream was aborted."); + return make_unexpected(status); + } + CHECK_SUCCESS_AS_EXPECTED(status); + + status = enqueue(buffer); + if (HAILO_STREAM_ABORTED_BY_USER == status) { + LOGGER__INFO("Enqueue was aborted."); + network_group_scheduler->mark_failed_write(m_network_group_handle, name()); + return make_unexpected(status); + } + CHECK_SUCCESS_AS_EXPECTED(status); + + status = network_group_scheduler->signal_write_finish(m_network_group_handle, name()); + if (HAILO_STREAM_ABORTED_BY_USER == status) { + return make_unexpected(status); + } + CHECK_SUCCESS_AS_EXPECTED(status); + + return buffer.size(); +} + +Expected MultiDeviceScheduledInputStream::get_pending_frames_count() const +{ + return get_queue_size(); +} + +hailo_status MultiDeviceScheduledInputStream::enqueue(const MemoryView &buffer) +{ + return m_queue->enqueue(buffer, get_timeout()); +} + +Expected MultiDeviceScheduledInputStream::dequeue() +{ + return m_queue->dequeue(get_timeout()); +} + +size_t MultiDeviceScheduledInputStream::get_queue_size() const +{ + return m_queue->size(); +} + +hailo_status MultiDeviceScheduledInputStream::abort() +{ + auto status = HAILO_SUCCESS; // Best effort + for (auto &stream : m_streams) { + auto abort_status = stream.get().abort(); + if (HAILO_SUCCESS != status) { + LOGGER__ERROR("Failed to abort input stream. (status: {} device: {})", status, stream.get().get_dev_id()); + status = abort_status; + } + } + m_queue->abort(); + + auto network_group_scheduler = m_network_group_scheduler.lock(); + CHECK(network_group_scheduler, HAILO_INTERNAL_FAILURE); + + auto disable_status = network_group_scheduler->disable_stream(m_network_group_handle, name()); + if (HAILO_SUCCESS != disable_status) { + LOGGER__ERROR("Failed to disable stream in the network group scheduler. (status: {})", disable_status); + status = disable_status; + } + + return status; +} + +hailo_status MultiDeviceScheduledInputStream::clear_abort() +{ + auto status = HAILO_SUCCESS; // Best effort + for (auto &stream : m_streams) { + auto clear_abort_status = stream.get().clear_abort(); + if ((HAILO_SUCCESS != clear_abort_status) && (HAILO_STREAM_NOT_ACTIVATED != clear_abort_status)) { + LOGGER__ERROR("Failed to clear abort input stream. (status: {} device: {})", clear_abort_status, stream.get().get_dev_id()); + status = clear_abort_status; + } + } + m_queue->clear_abort(); + + auto network_group_scheduler = m_network_group_scheduler.lock(); + CHECK(network_group_scheduler, HAILO_INTERNAL_FAILURE); + + auto enable_status = network_group_scheduler->enable_stream(m_network_group_handle, name()); + if (HAILO_SUCCESS != enable_status) { + LOGGER__ERROR("Failed to enable stream in the network group scheduler. (status: {})", enable_status); + status = enable_status; + } + + return status; +} + +} /* namespace hailort */ diff --git a/hailort/libhailort/src/multi_device_scheduled_stream.hpp b/hailort/libhailort/src/multi_device_scheduled_stream.hpp new file mode 100644 index 0000000..89f71a3 --- /dev/null +++ b/hailort/libhailort/src/multi_device_scheduled_stream.hpp @@ -0,0 +1,183 @@ +/** + * Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved. + * Distributed under the MIT license (https://opensource.org/licenses/MIT) + **/ +/** + * @file multi_device_stream.hpp + * @brief Internal multi device stream implementation for scheduled streams + * + **/ + +#ifndef HAILO_MULTI_DEVICE_SCHEDULED_STREAM_HPP_ +#define HAILO_MULTI_DEVICE_SCHEDULED_STREAM_HPP_ + +#include "stream_internal.hpp" +#include "hailo/hailort.h" +#include "vdevice_internal.hpp" +#include "vdma_device.hpp" +#include "scheduled_stream.hpp" +#include "hailo/expected.hpp" + +namespace hailort +{ + +class BuffersQueue +{ +public: + static Expected> create_unique(size_t buffer_size, size_t buffers_count) + { + std::vector queue; + queue.reserve(buffers_count); + for (size_t i = 0; i < (buffers_count); i++) { + auto buff = Buffer::create(buffer_size); + CHECK_EXPECTED(buff); + queue.emplace_back(buff.release()); + } + + auto ptr = make_unique_nothrow(std::move(queue)); + CHECK_NOT_NULL_AS_EXPECTED(ptr, HAILO_OUT_OF_HOST_MEMORY); + return ptr; + } + + hailo_status enqueue(const MemoryView &buff, const std::chrono::milliseconds &timeout) + { + auto status = HAILO_SUCCESS; + { + std::unique_lock lock(m_mutex); + + // TODO: this validation is done in scheduler logic. can be removed? + auto wait_res = m_cv.wait_for(lock, timeout, [this, &status] { + if (m_should_stop) { + status = HAILO_STREAM_ABORTED_BY_USER; + return true; + } + return size() < m_queue.size(); + }); + CHECK(wait_res, HAILO_TIMEOUT, "Failed to enqueue frame with status={}, timeout={}ms", HAILO_TIMEOUT, timeout.count()); + if (HAILO_STREAM_ABORTED_BY_USER == status) { + LOGGER__INFO("'enqueue' was aborted by user"); + return status; + } + + std::memcpy(m_queue[m_head].data(), buff.data(), buff.size()); + m_head = static_cast((m_head + 1) % m_queue.size()); + m_is_empty = false; + } + m_cv.notify_all(); + + return HAILO_SUCCESS; + } + + Expected dequeue(const std::chrono::milliseconds &timeout) + { + auto status = HAILO_SUCCESS; + size_t last_tail = 0; + { + std::unique_lock lock(m_mutex); + + // TODO: this validation is done in scheduler logic. can be removed? + auto wait_res = m_cv.wait_for(lock, timeout, [this, &status] { + if (m_should_stop) { + status = HAILO_STREAM_ABORTED_BY_USER; + return true; + } + return 0 < size(); + }); + CHECK_AS_EXPECTED(wait_res, HAILO_TIMEOUT, "Failed to dequeue frame with status={}, timeout={}ms", HAILO_TIMEOUT, timeout.count()); + if (HAILO_STREAM_ABORTED_BY_USER == status) { + LOGGER__INFO("'dequeue' was aborted by user"); + return make_unexpected(status); + } + + last_tail = m_tail; + m_tail = static_cast((m_tail + 1) % m_queue.size()); + if (m_tail == m_head) { + m_is_empty = true; + } + } + m_cv.notify_all(); + + return MemoryView(m_queue[last_tail]); + } + + size_t size() + { + if (m_head == m_tail) { + return m_is_empty ? 0 : m_queue.size(); + } else if (m_head > m_tail) { + return (m_head - m_tail); + } else { + return (m_queue.size() - m_tail) + m_head; + } + } + + void abort() + { + std::unique_lock lock(m_mutex); + m_should_stop = true; + m_cv.notify_all(); + } + + void clear_abort() + { + std::unique_lock lock(m_mutex); + m_should_stop = false; + m_cv.notify_all(); + } + + BuffersQueue(std::vector &&queue) : m_queue(std::move(queue)), m_head(0), m_tail(0), m_is_empty(true), m_should_stop(false) + {} + +private: + std::vector m_queue; + std::atomic_uint32_t m_head; + std::atomic_uint32_t m_tail; + + std::atomic_bool m_is_empty; + + std::condition_variable m_cv; + std::mutex m_mutex; + std::atomic_bool m_should_stop; +}; + +class MultiDeviceScheduledInputStream : public ScheduledInputStream { +public: + MultiDeviceScheduledInputStream(MultiDeviceScheduledInputStream &&other) : + ScheduledInputStream(std::move(other)), + m_queue(std::move(other.m_queue)) + {} + + explicit MultiDeviceScheduledInputStream( + std::vector> &&streams, + const scheduler_ng_handle_t &network_group_handle, + EventPtr &&network_group_activated_event, + const LayerInfo &layer_info, + NetworkGroupSchedulerWeakPtr network_group_scheduler, + std::unique_ptr &&frames_queue, + hailo_status &status) : + ScheduledInputStream(std::move(streams), network_group_handle, + std::move(network_group_activated_event), layer_info, network_group_scheduler, status), + m_queue(std::move(frames_queue)) + { + } + + virtual hailo_status send_pending_buffer(size_t device_index = 0) override; + virtual Expected get_pending_frames_count() const override; + +protected: + virtual Expected sync_write_raw_buffer(const MemoryView &buffer, + const std::function &should_cancel = []() { return false; }) override; + virtual hailo_status abort() override; + virtual hailo_status clear_abort() override; + +private: + hailo_status enqueue(const MemoryView &buffer); + Expected dequeue(); + size_t get_queue_size() const; + + std::unique_ptr m_queue; +}; + +} /* namespace hailort */ + +#endif /* HAILO_MULTI_DEVICE_SCHEDULED_STREAM_HPP_ */ diff --git a/hailort/libhailort/src/net_flow/CMakeLists.txt b/hailort/libhailort/src/net_flow/CMakeLists.txt new file mode 100644 index 0000000..430284e --- /dev/null +++ b/hailort/libhailort/src/net_flow/CMakeLists.txt @@ -0,0 +1 @@ +cmake_minimum_required(VERSION 3.0.0) \ No newline at end of file diff --git a/hailort/libhailort/src/net_flow/ops/yolo_post_processing.hpp b/hailort/libhailort/src/net_flow/ops/yolo_post_processing.hpp new file mode 100644 index 0000000..9db6e53 --- /dev/null +++ b/hailort/libhailort/src/net_flow/ops/yolo_post_processing.hpp @@ -0,0 +1,386 @@ +/** + * Copyright (c) 2022 Hailo Technologies Ltd. All rights reserved. + * Distributed under the MIT license (https://opensource.org/licenses/MIT) +**/ +/** + * @file yolo_post_processing.hpp + * @brief YOLO post processing + * + * https://learnopencv.com/object-detection-using-yolov5-and-opencv-dnn-in-c-and-python : + * The headline '4.3.5 POST-PROCESSING YOLOv5 Prediction Output' contains explanations on the YOLOv5 post-processing. + **/ + +#ifndef _HAILO_YOLO_POST_PROCESSING_HPP_ +#define _HAILO_YOLO_POST_PROCESSING_HPP_ + +#include "hailo/hailort.hpp" + +namespace hailort +{ +namespace net_flow +{ + +static const float32_t REMOVED_CLASS_SCORE = 0.0f; + +struct DetectionBbox +{ + DetectionBbox(float32_t x_min, float32_t y_min, float32_t width, float32_t height, float32_t score, uint32_t class_id) : + m_class_id(class_id), m_bbox{y_min, x_min, (y_min + height), (x_min + width), score} {} + + uint32_t m_class_id; + hailo_bbox_float32_t m_bbox; +}; + +/** + * Computes the value of the sigmoid function on @a x input: f(x) = 1/(1 + e^-x) +*/ +inline float32_t sigmoid(float32_t x) +{ + return 1.0f / (1.0f + expf(-x)); +} + +// TODO: Maybe change to dequantize entry and add @a should_sigmoid to dequantize_output_buffer in `quantization.hpp`. +// Its an API addition but does not break anything. +template +HostType apply_dequantization_activation(DeviceType value, hailo_quant_info_t quant_info, bool should_sigmoid) +{ + auto dequantized_val = Quantization::dequantize_output(value, quant_info); + + if (should_sigmoid) { + return sigmoid(dequantized_val); + } else { + return dequantized_val; + } +} + +class YOLOv5PostProcessingOp +{ +public: + + /** + * @param[in] anchors A vector of anchors, each element in the vector represents the anchors for a specific layer. + * @param[in] image_height The image height. + * @param[in] image_width The image width. + * @param[in] confidence_threshold User given confidence threshold for a bbox. A bbox will be consider as detection if the + * (objectness * class_score) is higher then the confidence_threshold. + * @param[in] iou_threshold User given IOU threshold (intersection over union). This threshold is for performing + * Non-maximum suppression (Removing overlapping boxes). + * @param[in] num_of_classes The model's number of classes. (This depends on the dataset that the model trained on). + * @param[in] should_dequantize Indicates whether the post-processing function should de-quantize the tensors data. + * @param[in] max_bboxes_per_class Maximum amount of bboxes per nms class. + * @param[in] should_sigmoid Indicates whether sigmoid() function should be performed on the @a tensors' data. + * @param[in] one_class_per_bbox Indicates whether the post-processing function should return only one class per detected bbox. + * If set to flase - Two different classes can have the same bbox. + * + * @return Upon success, returns a vector of detection objects. Otherwise, returns Unexpected of ::hailo_status error. + * TODO: For integrating with SDK Json - consider changing anchors vector to a vector of w,h pairs. + * HRT-8526 - Add post-processing support for quantized data + */ + static Expected create(const std::vector> &anchors, + const std::vector &shapes, const std::vector &formats, + const std::vector &quant_infos, float32_t image_height, float32_t image_width, + float32_t confidence_threshold, float32_t iou_threshold, uint32_t num_of_classes, bool should_dequantize, + uint32_t max_bboxes_per_class, bool should_sigmoid, bool one_class_per_bbox=true) + { + return YOLOv5PostProcessingOp(anchors, shapes, formats, quant_infos, image_height, image_width, confidence_threshold, iou_threshold, + num_of_classes, should_dequantize, max_bboxes_per_class, should_sigmoid, one_class_per_bbox); + } + + /** + * Execute YOLOv5 post-processing on inferred data. + * @a HostType can be uint16 or float32. + * TODO: HRT-8525 - Add support for these types. Currently we support only in: @a HostType = float32_t + * + * @param[in] tensors A vector of the input buffers for the post-processing, + * the buffer's shape and the quantization info. + * NOTE: The Order of the @a tensors vector should be corresponding to the order of @a anchors vector given in the creation of YOLOv5PostProcessingOp. + * + * @return Upon success, returns a buffer containing the detection objects, in ::HAILO_FORMAT_ORDER_HAILO_NMS format. + * Otherwise, returns Unexpected of ::hailo_status error. + */ + template + hailo_status execute(const std::vector &tensors, MemoryView dst_view) + { + CHECK(tensors.size() == m_anchors.size(), HAILO_INVALID_ARGUMENT, + "Anchors vector count must be equal to data vector count. Anchors size is {}, data size is {}", m_anchors.size(), tensors.size()); + + std::vector detections; + std::vector classes_detections_count(m_num_of_classes, 0); + detections.reserve(m_max_bboxes_per_class * m_num_of_classes); + for (size_t i = 0; i < tensors.size(); i++) { + hailo_status status; + if (m_formants[i].type == HAILO_FORMAT_TYPE_UINT8) { + status = extract_detections(tensors[i], m_quant_infos[i], m_shapes[i], + m_anchors[i], detections, classes_detections_count); + } else if (m_formants[i].type == HAILO_FORMAT_TYPE_UINT16) { + status = extract_detections(tensors[i], m_quant_infos[i], m_shapes[i], + m_anchors[i], detections, classes_detections_count); + } else { + CHECK_SUCCESS(HAILO_INVALID_ARGUMENT, "YOLOv5 post-process received invalid input type"); + } + CHECK_SUCCESS(status); + } + + // TODO: Add support for TF_FORMAT_ORDER + return hailo_nms_format(std::move(detections), dst_view, classes_detections_count); + } + +private: + YOLOv5PostProcessingOp(const std::vector> &anchors, const std::vector &shapes, + const std::vector &formats, const std::vector &quant_infos, float32_t image_height, float32_t image_width, + float32_t confidence_threshold, float32_t iou_threshold, uint32_t num_of_classes, bool should_dequantize, uint32_t max_bboxes_per_class, bool should_sigmoid, bool one_class_per_bbox) : + m_anchors(anchors), m_shapes(shapes), m_formants(formats), m_quant_infos(quant_infos), m_image_height(image_height), m_image_width(image_width), + m_confidence_threshold(confidence_threshold), m_iou_threshold(iou_threshold), m_num_of_classes(num_of_classes), + m_should_dequantize(should_dequantize), m_max_bboxes_per_class(max_bboxes_per_class), m_should_sigmoid(should_sigmoid), + m_one_class_per_bbox(one_class_per_bbox) + { + (void)m_should_dequantize; + } + + template + std::pair get_max_class(const uint8_t *data, size_t entry_classes_idx, float32_t objectness, hailo_quant_info_t quant_info) + { + std::pair max_id_score_pair; + for (uint32_t class_index = 0; class_index < m_num_of_classes; class_index++) { + auto class_confidence = apply_dequantization_activation(data[entry_classes_idx + class_index], quant_info, m_should_sigmoid); + auto class_score = class_confidence * objectness; + if (class_score > max_id_score_pair.second) { + max_id_score_pair.first = class_index; + max_id_score_pair.second = class_score; + } + } + return max_id_score_pair; + } + + /** + * Extract bboxes with confidence level higher then @a confidence_threshold from @a buffer and add them to @a detections. + * + * @param[in] buffer Buffer containing data after inference and + * @param[in] quant_info Quantization info corresponding to the @a buffer layer. + * @param[in] shape Shape corresponding to the @a buffer layer. + * @param[in] image_height The image height. + * @param[in] image_width The image width. + * @param[in] layer_anchors The layer anchors corresponding to layer receiving the @a buffer. + * Each anchor is structured as {width, height} pairs. + * @param[in] confidence_threshold User given confidence threshold for a bbox. A bbox will be consider as detection if the + * (objectness * class_score) is higher then the confidence_threshold. + * @param[in] num_of_classes The model's number of classes. + * @param[in] should_sigmoid Indicates whether sigmoid() function should be performed on the @a buffer's data. + * @param[inout] detections A vector of ::DetectionBbox objects, to add the detected bboxes to. + * + * @return Upon success, returns ::HAILO_SUCCESS. Otherwise, returns a ::hailo_status error. + */ + template + hailo_status extract_detections(const MemoryView &buffer, hailo_quant_info_t quant_info, hailo_3d_image_shape_t shape, + const std::vector &layer_anchors, std::vector &detections, std::vector &classes_detections_count) + { + static const uint32_t X_INDEX = 0; + static const uint32_t Y_INDEX = 1; + static const uint32_t W_INDEX = 2; + static const uint32_t H_INDEX = 3; + static const uint32_t OBJECTNESS_INDEX = 4; + static const uint32_t CLASSES_START_INDEX = 5; + + // Each layer anchors vector is structured as {w,h} pairs. + // For example, if we have a vector of size 6 (default YOLOv5 vector) then we have 3 anchors for this layer. + assert(layer_anchors.size() % 2 == 0); + const size_t num_of_anchors = (layer_anchors.size() / 2); + + const uint32_t entry_size = CLASSES_START_INDEX + m_num_of_classes; + auto number_of_entries = shape.height * shape.width * num_of_anchors; + // TODO: this can also be part of the Op configuration + auto buffer_size = number_of_entries * entry_size; + CHECK(buffer_size == buffer.size(), HAILO_INVALID_ARGUMENT, + "Failed to extract_detections, buffer_size should be {}, but is {}", buffer_size, buffer.size()); + + auto *data = buffer.data(); + for (size_t row = 0; row < shape.height; row++) { + for (size_t col = 0; col < shape.width; col++) { + for (size_t anchor = 0; anchor < num_of_anchors; anchor++) { + auto entry_idx = entry_size * (num_of_anchors * (shape.height * row + col) + anchor); + + auto objectness = apply_dequantization_activation(data[entry_idx + OBJECTNESS_INDEX], quant_info, m_should_sigmoid); + if (objectness < m_confidence_threshold) { + continue; + } + + auto tx = apply_dequantization_activation(data[entry_idx + X_INDEX], quant_info, m_should_sigmoid); + auto ty = apply_dequantization_activation(data[entry_idx + Y_INDEX], quant_info, m_should_sigmoid); + auto tw = apply_dequantization_activation(data[entry_idx + W_INDEX], quant_info, m_should_sigmoid); + auto th = apply_dequantization_activation(data[entry_idx + H_INDEX], quant_info, m_should_sigmoid); + + // Source for the calculations - https://github.com/ultralytics/yolov5/blob/HEAD/models/yolo.py + // Explanations for the calculations - https://github.com/ultralytics/yolov5/issues/471 + auto w = pow(2.0f * tw, 2.0f) * static_cast(layer_anchors[anchor * 2]) / m_image_width; + auto h = pow(2.0f * th, 2.0f) * static_cast(layer_anchors[anchor * 2 + 1]) / m_image_height; + auto x_center = (tx * 2.0f - 0.5f + static_cast(col)) / static_cast(shape.width); + auto y_center = (ty * 2.0f - 0.5f + static_cast(row)) / static_cast(shape.height); + auto x_min = (x_center - (w / 2.0f)); + auto y_min = (y_center - (h / 2.0f)); + + if (m_one_class_per_bbox) { + auto entry_classes_idx = entry_idx + CLASSES_START_INDEX; + auto max_id_score_pair = get_max_class(data, entry_classes_idx , objectness, quant_info); + if (max_id_score_pair.second >= m_confidence_threshold) { + detections.emplace_back(x_min, y_min, w, h, max_id_score_pair.second, max_id_score_pair.first); + classes_detections_count[max_id_score_pair.first]++; + } + } + else { + for (uint32_t class_index = 0; class_index < m_num_of_classes; class_index++) { + auto class_confidence = apply_dequantization_activation( + data[entry_idx + CLASSES_START_INDEX + class_index], quant_info, m_should_sigmoid); + auto class_score = class_confidence * objectness; + if (class_score >= m_confidence_threshold) { + detections.emplace_back(x_min, y_min, w, h, class_score, class_index); + classes_detections_count[class_index]++; + } + } + } + } + } + } + + return HAILO_SUCCESS; + } + + /** + * Computes the IOU ratio of @a box_1 and @a box_2 + */ + float compute_iou(const DetectionBbox &box_1, const DetectionBbox &box_2) + { + const float overlap_area_width = std::min(box_1.m_bbox.x_max, box_2.m_bbox.x_max) - std::max(box_1.m_bbox.x_min, box_2.m_bbox.x_min); + const float overlap_area_height = std::min(box_1.m_bbox.y_max, box_2.m_bbox.y_max) - std::max(box_1.m_bbox.y_min, box_2.m_bbox.y_min); + if (overlap_area_width <= 0.0f || overlap_area_height <= 0.0f) { + return 0.0f; + } + const float intersection = overlap_area_width * overlap_area_height; + const float box_1_area = (box_1.m_bbox.y_max - box_1.m_bbox.y_min) * (box_1.m_bbox.x_max - box_1.m_bbox.x_min); + const float box_2_area = (box_2.m_bbox.y_max - box_2.m_bbox.y_min) * (box_2.m_bbox.x_max - box_2.m_bbox.x_min); + const float union_area = (box_1_area + box_2_area - intersection); + + return (intersection / union_area); + } + + /** + * Removes overlapping boxes in @a detections by setting the class confidence to zero. + * + * @param[in] detections A vector of @a DetectionBbox containing the detections boxes after ::extract_detections() function. + * + */ + void remove_overlapping_boxes(std::vector &detections, std::vector &classes_detections_count) + { + std::sort(detections.begin(), detections.end(), + [](DetectionBbox a, DetectionBbox b) + { return a.m_bbox.score > b.m_bbox.score; }); + + for (size_t i = 0; i < detections.size(); i++) { + if (detections[i].m_bbox.score == REMOVED_CLASS_SCORE) { + // Detection overlapped with a higher score detection + continue; + } + + for (size_t j = i + 1; j < detections.size(); j++) { + if (detections[j].m_bbox.score == REMOVED_CLASS_SCORE) { + // Detection overlapped with a higher score detection + continue; + } + + if ((detections[i].m_class_id == detections[j].m_class_id) && + (compute_iou(detections[i], detections[j]) >= m_iou_threshold)) { + // Remove detections[j] if the iou is higher then the threshold + detections[j].m_bbox.score = REMOVED_CLASS_SCORE; + assert(classes_detections_count[detections[j].m_class_id] > 0); + classes_detections_count[detections[j].m_class_id]--; + } + } + } + } + + /* + * For each class the layout is + * \code + * struct (packed) { + * uint16_t/float32_t bbox_count; + * hailo_bbox_t/hailo_bbox_float32_t bbox[bbox_count]; + * }; + * \endcode + */ + void fill_nms_format_buffer(MemoryView &buffer, const std::vector &detections, + std::vector &classes_detections_count) + { + // Calculate the number of detections before each class, to help us later calculate the buffer_offset for it's detections. + std::vector num_of_detections_before; + num_of_detections_before.reserve(m_num_of_classes); + uint32_t ignored_detections_count = 0; + for (size_t class_idx = 0; class_idx < m_num_of_classes; class_idx++) { + if (classes_detections_count[class_idx] > m_max_bboxes_per_class) { + ignored_detections_count += (classes_detections_count[class_idx] - m_max_bboxes_per_class); + classes_detections_count[class_idx] = m_max_bboxes_per_class; + } + + if (0 == class_idx) { + num_of_detections_before[class_idx] = 0; + } + else { + num_of_detections_before[class_idx] = num_of_detections_before[class_idx - 1] + classes_detections_count[class_idx - 1]; + } + + // Fill `bbox_count` value for class_idx in the result buffer + float32_t bbox_count_casted = static_cast(classes_detections_count[class_idx]); + auto buffer_offset = (class_idx * sizeof(bbox_count_casted)) + (num_of_detections_before[class_idx] * sizeof(hailo_bbox_float32_t)); + memcpy((buffer.data() + buffer_offset), &bbox_count_casted, sizeof(bbox_count_casted)); + } + + for (auto &detection : detections) { + if (REMOVED_CLASS_SCORE == detection.m_bbox.score) { + // Detection overlapped with a higher score detection and removed in remove_overlapping_boxes() + continue; + } + if (0 == classes_detections_count[detection.m_class_id]) { + // This class' detections count is higher then m_max_bboxes_per_class. + // This detection is ignored due to having lower score (detections vector is sorted by score). + continue; + } + + auto buffer_offset = ((detection.m_class_id + 1) * sizeof(float32_t)) + + (num_of_detections_before[detection.m_class_id] * sizeof(hailo_bbox_float32_t)); + + assert((buffer_offset + sizeof(hailo_bbox_float32_t)) <= buffer.size()); + memcpy((hailo_bbox_float32_t*)(buffer.data() + buffer_offset), &detection.m_bbox, sizeof(hailo_bbox_float32_t)); + num_of_detections_before[detection.m_class_id]++; + classes_detections_count[detection.m_class_id]--; + } + + if (0 != ignored_detections_count) { + LOGGER__INFO("{} Detections were ignored, due to `max_bboxes_per_class` defined as {}.", + ignored_detections_count, m_max_bboxes_per_class); + } + } + + hailo_status hailo_nms_format(std::vector &&detections, MemoryView dst_view, std::vector &classes_detections_count) + { + remove_overlapping_boxes(detections, classes_detections_count); + fill_nms_format_buffer(dst_view, detections, classes_detections_count); + return HAILO_SUCCESS; + } + + std::vector> m_anchors; + std::vector m_shapes; + std::vector m_formants; + std::vector m_quant_infos; + float32_t m_image_height; + float32_t m_image_width; + float32_t m_confidence_threshold; + float32_t m_iou_threshold; + uint32_t m_num_of_classes; + bool m_should_dequantize; + uint32_t m_max_bboxes_per_class; + bool m_should_sigmoid; + bool m_one_class_per_bbox; +}; + +} /* namespace net_flow */ +} /* namespace hailort */ + +#endif /* _HAILO_YOLO_POST_PROCESSING_HPP_ */ diff --git a/hailort/libhailort/src/network_group_client.cpp b/hailort/libhailort/src/network_group_client.cpp index b8ac31d..d522693 100644 --- a/hailort/libhailort/src/network_group_client.cpp +++ b/hailort/libhailort/src/network_group_client.cpp @@ -20,8 +20,8 @@ ConfiguredNetworkGroupClient::ConfiguredNetworkGroupClient(std::unique_ptrConfiguredNetworkGroup_get_name(m_handle); - if (reply.status() != HAILO_SUCCESS) { + auto reply = m_client->ConfiguredNetworkGroup_name(m_handle); + if (!reply) { LOGGER__ERROR("get_network_group_name failed with status {}", reply.status()); return; } @@ -32,16 +32,15 @@ ConfiguredNetworkGroupClient::~ConfiguredNetworkGroupClient() { auto reply = m_client->ConfiguredNetworkGroup_release(m_handle); if (reply != HAILO_SUCCESS) { - LOGGER__CRITICAL("ConfiguredNetworkGroup_release failed!"); + LOGGER__CRITICAL("ConfiguredNetworkGroup_release failed with status: {}", reply); } } Expected> ConfiguredNetworkGroupClient::activate( const hailo_activate_network_group_params_t &network_group_params) { - // TODO: HRT-6606 (void)network_group_params; - LOGGER__ERROR("activate is not supported when using multi process service"); + LOGGER__ERROR("ConfiguredNetworkGroup::activate function is not supported when using multi-process service, please use HailoRT Scheduler."); return make_unexpected(HAILO_INVALID_OPERATION); } @@ -51,15 +50,6 @@ Expected ConfiguredNetworkGroupClient::get_latency_mea return m_client->ConfiguredNetworkGroup_get_latency_measurement(m_handle, network_name); } -Expected> ConfiguredNetworkGroupClient::activate_internal( - const hailo_activate_network_group_params_t &network_group_params, uint16_t dynamic_batch_size) -{ - // TODO: HRT-6606 - (void)network_group_params; - (void)dynamic_batch_size; - return make_unexpected(HAILO_INVALID_OPERATION); -} - const std::string &ConfiguredNetworkGroupClient::get_network_group_name() const { return m_network_group_name; @@ -77,65 +67,65 @@ Expected ConfiguredNetworkGroupClient::get_default_str std::vector> ConfiguredNetworkGroupClient::get_input_streams_by_interface(hailo_stream_interface_t) { - LOGGER__ERROR("get_input_streams_by_interface is not supported when using multi process service"); + LOGGER__ERROR("ConfiguredNetworkGroup::get_input_streams_by_interface function is not supported when using multi-process service"); std::vector> empty_vec; return empty_vec; } std::vector> ConfiguredNetworkGroupClient::get_output_streams_by_interface(hailo_stream_interface_t) { - LOGGER__ERROR("get_output_streams_by_interface is not supported when using multi process service"); + LOGGER__ERROR("ConfiguredNetworkGroup::get_output_streams_by_interface function is not supported when using multi-process service"); std::vector> empty_vec; return empty_vec; } ExpectedRef ConfiguredNetworkGroupClient::get_input_stream_by_name(const std::string&) { - LOGGER__ERROR("get_input_stream_by_name is not supported when using multi process service"); + LOGGER__ERROR("ConfiguredNetworkGroup::get_input_stream_by_name function is not supported when using multi-process service"); return make_unexpected(HAILO_INVALID_OPERATION); } ExpectedRef ConfiguredNetworkGroupClient::get_output_stream_by_name(const std::string&) { - LOGGER__ERROR("get_output_stream_by_name is not supported when using multi process service"); + LOGGER__ERROR("ConfiguredNetworkGroup::get_output_stream_by_name function is not supported when using multi-process service"); return make_unexpected(HAILO_INVALID_OPERATION); } Expected ConfiguredNetworkGroupClient::get_input_streams_by_network(const std::string&) { - LOGGER__ERROR("get_input_streams_by_network is not supported when using multi process service"); + LOGGER__ERROR("ConfiguredNetworkGroup::get_input_streams_by_network function is not supported when using multi-process service"); return make_unexpected(HAILO_INVALID_OPERATION); } Expected ConfiguredNetworkGroupClient::get_output_streams_by_network(const std::string&) { - LOGGER__ERROR("get_output_streams_by_network is not supported when using multi process service"); + LOGGER__ERROR("ConfiguredNetworkGroup::get_output_streams_by_network function is not supported when using multi-process service"); return make_unexpected(HAILO_INVALID_OPERATION); } InputStreamRefVector ConfiguredNetworkGroupClient::get_input_streams() { - LOGGER__ERROR("get_input_streams is not supported when using multi process service"); + LOGGER__ERROR("ConfiguredNetworkGroup::get_input_streams function is not supported when using multi-process service"); InputStreamRefVector empty_vec; return empty_vec; } OutputStreamRefVector ConfiguredNetworkGroupClient::get_output_streams() { - LOGGER__ERROR("get_output_streams is not supported when using multi process service"); + LOGGER__ERROR("ConfiguredNetworkGroup::get_output_streams function is not supported when using multi-process service"); OutputStreamRefVector empty_vec; return empty_vec; } Expected ConfiguredNetworkGroupClient::get_output_streams_from_vstream_names(const std::map&) { - LOGGER__ERROR("get_output_streams_from_vstream_names is not supported when using multi process service"); + LOGGER__ERROR("ConfiguredNetworkGroup::get_output_streams_from_vstream_names function is not supported when using multi-process service"); return make_unexpected(HAILO_INVALID_OPERATION); } hailo_status ConfiguredNetworkGroupClient::wait_for_activation(const std::chrono::milliseconds&) { - LOGGER__ERROR("wait_for_activation is not supported when using multi process service"); + LOGGER__ERROR("ConfiguredNetworkGroup::wait_for_activation function is not supported when using multi-process service"); return HAILO_NOT_IMPLEMENTED; } @@ -147,13 +137,8 @@ Expected>> ConfiguredNetworkGroupClient::ge Expected>> ConfiguredNetworkGroupClient::make_output_vstream_params_groups( bool quantized, hailo_format_type_t format_type, uint32_t timeout_ms, uint32_t queue_size) { - // TODO: HRT-6606 - LOGGER__ERROR("make_output_vstream_params_groups is not supported when using multi process service"); - (void)quantized; - (void)format_type; - (void)timeout_ms; - (void)queue_size; - return make_unexpected(HAILO_NOT_IMPLEMENTED); + return m_client->ConfiguredNetworkGroup_make_output_vstream_params_groups(m_handle, + quantized, format_type, timeout_ms, queue_size); } Expected> ConfiguredNetworkGroupClient::make_input_vstream_params( @@ -212,30 +197,34 @@ hailo_status ConfiguredNetworkGroupClient::set_scheduler_threshold(uint32_t thre AccumulatorPtr ConfiguredNetworkGroupClient::get_activation_time_accumulator() const { - LOGGER__ERROR("get_activation_time_accumulator is not supported when using multi process service"); - // TODO: HRT-6606 - return nullptr; + LOGGER__ERROR("ConfiguredNetworkGroup::get_activation_time_accumulator function is not supported when using multi-process service"); + return AccumulatorPtr(); } AccumulatorPtr ConfiguredNetworkGroupClient::get_deactivation_time_accumulator() const { - LOGGER__ERROR("get_deactivation_time_accumulator is not supported when using multi process service"); - // TODO: HRT-6606 - return nullptr; + LOGGER__ERROR("ConfiguredNetworkGroup::get_deactivation_time_accumulator function is not supported when using multi-process service"); + return AccumulatorPtr(); } bool ConfiguredNetworkGroupClient::is_multi_context() const { - LOGGER__ERROR("is_multi_context is not supported when using multi process service"); - // TODO: HRT-6606 - return false; + auto reply = m_client->ConfiguredNetworkGroup_is_multi_context(m_handle); + if (reply.status() != HAILO_SUCCESS) { + LOGGER__ERROR("is_multi_context failed with status {}", reply.status()); + return false; + } + return reply.value(); } const ConfigureNetworkParams ConfiguredNetworkGroupClient::get_config_params() const { - LOGGER__ERROR("get_config_params is not supported when using multi process service"); - // TODO: HRT-6606 - return {}; + auto reply = m_client->ConfiguredNetworkGroup_get_config_params(m_handle); + if (reply.status() != HAILO_SUCCESS) { + LOGGER__ERROR("get_config_params failed with status {}", reply.status()); + return ConfigureNetworkParams(); + } + return reply.value(); } Expected> ConfiguredNetworkGroupClient::create_input_vstreams(const std::map &inputs_params) diff --git a/hailort/libhailort/src/network_group_metadata.cpp b/hailort/libhailort/src/network_group_metadata.cpp new file mode 100644 index 0000000..32a61c9 --- /dev/null +++ b/hailort/libhailort/src/network_group_metadata.cpp @@ -0,0 +1,463 @@ +/** + * Copyright (c) 2022 Hailo Technologies Ltd. All rights reserved. + * Distributed under the MIT license (https://opensource.org/licenses/MIT) +**/ +/** + * @file network_group_metadata.cpp + * @brief Contains all relevant information about a network group from the hef. + **/ + +#include "network_group_metadata.hpp" + +namespace hailort +{ + +static void get_demuxes_names_impl(const LayerInfo &info, std::vector &res) +{ + if (!info.is_mux) { + res.push_back(info.name); + } else { + for (auto &pred : info.predecessor) { + get_demuxes_names_impl(pred, res); + } + } +} + +static std::vector get_demuxes_names(const LayerInfo &info) +{ + std::vector res; + get_demuxes_names_impl(info, res); + return res; +} + +static bool is_edge_under_mux(const LayerInfo &info, const std::string &edge_name) +{ + if (!info.is_mux) { + return edge_name == info.name; + } + for (const auto &pred : info.predecessor) { + if (info.is_mux) { + if (is_edge_under_mux(pred, edge_name)) { + return true; + } + } else { + if (edge_name == pred.name) { + return true; + } + } + } + return false; +} + + +PreliminaryContextMetadata::PreliminaryContextMetadata(std::vector &&operations, + ConfigBufferInfoMap&& config_buffers_info) : + m_operations(std::move(operations)), + m_config_buffers_info(std::move(config_buffers_info)) +{} + +const std::vector &PreliminaryContextMetadata::get_operations() const +{ + return m_operations; +} + +const ConfigBufferInfoMap &PreliminaryContextMetadata::config_buffers_info() const +{ + return m_config_buffers_info; +} + +ContextMetadata::ContextMetadata(std::vector &&operations, + ConfigBufferInfoMap&& config_buffers_info) : + m_operations(std::move(operations)), + m_config_buffers_info(std::move(config_buffers_info)) +{} + +const std::vector &ContextMetadata::get_operations() const +{ + return m_operations; +} + +const ConfigBufferInfoMap &ContextMetadata::config_buffers_info() const +{ + return m_config_buffers_info; +} + +void ContextMetadata::add_boundary_layer(const LayerInfo &layer_info) +{ + if (HAILO_H2D_STREAM == layer_info.direction) { + m_boundary_input_layers.push_back(layer_info); + } else { + m_boundary_output_layers.push_back(layer_info); + } +} + +void ContextMetadata::add_inter_context_layer(const LayerInfo &layer_info) +{ + if (HAILO_H2D_STREAM == layer_info.direction) { + m_inter_context_input_layers.push_back(layer_info); + } else { + m_inter_context_output_layers.push_back(layer_info); + } +} + +void ContextMetadata::add_ddr_layer(const LayerInfo &layer_info) +{ + if (HAILO_H2D_STREAM == layer_info.direction) { + m_ddr_input_layers.push_back(layer_info); + } else { + m_ddr_output_layers.push_back(layer_info); + } +} + +const std::vector &ContextMetadata::get_boundary_input_layers() const +{ + return m_boundary_input_layers; +} + +const std::vector &ContextMetadata::get_boundary_output_layers() const +{ + return m_boundary_output_layers; +} + +const std::vector &ContextMetadata::get_inter_context_input_layers() const +{ + return m_inter_context_input_layers; +} + +const std::vector &ContextMetadata::get_inter_context_output_layers() const +{ + return m_inter_context_output_layers; +} + +const std::vector &ContextMetadata::get_ddr_input_layers() const +{ + return m_ddr_input_layers; +} + +const std::vector &ContextMetadata::get_ddr_output_layers() const +{ + return m_ddr_output_layers; +} + +NetworkGroupMetadata::NetworkGroupMetadata(const std::string &network_group_name, + PreliminaryContextMetadata &&preliminary_context, + std::vector &&dynamic_contexts, + std::vector &&config_channels_info, + std::vector &&sorted_output_names, + SupportedFeatures &supported_features, const std::vector &sorted_network_names) + : m_preliminary_context(std::move(preliminary_context)), + m_dynamic_contexts(std::move(dynamic_contexts)), + m_config_channels_info(std::move(config_channels_info)), + m_network_group_name(network_group_name), m_sorted_output_names(std::move(sorted_output_names)), + m_supported_features(supported_features), m_sorted_network_names(sorted_network_names) {} + +Expected NetworkGroupMetadata::get_layer_info_by_stream_name(const std::string &stream_name) const +{ + for (auto layer_info : get_all_layer_infos()) { + if (layer_info.name == stream_name) { + return layer_info; + } + } + LOGGER__ERROR("Failed to find layer with name {}", stream_name); + return make_unexpected(HAILO_NOT_FOUND); +} + +std::vector NetworkGroupMetadata::get_input_layer_infos() const +{ + std::vector res; + // Edge layers exists only in the dynamic context. + for (const auto &context : m_dynamic_contexts) { + for (const auto &layer_info : context.get_boundary_input_layers()) { + res.emplace_back(layer_info); + } + } + return res; +} + +std::vector NetworkGroupMetadata::get_output_layer_infos() const +{ + std::vector res; + // Edge layers exists only in the dynamic context. + for (const auto &context : m_dynamic_contexts) { + for (const auto &layer_info : context.get_boundary_output_layers()) { + res.emplace_back(layer_info); + } + } + return res; +} + +std::vector NetworkGroupMetadata::get_all_layer_infos() const +{ + const auto input_layer_infos = get_input_layer_infos(); + const auto output_layer_infos = get_output_layer_infos(); + + std::vector res; + res.reserve(input_layer_infos.size() + output_layer_infos.size()); + res.insert(res.end(), input_layer_infos.begin(), input_layer_infos.end()); + res.insert(res.end(), output_layer_infos.begin(), output_layer_infos.end()); + + return res; +} + +Expected> NetworkGroupMetadata::get_input_layer_infos(const std::string &network_name) const +{ + std::vector res; + // Edge layers exists only in the dynamic context. + for (const auto &context : m_dynamic_contexts) { + for (const auto &layer_info : context.get_boundary_input_layers()) { + if ((layer_info.network_name == network_name) || (network_name.empty()) || (network_name == default_network_name())) { + res.emplace_back(layer_info); + } + } + } + CHECK_AS_EXPECTED(res.size() > 0, HAILO_NOT_FOUND, "Network name {} is not found in networks metadata", network_name); + return res; +} + +Expected> NetworkGroupMetadata::get_output_layer_infos(const std::string &network_name) const +{ + std::vector res; + // Edge layers exists only in the dynamic context. + for (const auto &context : m_dynamic_contexts) { + for (auto &layer_info : context.get_boundary_output_layers()) { + if ((layer_info.network_name == network_name) || (network_name.empty()) || (network_name == default_network_name())) { + res.emplace_back(layer_info); + } + } + } + CHECK_AS_EXPECTED(res.size() > 0, HAILO_NOT_FOUND, "Network name {} is not found in networks metadata", network_name); + return res; +} + +const PreliminaryContextMetadata &NetworkGroupMetadata::preliminary_context() const +{ + return m_preliminary_context; +} + +const std::vector &NetworkGroupMetadata::dynamic_contexts() const +{ + return m_dynamic_contexts; +} + +const std::vector &NetworkGroupMetadata::config_channels_info() const +{ + return m_config_channels_info; +} + +Expected> NetworkGroupMetadata::get_all_layer_infos(const std::string &network_name) const +{ + auto input_layer_infos = get_input_layer_infos(network_name); + CHECK_EXPECTED(input_layer_infos); + + auto output_layer_infos = get_output_layer_infos(network_name); + CHECK_EXPECTED(output_layer_infos); + + std::vector res; + res.reserve(input_layer_infos->size() + output_layer_infos->size()); + res.insert(res.end(), input_layer_infos->begin(), input_layer_infos->end()); + res.insert(res.end(), output_layer_infos->begin(), output_layer_infos->end()); + + return res; +} + +Expected> NetworkGroupMetadata::get_input_stream_infos(const std::string &network_name) const +{ + auto input_layer_infos = get_input_layer_infos(network_name); + CHECK_EXPECTED(input_layer_infos); + + return convert_layer_infos_to_stream_infos(input_layer_infos.value()); +} + +Expected> NetworkGroupMetadata::get_output_stream_infos(const std::string &network_name) const +{ + auto output_layer_infos = get_output_layer_infos(network_name); + CHECK_EXPECTED(output_layer_infos); + + return convert_layer_infos_to_stream_infos(output_layer_infos.value()); +} + +Expected> NetworkGroupMetadata::get_all_stream_infos(const std::string &network_name) const +{ + auto input_stream_infos = get_input_stream_infos(network_name); + CHECK_EXPECTED(input_stream_infos); + + auto output_stream_infos = get_output_stream_infos(network_name); + CHECK_EXPECTED(output_stream_infos); + + std::vector res; + res.reserve(input_stream_infos->size() + output_stream_infos->size()); + res.insert(res.end(), input_stream_infos->begin(), input_stream_infos->end()); + res.insert(res.end(), output_stream_infos->begin(), output_stream_infos->end()); + + return res; +} + +Expected> NetworkGroupMetadata::get_input_vstream_infos(const std::string &network_name) const +{ + auto input_layer_infos = get_input_layer_infos(network_name); + CHECK_EXPECTED(input_layer_infos); + + return convert_layer_infos_to_vstream_infos(input_layer_infos.value()); +} + +Expected> NetworkGroupMetadata::get_output_vstream_infos(const std::string &network_name) const +{ + std::vector res; + if (m_supported_features.hailo_net_flow) { + res = m_output_vstreams_infos; + return res; + } + auto expected_output_layer_infos = get_output_layer_infos(network_name); + CHECK_EXPECTED(expected_output_layer_infos); + auto output_layer_infos = expected_output_layer_infos.release(); + + res = convert_layer_infos_to_vstream_infos(output_layer_infos); + + hailo_status status = HAILO_SUCCESS; + std::sort(res.begin(), res.end(), + [this, &status](const auto &info1, const auto &info2) + { + const auto index1 = std::find(m_sorted_output_names.begin(), m_sorted_output_names.end(), std::string(info1.name)); + const auto index2 = std::find(m_sorted_output_names.begin(), m_sorted_output_names.end(), std::string(info2.name)); + + if (m_sorted_output_names.end() == index1) { + LOGGER__ERROR("Stream {} not found in sorted output names", info1.name); + status = HAILO_INTERNAL_FAILURE; + return false; + } + + if (m_sorted_output_names.end() == index2) { + LOGGER__ERROR("Stream {} not found in sorted output names", info2.name); + status = HAILO_INTERNAL_FAILURE; + return false; + } + + return index1 < index2; + }); + CHECK_SUCCESS_AS_EXPECTED(status); + + return res; +} + +Expected> NetworkGroupMetadata::get_all_vstream_infos(const std::string &network_name) const +{ + auto input_vstream_infos = get_input_vstream_infos(network_name); + CHECK_EXPECTED(input_vstream_infos); + + auto output_vstream_infos = get_output_vstream_infos(network_name); + CHECK_EXPECTED(output_vstream_infos); + + std::vector res; + res.reserve(input_vstream_infos->size() + output_vstream_infos->size()); + res.insert(res.end(), input_vstream_infos->begin(), input_vstream_infos->end()); + res.insert(res.end(), output_vstream_infos->begin(), output_vstream_infos->end()); + + return res; +} + +Expected> NetworkGroupMetadata::get_vstream_names_from_stream_name(const std::string &stream_name) const +{ + std::vector results; + for (auto &layer_info : get_all_layer_infos()) { + if (stream_name == layer_info.name) { + if (layer_info.is_defused_nms) { + return std::vector (1, layer_info.fused_nms_layer[0].name); + } else if (layer_info.is_mux) { + return get_demuxes_names(layer_info); + } else { + return std::vector (1, layer_info.name); + } + } + } + return make_unexpected(HAILO_NOT_FOUND); +} + +Expected> NetworkGroupMetadata::get_stream_names_from_vstream_name(const std::string &vstream_name) const +{ + std::vector results; + for (auto &layer_info : get_all_layer_infos()) { + if (layer_info.is_mux) { + if (is_edge_under_mux(layer_info, vstream_name)) { + // vstream_name is a demux of the layer info + results.push_back(layer_info.name); + } + } else if (layer_info.is_defused_nms) { + if (vstream_name == layer_info.fused_nms_layer[0].name) { + // vstream_name is the fused-layer of the layer info + results.push_back(layer_info.name); + } + } else if (m_supported_features.hailo_net_flow && layer_info.direction == HAILO_D2H_STREAM) { + results.push_back(layer_info.name); + } else if (vstream_name == layer_info.name) { + // vstream_name is a regular stream + results.push_back(layer_info.name); + } + } + CHECK_AS_EXPECTED(0 < results.size(), HAILO_NOT_FOUND, "Did not found vstream {}", vstream_name); + return results; +} + +std::vector NetworkGroupMetadata::convert_layer_infos_to_stream_infos(const std::vector &layer_infos) const +{ + std::vector res; + for (auto &layer_info : layer_infos) { + res.push_back(LayerInfoUtils::get_stream_info_from_layer_info(layer_info)); + } + return res; +} + +std::vector NetworkGroupMetadata::convert_layer_infos_to_vstream_infos(const std::vector &layer_infos) const +{ + std::vector res; + for (auto &layer_info : layer_infos) { + auto vstream_infos = LayerInfoUtils::get_vstream_infos_from_layer_info(layer_info); + for (const auto &vstream_info : vstream_infos) { + // In case of fused nms layers, several LayerInfos will contain data about the same fused layer + if (!LayerInfoUtils::vstream_info_already_in_vector(res, vstream_info.name)) { + res.push_back(vstream_info); + } + } + } + return res; +} + +Expected> NetworkGroupMetadata::get_network_infos() const +{ + std::vector network_infos; + auto net_group_name = network_group_name(); + network_infos.reserve(m_sorted_network_names.size()); + for (auto const &network_name : m_sorted_network_names) { + hailo_network_info_t network_info = {}; + CHECK_AS_EXPECTED(HAILO_MAX_NETWORK_NAME_SIZE >= (network_name.length() + 1), HAILO_INTERNAL_FAILURE, + "The network '{}' has a too long name (max is HAILO_MAX_NETWORK_NAME_SIZE)", network_name); + memcpy(network_info.name, network_name.c_str(), network_name.length() + 1); + + network_infos.push_back(network_info); + } + + return network_infos; +} + + +Expected NetworkGroupMetadataPerArch::get_metadata(uint32_t partial_clusters_layout_bitmap) +{ + if (PARTIAL_CLUSTERS_LAYOUT_IGNORE == partial_clusters_layout_bitmap) { + // Passing PARTIAL_CLUSTERS_LAYOUT_IGNORE is magic for getting one of the metadata + assert(0 != m_metadata_per_arch.size()); + auto result = m_metadata_per_arch.begin()->second; + return result; + } + if (contains(m_metadata_per_arch, partial_clusters_layout_bitmap)) { + auto result = m_metadata_per_arch[partial_clusters_layout_bitmap]; + return result; + } + LOGGER__ERROR("NetworkGroupMetadataPerArch does not contain metadata for partial_clusters_layout_bitmap {}", partial_clusters_layout_bitmap); + return make_unexpected(HAILO_INTERNAL_FAILURE); +} + +void NetworkGroupMetadataPerArch::add_metadata(const NetworkGroupMetadata &metadata, uint32_t partial_clusters_layout_bitmap) +{ + m_metadata_per_arch[partial_clusters_layout_bitmap] = metadata; +} + +} /* namespace hailort */ diff --git a/hailort/libhailort/src/network_group_metadata.hpp b/hailort/libhailort/src/network_group_metadata.hpp new file mode 100644 index 0000000..813dbd7 --- /dev/null +++ b/hailort/libhailort/src/network_group_metadata.hpp @@ -0,0 +1,178 @@ +/** + * Copyright (c) 2022 Hailo Technologies Ltd. All rights reserved. + * Distributed under the MIT license (https://opensource.org/licenses/MIT) +**/ +/** + * @file network_group_metadata.hpp + * @brief Contains all relevant information about a network group from the hef. + **/ + +#ifndef _HAILO_NETWORK_GROUP_METADATA_HPP_ +#define _HAILO_NETWORK_GROUP_METADATA_HPP_ + +#include "layer_info.hpp" +#include "context_switch/context_switch_actions.hpp" + +namespace hailort +{ + +constexpr const uint32_t PARTIAL_CLUSTERS_LAYOUT_IGNORE = static_cast(-1); + +struct SupportedFeatures { + bool padded_ddr_buffers = false; + bool multi_network_support = false; + bool multi_context = false; + bool preliminary_run_asap = false; + bool hailo_net_flow = false; +}; + +// For each config_stream_index we store vector of all ccw write length. The vector is used to build the config buffer.g +using ConfigBufferInfoMap = std::unordered_map>; + +class PreliminaryContextMetadata final { +public: + PreliminaryContextMetadata() = default; // TODO HRT-8478: remove + PreliminaryContextMetadata(std::vector &&operations, + ConfigBufferInfoMap&& config_buffers_info); + const std::vector &get_operations() const; + const ConfigBufferInfoMap &config_buffers_info() const; + +private: + std::vector m_operations; + ConfigBufferInfoMap m_config_buffers_info; +}; + +class ContextMetadata final { +public: + explicit ContextMetadata(std::vector &&operations, + ConfigBufferInfoMap&& config_buffers_info); + + const std::vector &get_operations() const; + const ConfigBufferInfoMap &config_buffers_info() const; + + void add_boundary_layer(const LayerInfo &layer_info); + void add_inter_context_layer(const LayerInfo &layer_info); + void add_ddr_layer(const LayerInfo &layer_info); + + const std::vector &get_boundary_input_layers() const; + const std::vector &get_boundary_output_layers() const; + const std::vector &get_inter_context_input_layers() const; + const std::vector &get_inter_context_output_layers() const; + const std::vector &get_ddr_input_layers() const; + const std::vector &get_ddr_output_layers() const; + +private: + std::vector m_operations; + ConfigBufferInfoMap m_config_buffers_info; + + std::vector m_boundary_input_layers; + std::vector m_boundary_output_layers; + std::vector m_inter_context_input_layers; + std::vector m_inter_context_output_layers; + std::vector m_ddr_input_layers; + std::vector m_ddr_output_layers; +}; + +struct ConfigChannelInfo { + uint8_t engine_index; +}; + +class NetworkGroupMetadata final { +public: + NetworkGroupMetadata() = default; // TODO HRT-8478: remove + NetworkGroupMetadata(const std::string &network_group_name, + PreliminaryContextMetadata &&preliminary_context, + std::vector &&dynamic_contexts, + std::vector &&config_channels_info, + std::vector &&sorted_output_names, + SupportedFeatures &supported_features, + const std::vector &sorted_network_names); + + std::vector get_input_layer_infos() const; + std::vector get_output_layer_infos() const; + std::vector get_all_layer_infos() const; + + Expected> get_input_layer_infos(const std::string &network_name) const; + Expected> get_output_layer_infos(const std::string &network_name) const; + Expected> get_all_layer_infos(const std::string &network_name) const; + Expected get_layer_info_by_stream_name(const std::string &stream_name) const; + + const PreliminaryContextMetadata &preliminary_context() const; + const std::vector &dynamic_contexts() const; + + const std::vector &config_channels_info() const; + + Expected> get_input_stream_infos(const std::string &network_name = "") const; + Expected> get_output_stream_infos(const std::string &network_name = "") const; + Expected> get_all_stream_infos(const std::string &network_name = "") const; + + Expected> get_input_vstream_infos(const std::string &network_name = "") const; + Expected> get_output_vstream_infos(const std::string &network_name = "") const; + Expected> get_all_vstream_infos(const std::string &network_name = "") const; + + Expected> get_vstream_names_from_stream_name(const std::string &stream_name) const; + Expected> get_stream_names_from_vstream_name(const std::string &vstream_name) const; + + Expected> get_network_infos() const; + + const std::string &network_group_name() const + { + return m_network_group_name; + } + + const std::string default_network_name() const + { + return HailoRTDefaults::get_network_name(m_network_group_name); + } + + const std::vector get_sorted_output_names() const + { + return m_sorted_output_names; + } + + const SupportedFeatures &supported_features() const + { + return m_supported_features; + } + + const std::vector &get_network_names() const + { + return m_sorted_network_names; + } + + void add_output_vstream_info(const hailo_vstream_info_t &output_vstream_info) { + m_output_vstreams_infos.push_back(output_vstream_info); + } + +private: + std::vector convert_layer_infos_to_stream_infos(const std::vector &layer_infos) const; + std::vector convert_layer_infos_to_vstream_infos(const std::vector &layer_infos) const; + + PreliminaryContextMetadata m_preliminary_context; + std::vector m_dynamic_contexts; + std::vector m_config_channels_info; + std::string m_network_group_name; + std::vector m_sorted_output_names; + SupportedFeatures m_supported_features; + std::vector m_sorted_network_names; + // TODO: remove this from here! NetworkGroupMetadata should be CoreOpMetadata and contain no net_flow information! (HRT-8639) + // To add insult to injury, this is being constructed lazyly by add_output_layer_info + std::vector m_output_vstreams_infos; // Valid only in case of post process +}; + + +class NetworkGroupMetadataPerArch final +{ +public: + NetworkGroupMetadataPerArch() = default; + + Expected get_metadata(uint32_t partial_clusters_layout_bitmap); + void add_metadata(const NetworkGroupMetadata &metadata, uint32_t partial_clusters_layout_bitmap); + +private: + std::map m_metadata_per_arch; +}; + +} /* namespace hailort */ + +#endif /* _HAILO_NETWORK_GROUP_METADATA_HPP_ */ diff --git a/hailort/libhailort/src/network_group_scheduler.cpp b/hailort/libhailort/src/network_group_scheduler.cpp index d92bd81..b4a0527 100644 --- a/hailort/libhailort/src/network_group_scheduler.cpp +++ b/hailort/libhailort/src/network_group_scheduler.cpp @@ -9,27 +9,35 @@ #include "network_group_scheduler.hpp" #include "context_switch/network_group_internal.hpp" +#include "context_switch/vdevice_network_group.hpp" #include "hef_internal.hpp" -#include "vdevice_stream_wrapper.hpp" +#include "vdevice_stream_multiplexer_wrapper.hpp" +#include "tracer_macros.hpp" +#include "scheduler_oracle.hpp" #include namespace hailort { -NetworkGroupScheduler::NetworkGroupScheduler(hailo_scheduling_algorithm_t algorithm) : - m_is_switching_network_group(true), - m_current_network_group(INVALID_NETWORK_GROUP_HANDLE), - m_next_network_group(INVALID_NETWORK_GROUP_HANDLE), +#define SINGLE_CONTEXT_BATCH_SIZE (1) + +// TODO: use device handles instead device count +NetworkGroupScheduler::NetworkGroupScheduler(hailo_scheduling_algorithm_t algorithm, uint32_t device_count) : + m_changing_current_batch_size(), + m_should_ng_stop(), m_algorithm(algorithm), m_before_read_write_mutex(), - m_current_batch_size(0), m_write_read_cv(), m_should_monitor(false) #if defined(__GNUC__) , m_mon_tmp_output() #endif { + for (uint32_t i = 0; i < device_count; i++) { + m_devices.push_back(make_shared_nothrow(i)); + } + // TODO: HRT-7391 - Change scheduler monitor to work only when MON command is active m_should_monitor = SchedulerMon::should_monitor(); if (m_should_monitor) { @@ -42,6 +50,22 @@ NetworkGroupScheduler::NetworkGroupScheduler(hailo_scheduling_algorithm_t algori NetworkGroupScheduler::~NetworkGroupScheduler() { + for (auto device_info : m_devices) { + if (INVALID_NETWORK_GROUP_HANDLE != device_info->current_network_group_handle) { + auto current_ng = m_cngs[device_info->current_network_group_handle]->get_network_group(); + auto current_network_group_bundle = std::dynamic_pointer_cast(current_ng); + assert(nullptr != current_network_group_bundle); + auto vdma_network_group = current_network_group_bundle->get_network_group_by_device_index(device_info->device_id); + if (!vdma_network_group) { + LOGGER__ERROR("Error retrieving network group in scheduler destructor"); + } else { + if (HAILO_SUCCESS != VdmaConfigManager::switch_network_group(vdma_network_group.value(), nullptr, 0)) { + LOGGER__ERROR("Error deactivating network group when destroying scheduler"); + } + } + } + } + if (m_should_monitor) { m_should_monitor = false; m_mon_shutdown_event->signal(); @@ -51,12 +75,12 @@ NetworkGroupScheduler::~NetworkGroupScheduler() } } -Expected NetworkGroupScheduler::create_round_robin() +Expected NetworkGroupScheduler::create_round_robin(uint32_t device_count) { - auto ptr = make_shared_nothrow(); + auto ptr = make_shared_nothrow(HAILO_SCHEDULING_ALGORITHM_ROUND_ROBIN, device_count); CHECK_AS_EXPECTED(nullptr != ptr, HAILO_OUT_OF_HOST_MEMORY); - return std::static_pointer_cast(ptr); + return ptr; } std::string get_curr_pid_as_str() @@ -140,14 +164,9 @@ void NetworkGroupScheduler::dump_state() } #endif -std::string NetworkGroupScheduler::get_network_group_name(const scheduler_ng_handle_t network_group_handle) +std::string NetworkGroupScheduler::get_network_group_name(const scheduler_ng_handle_t &network_group_handle) { - auto cng = m_cngs[network_group_handle].lock(); - if (nullptr == cng) { - LOGGER__CRITICAL("Configured network group is null!"); - return ""; - } - return cng->name(); + return m_cngs[network_group_handle]->get_network_group_name(); } // TODO: HRT-7392 - Reduce core percentage when scheduler is idle @@ -158,26 +177,28 @@ void NetworkGroupScheduler::log_monitor_networks_infos(ProtoMon &mon) for (uint32_t network_group_handle = 0; network_group_handle < m_last_measured_activation_timestamp.size(); network_group_handle++) { assert(contains(m_active_duration, network_group_handle)); - auto curr_ng_core = m_active_duration[network_group_handle]; - - if (network_group_handle == m_current_network_group) { - // Network is currently active - auto time_diff = std::chrono::duration_cast>( - curr_time - m_last_measured_activation_timestamp[m_current_network_group]).count(); - curr_ng_core += time_diff; - m_last_measured_activation_timestamp[m_current_network_group] = curr_time; + auto curr_ng_active_time = m_active_duration[network_group_handle]; + + for (auto device_info : m_devices) { + if (network_group_handle == device_info->current_network_group_handle) { + // Network is currently active + auto time_diff = std::chrono::duration_cast>( + curr_time - m_last_measured_activation_timestamp[device_info->current_network_group_handle]).count(); + curr_ng_active_time += time_diff; + m_last_measured_activation_timestamp[device_info->current_network_group_handle] = curr_time; + } } - auto core_utilization = ((curr_ng_core * 100) / measurement_duration); - auto outputs_count = static_cast(m_allowed_read[network_group_handle].size()); + auto active_time = ((curr_ng_active_time * 100) / measurement_duration); + auto outputs_count = static_cast(m_cngs[network_group_handle]->get_outputs_names().size()); auto fps = static_cast((m_fps_accumulator[network_group_handle] / outputs_count) / measurement_duration); auto net_info = mon.add_networks_infos(); net_info->set_network_name(get_network_group_name(network_group_handle)); - net_info->set_core_utilization(core_utilization); + net_info->set_active_time(active_time); net_info->set_fps(fps); } - + m_last_measured_timestamp = curr_time; } @@ -187,10 +208,7 @@ void NetworkGroupScheduler::log_monitor_frames_infos(ProtoMon &mon) auto net_frames_info = mon.add_net_frames_infos(); net_frames_info->set_network_name(get_network_group_name(network_group_handle)); - assert(contains(m_requested_write, network_group_handle)); - for (auto &streams_requested_write_pair : m_requested_write[network_group_handle]) { - auto &stream_name = streams_requested_write_pair.first; - + for (auto &stream_name : m_cngs[network_group_handle]->get_inputs_names()) { auto stream_frames_info = net_frames_info->add_streams_frames_infos(); stream_frames_info->set_stream_name(stream_name); stream_frames_info->set_stream_direction(PROTO__STREAM_DIRECTION__HOST_TO_DEVICE); @@ -201,10 +219,7 @@ void NetworkGroupScheduler::log_monitor_frames_infos(ProtoMon &mon) } } - assert(contains(m_allowed_read, network_group_handle)); - for (auto &streams_requested_read_pair : m_allowed_read[network_group_handle]) { - auto &stream_name = streams_requested_read_pair.first; - + for (auto &stream_name : m_cngs[network_group_handle]->get_outputs_names()) { auto stream_frames_info = net_frames_info->add_streams_frames_infos(); stream_frames_info->set_stream_name(stream_name); stream_frames_info->set_stream_direction(PROTO__STREAM_DIRECTION__DEVICE_TO_HOST); @@ -217,12 +232,11 @@ void NetworkGroupScheduler::log_monitor_frames_infos(ProtoMon &mon) } } -hailo_status NetworkGroupScheduler::set_h2d_frames_counters(scheduler_ng_handle_t network_group_handle, const std::string &stream_name, +hailo_status NetworkGroupScheduler::set_h2d_frames_counters(const scheduler_ng_handle_t &network_group_handle, const std::string &stream_name, ProtoMonStreamFramesInfo &stream_frames_info) { assert(m_cngs.size() > network_group_handle); - auto current_cng = m_cngs[network_group_handle].lock(); - CHECK(current_cng, HAILO_INTERNAL_FAILURE); + auto current_cng = m_cngs[network_group_handle]->get_network_group(); auto input_stream = current_cng->get_input_stream_by_name(stream_name); CHECK_EXPECTED_AS_STATUS(input_stream); @@ -245,12 +259,11 @@ hailo_status NetworkGroupScheduler::set_h2d_frames_counters(scheduler_ng_handle_ return HAILO_SUCCESS; } -hailo_status NetworkGroupScheduler::set_d2h_frames_counters(scheduler_ng_handle_t network_group_handle, const std::string &stream_name, +hailo_status NetworkGroupScheduler::set_d2h_frames_counters(const scheduler_ng_handle_t &network_group_handle, const std::string &stream_name, ProtoMonStreamFramesInfo &stream_frames_info) { assert(m_cngs.size() > network_group_handle); - auto current_cng = m_cngs[network_group_handle].lock(); - CHECK(current_cng, HAILO_INTERNAL_FAILURE); + auto current_cng = m_cngs[network_group_handle]->get_network_group(); auto output_stream = current_cng->get_output_stream_by_name(stream_name); CHECK_EXPECTED_AS_STATUS(output_stream); @@ -273,177 +286,136 @@ hailo_status NetworkGroupScheduler::set_d2h_frames_counters(scheduler_ng_handle_ return HAILO_SUCCESS; } -Expected NetworkGroupScheduler::add_network_group(std::weak_ptr added_cng) +Expected NetworkGroupScheduler::add_network_group(std::shared_ptr added_cng) { scheduler_ng_handle_t network_group_handle = INVALID_NETWORK_GROUP_HANDLE; { std::unique_lock lock(m_before_read_write_mutex); - network_group_handle = static_cast(m_cngs.size()); - - m_cngs.emplace_back(added_cng); - m_last_measured_activation_timestamp[network_group_handle] = {}; - m_active_duration[network_group_handle] = 0; - m_fps_accumulator[network_group_handle] = 0; - m_last_run_time_stamp[network_group_handle] = std::chrono::steady_clock::now(); - m_frame_was_sent_per_network_group[network_group_handle] = false; - m_timeout_per_network_group[network_group_handle] = make_shared_nothrow(DEFAULT_SCHEDULER_TIMEOUT); - CHECK_AS_EXPECTED(nullptr != m_timeout_per_network_group[network_group_handle], HAILO_OUT_OF_HOST_MEMORY); - auto added_cng_ptr = added_cng.lock(); - CHECK_AS_EXPECTED(added_cng_ptr, HAILO_INTERNAL_FAILURE); + network_group_handle = static_cast(m_cngs.size()); + TRACE(AddNetworkGroupTrace, "", added_cng->name(), DEFAULT_SCHEDULER_TIMEOUT.count(), DEFAULT_SCHEDULER_MIN_THRESHOLD, network_group_handle); - auto stream_infos = added_cng_ptr->get_all_stream_infos(); + auto stream_infos = added_cng->get_all_stream_infos(); CHECK_EXPECTED(stream_infos); - m_max_batch_size[network_group_handle] = CONTROL_PROTOCOL__IGNORE_DYNAMIC_BATCH_SIZE; - auto cng_base = std::dynamic_pointer_cast(added_cng_ptr); - if (cng_base->get_supported_features().multi_context) { - auto batch_size = cng_base->get_stream_batch_size(stream_infos.value()[0].name); - CHECK_EXPECTED(batch_size); + auto scheduled_ng = ScheduledNetworkGroup::create(added_cng, stream_infos.value()); + CHECK_EXPECTED(scheduled_ng); - if (batch_size.value() > HAILO_DEFAULT_BATCH_SIZE) { - m_max_batch_size[network_group_handle] = batch_size.release(); - } - } + m_cngs.emplace_back(scheduled_ng.release()); + + m_changing_current_batch_size[network_group_handle] = false; - // Prepare empty counters for the added cng for (const auto &stream_info : stream_infos.value()) { m_should_ng_stop[network_group_handle][stream_info.name] = false; - m_min_threshold_per_stream[network_group_handle][stream_info.name] = DEFAULT_SCHEDULER_MIN_THRESHOLD; - if (HAILO_H2D_STREAM == stream_info.direction) { - m_requested_write[network_group_handle][stream_info.name] = 0; - m_written_buffer[network_group_handle][stream_info.name] = 0; - m_sent_pending_buffer[network_group_handle][stream_info.name] = 0; - m_current_sent_pending_buffer[network_group_handle][stream_info.name] = 0; - m_finished_sent_pending_buffer[network_group_handle][stream_info.name] = 0; - - auto event = Event::create_shared(Event::State::signalled); - CHECK_AS_EXPECTED(nullptr != event, HAILO_OUT_OF_HOST_MEMORY); - - m_write_buffer_events[network_group_handle][stream_info.name] = event; - } else { - m_requested_read[network_group_handle][stream_info.name] = 0; - m_allowed_read[network_group_handle][stream_info.name] = 0; - m_finished_read[network_group_handle][stream_info.name] = 0; - m_current_finished_read[network_group_handle][stream_info.name] = 0; - m_pending_read[network_group_handle][stream_info.name] = 0; + } + + for (auto& device_info : m_devices) { + for (const auto &stream_info : stream_infos.value()) { + if (HAILO_H2D_STREAM == stream_info.direction) { + device_info->current_cycle_requested_transferred_frames_h2d[network_group_handle][stream_info.name] = 0; + } else { + device_info->current_cycle_finished_transferred_frames_d2h[network_group_handle][stream_info.name] = 0; + device_info->current_cycle_finished_read_frames_d2h[network_group_handle][stream_info.name] = 0; + } } } + + // Monitor members + m_last_measured_activation_timestamp[network_group_handle] = {}; + m_active_duration[network_group_handle] = 0; + m_fps_accumulator[network_group_handle] = 0; } m_write_read_cv.notify_all(); return network_group_handle; } -hailo_status NetworkGroupScheduler::wait_for_write(const scheduler_ng_handle_t &network_group_handle, const std::string &stream_name) +bool NetworkGroupScheduler::is_network_group_active(const scheduler_ng_handle_t &network_group_handle) { - while (true) { - auto status = block_write_if_needed(network_group_handle, stream_name); - if (HAILO_STREAM_INTERNAL_ABORT == status) { - return HAILO_STREAM_INTERNAL_ABORT; + for (auto device_info : m_devices) { + if (network_group_handle == device_info->current_network_group_handle) { + return true; } - CHECK_SUCCESS(status); - m_write_read_cv.notify_all(); - - status = m_write_buffer_events[network_group_handle][stream_name]->wait(std::chrono::milliseconds(HAILO_INFINITE)); - CHECK_SUCCESS(status); - - { - std::unique_lock lock(m_before_read_write_mutex); + } - auto should_wait_again = should_wait_for_write(network_group_handle, stream_name); - if (HAILO_STREAM_INTERNAL_ABORT == should_wait_again.status()) { - return HAILO_STREAM_INTERNAL_ABORT; - } - CHECK_EXPECTED_AS_STATUS(should_wait_again); + return false; +} - if (!should_wait_again.value()) { - if (!m_frame_was_sent_per_network_group[network_group_handle]) { - m_frame_was_sent_per_network_group[network_group_handle] = true; - } - m_requested_write[network_group_handle][stream_name]++; - status = allow_writes_for_other_inputs_if_needed(network_group_handle); - CHECK_SUCCESS(status); - break; - } +bool NetworkGroupScheduler::is_switching_current_network_group(const scheduler_ng_handle_t &network_group_handle) +{ + for (auto device_info : m_devices) { + if (network_group_handle == device_info->current_network_group_handle && device_info->is_switching_network_group) { + return true; } } - m_write_read_cv.notify_all(); - return HAILO_SUCCESS; + return false; } -hailo_status NetworkGroupScheduler::block_write_if_needed(const scheduler_ng_handle_t &network_group_handle, const std::string &stream_name) +bool NetworkGroupScheduler::is_multi_device() { - std::unique_lock lock(m_before_read_write_mutex); - assert(contains(m_write_buffer_events, network_group_handle)); - auto should_wait = should_wait_for_write(network_group_handle, stream_name); - if (HAILO_STREAM_INTERNAL_ABORT == should_wait.status()) { - return HAILO_STREAM_INTERNAL_ABORT; - } - CHECK_EXPECTED_AS_STATUS(should_wait); - if (should_wait.value()) { - auto status = m_write_buffer_events[network_group_handle][stream_name]->reset(); - CHECK_SUCCESS(status); - } - return HAILO_SUCCESS; + return m_devices.size() > 1; } -bool NetworkGroupScheduler::has_enough_space_in_read_buffers(const scheduler_ng_handle_t &network_group_handle, uint32_t ongoing_frames) +hailo_status NetworkGroupScheduler::wait_for_write(const scheduler_ng_handle_t &network_group_handle, const std::string &stream_name, + const std::chrono::milliseconds &timeout, const std::function &should_cancel) { - assert(network_group_handle < m_cngs.size()); - auto cng = m_cngs[network_group_handle].lock(); - assert(cng); - - auto output_streams = cng->get_output_streams(); - for (auto &output_stream : output_streams) { - OutputStreamBase &vdevice_output = static_cast(output_stream.get()); - if (auto pending_frames_size = vdevice_output.get_buffer_frames_size()) { - if (pending_frames_size.value() <= ongoing_frames) { - return false; + { + std::unique_lock lock(m_before_read_write_mutex); + + hailo_status status = HAILO_SUCCESS; + auto wait_res = m_write_read_cv.wait_for(lock, timeout, [this, network_group_handle, stream_name, &should_cancel, &status] { + + if (should_cancel()) { + status = HAILO_STREAM_ABORTED_BY_USER; + return true; // return true so that the wait will finish } - // If couldnt get pending frames size and count (e.g. NMS layer), assume we have space - scheduler switch will prevent deadlocks here - } - } - return true; -} -bool NetworkGroupScheduler::has_input_written_most_frames(const scheduler_ng_handle_t &network_group_handle, const std::string &stream_name) -{ - return m_requested_write[network_group_handle][stream_name] == get_max_value_of_unordered_map(m_requested_write[network_group_handle]); -} + if (should_ng_stop(network_group_handle)) { + status = HAILO_STREAM_ABORTED_BY_USER; + return true; // return true so that the wait will finish + } -bool NetworkGroupScheduler::should_ng_stop(const scheduler_ng_handle_t &network_group_handle) -{ - assert(contains(m_should_ng_stop, network_group_handle)); - for (const auto &name_flag_pair : m_should_ng_stop[network_group_handle]) { - if (name_flag_pair.second) { - return true; + auto should_wait = should_wait_for_write(network_group_handle, stream_name); + if (HAILO_SUCCESS != should_wait.status()) { + status = should_wait.status(); + return true; // return true so that the wait will finish + } + return !should_wait.value(); + }); + CHECK(wait_res, HAILO_TIMEOUT, "{} (H2D) failed with status={}, timeout={}ms", stream_name, HAILO_TIMEOUT, timeout.count()); + if (HAILO_STREAM_ABORTED_BY_USER == status) { + return status; } + CHECK_SUCCESS(status); + + m_cngs[network_group_handle]->mark_frame_sent(); + m_cngs[network_group_handle]->requested_write_frames().increase(stream_name); } + m_write_read_cv.notify_all(); - return false; + return HAILO_SUCCESS; } Expected NetworkGroupScheduler::should_wait_for_write(const scheduler_ng_handle_t &network_group_handle, const std::string &stream_name) { + auto scheduled_ng = m_cngs[network_group_handle]; + if (should_ng_stop(network_group_handle)) { - return make_unexpected(HAILO_STREAM_INTERNAL_ABORT); + return make_unexpected(HAILO_STREAM_ABORTED_BY_USER); } - assert(contains(m_requested_write, network_group_handle)); - assert(contains(m_sent_pending_buffer, network_group_handle)); - assert(contains(m_max_batch_size, network_group_handle)); - - auto pending_buffers = m_requested_write[network_group_handle][stream_name] - m_sent_pending_buffer[network_group_handle][stream_name]; - bool has_written_max_batch_size = (is_ng_multicontext(network_group_handle) && (m_max_batch_size[network_group_handle] == pending_buffers)); + auto pre_transfer_h2d_frames = scheduled_ng->requested_write_frames(stream_name) + scheduled_ng->finished_write_frames(stream_name); + bool has_written_max_batch_size = ((scheduled_ng->use_dynamic_batch_flow() || is_multi_device()) && + ((scheduled_ng->get_max_batch_size() * m_devices.size()) == pre_transfer_h2d_frames)); - bool should_stop_writing_because_switching = ((nullptr != m_ang) && m_is_switching_network_group && - (network_group_handle == m_current_network_group) && has_input_written_most_frames(network_group_handle, stream_name)); + bool should_stop_writing_because_switching = ((!(scheduled_ng->use_dynamic_batch_flow() || is_multi_device())) && + (is_switching_current_network_group(network_group_handle) || m_changing_current_batch_size[network_group_handle]) && + is_network_group_active(network_group_handle) && scheduled_ng->has_input_written_most_frames(stream_name)); - auto min_finished_read = get_min_value_of_unordered_map(m_finished_read[network_group_handle]); - auto ongoing_frames = (min_finished_read < m_requested_write[network_group_handle][stream_name]) ? - (m_requested_write[network_group_handle][stream_name] - min_finished_read) : 0; - bool has_enough_space_for_writes = has_enough_space_in_read_buffers(network_group_handle, ongoing_frames); + auto total_written_frames = scheduled_ng->total_written_frames_count()[stream_name]; + auto min_finished_read = scheduled_ng->finished_read_frames_min_value(); + auto ongoing_frames = (min_finished_read < total_written_frames) ? (total_written_frames - min_finished_read) : 0; + bool has_enough_space_for_writes = scheduled_ng->has_enough_space_in_read_buffers(ongoing_frames); if (has_written_max_batch_size || should_stop_writing_because_switching || (!has_enough_space_for_writes)) { return true; @@ -452,173 +424,132 @@ Expected NetworkGroupScheduler::should_wait_for_write(const scheduler_ng_h return false; } -hailo_status NetworkGroupScheduler::allow_writes_for_other_inputs_if_needed(const scheduler_ng_handle_t &network_group_handle) -{ - if (!has_ng_finished(network_group_handle) && m_is_switching_network_group) { - auto max_write = get_max_value_of_unordered_map(m_requested_write[network_group_handle]); - for (auto &name_event_pair : m_write_buffer_events[network_group_handle]) { - if (m_requested_write[network_group_handle][name_event_pair.first] < max_write) { - auto status = name_event_pair.second->signal(); - CHECK_SUCCESS(status); - } - } - } - return HAILO_SUCCESS; -} - hailo_status NetworkGroupScheduler::signal_write_finish(const scheduler_ng_handle_t &network_group_handle, const std::string &stream_name) { { std::unique_lock lock(m_before_read_write_mutex); + auto scheduled_ng = m_cngs[network_group_handle]; if (should_ng_stop(network_group_handle)) { - return HAILO_STREAM_INTERNAL_ABORT; + return HAILO_STREAM_ABORTED_BY_USER; } - assert(contains(m_written_buffer, network_group_handle)); - assert(contains(m_written_buffer[network_group_handle], stream_name)); - m_written_buffer[network_group_handle][stream_name]++; - - auto status = switch_network_group_if_idle(network_group_handle, lock); - CHECK_SUCCESS(status); - - status = switch_network_group_if_should_be_next(network_group_handle, lock); - CHECK_SUCCESS(status); + scheduled_ng->finished_write_frames().increase(stream_name); + scheduled_ng->requested_write_frames().decrease(stream_name); - status = send_all_pending_buffers(network_group_handle, lock); - if (HAILO_STREAM_INTERNAL_ABORT == status) { - LOGGER__INFO("send_all_pending_buffers has failed with status=HAILO_STREAM_INTERNAL_ABORT"); - return status; + auto device_id = NetworkGroupSchedulerOracle::get_avail_device(*this, network_group_handle); + if (INVALID_DEVICE_ID != device_id) { + auto status = switch_network_group(network_group_handle, device_id); + CHECK_SUCCESS(status); } - CHECK_SUCCESS(status); - } - m_write_read_cv.notify_all(); - return HAILO_SUCCESS; -} - -hailo_status NetworkGroupScheduler::switch_network_group_if_idle(const scheduler_ng_handle_t &network_group_handle, - std::unique_lock &read_write_lock) -{ - const bool check_threshold = false; - if (!m_is_switching_network_group && has_ng_drained_everything(m_current_network_group) && - ((nullptr == m_ang) || (network_group_handle != m_current_network_group)) && is_network_group_ready(network_group_handle, check_threshold)) { - auto status = activate_network_group(network_group_handle, read_write_lock); - if (HAILO_STREAM_INTERNAL_ABORT == status) { - return status; + for (auto &device_info : m_devices) { + if (device_info->current_network_group_handle == network_group_handle && !(scheduled_ng->use_dynamic_batch_flow() || is_multi_device())) { + auto status = send_all_pending_buffers(network_group_handle, device_info->device_id); + if (HAILO_STREAM_ABORTED_BY_USER == status) { + LOGGER__INFO("send_all_pending_buffers has failed with status=HAILO_STREAM_ABORTED_BY_USER"); + return status; + } + CHECK_SUCCESS(status); + } } - CHECK_SUCCESS(status); - - return HAILO_SUCCESS; } - - auto status = try_change_multicontext_ng_batch_size(network_group_handle, read_write_lock); - CHECK_SUCCESS(status); + m_write_read_cv.notify_all(); return HAILO_SUCCESS; } -bool NetworkGroupScheduler::has_pending_frames(const scheduler_ng_handle_t &network_group_handle) +hailo_status NetworkGroupScheduler::switch_network_group(const scheduler_ng_handle_t &network_group_handle, uint32_t device_id, bool /*keep_nn_config*/) { - uint32_t transferred_frames = get_max_value_of_unordered_map(m_sent_pending_buffer[network_group_handle]); - for (auto &name_counter_pair : m_finished_read[network_group_handle]) { - if (name_counter_pair.second < transferred_frames) { - return true; - } - } - return false; -} + auto scheduled_ng = m_cngs[network_group_handle]; + auto curr_device_info = m_devices[device_id]; -hailo_status NetworkGroupScheduler::try_change_multicontext_ng_batch_size(const scheduler_ng_handle_t &network_group_handle, - std::unique_lock &read_write_lock) -{ - if ((nullptr != m_ang) && (network_group_handle == m_current_network_group) && is_ng_multicontext(network_group_handle) && has_ng_finished(network_group_handle)) { - if (get_buffered_frames_count() > 0) { - hailo_status status = activate_network_group(network_group_handle, read_write_lock, true); - CHECK_SUCCESS(status); - } + // initialize current cycle maps + for (const auto &name : scheduled_ng->get_inputs_names()) { + curr_device_info->current_cycle_requested_transferred_frames_h2d[network_group_handle][name] = 0; } - return HAILO_SUCCESS; -} - -hailo_status NetworkGroupScheduler::activate_network_group(const scheduler_ng_handle_t &network_group_handle, - std::unique_lock &read_write_lock, bool keep_nn_config) -{ - for (auto &name_counter_pair : m_current_sent_pending_buffer[network_group_handle]) { - name_counter_pair.second = 0; - } - - for (auto &name_counter_pair : m_current_finished_read[network_group_handle]) { - name_counter_pair.second = 0; + for (const auto &name : scheduled_ng->get_outputs_names()) { + curr_device_info->current_cycle_finished_transferred_frames_d2h[network_group_handle][name] = 0; + curr_device_info->current_cycle_finished_read_frames_d2h[network_group_handle][name] = 0; } uint16_t batch_size = CONTROL_PROTOCOL__IGNORE_DYNAMIC_BATCH_SIZE; - if (is_ng_multicontext(network_group_handle)) { - batch_size = static_cast(get_buffered_frames_count()); - } - - if (CONTROL_PROTOCOL__IGNORE_DYNAMIC_BATCH_SIZE == batch_size) { - batch_size = 1; + uint16_t burst_size = CONTROL_PROTOCOL__IGNORE_DYNAMIC_BATCH_SIZE; + if (scheduled_ng->use_dynamic_batch_flow()) { + burst_size = std::min(static_cast(scheduled_ng->finished_write_frames_min_value()), scheduled_ng->get_max_batch_size()); + batch_size = burst_size; + } else { + burst_size = is_multi_device() ? static_cast(scheduled_ng->finished_write_frames_min_value()) : SINGLE_CONTEXT_BATCH_SIZE; + batch_size = SINGLE_CONTEXT_BATCH_SIZE; } - bool has_same_batch_size_as_previous = (m_current_batch_size == batch_size); - m_current_batch_size = batch_size; - - if (m_current_network_group != INVALID_NETWORK_GROUP_HANDLE) { - if ((network_group_handle != m_current_network_group) || (!has_same_batch_size_as_previous)) { - if (nullptr != m_ang) { - auto status = m_ang->set_keep_nn_config_during_reset(keep_nn_config); - CHECK_SUCCESS(status); - } - - deactivate_network_group(); - } else { - reset_current_ng_timestamps(); - } - } + bool has_same_batch_size_as_previous = (curr_device_info->current_batch_size == batch_size); + curr_device_info->current_batch_size = batch_size; + curr_device_info->current_burst_size = burst_size; m_last_measured_activation_timestamp[network_group_handle] = std::chrono::steady_clock::now(); - if (m_current_network_group != network_group_handle) { - m_is_switching_network_group = false; + if (curr_device_info->current_network_group_handle != network_group_handle) { + curr_device_info->is_switching_network_group = false; } - auto status = allow_all_writes(); - CHECK_SUCCESS(status); - - if ((network_group_handle != m_current_network_group) || (!has_same_batch_size_as_previous)) { + if ((network_group_handle != curr_device_info->current_network_group_handle) || (!has_same_batch_size_as_previous)) { assert(m_cngs.size() > network_group_handle); - auto cng = m_cngs[network_group_handle].lock(); - CHECK(cng, HAILO_INTERNAL_FAILURE); - - auto cng_base = std::dynamic_pointer_cast(cng); - auto expected_ang = cng_base->force_activate(batch_size); - CHECK_EXPECTED_AS_STATUS(expected_ang); - - m_ang = expected_ang.release(); + auto next_active_cng = scheduled_ng->get_network_group(); + auto next_active_cng_wrapper = std::dynamic_pointer_cast(next_active_cng); + assert(nullptr != next_active_cng_wrapper); + auto next_active_cng_expected = next_active_cng_wrapper->get_network_group_by_device_index(curr_device_info->device_id); + CHECK_EXPECTED_AS_STATUS(next_active_cng_expected); + + std::shared_ptr current_active_vdma_cng = nullptr; + if (curr_device_info->current_network_group_handle != INVALID_NETWORK_GROUP_HANDLE) { + reset_current_ng_timestamps(curr_device_info->device_id); + auto current_active_cng = m_cngs[curr_device_info->current_network_group_handle]->get_network_group(); + auto current_active_cng_bundle = std::dynamic_pointer_cast(current_active_cng); + assert(nullptr != current_active_cng_bundle); + auto current_active_cng_expected = current_active_cng_bundle->get_network_group_by_device_index(curr_device_info->device_id); + CHECK_EXPECTED_AS_STATUS(current_active_cng_expected); + current_active_vdma_cng = current_active_cng_expected.release(); + } + + TRACE(SwitchNetworkGroupTrace, "", network_group_handle); + auto status = VdmaConfigManager::switch_network_group(current_active_vdma_cng, next_active_cng_expected.value(), batch_size); + CHECK_SUCCESS(status, "Failed switching network group"); // Register to get interrupts - has to be after network group is activated - for (auto &output_stream : cng->get_output_streams()) { + for (auto &output_stream : next_active_cng_expected.value()->get_output_streams()) { OutputStreamBase &vdevice_output = static_cast(output_stream.get()); status = vdevice_output.register_for_d2h_interrupts( - [this, network_group_handle, name = output_stream.get().name(), format = vdevice_output.get_layer_info().format.order](uint32_t frames) { - if(hailo_format_order_t::HAILO_FORMAT_ORDER_HAILO_NMS != format) { - std::unique_lock lock(m_before_read_write_mutex); - m_pending_read[network_group_handle][name] += frames; - } - m_write_read_cv.notify_all(); + [this, name = output_stream.get().name(), format = vdevice_output.get_layer_info().format.order, scheduled_ng, network_group_handle, device_id] + (uint32_t frames) { + { + std::unique_lock lock(m_before_read_write_mutex); + if (hailo_format_order_t::HAILO_FORMAT_ORDER_HAILO_NMS != format) { + TRACE(OutputVdmaEnqueueTrace, "", network_group_handle, name, frames); + // TODO: Remove d2h_finished_transferred_frames and use current_cycle_finished_transferred_frames_d2h instead + scheduled_ng->d2h_finished_transferred_frames(name) += frames; + m_devices[device_id]->current_cycle_finished_transferred_frames_d2h[network_group_handle][name] += frames; + } + if (!(is_multi_device() || scheduled_ng->use_dynamic_batch_flow()) || has_ng_drained_everything(network_group_handle, device_id)) { + choose_next_network_group(device_id); + } + } + m_write_read_cv.notify_all(); }); CHECK_SUCCESS(status); } } - m_last_run_time_stamp[network_group_handle] = std::chrono::steady_clock::now(); // Mark timestamp on activation - m_current_network_group = network_group_handle; + scheduled_ng->set_last_run_timestamp(std::chrono::steady_clock::now()); // Mark timestamp on activation + curr_device_info->current_network_group_handle = network_group_handle; + + // Finished switching batch size + m_changing_current_batch_size[network_group_handle] = false; - status = send_all_pending_buffers(network_group_handle, read_write_lock); - if (HAILO_STREAM_INTERNAL_ABORT == status) { - LOGGER__INFO("send_all_pending_buffers has failed with status=HAILO_STREAM_INTERNAL_ABORT"); + auto status = send_all_pending_buffers(network_group_handle, device_id); + if (HAILO_STREAM_ABORTED_BY_USER == status) { + LOGGER__INFO("send_all_pending_buffers has failed with status=HAILO_STREAM_ABORTED_BY_USER"); return status; } CHECK_SUCCESS(status); @@ -626,251 +557,236 @@ hailo_status NetworkGroupScheduler::activate_network_group(const scheduler_ng_ha return HAILO_SUCCESS; } -hailo_status NetworkGroupScheduler::allow_all_writes() +hailo_status NetworkGroupScheduler::send_all_pending_buffers(const scheduler_ng_handle_t &network_group_handle, uint32_t device_id) { - for (auto &handle_dict_pair : m_write_buffer_events) { - for (auto &name_event_pair : handle_dict_pair.second) { - auto status = name_event_pair.second->signal(); - CHECK_SUCCESS(status); - } - } - return HAILO_SUCCESS; -} - -hailo_status NetworkGroupScheduler::send_all_pending_buffers(const scheduler_ng_handle_t &network_group_handle, - std::unique_lock &read_write_lock) -{ - if ((nullptr == m_ang) || (m_current_network_group != network_group_handle)) { + auto current_device_info = m_devices[device_id]; + if ((INVALID_NETWORK_GROUP_HANDLE == current_device_info->current_network_group_handle) || (current_device_info->current_network_group_handle != network_group_handle)) { return HAILO_SUCCESS; } - while (true) { - uint32_t finished_sending_count = 0; - for (auto &name_counter_pair : m_written_buffer[network_group_handle]) { - if ((m_sent_pending_buffer[network_group_handle][name_counter_pair.first] < name_counter_pair.second) - && ((!is_ng_multicontext(network_group_handle)) || (m_current_sent_pending_buffer[network_group_handle][name_counter_pair.first] < m_current_batch_size))) { - auto status = send_pending_buffer(network_group_handle, name_counter_pair.first, read_write_lock); - if (HAILO_STREAM_INTERNAL_ABORT == status) { - LOGGER__INFO("send_pending_buffer has failed with status=HAILO_STREAM_INTERNAL_ABORT"); - return status; - } - CHECK_SUCCESS(status); - } else { - finished_sending_count++; + auto scheduled_ng = m_cngs[network_group_handle]; + + while(true) { + auto finished_send = false; + for (const auto &name : scheduled_ng->get_inputs_names()) { + if ((scheduled_ng->finished_write_frames(name) == 0) || (((scheduled_ng->use_dynamic_batch_flow()) || (is_multi_device())) && + ((current_device_info->current_cycle_requested_transferred_frames_h2d[network_group_handle][name] == current_device_info->current_burst_size)))) { + finished_send = true; + break; } } - if (finished_sending_count == m_written_buffer[network_group_handle].size()) { + if (finished_send) { break; } + + for (const auto &name : scheduled_ng->get_inputs_names()) { + auto status = send_pending_buffer(network_group_handle, name, device_id); + if (HAILO_STREAM_ABORTED_BY_USER == status) { + LOGGER__INFO("send_pending_buffer has failed with status=HAILO_STREAM_ABORTED_BY_USER"); + return status; + } + CHECK_SUCCESS(status); + } + scheduled_ng->push_device_index(device_id); } return HAILO_SUCCESS; } hailo_status NetworkGroupScheduler::send_pending_buffer(const scheduler_ng_handle_t &network_group_handle, const std::string &stream_name, - std::unique_lock &read_write_lock) + uint32_t device_id) { assert(m_cngs.size() > network_group_handle); - auto current_cng = m_cngs[network_group_handle].lock(); - CHECK(current_cng, HAILO_INTERNAL_FAILURE); + auto scheduled_ng = m_cngs[network_group_handle]; + auto current_cng = scheduled_ng->get_network_group(); auto input_stream = current_cng->get_input_stream_by_name(stream_name); CHECK_EXPECTED_AS_STATUS(input_stream); - VDeviceInputStreamWrapper &vdevice_input = static_cast(input_stream->get()); - auto pending_buffer_state = vdevice_input.send_pending_buffer(); - CHECK_EXPECTED_AS_STATUS(pending_buffer_state); - - assert(contains(m_sent_pending_buffer, network_group_handle)); - m_sent_pending_buffer[network_group_handle][stream_name]++; - - assert(contains(m_current_sent_pending_buffer, network_group_handle)); - m_current_sent_pending_buffer[network_group_handle][stream_name]++; - - auto status = pending_buffer_state->finish(vdevice_input.get_timeout(), read_write_lock); - if (HAILO_STREAM_INTERNAL_ABORT == status) { - LOGGER__INFO("finish has failed with status=HAILO_STREAM_INTERNAL_ABORT"); + VDeviceInputStreamMultiplexerWrapper &vdevice_input = static_cast(input_stream->get()); + TRACE(InputVdmaEnqueueTrace, "", network_group_handle, stream_name); + auto status = vdevice_input.send_pending_buffer(device_id); + if (HAILO_STREAM_ABORTED_BY_USER == status) { + LOGGER__INFO("send_pending_buffer has failed with status=HAILO_STREAM_ABORTED_BY_USER"); return status; } CHECK_SUCCESS(status); - assert(contains(m_finished_sent_pending_buffer, network_group_handle)); - m_finished_sent_pending_buffer[network_group_handle][stream_name]++; + scheduled_ng->h2d_requested_transferred_frames().increase(stream_name); + m_devices[device_id]->current_cycle_requested_transferred_frames_h2d[network_group_handle][stream_name]++; + scheduled_ng->finished_write_frames().decrease(stream_name); + + scheduled_ng->h2d_finished_transferred_frames().increase(stream_name); + scheduled_ng->h2d_requested_transferred_frames().decrease(stream_name); if (should_ng_stop(network_group_handle)) { - return HAILO_STREAM_INTERNAL_ABORT; + return HAILO_STREAM_ABORTED_BY_USER; } return HAILO_SUCCESS; } -void NetworkGroupScheduler::deactivate_network_group() +void NetworkGroupScheduler::reset_current_ng_timestamps(uint32_t device_id) { - if (m_ang) { - m_ang.reset(); + auto curr_device_info = m_devices[device_id]; + if (INVALID_NETWORK_GROUP_HANDLE == curr_device_info->current_network_group_handle) { + return; } - reset_current_ng_timestamps(); -} + m_cngs[curr_device_info->current_network_group_handle]->set_last_run_timestamp(std::chrono::steady_clock::now()); // Mark timestamp on de-activation -void NetworkGroupScheduler::reset_current_ng_timestamps() -{ - m_last_run_time_stamp[m_current_network_group] = std::chrono::steady_clock::now(); // Mark timestamp on de-activation - assert(contains(m_last_measured_activation_timestamp, m_current_network_group)); const auto active_duration_sec = std::chrono::duration_cast>( - std::chrono::steady_clock::now() - m_last_measured_activation_timestamp[m_current_network_group]).count(); - m_active_duration[m_current_network_group] += active_duration_sec; -} + std::chrono::steady_clock::now() - m_last_measured_activation_timestamp[curr_device_info->current_network_group_handle]).count(); -hailo_status NetworkGroupScheduler::switch_network_group_if_should_be_next(const scheduler_ng_handle_t &network_group_handle, - std::unique_lock &read_write_lock) -{ - const bool check_threshold = false; - /* Checking (nullptr == m_ang) for activating the first time the scheduler is running. - In this case we don't want to check threshold. */ - if (m_is_switching_network_group && has_ng_drained_everything(m_current_network_group) && - (((nullptr == m_ang) && is_network_group_ready(network_group_handle, check_threshold)) || (m_next_network_group == network_group_handle))) { - auto status = activate_network_group(network_group_handle, read_write_lock); - if (HAILO_STREAM_INTERNAL_ABORT == status) { - return status; - } - CHECK_SUCCESS(status); - } - return HAILO_SUCCESS; + assert(contains(m_active_duration, curr_device_info->current_network_group_handle)); + m_active_duration[curr_device_info->current_network_group_handle] += active_duration_sec; } -bool NetworkGroupScheduler::is_network_group_ready(const scheduler_ng_handle_t &network_group_handle, bool check_threshold) +NetworkGroupScheduler::ReadyInfo NetworkGroupScheduler::is_network_group_ready(const scheduler_ng_handle_t &network_group_handle, bool check_threshold, uint32_t device_id) { - assert(contains(m_written_buffer, network_group_handle)); - assert(contains(m_min_threshold_per_stream, network_group_handle)); - assert(contains(m_last_run_time_stamp, network_group_handle)); + ReadyInfo result; + result.is_ready = false; - // Check if there arent any write requests - bool has_pending_writes = false; - uint32_t written_frames = get_max_value_of_unordered_map(m_requested_write[network_group_handle]); - for (const auto &name_counter_pair : m_pending_read[network_group_handle]) { - uint32_t finished_read_frames = m_finished_read[network_group_handle][name_counter_pair.first]; - if ((finished_read_frames + name_counter_pair.second) < written_frames) { - has_pending_writes = true; - break; - } + if (should_ng_stop(network_group_handle)) { + // Do not switch to an aborted network group + return result; } + auto scheduled_ng = m_cngs[network_group_handle]; + // Check if there arent any write requests + bool has_pending_writes = scheduled_ng->finished_write_frames_min_value() > 0; + // Check if there arent any read requests - bool has_pending_reads = false; - uint32_t read_requests = get_max_value_of_unordered_map(m_requested_read[network_group_handle]); - for (const auto &name_counter_pair : m_allowed_read[network_group_handle]) { - if (name_counter_pair.second < read_requests) { - has_pending_reads = true; + bool has_pending_user_reads = false; + for (const auto &name : scheduled_ng->get_outputs_names()) { + if (scheduled_ng->requested_read_frames(name) > 0) { + has_pending_user_reads = true; break; } } + std::vector over_threshold; + over_threshold.reserve(scheduled_ng->get_inputs_names().size()); + std::vector over_timeout; + over_timeout.reserve(scheduled_ng->get_inputs_names().size()); + if (check_threshold) { - for (auto &name_counter_pair : m_written_buffer[network_group_handle]) { + for (const auto &name : scheduled_ng->get_inputs_names()) { + auto threshold_exp = scheduled_ng->get_threshold(name); + if (!threshold_exp) { + LOGGER__ERROR("Failed to get threshold for stream {}", name); + return result; + } + auto threshold = (DEFAULT_SCHEDULER_MIN_THRESHOLD == threshold_exp.value()) ? 1 : threshold_exp.value(); + auto timeout_exp = scheduled_ng->get_timeout(); + if (!timeout_exp) { + LOGGER__ERROR("Failed to get timeout for stream {}", name); + return result; + } + auto timeout = timeout_exp.release(); + // Check if there arent enough write requests to reach threshold and timeout didnt passed - if ((name_counter_pair.second < m_min_threshold_per_stream[network_group_handle][name_counter_pair.first]) && - ((*(m_timeout_per_network_group[network_group_handle]) > (std::chrono::steady_clock::now() - m_last_run_time_stamp[network_group_handle])))) { - return false; + auto write_requests = scheduled_ng->requested_write_frames(name) + scheduled_ng->finished_write_frames(name); + auto stream_over_threshold = write_requests >= threshold; + auto stream_over_timeout = timeout <= (std::chrono::steady_clock::now() - scheduled_ng->get_last_run_timestamp()); + over_threshold.push_back(stream_over_threshold); + over_timeout.push_back(stream_over_timeout); + if (stream_over_threshold || stream_over_timeout) { + continue; + } else { + result.is_ready = false; + return result; } } } - return has_pending_writes && has_pending_reads && (!has_pending_frames(network_group_handle)); + auto has_pending_vdma_frames = get_max_value_of_unordered_map(m_devices[device_id]->current_cycle_requested_transferred_frames_h2d[network_group_handle]) != + get_min_value_of_unordered_map(m_devices[device_id]->current_cycle_finished_read_frames_d2h[network_group_handle]); + + result.threshold = std::all_of(over_threshold.begin(), over_threshold.end(), [](auto over) { return over; }); + result.timeout = std::all_of(over_timeout.begin(), over_timeout.end(), [](auto over) { return over; }); + result.is_ready = has_pending_writes && has_pending_user_reads && (!has_pending_vdma_frames); + + return result; } -hailo_status NetworkGroupScheduler::wait_for_read(const scheduler_ng_handle_t &network_group_handle, const std::string &stream_name) +Expected NetworkGroupScheduler::wait_for_read(const scheduler_ng_handle_t &network_group_handle, const std::string &stream_name, + const std::chrono::milliseconds &timeout) { + uint32_t device_id = INVALID_DEVICE_ID; { std::unique_lock lock(m_before_read_write_mutex); - assert(contains(m_allowed_read, network_group_handle)); - assert(contains(m_allowed_read[network_group_handle], stream_name)); - assert(contains(m_requested_read, network_group_handle)); - assert(contains(m_requested_read[network_group_handle], stream_name)); - m_requested_read[network_group_handle][stream_name]++; + auto scheduled_ng = m_cngs[network_group_handle]; - hailo_status status = HAILO_UNINITIALIZED; - m_write_read_cv.wait(lock, [this, network_group_handle, stream_name, &status, &lock] { - if (should_ng_stop(network_group_handle)) { - status = HAILO_STREAM_INTERNAL_ABORT; - return true; // return true so that the wait will finish - } + scheduled_ng->requested_read_frames().increase(stream_name); - status = switch_network_group_if_idle(network_group_handle, lock); - if (HAILO_SUCCESS != status) { + hailo_status status = HAILO_SUCCESS; + auto wait_res = m_write_read_cv.wait_for(lock, timeout, [this, network_group_handle, scheduled_ng, stream_name, &status] { + + if (should_ng_stop(network_group_handle)) { + status = HAILO_STREAM_ABORTED_BY_USER; return true; // return true so that the wait will finish } - status = switch_network_group_if_should_be_next(network_group_handle, lock); - if (HAILO_SUCCESS != status) { - return true; // return true so that the wait will finish + auto device_id = NetworkGroupSchedulerOracle::get_avail_device(*this, network_group_handle); + if (INVALID_DEVICE_ID != device_id) { + status = switch_network_group(network_group_handle, device_id); + if (HAILO_SUCCESS != status) { + return true; // return true so that the wait will finish + } } - return can_stream_read(network_group_handle, stream_name); + return scheduled_ng->can_stream_read(stream_name); }); - if (HAILO_STREAM_INTERNAL_ABORT == status) { - return status; + CHECK_AS_EXPECTED(wait_res, HAILO_TIMEOUT, "{} (D2H) failed with status={}, timeout={}ms", stream_name, HAILO_TIMEOUT, timeout.count()); + if (HAILO_STREAM_ABORTED_BY_USER == status) { + return make_unexpected(status); } - CHECK_SUCCESS(status); + CHECK_SUCCESS_AS_EXPECTED(status); - m_allowed_read[network_group_handle][stream_name]++; + scheduled_ng->ongoing_read_frames().increase(stream_name); + scheduled_ng->requested_read_frames().decrease(stream_name); + device_id = scheduled_ng->pop_device_index(stream_name); } m_write_read_cv.notify_all(); - return HAILO_SUCCESS; + return device_id; } -bool NetworkGroupScheduler::can_stream_read(const scheduler_ng_handle_t &network_group_handle, const std::string &stream_name) -{ - assert(contains(m_allowed_read, network_group_handle)); - assert(contains(m_sent_pending_buffer, network_group_handle)); - return m_allowed_read[network_group_handle][stream_name].load() < get_max_value_of_unordered_map(m_sent_pending_buffer[network_group_handle]); -} -hailo_status NetworkGroupScheduler::signal_read_finish(const scheduler_ng_handle_t &network_group_handle, const std::string &stream_name) +hailo_status NetworkGroupScheduler::signal_read_finish(const scheduler_ng_handle_t &network_group_handle, const std::string &stream_name, uint32_t device_id) { { std::unique_lock lock(m_before_read_write_mutex); - assert(contains(m_finished_read, network_group_handle)); - assert(contains(m_finished_read[network_group_handle], stream_name)); - // Prevent integer underflow in nms - if (m_pending_read[network_group_handle][stream_name] > 0) { - m_pending_read[network_group_handle][stream_name]--; - } - m_finished_read[network_group_handle][stream_name]++; - m_current_finished_read[network_group_handle][stream_name]++; - m_fps_accumulator[network_group_handle]++; + auto scheduled_ng = m_cngs[network_group_handle]; - hailo_status status = choose_next_network_group(); - CHECK_SUCCESS(status); + scheduled_ng->finished_read_frames().increase(stream_name); + m_devices[device_id]->current_cycle_finished_read_frames_d2h[network_group_handle][stream_name]++; + scheduled_ng->d2h_finished_transferred_frames().decrease(stream_name); + scheduled_ng->ongoing_read_frames().decrease(stream_name); + m_fps_accumulator[network_group_handle]++; - if (!is_ng_multicontext(network_group_handle)) { - // Prevents integer overflow of the counters - decrease_current_ng_counters(); - } else { - status = try_change_multicontext_ng_batch_size(network_group_handle, lock); - CHECK_SUCCESS(status); - } + decrease_ng_counters(network_group_handle); } - - auto status = allow_all_writes(); - CHECK_SUCCESS(status); m_write_read_cv.notify_all(); return HAILO_SUCCESS; } -bool NetworkGroupScheduler::has_ng_finished(scheduler_ng_handle_t network_group_handle) + +bool NetworkGroupScheduler::has_ng_finished(const scheduler_ng_handle_t &network_group_handle, uint32_t device_id) { if (INVALID_NETWORK_GROUP_HANDLE == network_group_handle) { return true; // If no network group is running, consider it as finished } - if (is_ng_multicontext(network_group_handle)) { - for (auto &name_counter_pair : m_current_finished_read[network_group_handle]) { - if (name_counter_pair.second < m_current_batch_size) { + auto scheduled_ng = m_cngs[network_group_handle]; + + if (scheduled_ng->use_dynamic_batch_flow() || is_multi_device()) { + for (const auto &name : scheduled_ng->get_outputs_names()) { + if (m_devices[device_id]->current_cycle_finished_read_frames_d2h[network_group_handle][name] < m_devices[device_id]->current_batch_size) { return false; } } @@ -878,118 +794,41 @@ bool NetworkGroupScheduler::has_ng_finished(scheduler_ng_handle_t network_group_ return true; } - uint32_t written_frames = get_max_value_of_unordered_map(m_requested_write[network_group_handle]); - for (auto &name_counter_pair : m_finished_read[network_group_handle]) { - if (name_counter_pair.second < written_frames) { + uint32_t written_frames = get_max_value_of_unordered_map(scheduled_ng->total_written_frames_count()); + for (const auto &name : scheduled_ng->get_outputs_names()) { + if (scheduled_ng->finished_read_frames(name) < written_frames) { return false; } } return true; } -bool NetworkGroupScheduler::has_ng_drained_everything(scheduler_ng_handle_t network_group_handle) +void NetworkGroupScheduler::decrease_ng_counters(const scheduler_ng_handle_t &network_group_handle) { - if (INVALID_NETWORK_GROUP_HANDLE == network_group_handle) { - // If no network group is running, consider it as drained - return true; - } - - uint32_t written_frames = get_max_value_of_unordered_map(m_requested_write[network_group_handle]); - for (auto &name_counter_pair : m_finished_sent_pending_buffer[network_group_handle]) { - if (name_counter_pair.second < written_frames) { - return false; - } - } - - assert(contains(m_finished_read, network_group_handle)); - for (const auto &name_counter_pair : m_pending_read[network_group_handle]) { - uint32_t finished_read_frames = m_finished_read[network_group_handle][name_counter_pair.first]; - if ((finished_read_frames + name_counter_pair.second) < written_frames) { - return false; - } - } - return true; + return m_cngs[network_group_handle]->decrease_current_ng_counters(); } -void NetworkGroupScheduler::decrease_current_ng_counters() +bool NetworkGroupScheduler::has_ng_drained_everything(const scheduler_ng_handle_t &network_group_handle, uint32_t device_id) { - if (nullptr == m_ang) { - return; - } - - // Decrease only if counter is 2 or bigger because reaching 0 can cause states to change - for (auto &name_counter_pair : m_requested_write[m_current_network_group]) { - if (name_counter_pair.second <= 1) { - return; - } - } - for (auto &name_counter_pair : m_written_buffer[m_current_network_group]) { - if (name_counter_pair.second <= 1) { - return; - } - } - for (auto &name_counter_pair : m_sent_pending_buffer[m_current_network_group]) { - if (name_counter_pair.second <= 1) { - return; - } - } - for (auto &name_counter_pair : m_finished_sent_pending_buffer[m_current_network_group]) { - if (name_counter_pair.second <= 1) { - return; - } - } - for (auto &name_counter_pair : m_requested_read[m_current_network_group]) { - if (name_counter_pair.second <= 1) { - return; - } - } - for (auto &name_counter_pair : m_allowed_read[m_current_network_group]) { - if (name_counter_pair.second <= 1) { - return; - } - } - for (auto &name_counter_pair : m_finished_read[m_current_network_group]) { - if (name_counter_pair.second <= 1) { - return; - } + if (INVALID_NETWORK_GROUP_HANDLE == network_group_handle) { + // If no network group is running, consider it as drained + return true; } - for (auto &name_counter_pair : m_requested_write[m_current_network_group]) { - name_counter_pair.second--; - } - for (auto &name_counter_pair : m_written_buffer[m_current_network_group]) { - name_counter_pair.second--; - } - for (auto &name_counter_pair : m_sent_pending_buffer[m_current_network_group]) { - name_counter_pair.second--; - } - for (auto &name_counter_pair : m_finished_sent_pending_buffer[m_current_network_group]) { - name_counter_pair.second--; - } - for (auto &name_counter_pair : m_requested_read[m_current_network_group]) { - name_counter_pair.second--; - } - for (auto &name_counter_pair : m_allowed_read[m_current_network_group]) { - name_counter_pair.second--; - } - for (auto &name_counter_pair : m_finished_read[m_current_network_group]) { - name_counter_pair.second--; + if (ng_all_streams_aborted(network_group_handle)) { + // We treat NG as drained only if all streams are aborted - to make sure there aren't any ongoing transfers + return true; } -} -bool NetworkGroupScheduler::is_ng_multicontext(const scheduler_ng_handle_t &network_group_handle) -{ - return (CONTROL_PROTOCOL__IGNORE_DYNAMIC_BATCH_SIZE != m_max_batch_size[network_group_handle]); -} + if ((!m_cngs[network_group_handle]->is_nms()) && (is_multi_device() || m_cngs[network_group_handle]->use_dynamic_batch_flow())) { + auto current_device_info = m_devices[device_id]; + auto max_transferred_h2d = get_max_value_of_unordered_map(current_device_info->current_cycle_requested_transferred_frames_h2d[network_group_handle]); + auto min_transferred_d2h = get_min_value_of_unordered_map(current_device_info->current_cycle_finished_transferred_frames_d2h[network_group_handle]); -uint32_t NetworkGroupScheduler::get_buffered_frames_count() -{ - std::unordered_map buffered_frames; - for (const auto &name_counter_pair : m_requested_write[m_current_network_group]) { - buffered_frames[name_counter_pair.first] = name_counter_pair.second - m_sent_pending_buffer[m_current_network_group][name_counter_pair.first]; + return (max_transferred_h2d == min_transferred_d2h); } - return get_max_value_of_unordered_map(buffered_frames); + return m_cngs[network_group_handle]->has_ng_drained_everything(!(m_cngs[network_group_handle]->use_dynamic_batch_flow() || is_multi_device())); } hailo_status NetworkGroupScheduler::enable_stream(const scheduler_ng_handle_t &network_group_handle, const std::string &stream_name) @@ -997,7 +836,6 @@ hailo_status NetworkGroupScheduler::enable_stream(const scheduler_ng_handle_t &n { std::unique_lock lock(m_before_read_write_mutex); - assert(contains(m_should_ng_stop, network_group_handle)); if (!m_should_ng_stop[network_group_handle][stream_name]) { return HAILO_SUCCESS; } @@ -1012,91 +850,75 @@ hailo_status NetworkGroupScheduler::disable_stream(const scheduler_ng_handle_t & { { std::unique_lock lock(m_before_read_write_mutex); - assert(contains(m_should_ng_stop, network_group_handle)); + if (m_should_ng_stop[network_group_handle][stream_name]) { return HAILO_SUCCESS; } m_should_ng_stop[network_group_handle][stream_name] = true; - - // Signal event to exit infinite timeout on wait_for_write if actually an input stream - assert(contains(m_write_buffer_events, network_group_handle)); - if (contains(m_write_buffer_events[network_group_handle], stream_name)) { - auto status = m_write_buffer_events[network_group_handle][stream_name]->signal(); - CHECK_SUCCESS(status); - } } m_write_read_cv.notify_all(); return HAILO_SUCCESS; } -hailo_status NetworkGroupScheduler::set_timeout(const scheduler_ng_handle_t &network_group_handle, const std::chrono::milliseconds &timeout, const std::string &network_name) +hailo_status NetworkGroupScheduler::set_timeout(const scheduler_ng_handle_t &network_group_handle, const std::chrono::milliseconds &timeout, const std::string &/*network_name*/) { - (void)network_name; - - assert(contains(m_timeout_per_network_group, network_group_handle)); - assert(contains(m_last_run_time_stamp, network_group_handle)); - assert(contains(m_frame_was_sent_per_network_group, network_group_handle)); - CHECK(!m_frame_was_sent_per_network_group[network_group_handle], HAILO_INVALID_OPERATION, - "Setting scheduler timeout is allowed only before sending / receiving frames on the network group."); - *(m_timeout_per_network_group[network_group_handle]) = timeout; - - assert(m_cngs.size() > network_group_handle); - auto cng = m_cngs[network_group_handle].lock(); - CHECK(cng, HAILO_INTERNAL_FAILURE); - - auto name = (network_name.empty()) ? cng->name() : network_name; - LOGGER__INFO("Setting scheduler timeout of {} to {}ms", name, timeout.count()); + // TODO: call in loop for set_timeout with the relevant stream-names (of the given network) + return m_cngs[network_group_handle]->set_timeout(timeout); +} - return HAILO_SUCCESS; +hailo_status NetworkGroupScheduler::set_threshold(const scheduler_ng_handle_t &network_group_handle, uint32_t threshold, const std::string &/*network_name*/) +{ + // TODO: call in loop for set_timeout with the relevant stream-names (of the given network) + return m_cngs[network_group_handle]->set_threshold(threshold); } -hailo_status NetworkGroupScheduler::set_threshold(const scheduler_ng_handle_t &network_group_handle, uint32_t threshold, const std::string &network_name) +void NetworkGroupScheduler::choose_next_network_group(size_t device_id) { - (void)network_name; - - assert(contains(m_min_threshold_per_stream, network_group_handle)); - assert(contains(m_last_run_time_stamp, network_group_handle)); - assert(contains(m_frame_was_sent_per_network_group, network_group_handle)); - CHECK(!m_frame_was_sent_per_network_group[network_group_handle], HAILO_INVALID_OPERATION, - "Setting scheduler threshold is allowed only before sending / receiving frames on the network group."); - for (auto &threshold_per_stream_pair : m_min_threshold_per_stream[network_group_handle]) { - threshold_per_stream_pair.second = threshold; + if (!m_devices[device_id]->is_switching_network_group) { + NetworkGroupSchedulerOracle::choose_next_model(*this, m_devices[device_id]->device_id); } +} - assert(m_cngs.size() > network_group_handle); - auto cng = m_cngs[network_group_handle].lock(); - CHECK(cng, HAILO_INTERNAL_FAILURE); - - auto name = (network_name.empty()) ? cng->name() : network_name; - LOGGER__INFO("Setting scheduler threshold of {} to {} frames", name, threshold); +bool NetworkGroupScheduler::should_ng_stop(const scheduler_ng_handle_t &network_group_handle) +{ + for (const auto &name_flag_pair : m_should_ng_stop[network_group_handle]) { + if (name_flag_pair.second) { + return true; + } + } - return HAILO_SUCCESS; + return false; } -hailo_status NetworkGroupScheduler::choose_next_network_group() +bool NetworkGroupScheduler::ng_all_streams_aborted(const scheduler_ng_handle_t &network_group_handle) { - if (!m_is_switching_network_group) { - bool check_threshold = true; - if (find_next_network_group_by_algorithm(check_threshold)) { - return HAILO_SUCCESS; + for (const auto &name_flag_pair : m_should_ng_stop[network_group_handle]) { + if (!name_flag_pair.second) { + return false; } } - return HAILO_SUCCESS; + return true; } -bool NetworkGroupSchedulerRoundRobin::find_next_network_group_by_algorithm(bool check_threshold) +void NetworkGroupScheduler::notify_all() { - for (uint32_t i = 0; i < m_cngs.size() - 1; i++) { - uint32_t index = m_current_network_group + i + 1; - index %= static_cast(m_cngs.size()); - if (is_network_group_ready(index, check_threshold)) { - m_is_switching_network_group = true; - m_next_network_group = index; - return true; - } + { + // Acquire mutex to make sure the notify_all will wake the blocking threads on the cv + std::unique_lock lock(m_before_read_write_mutex); } - return false; + m_write_read_cv.notify_all(); } +void NetworkGroupScheduler::mark_failed_write(const scheduler_ng_handle_t &network_group_handle, const std::string &stream_name) +{ + { + std::unique_lock lock(m_before_read_write_mutex); + assert(m_cngs.size() > network_group_handle); + m_cngs[network_group_handle]->requested_write_frames().decrease(stream_name); + } + m_write_read_cv.notify_all(); +} + + } /* namespace hailort */ diff --git a/hailort/libhailort/src/network_group_scheduler.hpp b/hailort/libhailort/src/network_group_scheduler.hpp index f8f86fb..9b6b2b7 100644 --- a/hailort/libhailort/src/network_group_scheduler.hpp +++ b/hailort/libhailort/src/network_group_scheduler.hpp @@ -16,16 +16,19 @@ #include "common/utils.hpp" #include "common/filesystem.hpp" #include "scheduler_mon.hpp" +#include "scheduled_network_group.hpp" #include #define DEFAULT_SCHEDULER_TIMEOUT (std::chrono::milliseconds(0)) -#define DEFAULT_SCHEDULER_MIN_THRESHOLD (1) +#define DEFAULT_SCHEDULER_MIN_THRESHOLD (0) namespace hailort { #define INVALID_NETWORK_GROUP_HANDLE (UINT32_MAX) +#define INVALID_DEVICE_ID (UINT32_MAX) + using scheduler_ng_handle_t = uint32_t; class NetworkGroupScheduler; @@ -36,12 +39,28 @@ using NetworkGroupSchedulerWeakPtr = std::weak_ptr; using stream_name_t = std::string; +struct ActiveDeviceInfo { + ActiveDeviceInfo(uint32_t device_id) : current_network_group_handle(INVALID_NETWORK_GROUP_HANDLE), + next_network_group_handle(INVALID_NETWORK_GROUP_HANDLE), is_switching_network_group(false), current_batch_size(0), current_burst_size(0), + current_cycle_requested_transferred_frames_h2d(), current_cycle_finished_transferred_frames_d2h(), current_cycle_finished_read_frames_d2h(), + device_id(device_id) + {} + scheduler_ng_handle_t current_network_group_handle; + scheduler_ng_handle_t next_network_group_handle; + std::atomic_bool is_switching_network_group; + std::atomic_uint32_t current_batch_size; + std::atomic_uint32_t current_burst_size; + std::unordered_map> current_cycle_requested_transferred_frames_h2d; + std::unordered_map> current_cycle_finished_transferred_frames_d2h; + std::unordered_map> current_cycle_finished_read_frames_d2h; + uint32_t device_id; +}; class NetworkGroupScheduler { public: - static Expected create_round_robin(); - NetworkGroupScheduler(hailo_scheduling_algorithm_t algorithm); + static Expected create_round_robin(uint32_t device_count); + NetworkGroupScheduler(hailo_scheduling_algorithm_t algorithm, uint32_t device_count); virtual ~NetworkGroupScheduler(); NetworkGroupScheduler(const NetworkGroupScheduler &other) = delete; @@ -54,12 +73,14 @@ public: return m_algorithm; } - Expected add_network_group(std::weak_ptr added_cng); + Expected add_network_group(std::shared_ptr added_cng); - hailo_status wait_for_write(const scheduler_ng_handle_t &network_group_handle, const std::string &stream_name); + hailo_status wait_for_write(const scheduler_ng_handle_t &network_group_handle, const std::string &stream_name, + const std::chrono::milliseconds &timeout, const std::function &should_cancel); hailo_status signal_write_finish(const scheduler_ng_handle_t &network_group_handle, const std::string &stream_name); - hailo_status wait_for_read(const scheduler_ng_handle_t &network_group_handle, const std::string &stream_name); - hailo_status signal_read_finish(const scheduler_ng_handle_t &network_group_handle, const std::string &stream_name); + Expected wait_for_read(const scheduler_ng_handle_t &network_group_handle, const std::string &stream_name, + const std::chrono::milliseconds &timeout); + hailo_status signal_read_finish(const scheduler_ng_handle_t &network_group_handle, const std::string &stream_name, uint32_t device_id); hailo_status enable_stream(const scheduler_ng_handle_t &network_group_handle, const std::string &stream_name); hailo_status disable_stream(const scheduler_ng_handle_t &network_group_handle, const std::string &stream_name); @@ -67,53 +88,51 @@ public: hailo_status set_timeout(const scheduler_ng_handle_t &network_group_handle, const std::chrono::milliseconds &timeout, const std::string &network_name); hailo_status set_threshold(const scheduler_ng_handle_t &network_group_handle, uint32_t threshold, const std::string &network_name); + void notify_all(); + void mark_failed_write(const scheduler_ng_handle_t &network_group_handle, const std::string &stream_name); + protected: - hailo_status choose_next_network_group(); - virtual bool find_next_network_group_by_algorithm(bool check_threshold) = 0; - bool is_network_group_ready(const scheduler_ng_handle_t &network_group_handle, bool check_threshold); + struct ReadyInfo { + bool threshold = false; + bool timeout = false; + bool is_ready = false; + }; - std::atomic_bool m_is_switching_network_group; - scheduler_ng_handle_t m_current_network_group; - scheduler_ng_handle_t m_next_network_group; + void choose_next_network_group(size_t device_id); + ReadyInfo is_network_group_ready(const scheduler_ng_handle_t &network_group_handle, bool check_threshold, uint32_t device_id); - std::vector> m_cngs; - std::unique_ptr m_ang; + std::vector> m_devices; + std::unordered_map m_changing_current_batch_size; + std::unordered_map> m_should_ng_stop; + + std::vector> m_cngs; private: - hailo_status switch_network_group_if_should_be_next(const scheduler_ng_handle_t &network_group_handle, std::unique_lock &read_write_lock); - hailo_status switch_network_group_if_idle(const scheduler_ng_handle_t &network_group_handle, std::unique_lock &read_write_lock); - hailo_status activate_network_group(const scheduler_ng_handle_t &network_group_handle, std::unique_lock &read_write_lock, + hailo_status switch_network_group(const scheduler_ng_handle_t &network_group_handle, uint32_t device_id, bool keep_nn_config = false); - void deactivate_network_group(); - void reset_current_ng_timestamps(); - hailo_status try_change_multicontext_ng_batch_size(const scheduler_ng_handle_t &network_group_handle, std::unique_lock &read_write_lock); + void reset_current_ng_timestamps(uint32_t device_id); - bool has_input_written_most_frames(const scheduler_ng_handle_t &network_group_handle, const std::string &stream_name); - bool can_stream_write(const scheduler_ng_handle_t &network_group_handle, const std::string &stream_name); - hailo_status block_write_if_needed(const scheduler_ng_handle_t &network_group_handle, const std::string &stream_name); Expected should_wait_for_write(const scheduler_ng_handle_t &network_group_handle, const std::string &stream_name); - hailo_status allow_all_writes(); - hailo_status allow_writes_for_other_inputs_if_needed(const scheduler_ng_handle_t &network_group_handle); - hailo_status send_all_pending_buffers(const scheduler_ng_handle_t &network_group_handle, std::unique_lock &read_write_lock); - hailo_status send_pending_buffer(const scheduler_ng_handle_t &network_group_handle, const std::string &stream_name, std::unique_lock &read_write_lock); - + hailo_status send_all_pending_buffers(const scheduler_ng_handle_t &network_group_handle, uint32_t device_id); + hailo_status send_pending_buffer(const scheduler_ng_handle_t &network_group_handle, const std::string &stream_name, uint32_t device_id); + + void decrease_ng_counters(const scheduler_ng_handle_t &network_group_handle); + bool has_ng_drained_everything(const scheduler_ng_handle_t &network_group_handle, uint32_t device_id); + bool has_ng_finished(const scheduler_ng_handle_t &network_group_handle, uint32_t device_id); bool should_ng_stop(const scheduler_ng_handle_t &network_group_handle); - bool can_stream_read(const scheduler_ng_handle_t &network_group_handle, const std::string &stream_name); - bool has_ng_finished(scheduler_ng_handle_t network_group_handle); - bool has_ng_drained_everything(scheduler_ng_handle_t network_group_handle); - bool has_pending_frames(const scheduler_ng_handle_t &network_group_handle); - bool has_enough_space_in_read_buffers(const scheduler_ng_handle_t &network_group_handle, uint32_t ongoing_frames); - void decrease_current_ng_counters(); - bool is_ng_multicontext(const scheduler_ng_handle_t &network_group_handle); - uint32_t get_buffered_frames_count(); - - std::string get_network_group_name(scheduler_ng_handle_t network_group_handle); + bool ng_all_streams_aborted(const scheduler_ng_handle_t &network_group_handle); + + std::string get_network_group_name(const scheduler_ng_handle_t &network_group_handle); + bool is_network_group_active(const scheduler_ng_handle_t &network_group_handle); + bool is_switching_current_network_group(const scheduler_ng_handle_t &network_group_handle); + bool is_multi_device(); + hailo_status start_mon(); void log_monitor_networks_infos(ProtoMon &mon); void log_monitor_frames_infos(ProtoMon &mon); - hailo_status set_h2d_frames_counters(scheduler_ng_handle_t network_group_handle, const std::string &stream_name, + hailo_status set_h2d_frames_counters(const scheduler_ng_handle_t &network_group_handle, const std::string &stream_name, ProtoMonStreamFramesInfo &stream_frames_info); - hailo_status set_d2h_frames_counters(scheduler_ng_handle_t network_group_handle, const std::string &stream_name, + hailo_status set_d2h_frames_counters(const scheduler_ng_handle_t &network_group_handle, const std::string &stream_name, ProtoMonStreamFramesInfo &stream_frames_info); #if defined(__GNUC__) Expected> open_temp_mon_file(); @@ -122,30 +141,8 @@ private: hailo_scheduling_algorithm_t m_algorithm; std::mutex m_before_read_write_mutex; - std::atomic_uint32_t m_current_batch_size; std::condition_variable m_write_read_cv; - - std::unordered_map> m_requested_write; - std::unordered_map> m_written_buffer; - std::unordered_map> m_sent_pending_buffer; - std::unordered_map> m_current_sent_pending_buffer; - std::unordered_map> m_finished_sent_pending_buffer; - - std::unordered_map> m_requested_read; - std::unordered_map> m_allowed_read; - std::unordered_map> m_finished_read; - std::unordered_map> m_current_finished_read; - std::unordered_map> m_pending_read; - - std::unordered_map> m_min_threshold_per_stream; - - std::unordered_map> m_last_run_time_stamp; - std::unordered_map> m_timeout_per_network_group; - std::unordered_map m_frame_was_sent_per_network_group; - std::unordered_map m_max_batch_size; - - std::unordered_map> m_should_ng_stop; - std::unordered_map> m_write_buffer_events; + scheduler_ng_handle_t m_last_choosen_network_group; // Params for the scheduler MON std::atomic_bool m_should_monitor; @@ -159,18 +156,8 @@ private: // TODO: Consider adding Accumulator classes for more info (min, max, mean, etc..) std::unordered_map m_active_duration; std::unordered_map m_fps_accumulator; -}; - -class NetworkGroupSchedulerRoundRobin : public NetworkGroupScheduler -{ -public: - NetworkGroupSchedulerRoundRobin() : - NetworkGroupScheduler(HAILO_SCHEDULING_ALGORITHM_ROUND_ROBIN) - {}; - -protected: - virtual bool find_next_network_group_by_algorithm(bool check_threshold) override; + friend class NetworkGroupSchedulerOracle; }; } /* namespace hailort */ diff --git a/hailort/libhailort/src/os/CMakeLists.txt b/hailort/libhailort/src/os/CMakeLists.txt index 1f866a6..4e52af3 100644 --- a/hailort/libhailort/src/os/CMakeLists.txt +++ b/hailort/libhailort/src/os/CMakeLists.txt @@ -25,18 +25,7 @@ set(files ${HAILO_OS_DIR}/mmap_buffer.cpp ${HAILO_OS_DIR}/hailort_driver.cpp ${HAILO_FULL_OS_DIR}/event.cpp + ${HAILO_FULL_OS_DIR}/driver_scan.cpp ) -if(CMAKE_SYSTEM_NAME STREQUAL QNX) - # QNX only modules - set(files ${files} - ${HAILO_OS_DIR}/qnx/pcie_driver_scan.cpp - ) -elseif(UNIX) - # Unix only modules - set(files ${files} - ${HAILO_OS_DIR}/unix/pcie_driver_scan.cpp - ) -endif() - set(HAILORT_CPP_OS_SOURCES ${files} PARENT_SCOPE) diff --git a/hailort/libhailort/src/os/posix/pcie_driver_scan.hpp b/hailort/libhailort/src/os/driver_scan.hpp similarity index 75% rename from hailort/libhailort/src/os/posix/pcie_driver_scan.hpp rename to hailort/libhailort/src/os/driver_scan.hpp index 4536cfe..c8620aa 100644 --- a/hailort/libhailort/src/os/posix/pcie_driver_scan.hpp +++ b/hailort/libhailort/src/os/driver_scan.hpp @@ -3,7 +3,7 @@ * Distributed under the MIT license (https://opensource.org/licenses/MIT) **/ /** - * @file pcie_driver_scan.hpp + * @file driver_scan.hpp * @brief Get list and parse pcie driver info **/ @@ -12,11 +12,11 @@ namespace hailort { -Expected> list_pcie_devices(); -#if defined(__linux__) +Expected> list_devices(); +#ifndef __QNX__ Expected query_device_info(const std::string &device_name); -#elif defined(__QNX__) +#else // __QNX__ Expected query_device_info(const std::string &device_name, uint32_t index); -#endif // defined(__linux__) +#endif // __QNX__ } /* namespace hailort */ diff --git a/hailort/libhailort/src/os/hailort_driver.hpp b/hailort/libhailort/src/os/hailort_driver.hpp index 470e24b..c55fc67 100755 --- a/hailort/libhailort/src/os/hailort_driver.hpp +++ b/hailort/libhailort/src/os/hailort_driver.hpp @@ -13,10 +13,10 @@ #include "hailo/hailort.h" #include "hailo/expected.hpp" -#include "d2h_event_queue.hpp" #include "os/file_descriptor.hpp" -#include "os/mmap_buffer.hpp" #include "vdma/channel_id.hpp" +#include "common/utils.hpp" +#include "hailo_ioctl_common.h" #include #include @@ -33,7 +33,7 @@ namespace hailort #define DEVICE_NODE_NAME "hailo" #define PENDING_BUFFERS_SIZE (128) -static_assert((0 == ((PENDING_BUFFERS_SIZE - 1) & PENDING_BUFFERS_SIZE)), "PENDING_BUFFERS_SIZE must be a power of 2"); +static_assert((0 == ((PENDING_BUFFERS_SIZE - 1) & PENDING_BUFFERS_SIZE)), "PENDING_BUFFERS_SIZE must be a power of 2"); #define MIN_ACTIVE_TRANSFERS_SCALE (2) #define MAX_ACTIVE_TRANSFERS_SCALE (4) @@ -43,8 +43,6 @@ static_assert((0 == ((PENDING_BUFFERS_SIZE - 1) & PENDING_BUFFERS_SIZE)), "PEND // When measuring latency, each channel is capable of PENDING_BUFFERS_SIZE active transfers, each transfer raises max of 2 timestamps #define MAX_IRQ_TIMESTAMPS_SIZE (PENDING_BUFFERS_SIZE * 2) -#define DESCRIPTORS_IN_BUFFER(buffer_size, desc_page_size) (((buffer_size) + (desc_page_size) - 1) / (desc_page_size)) - #define PCIE_EXPECTED_MD5_LENGTH (16) constexpr size_t VDMA_CHANNELS_PER_ENGINE = 32; @@ -54,15 +52,6 @@ constexpr uint8_t MIN_D2H_CHANNEL_INDEX = MAX_H2D_CHANNEL_INDEX + 1; constexpr uint8_t MAX_D2H_CHANNEL_INDEX = 31; -enum class PciBar { - bar0 = 0, - bar1, - bar2, - bar3, - bar4, - bar5, -}; - // NOTE: don't change members from this struct without updating all code using it (platform specific) struct ChannelInterruptTimestamp { std::chrono::nanoseconds timestamp; @@ -91,16 +80,7 @@ public: struct DeviceInfo { std::string dev_path; - - // Board information - uint32_t vendor_id; - uint32_t device_id; - - // PCIe board location - uint32_t domain; - uint32_t bus; - uint32_t device; - uint32_t func; + std::string device_id; }; enum class DmaDirection { @@ -109,17 +89,30 @@ public: BOTH }; - // TODO: move to general place - enum class BoardType { - HAILO8 = 0, - MERCURY = 1 - }; - enum class DmaType { PCIE, DRAM }; + enum class MemoryType { + DIRECT_MEMORY, + + // vDMA memories + VDMA0, // On PCIe board, VDMA0 and BAR2 are the same + VDMA1, + VDMA2, + + // PCIe driver memories + PCIE_BAR0, + PCIE_BAR2, + PCIE_BAR4, + + // DRAM DMA driver memories + DMA_ENGINE0, + DMA_ENGINE1, + DMA_ENGINE2, + }; + using VdmaBufferHandle = size_t; using VdmaChannelHandle = uint64_t; @@ -130,10 +123,10 @@ public: static hailo_status hailo_ioctl(int fd, int request, void* request_struct, int &error_status); #endif // defined(__linux__) || defined(__QNX__) - static Expected> scan_pci(); + static Expected> scan_devices(); - hailo_status read_bar(PciBar bar, off_t offset, size_t size, void *buf); - hailo_status write_bar(PciBar bar, off_t offset, size_t size, const void *buf); + hailo_status read_memory(MemoryType memory_type, uint64_t address, void *buf, size_t size); + hailo_status write_memory(MemoryType memory_type, uint64_t address, const void *buf, size_t size); Expected read_vdma_channel_register(vdma::ChannelId channel_id, DmaDirection data_direction, size_t offset, size_t reg_size); @@ -143,14 +136,14 @@ public: hailo_status vdma_buffer_sync(VdmaBufferHandle buffer, DmaDirection sync_direction, void *address, size_t buffer_size); Expected vdma_channel_enable(vdma::ChannelId channel_id, DmaDirection data_direction, - uintptr_t desc_list_handle, bool enable_timestamps_measure); + bool enable_timestamps_measure); hailo_status vdma_channel_disable(vdma::ChannelId channel_index, VdmaChannelHandle channel_handle); Expected wait_channel_interrupts(vdma::ChannelId channel_id, VdmaChannelHandle channel_handle, const std::chrono::milliseconds &timeout); hailo_status vdma_channel_abort(vdma::ChannelId channel_id, VdmaChannelHandle channel_handle); hailo_status vdma_channel_clear_abort(vdma::ChannelId channel_id, VdmaChannelHandle channel_handle); - Expected read_notification(); + Expected> read_notification(); hailo_status disable_notifications(); hailo_status fw_control(const void *request, size_t request_len, const uint8_t request_md5[PCIE_EXPECTED_MD5_LENGTH], @@ -204,7 +197,7 @@ public: * Configure vdma channel descriptors to point to the given user address. */ hailo_status descriptors_list_bind_vdma_buffer(uintptr_t desc_handle, VdmaBufferHandle buffer_handle, - uint16_t desc_page_size, uint8_t channel_index); + uint16_t desc_page_size, uint8_t channel_index, size_t offset); Expected vdma_low_memory_buffer_alloc(size_t size); hailo_status vdma_low_memory_buffer_free(uintptr_t buffer_handle); @@ -234,11 +227,6 @@ public: return static_cast(std::min(static_cast(requested_size), static_cast(m_desc_max_page_size))); } - inline BoardType board_type() const - { - return m_board_type; - } - inline DmaType dma_type() const { return m_dma_type; @@ -274,6 +262,11 @@ public: return m_dma_engines_count; } + inline bool is_fw_loaded() const + { + return m_is_fw_loaded; + } + HailoRTDriver(const HailoRTDriver &other) = delete; HailoRTDriver &operator=(const HailoRTDriver &other) = delete; HailoRTDriver(HailoRTDriver &&other) noexcept = default; @@ -284,6 +277,8 @@ public: static const uint8_t INVALID_VDMA_CHANNEL_INDEX; private: + hailo_status read_memory_ioctl(MemoryType memory_type, uint64_t address, void *buf, size_t size); + hailo_status write_memory_ioctl(MemoryType memory_type, uint64_t address, const void *buf, size_t size); HailoRTDriver(const std::string &dev_path, FileDescriptor &&fd, hailo_status &status); @@ -292,10 +287,10 @@ private: FileDescriptor m_fd; std::string m_dev_path; uint16_t m_desc_max_page_size; - BoardType m_board_type; DmaType m_dma_type; bool m_allocate_driver_buffer; size_t m_dma_engines_count; + bool m_is_fw_loaded; #ifdef __QNX__ pid_t m_resource_manager_pid; #endif // __QNX__ diff --git a/hailort/libhailort/src/os/posix/hailort_driver.cpp b/hailort/libhailort/src/os/posix/hailort_driver.cpp index f6cd762..7b4d4a1 100755 --- a/hailort/libhailort/src/os/posix/hailort_driver.cpp +++ b/hailort/libhailort/src/os/posix/hailort_driver.cpp @@ -1,5 +1,5 @@ #include "os/hailort_driver.hpp" -#include "os/posix/pcie_driver_scan.hpp" +#include "os/driver_scan.hpp" #include "hailo_ioctl_common.h" #include "common/logger_macros.hpp" #include "common/utils.hpp" @@ -24,34 +24,66 @@ namespace hailort static_assert(VDMA_CHANNELS_PER_ENGINE == MAX_VDMA_CHANNELS_PER_ENGINE, "Driver and libhailort parameters mismatch"); static_assert(MIN_D2H_CHANNEL_INDEX == VDMA_DEST_CHANNELS_START, "Driver and libhailort parameters mismatch"); -constexpr hailo_dma_data_direction direction_to_dma_data_direction(HailoRTDriver::DmaDirection direction) { - switch (direction){ +static hailo_dma_data_direction direction_to_dma_data_direction(HailoRTDriver::DmaDirection direction) { + switch (direction) { case HailoRTDriver::DmaDirection::H2D: return HAILO_DMA_TO_DEVICE; case HailoRTDriver::DmaDirection::D2H: return HAILO_DMA_FROM_DEVICE; case HailoRTDriver::DmaDirection::BOTH: return HAILO_DMA_BIDIRECTIONAL; - default: - assert(true); - // On release build Return value that will make ioctls to fail. - return HAILO_DMA_NONE; } + + assert(false); + // On release build Return value that will make ioctls to fail. + return HAILO_DMA_NONE; } -constexpr enum hailo_cpu_id translate_cpu_id(hailo_cpu_id_t cpu_id) +static enum hailo_cpu_id translate_cpu_id(hailo_cpu_id_t cpu_id) { - switch (cpu_id) - { + switch (cpu_id) { case HAILO_CPU_ID_0: return HAILO_CPU_ID_CPU0; case HAILO_CPU_ID_1: return HAILO_CPU_ID_CPU1; - default: - assert(true); - // On release build Return value that will make ioctls to fail. - return HAILO_CPU_ID_NONE; + case HAILO_CPU_ID_MAX_ENUM: + // Add label for HAILO_CPU_ID_MAX_ENUM to cover all enum cases (avoid warnings). Continue to the assert. + break; + } + + assert(false); + // On release build Return value that will make ioctls to fail. + return HAILO_CPU_ID_NONE; +} + +static hailo_transfer_memory_type translate_memory_type(HailoRTDriver::MemoryType memory_type) +{ + using MemoryType = HailoRTDriver::MemoryType; + switch (memory_type) { + case MemoryType::DIRECT_MEMORY: + return HAILO_TRANSFER_DEVICE_DIRECT_MEMORY; + case MemoryType::VDMA0: + return HAILO_TRANSFER_MEMORY_VDMA0; + case MemoryType::VDMA1: + return HAILO_TRANSFER_MEMORY_VDMA1; + case MemoryType::VDMA2: + return HAILO_TRANSFER_MEMORY_VDMA2; + case MemoryType::PCIE_BAR0: + return HAILO_TRANSFER_MEMORY_PCIE_BAR0; + case MemoryType::PCIE_BAR2: + return HAILO_TRANSFER_MEMORY_PCIE_BAR2; + case MemoryType::PCIE_BAR4: + return HAILO_TRANSFER_MEMORY_PCIE_BAR4; + case MemoryType::DMA_ENGINE0: + return HAILO_TRANSFER_MEMORY_DMA_ENGINE0; + case MemoryType::DMA_ENGINE1: + return HAILO_TRANSFER_MEMORY_DMA_ENGINE1; + case MemoryType::DMA_ENGINE2: + return HAILO_TRANSFER_MEMORY_DMA_ENGINE2; } + + assert(false); + return HAILO_TRANSFER_MEMORY_MAX_ENUM; } static Expected create_interrupt_timestamp_list(hailo_vdma_channel_wait_params &inter_data) @@ -104,7 +136,7 @@ hailo_status HailoRTDriver::hailo_ioctl(int fd, int request, void* request_struc case ETIMEDOUT: return HAILO_TIMEOUT; case ECONNABORTED: - return HAILO_STREAM_INTERNAL_ABORT; + return HAILO_STREAM_ABORTED_BY_USER; case ECONNRESET: return HAILO_STREAM_NOT_ACTIVATED; default: @@ -157,18 +189,6 @@ HailoRTDriver::HailoRTDriver(const std::string &dev_path, FileDescriptor &&fd, h m_desc_max_page_size = device_properties.desc_max_page_size; m_allocate_driver_buffer = (HAILO_ALLOCATION_MODE_DRIVER == device_properties.allocation_mode); m_dma_engines_count = device_properties.dma_engines_count; - switch (device_properties.board_type) { - case HAILO8: - m_board_type = BoardType::HAILO8; - break; - case HAILO_MERCURY: - m_board_type = BoardType::MERCURY; - break; - default: - LOGGER__ERROR("Invalid board type returned from ioctl {}", device_properties.board_type); - status = HAILO_PCIE_DRIVER_FAIL; - return; - } switch (device_properties.dma_type) { case HAILO_DMA_TYPE_PCIE: @@ -183,6 +203,8 @@ HailoRTDriver::HailoRTDriver(const std::string &dev_path, FileDescriptor &&fd, h return; } + m_is_fw_loaded = device_properties.is_fw_loaded; + #ifdef __QNX__ m_resource_manager_pid = device_properties.resource_manager_pid; #endif // __QNX__ @@ -190,10 +212,9 @@ HailoRTDriver::HailoRTDriver(const std::string &dev_path, FileDescriptor &&fd, h status = HAILO_SUCCESS; } -Expected HailoRTDriver::read_notification() +Expected> HailoRTDriver::read_notification() { hailo_d2h_notification notification_buffer = {}; - D2H_EVENT_MESSAGE_t notification; int err = 0; auto status = hailo_ioctl(this->m_fd, HAILO_READ_NOTIFICATION, ¬ification_buffer, err); @@ -201,10 +222,8 @@ Expected HailoRTDriver::read_notification() return make_unexpected(HAILO_PCIE_DRIVER_FAIL); } - CHECK_AS_EXPECTED(sizeof(notification) >= notification_buffer.buffer_len, HAILO_GET_D2H_EVENT_MESSAGE_FAIL, - "buffer len is not valid = {}", notification_buffer.buffer_len); - - memcpy(¬ification, notification_buffer.buffer, notification_buffer.buffer_len); + std::vector notification(notification_buffer.buffer_len); + memcpy(notification.data(), notification_buffer.buffer, notification_buffer.buffer_len); return notification; } @@ -221,9 +240,9 @@ hailo_status HailoRTDriver::disable_notifications() } #if defined(__linux__) -Expected> HailoRTDriver::scan_pci() +Expected> HailoRTDriver::scan_devices() { - auto device_names = list_pcie_devices(); + auto device_names = list_devices(); CHECK_EXPECTED(device_names, "Failed listing pcie devices"); std::vector devices_info; @@ -235,9 +254,9 @@ Expected> HailoRTDriver::scan_pci() return devices_info; } #elif defined(__QNX__) -Expected> HailoRTDriver::scan_pci() +Expected> HailoRTDriver::scan_devices() { - auto device_names = list_pcie_devices(); + auto device_names = list_devices(); CHECK_EXPECTED(device_names, "Failed listing pcie devices"); // TODO: HRT-6785 - support multiple devices - currently device_names is vector of one device - in future will be multiple @@ -303,7 +322,32 @@ hailo_status HailoRTDriver::write_vdma_channel_register(vdma::ChannelId channel_ return HAILO_SUCCESS; } -hailo_status HailoRTDriver::read_bar(PciBar bar, off_t offset, size_t size, void *buf) +hailo_status HailoRTDriver::read_memory(MemoryType memory_type, uint64_t address, void *buf, size_t size) +{ + if (size == 0) { + LOGGER__ERROR("Invalid size to read"); + return HAILO_INVALID_ARGUMENT; + } + + if (buf == nullptr) { + LOGGER__ERROR("Read buffer pointer is NULL"); + return HAILO_INVALID_ARGUMENT; + } + + constexpr uint32_t CHUNK_SIZE = ARRAY_ENTRIES(hailo_memory_transfer_params::buffer); + uint32_t offset = 0; + + while (offset < size) { + const uint32_t actual_size = std::min(CHUNK_SIZE, static_cast(size) - offset); + auto status = read_memory_ioctl(memory_type, address + offset, + reinterpret_cast(buf) + offset, actual_size); + CHECK_SUCCESS(status); + offset += actual_size; + } + return HAILO_SUCCESS; +} + +hailo_status HailoRTDriver::write_memory(MemoryType memory_type, uint64_t address, const void *buf, size_t size) { if (size == 0) { LOGGER__ERROR("Invalid size to read"); @@ -315,23 +359,42 @@ hailo_status HailoRTDriver::read_bar(PciBar bar, off_t offset, size_t size, void return HAILO_INVALID_ARGUMENT; } - hailo_bar_transfer_params transfer = { + constexpr uint32_t CHUNK_SIZE = ARRAY_ENTRIES(hailo_memory_transfer_params::buffer); + uint32_t offset = 0; + + while (offset < size) { + const uint32_t actual_size = std::min(CHUNK_SIZE, static_cast(size) - offset); + auto status = write_memory_ioctl(memory_type, address + offset, + reinterpret_cast(buf) + offset, actual_size); + CHECK_SUCCESS(status); + offset += actual_size; + } + return HAILO_SUCCESS; +} + +hailo_status HailoRTDriver::read_memory_ioctl(MemoryType memory_type, uint64_t address, void *buf, size_t size) +{ + hailo_memory_transfer_params transfer = { .transfer_direction = TRANSFER_READ, - .bar_index = static_cast(bar), - .offset = offset, + .memory_type = translate_memory_type(memory_type), + .address = address, .count = size, .buffer = {0} }; + if (m_dma_type == DmaType::PCIE) { + CHECK(address < std::numeric_limits::max(), HAILO_INVALID_ARGUMENT, "Address out of range {}", address); + } + if (size > sizeof(transfer.buffer)) { LOGGER__ERROR("Invalid size to read, size given {} is larger than max size {}", size, sizeof(transfer.buffer)); return HAILO_INVALID_ARGUMENT; } int err = 0; - auto status = hailo_ioctl(this->m_fd, HAILO_BAR_TRANSFER, &transfer, err); + auto status = hailo_ioctl(this->m_fd, HAILO_MEMORY_TRANSFER, &transfer, err); if (HAILO_SUCCESS != status) { - LOGGER__ERROR("HailoRTDriver::read_bar failed with errno:{}", err); + LOGGER__ERROR("HailoRTDriver::read_memory failed with errno:{}", err); return HAILO_PCIE_DRIVER_FAIL; } @@ -340,26 +403,20 @@ hailo_status HailoRTDriver::read_bar(PciBar bar, off_t offset, size_t size, void return HAILO_SUCCESS; } -hailo_status HailoRTDriver::write_bar(PciBar bar, off_t offset, size_t size, const void *buf) +hailo_status HailoRTDriver::write_memory_ioctl(MemoryType memory_type, uint64_t address, const void *buf, size_t size) { - if (size == 0) { - LOGGER__ERROR("Invalid size to read"); - return HAILO_INVALID_ARGUMENT; - } - - if (buf == nullptr) { - LOGGER__ERROR("Read buffer pointer is NULL"); - return HAILO_INVALID_ARGUMENT; - } - - hailo_bar_transfer_params transfer = { + hailo_memory_transfer_params transfer = { .transfer_direction = TRANSFER_WRITE, - .bar_index = static_cast(bar), - .offset = offset, + .memory_type = translate_memory_type(memory_type), + .address = address, .count = size, .buffer = {0} }; + if (m_dma_type == DmaType::PCIE) { + CHECK(address < std::numeric_limits::max(), HAILO_INVALID_ARGUMENT, "Address out of range {}", address); + } + if (size > sizeof(transfer.buffer)) { LOGGER__ERROR("Invalid size to read, size given {} is larger than max size {}", size, sizeof(transfer.buffer)); return HAILO_INVALID_ARGUMENT; @@ -368,9 +425,9 @@ hailo_status HailoRTDriver::write_bar(PciBar bar, off_t offset, size_t size, con memcpy(transfer.buffer, buf, transfer.count); int err = 0; - auto status = hailo_ioctl(this->m_fd, HAILO_BAR_TRANSFER, &transfer, err); + auto status = hailo_ioctl(this->m_fd, HAILO_MEMORY_TRANSFER, &transfer, err); if (HAILO_SUCCESS != status) { - LOGGER__ERROR("HailoRTDriver::write_bar failed with errno:{}", err); + LOGGER__ERROR("HailoRTDriver::write_memory failed with errno:{}", err); return HAILO_PCIE_DRIVER_FAIL; } @@ -409,7 +466,7 @@ hailo_status HailoRTDriver::vdma_buffer_sync(VdmaBufferHandle handle, DmaDirecti Expected HailoRTDriver::vdma_channel_enable(vdma::ChannelId channel_id, - DmaDirection data_direction, uintptr_t desc_list_handle, bool enable_timestamps_measure) + DmaDirection data_direction, bool enable_timestamps_measure) { CHECK_AS_EXPECTED(is_valid_channel_id(channel_id), HAILO_INVALID_ARGUMENT, "Invalid channel id {} given", channel_id); CHECK_AS_EXPECTED(data_direction != DmaDirection::BOTH, HAILO_INVALID_ARGUMENT, "Invalid direction given"); @@ -417,7 +474,6 @@ Expected HailoRTDriver::vdma_channel_enable(vd .engine_index = channel_id.engine_index, .channel_index = channel_id.channel_index, .direction = direction_to_dma_data_direction(data_direction), - .desc_list_handle = desc_list_handle, .enable_timestamps_measure = enable_timestamps_measure, .channel_handle = INVALID_CHANNEL_HANDLE_VALUE, }; @@ -484,7 +540,7 @@ Expected HailoRTDriver::wait_channel_interrupts(v LOGGER__ERROR("Waiting for interrupt for channel {} timed-out (errno=ETIMEDOUT)", channel_id); return make_unexpected(status); } - if (HAILO_STREAM_INTERNAL_ABORT == status) { + if (HAILO_STREAM_ABORTED_BY_USER == status) { LOGGER__INFO("Channel (index={}) was aborted!", channel_id); return make_unexpected(status); } @@ -508,7 +564,7 @@ hailo_status HailoRTDriver::fw_control(const void *request, size_t request_len, CHECK_ARG_NOT_NULL(response_len); CHECK(timeout.count() >= 0, HAILO_INVALID_ARGUMENT); - hailo_fw_control command; + hailo_fw_control command{}; static_assert(PCIE_EXPECTED_MD5_LENGTH == sizeof(command.expected_md5), "mismatch md5 size"); memcpy(&command.expected_md5, request_md5, sizeof(command.expected_md5)); command.buffer_len = static_cast(request_len); @@ -658,13 +714,14 @@ hailo_status HailoRTDriver::descriptors_list_release(uintptr_t desc_handle) } hailo_status HailoRTDriver::descriptors_list_bind_vdma_buffer(uintptr_t desc_handle, VdmaBufferHandle buffer_handle, - uint16_t desc_page_size, uint8_t channel_index) + uint16_t desc_page_size, uint8_t channel_index, size_t offset) { hailo_desc_list_bind_vdma_buffer_params config_info; config_info.buffer_handle = buffer_handle; config_info.desc_handle = desc_handle; config_info.desc_page_size = desc_page_size; config_info.channel_index = channel_index; + config_info.offset = offset; int err = 0; auto status = hailo_ioctl(this->m_fd, HAILO_DESC_LIST_BIND_VDMA_BUFFER, &config_info, err); diff --git a/hailort/libhailort/src/os/posix/qnx/pcie_driver_scan.cpp b/hailort/libhailort/src/os/posix/qnx/driver_scan.cpp similarity index 75% rename from hailort/libhailort/src/os/posix/qnx/pcie_driver_scan.cpp rename to hailort/libhailort/src/os/posix/qnx/driver_scan.cpp index 05b5de3..bc7f731 100644 --- a/hailort/libhailort/src/os/posix/qnx/pcie_driver_scan.cpp +++ b/hailort/libhailort/src/os/posix/qnx/driver_scan.cpp @@ -3,11 +3,11 @@ * Distributed under the MIT license (https://opensource.org/licenses/MIT) **/ /** - * @file pcie_driver_scan.cpp + * @file driver_scan.cpp * @brief Get list and parse pcie driver info **/ -#include "os/posix/pcie_driver_scan.hpp" +#include "os/driver_scan.hpp" #include extern "C" { #include @@ -21,7 +21,7 @@ namespace hailort // Every device name will start with "hailo" #define HAILO_PCIE_DEVICE_NAME_PREFIX ("hailo") -Expected> list_pcie_devices() +Expected> list_devices() { DIR *dir_iter = opendir(HAILO_PCIE_CLASS_PATH); if (!dir_iter) { @@ -57,7 +57,6 @@ Expected> list_pcie_devices() Expected query_device_info(const std::string &device_name, uint32_t index) { HailoRTDriver::DeviceInfo dev_info = {}; - pci_err_t err; // pci_device_find finds all relevant devices - find specific using index pci_bdf_t pci_dev = pci_device_find(index, HAILO_VENDOR_ID, PCI_DID_ANY, PCI_CCODE_ANY); @@ -66,19 +65,8 @@ Expected query_device_info(const std::string &device_ make_unexpected(HAILO_INVALID_ARGUMENT); } - pci_did_t device_id; - if (PCI_ERR_OK != (err = pci_device_read_did(pci_dev, &device_id))) { - LOGGER__ERROR("Failed reading Device ID, error {}", err); - make_unexpected(HAILO_INTERNAL_FAILURE); - } - - dev_info.dev_path = std::move(std::string(HAILO_PCIE_CLASS_PATH) + device_name); - dev_info.vendor_id = HAILO_VENDOR_ID; - dev_info.device_id = device_id; - dev_info.domain = 0; - dev_info.bus = PCI_BUS(pci_dev); - dev_info.device = PCI_DEV(pci_dev); - dev_info.func = PCI_FUNC(pci_dev); + dev_info.dev_path = std::string(HAILO_PCIE_CLASS_PATH) + device_name; + dev_info.device_id = fmt::format("{:04X}:{:02X}:{:02X}.{}", 0, PCI_BUS(pci_dev), PCI_DEV(pci_dev), PCI_FUNC(pci_dev)); return dev_info; } diff --git a/hailort/libhailort/src/os/posix/unix/driver_scan.cpp b/hailort/libhailort/src/os/posix/unix/driver_scan.cpp new file mode 100644 index 0000000..a91fc08 --- /dev/null +++ b/hailort/libhailort/src/os/posix/unix/driver_scan.cpp @@ -0,0 +1,69 @@ +/** + * Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved. + * Distributed under the MIT license (https://opensource.org/licenses/MIT) + **/ +/** + * @file driver_scan.cpp + * @brief Parse pcie driver sysfs + **/ + +#include "os/driver_scan.hpp" +#include +#include +#include + +namespace hailort +{ + +#define HAILO_CLASS_PATH ("/sys/class/hailo_chardev") +#define HAILO_BOARD_LOCATION_FILENAME ("board_location") + + +Expected> list_devices() +{ + DIR *dir_iter = opendir(HAILO_CLASS_PATH); + if (!dir_iter) { + if (ENOENT == errno) { + LOGGER__ERROR("Can't find hailo pcie class, this may happen if the driver is not installed (this may happen" + " if the kernel was updated), or if there is no connected Hailo board"); + return make_unexpected(HAILO_PCIE_DRIVER_NOT_INSTALLED); + } + else { + LOGGER__ERROR("Failed to open hailo pcie class ({}), errno {}", HAILO_CLASS_PATH, errno); + return make_unexpected(HAILO_PCIE_DRIVER_FAIL); + } + } + + std::vector devices; + struct dirent *dir = nullptr; + while ((dir = readdir(dir_iter)) != nullptr) { + std::string device_name(dir->d_name); + if (device_name == "." || device_name == "..") { + continue; + } + devices.push_back(device_name); + } + + closedir(dir_iter); + return devices; +} + +Expected query_device_info(const std::string &device_name) +{ + const std::string device_id_path = std::string(HAILO_CLASS_PATH) + "/" + + device_name + "/" + HAILO_BOARD_LOCATION_FILENAME; + std::ifstream device_id_file(device_id_path); + CHECK_AS_EXPECTED(device_id_file.good(), HAILO_PCIE_DRIVER_FAIL, "Failed open {}", device_id_path); + + std::string device_id; + std::getline(device_id_file, device_id); + CHECK_AS_EXPECTED(device_id_file.eof(), HAILO_PCIE_DRIVER_FAIL, "Failed read {}", device_id_path); + + HailoRTDriver::DeviceInfo device_info = {}; + device_info.dev_path = std::string("/dev/") + device_name; + device_info.device_id = device_id; + + return device_info; +} + +} /* namespace hailort */ diff --git a/hailort/libhailort/src/os/posix/unix/pcie_driver_scan.cpp b/hailort/libhailort/src/os/posix/unix/pcie_driver_scan.cpp deleted file mode 100644 index 531778a..0000000 --- a/hailort/libhailort/src/os/posix/unix/pcie_driver_scan.cpp +++ /dev/null @@ -1,101 +0,0 @@ -/** - * Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved. - * Distributed under the MIT license (https://opensource.org/licenses/MIT) - **/ -/** - * @file pcie_driver_scan.cpp - * @brief Parse pcie driver sysfs - **/ - -#include "os/posix/pcie_driver_scan.hpp" -#include -#include - -namespace hailort -{ - -#define HAILO_PCIE_CLASS_PATH ("/sys/class/hailo_chardev") -#define HAILO_BOARD_LOCATION_FILENAME ("board_location") -#define HAILO_DEVICE_ID_FILENAME ("device_id") - - -Expected> list_pcie_devices() -{ - DIR *dir_iter = opendir(HAILO_PCIE_CLASS_PATH); - if (!dir_iter) { - if (ENOENT == errno) { - LOGGER__ERROR("Can't find hailo pcie class, this may happen if the driver is not installed (this may happen" - " if the kernel was updated), or if there is no connected Hailo board"); - return make_unexpected(HAILO_PCIE_DRIVER_NOT_INSTALLED); - } - else { - LOGGER__ERROR("Failed to open hailo pcie class ({}), errno {}", HAILO_PCIE_CLASS_PATH, errno); - return make_unexpected(HAILO_PCIE_DRIVER_FAIL); - } - } - - std::vector devices; - struct dirent *dir = nullptr; - while ((dir = readdir(dir_iter)) != nullptr) { - std::string device_name(dir->d_name); - if (device_name == "." || device_name == "..") { - continue; - } - devices.push_back(device_name); - } - - closedir(dir_iter); - return devices; -} - -/** - * Parses hailo driver sysfs entry using scanf format string - * @param device_name - name of the specific device (inside hailo class sysfs directory) - * @param sysfs_file_name - file name inside the device sysfs directory - * @param expected_count - expected amount of scanf variable - * @param fscanf_format - scanf format of the file - * @param ... - external arguments, filled by the scanf - */ -__attribute__((__format__ (__scanf__, 4, 5))) -static hailo_status parse_device_sysfs_file(const std::string &device_name, const std::string &sysfs_file_name, uint32_t expected_count, - const char *fscanf_format, ...) -{ - std::string sysfs_file_path = std::string(HAILO_PCIE_CLASS_PATH) + "/" + - device_name + "/" + sysfs_file_name; - FILE *file_obj = fopen(sysfs_file_path.c_str(), "r"); - if (!file_obj) { - LOGGER__ERROR("Failed opening sysfs file {}, errno {}", sysfs_file_path, errno); - return HAILO_FILE_OPERATION_FAILURE; - } - - va_list args; - va_start(args, fscanf_format); - auto items_count = vfscanf(file_obj, fscanf_format, args); - va_end(args); - fclose(file_obj); - - if (static_cast(items_count) != expected_count) { - LOGGER__ERROR("Invalid sysfs file format {}", sysfs_file_path); - return HAILO_PCIE_DRIVER_FAIL; - } - - return HAILO_SUCCESS; -} - -Expected query_device_info(const std::string &device_name) -{ - HailoRTDriver::DeviceInfo device_info = {}; - device_info.dev_path = std::string("/dev/") + device_name; - - auto status = parse_device_sysfs_file(device_name, HAILO_BOARD_LOCATION_FILENAME, 4, "%04x:%02x:%02x.%d", - &device_info.domain, &device_info.bus, &device_info.device, &device_info.func); - CHECK_SUCCESS_AS_EXPECTED(status, "Failed reading {} file", HAILO_BOARD_LOCATION_FILENAME); - - status = parse_device_sysfs_file(device_name, HAILO_DEVICE_ID_FILENAME, 2, "%x:%x", - &device_info.vendor_id, &device_info.device_id); - CHECK_SUCCESS_AS_EXPECTED(status, "Failed reading {} file", HAILO_DEVICE_ID_FILENAME); - - return device_info; -} - -} /* namespace hailort */ diff --git a/hailort/libhailort/src/os/windows/driver_scan.cpp b/hailort/libhailort/src/os/windows/driver_scan.cpp new file mode 100644 index 0000000..88d68ec --- /dev/null +++ b/hailort/libhailort/src/os/windows/driver_scan.cpp @@ -0,0 +1,208 @@ +/** + * Copyright (c) 2022 Hailo Technologies Ltd. All rights reserved. + * Distributed under the MIT license (https://opensource.org/licenses/MIT) + **/ +/** + * @file driver_scan.cpp + * @brief Get list and parse pcie driver info + */ + +#include "os/windows/osdep.hpp" +#include "common/logger_macros.hpp" +#include "common/utils.hpp" +#include "common/os/windows/string_conversion.hpp" +#include "os/driver_scan.hpp" +#include "../../../../drivers/win/include/Public.h" + +namespace hailort +{ + +class CDeviceProperty { +public: + CDeviceProperty() {} + ~CDeviceProperty() + { + Drop(); + } + bool IsValid() const + { + return m_Buffer != NULL; + } + void MoveTo(CDeviceProperty& other) + { + other.Drop(); + other.m_Size = m_Size; + other.m_Buffer = m_Buffer; + other.m_String = m_String; + other.m_Type = m_Type; + other.m_Value = m_Value; + m_Buffer = NULL; + } + bool Number(uint32_t& Value) const { + Value = m_Value; + return m_Type == DEVPROP_TYPE_UINT32 && IsValid(); + } +protected: + PBYTE m_Buffer = NULL; + ULONG m_Size = 0; + DEVPROPTYPE m_Type = DEVPROP_TYPE_EMPTY; + std::wstring m_String; + uint32_t m_Value = 0; +protected: + void Drop() + { + if (m_Buffer) free(m_Buffer); + m_Buffer = NULL; + m_Size = 0; + m_Type = DEVPROP_TYPE_EMPTY; + } + void PostProcess(CONFIGRET cr) + { + if (cr != CR_SUCCESS) { + Drop(); + } + if (m_Type == DEVPROP_TYPE_STRING) { + m_String = (wchar_t *)m_Buffer; + } + if (m_Type == DEVPROP_TYPE_UINT32) { + if (m_Size == sizeof(uint32_t)) { + m_Value = *(uint32_t *)m_Buffer; + } else { + Drop(); + } + } + } +}; + +class CDeviceInterfaceProperty : public CDeviceProperty +{ +public: + CDeviceInterfaceProperty(LPCWSTR DevInterface, const DEVPROPKEY* Key, bool AllowRecursion = true); +}; + +class CDevInstProperty : public CDeviceProperty +{ +public: + CDevInstProperty(LPCWSTR DevInst, const DEVPROPKEY* Key) + { + DEVINST dn; + CONFIGRET cr = CM_Locate_DevNodeW(&dn, (WCHAR *)DevInst, CM_LOCATE_DEVNODE_NORMAL); + if (cr != CR_SUCCESS) + return; + // try to get the size of the property + CM_Get_DevNode_PropertyW(dn, Key, &m_Type, NULL, &m_Size, 0); + if (!m_Size) + return; + m_Buffer = (PBYTE)malloc(m_Size); + if (!m_Buffer) { + return; + } + cr = CM_Get_DevNode_PropertyW(dn, Key, &m_Type, m_Buffer, &m_Size, 0); + PostProcess(cr); + } +}; + +class CDeviceInstancePropertyOfInterface : public CDeviceInterfaceProperty +{ +public: + CDeviceInstancePropertyOfInterface(LPCWSTR DevInterface) : + CDeviceInterfaceProperty(DevInterface, &DEVPKEY_Device_InstanceId, false) + { } + const std::wstring& DevInst() const { return m_String; } +}; + +CDeviceInterfaceProperty::CDeviceInterfaceProperty( + LPCWSTR DevInterface, + const DEVPROPKEY* Key, + bool AllowRecursion) +{ + // try to get the property via device interface + CM_Get_Device_Interface_PropertyW(DevInterface, Key, &m_Type, NULL, &m_Size, 0); + if (!m_Size) { + if (AllowRecursion) { + // try to get the property via device instance + CDeviceInstancePropertyOfInterface diProp(DevInterface); + if (diProp.IsValid()) { + const std::wstring& di = diProp.DevInst(); + CDevInstProperty dip(di.c_str(), Key); + if (dip.IsValid()) { + dip.MoveTo(*this); + } + } + } + return; + } + m_Buffer = (PBYTE)malloc(m_Size); + if (!m_Buffer) + return; + CONFIGRET cr = CM_Get_Device_Interface_PropertyW( + DevInterface, Key, &m_Type, m_Buffer, &m_Size, 0); + PostProcess(cr); +} + +Expected> list_devices() +{ + GUID guid = GUID_DEVINTERFACE_HailoKM; + + ULONG len = 0; + CONFIGRET cr = CM_Get_Device_Interface_List_SizeA( + &len, + &guid, + NULL, + CM_GET_DEVICE_INTERFACE_LIST_PRESENT); + CHECK_AS_EXPECTED(cr == CR_SUCCESS && len >= 2, HAILO_PCIE_DRIVER_NOT_INSTALLED, + "Driver interface not found error {}", cr); + + std::string names_str; + names_str.resize(len); + + cr = CM_Get_Device_Interface_ListA( + &guid, + NULL, + const_cast(names_str.c_str()), + len, + CM_GET_DEVICE_INTERFACE_LIST_PRESENT); + CHECK_AS_EXPECTED(cr == CR_SUCCESS, HAILO_PCIE_DRIVER_NOT_INSTALLED, "Can't retrieve driver interface error {}", cr); + + std::vector names; + for (const char *current_name = names_str.c_str(); *current_name; current_name += strlen(current_name) + 1) { + names.emplace_back(current_name); + } + + return names; +} + +static Expected parse_uint32_property(const std::wstring &dev_interface, + const DEVPROPKEY* key) +{ + CDeviceInterfaceProperty prop(dev_interface.c_str(), key); + uint32_t number = 0; + if (!prop.Number(number)) { + LOGGER__ERROR("Failed parsing prop"); + return make_unexpected(HAILO_PCIE_DRIVER_FAIL); + } + return number; +} + +#define DEVICE_ADDRESS_GET_FUNC(device_func) ((device_func) & 0xff) +#define DEVICE_ADDRESS_GET_DEV(device_func) ((device_func) >> 16) + +Expected query_device_info(const std::string &device_name) +{ + const auto device_name_wstring = StringConverter::ansi_to_utf16(device_name); + CHECK_EXPECTED(device_name_wstring); + + auto bus = parse_uint32_property(device_name_wstring.value(), &DEVPKEY_Device_BusNumber); + CHECK_EXPECTED(bus); + + auto device_func = parse_uint32_property(device_name_wstring.value(), &DEVPKEY_Device_Address); + CHECK_EXPECTED(device_func); + + HailoRTDriver::DeviceInfo device_info{}; + device_info.device_id = fmt::format("{:04X}:{:02X}:{:02X}.{}", 0, *bus, DEVICE_ADDRESS_GET_DEV(*device_func), + DEVICE_ADDRESS_GET_FUNC(*device_func)); + device_info.dev_path = device_name; + return device_info; +} + +} /* namespace hailort */ diff --git a/hailort/libhailort/src/os/windows/hailort_driver.cpp b/hailort/libhailort/src/os/windows/hailort_driver.cpp index bf29c92..c167918 100644 --- a/hailort/libhailort/src/os/windows/hailort_driver.cpp +++ b/hailort/libhailort/src/os/windows/hailort_driver.cpp @@ -9,6 +9,7 @@ #include "os/windows/osdep.hpp" #include "os/hailort_driver.hpp" +#include "os/driver_scan.hpp" #include "common/logger_macros.hpp" #include "common/utils.hpp" #include "common/os/windows/string_conversion.hpp" @@ -24,7 +25,7 @@ static_assert(VDMA_CHANNELS_PER_ENGINE == MAX_VDMA_CHANNELS_PER_ENGINE, "Driver static_assert(MIN_D2H_CHANNEL_INDEX == VDMA_DEST_CHANNELS_START, "Driver and libhailort parameters mismatch"); //TODO HRT-7309: merge with posix -constexpr hailo_dma_data_direction direction_to_dma_data_direction(HailoRTDriver::DmaDirection direction) { +static hailo_dma_data_direction direction_to_dma_data_direction(HailoRTDriver::DmaDirection direction) { switch (direction){ case HailoRTDriver::DmaDirection::H2D: return HAILO_DMA_TO_DEVICE; @@ -32,14 +33,14 @@ constexpr hailo_dma_data_direction direction_to_dma_data_direction(HailoRTDriver return HAILO_DMA_FROM_DEVICE; case HailoRTDriver::DmaDirection::BOTH: return HAILO_DMA_BIDIRECTIONAL; - default: - assert(true); - // On release build Return value that will make ioctls to fail. - return HAILO_DMA_NONE; } + + assert(false); + // On release build Return value that will make ioctls to fail. + return HAILO_DMA_NONE; } -constexpr enum hailo_cpu_id translate_cpu_id(hailo_cpu_id_t cpu_id) +static enum hailo_cpu_id translate_cpu_id(hailo_cpu_id_t cpu_id) { switch (cpu_id) { @@ -47,170 +48,44 @@ constexpr enum hailo_cpu_id translate_cpu_id(hailo_cpu_id_t cpu_id) return HAILO_CPU_ID_CPU0; case HAILO_CPU_ID_1: return HAILO_CPU_ID_CPU1; - default: - assert(true); - // On release build Return value that will make ioctls to fail. - return HAILO_CPU_ID_NONE; - } -} - -class CDeviceProperty -{ -public: - CDeviceProperty(LPCSTR FriendlyName) : m_FriendlyName(FriendlyName) {} - ~CDeviceProperty() - { - Drop(); - } - bool IsValid() const - { - return m_Buffer != NULL; - } - void MoveTo(CDeviceProperty& other) - { - other.Drop(); - other.m_Size = m_Size; - other.m_Buffer = m_Buffer; - other.m_String = m_String; - other.m_Type = m_Type; - other.m_Value = m_Value; - m_Buffer = NULL; - } - bool Number(uint32_t& Value) const { - Value = m_Value; - return m_Type == DEVPROP_TYPE_UINT32 && IsValid(); - } -protected: - PBYTE m_Buffer = NULL; - ULONG m_Size = 0; - DEVPROPTYPE m_Type = DEVPROP_TYPE_EMPTY; - std::wstring m_String; - LPCSTR m_FriendlyName; - uint32_t m_Value = 0; -protected: - void Drop() - { - if (m_Buffer) free(m_Buffer); - m_Buffer = NULL; - m_Size = 0; - m_Type = DEVPROP_TYPE_EMPTY; - } - void PostProcess(CONFIGRET cr) - { - if (cr != CR_SUCCESS) { - Drop(); - } - if (m_Type == DEVPROP_TYPE_STRING) { - m_String = (wchar_t *)m_Buffer; - } - if (m_Type == DEVPROP_TYPE_UINT32) { - if (m_Size == sizeof(uint32_t)) { - m_Value = *(uint32_t *)m_Buffer; - } else { - Drop(); - } - } - } -}; - -class CDeviceInterfaceProperty : public CDeviceProperty -{ -public: - CDeviceInterfaceProperty(LPCWSTR DevInterface, const DEVPROPKEY* Key, LPCSTR FriendlyName, bool AllowRecursion = true); -}; - -class CDevInstProperty : public CDeviceProperty -{ -public: - CDevInstProperty(LPCWSTR DevInst, const DEVPROPKEY* Key, LPCSTR FriendlyName) : - CDeviceProperty(FriendlyName) - { - DEVINST dn; - CONFIGRET cr = CM_Locate_DevNodeW(&dn, (WCHAR *)DevInst, CM_LOCATE_DEVNODE_NORMAL); - if (cr != CR_SUCCESS) - return; - // try to get the size of the property - CM_Get_DevNode_PropertyW(dn, Key, &m_Type, NULL, &m_Size, 0); - if (!m_Size) - return; - m_Buffer = (PBYTE)malloc(m_Size); - if (!m_Buffer) { - return; - } - cr = CM_Get_DevNode_PropertyW(dn, Key, &m_Type, m_Buffer, &m_Size, 0); - PostProcess(cr); + case HAILO_CPU_ID_MAX_ENUM: + // Add label for HAILO_CPU_ID_MAX_ENUM to cover all enum cases (avoid warnings). Continue to the assert. + break; } -}; - -class CDeviceInstancePropertyOfInterface : public CDeviceInterfaceProperty -{ -public: - CDeviceInstancePropertyOfInterface(LPCWSTR DevInterface) : - CDeviceInterfaceProperty(DevInterface, &DEVPKEY_Device_InstanceId, "DevInstance", false) - { } - const std::wstring& DevInst() const { return m_String; } -}; - -bool IsSame(const HailoRTDriver::DeviceInfo& a, const HailoRTDriver::DeviceInfo& b) -{ - return a.bus == b.bus && a.device == b.device && a.func == b.func; -} -bool IsAny(const HailoRTDriver::DeviceInfo& a) -{ - return a.bus == MAXUINT; + assert(false); + // On release build Return value that will make ioctls to fail. + return HAILO_CPU_ID_NONE; } -class CDevicePCILocation +static hailo_transfer_memory_type translate_memory_type(HailoRTDriver::MemoryType memory_type) { -public: - CDevicePCILocation(LPCWSTR DevInterface) - { - CDeviceInterfaceProperty BusNumber(DevInterface, &DEVPKEY_Device_BusNumber, "BusNumber"); - CDeviceInterfaceProperty Address(DevInterface, &DEVPKEY_Device_Address, "Address"); - m_Valid = BusNumber.Number(m_Location.bus) && Address.Number(m_Location.device); - if (m_Valid) { - m_Location.func = m_Location.device & 0xff; - m_Location.device = m_Location.device >> 16; - } - std::wstring devInterface = DevInterface; - m_Location.dev_path = StringConverter::utf16_to_ansi(devInterface).value(); + using MemoryType = HailoRTDriver::MemoryType; + switch (memory_type) { + case MemoryType::DIRECT_MEMORY: + return HAILO_TRANSFER_DEVICE_DIRECT_MEMORY; + case MemoryType::VDMA0: + return HAILO_TRANSFER_MEMORY_VDMA0; + case MemoryType::VDMA1: + return HAILO_TRANSFER_MEMORY_VDMA1; + case MemoryType::VDMA2: + return HAILO_TRANSFER_MEMORY_VDMA2; + case MemoryType::PCIE_BAR0: + return HAILO_TRANSFER_MEMORY_PCIE_BAR0; + case MemoryType::PCIE_BAR2: + return HAILO_TRANSFER_MEMORY_PCIE_BAR2; + case MemoryType::PCIE_BAR4: + return HAILO_TRANSFER_MEMORY_PCIE_BAR4; + case MemoryType::DMA_ENGINE0: + return HAILO_TRANSFER_MEMORY_DMA_ENGINE0; + case MemoryType::DMA_ENGINE1: + return HAILO_TRANSFER_MEMORY_DMA_ENGINE1; + case MemoryType::DMA_ENGINE2: + return HAILO_TRANSFER_MEMORY_DMA_ENGINE2; } - const HailoRTDriver::DeviceInfo& Location() const { return m_Location; } - bool IsValid() const { return m_Valid; } -private: - HailoRTDriver::DeviceInfo m_Location = {}; - bool m_Valid = false; -}; -CDeviceInterfaceProperty::CDeviceInterfaceProperty( - LPCWSTR DevInterface, - const DEVPROPKEY* Key, - LPCSTR FriendlyName, - bool AllowRecursion) : CDeviceProperty(FriendlyName) -{ - // try to get the property via device interface - CM_Get_Device_Interface_PropertyW(DevInterface, Key, &m_Type, NULL, &m_Size, 0); - if (!m_Size) { - if (AllowRecursion) { - // try to get the property via device instance - CDeviceInstancePropertyOfInterface diProp(DevInterface); - if (diProp.IsValid()) { - const std::wstring& di = diProp.DevInst(); - CDevInstProperty dip(di.c_str(), Key, FriendlyName); - if (dip.IsValid()) { - dip.MoveTo(*this); - } - } - } - return; - } - m_Buffer = (PBYTE)malloc(m_Size); - if (!m_Buffer) - return; - CONFIGRET cr = CM_Get_Device_Interface_PropertyW( - DevInterface, Key, &m_Type, m_Buffer, &m_Size, 0); - PostProcess(cr); + assert(false); + return HAILO_TRANSFER_MEMORY_MAX_ENUM; } class CWaitable @@ -274,20 +149,10 @@ using CMutexSync = CSync; class CDeviceFile { public: - CDeviceFile(std::vector& Instances) - { - EnumerateInstances(Instances); - } + CDeviceFile(const std::string& path) { - std::vector found; - EnumerateInstances(found); - for (size_t i = 0; i < found.size(); ++i) { - if (path == found[i].dev_path) { - Create(path.c_str(), true); - break; - } - } + Create(path.c_str(), true); } void Close() { @@ -313,55 +178,6 @@ public: return h; } protected: - void EnumerateInstances(std::vector& Instances) - { - CONFIGRET cr; - WCHAR* names = NULL, * currentName; - ULONG len = 0; - do { - cr = CM_Get_Device_Interface_List_SizeW( - &len, - &m_InterfaceGuid, - NULL, - CM_GET_DEVICE_INTERFACE_LIST_PRESENT); - - if (cr != CR_SUCCESS || len < 2) { - LOGGER__ERROR("Driver interface not found, error {}", cr); - break; - } - if (len <= 1) { - LOGGER__ERROR("Driver interface not found"); - break; - } - names = (WCHAR*)malloc(len * sizeof(WCHAR)); - if (!names) { - LOGGER__ERROR("Can't allocate buffer of {} chars", len); - cr = CR_OUT_OF_MEMORY; - break; - } - cr = CM_Get_Device_Interface_ListW( - &m_InterfaceGuid, - NULL, - names, - len, - CM_GET_DEVICE_INTERFACE_LIST_PRESENT); - if (cr != CR_SUCCESS) { - LOGGER__ERROR("Can't retrieve driver interface, error {}", cr); - break; - } - for (currentName = names; names && *currentName; currentName += wcslen(currentName) + 1) { - CDevicePCILocation locationData(currentName); - if (!locationData.IsValid()) - continue; - Instances.push_back(locationData.Location()); - } - } while (false); - - if (names) - { - free(names); - } - } bool Notify() { if (m_Handle) { @@ -429,7 +245,6 @@ protected: } } private: - GUID m_InterfaceGuid = GUID_DEVINTERFACE_HailoKM; std::string m_InterfaceName; HCMNOTIFICATION m_Notification = NULL; CMutex m_Mutex; @@ -504,18 +319,6 @@ HailoRTDriver::HailoRTDriver(const std::string &dev_path, FileDescriptor &&fd, h m_desc_max_page_size = device_properties.desc_max_page_size; m_dma_engines_count = device_properties.dma_engines_count; - switch (device_properties.board_type) { - case HAILO8: - m_board_type = BoardType::HAILO8; - break; - case HAILO_MERCURY: - m_board_type = BoardType::MERCURY; - break; - default: - LOGGER__ERROR("Invalid board type {} returned from ioctl", device_properties.board_type); - status = HAILO_PCIE_DRIVER_FAIL; - return; - } switch (device_properties.dma_type) { case HAILO_DMA_TYPE_PCIE: @@ -530,18 +333,22 @@ HailoRTDriver::HailoRTDriver(const std::string &dev_path, FileDescriptor &&fd, h return; } + m_is_fw_loaded = device_properties.is_fw_loaded; status = HAILO_SUCCESS; } -Expected> HailoRTDriver::scan_pci() +Expected> HailoRTDriver::scan_devices() { - std::vector all; - CDeviceFile f(all); - for (size_t i = 0; i < all.size(); ++i) { - const HailoRTDriver::DeviceInfo& di = all[i]; - LOGGER__INFO("Found {}:{}:{} {}", di.bus, di.device, di.func, di.dev_path); + auto device_names = list_devices(); + CHECK_EXPECTED(device_names, "Failed listing pcie devices"); + + std::vector devices_info; + for (const auto &device_name : device_names.value()) { + auto device_info = query_device_info(device_name); + CHECK_EXPECTED(device_info, "failed parsing device info for {}", device_name); + devices_info.push_back(device_info.release()); } - return std::move(all); + return devices_info; } Expected HailoRTDriver::create(const std::string &dev_path) @@ -561,10 +368,9 @@ Expected HailoRTDriver::create(const std::string &dev_path) return platform; } -Expected HailoRTDriver::read_notification() +Expected> HailoRTDriver::read_notification() { tCompatibleHailoIoctlData data; - D2H_EVENT_MESSAGE_t notification; hailo_d2h_notification& notification_buffer = data.Buffer.D2HNotification; auto rc = ioctl(this->m_fd, HAILO_READ_NOTIFICATION, &data); @@ -572,11 +378,9 @@ Expected HailoRTDriver::read_notification() return make_unexpected(HAILO_PCIE_DRIVER_FAIL); } - CHECK_AS_EXPECTED(sizeof(notification) >= notification_buffer.buffer_len, HAILO_GET_D2H_EVENT_MESSAGE_FAIL, - "buffer len is not valid = {}", notification_buffer.buffer_len); - - memcpy(¬ification, notification_buffer.buffer, notification_buffer.buffer_len); - return std::move(notification); + std::vector notification(notification_buffer.buffer_len); + memcpy(notification.data(), notification_buffer.buffer, notification_buffer.buffer_len); + return notification; } hailo_status HailoRTDriver::disable_notifications() @@ -588,8 +392,57 @@ hailo_status HailoRTDriver::disable_notifications() return HAILO_SUCCESS; } +hailo_status HailoRTDriver::read_memory(MemoryType memory_type, uint64_t address, void *buf, size_t size) +{ + if (size == 0) { + LOGGER__ERROR("Invalid size to read"); + return HAILO_INVALID_ARGUMENT; + } + + if (buf == nullptr) { + LOGGER__ERROR("Read buffer pointer is NULL"); + return HAILO_INVALID_ARGUMENT; + } + + constexpr uint32_t CHUNK_SIZE = ARRAY_ENTRIES(hailo_memory_transfer_params::buffer); + uint32_t offset = 0; + + while (offset < size) { + const uint32_t actual_size = std::min(CHUNK_SIZE, static_cast(size) - offset); + auto status = read_memory_ioctl(memory_type, address + offset, + reinterpret_cast(buf) + offset, actual_size); + CHECK_SUCCESS(status); + offset += actual_size; + } + return HAILO_SUCCESS; +} + +hailo_status HailoRTDriver::write_memory(MemoryType memory_type, uint64_t address, const void *buf, size_t size) +{ + if (size == 0) { + LOGGER__ERROR("Invalid size to read"); + return HAILO_INVALID_ARGUMENT; + } + + if (buf == nullptr) { + LOGGER__ERROR("Read buffer pointer is NULL"); + return HAILO_INVALID_ARGUMENT; + } + + constexpr uint32_t CHUNK_SIZE = ARRAY_ENTRIES(hailo_memory_transfer_params::buffer); + uint32_t offset = 0; + + while (offset < size) { + const uint32_t actual_size = std::min(CHUNK_SIZE, static_cast(size) - offset); + auto status = write_memory_ioctl(memory_type, address + offset, + reinterpret_cast(buf) + offset, actual_size); + CHECK_SUCCESS(status); + offset += actual_size; + } + return HAILO_SUCCESS; +} -hailo_status HailoRTDriver::read_bar(PciBar bar, off_t offset, size_t size, void *buf) +hailo_status HailoRTDriver::read_memory_ioctl(MemoryType memory_type, uint64_t address, void *buf, size_t size) { if (size == 0) { LOGGER__ERROR("Invalid size to read"); @@ -601,19 +454,23 @@ hailo_status HailoRTDriver::read_bar(PciBar bar, off_t offset, size_t size, void return HAILO_INVALID_ARGUMENT; } + if (m_dma_type == DmaType::PCIE) { + CHECK(address < std::numeric_limits::max(), HAILO_INVALID_ARGUMENT, "Address out of range {}", address); + } + tCompatibleHailoIoctlData data = {}; - hailo_bar_transfer_params& transfer = data.Buffer.BarTransfer; + hailo_memory_transfer_params& transfer = data.Buffer.MemoryTransfer; transfer.transfer_direction = TRANSFER_READ; - transfer.bar_index = static_cast(bar); - transfer.offset = offset; + transfer.memory_type = translate_memory_type(memory_type); + transfer.address = address; transfer.count = size; memset(transfer.buffer, 0, sizeof(transfer.buffer)); CHECK(size <= sizeof(transfer.buffer), HAILO_INVALID_ARGUMENT, "Invalid size to read, size given {} is larger than max size {}", size, sizeof(transfer.buffer)); - if (0 > ioctl(m_fd, HAILO_BAR_TRANSFER, &data)) { - LOGGER__ERROR("HailoRTDriver::read_bar failed with errno:{}", errno); + if (0 > ioctl(m_fd, HAILO_MEMORY_TRANSFER, &data)) { + LOGGER__ERROR("HailoRTDriver::read_memory failed with errno:{}", errno); return HAILO_PCIE_DRIVER_FAIL; } @@ -622,7 +479,7 @@ hailo_status HailoRTDriver::read_bar(PciBar bar, off_t offset, size_t size, void return HAILO_SUCCESS; } -hailo_status HailoRTDriver::write_bar(PciBar bar, off_t offset, size_t size, const void *buf) +hailo_status HailoRTDriver::write_memory_ioctl(MemoryType memory_type, uint64_t address, const void *buf, size_t size) { if (size == 0) { LOGGER__ERROR("Invalid size to write"); @@ -634,11 +491,15 @@ hailo_status HailoRTDriver::write_bar(PciBar bar, off_t offset, size_t size, con return HAILO_INVALID_ARGUMENT; } + if (m_dma_type == DmaType::PCIE) { + CHECK(address < std::numeric_limits::max(), HAILO_INVALID_ARGUMENT, "Address out of range {}", address); + } + tCompatibleHailoIoctlData data = {}; - hailo_bar_transfer_params& transfer = data.Buffer.BarTransfer; + hailo_memory_transfer_params& transfer = data.Buffer.MemoryTransfer; transfer.transfer_direction = TRANSFER_WRITE; - transfer.bar_index = static_cast(bar); - transfer.offset = offset; + transfer.memory_type = translate_memory_type(memory_type); + transfer.address = address; transfer.count = size; memset(transfer.buffer, 0, sizeof(transfer.buffer)); @@ -647,8 +508,8 @@ hailo_status HailoRTDriver::write_bar(PciBar bar, off_t offset, size_t size, con memcpy(transfer.buffer, buf, transfer.count); - if (0 > ioctl(this->m_fd, HAILO_BAR_TRANSFER, &data)) { - LOGGER__ERROR("HailoRTDriver::write_bar failed with errno: {}", errno); + if (0 > ioctl(this->m_fd, HAILO_MEMORY_TRANSFER, &data)) { + LOGGER__ERROR("HailoRTDriver::write_memory failed with errno: {}", errno); return HAILO_PCIE_DRIVER_FAIL; } @@ -719,7 +580,7 @@ hailo_status HailoRTDriver::vdma_buffer_sync(VdmaBufferHandle handle, DmaDirecti } Expected HailoRTDriver::vdma_channel_enable(vdma::ChannelId channel_id, - DmaDirection data_direction, uintptr_t desc_list_handle, bool enable_timestamps_measure) + DmaDirection data_direction, bool enable_timestamps_measure) { CHECK_AS_EXPECTED(is_valid_channel_id(channel_id), HAILO_INVALID_ARGUMENT, "Invalid channel id {} given", channel_id); CHECK_AS_EXPECTED(data_direction != DmaDirection::BOTH, HAILO_INVALID_ARGUMENT, "Invalid direction given"); @@ -728,7 +589,6 @@ Expected HailoRTDriver::vdma_channel_enable(vd params.engine_index = channel_id.engine_index; params.channel_index = channel_id.channel_index; params.direction = direction_to_dma_data_direction(data_direction); - params.desc_list_handle = desc_list_handle, params.enable_timestamps_measure = enable_timestamps_measure; if (0 > ioctl(this->m_fd, HAILO_VDMA_CHANNEL_ENABLE, &data)) { @@ -792,7 +652,7 @@ Expected HailoRTDriver::wait_channel_interrupts(v } if (ERROR_OPERATION_ABORTED == ioctl_errno) { LOGGER__INFO("Stream (index={}) was aborted!", channel_id); - return make_unexpected(HAILO_STREAM_INTERNAL_ABORT); + return make_unexpected(HAILO_STREAM_ABORTED_BY_USER); } if (ERROR_NOT_READY == ioctl_errno) { LOGGER__INFO("Channel (index={}) was deactivated!", channel_id); @@ -913,7 +773,7 @@ hailo_status HailoRTDriver::descriptors_list_release(uintptr_t desc_handle) } hailo_status HailoRTDriver::descriptors_list_bind_vdma_buffer(uintptr_t desc_handle, VdmaBufferHandle buffer_handle, - uint16_t desc_page_size, uint8_t channel_index) + uint16_t desc_page_size, uint8_t channel_index, size_t offset) { tCompatibleHailoIoctlData data = {}; hailo_desc_list_bind_vdma_buffer_params& config_info = data.Buffer.DescListBind; @@ -921,6 +781,7 @@ hailo_status HailoRTDriver::descriptors_list_bind_vdma_buffer(uintptr_t desc_han config_info.desc_handle = desc_handle; config_info.desc_page_size = desc_page_size; config_info.channel_index = channel_index; + config_info.offset = offset; if (0 > ioctl(this->m_fd, HAILO_DESC_LIST_BIND_VDMA_BUFFER, &data)) { LOGGER__ERROR("Failed to bind vdma buffer to descriptors list with errno: {}", errno); @@ -964,11 +825,27 @@ hailo_status HailoRTDriver::vdma_channel_clear_abort(vdma::ChannelId channel_id, hailo_status HailoRTDriver::read_log(uint8_t *buffer, size_t buffer_size, size_t *read_bytes, hailo_cpu_id_t cpu_id) { - (void)buffer; - (void)buffer_size; - (void)read_bytes; - (void)cpu_id; - return HAILO_PCIE_NOT_SUPPORTED_ON_PLATFORM; + tCompatibleHailoIoctlData data = {}; + hailo_read_log_params& params = data.Buffer.ReadLog; + params.buffer_size = __min(buffer_size, sizeof(params.buffer)); + params.cpu_id = translate_cpu_id(cpu_id); + + CHECK_ARG_NOT_NULL(buffer); + CHECK_ARG_NOT_NULL(read_bytes); + + if (0 > ioctl(this->m_fd, HAILO_READ_LOG, &data)) { + LOGGER__ERROR("Failed to read log with errno:{}", errno); + return HAILO_PCIE_DRIVER_FAIL; + } + + CHECK(params.read_bytes <= sizeof(params.buffer), HAILO_PCIE_DRIVER_FAIL, + "Amount of bytes read from log {} is bigger than size of buffer {}", + params.read_bytes, sizeof(params.buffer)); + + memcpy(buffer, params.buffer, params.read_bytes); + *read_bytes = params.read_bytes; + + return HAILO_SUCCESS; } hailo_status HailoRTDriver::reset_nn_core() diff --git a/hailort/libhailort/src/pcie_device.cpp b/hailort/libhailort/src/pcie_device.cpp index 51482d3..44ca5b2 100644 --- a/hailort/libhailort/src/pcie_device.cpp +++ b/hailort/libhailort/src/pcie_device.cpp @@ -15,7 +15,6 @@ #include "hailo/device.hpp" #include "hailo/hef.hpp" #include "control.hpp" -#include "hlpcie.hpp" #include "common/compiler_extensions_compat.hpp" #include "os/hailort_driver.hpp" #include "context_switch/multi_context/resource_manager.hpp" @@ -27,35 +26,21 @@ namespace hailort { -#define ISTATUS_HOST_FW_IRQ_EVENT 0x2000000 /* IN BCS_ISTATUS_HOST_FW_IRQ_MASK IN ISTATUS_HOST */ -#define ISTATUS_HOST_FW_IRQ_CONTROL 0x4000000 /* IN BCS_ISTATUS_HOST_FW_IRQ_MASK IN ISTATUS_HOST */ -#define ISTATUS_HOST_FW_IRQ_FW_LOAD 0x6000000 /* IN BCS_ISTATUS_HOST_FW_IRQ_MASK IN ISTATUS_HOST */ - - -#ifndef HAILO_EMULATOR -static const uint32_t PCIE_DEFAULT_TIMEOUT_MS = 1000; -#else /* ifndef HAILO_EMULATOR */ -static const uint32_t PCIE_DEFAULT_TIMEOUT_MS = 50000; -#endif /* ifndef HAILO_EMULATOR */ - - Expected> PcieDevice::scan() { - auto scan_results = HailoRTDriver::scan_pci(); - if (!scan_results) { - LOGGER__ERROR("scan pci failed"); - return make_unexpected(scan_results.status()); + auto scan_results = HailoRTDriver::scan_devices(); + CHECK_EXPECTED(scan_results); + + std::vector out_results; + out_results.reserve(scan_results->size()); + for (const auto &scan_result : scan_results.value()) { + const bool DONT_LOG_ON_FAILURE = true; + auto device_info = parse_pcie_device_info(scan_result.device_id, DONT_LOG_ON_FAILURE); + if (device_info) { + out_results.emplace_back(device_info.release()); + } } - std::vector out_results(scan_results->size()); - std::transform(scan_results->begin(), scan_results->end(), std::begin(out_results), [](const auto &scan_result) { - hailo_pcie_device_info_t device_info = {}; - device_info.domain = scan_result.domain; - device_info.bus = scan_result.bus; - device_info.device = scan_result.device; - device_info.func = scan_result.func; - return device_info; - }); return out_results; } @@ -69,43 +54,22 @@ Expected> PcieDevice::create() return create(scan_result->at(0)); } -Expected> PcieDevice::create(const hailo_pcie_device_info_t &device_info) +Expected> PcieDevice::create(const hailo_pcie_device_info_t &pcie_device_info) { - auto scan_results = HailoRTDriver::scan_pci(); - if (!scan_results) { - LOGGER__ERROR("scan pci failed"); - return make_unexpected(scan_results.status()); - } + auto device_info = find_device_info(pcie_device_info); + CHECK_EXPECTED(device_info); - // Find device index based on the information from "device_info" - auto device_found = std::find_if(scan_results->cbegin(), scan_results->cend(), - [device_info](const auto &compared_board) { - return (device_info.bus == compared_board.bus) && - (device_info.device == compared_board.device) && - (device_info.func == compared_board.func) && - ((HAILO_PCIE_ANY_DOMAIN == device_info.domain) || (device_info.domain == compared_board.domain)); - }); - - if (device_found == std::end(scan_results.value())) { - LOGGER__ERROR("Requested device not found"); - return make_unexpected(HAILO_INVALID_ARGUMENT); - } + auto pcie_device_info_str = pcie_device_info_to_string(pcie_device_info); + CHECK_EXPECTED(pcie_device_info_str); - auto driver = HailoRTDriver::create(device_found->dev_path); - if (!driver) { - LOGGER__ERROR("Failed to initialize HailoRTDriver"); - return make_unexpected(driver.status()); - } + auto driver = HailoRTDriver::create(device_info->dev_path); + CHECK_EXPECTED(driver); hailo_status status = HAILO_UNINITIALIZED; - auto device = std::unique_ptr(new (std::nothrow) PcieDevice(driver.release(), device_info, status)); + auto device = std::unique_ptr(new (std::nothrow) PcieDevice(driver.release(), pcie_device_info, status, + pcie_device_info_str.release())); CHECK_AS_EXPECTED((nullptr != device), HAILO_OUT_OF_HOST_MEMORY); - - if (HAILO_SUCCESS != status) { - LOGGER__ERROR("Failed creating PcieDevice"); - return make_unexpected(status); - } - + CHECK_SUCCESS_AS_EXPECTED(status, "Failed creating PcieDevice"); return device; } @@ -163,22 +127,12 @@ Expected PcieDevice::pcie_device_info_to_string(const hailo_pcie_de return std::string(device_string); } -PcieDevice::PcieDevice(HailoRTDriver &&driver, const hailo_pcie_device_info_t &device_info, hailo_status &status) : - VdmaDevice::VdmaDevice(std::move(driver), Device::Type::PCIE), - m_fw_up(false), - m_device_info(device_info), - m_context_switch_manager(nullptr) +PcieDevice::PcieDevice(HailoRTDriver &&driver, const hailo_pcie_device_info_t &device_info, hailo_status &status, + const std::string &device_id) : + VdmaDevice::VdmaDevice(std::move(driver), Device::Type::PCIE, device_id), + m_device_info(device_info) { - // Send identify if FW is loaded - status = HAILO_PCIE__read_atr_to_validate_fw_is_up(m_driver, &m_fw_up); - if (HAILO_SUCCESS != status) { - LOGGER__ERROR("HAILO_PCIE__read_atr_to_validate_fw_is_up failed with status {}", status); - return; - } - - // Note: m_fw_up needs to be called after each reset/fw_update if we want the device's - // state to remain valid after these ops (see HRT-3116) - if (m_fw_up) { + if (driver.is_fw_loaded()) { status = update_fw_state(); if (HAILO_SUCCESS != status) { LOGGER__ERROR("update_fw_state() failed with status {}", status); @@ -189,35 +143,11 @@ PcieDevice::PcieDevice(HailoRTDriver &&driver, const hailo_pcie_device_info_t &d m_is_control_version_supported = false; } - auto message = pcie_device_info_to_string(device_info); - if (HAILO_SUCCESS != message.status()) { - status = message.status(); - LOGGER__ERROR("pcie_device_info_to_string() failed with status {}", status); - return; - } - m_device_id = message.release(); - - this->activate_notifications(m_device_id); + m_device_id = device_id; status = HAILO_SUCCESS; } -PcieDevice::~PcieDevice() -{ - auto status = stop_notification_fetch_thread(); - if (HAILO_SUCCESS != status) { - LOGGER__WARNING("Stopping notification thread ungracefully"); - } -} - -hailo_status PcieDevice::fw_interact_impl(uint8_t *request_buffer, size_t request_size, uint8_t *response_buffer, - size_t *response_size, hailo_cpu_id_t cpu_id) -{ - // TODO: HRT-7535 - return HAILO_PCIE__fw_interact(m_driver, request_buffer, (uint32_t)request_size, response_buffer, - response_size, PCIE_DEFAULT_TIMEOUT_MS, cpu_id); -} - void PcieDevice::set_is_control_version_supported(bool value) { m_is_control_version_supported = value; @@ -225,7 +155,7 @@ void PcieDevice::set_is_control_version_supported(bool value) Expected PcieDevice::get_architecture() const { - if (!m_fw_up) { + if (!m_driver.is_fw_loaded()) { LOGGER__WARNING("FW is not loaded to the device. Please load FW before using the device."); return make_unexpected(HAILO_INVALID_OPERATION); } @@ -235,28 +165,12 @@ Expected PcieDevice::get_architecture() const hailo_status PcieDevice::direct_write_memory(uint32_t address, const void *buffer, uint32_t size) { - return HAILO_PCIE__write_memory(m_driver, address, buffer, size); + return m_driver.write_memory(HailoRTDriver::MemoryType::DIRECT_MEMORY, address, buffer, size); } hailo_status PcieDevice::direct_read_memory(uint32_t address, void *buffer, uint32_t size) { - return HAILO_PCIE__read_memory(m_driver, address, buffer, size); -} - -ExpectedRef PcieDevice::get_config_manager() -{ - auto status = mark_as_used(); - CHECK_SUCCESS_AS_EXPECTED(status); - - if (!m_context_switch_manager) { - auto local_context_switch_manager = VdmaConfigManager::create(*this); - CHECK_EXPECTED(local_context_switch_manager); - - m_context_switch_manager = make_unique_nothrow(local_context_switch_manager.release()); - CHECK_AS_EXPECTED(nullptr != m_context_switch_manager, HAILO_OUT_OF_HOST_MEMORY); - } - - return std::ref(*m_context_switch_manager); + return m_driver.read_memory(HailoRTDriver::MemoryType::DIRECT_MEMORY, address, buffer, size); } const char *PcieDevice::get_dev_id() const @@ -339,4 +253,30 @@ hailo_status PcieDevice::reset_impl(CONTROL_PROTOCOL__reset_type_t reset_type) return HAILO_SUCCESS; } +Expected PcieDevice::find_device_info(const hailo_pcie_device_info_t &pcie_device_info) +{ + auto scan_results = HailoRTDriver::scan_devices(); + CHECK_EXPECTED(scan_results); + + // Find device index based on the information from "device_info" + for (const auto &scan_result : scan_results.value()) { + const bool DONT_LOG_ON_FAILURE = false; + auto scanned_info = parse_pcie_device_info(scan_result.device_id, DONT_LOG_ON_FAILURE); + if (!scanned_info) { + continue; + } + + const bool match = (pcie_device_info.bus == scanned_info->bus) && + (pcie_device_info.device == scanned_info->device) && + (pcie_device_info.func == scanned_info->func) && + ((HAILO_PCIE_ANY_DOMAIN == pcie_device_info.domain) || (pcie_device_info.domain == scanned_info->domain)); + if (match) { + return HailoRTDriver::DeviceInfo(scan_result); + } + } + + LOGGER__ERROR("Requested device not found"); + return make_unexpected(HAILO_INVALID_ARGUMENT); +} + } /* namespace hailort */ diff --git a/hailort/libhailort/src/pcie_device.hpp b/hailort/libhailort/src/pcie_device.hpp index 4498923..1755563 100644 --- a/hailort/libhailort/src/pcie_device.hpp +++ b/hailort/libhailort/src/pcie_device.hpp @@ -14,7 +14,6 @@ #include "hailo/hailort.h" #include "hailo/expected.hpp" -#include "hlpcie.hpp" #include "vdma_channel.hpp" #include "vdma_device.hpp" @@ -30,10 +29,7 @@ public: bool log_on_failure); static Expected pcie_device_info_to_string(const hailo_pcie_device_info_t &device_info); - virtual ~PcieDevice(); - - virtual hailo_status fw_interact_impl(uint8_t *request_buffer, size_t request_size, - uint8_t *response_buffer, size_t *response_size, hailo_cpu_id_t cpu_id) override; + virtual ~PcieDevice() = default; virtual hailo_status reset_impl(CONTROL_PROTOCOL__reset_type_t reset_type) override; virtual hailo_status direct_write_memory(uint32_t address, const void *buffer, uint32_t size) override; @@ -52,7 +48,6 @@ public: return false; } } - virtual ExpectedRef get_config_manager() override; // TODO: used for tests void set_is_control_version_supported(bool value); @@ -65,19 +60,15 @@ public: virtual const char* get_dev_id() const override; private: - PcieDevice(HailoRTDriver &&driver, const hailo_pcie_device_info_t &device_info, hailo_status &status); + PcieDevice(HailoRTDriver &&driver, const hailo_pcie_device_info_t &device_info, hailo_status &status, + const std::string &device_id); hailo_status close_all_vdma_channels(); - bool m_fw_up; + static Expected find_device_info(const hailo_pcie_device_info_t &pcie_device_info); + const hailo_pcie_device_info_t m_device_info; std::string m_device_id; - // TODO: (HRT-7535) This member needs to be held in the object that impls fw_interact_impl func, - // because VdmaConfigManager calls a control (which in turn calls fw_interact_impl). - // (otherwise we'll get a "pure virtual method called" runtime error in the Device's dtor) - // Once we merge CoreDevice::fw_interact_impl and PcieDevice::fw_interact_impl we can - // move the m_context_switch_manager member and get_config_manager() func to VdmaDevice. - std::unique_ptr m_context_switch_manager; }; } /* namespace hailort */ diff --git a/hailort/libhailort/src/pipeline.cpp b/hailort/libhailort/src/pipeline.cpp index 1b478e6..41cdff8 100644 --- a/hailort/libhailort/src/pipeline.cpp +++ b/hailort/libhailort/src/pipeline.cpp @@ -10,7 +10,6 @@ #include "pipeline.hpp" #include "common/utils.hpp" #include "common/runtime_statistics_internal.hpp" -#include "microprofile.h" namespace hailort { @@ -186,7 +185,9 @@ Expected BufferPool::acquire_buffer(std::chrono::milliseconds ti return make_unexpected(buffer.status()); } else if (HAILO_TIMEOUT == buffer.status()) { - LOGGER__WARNING("Failed to acquire buffer because the buffer pool is empty. This could be caused by uneven reading and writing speeds, with a short user-defined timeout."); + LOGGER__WARNING( + "Failed to acquire buffer because the buffer pool is empty. This could be caused by uneven reading and writing speeds, with a short user-defined timeout. (timeout={}ms)", + timeout.count()); return make_unexpected(buffer.status()); } CHECK_EXPECTED(buffer); @@ -211,7 +212,7 @@ Expected BufferPool::get_available_buffer(PipelineBuffer &&optio if (HAILO_SHUTDOWN_EVENT_SIGNALED == acquired_buffer.status()) { return make_unexpected(acquired_buffer.status()); } - CHECK_EXPECTED(acquired_buffer, "Failed to acquire buffer"); + CHECK_EXPECTED(acquired_buffer, "Failed to acquire buffer with status={}", acquired_buffer.status()); return acquired_buffer.release(); } @@ -397,9 +398,9 @@ hailo_status PipelinePad::abort() return m_element.abort(); } -void PipelinePad::wait_for_finish() +hailo_status PipelinePad::wait_for_finish() { - m_element.wait_for_finish(); + return m_element.wait_for_finish(); } hailo_status PipelinePad::resume() @@ -511,14 +512,10 @@ IntermediateElement::IntermediateElement(const std::string &name, DurationCollec m_sources.emplace_back(*this, name, PipelinePad::Type::SOURCE); } -hailo_status IntermediateElement::flush() +std::vector IntermediateElement::execution_pads() { - return next_pad().flush(); -} - -void IntermediateElement::wait_for_finish() -{ - next_pad().wait_for_finish(); + std::vector result{&next_pad()}; + return result; } PipelineElement::PipelineElement(const std::string &name, DurationCollector &&duration_collector, @@ -572,41 +569,112 @@ std::string PipelineElement::description() const return element_description.str(); } -FilterElement::FilterElement(const std::string &name, DurationCollector &&duration_collector, - std::shared_ptr> &&pipeline_status) : - IntermediateElement(name, std::move(duration_collector), std::move(pipeline_status)) -{} +hailo_status PipelineElement::activate() +{ + return execute_activate(); +} + +hailo_status PipelineElement::deactivate() +{ + return execute_deactivate(); +} + +hailo_status PipelineElement::post_deactivate() +{ + return execute_post_deactivate(); +} + +hailo_status PipelineElement::clear() +{ + return execute_clear(); +} + +hailo_status PipelineElement::flush() +{ + return execute_flush(); +} + +hailo_status PipelineElement::abort() +{ + return execute_abort(); +} -hailo_status FilterElement::activate() +hailo_status PipelineElement::resume() { - return next_pad().activate(); + return execute_resume(); } -hailo_status FilterElement::deactivate() +hailo_status PipelineElement::wait_for_finish() { - return next_pad().deactivate(); + return execute_wait_for_finish(); } -hailo_status FilterElement::post_deactivate() +hailo_status PipelineElement::execute_activate() { - return next_pad().post_deactivate(); + return execute([&](auto *pad){ return pad->activate(); }); } -hailo_status FilterElement::clear() +hailo_status PipelineElement::execute_deactivate() { - return next_pad().clear(); + return execute([&](auto *pad){ return pad->deactivate(); }); } -hailo_status FilterElement::abort() +hailo_status PipelineElement::execute_post_deactivate() { - return next_pad().abort(); + return execute([&](auto *pad){ return pad->post_deactivate(); }); } -hailo_status FilterElement::resume() +hailo_status PipelineElement::execute_clear() { - return next_pad().resume(); + return execute([&](auto *pad){ return pad->clear(); }); } +hailo_status PipelineElement::execute_flush() +{ + return execute([&](auto *pad){ return pad->flush(); }); +} + +hailo_status PipelineElement::execute_abort() +{ + return execute([&](auto *pad){ return pad->abort(); }); +} + +hailo_status PipelineElement::execute_resume() +{ + return execute([&](auto *pad){ return pad->resume(); }); +} + +hailo_status PipelineElement::execute_wait_for_finish() +{ + return execute([&](auto *pad){ return pad->wait_for_finish(); }); +} + +hailo_status PipelineElement::execute(std::function func) +{ + for (auto pad : execution_pads()) { + auto status = func(pad); + CHECK_SUCCESS(status); + } + return HAILO_SUCCESS; +} + +std::vector SourceElement::execution_pads() +{ + std::vector result{&source()}; + return result; +} + +std::vector SinkElement::execution_pads() +{ + std::vector result{&sink()}; + return result; +} + +FilterElement::FilterElement(const std::string &name, DurationCollector &&duration_collector, + std::shared_ptr> &&pipeline_status) : + IntermediateElement(name, std::move(duration_collector), std::move(pipeline_status)) +{} + hailo_status FilterElement::run_push(PipelineBuffer &&buffer) { auto output = action(std::move(buffer), PipelineBuffer()); @@ -616,8 +684,12 @@ hailo_status FilterElement::run_push(PipelineBuffer &&buffer) CHECK_EXPECTED_AS_STATUS(output); hailo_status status = next_pad().run_push(output.release()); - if (HAILO_SHUTDOWN_EVENT_SIGNALED == status) { - LOGGER__INFO("run_push of FilterElement was shutdown!"); + if (status == HAILO_SHUTDOWN_EVENT_SIGNALED) { + LOGGER__INFO("run_push of {} was shutdown!", name()); + return status; + } + if (status == HAILO_STREAM_ABORTED_BY_USER) { + LOGGER__INFO("run_push of {} was aborted!", name()); return status; } CHECK_SUCCESS(status); @@ -659,14 +731,14 @@ BaseQueueElement::BaseQueueElement(SpscQueue &&queue, EventPtr s m_is_run_in_thread_running(false) {} +BaseQueueElement::~BaseQueueElement() +{ + LOGGER__INFO("Queue element {} has {} frames in his Queue on destruction", name(), m_queue.size_approx()); +} + void BaseQueueElement::start_thread() { m_thread = std::thread([this] () { - // Microprofile the thread - MicroProfileOnThreadCreate(name().c_str()); - MicroProfileSetEnableAllGroups(true); - MicroProfileSetForceMetaCounters(true); - while (m_is_thread_running.load()) { auto status = m_activation_event.wait(INIFINITE_TIMEOUT()); @@ -692,8 +764,8 @@ void BaseQueueElement::start_thread() if (HAILO_SUCCESS != status) { if (HAILO_SHUTDOWN_EVENT_SIGNALED != status) { - // We do not want to log error for HAILO_STREAM_INTERNAL_ABORT - if (HAILO_STREAM_INTERNAL_ABORT != status) { + // We do not want to log error for HAILO_STREAM_ABORTED_BY_USER + if (HAILO_STREAM_ABORTED_BY_USER != status) { LOGGER__ERROR("Queue element {} run in thread function failed! status = {}", this->name(), status); } @@ -719,8 +791,6 @@ void BaseQueueElement::start_thread() } } } - // TODO: Should we use MicroProfileShutdown? - MicroProfileOnThreadExit(); }); } @@ -745,9 +815,9 @@ std::vector BaseQueueElement::get_queue_size_accumulators() return {m_queue_size_accumulator}; } -hailo_status BaseQueueElement::activate() +hailo_status BaseQueueElement::execute_activate() { - hailo_status status = next_pad().activate(); + hailo_status status = PipelineElement::execute_activate(); CHECK_SUCCESS(status); status = m_activation_event.signal(); @@ -756,7 +826,7 @@ hailo_status BaseQueueElement::activate() return HAILO_SUCCESS; } -hailo_status BaseQueueElement::post_deactivate() +hailo_status BaseQueueElement::execute_post_deactivate() { hailo_status status = m_deactivation_event.wait(INIFINITE_TIMEOUT()); if (HAILO_SUCCESS != status) { @@ -768,12 +838,12 @@ hailo_status BaseQueueElement::post_deactivate() LOGGER__ERROR("Failed to reset of deactivation event in {} with status {}", name(), status); } - return next_pad().post_deactivate(); + return PipelineElement::execute_post_deactivate(); } -hailo_status BaseQueueElement::clear() +hailo_status BaseQueueElement::execute_clear() { - auto status = next_pad().clear(); + auto status = PipelineElement::execute_clear(); if (HAILO_SUCCESS != status) { LOGGER__ERROR("Failed to clear() in {} with status {}", name(), status); } @@ -784,25 +854,33 @@ hailo_status BaseQueueElement::clear() return status; } -hailo_status BaseQueueElement::abort() -{ - return next_pad().abort(); -} - -void BaseQueueElement::wait_for_finish() +hailo_status BaseQueueElement::execute_wait_for_finish() { std::unique_lock lock(m_mutex); m_cv.wait(lock, [this] () { return !m_is_run_in_thread_running; }); + return HAILO_SUCCESS; +} + +hailo_status PushQueueElement::execute_abort() +{ + auto status = m_shutdown_event->reset(); + CHECK_SUCCESS(status); + m_pipeline_status->store(HAILO_STREAM_ABORTED_BY_USER); + status = PipelineElement::execute_abort(); + CHECK_SUCCESS(status); + return m_activation_event.signal(); } -hailo_status BaseQueueElement::resume() +hailo_status BaseQueueElement::execute_resume() { auto status = m_shutdown_event->reset(); CHECK_SUCCESS(status); m_pipeline_status->store(HAILO_SUCCESS); - return next_pad().resume(); + status = PipelineElement::execute_resume(); + CHECK_SUCCESS(status); + return m_activation_event.signal(); } hailo_status BaseQueueElement::set_timeout(std::chrono::milliseconds timeout) @@ -828,8 +906,8 @@ hailo_status BaseQueueElement::pipeline_status() { auto status = m_pipeline_status->load(); - // We treat HAILO_STREAM_INTERNAL_ABORT as success because it is caused by user action (aborting streams) - if (HAILO_STREAM_INTERNAL_ABORT == status) { + // We treat HAILO_STREAM_ABORTED_BY_USER as success because it is caused by user action (aborting streams) + if (HAILO_STREAM_ABORTED_BY_USER == status) { return HAILO_SUCCESS; } return status; @@ -896,7 +974,13 @@ hailo_status PushQueueElement::run_push(PipelineBuffer &&buffer) if (nullptr != m_queue_size_accumulator) { m_queue_size_accumulator->add_data_point(static_cast(m_queue.size_approx())); } - hailo_status status = m_queue.enqueue(std::move(buffer), m_timeout); + auto status = m_pipeline_status->load(); + if (status == HAILO_STREAM_ABORTED_BY_USER) { + LOGGER__INFO("run_push of {} was aborted!", name()); + return status; + } + CHECK_SUCCESS(m_pipeline_status->load()); + status = m_queue.enqueue(std::move(buffer), m_timeout); if (HAILO_SHUTDOWN_EVENT_SIGNALED == status) { auto queue_thread_status = pipeline_status(); CHECK_SUCCESS(queue_thread_status, @@ -914,15 +998,15 @@ Expected PushQueueElement::run_pull(PipelineBuffer &&/*optional* return make_unexpected(HAILO_INVALID_OPERATION); } -hailo_status PushQueueElement::deactivate() +hailo_status PushQueueElement::execute_deactivate() { // Mark to the threads that deactivate() was called. hailo_status status = m_queue.enqueue(PipelineBuffer(PipelineBuffer::Type::DEACTIVATE)); if (HAILO_SUCCESS != status) { // We want to deactivate source even if enqueue failed - auto deactivation_status = next_pad().deactivate(); + auto deactivation_status = PipelineElement::execute_deactivate(); CHECK_SUCCESS(deactivation_status); - if ((HAILO_STREAM_INTERNAL_ABORT == status) || (HAILO_SHUTDOWN_EVENT_SIGNALED == status)) { + if ((HAILO_STREAM_ABORTED_BY_USER == status) || (HAILO_SHUTDOWN_EVENT_SIGNALED == status)) { LOGGER__INFO("enqueue() in element {} was aborted, got status = {}", name(), status); } else { @@ -963,7 +1047,7 @@ hailo_status PushQueueElement::run_in_thread() } hailo_status status = next_pad().run_push(buffer.release()); - if (HAILO_STREAM_INTERNAL_ABORT == status) { + if (HAILO_STREAM_ABORTED_BY_USER == status) { LOGGER__INFO("run_push of {} was aborted!", name()); return status; } @@ -1031,11 +1115,6 @@ hailo_status PullQueueElement::run_push(PipelineBuffer &&/*buffer*/) return HAILO_INVALID_OPERATION; } -hailo_status PullQueueElement::resume() -{ - return next_pad().resume(); -} - Expected PullQueueElement::run_pull(PipelineBuffer &&optional, const PipelinePad &/*sink*/) { // TODO: Support fps/latency collection for queue elems (HRT-7711) @@ -1058,9 +1137,9 @@ Expected PullQueueElement::run_pull(PipelineBuffer &&optional, c return output; } -hailo_status PullQueueElement::deactivate() +hailo_status PullQueueElement::execute_deactivate() { - hailo_status status = next_pad().deactivate(); + hailo_status status = PipelineElement::execute_deactivate(); auto shutdown_event_status = m_shutdown_event->signal(); CHECK_SUCCESS(status); CHECK_SUCCESS(shutdown_event_status); @@ -1081,9 +1160,9 @@ hailo_status PullQueueElement::run_in_thread() LOGGER__INFO("Shutdown event was signaled in run_pull of queue element {}!", name()); return HAILO_SHUTDOWN_EVENT_SIGNALED; } - if (HAILO_STREAM_INTERNAL_ABORT == buffer.status()) { + if (HAILO_STREAM_ABORTED_BY_USER == buffer.status()) { LOGGER__INFO("run_pull of queue element {} was aborted!", name()); - return HAILO_STREAM_INTERNAL_ABORT; + return HAILO_STREAM_ABORTED_BY_USER; } if (HAILO_NETWORK_GROUP_NOT_ACTIVATED == buffer.status()) { LOGGER__INFO("run_pull of queue element {} was called before network_group is activated!", name()); @@ -1175,15 +1254,16 @@ Expected UserBufferQueueElement::run_pull(PipelineBuffer &&optio LOGGER__INFO("Shutdown event was signaled in dequeue of queue element {}!", name()); return make_unexpected(HAILO_SHUTDOWN_EVENT_SIGNALED); } + CHECK_AS_EXPECTED(HAILO_TIMEOUT != output.status(), HAILO_TIMEOUT, "{} (D2H) failed with status={} (timeout={}ms)", name(), HAILO_TIMEOUT, m_timeout.count()); CHECK_EXPECTED(output); CHECK_AS_EXPECTED(output->data() == optional.data(), HAILO_INTERNAL_FAILURE, "The buffer received in {} was not the same as the user buffer!", name()); return output; } -hailo_status UserBufferQueueElement::clear() +hailo_status UserBufferQueueElement::execute_clear() { - auto status = next_pad().clear(); + auto status = PipelineElement::execute_clear(); if (HAILO_SUCCESS != status) { LOGGER__ERROR("Failed to clear() in {} with status {}", name(), status); } @@ -1217,9 +1297,9 @@ hailo_status UserBufferQueueElement::run_in_thread() LOGGER__INFO("Shutdown event was signaled in run_pull of {}!", name()); return HAILO_SHUTDOWN_EVENT_SIGNALED; } - if (HAILO_STREAM_INTERNAL_ABORT == buffer.status()) { + if (HAILO_STREAM_ABORTED_BY_USER == buffer.status()) { LOGGER__INFO("run_pull of {} was aborted!", name()); - return HAILO_STREAM_INTERNAL_ABORT; + return HAILO_STREAM_ABORTED_BY_USER; } CHECK_EXPECTED_AS_STATUS(buffer); @@ -1245,6 +1325,16 @@ BaseMuxElement::BaseMuxElement(size_t sink_count, const std::string &name, std:: } } +std::vector BaseMuxElement::execution_pads() +{ + std::vector result; + result.reserve(m_sinks.size()); + for (auto& pad : m_sinks) { + result.push_back(pad.prev()); + } + return result; +} + hailo_status BaseMuxElement::run_push(PipelineBuffer &&/*buffer*/) { return HAILO_NOT_IMPLEMENTED; @@ -1270,82 +1360,6 @@ Expected BaseMuxElement::run_pull(PipelineBuffer &&optional, con return output; } -hailo_status BaseMuxElement::activate() -{ - for (auto &sink : m_sinks) { - hailo_status status = sink.prev()->activate(); - CHECK_SUCCESS(status); - } - return HAILO_SUCCESS; -} - -hailo_status BaseMuxElement::deactivate() -{ - for (auto &sink : m_sinks) { - hailo_status status = sink.prev()->deactivate(); - CHECK_SUCCESS(status); - } - return HAILO_SUCCESS; -} - -hailo_status BaseMuxElement::post_deactivate() -{ - for (auto &sink : m_sinks) { - hailo_status status = sink.prev()->post_deactivate(); - CHECK_SUCCESS(status); - } - return HAILO_SUCCESS; -} - -hailo_status BaseMuxElement::clear() -{ - hailo_status status = HAILO_SUCCESS; - for (auto &sink : m_sinks) { - hailo_status clear_status = sink.prev()->clear(); - if (HAILO_SUCCESS != clear_status) { - status = clear_status; - } - } - return status; -} - -hailo_status BaseMuxElement::abort() -{ - for (auto &sink : m_sinks) { - hailo_status status = sink.prev()->abort(); - CHECK_SUCCESS(status); - } - return HAILO_SUCCESS; -} - -void BaseMuxElement::wait_for_finish() -{ - for (auto &sink : m_sinks) { - sink.prev()->wait_for_finish(); - } -} - -hailo_status BaseMuxElement::resume() -{ - for (auto &sink : m_sinks) { - hailo_status status = sink.prev()->resume(); - CHECK_SUCCESS(status); - } - return HAILO_SUCCESS; -} - -hailo_status BaseMuxElement::flush() -{ - hailo_status status = HAILO_SUCCESS; - for (auto &sink : m_sinks) { - hailo_status clear_status = sink.prev()->flush(); - if (HAILO_SUCCESS != clear_status) { - status = clear_status; - } - } - return status; -} - BaseDemuxElement::BaseDemuxElement(size_t source_count, const std::string &name, std::chrono::milliseconds timeout, DurationCollector &&duration_collector, std::shared_ptr> &&pipeline_status) : PipelineElement(name, std::move(duration_collector), std::move(pipeline_status)), @@ -1382,7 +1396,7 @@ Expected BaseDemuxElement::run_pull(PipelineBuffer &&optional, c m_was_source_called[m_index_of_source[&source]] = true; if (were_all_sinks_called()) { auto input = next_pad().run_pull(); - if (HAILO_STREAM_INTERNAL_ABORT == input.status()) { + if (HAILO_STREAM_ABORTED_BY_USER == input.status()) { LOGGER__INFO("run_pull of demux element was aborted!"); m_was_stream_aborted = true; lock.unlock(); @@ -1411,14 +1425,18 @@ Expected BaseDemuxElement::run_pull(PipelineBuffer &&optional, c m_cv.notify_all(); } else { auto cv_status = m_cv.wait_for(lock, m_timeout); - CHECK_AS_EXPECTED(std::cv_status::timeout != cv_status, HAILO_TIMEOUT, "Waiting for other threads in demux {} has reached a timeout!", name()); + CHECK_AS_EXPECTED(std::cv_status::timeout != cv_status, HAILO_TIMEOUT, "Waiting for other threads in demux {} has reached a timeout (timeout={}ms)", name(), m_timeout.count()); if (m_was_stream_aborted) { - return make_unexpected(HAILO_STREAM_INTERNAL_ABORT); + lock.unlock(); + m_cv.notify_all(); + return make_unexpected(HAILO_STREAM_ABORTED_BY_USER); } // We check if the element is not activated in case notify_all() was called from deactivate() if (!m_is_activated) { + lock.unlock(); + m_cv.notify_all(); return make_unexpected(HAILO_SHUTDOWN_EVENT_SIGNALED); } } @@ -1432,17 +1450,17 @@ bool BaseDemuxElement::were_all_sinks_called() return std::all_of(m_was_source_called.begin(), m_was_source_called.end(), [](bool v) { return v; }); } -hailo_status BaseDemuxElement::activate() +hailo_status BaseDemuxElement::execute_activate() { if (m_is_activated) { return HAILO_SUCCESS; } m_is_activated = true;// TODO Should this always be true, no matter the status of source().activate()? m_was_stream_aborted = false; - return next_pad().activate(); + return PipelineElement::execute_activate(); } -hailo_status BaseDemuxElement::deactivate() +hailo_status BaseDemuxElement::execute_deactivate() { if (!m_is_activated) { return HAILO_SUCCESS; @@ -1451,7 +1469,7 @@ hailo_status BaseDemuxElement::deactivate() // deactivate should be called before mutex acquire and notify_all because it is possible that all queues are waiting on // the run_pull of the source (HwRead) and the mutex is already acquired so this would prevent a timeout error - hailo_status status = next_pad().deactivate(); + hailo_status status = PipelineElement::execute_deactivate(); { // There is a case where the other thread is halted (via context switch) before the wait_for() function, @@ -1466,38 +1484,22 @@ hailo_status BaseDemuxElement::deactivate() return HAILO_SUCCESS; } -hailo_status BaseDemuxElement::post_deactivate() +hailo_status BaseDemuxElement::execute_post_deactivate() { for (uint32_t i = 0; i < m_was_source_called.size(); i++) { m_was_source_called[i] = false; } - return next_pad().post_deactivate(); + return PipelineElement::execute_post_deactivate(); } -hailo_status BaseDemuxElement::clear() +hailo_status BaseDemuxElement::execute_abort() { - return next_pad().clear(); -} - -hailo_status BaseDemuxElement::flush() -{ - return next_pad().flush(); -} - -hailo_status BaseDemuxElement::abort() -{ - m_was_stream_aborted = true; - return next_pad().abort(); -} - -void BaseDemuxElement::wait_for_finish() -{ - next_pad().wait_for_finish(); -} - -hailo_status BaseDemuxElement::resume() -{ - return next_pad().resume(); + { + std::unique_lock lock(m_mutex); + m_was_stream_aborted = true; + } + m_cv.notify_all(); + return PipelineElement::execute_abort(); } PipelinePad &BaseDemuxElement::next_pad() @@ -1512,4 +1514,11 @@ hailo_status BaseDemuxElement::set_timeout(std::chrono::milliseconds timeout) return HAILO_SUCCESS; } +std::vector BaseDemuxElement::execution_pads() +{ + std::vector result{&next_pad()}; + return result; +} + + } /* namespace hailort */ diff --git a/hailort/libhailort/src/pipeline.hpp b/hailort/libhailort/src/pipeline.hpp index 9895c01..e66b192 100644 --- a/hailort/libhailort/src/pipeline.hpp +++ b/hailort/libhailort/src/pipeline.hpp @@ -176,6 +176,55 @@ class PipelineElement; using PushCompleteCallback = std::function; using PullCompleteCallback = std::function; +struct NetFlowPad { + std::string name; + hailo_format_t format; + hailo_quant_info_t quant_info; + uint32_t number_of_classes = 0; // temporarly here, should be only if the previous op is NMS +}; + +struct NetFlowElement { + std::vector input_pads; + std::vector output_pads; + + enum class Type + { + None = 0, + CoreOp = 1, + YoloNmsOp = 2 + }; + + Type type; + std::string name; + std::set input_streams; + + virtual ~NetFlowElement() = default; +}; + +struct YoloBboxDecoder { + std::vector h; + std::vector w; + uint32_t stride = 0; + // uint32_t pad_index; + std::string stream_name; +}; + +struct NetFlowNmsElement : NetFlowElement { + float32_t nms_score_th = 0; + float32_t nms_iou_th = 0; + uint32_t max_proposals_per_class = 0; + uint32_t classes = 0; + bool background_removal = false; + uint32_t background_removal_index = 0; +}; + +struct NetFlowYoloNmsElement final : NetFlowNmsElement { + std::vector bbox_decoders; + float32_t image_height = 0; + float32_t image_width = 0; + uint32_t input_division_factor = 0; +}; + class PipelinePad final : public PipelineObject { public: @@ -200,14 +249,14 @@ public: PipelinePad &operator=(PipelinePad &&other) = delete; ~PipelinePad() = default; - virtual hailo_status activate(); - virtual hailo_status deactivate(); - virtual hailo_status post_deactivate(); - virtual hailo_status clear(); - virtual hailo_status flush(); - virtual hailo_status abort(); - virtual void wait_for_finish(); - virtual hailo_status resume(); + hailo_status activate(); + hailo_status deactivate(); + hailo_status post_deactivate(); + hailo_status clear(); + hailo_status flush(); + hailo_status abort(); + hailo_status wait_for_finish(); + hailo_status resume(); virtual hailo_status run_push(PipelineBuffer &&buffer); virtual Expected run_pull(PipelineBuffer &&optional = PipelineBuffer()); void set_push_complete_callback(PushCompleteCallback push_complete_callback); @@ -248,14 +297,14 @@ public: PipelineElement &operator=(const PipelineElement &) = delete; PipelineElement &operator=(PipelineElement &&other) = delete; - virtual hailo_status activate() = 0; - virtual hailo_status deactivate() = 0; - virtual hailo_status post_deactivate() = 0; - virtual hailo_status clear() = 0; - virtual hailo_status flush() = 0; - virtual hailo_status abort() = 0; - virtual void wait_for_finish() = 0; - virtual hailo_status resume() = 0; + hailo_status activate(); + hailo_status deactivate(); + hailo_status post_deactivate(); + hailo_status clear(); + hailo_status flush(); + hailo_status abort(); + hailo_status resume(); + hailo_status wait_for_finish(); virtual hailo_status run_push(PipelineBuffer &&buffer) = 0; virtual Expected run_pull(PipelineBuffer &&optional, const PipelinePad &source) = 0; AccumulatorPtr get_fps_accumulator(); @@ -285,6 +334,18 @@ protected: std::function m_cant_pull_callback; std::function m_can_pull_callback; + + virtual std::vector execution_pads() = 0; + virtual hailo_status execute_activate(); + virtual hailo_status execute_deactivate(); + virtual hailo_status execute_post_deactivate(); + virtual hailo_status execute_clear(); + virtual hailo_status execute_flush(); + virtual hailo_status execute_abort(); + virtual hailo_status execute_resume(); + virtual hailo_status execute_wait_for_finish(); + + virtual hailo_status execute(std::function); }; // An element with one source pad only (generates data) @@ -294,6 +355,9 @@ public: SourceElement(const std::string &name, DurationCollector &&duration_collector, std::shared_ptr> &&pipeline_status); PipelinePad &source(); + +protected: + virtual std::vector execution_pads() override; }; // An element with one sink pad only (consumes data) @@ -303,6 +367,9 @@ public: SinkElement(const std::string &name, DurationCollector &&duration_collector, std::shared_ptr> &&pipeline_status); PipelinePad &sink(); + +protected: + virtual std::vector execution_pads() override; }; // Transfers data from one pad to another pad. Has one sink pad and one source pad. @@ -312,8 +379,9 @@ public: IntermediateElement(const std::string &name, DurationCollector &&duration_collector, std::shared_ptr> &&pipeline_status); virtual PipelinePad &next_pad() = 0; - virtual void wait_for_finish() override; - virtual hailo_status flush() override; + +protected: + virtual std::vector execution_pads() override; }; class FilterElement : public IntermediateElement @@ -323,12 +391,6 @@ public: std::shared_ptr> &&pipeline_status); virtual ~FilterElement() = default; - virtual hailo_status activate() override; - virtual hailo_status deactivate() override; - virtual hailo_status post_deactivate() override; - virtual hailo_status clear() override; - virtual hailo_status abort() override; - virtual hailo_status resume() override; virtual hailo_status run_push(PipelineBuffer &&buffer) override; virtual Expected run_pull(PipelineBuffer &&optional, const PipelinePad &source) override; @@ -340,15 +402,8 @@ protected: class BaseQueueElement : public IntermediateElement { public: - virtual ~BaseQueueElement() = default; - - virtual hailo_status activate() override; - virtual hailo_status deactivate() = 0; - virtual hailo_status post_deactivate() override; - virtual hailo_status clear() override; - virtual hailo_status abort() override; - virtual void wait_for_finish() override; - virtual hailo_status resume() override; + virtual ~BaseQueueElement(); + hailo_status set_timeout(std::chrono::milliseconds timeout); virtual std::string description() const override; @@ -363,6 +418,12 @@ protected: hailo_status pipeline_status(); + virtual hailo_status execute_activate() override; + virtual hailo_status execute_post_deactivate() override; + virtual hailo_status execute_clear() override; + virtual hailo_status execute_resume() override; + virtual hailo_status execute_wait_for_finish() override; + /// Starts/stops the queue thread. This functions needs to be called on subclasses ctor and dtor /// accordingly because otherwise, if we will start/stop thread in this class we will face pure-call /// to `run_in_thread`. @@ -402,11 +463,12 @@ public: virtual hailo_status run_push(PipelineBuffer &&buffer) override; virtual Expected run_pull(PipelineBuffer &&optional, const PipelinePad &source) override; - virtual hailo_status deactivate() override; virtual PipelinePad &next_pad() override; protected: + virtual hailo_status execute_deactivate() override; virtual hailo_status run_in_thread() override; + virtual hailo_status execute_abort() override; }; class PullQueueElement : public BaseQueueElement @@ -424,8 +486,6 @@ public: virtual hailo_status run_push(PipelineBuffer &&buffer) override; virtual Expected run_pull(PipelineBuffer &&optional, const PipelinePad &source) override; - virtual hailo_status deactivate() override; - virtual hailo_status resume() override; virtual PipelinePad &next_pad() override; virtual void set_on_cant_pull_callback(std::function callback) override @@ -445,6 +505,7 @@ public: } protected: + virtual hailo_status execute_deactivate() override; virtual hailo_status run_in_thread() override; }; @@ -460,7 +521,6 @@ public: std::shared_ptr> &&pipeline_status, Event &&activation_event, Event &&deactivation_event); virtual Expected run_pull(PipelineBuffer &&optional, const PipelinePad &source) override; - virtual hailo_status clear() override; virtual void set_on_cant_pull_callback(std::function callback) override { @@ -473,6 +533,7 @@ public: } protected: + virtual hailo_status execute_clear() override; virtual hailo_status run_in_thread() override; private: @@ -488,17 +549,10 @@ public: virtual hailo_status run_push(PipelineBuffer &&buffer) override; virtual Expected run_pull(PipelineBuffer &&optional, const PipelinePad &source) override; - virtual hailo_status activate() override; - virtual hailo_status deactivate() override; - virtual hailo_status post_deactivate() override; - virtual hailo_status clear() override; - virtual hailo_status flush() override; - virtual hailo_status abort() override; - virtual void wait_for_finish() override; - virtual hailo_status resume() override; protected: virtual Expected action(std::vector &&inputs, PipelineBuffer &&optional) = 0; + virtual std::vector execution_pads() override; std::chrono::milliseconds m_timeout; }; @@ -512,18 +566,15 @@ public: virtual hailo_status run_push(PipelineBuffer &&buffer) override; virtual Expected run_pull(PipelineBuffer &&optional, const PipelinePad &source) override; - virtual hailo_status activate() override; - virtual hailo_status deactivate() override; - virtual hailo_status post_deactivate() override; - virtual hailo_status clear() override; - virtual hailo_status flush() override; - virtual hailo_status abort() override; - virtual void wait_for_finish() override; - virtual hailo_status resume() override; hailo_status set_timeout(std::chrono::milliseconds timeout); protected: + virtual hailo_status execute_activate() override; + virtual hailo_status execute_deactivate() override; + virtual hailo_status execute_post_deactivate() override; + virtual hailo_status execute_abort() override; virtual Expected> action(PipelineBuffer &&input) = 0; + virtual std::vector execution_pads() override; std::chrono::milliseconds m_timeout; diff --git a/hailort/libhailort/src/context_switch/pipeline_multiplexer.cpp b/hailort/libhailort/src/pipeline_multiplexer.cpp similarity index 71% rename from hailort/libhailort/src/context_switch/pipeline_multiplexer.cpp rename to hailort/libhailort/src/pipeline_multiplexer.cpp index a2bdda5..4d350a7 100644 --- a/hailort/libhailort/src/context_switch/pipeline_multiplexer.cpp +++ b/hailort/libhailort/src/pipeline_multiplexer.cpp @@ -19,9 +19,19 @@ PipelineMultiplexer::PipelineMultiplexer() : m_order_queue(), m_currently_writing(INVALID_NETWORK_GROUP_HANDLE), m_written_streams_count(0), - m_read_streams_count(0) + m_read_streams_count(0), + m_next_to_read_after_drain(INVALID_NETWORK_GROUP_HANDLE) {} +bool PipelineMultiplexer::should_use_multiplexer() +{ + auto disable_multiplexer_env = std::getenv(DISABLE_MULTIPLEXER_ENV_VAR); + if ((nullptr != disable_multiplexer_env) && (strnlen(disable_multiplexer_env, 2) == 1) && (strncmp(disable_multiplexer_env, "1", 1) == 0)) { + return false; + } + return true; +} + hailo_status PipelineMultiplexer::add_network_group_instance(multiplexer_ng_handle_t network_group_handle, ConfiguredNetworkGroup &network_group) { std::unique_lock lock(m_writing_mutex); @@ -71,6 +81,8 @@ hailo_status PipelineMultiplexer::wait_for_write(multiplexer_ng_handle_t network assert(contains(m_write_barriers, network_group_handle)); barrier = m_write_barriers[network_group_handle]; } + // TODO: This has no timeout + // TODO: HRT-8634 barrier->arrive_and_wait(); { std::unique_lock lock(m_writing_mutex); @@ -79,6 +91,10 @@ hailo_status PipelineMultiplexer::wait_for_write(multiplexer_ng_handle_t network m_is_waiting_to_write[network_group_handle] = true; m_writing_cv.wait(lock, [this, network_group_handle] { + if (!has_more_than_one_ng_instance() || !should_use_multiplexer()) { + return true; + } + if (m_should_ng_stop[network_group_handle]) { return true; } @@ -104,17 +120,12 @@ hailo_status PipelineMultiplexer::wait_for_write(multiplexer_ng_handle_t network m_is_waiting_to_write[network_group_handle] = false; if (m_should_ng_stop[network_group_handle]) { - return HAILO_STREAM_INTERNAL_ABORT; + return HAILO_STREAM_ABORTED_BY_USER; } if (INVALID_NETWORK_GROUP_HANDLE == m_currently_writing) { m_currently_writing = network_group_handle; - { - std::unique_lock reading_lock(m_reading_mutex); - m_order_queue.push(m_currently_writing); - m_next_to_write = m_currently_writing; - } - m_reading_cv.notify_all(); + m_next_to_write = m_currently_writing; } } m_writing_cv.notify_all(); @@ -124,6 +135,10 @@ hailo_status PipelineMultiplexer::wait_for_write(multiplexer_ng_handle_t network bool PipelineMultiplexer::can_network_group_read(multiplexer_ng_handle_t network_group_handle) { + if (m_should_ng_stop[network_group_handle]) { + return false; + } + if (!contains(m_can_network_group_read, network_group_handle)) { return true; } @@ -131,7 +146,7 @@ bool PipelineMultiplexer::can_network_group_read(multiplexer_ng_handle_t network return m_can_network_group_read[network_group_handle]; } -hailo_status PipelineMultiplexer::signal_write_finish() +hailo_status PipelineMultiplexer::signal_write_finish(multiplexer_ng_handle_t network_group_handle) { std::unique_lock lock(m_writing_mutex); m_written_streams_count++; @@ -142,6 +157,12 @@ hailo_status PipelineMultiplexer::signal_write_finish() m_next_to_write++; m_next_to_write %= static_cast(instances_count()); + { + std::unique_lock reading_lock(m_reading_mutex); + m_order_queue.push_back(network_group_handle); + } + m_reading_cv.notify_all(); + lock.unlock(); m_writing_cv.notify_all(); } @@ -149,40 +170,102 @@ hailo_status PipelineMultiplexer::signal_write_finish() return HAILO_SUCCESS; } -hailo_status PipelineMultiplexer::wait_for_read(multiplexer_ng_handle_t network_group_handle, const std::string &stream_name) +Expected PipelineMultiplexer::wait_for_read(multiplexer_ng_handle_t network_group_handle, const std::string &stream_name, + const std::chrono::milliseconds &timeout) { std::unique_lock lock(m_reading_mutex); + uint32_t drain_frames = 0; assert(contains(m_should_ng_stop, network_group_handle)); assert(contains(m_is_stream_reading, network_group_handle)); assert(contains(m_is_stream_reading[network_group_handle], stream_name)); - m_reading_cv.wait(lock, [this, network_group_handle, stream_name] { + auto wait_res = m_reading_cv.wait_for(lock, timeout, [this, network_group_handle, stream_name, &drain_frames] { if (m_should_ng_stop[network_group_handle]) { return true; } - if (m_order_queue.empty()) { + if (m_is_stream_reading[network_group_handle][stream_name]) { return false; } - if (m_order_queue.front() != network_group_handle) { - return false; + if (m_next_to_read_after_drain == network_group_handle) { + drain_frames = m_num_frames_to_drain[stream_name]; + return true; } - if (m_is_stream_reading[network_group_handle][stream_name]) { + if (m_order_queue.empty()) { return false; } + if (m_order_queue.front() != network_group_handle) { + if (!m_should_ng_stop[m_order_queue.front()]) { + return false; + } + + uint32_t max_drain_count = get_frame_count_to_drain(network_group_handle); + if (0 == max_drain_count) { + return false; + } + + drain_frames = drain_aborted_in_order_queue(network_group_handle, stream_name, max_drain_count); + } + return true; }); + CHECK_AS_EXPECTED(wait_res, HAILO_TIMEOUT, "{} (D2H) failed with status={}, timeout={}ms", stream_name, HAILO_TIMEOUT, timeout.count()); + if (m_should_ng_stop[network_group_handle]) { - return HAILO_STREAM_INTERNAL_ABORT; + return make_unexpected(HAILO_STREAM_ABORTED_BY_USER); } m_is_stream_reading[network_group_handle][stream_name] = true; - return HAILO_SUCCESS; + return drain_frames; +} + +uint32_t PipelineMultiplexer::get_frame_count_to_drain(multiplexer_ng_handle_t network_group_handle) +{ + uint32_t drain_count = 0; + for (const auto &handle : m_order_queue) { + if (!m_should_ng_stop[handle]) { + if (handle == network_group_handle) { + // Current instance is in the front after draining + break; + } else { + // Someone else should drain these frames, the current instance won't be in front after draining + return 0; + } + } + + drain_count++; + } + + return drain_count; +} + +uint32_t PipelineMultiplexer::drain_aborted_in_order_queue(multiplexer_ng_handle_t network_group_handle, const std::string &stream_name, + uint32_t max_drain_count) +{ + // In case of multiple outputs where one or more already read the frame we need to drain one less frame + for (auto &name_flag_pair : m_is_stream_reading[m_order_queue.front()]) { + if (name_flag_pair.second) { + m_num_frames_to_drain[name_flag_pair.first] = max_drain_count - 1; + } else { + m_num_frames_to_drain[name_flag_pair.first] = max_drain_count; + } + } + + m_next_to_read_after_drain = network_group_handle; + m_read_streams_count = 0; + for (uint32_t i = 0; i < max_drain_count; i++) { + for (auto &name_flag_pair : m_is_stream_reading[m_order_queue.front()]) { + name_flag_pair.second = false; + } + m_order_queue.pop_front(); + } + + return m_num_frames_to_drain[stream_name]; } hailo_status PipelineMultiplexer::signal_read_finish(multiplexer_ng_handle_t network_group_handle) @@ -190,15 +273,20 @@ hailo_status PipelineMultiplexer::signal_read_finish(multiplexer_ng_handle_t net std::unique_lock lock(m_reading_mutex); assert(contains(m_is_stream_reading, network_group_handle)); + if (m_should_ng_stop[network_group_handle]) { + return HAILO_STREAM_ABORTED_BY_USER; + } + m_read_streams_count++; if (m_read_streams_count == m_output_streams_count) { m_read_streams_count = 0; - m_order_queue.pop(); - + m_order_queue.pop_front(); for (auto &name_flag_pair : m_is_stream_reading[network_group_handle]) { name_flag_pair.second = false; } + m_next_to_read_after_drain = INVALID_NETWORK_GROUP_HANDLE; + lock.unlock(); m_reading_cv.notify_all(); } @@ -236,6 +324,9 @@ hailo_status PipelineMultiplexer::disable_network_group(multiplexer_ng_handle_t } m_should_ng_stop[network_group_handle] = true; + if (m_currently_writing == network_group_handle) { + m_currently_writing = INVALID_NETWORK_GROUP_HANDLE; + } assert(contains(m_write_barriers, network_group_handle)); m_write_barriers[network_group_handle]->terminate(); diff --git a/hailort/libhailort/src/context_switch/pipeline_multiplexer.hpp b/hailort/libhailort/src/pipeline_multiplexer.hpp similarity index 84% rename from hailort/libhailort/src/context_switch/pipeline_multiplexer.hpp rename to hailort/libhailort/src/pipeline_multiplexer.hpp index 8b483e7..3187724 100644 --- a/hailort/libhailort/src/context_switch/pipeline_multiplexer.hpp +++ b/hailort/libhailort/src/pipeline_multiplexer.hpp @@ -16,12 +16,14 @@ #include "network_group_scheduler.hpp" #include "common/barrier.hpp" -#include #include +#include namespace hailort { +#define DISABLE_MULTIPLEXER_ENV_VAR "HAILO_DISABLE_MULTIPLEXER" + using multiplexer_ng_handle_t = uint32_t; using run_once_for_stream_handle_t = uint32_t; @@ -41,8 +43,9 @@ public: bool has_more_than_one_ng_instance() const; size_t instances_count() const; hailo_status wait_for_write(multiplexer_ng_handle_t network_group_handle); - hailo_status signal_write_finish(); - hailo_status wait_for_read(multiplexer_ng_handle_t network_group_handle, const std::string &stream_name); + hailo_status signal_write_finish(multiplexer_ng_handle_t network_group_handle); + Expected wait_for_read(multiplexer_ng_handle_t network_group_handle, const std::string &stream_name, + const std::chrono::milliseconds &timeout); hailo_status signal_read_finish(multiplexer_ng_handle_t network_group_handle); hailo_status enable_network_group(multiplexer_ng_handle_t network_group_handle); hailo_status disable_network_group(multiplexer_ng_handle_t network_group_handle); @@ -53,6 +56,8 @@ public: void set_can_output_vstream_read(multiplexer_ng_handle_t network_group_handle, const std::string &vstream_name, bool can_read); + static bool should_use_multiplexer(); + private: std::unordered_map m_should_ng_stop; std::unordered_map m_is_waiting_to_write; @@ -62,7 +67,7 @@ private: multiplexer_ng_handle_t m_next_to_write; std::unordered_map> m_write_barriers; - std::queue m_order_queue; + std::deque m_order_queue; std::mutex m_writing_mutex; std::condition_variable m_writing_cv; multiplexer_ng_handle_t m_currently_writing; @@ -72,11 +77,15 @@ private: std::mutex m_reading_mutex; std::condition_variable m_reading_cv; std::atomic_uint32_t m_read_streams_count; + std::unordered_map m_num_frames_to_drain; + multiplexer_ng_handle_t m_next_to_read_after_drain; std::unordered_map> m_can_output_vstream_read; std::unordered_map m_can_network_group_read; bool can_network_group_read(multiplexer_ng_handle_t network_group_handle); + uint32_t get_frame_count_to_drain(multiplexer_ng_handle_t network_group_handle); + uint32_t drain_aborted_in_order_queue(multiplexer_ng_handle_t network_group_handle, const std::string &stream_name, uint32_t max_drain_count); class RunOnceForStream final { diff --git a/hailort/libhailort/src/scheduled_network_group.cpp b/hailort/libhailort/src/scheduled_network_group.cpp new file mode 100644 index 0000000..a9a60da --- /dev/null +++ b/hailort/libhailort/src/scheduled_network_group.cpp @@ -0,0 +1,391 @@ +/** + * Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved. + * Distributed under the MIT license (https://opensource.org/licenses/MIT) + **/ +/** + * @file network_group_scheduler.cpp + * @brief: Network scheduler + **/ + +#include "scheduled_network_group.hpp" +#include "context_switch/network_group_internal.hpp" +#include "hef_internal.hpp" +#include "vdevice_stream_multiplexer_wrapper.hpp" +#include "scheduler_oracle.hpp" + +#include + +namespace hailort +{ + +ScheduledNetworkGroup::ScheduledNetworkGroup(std::shared_ptr cng, std::chrono::milliseconds timeout, + uint16_t max_batch_size, StreamInfoVector &stream_infos, std::string network_group_name) : + m_cng(cng), + m_last_run_time_stamp(std::chrono::steady_clock::now()), + m_timeout(std::move(timeout)), + m_frame_was_sent(false), + m_max_batch_size(max_batch_size), + m_network_group_name(network_group_name), + m_inputs_names(), + m_outputs_names(), + m_is_nms(false) +{ + // Prepare empty counters for the added cng + for (const auto &stream_info : stream_infos) { + m_min_threshold_per_stream[stream_info.name] = DEFAULT_SCHEDULER_MIN_THRESHOLD; + if (HAILO_H2D_STREAM == stream_info.direction) { + m_requested_write_frames.insert(stream_info.name); + m_finished_write_frames.insert(stream_info.name); + m_h2d_requested_transferred_frames.insert(stream_info.name); + m_h2d_finished_transferred_frames.insert(stream_info.name); + m_inputs_names.push_back(stream_info.name); + } else { + m_requested_read_frames.insert(stream_info.name); + m_ongoing_read_frames.insert(stream_info.name); + m_finished_read_frames.insert(stream_info.name); + m_d2h_finished_transferred_frames.insert(stream_info.name); + m_outputs_names.push_back(stream_info.name); + m_output_streams_read_orders[stream_info.name] = std::queue(); + if (HAILO_FORMAT_ORDER_HAILO_NMS == stream_info.format.order) { + m_is_nms = true; + } + } + } +} + +Expected> ScheduledNetworkGroup::create(std::shared_ptr added_cng, StreamInfoVector &stream_infos) +{ + auto timeout = DEFAULT_SCHEDULER_TIMEOUT; + + uint16_t max_batch_size = CONTROL_PROTOCOL__IGNORE_DYNAMIC_BATCH_SIZE; + auto cng_base = std::dynamic_pointer_cast(added_cng); + assert(nullptr != cng_base); + if (cng_base->get_supported_features().multi_context) { + auto batch_size = cng_base->get_stream_batch_size(stream_infos[0].name); + CHECK_EXPECTED(batch_size); + + if (batch_size.value() > SINGLE_CONTEXT_BATCH_SIZE) { + max_batch_size = batch_size.release(); + } + } + + return make_shared_nothrow(added_cng, timeout, max_batch_size, stream_infos, added_cng->name()); +} + +bool ScheduledNetworkGroup::has_enough_space_in_read_buffers(uint32_t ongoing_frames) +{ + auto output_streams = m_cng->get_output_streams(); + for (auto &output_stream : output_streams) { + OutputStreamBase &vdevice_output = static_cast(output_stream.get()); + if (auto pending_frames_size = vdevice_output.get_buffer_frames_size()) { + if (pending_frames_size.value() <= ongoing_frames) { + return false; + } + // If couldnt get pending frames size and count (e.g. NMS layer), assume we have space - scheduler switch will prevent deadlocks here + } + } + return true; +} + +bool ScheduledNetworkGroup::has_input_written_most_frames(const std::string &stream_name) +{ + auto total_writes = total_written_frames_count(); + return total_writes[stream_name] == get_max_value_of_unordered_map(total_writes); +} + +// TODO: Use get_pre_transfer_h2d_frames_count + get_h2d_transferred_frames_count +// TODO: Avoid returning map (malloc) +std::unordered_map ScheduledNetworkGroup::total_written_frames_count() +{ + std::unordered_map write_sum; + for (const auto &name : get_inputs_names()) { + write_sum[name] = m_requested_write_frames[name] + m_finished_write_frames[name] + + m_h2d_requested_transferred_frames[name] + + m_h2d_finished_transferred_frames[name]; + } + return write_sum; +} + +// TODO: Use max(m_d2h_finished_transferred_frames) == 0 instead +bool ScheduledNetworkGroup::has_pending_frames() +{ + uint32_t h2d_transferred_frames_count = get_h2d_transferred_frames_count(); + for (const auto &name : get_outputs_names()) { + if (m_finished_read_frames[name] < h2d_transferred_frames_count) { + return true; + } + } + return false; +} + +uint32_t ScheduledNetworkGroup::get_h2d_transferred_frames_count() +{ + std::unordered_map transferred_frames; + for (const auto &name : get_inputs_names()) { + transferred_frames[name] = m_h2d_requested_transferred_frames[name] + m_h2d_finished_transferred_frames[name]; + } + return get_max_value_of_unordered_map(transferred_frames); +} + +bool ScheduledNetworkGroup::can_stream_read(const std::string &stream_name) +{ + return !m_output_streams_read_orders[stream_name].empty(); +} + +bool ScheduledNetworkGroup::use_dynamic_batch_flow() +{ + return (CONTROL_PROTOCOL__IGNORE_DYNAMIC_BATCH_SIZE != m_max_batch_size); +} + +bool ScheduledNetworkGroup::has_ng_drained_everything(bool streaming_mode) +{ + // On streaming mode we want to check those conditions even on NMS + if (!is_nms() || streaming_mode) { + if (!m_requested_write_frames.empty()) { + return false; + } + if (!m_finished_write_frames.empty()) { + return false; + } + if (!m_h2d_requested_transferred_frames.empty()) { + return false; + } + } + + uint32_t written_frames = m_h2d_finished_transferred_frames.get_max_value(); + for (const auto &name : get_outputs_names()) { + if ((m_finished_read_frames[name] + m_d2h_finished_transferred_frames[name]) < written_frames) { + return false; + } + } + return true; +} + +void ScheduledNetworkGroup::decrease_current_ng_counters() +{ + // Decrease only if counter is 2 or bigger because reaching 0 can cause states to change + if (!m_h2d_finished_transferred_frames.all_values_bigger_or_equal(2)) { + return; + } + if (!m_finished_read_frames.all_values_bigger_or_equal(2)) { + return; + } + + for (const auto &name : get_inputs_names()) { + m_h2d_finished_transferred_frames[name]--; + } + for (const auto &name : get_outputs_names()) { + m_finished_read_frames[name]--; + } +} + +uint32_t ScheduledNetworkGroup::get_pre_transfer_h2d_frames_count() +{ + std::unordered_map write_sum; + for (const auto &name : get_inputs_names()) { + write_sum[name] = m_requested_write_frames[name] + m_finished_write_frames[name]; + } + return get_max_value_of_unordered_map(write_sum); +} + +hailo_status ScheduledNetworkGroup::set_timeout(const std::chrono::milliseconds &timeout, const stream_name_t &stream_name) +{ + CHECK(!m_frame_was_sent, HAILO_INVALID_OPERATION, + "Setting scheduler timeout is allowed only before sending / receiving frames on the network group."); + m_timeout = timeout; + + auto name = (stream_name.empty()) ? get_network_group_name() : stream_name; + LOGGER__INFO("Setting scheduler timeout of {} to {}ms", name, timeout.count()); + + return HAILO_SUCCESS; +} + +hailo_status ScheduledNetworkGroup::set_threshold(uint32_t threshold, const stream_name_t &stream_name) +{ + CHECK((CONTROL_PROTOCOL__IGNORE_DYNAMIC_BATCH_SIZE == m_max_batch_size) || + (threshold <= m_max_batch_size), HAILO_INVALID_ARGUMENT, "Threshold must be equal or lower than the maximum batch size!"); + + CHECK(!m_frame_was_sent, HAILO_INVALID_OPERATION, + "Setting scheduler threshold is allowed only before sending / receiving frames on the network group."); + + // TODO: Support setting threshold per stream. currently stream_name is always empty and de-facto we set threshold for the whole NG + for (auto &threshold_per_stream_pair : m_min_threshold_per_stream) { + threshold_per_stream_pair.second = threshold; + } + + auto name = (stream_name.empty()) ? get_network_group_name() : stream_name; + LOGGER__INFO("Setting scheduler threshold of {} to {} frames", name, threshold); + + return HAILO_SUCCESS; +} + +std::string ScheduledNetworkGroup::get_network_group_name() +{ + return m_network_group_name; +} + + +std::shared_ptr ScheduledNetworkGroup::get_network_group() +{ + return m_cng; +} + +void ScheduledNetworkGroup::mark_frame_sent() +{ + m_frame_was_sent = true; +} + +std::chrono::time_point ScheduledNetworkGroup::get_last_run_timestamp() +{ + return m_last_run_time_stamp; +} + +void ScheduledNetworkGroup::set_last_run_timestamp(const std::chrono::time_point ×tamp) +{ + m_last_run_time_stamp = timestamp; +} + +Expected ScheduledNetworkGroup::get_timeout(const stream_name_t &stream_name) +{ + CHECK_AS_EXPECTED(stream_name.empty(), HAILO_INVALID_OPERATION, "timeout per network is not supported"); + auto timeout = m_timeout; + return timeout; +} + +Expected ScheduledNetworkGroup::get_threshold(const stream_name_t &stream_name) +{ + CHECK_AS_EXPECTED(contains(m_min_threshold_per_stream, stream_name), HAILO_NOT_FOUND); + return m_min_threshold_per_stream[stream_name].load(); +} + +uint16_t ScheduledNetworkGroup::get_max_batch_size() +{ + if (!use_dynamic_batch_flow()) { + return SINGLE_CONTEXT_BATCH_SIZE; + } + return m_max_batch_size; +} + +Counter &ScheduledNetworkGroup::requested_write_frames() +{ + return m_requested_write_frames; +} + +std::atomic_uint32_t &ScheduledNetworkGroup::requested_write_frames(const stream_name_t &stream_name) +{ + return m_requested_write_frames[stream_name]; +} + +uint32_t ScheduledNetworkGroup::requested_write_frames_max_value() +{ + return m_requested_write_frames.get_max_value(); +} + +Counter &ScheduledNetworkGroup::finished_write_frames() +{ + return m_finished_write_frames; +} + +std::atomic_uint32_t &ScheduledNetworkGroup::finished_write_frames(const stream_name_t &stream_name) +{ + return m_finished_write_frames[stream_name]; +} + +uint32_t ScheduledNetworkGroup::finished_write_frames_min_value() +{ + return m_finished_write_frames.get_min_value(); +} + +Counter &ScheduledNetworkGroup::h2d_requested_transferred_frames() +{ + return m_h2d_requested_transferred_frames; +} + +std::atomic_uint32_t &ScheduledNetworkGroup::h2d_requested_transferred_frames(const stream_name_t &stream_name) +{ + return m_h2d_requested_transferred_frames[stream_name]; +} + +Counter &ScheduledNetworkGroup::h2d_finished_transferred_frames() +{ + return m_h2d_finished_transferred_frames; +} + +std::atomic_uint32_t &ScheduledNetworkGroup::h2d_finished_transferred_frames(const stream_name_t &stream_name) +{ + return m_h2d_finished_transferred_frames[stream_name]; +} + +Counter &ScheduledNetworkGroup::requested_read_frames() +{ + return m_requested_read_frames; +} + +std::atomic_uint32_t &ScheduledNetworkGroup::requested_read_frames(const stream_name_t &stream_name) +{ + return m_requested_read_frames[stream_name]; +} + +Counter &ScheduledNetworkGroup::ongoing_read_frames() +{ + return m_ongoing_read_frames; +} + +std::atomic_uint32_t &ScheduledNetworkGroup::ongoing_read_frames(const stream_name_t &stream_name) +{ + return m_ongoing_read_frames[stream_name]; +} + +Counter &ScheduledNetworkGroup::d2h_finished_transferred_frames() +{ + return m_d2h_finished_transferred_frames; +} + +std::atomic_uint32_t &ScheduledNetworkGroup::d2h_finished_transferred_frames(const stream_name_t &stream_name) +{ + return m_d2h_finished_transferred_frames[stream_name]; +} + +Counter &ScheduledNetworkGroup::finished_read_frames() +{ + return m_finished_read_frames; +} + +std::atomic_uint32_t &ScheduledNetworkGroup::finished_read_frames(const stream_name_t &stream_name) +{ + return m_finished_read_frames[stream_name]; +} + +uint32_t ScheduledNetworkGroup::finished_read_frames_min_value() +{ + return m_finished_read_frames.get_min_value(); +} + +const std::vector &ScheduledNetworkGroup::get_inputs_names() +{ + return m_inputs_names; +} + +const std::vector &ScheduledNetworkGroup::get_outputs_names() +{ + return m_outputs_names; +} + +void ScheduledNetworkGroup::push_device_index(uint32_t device_index) +{ + for (auto& stream_name : get_outputs_names()) { + m_output_streams_read_orders[stream_name].push(device_index); + } +} + +uint32_t ScheduledNetworkGroup::pop_device_index(const stream_name_t &stream_name) +{ + assert(contains(m_output_streams_read_orders, stream_name)); + assert(!m_output_streams_read_orders[stream_name].empty()); + auto device_index = m_output_streams_read_orders[stream_name].front(); + m_output_streams_read_orders[stream_name].pop(); + + return device_index; +} + +} /* namespace hailort */ diff --git a/hailort/libhailort/src/scheduled_network_group.hpp b/hailort/libhailort/src/scheduled_network_group.hpp new file mode 100644 index 0000000..bd0b149 --- /dev/null +++ b/hailort/libhailort/src/scheduled_network_group.hpp @@ -0,0 +1,210 @@ +/** + * Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved. + * Distributed under the MIT license (https://opensource.org/licenses/MIT) + **/ +/** + * @file network_group_scheduler.hpp + * @brief Class declaration for NetworkGroupScheduler that schedules network groups to be active depending on the scheduling algorithm. + **/ + +#ifndef _HAILO_SCHEDULED_NETWORK_GROUP_HPP_ +#define _HAILO_SCHEDULED_NETWORK_GROUP_HPP_ + +#include "hailo/hailort.h" +#include "hailo/expected.hpp" +#include "hailo/network_group.hpp" +#include "common/utils.hpp" +#include "common/filesystem.hpp" +#include "scheduler_mon.hpp" + +#include +#include + + +namespace hailort +{ + +#define DEFAULT_SCHEDULER_TIMEOUT (std::chrono::milliseconds(0)) +#define DEFAULT_SCHEDULER_MIN_THRESHOLD (0) + +using stream_name_t = std::string; + +#define SINGLE_CONTEXT_BATCH_SIZE (1) + +class Counter +{ +public: + Counter() : m_map() + {}; + + void insert(const stream_name_t &name) + { + assert(!contains(m_map, name)); + m_map[name] = 0; + } + + std::atomic_uint32_t &operator [](const stream_name_t &name) + { + assert(contains(m_map, name)); + return m_map[name]; + } + + void increase(const stream_name_t &name) + { + assert(contains(m_map, name)); + m_map[name]++; + } + + void decrease(const stream_name_t &name) + { + assert(contains(m_map, name)); + if (0 != m_map[name]) { + m_map[name]--; + } + } + + uint32_t get_min_value() + { + return get_min_value_of_unordered_map(m_map); + } + + uint32_t get_max_value() + { + return get_max_value_of_unordered_map(m_map); + } + + bool all_values_bigger_or_equal(uint32_t value) + { + for (const auto &pair : m_map) { + if (value > pair.second) { + return false; + } + } + return true; + } + + bool empty() + { + for (const auto &pair : m_map) { + if (0 != pair.second) { + return false; + } + } + return true; + } + +private: + std::unordered_map m_map; +}; + +class ScheduledNetworkGroup +{ +public: + static Expected> create(std::shared_ptr added_cng, StreamInfoVector &stream_infos); + + virtual ~ScheduledNetworkGroup() = default; + ScheduledNetworkGroup(const ScheduledNetworkGroup &other) = delete; + ScheduledNetworkGroup &operator=(const ScheduledNetworkGroup &other) = delete; + ScheduledNetworkGroup &operator=(ScheduledNetworkGroup &&other) = delete; + ScheduledNetworkGroup(ScheduledNetworkGroup &&other) noexcept = delete; + + bool has_enough_space_in_read_buffers(uint32_t ongoing_frames); + bool has_input_written_most_frames(const std::string &stream_name); + std::unordered_map total_written_frames_count(); + bool has_pending_frames(); + bool can_stream_read(const std::string &stream_name); + bool use_dynamic_batch_flow(); + bool has_ng_drained_everything(bool streaming_mode); + void decrease_current_ng_counters(); + uint32_t get_pre_transfer_h2d_frames_count(); + + std::string get_network_group_name(); + uint32_t get_h2d_transferred_frames_count(); + + std::shared_ptr get_network_group(); + + void mark_frame_sent(); + + std::chrono::time_point get_last_run_timestamp(); + void set_last_run_timestamp(const std::chrono::time_point ×tamp); + + Expected get_timeout(const stream_name_t &stream_name = ""); + hailo_status set_timeout(const std::chrono::milliseconds &timeout, const stream_name_t &stream_name = ""); + Expected get_threshold(const stream_name_t &stream_name); + hailo_status set_threshold(uint32_t threshold, const stream_name_t &stream_name = ""); + + uint16_t get_max_batch_size(); + + Counter &requested_write_frames(); + std::atomic_uint32_t &requested_write_frames(const stream_name_t &stream_name); + uint32_t requested_write_frames_max_value(); + Counter &finished_write_frames(); + std::atomic_uint32_t &finished_write_frames(const stream_name_t &stream_name); + uint32_t finished_write_frames_min_value(); + + Counter &h2d_requested_transferred_frames(); + std::atomic_uint32_t &h2d_requested_transferred_frames(const stream_name_t &stream_name); + Counter &h2d_finished_transferred_frames(); + std::atomic_uint32_t &h2d_finished_transferred_frames(const stream_name_t &stream_name); + + Counter &requested_read_frames(); + std::atomic_uint32_t &requested_read_frames(const stream_name_t &stream_name); + Counter &ongoing_read_frames(); + std::atomic_uint32_t &ongoing_read_frames(const stream_name_t &stream_name); + + Counter &d2h_finished_transferred_frames(); + std::atomic_uint32_t &d2h_finished_transferred_frames(const stream_name_t &stream_name); + Counter &finished_read_frames(); + std::atomic_uint32_t &finished_read_frames(const stream_name_t &stream_name); + uint32_t finished_read_frames_min_value(); + + const std::vector &get_outputs_names(); + const std::vector &get_inputs_names(); + + bool is_nms() + { + return m_is_nms; + } + + void push_device_index(uint32_t device_index); + uint32_t pop_device_index(const stream_name_t &stream_name); + + ScheduledNetworkGroup(std::shared_ptr cng, std::chrono::milliseconds timeout, + uint16_t max_batch_size, StreamInfoVector &stream_infos, std::string network_group_name); + +private: + std::shared_ptr m_cng; + + std::chrono::time_point m_last_run_time_stamp; + std::chrono::milliseconds m_timeout; + + std::atomic_bool m_frame_was_sent; + uint16_t m_max_batch_size; + + Counter m_requested_write_frames; // 'wait_for_write()' has been called + Counter m_finished_write_frames; // 'signal_finished_write()' has been called - frame is written in buffer (writes are a-sync) + + Counter m_h2d_requested_transferred_frames; // 'send_pending_buffer()' has been called + Counter m_h2d_finished_transferred_frames; // Frame has been transferred to device (intrpt was raised) + + Counter m_requested_read_frames; // 'wait_for_read()' has been called + Counter m_ongoing_read_frames; // 'wait_for_read()' has finished, the user is blocking on read (reads are sync) + + Counter m_d2h_finished_transferred_frames; // Frame has been transferred from device (intrpt was raised) + Counter m_finished_read_frames; // 'signal_finish_read()' has been called - user finished getting the frame + + std::unordered_map m_min_threshold_per_stream; + + std::string m_network_group_name; + + std::vector m_inputs_names; + std::vector m_outputs_names; + + std::unordered_map> m_output_streams_read_orders; + + bool m_is_nms; +}; + +} /* namespace hailort */ + +#endif /* _HAILO_SCHEDULED_NETWORK_GROUP_HPP_ */ diff --git a/hailort/libhailort/src/scheduled_stream.hpp b/hailort/libhailort/src/scheduled_stream.hpp new file mode 100644 index 0000000..1cec64d --- /dev/null +++ b/hailort/libhailort/src/scheduled_stream.hpp @@ -0,0 +1,115 @@ +/** + * Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved. + * Distributed under the MIT license (https://opensource.org/licenses/MIT) + **/ +/** + * @file scheduled_stream.hpp + * @brief Internal stream implementation for scheduled streams + * + **/ + +#ifndef HAILO_SCHEDULED_STREAM_HPP_ +#define HAILO_SCHEDULED_STREAM_HPP_ + +#include "stream_internal.hpp" +#include "hailo/hailort.h" +#include "vdevice_internal.hpp" +#include "vdma_device.hpp" +#include "vdevice_stream.hpp" +#include "hailo/expected.hpp" + +namespace hailort +{ + +class ScheduledInputStream : public InputVDeviceBaseStream { +public: + ScheduledInputStream(ScheduledInputStream &&other) : + InputVDeviceBaseStream(std::move(other)), + m_network_group_handle(std::move(other.m_network_group_handle)), + m_network_group_scheduler(std::move(other.m_network_group_scheduler)) + {} + + explicit ScheduledInputStream( + std::vector> &&streams, + const scheduler_ng_handle_t &network_group_handle, + EventPtr &&network_group_activated_event, + const LayerInfo &layer_info, + NetworkGroupSchedulerWeakPtr network_group_scheduler, + hailo_status &status) : + InputVDeviceBaseStream(std::move(streams), std::move(network_group_activated_event), layer_info, status), + m_network_group_handle(network_group_handle), + m_network_group_scheduler(network_group_scheduler) + {} + + virtual hailo_status abort() override; + virtual hailo_status clear_abort() override; + virtual bool is_scheduled() override { return true; }; + + virtual void notify_all() override + { + auto scheduler = m_network_group_scheduler.lock(); + if (nullptr == scheduler) { + LOGGER__CRITICAL("Failed to acquire scheduler"); + return; + } + scheduler->notify_all(); + + for (auto &stream : m_streams) { + stream.get().notify_all(); + } + } + +protected: + virtual Expected sync_write_raw_buffer(const MemoryView &buffer, + const std::function &should_cancel = []() { return false; }); + + Expected sync_write_raw_buffer_impl(const MemoryView &buffer, scheduler_ng_handle_t network_group_handle, + const std::function &should_cancel); + + scheduler_ng_handle_t m_network_group_handle; + NetworkGroupSchedulerWeakPtr m_network_group_scheduler; + +private: + hailo_status abort_impl(scheduler_ng_handle_t network_group_handle); + hailo_status clear_abort_impl(scheduler_ng_handle_t network_group_handle); +}; + +class ScheduledOutputStream : public OutputVDeviceBaseStream { +public: + ScheduledOutputStream(ScheduledOutputStream &&other) : + OutputVDeviceBaseStream(std::move(other)), + m_network_group_handle(std::move(other.m_network_group_handle)), + m_network_group_scheduler(std::move(other.m_network_group_scheduler)) + {} + + explicit ScheduledOutputStream( + std::vector> &&streams, + const scheduler_ng_handle_t &network_group_handle, + const LayerInfo &layer_info, + EventPtr &&network_group_activated_event, + NetworkGroupSchedulerWeakPtr network_group_scheduler, + hailo_status &status) : + OutputVDeviceBaseStream(std::move(streams), layer_info, std::move(network_group_activated_event), status), + m_network_group_handle(network_group_handle), + m_network_group_scheduler(network_group_scheduler) + {} + + virtual hailo_status abort() override; + virtual hailo_status clear_abort() override; + virtual bool is_scheduled() override { return true; }; + +protected: + virtual hailo_status read(MemoryView buffer) override; + hailo_status read_impl(MemoryView buffer, scheduler_ng_handle_t network_group_handle); + + scheduler_ng_handle_t m_network_group_handle; + NetworkGroupSchedulerWeakPtr m_network_group_scheduler; + +private: + hailo_status abort_impl(scheduler_ng_handle_t network_group_handle); + hailo_status clear_abort_impl(scheduler_ng_handle_t network_group_handle); +}; + +} /* namespace hailort */ + +#endif /* HAILO_SCHEDULED_STREAM_HPP_ */ diff --git a/hailort/libhailort/src/scheduler_oracle.cpp b/hailort/libhailort/src/scheduler_oracle.cpp new file mode 100644 index 0000000..a375bbe --- /dev/null +++ b/hailort/libhailort/src/scheduler_oracle.cpp @@ -0,0 +1,74 @@ +/** + * Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved. + * Distributed under the MIT license (https://opensource.org/licenses/MIT) + **/ +/** + * @file scheduler_oracle.cpp + * @brief: + **/ + +#include "scheduler_oracle.hpp" +#include "tracer_macros.hpp" + +namespace hailort +{ + +bool NetworkGroupSchedulerOracle::choose_next_model(NetworkGroupScheduler &scheduler, uint32_t device_id) +{ + auto cngs_size = scheduler.m_cngs.size(); + auto& device_info = scheduler.m_devices[device_id]; + for (uint32_t i = 0; i < cngs_size; i++) { + uint32_t index = scheduler.m_last_choosen_network_group + i + 1; + index %= static_cast(cngs_size); + auto ready_info = scheduler.is_network_group_ready(index, true, device_id); + if (ready_info.is_ready) { + TRACE(ChooseNetworkGroupTrace, "", index, ready_info.threshold, ready_info.timeout); + device_info->is_switching_network_group = true; + device_info->next_network_group_handle = index; + scheduler.m_last_choosen_network_group = index; + return true; + } + } + return false; +} + +// TODO: return device handle instead index +uint32_t NetworkGroupSchedulerOracle::get_avail_device(NetworkGroupScheduler &scheduler, scheduler_ng_handle_t network_group_handle) +{ + const bool check_threshold = false; + + // Check if should be next + /* Checking (INVALID_NETWORK_GROUP_HANDLE == m_current_network_group) for activating the first time the scheduler is running. + In this case we don't want to check threshold. */ + for (auto active_device_info : scheduler.m_devices) { + if (active_device_info->is_switching_network_group && scheduler.has_ng_drained_everything(active_device_info->current_network_group_handle, active_device_info->device_id) && + (((INVALID_NETWORK_GROUP_HANDLE == active_device_info->current_network_group_handle) && + scheduler.is_network_group_ready(network_group_handle, check_threshold, active_device_info->device_id).is_ready) || + (active_device_info->next_network_group_handle == network_group_handle))) { + return active_device_info->device_id; + } + } + + // Check if device Idle with this network active + for (auto active_device_info : scheduler.m_devices) { + if ((active_device_info->current_network_group_handle == network_group_handle) && !active_device_info->is_switching_network_group && + scheduler.has_ng_drained_everything(active_device_info->current_network_group_handle, active_device_info->device_id) && + scheduler.is_network_group_ready(network_group_handle, check_threshold, active_device_info->device_id).is_ready) { + scheduler.m_last_choosen_network_group = network_group_handle; + return active_device_info->device_id; + } + } + + // Check if device Idle + for (auto active_device_info : scheduler.m_devices) { + if (!active_device_info->is_switching_network_group && scheduler.has_ng_drained_everything(active_device_info->current_network_group_handle, active_device_info->device_id) && + scheduler.is_network_group_ready(network_group_handle, check_threshold, active_device_info->device_id).is_ready) { + scheduler.m_last_choosen_network_group = network_group_handle; + return active_device_info->device_id; + } + } + + return INVALID_DEVICE_ID; +} + +} /* namespace hailort */ diff --git a/hailort/libhailort/src/scheduler_oracle.hpp b/hailort/libhailort/src/scheduler_oracle.hpp new file mode 100644 index 0000000..df1bedf --- /dev/null +++ b/hailort/libhailort/src/scheduler_oracle.hpp @@ -0,0 +1,34 @@ +/** + * Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved. + * Distributed under the MIT license (https://opensource.org/licenses/MIT) + **/ +/** + * @file scheduler_oracle.hpp + * @brief + **/ + +#ifndef _HAILO_SCHEDULER_ORACLE_HPP_ +#define _HAILO_SCHEDULER_ORACLE_HPP_ + +#include "hailo/hailort.h" +#include "hailo/expected.hpp" +#include "hailo/network_group.hpp" +#include "common/utils.hpp" +#include "network_group_scheduler.hpp" + +namespace hailort +{ + +class NetworkGroupSchedulerOracle +{ +public: + static bool choose_next_model(NetworkGroupScheduler &scheduler, uint32_t device_id); + static uint32_t get_avail_device(NetworkGroupScheduler &scheduler, scheduler_ng_handle_t network_group_handle); + +private: + NetworkGroupSchedulerOracle() {} +}; + +} /* namespace hailort */ + +#endif /* _HAILO_SCHEDULER_ORACLE_HPP_ */ diff --git a/hailort/libhailort/src/stream.cpp b/hailort/libhailort/src/stream.cpp index d758a69..32e5951 100644 --- a/hailort/libhailort/src/stream.cpp +++ b/hailort/libhailort/src/stream.cpp @@ -12,8 +12,6 @@ #include "hailo/hailort_common.hpp" #include "hailo/transform.hpp" #include "common/utils.hpp" -#include "hef_internal.hpp" -#include "microprofile.h" #include @@ -27,16 +25,13 @@ hailo_status InputStream::flush() hailo_status InputStream::write(const MemoryView &buffer) { - MICROPROFILE_SCOPEI("Stream", "Write", 0); CHECK((buffer.size() % get_info().hw_frame_size) == 0, HAILO_INVALID_ARGUMENT, "write size {} must be a multiple of hw size {}", buffer.size(), get_info().hw_frame_size); CHECK(((buffer.size() % HailoRTCommon::HW_DATA_ALIGNMENT) == 0), HAILO_INVALID_ARGUMENT, "Input must be aligned to {} (got {})", HailoRTCommon::HW_DATA_ALIGNMENT, buffer.size()); - auto status = sync_write_all_raw_buffer_no_transform_impl(const_cast(buffer.data()), 0, buffer.size()); - MicroProfileFlip(nullptr); - return status; + return sync_write_all_raw_buffer_no_transform_impl(const_cast(buffer.data()), 0, buffer.size()); } std::string InputStream::to_string() const @@ -73,7 +68,7 @@ hailo_status OutputStream::read_nms(void *buffer, size_t offset, size_t size) for (;;) { MemoryView buffer_view(static_cast(buffer) + offset, transfer_size); auto expected_bytes_read = sync_read_raw_buffer(buffer_view); - if ((HAILO_STREAM_INTERNAL_ABORT == expected_bytes_read.status()) || + if ((HAILO_STREAM_ABORTED_BY_USER == expected_bytes_read.status()) || ((HAILO_STREAM_NOT_ACTIVATED == expected_bytes_read.status()))) { return expected_bytes_read.status(); } @@ -104,7 +99,6 @@ hailo_status OutputStream::read_nms(void *buffer, size_t offset, size_t size) hailo_status OutputStream::read(MemoryView buffer) { - MICROPROFILE_SCOPEI("Stream", "Read", 0); CHECK((buffer.size() % get_info().hw_frame_size) == 0, HAILO_INVALID_ARGUMENT, "When read size {} must be a multiple of hw size {}", buffer.size(), get_info().hw_frame_size); diff --git a/hailort/libhailort/src/stream_internal.hpp b/hailort/libhailort/src/stream_internal.hpp index 51d9f60..5ea1a1e 100644 --- a/hailort/libhailort/src/stream_internal.hpp +++ b/hailort/libhailort/src/stream_internal.hpp @@ -70,9 +70,10 @@ public: return m_nn_stream_config; }; - virtual Expected send_pending_buffer() + virtual hailo_status send_pending_buffer(size_t device_index = 0) { - return make_unexpected(HAILO_INVALID_OPERATION); + (void)device_index; + return HAILO_INVALID_OPERATION; } virtual Expected get_buffer_frames_size() const diff --git a/hailort/libhailort/src/tracer.cpp b/hailort/libhailort/src/tracer.cpp new file mode 100644 index 0000000..28982a7 --- /dev/null +++ b/hailort/libhailort/src/tracer.cpp @@ -0,0 +1,232 @@ +/** + * Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved. + * Distributed under the MIT license (https://opensource.org/licenses/MIT) + **/ +/** + * @file tracer.cpp + * @brief: Tracing mechanism for HailoRT + FW events + * + **/ + + +#include "tracer.hpp" +#include "common/utils.hpp" +#include "hailort_logger.hpp" + +#include +#include +#include +#include + +#include +#include + +#define SCHEDULER_PROFILER_NAME ("SchedulerProfiler") +#define SCHEDULER_PROFILER_LOGGER_FILENAME ("scheduler_profiler.json") +#define SCHEDULER_PROFILER_LOGGER_PATTERN ("%v") + +#define SCHEDULER_PROFILER_LOGGER_PATH ("SCHEDULER_PROFILER_LOGGER_PATH") + +#define PROFILER_ENV_VAR ("HAILO_ENABLE_PROFILER") + +namespace hailort +{ + +Tracer::Tracer() +{ + auto should_trace_env = std::getenv(PROFILER_ENV_VAR); + m_should_trace = ((nullptr != should_trace_env) && (strnlen(should_trace_env, 2) == 1) && (strncmp(should_trace_env, "1", 1) == 0)); + if (m_should_trace) { + m_start_time = std::chrono::high_resolution_clock::now(); + int64_t time_since_epoch = std::chrono::duration_cast(m_start_time.time_since_epoch()).count(); + m_handlers.push_back(std::make_unique(time_since_epoch)); + } +} + +SchedulerProfilerHandler::SchedulerProfilerHandler(int64_t &start_time) +#ifndef __ANDROID__ + : m_file_sink(HailoRTLogger::create_file_sink(HailoRTLogger::get_log_path(SCHEDULER_PROFILER_LOGGER_PATH), SCHEDULER_PROFILER_LOGGER_FILENAME, false)), + m_first_write(true) +#endif +{ +#ifndef __ANDROID__ + spdlog::sinks_init_list sink_list = { m_file_sink }; + m_profiler_logger = make_shared_nothrow(SCHEDULER_PROFILER_NAME, sink_list.begin(), sink_list.end()); + m_file_sink->set_level(spdlog::level::level_enum::info); + m_file_sink->set_pattern(SCHEDULER_PROFILER_LOGGER_PATTERN); + std::stringstream ss; + ss << "{\"ms_since_epoch_zero_time\": \"" << start_time << "\",\n\"scheduler_actions\": [\n"; + m_profiler_logger->info(ss.str()); +#else + (void)start_time; +#endif +} + +SchedulerProfilerHandler::~SchedulerProfilerHandler() +{ + m_profiler_logger->info("]\n}"); +} + +struct JSON +{ + std::unordered_map members; + JSON(const std::initializer_list> &dict) : members{dict} {} + JSON(const std::unordered_map &dict) { + for (auto &pair : dict) { + members.insert({pair.first, std::to_string(pair.second)}); + } + } +}; + +template +std::string json_to_string(const T &val) { + return std::to_string(val); +} + +template<> +std::string json_to_string(const std::string &val) { + std::ostringstream os; + os << std::quoted(val); + return os.str(); +} + +template<> +std::string json_to_string(const bool &bool_val) { + return bool_val ? "true" : "false"; +} + +template<> +std::string json_to_string(const JSON &json_val) { + std::ostringstream os; + os << "{\n"; + size_t i = 0; + for (const auto &kv : json_val.members) { + ++i; + os << std::quoted(kv.first) << " : "; + os << kv.second; + if (i != json_val.members.size()) { + os << ",\n"; + } + } + os << "\n}"; + return os.str(); +} + +bool SchedulerProfilerHandler::comma() +{ + auto result = !m_first_write; + m_first_write = false; + return result; +} + +void SchedulerProfilerHandler::log(JSON json) +{ + m_profiler_logger->info("{}{}", comma() ? ",\n" : "", json_to_string(json)); +} + +void SchedulerProfilerHandler::handle_trace(const AddNetworkGroupTrace &trace) +{ + log(JSON({ + {"action", json_to_string(trace.name)}, + {"timestamp", json_to_string(trace.timestamp)}, + {"device_id", json_to_string(trace.device_id)}, + {"network_group_name", json_to_string(trace.network_group_name)}, + {"network_group_handle", json_to_string(trace.network_group_handle)}, + {"timeout", json_to_string((uint64_t)trace.timeout)}, + {"threshold", json_to_string((uint64_t)trace.threshold)} + })); +} + +void SchedulerProfilerHandler::handle_trace(const CreateNetworkGroupInputStreamsTrace &trace) +{ + log(JSON({ + {"action", json_to_string(trace.name)}, + {"timestamp", json_to_string(trace.timestamp)}, + {"device_id", json_to_string(trace.device_id)}, + {"network_group_name", json_to_string(trace.network_group_name)}, + {"stream_name", json_to_string(trace.stream_name)}, + {"queue_size", json_to_string(trace.queue_size)} + })); +} + +void SchedulerProfilerHandler::handle_trace(const CreateNetworkGroupOutputStreamsTrace &trace) +{ + log(JSON({ + {"action", json_to_string(trace.name)}, + {"timestamp", json_to_string(trace.timestamp)}, + {"device_id", json_to_string(trace.device_id)}, + {"network_group_name", json_to_string(trace.network_group_name)}, + {"stream_name", json_to_string(trace.stream_name)}, + {"queue_size", json_to_string(trace.queue_size)} + })); +} + +void SchedulerProfilerHandler::handle_trace(const WriteFrameTrace &trace) +{ + log(JSON({ + {"action", json_to_string(trace.name)}, + {"timestamp", json_to_string(trace.timestamp)}, + {"device_id", json_to_string(trace.device_id)}, + {"network_group_handle", json_to_string(trace.network_group_handle)}, + {"queue_name", json_to_string(trace.queue_name)} + })); +} + +void SchedulerProfilerHandler::handle_trace(const InputVdmaEnqueueTrace &trace) +{ + log(JSON({ + {"action", json_to_string(trace.name)}, + {"timestamp", json_to_string(trace.timestamp)}, + {"device_id", json_to_string(trace.device_id)}, + {"network_group_handle", json_to_string(trace.network_group_handle)}, + {"queue_name", json_to_string(trace.queue_name)} + })); +} + +void SchedulerProfilerHandler::handle_trace(const ReadFrameTrace &trace) +{ + log(JSON({ + {"action", json_to_string(trace.name)}, + {"timestamp", json_to_string(trace.timestamp)}, + {"device_id", json_to_string(trace.device_id)}, + {"network_group_handle", json_to_string(trace.network_group_handle)}, + {"queue_name", json_to_string(trace.queue_name)} + })); +} + +void SchedulerProfilerHandler::handle_trace(const OutputVdmaEnqueueTrace &trace) +{ + log(JSON({ + {"action", json_to_string(trace.name)}, + {"timestamp", json_to_string(trace.timestamp)}, + {"device_id", json_to_string(trace.device_id)}, + {"network_group_handle", json_to_string(trace.network_group_handle)}, + {"queue_name", json_to_string(trace.queue_name)}, + {"frames", json_to_string(trace.frames)} + })); +} + +void SchedulerProfilerHandler::handle_trace(const ChooseNetworkGroupTrace &trace) +{ + log(JSON({ + {"action", json_to_string(trace.name)}, + {"timestamp", json_to_string(trace.timestamp)}, + {"device_id", json_to_string(trace.device_id)}, + {"chosen_network_group_handle", json_to_string(trace.network_group_handle)}, + {"threshold", json_to_string(trace.threshold)}, + {"timeout", json_to_string(trace.timeout)} + })); +} + +void SchedulerProfilerHandler::handle_trace(const SwitchNetworkGroupTrace &trace) +{ + log(JSON({ + {"action", json_to_string(trace.name)}, + {"timestamp", json_to_string(trace.timestamp)}, + {"device_id", json_to_string(trace.device_id)}, + {"network_group_handle", json_to_string(trace.network_group_handle)} + })); +} + + +} diff --git a/hailort/libhailort/src/tracer.hpp b/hailort/libhailort/src/tracer.hpp new file mode 100644 index 0000000..76caf36 --- /dev/null +++ b/hailort/libhailort/src/tracer.hpp @@ -0,0 +1,240 @@ +/** + * Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved. + * Distributed under the MIT license (https://opensource.org/licenses/MIT) + **/ +/** + * @file tracer.hpp + * @brief Tracing mechanism for HailoRT + FW events + **/ + +#ifndef _HAILO_TRACER_HPP_ +#define _HAILO_TRACER_HPP_ + +#include "hailo/hailort.h" +#include "common/logger_macros.hpp" +#include "network_group_scheduler.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace hailort +{ + +struct Trace +{ + Trace(const std::string &name) + : name(name) + {} + + virtual ~Trace() = default; + + uint64_t timestamp = 0; + std::string name; +}; + +struct InitTrace : Trace +{ + InitTrace() : Trace("init") {} +}; + +struct AddNetworkGroupTrace : Trace +{ + AddNetworkGroupTrace(const std::string &device_id, const std::string &network_group_name, uint64_t timeout, uint32_t threshold, scheduler_ng_handle_t handle) + : Trace("add_network_group"), device_id(device_id), network_group_name(network_group_name), timeout(timeout), threshold(threshold), network_group_handle(handle) + {} + + std::string device_id; + std::string network_group_name; + uint64_t timeout = 0; + uint32_t threshold = 0; + scheduler_ng_handle_t network_group_handle = INVALID_NETWORK_GROUP_HANDLE; +}; + +struct CreateNetworkGroupInputStreamsTrace : Trace +{ + CreateNetworkGroupInputStreamsTrace(const std::string &device_id, const std::string &network_group_name, const std::string &stream_name, uint32_t queue_size) + : Trace("create_input_stream"), device_id(device_id), network_group_name(network_group_name), stream_name(stream_name), queue_size(queue_size) + {} + + std::string device_id; + std::string network_group_name; + std::string stream_name; + uint32_t queue_size; +}; + +struct CreateNetworkGroupOutputStreamsTrace : Trace +{ + CreateNetworkGroupOutputStreamsTrace(const std::string &device_id, const std::string &network_group_name, const std::string &stream_name, uint32_t queue_size) + : Trace("create_output_stream"), device_id(device_id), network_group_name(network_group_name), stream_name(stream_name), queue_size(queue_size) + {} + + std::string device_id; + std::string network_group_name; + std::string stream_name; + uint32_t queue_size; +}; + +struct WriteFrameTrace : Trace +{ + WriteFrameTrace(const std::string &device_id, scheduler_ng_handle_t network_group_handle, const std::string &queue_name) + : Trace("wrte_frame"), device_id(device_id), network_group_handle(network_group_handle), queue_name(queue_name) + {} + + std::string device_id; + scheduler_ng_handle_t network_group_handle; + std::string queue_name; +}; + +struct InputVdmaEnqueueTrace : Trace +{ + InputVdmaEnqueueTrace(const std::string &device_id, scheduler_ng_handle_t network_group_handle, const std::string &queue_name) + : Trace("input_vdma_enqueue"), device_id(device_id), network_group_handle(network_group_handle), queue_name(queue_name) + {} + + std::string device_id; + scheduler_ng_handle_t network_group_handle; + std::string queue_name; +}; + +struct ReadFrameTrace : Trace +{ + ReadFrameTrace(const std::string &device_id, scheduler_ng_handle_t network_group_handle, const std::string &queue_name) + : Trace("read_frame"), device_id(device_id), network_group_handle(network_group_handle), queue_name(queue_name) + {} + + std::string device_id; + scheduler_ng_handle_t network_group_handle; + std::string queue_name; +}; + +struct OutputVdmaEnqueueTrace : Trace +{ + OutputVdmaEnqueueTrace(const std::string &device_id, scheduler_ng_handle_t network_group_handle, const std::string &queue_name, uint32_t frames) + : Trace("output_vdma_enqueue"), device_id(device_id), network_group_handle(network_group_handle), queue_name(queue_name), frames(frames) + {} + + std::string device_id; + scheduler_ng_handle_t network_group_handle; + std::string queue_name; + uint32_t frames = 0; +}; + +struct ChooseNetworkGroupTrace : Trace +{ + ChooseNetworkGroupTrace(const std::string &device_id, scheduler_ng_handle_t handle, bool threshold, bool timeout) + : Trace("choose_network_group"), device_id(device_id), network_group_handle(handle), threshold(threshold), timeout(timeout) + {} + + std::string device_id; + scheduler_ng_handle_t network_group_handle; + bool threshold = false; + bool timeout = false; +}; + +struct SwitchNetworkGroupTrace : Trace +{ + SwitchNetworkGroupTrace(const std::string &device_id, scheduler_ng_handle_t handle) + : Trace("switch_network_group"), device_id(device_id), network_group_handle(handle) + {} + + std::string device_id; + scheduler_ng_handle_t network_group_handle; +}; + +class Handler +{ +public: + virtual ~Handler() = default; + + virtual void handle_trace(const InitTrace&) {}; + virtual void handle_trace(const AddNetworkGroupTrace&) {}; + virtual void handle_trace(const CreateNetworkGroupInputStreamsTrace&) {}; + virtual void handle_trace(const CreateNetworkGroupOutputStreamsTrace&) {}; + virtual void handle_trace(const WriteFrameTrace&) {}; + virtual void handle_trace(const InputVdmaEnqueueTrace&) {}; + virtual void handle_trace(const ReadFrameTrace&) {}; + virtual void handle_trace(const OutputVdmaEnqueueTrace&) {}; + virtual void handle_trace(const ChooseNetworkGroupTrace&) {}; + virtual void handle_trace(const SwitchNetworkGroupTrace&) {}; +}; + +struct JSON; + +class SchedulerProfilerHandler : public Handler +{ +public: + SchedulerProfilerHandler(SchedulerProfilerHandler const&) = delete; + void operator=(SchedulerProfilerHandler const&) = delete; + + SchedulerProfilerHandler(int64_t &start_time); + ~SchedulerProfilerHandler(); + + virtual void handle_trace(const AddNetworkGroupTrace&) override; + virtual void handle_trace(const CreateNetworkGroupInputStreamsTrace&) override; + virtual void handle_trace(const CreateNetworkGroupOutputStreamsTrace&) override; + virtual void handle_trace(const WriteFrameTrace&) override; + virtual void handle_trace(const InputVdmaEnqueueTrace&) override; + virtual void handle_trace(const ReadFrameTrace&) override; + virtual void handle_trace(const OutputVdmaEnqueueTrace&) override; + virtual void handle_trace(const ChooseNetworkGroupTrace&) override; + virtual void handle_trace(const SwitchNetworkGroupTrace&) override; + +private: + void log(JSON json); + bool comma(); + + std::shared_ptr m_file_sink; + std::shared_ptr m_profiler_logger; + std::atomic m_first_write; +}; + +class Tracer +{ +public: + template + static void trace(Args... trace_args) + { + auto &tracer = get_instance(); + tracer.execute_trace(trace_args...); + } + +private: + Tracer(); + + static Tracer& get_instance() + { + static Tracer tracer; + return tracer; + } + + template + void execute_trace(Args... trace_args) + { + if (!m_should_trace) { + return; + } + + TraceType trace_struct(trace_args...); + auto curr_time = std::chrono::high_resolution_clock::now(); + trace_struct.timestamp = std::chrono::duration_cast(curr_time - this->m_start_time).count(); + for (auto &handler : this->m_handlers) { + handler->handle_trace(trace_struct); + } + } + + bool m_should_trace = false; + std::chrono::high_resolution_clock::time_point m_start_time; + std::vector> m_handlers; +}; + +} + +#endif \ No newline at end of file diff --git a/hailort/libhailort/src/tracer_macros.hpp b/hailort/libhailort/src/tracer_macros.hpp new file mode 100644 index 0000000..757555f --- /dev/null +++ b/hailort/libhailort/src/tracer_macros.hpp @@ -0,0 +1,32 @@ +/** + * Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved. + * Distributed under the MIT license (https://opensource.org/licenses/MIT) + **/ +/** + * @file tracer_macros.hpp + * @brief Macros for tracing mechanism for HailoRT + FW events + **/ + +#ifndef _HAILO_TRACER_MACROS_HPP_ +#define _HAILO_TRACER_MACROS_HPP_ + +#if defined HAILO_ENABLE_PROFILER_BUILD +#include "tracer.hpp" +#endif + +namespace hailort +{ + +struct VoidAll { + template VoidAll(Args const& ...) {} +}; + +#if defined HAILO_ENABLE_PROFILER_BUILD +#define TRACE(type, ...) (Tracer::trace(__VA_ARGS__)) +#else +#define TRACE(type, ...) {VoidAll temporary_name{__VA_ARGS__};} +#endif + +} + +#endif // _HAILO_TRACER_MACROS_HPP_ \ No newline at end of file diff --git a/hailort/libhailort/src/transform.cpp b/hailort/libhailort/src/transform.cpp index ee50d20..799d22b 100644 --- a/hailort/libhailort/src/transform.cpp +++ b/hailort/libhailort/src/transform.cpp @@ -17,7 +17,6 @@ #include "common/logger_macros.hpp" #include "common/utils.hpp" #include "transform_internal.hpp" -#include "microprofile.h" #include #include @@ -52,11 +51,11 @@ bool TransformContextUtils::should_reorder(const hailo_3d_image_shape_t &src_ima { /* If shapes and format are different - need to use transform_context */ - if (!((src_image_shape.features == dst_image_shape.features) && - (src_image_shape.height == dst_image_shape.height) && - (src_image_shape.width == dst_image_shape.width) && - (src_format.order == dst_format.order) && - (src_format.type == dst_format.type))) { + if (!((src_image_shape.features == dst_image_shape.features) && + (src_image_shape.height == dst_image_shape.height) && + (src_image_shape.width == dst_image_shape.width) && + (src_format.order == dst_format.order) && + (src_format.type == dst_format.type))) { return true; } @@ -208,7 +207,7 @@ hailo_status transpose_buffer(const MemoryView src, const hailo_3d_image_shape_t /* Re-Ordering funcs */ -template +template void transform__h2d_NHWC_to_NHWC(const T *src_ptr, hailo_3d_image_shape_t *src_image_shape, T *dst_ptr, hailo_3d_image_shape_t *dst_image_shape) { @@ -230,7 +229,7 @@ void transform__h2d_NHWC_to_NHWC(const T *src_ptr, hailo_3d_image_shape_t *src_i } } -template +template void transform__d2h_NHWC_to_NHWC(const T *src_ptr, hailo_3d_image_shape_t *src_image_shape, T *dst_ptr, hailo_3d_image_shape_t *dst_image_shape) { @@ -251,7 +250,7 @@ void transform__d2h_NHWC_to_NHWC(const T *src_ptr, hailo_3d_image_shape_t *src_i } } -template +template void transform__h2d_NV12_to_NV12(const T *src_ptr, hailo_3d_image_shape_t *src_image_shape, T *dst_ptr, hailo_3d_image_shape_t *dst_image_shape) { /* Validate arguments */ @@ -287,7 +286,7 @@ void transform__h2d_NV12_to_NV12(const T *src_ptr, hailo_3d_image_shape_t *src_i } } -template +template void transform__h2d_NHWC_to_NHCW(const T *src_ptr, hailo_3d_image_shape_t *src_image_shape, T *dst_ptr, hailo_3d_image_shape_t *dst_image_shape) { @@ -319,7 +318,7 @@ void transform__h2d_NHWC_to_NHCW(const T *src_ptr, hailo_3d_image_shape_t *src_i } } -template +template void transform__d2h_NHCW_to_NHWC(const T *src_ptr, hailo_3d_image_shape_t *src_image_shape, T *dst_ptr, hailo_3d_image_shape_t *dst_image_shape) { @@ -343,7 +342,7 @@ void transform__d2h_NHCW_to_NHWC(const T *src_ptr, hailo_3d_image_shape_t *src_i } } -template +template void transform__d2h_NHW_to_NHW(const T *src_ptr, hailo_3d_image_shape_t *src_image_shape, T *dst_ptr, hailo_3d_image_shape_t *dst_image_shape) { @@ -358,7 +357,7 @@ void transform__d2h_NHW_to_NHW(const T *src_ptr, hailo_3d_image_shape_t *src_ima } } -template +template void transform__h2d_NC_to_NC(const T *src_ptr, hailo_3d_image_shape_t *src_image_shape, T *dst_ptr, hailo_3d_image_shape_t *dst_image_shape) { @@ -371,7 +370,7 @@ void transform__h2d_NC_to_NC(const T *src_ptr, hailo_3d_image_shape_t *src_image memset(dst_ptr + src_image_shape->features, 0, (dst_image_shape->features - src_image_shape->features) * sizeof(T)); } -template +template void transform__d2h_NC_to_NC(const T *src_ptr, T *dst_ptr, hailo_3d_image_shape_t *dst_image_shape) { /* Validate arguments */ @@ -448,7 +447,7 @@ void transform__d2h_NMS(const uint8_t *src_ptr, uint8_t *dst_ptr, const hailo_nm } } -template +template void transform__h2d_FCR(const T *src_ptr, hailo_3d_image_shape_t *src_image_shape, T *dst_ptr, hailo_3d_image_shape_t *dst_image_shape) { @@ -474,7 +473,7 @@ void transform__h2d_FCR(const T *src_ptr, hailo_3d_image_shape_t *src_image_shap } } -template +template void transform__h2d_F8CR(const T *src_ptr, hailo_3d_image_shape_t *src_image_shape, T *dst_ptr, hailo_3d_image_shape_t *dst_image_shape) { @@ -511,7 +510,7 @@ void transform__h2d_F8CR(const T *src_ptr, hailo_3d_image_shape_t *src_image_sha } } -template +template void transform__d2h_F8CR(const T *src_ptr, hailo_3d_image_shape_t *src_image_shape, T *dst_ptr, hailo_3d_image_shape_t *dst_image_shape) { @@ -543,7 +542,7 @@ void transform__d2h_F8CR(const T *src_ptr, hailo_3d_image_shape_t *src_image_sha } } -template +template void transform__d2h_BAYER_RGB(const T *src_ptr, hailo_3d_image_shape_t *src_image_shape, T *dst_ptr, hailo_3d_image_shape_t *dst_image_shape) { @@ -561,7 +560,7 @@ void transform__d2h_BAYER_RGB(const T *src_ptr, hailo_3d_image_shape_t *src_imag } } -template +template hailo_status transform__h2d_NHWC_to_RGB888(const T *src_ptr, hailo_3d_image_shape_t *src_image_shape, T *dst_ptr, hailo_3d_image_shape_t *dst_image_shape) { @@ -720,7 +719,7 @@ hailo_status transform__d2h_argmax_NHCW_to_NHW(const T *src_ptr, const hailo_3d_ } -template +template hailo_status transform__h2d_YUY2_to_YUY2(const T *src_ptr, T *dst_ptr, uint32_t shape_size) { /* Validate arguments */ @@ -735,6 +734,71 @@ hailo_status transform__h2d_YUY2_to_YUY2(const T *src_ptr, T *dst_ptr, uint32_t return HAILO_SUCCESS; } +template +hailo_status transform__h2d_RGB4_to_NHWC(const T *src_ptr, const hailo_3d_image_shape_t &src_image_shape, T *dst_ptr, + const hailo_3d_image_shape_t &dst_image_shape) +{ + /* Validate arguments */ + ASSERT(NULL != src_ptr); + ASSERT(NULL != dst_ptr); + + const auto row_size = src_image_shape.width * src_image_shape.features; + const auto src_row_size = HailoRTCommon::align_to(row_size, RGB4_ALIGNMENT); + const auto dst_row_size = dst_image_shape.width * dst_image_shape.features; + + const auto pad_size = (dst_image_shape.width - src_image_shape.width) * dst_image_shape.features; + + uint32_t src_offset = 0; + uint32_t dst_offset = 0; + + for (uint32_t r = 0; r < dst_image_shape.height; r++) { + src_offset = r * src_row_size; + dst_offset = r * dst_row_size; + memcpy(dst_ptr + dst_offset, src_ptr + src_offset, src_row_size * sizeof(T)); + if (pad_size != 0) { + std::fill_n(dst_ptr + dst_offset + src_row_size, pad_size, static_cast(0)); + } + } + + return HAILO_SUCCESS; +} + +template +hailo_status transform__h2d_RGB4_to_NHCW(const T *src_ptr, const hailo_3d_image_shape_t &src_image_shape, T *dst_ptr, + const hailo_3d_image_shape_t &dst_image_shape) +{ + /* Validate arguments */ + ASSERT(NULL != src_ptr); + ASSERT(NULL != dst_ptr); + + const auto row_size = src_image_shape.width * src_image_shape.features; + const auto src_row_size = HailoRTCommon::align_to(row_size, RGB4_ALIGNMENT); + const auto dst_row_size = dst_image_shape.width * dst_image_shape.features; + + const auto pad_size = (dst_image_shape.width - src_image_shape.width) * dst_image_shape.features; + + uint32_t src_offset = 0; + uint32_t dst_offset = 0; + + for (uint32_t r = 0; r < src_image_shape.height ; r++) { + /* transpose - switch width and channels */ + for (uint32_t f = 0; f < src_image_shape.features; f++) { + for (uint32_t c = 0; c < src_image_shape.width; c++) { + src_offset = r * src_row_size + c * src_image_shape.features + f; + dst_offset = r * dst_row_size + f * dst_image_shape.width + c; + dst_ptr[dst_offset] = src_ptr[src_offset]; + } + /* pad feature to 8 elemnts */ + if (pad_size != 0) { + dst_offset = r * dst_row_size + f * dst_image_shape.width + src_image_shape.width; + std::fill_n(dst_ptr + dst_offset, pad_size, static_cast(0)); + } + } + } + + return HAILO_SUCCESS; +} + hailo_status InputTransformContext::quantize_stream(const void *src_ptr, void *quant_buffer) { auto shape_size = HailoRTCommon::get_shape_size(m_src_image_shape); @@ -1009,6 +1073,38 @@ hailo_status reorder_input_stream(const void *src_ptr, hailo_3d_image_shape_t sr return HAILO_SUCCESS; } + if ((HAILO_FORMAT_ORDER_RGB4 == src_format.order) && + (HAILO_FORMAT_ORDER_NHWC == dst_format.order)) { + switch (dst_format.type) { + case HAILO_FORMAT_TYPE_UINT8: + transform__h2d_RGB4_to_NHWC((uint8_t*)src_ptr, src_image_shape, (uint8_t*)dst_ptr, dst_image_shape); + break; + case HAILO_FORMAT_TYPE_UINT16: + transform__h2d_RGB4_to_NHWC((uint16_t*)src_ptr, src_image_shape, (uint16_t*)dst_ptr, dst_image_shape); + break; + default: + LOGGER__ERROR("Invalid src-buffer's type format"); + return HAILO_INVALID_ARGUMENT; + } + return HAILO_SUCCESS; + } + + if ((HAILO_FORMAT_ORDER_RGB4 == src_format.order) && + (HAILO_FORMAT_ORDER_NHCW == dst_format.order)) { + switch (dst_format.type) { + case HAILO_FORMAT_TYPE_UINT8: + transform__h2d_RGB4_to_NHCW((uint8_t*)src_ptr, src_image_shape, (uint8_t*)dst_ptr, dst_image_shape); + break; + case HAILO_FORMAT_TYPE_UINT16: + transform__h2d_RGB4_to_NHCW((uint16_t*)src_ptr, src_image_shape, (uint16_t*)dst_ptr, dst_image_shape); + break; + default: + LOGGER__ERROR("Invalid src-buffer's type format"); + return HAILO_INVALID_ARGUMENT; + } + return HAILO_SUCCESS; + } + LOGGER__ERROR("Unsupported input stream transformation from hailo_format_order_t " "{} to hailo_format_order_t {}", src_format.order, dst_format.order); return HAILO_INVALID_OPERATION; @@ -1298,7 +1394,6 @@ hailo_status FrameOutputTransformContext::transform_inner(const void *src_ptr, v hailo_status transform_demux_raw_frame(const void *src, uint32_t offset, hailo_mux_info_t *mux_info, uint32_t mux_row_count) { - MICROPROFILE_SCOPEI("Transformations", "Demux", 0); // This is a recursive function with a maximum depth of HailoRTCommon::MUX_INFO_COUNT. hailo_status status = HAILO_UNINITIALIZED; struct hailo_mux_info_t *predecessor = NULL; @@ -1539,7 +1634,6 @@ InputTransformContext::InputTransformContext(size_t src_frame_size, const hailo_ hailo_status InputTransformContext::transform(const MemoryView src, MemoryView dst) { - MICROPROFILE_SCOPEI("Transformations", "H2D transform", 0); /* Check sizes */ CHECK(src.size() == m_src_frame_size, HAILO_INVALID_ARGUMENT, "src size must be {}. passed size - {}", m_src_frame_size, src.size()); @@ -1706,7 +1800,6 @@ Expected> NMSOutputTransformContext::cre hailo_status FrameOutputTransformContext::transform(const MemoryView src, MemoryView dst) { - MICROPROFILE_SCOPEI("Transformations", "D2H transform", 0); /* Check sizes */ CHECK(src.size() == m_src_frame_size, HAILO_INVALID_ARGUMENT, "src size must be {}. passed size - {}", m_src_frame_size, src.size()); @@ -1721,7 +1814,6 @@ hailo_status FrameOutputTransformContext::transform(const MemoryView src, Memory hailo_status NMSOutputTransformContext::transform(const MemoryView src, MemoryView dst) { - MICROPROFILE_SCOPEI("Transformations", "D2H NMS transform", 0); /* Check sizes */ CHECK(src.size() == m_src_frame_size, HAILO_INVALID_ARGUMENT, "src size must be {}. passed size - {}", m_src_frame_size, src.size()); @@ -1869,7 +1961,7 @@ hailo_status OutputDemuxerBase::get_mux_info_from_layer_info_impl(hailo_mux_info // This is a recursive function with a maximum depth of HailoRTCommon::MUX_INFO_COUNT. mux_info.info = LayerInfoUtils::get_stream_info_from_layer_info(layer_info); - mux_info.row_size = height_ratio * layer_info.hw_shape.width * layer_info.hw_shape.features; + mux_info.row_size = height_ratio * layer_info.hw_shape.width * layer_info.hw_shape.features * layer_info.hw_data_bytes; mux_info.row_counter = 0; if (mux_info.info.is_mux) { @@ -1898,7 +1990,6 @@ hailo_status OutputDemuxerBase::get_mux_info_from_layer_info_impl(hailo_mux_info hailo_status fuse_buffers(const std::vector &buffers, const std::vector &infos_of_buffers, MemoryView dst) { - MICROPROFILE_SCOPEI("Transformations", "Fuse NMS", 0); CHECK_ARG_NOT_NULL(dst.data()); CHECK(buffers.size() == infos_of_buffers.size(), HAILO_INVALID_ARGUMENT, "Vectors of buffers and NMS infos does not match!"); diff --git a/hailort/libhailort/src/udp.cpp b/hailort/libhailort/src/udp.cpp index d002ac5..b2fc899 100644 --- a/hailort/libhailort/src/udp.cpp +++ b/hailort/libhailort/src/udp.cpp @@ -127,7 +127,7 @@ hailo_status Udp::send(uint8_t *buffer, size_t *size, bool use_padding, size_t m status = m_socket.send_to((const uint8_t*)send_ptr, *size, MSG_CONFIRM, (const struct sockaddr *) &m_device_address, m_device_address_length, &number_of_sent_bytes); - if (HAILO_STREAM_INTERNAL_ABORT == status) { + if (HAILO_STREAM_ABORTED_BY_USER == status) { LOGGER__INFO("Socket send_to was aborted!"); return status; } @@ -159,7 +159,7 @@ hailo_status Udp::recv(uint8_t *buffer, size_t *size) status = m_socket.recv_from(buffer, *size, 0, (struct sockaddr *) &m_device_address, m_device_address_length, &number_of_received_bytes); - if (HAILO_STREAM_INTERNAL_ABORT == status) { + if (HAILO_STREAM_ABORTED_BY_USER == status) { LOGGER__INFO("Socket recv_from was aborted!"); return status; } diff --git a/hailort/libhailort/src/vdevice.cpp b/hailort/libhailort/src/vdevice.cpp index 6509e36..9045718 100644 --- a/hailort/libhailort/src/vdevice.cpp +++ b/hailort/libhailort/src/vdevice.cpp @@ -17,6 +17,7 @@ #include "hailort_defaults.hpp" #include "shared_resource_manager.hpp" #include "context_switch/network_group_internal.hpp" +#include "context_switch/vdevice_network_group.hpp" #ifdef HAILO_SUPPORT_MULTI_PROCESS #include "rpc_client_utils.hpp" @@ -81,6 +82,10 @@ VDeviceHandle::~VDeviceHandle() Expected> VDeviceHandle::create(const hailo_vdevice_params_t ¶ms) { + CHECK_AS_EXPECTED((HAILO_SCHEDULING_ALGORITHM_NONE == params.scheduling_algorithm) + || (1 == params.device_count) || (VDeviceBase::enable_multi_device_schedeulr()), HAILO_NOT_SUPPORTED, + "Multiple devices scheduler feature is preview. To enable it, set env variable 'HAILO_ENABLE_MULTI_DEVICE_SCHEDULER' to 1"); + auto &manager = SharedResourceManager::get_instance(); auto create = [¶ms]() { return VDeviceBase::create(params); @@ -129,6 +134,15 @@ Expected> VDeviceHandle::get_physical_devices_ids() con return vdevice.value()->get_physical_devices_ids(); } +Expected VDeviceHandle::get_default_streams_interface() const +{ + auto &manager = SharedResourceManager::get_instance(); + auto vdevice = manager.resource_lookup(m_handle); + CHECK_EXPECTED(vdevice); + + return vdevice.value()->get_default_streams_interface(); +} + #ifdef HAILO_SUPPORT_MULTI_PROCESS VDeviceClient::VDeviceClient(std::unique_ptr client, uint32_t handle) @@ -184,8 +198,7 @@ Expected VDeviceClient::configure(Hef &hef, Expected>> VDeviceClient::get_physical_devices() const { - // TODO: HRT-6606 - LOGGER__ERROR("get_physical_devices is not supported when using multi process service"); + LOGGER__ERROR("ConfiguredNetworkGroup::get_physical_devices function is not supported when using multi-process service"); return make_unexpected(HAILO_INVALID_OPERATION); } @@ -194,60 +207,23 @@ Expected> VDeviceClient::get_physical_devices_ids() con return m_client->VDevice_get_physical_devices_ids(m_handle); } -#endif // HAILO_SUPPORT_MULTI_PROCESS - -static Expected> convert_device_infos_to_ids(const hailo_vdevice_params_t ¶ms) +Expected VDeviceClient::get_default_streams_interface() const { -IGNORE_DEPRECATION_WARNINGS_BEGIN - assert(params.device_infos != nullptr); - - std::vector device_ids; - for (uint32_t i = 0; i < params.device_count; i++) { - auto device_id_str = Device::pcie_device_info_to_string(params.device_infos[i]); - CHECK_EXPECTED(device_id_str); - - auto device_id_struct = HailoRTCommon::to_device_id(device_id_str.value()); - CHECK_EXPECTED(device_id_struct); + return m_client->VDevice_get_default_streams_interface(m_handle); +} - device_ids.push_back(device_id_struct.release()); - } +#endif // HAILO_SUPPORT_MULTI_PROCESS - return device_ids; -IGNORE_DEPRECATION_WARNINGS_END -} Expected> VDevice::create(const hailo_vdevice_params_t ¶ms) { CHECK_AS_EXPECTED(0 != params.device_count, HAILO_INVALID_ARGUMENT, "VDevice creation failed. invalid device_count ({}).", params.device_count); - CHECK_AS_EXPECTED((HAILO_SCHEDULING_ALGORITHM_NONE == params.scheduling_algorithm) - || (1 == params.device_count), HAILO_INVALID_ARGUMENT, - "Network group scheduler can be active only when using one device in the vDevice!"); - - // Convert device_infos to device_ids -IGNORE_DEPRECATION_WARNINGS_BEGIN - // Save device_ids on this scope to guard the memory. - auto local_params = params; - std::vector device_ids; - if (local_params.device_infos != nullptr) { - CHECK_AS_EXPECTED(local_params.device_ids == nullptr, HAILO_INVALID_ARGUMENT, - "Invalid vdevice params. You can set either device_ids or device_infos"); - LOGGER__WARN("Passing 'device_infos' in 'hailo_vdevice_params_t' is deprecated. One should use 'device_ids'"); - - auto device_ids_expected = convert_device_infos_to_ids(local_params); - CHECK_EXPECTED(device_ids_expected); - - device_ids = device_ids_expected.release(); - local_params.device_ids = device_ids.data(); - local_params.device_infos = nullptr; - } -IGNORE_DEPRECATION_WARNINGS_END - std::unique_ptr vdevice; - if (local_params.multi_process_service) { + if (params.multi_process_service) { #ifdef HAILO_SUPPORT_MULTI_PROCESS - auto expected_vdevice = VDeviceClient::create(local_params); + auto expected_vdevice = VDeviceClient::create(params); CHECK_EXPECTED(expected_vdevice); vdevice = expected_vdevice.release(); #else @@ -255,7 +231,7 @@ IGNORE_DEPRECATION_WARNINGS_END return make_unexpected(HAILO_INVALID_OPERATION); #endif // HAILO_SUPPORT_MULTI_PROCESS } else { - auto expected_vdevice = VDeviceHandle::create(local_params); + auto expected_vdevice = VDeviceHandle::create(params); CHECK_EXPECTED(expected_vdevice); vdevice = expected_vdevice.release(); } @@ -270,23 +246,6 @@ Expected> VDevice::create() return create(params); } -Expected> VDevice::get_physical_devices_infos() const -{ - LOGGER__WARN("VDevice get_physical_devices_infos() is deprecated. one should use get_physical_devices_ids()."); - auto device_ids = get_physical_devices_ids(); - CHECK_EXPECTED(device_ids); - - std::vector device_infos; - device_infos.reserve(device_ids->size()); - for (const auto &device_id : device_ids.value()) { - auto device_info = Device::parse_pcie_device_info(device_id); - CHECK_EXPECTED(device_info); - device_infos.emplace_back(device_info.release()); - } - - return device_infos; -} - Expected> VDevice::create(const std::vector &device_ids) { auto params = HailoRTDefaults::get_vdevice_params(); @@ -305,7 +264,7 @@ Expected> VDeviceBase::create(const hailo_vdevice_p NetworkGroupSchedulerPtr scheduler_ptr; if (HAILO_SCHEDULING_ALGORITHM_NONE != params.scheduling_algorithm) { if (HAILO_SCHEDULING_ALGORITHM_ROUND_ROBIN == params.scheduling_algorithm) { - auto network_group_scheduler = NetworkGroupScheduler::create_round_robin(); + auto network_group_scheduler = NetworkGroupScheduler::create_round_robin(params.device_count); CHECK_EXPECTED(network_group_scheduler); scheduler_ptr = network_group_scheduler.release(); } else { @@ -331,41 +290,116 @@ Expected> VDeviceBase::create(const hailo_vdevice_p return vdevice; } -// TODO - make this function thread-safe. Expected VDeviceBase::configure(Hef &hef, const NetworkGroupsParamsMap &configure_params) { std::unique_lock lock(m_mutex); auto start_time = std::chrono::steady_clock::now(); - if (!m_context_switch_manager) { - auto local_context_switch_manager = VdmaConfigManager::create(*this); - CHECK_EXPECTED(local_context_switch_manager); - m_context_switch_manager = make_unique_nothrow(local_context_switch_manager.release()); - CHECK_AS_EXPECTED(nullptr != m_context_switch_manager, HAILO_OUT_OF_HOST_MEMORY); - } for (auto &device : m_devices) { auto status = device->check_hef_is_compatible(hef); CHECK_SUCCESS_AS_EXPECTED(status); } - auto network_groups = m_context_switch_manager->add_hef(hef, configure_params); - CHECK_EXPECTED(network_groups); + auto local_config_params = configure_params; + if (local_config_params.empty()) { + // All stream iface should be the same + auto stream_interface = m_devices[0]->get_default_streams_interface(); + CHECK_EXPECTED(stream_interface); + auto config_params_exp = hef.create_configure_params(stream_interface.value()); + CHECK_EXPECTED(config_params_exp); + local_config_params = config_params_exp.release(); + } + + /* Validate batch size is identical for all networks in case scheduler is enabled */ + if (m_network_group_scheduler) { + uint16_t ref_batch_size = UINT16_MAX; + for (const auto &ng_params_pair : local_config_params) { + for (const auto &network_params_pair : ng_params_pair.second.network_params_by_name) { + if (UINT16_MAX == ref_batch_size) { + ref_batch_size = network_params_pair.second.batch_size; + } + CHECK_AS_EXPECTED(ref_batch_size == network_params_pair.second.batch_size, HAILO_INVALID_OPERATION, + "When scheduler is enabled, all networks should have the same batch_size. configure_params contains {} and {}. " + "To disable scheduler, set HAILO_SCHEDULING_ALGORITHM_NONE in VDevice creation.", ref_batch_size, network_params_pair.second.batch_size); + } + } + } + + ConfiguredNetworkGroupVector added_network_groups; + added_network_groups.reserve(configure_params.size()); + + for (const auto &network_params_pair : local_config_params) { + std::shared_ptr identical_ng = nullptr; + if (m_network_group_scheduler && PipelineMultiplexer::should_use_multiplexer()) { + for (auto &network_group : m_network_groups) { + if ((network_group->equals(hef, network_params_pair.first)) && (1 == network_group->get_input_streams().size())) { + // TODO (HRT-8634): Support multi-inputs NGs (multi networks) + identical_ng = network_group; + break; + } + } + } + std::shared_ptr vdevice_netwrok_group = nullptr; + if (identical_ng) { + auto vdevice_netwrok_group_exp = VDeviceNetworkGroup::duplicate(identical_ng); + CHECK_EXPECTED(vdevice_netwrok_group_exp); + + vdevice_netwrok_group = vdevice_netwrok_group_exp.release(); + + vdevice_netwrok_group->set_network_group_handle(identical_ng->network_group_handle()); + vdevice_netwrok_group->create_vdevice_streams_from_duplicate(identical_ng); + + } else { + ConfiguredNetworkGroupVector network_group_bundle; // bundle of the same NGs for all devices + network_group_bundle.reserve(m_devices.size()); + + for (auto &device : m_devices) { + auto ng_vector = device->configure(hef, { std::make_pair(network_params_pair.first, network_params_pair.second) }); + CHECK_EXPECTED(ng_vector); + + assert(1 == ng_vector->size()); + network_group_bundle.push_back(ng_vector.release()[0]); + } + + auto vdevice_netwrok_group_exp = VDeviceNetworkGroup::create(network_group_bundle, m_network_group_scheduler); + CHECK_EXPECTED(vdevice_netwrok_group_exp); + + vdevice_netwrok_group = vdevice_netwrok_group_exp.release(); + + auto ng_handle = INVALID_NETWORK_GROUP_HANDLE; + if (m_network_group_scheduler) { + auto network_group_handle_exp = m_network_group_scheduler->add_network_group(vdevice_netwrok_group); + CHECK_EXPECTED(network_group_handle_exp); + ng_handle = network_group_handle_exp.release(); + } + vdevice_netwrok_group->set_network_group_handle(ng_handle); + auto status = vdevice_netwrok_group->create_vdevice_streams_from_config_params(make_shared_nothrow(), ng_handle); + CHECK_SUCCESS_AS_EXPECTED(status); + + m_network_groups.push_back(vdevice_netwrok_group); + } + + added_network_groups.push_back(vdevice_netwrok_group); + } auto elapsed_time_ms = std::chrono::duration(std::chrono::steady_clock::now() - start_time).count(); LOGGER__INFO("Configuring HEF on VDevice took {} milliseconds", elapsed_time_ms); - return network_groups; + return added_network_groups; } -Expected VDeviceBase::get_device_type() +Expected VDeviceBase::get_default_streams_interface() const { - auto device_type = m_devices[0]->get_type(); + auto stream_interface = m_devices[0]->get_default_streams_interface(); + CHECK_EXPECTED(stream_interface); for (auto &dev : m_devices) { - CHECK_AS_EXPECTED(device_type == dev->get_type(), HAILO_INTERNAL_FAILURE, + auto current_stream_interface = dev->get_default_streams_interface(); + CHECK_EXPECTED(current_stream_interface); + CHECK_AS_EXPECTED(*current_stream_interface == *stream_interface, HAILO_INTERNAL_FAILURE, "vDevice is supported only with homogeneous device type"); } - return device_type; + return stream_interface.release(); } Expected>> VDeviceBase::create_devices(const hailo_vdevice_params_t ¶ms) diff --git a/hailort/libhailort/src/vdevice_internal.hpp b/hailort/libhailort/src/vdevice_internal.hpp index c979f89..42c20f4 100644 --- a/hailort/libhailort/src/vdevice_internal.hpp +++ b/hailort/libhailort/src/vdevice_internal.hpp @@ -25,6 +25,7 @@ #include "hailo/vdevice.hpp" #include "vdma_device.hpp" #include "context_switch/multi_context/vdma_config_manager.hpp" +#include "context_switch/vdevice_network_group.hpp" #include "network_group_scheduler.hpp" #ifdef HAILO_SUPPORT_MULTI_PROCESS @@ -74,19 +75,27 @@ public: } // Currently only homogeneous vDevice is allow (= all devices are from the same type) - Expected get_device_type(); + virtual Expected get_default_streams_interface() const override; + + // TODO: Remove when feature becomes 'released' + static bool enable_multi_device_schedeulr() + { + auto enable_multi_device_schedeulr_env = std::getenv(HAILO_ENABLE_MULTI_DEVICE_SCHEDULER); + return ((nullptr != enable_multi_device_schedeulr_env) && + (strnlen(enable_multi_device_schedeulr_env, 2) == 1) && (strncmp(enable_multi_device_schedeulr_env, "1", 1) == 0)); + } private: VDeviceBase(std::vector> &&devices, NetworkGroupSchedulerPtr network_group_scheduler) : - m_devices(std::move(devices)), m_network_group_scheduler(network_group_scheduler) + m_devices(std::move(devices)), m_network_group_scheduler(network_group_scheduler), m_network_groups({}) {} static Expected>> create_devices(const hailo_vdevice_params_t ¶ms); static Expected> get_device_ids(const hailo_vdevice_params_t ¶ms); std::vector> m_devices; - std::unique_ptr m_context_switch_manager; NetworkGroupSchedulerPtr m_network_group_scheduler; + std::vector> m_network_groups; std::mutex m_mutex; }; @@ -109,6 +118,7 @@ public: Expected>> get_physical_devices() const override; Expected> get_physical_devices_ids() const override; + Expected get_default_streams_interface() const override; private: VDeviceClient(std::unique_ptr client, uint32_t handle); @@ -135,6 +145,7 @@ public: Expected>> get_physical_devices() const override; Expected> get_physical_devices_ids() const override; + Expected get_default_streams_interface() const override; private: VDeviceHandle(uint32_t handle); diff --git a/hailort/libhailort/src/vdevice_native_stream.hpp b/hailort/libhailort/src/vdevice_native_stream.hpp new file mode 100644 index 0000000..f1b9ec7 --- /dev/null +++ b/hailort/libhailort/src/vdevice_native_stream.hpp @@ -0,0 +1,69 @@ +/** + * Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved. + * Distributed under the MIT license (https://opensource.org/licenses/MIT) + **/ +/** + * @file vdevice_native_stream.hpp + * @brief Internal stream implementation for native streams + * + **/ + +#ifndef HAILO_VDEVICE_NATIVE_STREAM_HPP_ +#define HAILO_VDEVICE_NATIVE_STREAM_HPP_ + +#include "stream_internal.hpp" +#include "hailo/hailort.h" +#include "vdevice_stream.hpp" +#include "hailo/expected.hpp" + +namespace hailort +{ + +class InputVDeviceNativeStream : public InputVDeviceBaseStream { +public: + InputVDeviceNativeStream(InputVDeviceNativeStream &&other) : + InputVDeviceBaseStream(std::move(other)) + {} + + explicit InputVDeviceNativeStream( + std::vector> &&streams, + EventPtr &&network_group_activated_event, + const LayerInfo &layer_info, + hailo_status &status) : + InputVDeviceBaseStream(std::move(streams), std::move(network_group_activated_event), layer_info, status) + {} + + virtual hailo_status abort() override; + virtual hailo_status clear_abort() override; + virtual bool is_scheduled() override { return false; }; + +protected: + virtual Expected sync_write_raw_buffer(const MemoryView &buffer, + const std::function &should_cancel = []() { return false; }) override; +}; + +class OutputVDeviceNativeStream : public OutputVDeviceBaseStream { +public: + OutputVDeviceNativeStream(OutputVDeviceNativeStream &&other) : + OutputVDeviceBaseStream(std::move(other)) + {} + + explicit OutputVDeviceNativeStream( + std::vector> &&streams, + const LayerInfo &layer_info, + EventPtr &&network_group_activated_event, + hailo_status &status) : + OutputVDeviceBaseStream(std::move(streams), layer_info, std::move(network_group_activated_event), status) + {} + + virtual hailo_status abort() override; + virtual hailo_status clear_abort() override; + virtual bool is_scheduled() override { return false; }; + +protected: + virtual hailo_status read(MemoryView buffer) override;; +}; + +} /* namespace hailort */ + +#endif /* HAILO_VDEVICE_NATIVE_STREAM_HPP_ */ diff --git a/hailort/libhailort/src/vdevice_stream.cpp b/hailort/libhailort/src/vdevice_stream.cpp index ab5b982..7b9a792 100644 --- a/hailort/libhailort/src/vdevice_stream.cpp +++ b/hailort/libhailort/src/vdevice_stream.cpp @@ -16,19 +16,23 @@ #include "hailo/stream.hpp" #include "hailo/hef.hpp" #include "hailo/hailort_common.hpp" +#include "tracer_macros.hpp" #include "vdevice_stream.hpp" +#include "scheduled_stream.hpp" +#include "vdevice_native_stream.hpp" #include "context_switch/multi_context/resource_manager.hpp" +#include "multi_device_scheduled_stream.hpp" namespace hailort { -hailo_status VDeviceInputStream::deactivate_stream() +hailo_status InputVDeviceBaseStream::deactivate_stream() { auto status = HAILO_SUCCESS; // Best effort for (auto &stream : m_streams) { - auto deactivate_status = stream->deactivate_stream(); + auto deactivate_status = stream.get().deactivate_stream(); if (HAILO_SUCCESS != deactivate_status) { - LOGGER__ERROR("Failed to deactivate input stream. (status: {} device: {})", deactivate_status, stream->get_dev_id()); + LOGGER__ERROR("Failed to deactivate input stream. (status: {} device: {})", deactivate_status, stream.get().get_dev_id()); status = deactivate_status; } } @@ -37,7 +41,7 @@ hailo_status VDeviceInputStream::deactivate_stream() } /** Input stream **/ -VDeviceInputStream::~VDeviceInputStream() +InputVDeviceBaseStream::~InputVDeviceBaseStream() { // We want to stop the vdma channel before closing the stream in the firmware // because sending data to a closed stream may terminate the dma engine @@ -46,12 +50,12 @@ VDeviceInputStream::~VDeviceInputStream() } } -hailo_status VDeviceInputStream::activate_stream(uint16_t dynamic_batch_size) +hailo_status InputVDeviceBaseStream::activate_stream(uint16_t dynamic_batch_size) { for (auto &stream : m_streams) { - auto status = stream->activate_stream(dynamic_batch_size); + auto status = stream.get().activate_stream(dynamic_batch_size); if (HAILO_SUCCESS != status) { - LOGGER__ERROR("Failed to activate input stream. (device: {})", stream->get_dev_id()); + LOGGER__ERROR("Failed to activate input stream. (device: {})", stream.get().get_dev_id()); deactivate_stream(); return status; } @@ -60,251 +64,264 @@ hailo_status VDeviceInputStream::activate_stream(uint16_t dynamic_batch_size) return HAILO_SUCCESS; } -Expected VDeviceInputStream::sync_write_raw_buffer(const MemoryView &buffer) -{ - return sync_write_raw_buffer_impl(buffer, m_network_group_handle); -} - -Expected VDeviceInputStream::sync_write_raw_buffer_impl(const MemoryView &buffer, scheduler_ng_handle_t network_group_handle) -{ - size_t written_bytes = 0; - auto network_group_scheduler = m_network_group_scheduler.lock(); - if (network_group_scheduler) { - auto status = network_group_scheduler->wait_for_write(network_group_handle, name()); - if (HAILO_STREAM_INTERNAL_ABORT == status) { - LOGGER__INFO("Write to stream was aborted."); - return make_unexpected(status); - } - CHECK_SUCCESS_AS_EXPECTED(status); - - status = m_streams[m_next_transfer_stream_index]->write_buffer_only(buffer); - if (HAILO_SUCCESS != status) { - LOGGER__INFO("Write to stream has failed! status = {}", status); - return make_unexpected(status); - } - - status = network_group_scheduler->signal_write_finish(network_group_handle, name()); - if (HAILO_STREAM_INTERNAL_ABORT == status) { - return make_unexpected(status); - } - CHECK_SUCCESS_AS_EXPECTED(status); - - written_bytes = buffer.size(); - } else { - auto expected_written_bytes = m_streams[m_next_transfer_stream_index]->sync_write_raw_buffer(buffer); - if (HAILO_SUCCESS != expected_written_bytes.status()) { - LOGGER__INFO("Write to stream has failed! status = {}", expected_written_bytes.status()); - return make_unexpected(expected_written_bytes.status()); - } - written_bytes = expected_written_bytes.value(); - } - - // Update m_next_transfer_stream_index only if 'batch' frames has been transferred - if (0 == (++m_acc_frames % m_streams[0]->get_dynamic_batch_size())) { - m_next_transfer_stream_index = static_cast((m_next_transfer_stream_index + 1) % m_streams.size()); - m_acc_frames = 0; - } - return written_bytes; -} - -hailo_status VDeviceInputStream::sync_write_all_raw_buffer_no_transform_impl(void *buffer, size_t offset, size_t size) +hailo_status InputVDeviceBaseStream::sync_write_all_raw_buffer_no_transform_impl(void *buffer, size_t offset, size_t size) { ASSERT(NULL != buffer); return sync_write_raw_buffer(MemoryView(static_cast(buffer) + offset, size)).status(); } -Expected VDeviceInputStream::send_pending_buffer() +hailo_status InputVDeviceBaseStream::send_pending_buffer(size_t device_index) { assert(1 == m_streams.size()); - VdmaInputStream &vdma_input = static_cast(*m_streams[m_next_transfer_stream_index].get()); + CHECK(0 == device_index, HAILO_INVALID_OPERATION); + VdmaInputStream &vdma_input = static_cast(m_streams[m_next_transfer_stream_index].get()); return vdma_input.send_pending_buffer(); } -Expected VDeviceInputStream::get_buffer_frames_size() const +Expected InputVDeviceBaseStream::get_buffer_frames_size() const { size_t total_buffers_size = 0; for (auto &stream : m_streams) { - auto stream_buffer_size = stream->get_buffer_frames_size(); + auto stream_buffer_size = stream.get().get_buffer_frames_size(); CHECK_EXPECTED(stream_buffer_size); total_buffers_size += stream_buffer_size.value(); } - + return total_buffers_size; } -Expected VDeviceInputStream::get_pending_frames_count() const +Expected InputVDeviceBaseStream::get_pending_frames_count() const { size_t total_pending_frames_count = 0; for (auto &stream : m_streams) { - auto stream_pending_frames_count = stream->get_pending_frames_count(); + auto stream_pending_frames_count = stream.get().get_pending_frames_count(); CHECK_EXPECTED(stream_pending_frames_count); total_pending_frames_count += stream_pending_frames_count.value(); } - + return total_pending_frames_count; } -// TODO - HRT-6830 - make create_input/output_stream_from_net_group as virutal function -Expected> VDeviceInputStream::create_input_stream_from_net_group( - std::vector> &resources_managers, - const LayerInfo &edge_layer, const std::string &stream_name, const scheduler_ng_handle_t &network_group_handle, - EventPtr &&network_group_activated_event, NetworkGroupSchedulerWeakPtr network_group_scheduler) +Expected> InputVDeviceBaseStream::create(std::vector> &&low_level_streams, + const LayerInfo &edge_layer, const scheduler_ng_handle_t &network_group_handle, + EventPtr network_group_activated_event, NetworkGroupSchedulerWeakPtr network_group_scheduler) { - hailo_status status = HAILO_UNINITIALIZED; - - std::vector devices; - std::vector> streams; - - for (auto &resources_manager : resources_managers) { - auto vdma_channel_ptr_expected = resources_manager->get_boundary_vdma_channel_by_stream_name(stream_name); - CHECK_EXPECTED(vdma_channel_ptr_expected); - auto vdma_channel_ptr = vdma_channel_ptr_expected.release(); - - auto batch_size_expected = resources_manager->get_network_batch_size(edge_layer.network_name); - CHECK_EXPECTED(batch_size_expected); - const auto batch_size = batch_size_expected.release(); - - auto &device = resources_manager->get_device(); - devices.push_back(&device); - - auto local_stream = VdmaInputStream::create(device, vdma_channel_ptr, edge_layer, batch_size, - network_group_activated_event); - CHECK_EXPECTED(local_stream); - streams.emplace_back(local_stream.release()); - } - - // Validate all streams share the same interface - const auto stream_interface = streams[0]->get_interface(); - for (const auto &stream : streams) { - CHECK_AS_EXPECTED(stream_interface == stream->get_interface(), HAILO_INTERNAL_FAILURE, - "vDevice internal streams should have the same stream interface"); + assert(0 < low_level_streams.size()); + auto status = HAILO_UNINITIALIZED; + + std::unique_ptr local_vdevice_stream; + + if (network_group_scheduler.lock()) { + if (1 < low_level_streams.size()) { + const auto batch_size = low_level_streams[0].get().get_dynamic_batch_size(); + auto frame_size = low_level_streams[0].get().get_frame_size(); + auto buffers_queue_ptr = BuffersQueue::create_unique(frame_size, (low_level_streams.size() * batch_size)); + CHECK_EXPECTED(buffers_queue_ptr); + + local_vdevice_stream = make_unique_nothrow(std::move(low_level_streams), + network_group_handle, std::move(network_group_activated_event), edge_layer, + network_group_scheduler, buffers_queue_ptr.release(), status); + } else { + local_vdevice_stream = make_unique_nothrow(std::move(low_level_streams), + network_group_handle, std::move(network_group_activated_event), edge_layer, + network_group_scheduler, status); + } + } else { + local_vdevice_stream = make_unique_nothrow(std::move(low_level_streams), + std::move(network_group_activated_event), edge_layer,status); } - - std::shared_ptr local_vdevice_stream(new (std::nothrow) VDeviceInputStream(devices, - std::move(streams), network_group_handle, std::move(network_group_activated_event), edge_layer, - network_group_scheduler, stream_interface, status)); CHECK_AS_EXPECTED((nullptr != local_vdevice_stream), HAILO_OUT_OF_HOST_MEMORY); CHECK_SUCCESS_AS_EXPECTED(status); return local_vdevice_stream; } -Expected> VDeviceInputStream::create(std::vector> &resources_managers, - const LayerInfo &edge_layer, const std::string &stream_name, const scheduler_ng_handle_t &network_group_handle, - EventPtr network_group_activated_event, NetworkGroupSchedulerWeakPtr network_group_scheduler) -{ - assert(0 < resources_managers.size()); - - auto input_stream = create_input_stream_from_net_group(resources_managers, edge_layer, - stream_name, network_group_handle, std::move(network_group_activated_event), network_group_scheduler); - CHECK_EXPECTED(input_stream); - - return input_stream.release(); -} - -hailo_status VDeviceInputStream::set_timeout(std::chrono::milliseconds timeout) +hailo_status InputVDeviceBaseStream::set_timeout(std::chrono::milliseconds timeout) { for (auto &stream : m_streams) { - auto status = stream->set_timeout(timeout); - CHECK_SUCCESS(status, "Failed to set timeout to input stream. (device: {})", stream->get_dev_id()); + auto status = stream.get().set_timeout(timeout); + CHECK_SUCCESS(status, "Failed to set timeout to input stream. (device: {})", stream.get().get_dev_id()); } return HAILO_SUCCESS; } -std::chrono::milliseconds VDeviceInputStream::get_timeout() const +std::chrono::milliseconds InputVDeviceBaseStream::get_timeout() const { // All timeout values of m_streams should be the same - return m_streams[0]->get_timeout(); + return m_streams[0].get().get_timeout(); +} + +hailo_stream_interface_t InputVDeviceBaseStream::get_interface() const +{ + // All interface values of m_streams should be the same + return m_streams[0].get().get_interface(); } -hailo_status VDeviceInputStream::flush() +hailo_status InputVDeviceBaseStream::flush() { auto status = HAILO_SUCCESS; // Best effort for (auto &stream : m_streams) { - auto flush_status = stream->flush(); + auto flush_status = stream.get().flush(); if (HAILO_SUCCESS != status) { - LOGGER__ERROR("Failed to flush input stream. (status: {} device: {})", status, stream->get_dev_id()); + LOGGER__ERROR("Failed to flush input stream. (status: {} device: {})", status, stream.get().get_dev_id()); status = flush_status; } } return status; } -hailo_status VDeviceInputStream::abort() +Expected ScheduledInputStream::sync_write_raw_buffer(const MemoryView &buffer, const std::function &should_cancel) +{ + return sync_write_raw_buffer_impl(buffer, m_network_group_handle, should_cancel); +} + +Expected InputVDeviceNativeStream::sync_write_raw_buffer(const MemoryView &buffer, const std::function &should_cancel) +{ + if (should_cancel()) { + return make_unexpected(HAILO_STREAM_ABORTED_BY_USER); + } + + auto expected_written_bytes = m_streams[m_next_transfer_stream_index].get().sync_write_raw_buffer(buffer); + if (HAILO_SUCCESS != expected_written_bytes.status()) { + LOGGER__INFO("Write to stream has failed! status = {}", expected_written_bytes.status()); + return make_unexpected(expected_written_bytes.status()); + } + auto written_bytes = expected_written_bytes.value(); + + // Update m_next_transfer_stream_index only if 'batch' frames has been transferred + if (0 == (++m_acc_frames % m_streams[0].get().get_dynamic_batch_size())) { + m_next_transfer_stream_index = static_cast((m_next_transfer_stream_index + 1) % m_streams.size()); + m_acc_frames = 0; + } + return written_bytes; +} + +Expected ScheduledInputStream::sync_write_raw_buffer_impl(const MemoryView &buffer, scheduler_ng_handle_t network_group_handle, + const std::function &should_cancel) +{ + auto network_group_scheduler = m_network_group_scheduler.lock(); + CHECK_AS_EXPECTED(network_group_scheduler, HAILO_INTERNAL_FAILURE); + + auto status = network_group_scheduler->wait_for_write(network_group_handle, name(), get_timeout(), should_cancel); + if (HAILO_STREAM_ABORTED_BY_USER == status) { + LOGGER__INFO("Write to stream was aborted."); + return make_unexpected(status); + } + CHECK_SUCCESS_AS_EXPECTED(status); + + TRACE(WriteFrameTrace, "", network_group_handle, m_stream_info.name); + + assert(1 == m_streams.size()); + status = m_streams[0].get().write_buffer_only(buffer, should_cancel); + if (HAILO_SUCCESS != status) { + LOGGER__INFO("Write to stream has failed! status = {}", status); + network_group_scheduler->mark_failed_write(network_group_handle, name()); + return make_unexpected(status); + } + + status = network_group_scheduler->signal_write_finish(network_group_handle, name()); + if (HAILO_STREAM_ABORTED_BY_USER == status) { + return make_unexpected(status); + } + CHECK_SUCCESS_AS_EXPECTED(status); + + auto written_bytes = buffer.size(); + + return written_bytes; +} + +hailo_status ScheduledInputStream::abort() { return abort_impl(m_network_group_handle); } -hailo_status VDeviceInputStream::abort_impl(scheduler_ng_handle_t network_group_handle) +hailo_status InputVDeviceNativeStream::abort() { auto status = HAILO_SUCCESS; // Best effort for (auto &stream : m_streams) { - auto abort_status = stream->abort(); + auto abort_status = stream.get().abort(); if (HAILO_SUCCESS != status) { - LOGGER__ERROR("Failed to abort input stream. (status: {} device: {})", status, stream->get_dev_id()); + LOGGER__ERROR("Failed to abort input stream. (status: {} device: {})", status, stream.get().get_dev_id()); status = abort_status; } } + return status; +} + +hailo_status ScheduledInputStream::abort_impl(scheduler_ng_handle_t network_group_handle) +{ + auto status = HAILO_SUCCESS; // Best effort + assert(1 == m_streams.size()); + auto abort_status = m_streams[0].get().abort(); + if (HAILO_SUCCESS != status) { + LOGGER__ERROR("Failed to abort input stream. (status: {} device: {})", status, m_streams[0].get().get_dev_id()); + status = abort_status; + } + auto network_group_scheduler = m_network_group_scheduler.lock(); - if (network_group_scheduler) { - auto disable_status = network_group_scheduler->disable_stream(network_group_handle, name()); - if (HAILO_SUCCESS != disable_status) { - LOGGER__ERROR("Failed to disable stream in the network group scheduler. (status: {})", disable_status); - status = disable_status; - } + CHECK(network_group_scheduler, HAILO_INTERNAL_FAILURE); + + auto disable_status = network_group_scheduler->disable_stream(network_group_handle, name()); + if (HAILO_SUCCESS != disable_status) { + LOGGER__ERROR("Failed to disable stream in the network group scheduler. (status: {})", disable_status); + status = disable_status; } return status; } -hailo_status VDeviceInputStream::clear_abort() +hailo_status ScheduledInputStream::clear_abort() { return clear_abort_impl(m_network_group_handle); } -hailo_status VDeviceInputStream::clear_abort_impl(scheduler_ng_handle_t network_group_handle) +hailo_status InputVDeviceNativeStream::clear_abort() { auto status = HAILO_SUCCESS; // Best effort for (auto &stream : m_streams) { - auto clear_abort_status = stream->clear_abort(); + auto clear_abort_status = stream.get().clear_abort(); if ((HAILO_SUCCESS != clear_abort_status) && (HAILO_STREAM_NOT_ACTIVATED != clear_abort_status)) { - LOGGER__ERROR("Failed to clear abort input stream. (status: {} device: {})", clear_abort_status, stream->get_dev_id()); + LOGGER__ERROR("Failed to clear abort input stream. (status: {} device: {})", clear_abort_status, stream.get().get_dev_id()); status = clear_abort_status; } } - auto network_group_scheduler = m_network_group_scheduler.lock(); - if (network_group_scheduler) { - auto enable_status = network_group_scheduler->enable_stream(network_group_handle, name()); - if (HAILO_SUCCESS != enable_status) { - LOGGER__ERROR("Failed to enable stream in the network group scheduler. (status: {})", enable_status); - status = enable_status; - } - } - return status; } -bool VDeviceInputStream::is_scheduled() +hailo_status ScheduledInputStream::clear_abort_impl(scheduler_ng_handle_t network_group_handle) { + auto status = HAILO_SUCCESS; // Best effort + assert(1 == m_streams.size()); + auto clear_abort_status = m_streams[0].get().clear_abort(); + if ((HAILO_SUCCESS != clear_abort_status) && (HAILO_STREAM_NOT_ACTIVATED != clear_abort_status)) { + LOGGER__ERROR("Failed to clear abort input stream. (status: {} device: {})", clear_abort_status, m_streams[0].get().get_dev_id()); + status = clear_abort_status; + } + auto network_group_scheduler = m_network_group_scheduler.lock(); - if (!network_group_scheduler) { - return false; + CHECK(network_group_scheduler, HAILO_INTERNAL_FAILURE); + + auto enable_status = network_group_scheduler->enable_stream(network_group_handle, name()); + if (HAILO_SUCCESS != enable_status) { + LOGGER__ERROR("Failed to enable stream in the network group scheduler. (status: {})", enable_status); + status = enable_status; } - return (HAILO_SCHEDULING_ALGORITHM_NONE != network_group_scheduler->algorithm()); + + return status; } /** Output stream **/ -hailo_status VDeviceOutputStream::deactivate_stream() +hailo_status OutputVDeviceBaseStream::deactivate_stream() { auto status = HAILO_SUCCESS; // Best effort for (auto &stream : m_streams) { - auto deactivate_status = stream->deactivate_stream(); + auto deactivate_status = stream.get().deactivate_stream(); if (HAILO_SUCCESS != status) { - LOGGER__ERROR("Failed to deactivate output stream. (status: {} device: {})", status, stream->get_dev_id()); + LOGGER__ERROR("Failed to deactivate output stream. (status: {} device: {})", status, stream.get().get_dev_id()); status = deactivate_status; } } @@ -312,7 +329,7 @@ hailo_status VDeviceOutputStream::deactivate_stream() return status; } -VDeviceOutputStream::~VDeviceOutputStream() +OutputVDeviceBaseStream::~OutputVDeviceBaseStream() { // We want to stop the vdma channel before closing the stream in the firmware // because sending data to a closed stream may terminate the dma engine @@ -321,12 +338,12 @@ VDeviceOutputStream::~VDeviceOutputStream() } } -hailo_status VDeviceOutputStream::activate_stream(uint16_t dynamic_batch_size) +hailo_status OutputVDeviceBaseStream::activate_stream(uint16_t dynamic_batch_size) { for (auto &stream : m_streams) { - auto status = stream->activate_stream(dynamic_batch_size); + auto status = stream.get().activate_stream(dynamic_batch_size); if (HAILO_SUCCESS != status) { - LOGGER__ERROR("Failed to activate output stream. (device: {})", stream->get_dev_id()); + LOGGER__ERROR("Failed to activate output stream. (device: {})", stream.get().get_dev_id()); deactivate_stream(); return status; } @@ -335,223 +352,222 @@ hailo_status VDeviceOutputStream::activate_stream(uint16_t dynamic_batch_size) return HAILO_SUCCESS; } -hailo_status VDeviceOutputStream::read_all(MemoryView &/*buffer*/) +hailo_status OutputVDeviceBaseStream::read_all(MemoryView &/*buffer*/) { LOGGER__ERROR("read_all should not be called in vdevice flow"); return HAILO_INTERNAL_FAILURE; } -Expected VDeviceOutputStream::sync_read_raw_buffer(MemoryView &/*buffer*/) +Expected OutputVDeviceBaseStream::sync_read_raw_buffer(MemoryView &/*buffer*/) { LOGGER__ERROR("sync_read_raw_buffer should not be called in vdevice flow"); return make_unexpected(HAILO_INTERNAL_FAILURE); } -hailo_status VDeviceOutputStream::read(MemoryView buffer) +hailo_status ScheduledOutputStream::read(MemoryView buffer) { return read_impl(buffer, m_network_group_handle); } -hailo_status VDeviceOutputStream::read_impl(MemoryView buffer, scheduler_ng_handle_t network_group_handle) +hailo_status OutputVDeviceNativeStream::read(MemoryView buffer) { - auto network_group_scheduler = m_network_group_scheduler.lock(); - if (network_group_scheduler) { - auto status = network_group_scheduler->wait_for_read(network_group_handle, name()); - if (HAILO_STREAM_INTERNAL_ABORT == status) { - LOGGER__INFO("Read from stream was aborted."); - return status; - } - CHECK_SUCCESS(status); - } - - auto status = m_streams[m_next_transfer_stream_index]->read(buffer); + auto status = m_streams[m_next_transfer_stream_index].get().read(buffer); if (HAILO_SUCCESS != status) { LOGGER__INFO("Read from stream has failed! status = {}", status); return status; } // Update m_next_transfer_stream_index only if 'batch' frames has been transferred - if (0 == (++m_acc_frames % m_streams[0]->get_dynamic_batch_size())) { + if (0 == (++m_acc_frames % m_streams[0].get().get_dynamic_batch_size())) { m_next_transfer_stream_index = static_cast((m_next_transfer_stream_index + 1) % m_streams.size()); m_acc_frames = 0; } - if (network_group_scheduler) { - status = network_group_scheduler->signal_read_finish(network_group_handle, name()); - if (HAILO_STREAM_INTERNAL_ABORT == status) { - return status; - } - CHECK_SUCCESS(status); - } - return HAILO_SUCCESS; } -// TODO - HRT-6830 - make create_input/output_stream_from_net_group as virutal function -Expected> VDeviceOutputStream::create_output_stream_from_net_group( - std::vector> &resources_managers, - const LayerInfo &edge_layer, const std::string &stream_name, const scheduler_ng_handle_t &network_group_handle, - EventPtr &&network_group_activated_event, NetworkGroupSchedulerWeakPtr network_group_scheduler) +hailo_status ScheduledOutputStream::read_impl(MemoryView buffer, scheduler_ng_handle_t network_group_handle) { - hailo_status status = HAILO_UNINITIALIZED; - - std::vector devices; - std::vector> streams; - - for (auto &resources_manager : resources_managers) { - auto vdma_channel_ptr_expected = resources_manager->get_boundary_vdma_channel_by_stream_name(stream_name); - CHECK_EXPECTED(vdma_channel_ptr_expected); - auto vdma_channel_ptr = vdma_channel_ptr_expected.release(); - - auto batch_size_expected = resources_manager->get_network_batch_size(edge_layer.network_name); - CHECK_EXPECTED(batch_size_expected); - const auto batch_size = batch_size_expected.release(); - - auto &device = resources_manager->get_device(); - devices.push_back(&device); + auto network_group_scheduler = m_network_group_scheduler.lock(); + CHECK(network_group_scheduler, HAILO_INTERNAL_FAILURE); - auto local_stream = VdmaOutputStream::create(device, vdma_channel_ptr, edge_layer, batch_size, - network_group_activated_event); - CHECK_EXPECTED(local_stream); - streams.emplace_back(local_stream.release()); + auto device_id = network_group_scheduler->wait_for_read(network_group_handle, name(), get_timeout()); + if (HAILO_STREAM_ABORTED_BY_USER == device_id.status()) { + LOGGER__INFO("Read from stream was aborted."); + return device_id.status(); } + CHECK_EXPECTED_AS_STATUS(device_id); - // Validate all streams share the same interface - const auto stream_interface = streams[0]->get_interface(); - for (const auto &stream : streams) { - CHECK_AS_EXPECTED(stream_interface == stream->get_interface(), HAILO_INTERNAL_FAILURE, - "vDevice internal streams should have the same stream interface"); + TRACE(ReadFrameTrace, "", network_group_handle, m_stream_info.name); + auto status = m_streams[device_id.value()].get().read(buffer); + if (HAILO_SUCCESS != status) { + LOGGER__INFO("Read from stream has failed! status = {}", status); + return status; } - std::unique_ptr local_vdevice_stream(new (std::nothrow) VDeviceOutputStream(devices, - std::move(streams), network_group_handle, edge_layer, std::move(network_group_activated_event), - network_group_scheduler, stream_interface, status)); - CHECK_AS_EXPECTED((nullptr != local_vdevice_stream), HAILO_OUT_OF_HOST_MEMORY); - CHECK_SUCCESS_AS_EXPECTED(status); + status = network_group_scheduler->signal_read_finish(network_group_handle, name(), device_id.value()); + if (HAILO_STREAM_ABORTED_BY_USER == status) { + return status; + } + CHECK_SUCCESS(status); - return local_vdevice_stream; + return HAILO_SUCCESS; } -Expected> VDeviceOutputStream::create(std::vector> &resources_managers, - const LayerInfo &edge_layer, const std::string &stream_name, const scheduler_ng_handle_t &network_group_handle, EventPtr network_group_activated_event, +Expected> OutputVDeviceBaseStream::create(std::vector> &&low_level_streams, + const LayerInfo &edge_layer, const scheduler_ng_handle_t &network_group_handle, EventPtr network_group_activated_event, NetworkGroupSchedulerWeakPtr network_group_scheduler) { - assert(0 < resources_managers.size()); + assert(0 < low_level_streams.size()); + auto status = HAILO_UNINITIALIZED; + + std::unique_ptr local_vdevice_stream; + if (network_group_scheduler.lock()) { + local_vdevice_stream = make_unique_nothrow(std::move(low_level_streams), network_group_handle, + edge_layer, std::move(network_group_activated_event), network_group_scheduler, status); + } else { + local_vdevice_stream = make_unique_nothrow(std::move(low_level_streams), edge_layer, + std::move(network_group_activated_event), status); + } - auto output_stream = create_output_stream_from_net_group(resources_managers, edge_layer, - stream_name, network_group_handle, std::move(network_group_activated_event), network_group_scheduler); - CHECK_EXPECTED(output_stream); + CHECK_AS_EXPECTED((nullptr != local_vdevice_stream), HAILO_OUT_OF_HOST_MEMORY); + CHECK_SUCCESS_AS_EXPECTED(status); - return output_stream.release(); + return local_vdevice_stream; } -hailo_status VDeviceOutputStream::set_timeout(std::chrono::milliseconds timeout) +hailo_status OutputVDeviceBaseStream::set_timeout(std::chrono::milliseconds timeout) { for (auto &stream : m_streams) { - auto status = stream->set_timeout(timeout); - CHECK_SUCCESS(status, "Failed to set timeout to output stream. (device: {})", stream->get_dev_id()); + auto status = stream.get().set_timeout(timeout); + CHECK_SUCCESS(status, "Failed to set timeout to output stream. (device: {})", stream.get().get_dev_id()); } return HAILO_SUCCESS; } -std::chrono::milliseconds VDeviceOutputStream::get_timeout() const +std::chrono::milliseconds OutputVDeviceBaseStream::get_timeout() const { // All timeout values of m_streams should be the same - return m_streams[0]->get_timeout(); + return m_streams[0].get().get_timeout(); } -hailo_status VDeviceOutputStream::abort() +hailo_stream_interface_t OutputVDeviceBaseStream::get_interface() const +{ + // All interface values of m_streams should be the same + return m_streams[0].get().get_interface(); +} + +hailo_status ScheduledOutputStream::abort() { return abort_impl(m_network_group_handle); } -hailo_status VDeviceOutputStream::abort_impl(scheduler_ng_handle_t network_group_handle) +hailo_status OutputVDeviceNativeStream::abort() { auto status = HAILO_SUCCESS; // Best effort for (auto &stream : m_streams) { - auto abort_status = stream->abort(); + auto abort_status = stream.get().abort(); if (HAILO_SUCCESS != status) { - LOGGER__ERROR("Failed to abort output stream. (status: {} device: {})", status, stream->get_dev_id()); + LOGGER__ERROR("Failed to abort output stream. (status: {} device: {})", status, stream.get().get_dev_id()); status = abort_status; } } - auto network_group_scheduler = m_network_group_scheduler.lock(); - if (network_group_scheduler) { - auto disable_status = network_group_scheduler->disable_stream(network_group_handle, name()); - if (HAILO_SUCCESS != disable_status) { - LOGGER__ERROR("Failed to disable stream in the network group scheduler. (status: {})", disable_status); - status = disable_status; + return status; +} + +hailo_status ScheduledOutputStream::abort_impl(scheduler_ng_handle_t network_group_handle) +{ + auto status = HAILO_SUCCESS; // Best effort + for (auto& stream : m_streams) { + auto abort_status = stream.get().abort(); + if (HAILO_SUCCESS != status) { + LOGGER__ERROR("Failed to abort output stream. (status: {} device: {})", status, stream.get().get_dev_id()); + status = abort_status; } } + auto network_group_scheduler = m_network_group_scheduler.lock(); + CHECK(network_group_scheduler, HAILO_INTERNAL_FAILURE); + + auto disable_status = network_group_scheduler->disable_stream(network_group_handle, name()); + if (HAILO_SUCCESS != disable_status) { + LOGGER__ERROR("Failed to disable stream in the network group scheduler. (status: {})", disable_status); + status = disable_status; + } + return status; } -hailo_status VDeviceOutputStream::clear_abort() +hailo_status ScheduledOutputStream::clear_abort() { return clear_abort_impl(m_network_group_handle); } -hailo_status VDeviceOutputStream::clear_abort_impl(scheduler_ng_handle_t network_group_handle) +hailo_status OutputVDeviceNativeStream::clear_abort() { auto status = HAILO_SUCCESS; // Best effort for (auto &stream : m_streams) { - auto clear_abort_status = stream->clear_abort(); + auto clear_abort_status = stream.get().clear_abort(); if ((HAILO_SUCCESS != clear_abort_status) && (HAILO_STREAM_NOT_ACTIVATED != clear_abort_status)) { - LOGGER__ERROR("Failed to clear abort output stream. (status: {} device: {})", clear_abort_status, stream->get_dev_id()); + LOGGER__ERROR("Failed to clear abort output stream. (status: {} device: {})", clear_abort_status, stream.get().get_dev_id()); status = clear_abort_status; } } - auto network_group_scheduler = m_network_group_scheduler.lock(); - if (network_group_scheduler) { - auto enable_status = network_group_scheduler->enable_stream(network_group_handle, name()); - if (HAILO_SUCCESS != enable_status) { - LOGGER__ERROR("Failed to enable stream in the network group scheduler. (status: {})", enable_status); - status = enable_status; - } - } - return status; } -bool VDeviceOutputStream::is_scheduled() +hailo_status ScheduledOutputStream::clear_abort_impl(scheduler_ng_handle_t network_group_handle) { + auto status = HAILO_SUCCESS; // Best effort + for (auto& stream : m_streams) { + auto clear_abort_status = stream.get().clear_abort(); + if ((HAILO_SUCCESS != clear_abort_status) && (HAILO_STREAM_NOT_ACTIVATED != clear_abort_status)) { + LOGGER__ERROR("Failed to clear abort output stream. (status: {} device: {})", clear_abort_status, stream.get().get_dev_id()); + status = clear_abort_status; + } + } + auto network_group_scheduler = m_network_group_scheduler.lock(); - if (!network_group_scheduler) { - return false; + CHECK(network_group_scheduler, HAILO_INTERNAL_FAILURE); + + auto enable_status = network_group_scheduler->enable_stream(network_group_handle, name()); + if (HAILO_SUCCESS != enable_status) { + LOGGER__ERROR("Failed to enable stream in the network group scheduler. (status: {})", enable_status); + status = enable_status; } - return (HAILO_SCHEDULING_ALGORITHM_NONE != network_group_scheduler->algorithm()); + + return status; } -Expected VDeviceOutputStream::get_buffer_frames_size() const +Expected OutputVDeviceBaseStream::get_buffer_frames_size() const { size_t total_buffers_size = 0; for (auto &stream : m_streams) { - auto stream_buffer_size = stream->get_buffer_frames_size(); + auto stream_buffer_size = stream.get().get_buffer_frames_size(); if (HAILO_NOT_AVAILABLE == stream_buffer_size.status()) { return make_unexpected(HAILO_NOT_AVAILABLE); } CHECK_EXPECTED(stream_buffer_size); total_buffers_size += stream_buffer_size.value(); } - + return total_buffers_size; } -Expected VDeviceOutputStream::get_pending_frames_count() const +Expected OutputVDeviceBaseStream::get_pending_frames_count() const { size_t total_pending_frames_count = 0; for (auto &stream : m_streams) { - auto stream_pending_frames_count = stream->get_pending_frames_count(); + auto stream_pending_frames_count = stream.get().get_pending_frames_count(); if (HAILO_NOT_AVAILABLE == stream_pending_frames_count.status()) { return make_unexpected(HAILO_NOT_AVAILABLE); } CHECK_EXPECTED(stream_pending_frames_count); total_pending_frames_count += stream_pending_frames_count.value(); } - + return total_pending_frames_count; } diff --git a/hailort/libhailort/src/vdevice_stream.hpp b/hailort/libhailort/src/vdevice_stream.hpp index 15524f7..2d113e3 100644 --- a/hailort/libhailort/src/vdevice_stream.hpp +++ b/hailort/libhailort/src/vdevice_stream.hpp @@ -4,8 +4,19 @@ **/ /** * @file vdevice_stream.hpp - * @brief Internal stream implementation for VDevice - holds VdmaStream per physical device + * @brief Internal stream implementation for VDevice * + * InputStream (External "interface") + * |-- InputStreamBase (Base class) + * |-- InputVDeviceBaseStream (Base class for vdevice streams) + * | |-- InputVDeviceNativeStream + * | |-- ScheduledInputStream + * + * OutputStream (External "interface") + * |-- OutputStreamBase (Base class) + * |-- OutputVDeviceBaseStream (Base class for vdevice streams) + * | |-- OutputVDeviceNativeStream + * | |-- ScheduledOutputStream **/ #ifndef HAILO_VDEVICE_STREAM_HPP_ @@ -21,121 +32,104 @@ namespace hailort { -class VDeviceInputStream : public InputStreamBase { +class InputVDeviceBaseStream : public InputStreamBase { + public: - VDeviceInputStream(VDeviceInputStream &&other) : + static Expected> create(std::vector> &&low_level_streams, + const LayerInfo &edge_layer, const scheduler_ng_handle_t &network_group_handle, + EventPtr network_group_activated_event, NetworkGroupSchedulerWeakPtr network_group_scheduler); + + InputVDeviceBaseStream(InputVDeviceBaseStream &&other) : InputStreamBase(std::move(other)), - m_network_group_handle(std::move(other.m_network_group_handle)), - m_network_group_scheduler(std::move(other.m_network_group_scheduler)), - m_devices(std::move(other.m_devices)), m_streams(std::move(other.m_streams)), m_is_stream_activated(std::exchange(other.m_is_stream_activated, false)), m_next_transfer_stream_index(other.m_next_transfer_stream_index), - m_acc_frames(other.m_acc_frames), - m_stream_interface(other.m_stream_interface) + m_acc_frames(other.m_acc_frames) {} - virtual ~VDeviceInputStream(); - - static Expected> create(std::vector> &resources_managers, - const LayerInfo &edge_layer, const std::string &stream_name, const scheduler_ng_handle_t &network_group_handle, EventPtr network_group_activated_event, - NetworkGroupSchedulerWeakPtr network_group_scheduler); + virtual ~InputVDeviceBaseStream(); virtual hailo_status activate_stream(uint16_t dynamic_batch_size) override; virtual hailo_status deactivate_stream() override; - virtual hailo_stream_interface_t get_interface() const override { return m_stream_interface; } + virtual hailo_stream_interface_t get_interface() const override; virtual std::chrono::milliseconds get_timeout() const override; virtual hailo_status set_timeout(std::chrono::milliseconds timeout) override; - virtual hailo_status abort() override; - virtual hailo_status clear_abort() override; - virtual bool is_scheduled() override; - virtual Expected send_pending_buffer() override; + virtual hailo_status send_pending_buffer(size_t device_index = 0) override; virtual Expected get_buffer_frames_size() const override; virtual Expected get_pending_frames_count() const override; + virtual bool is_scheduled() override = 0; + virtual hailo_status abort() override = 0; + virtual hailo_status clear_abort() override = 0; + + virtual void notify_all() + { + // Overriden in scheduled_stream + return; + } protected: - virtual Expected sync_write_raw_buffer(const MemoryView &buffer) override; virtual hailo_status sync_write_all_raw_buffer_no_transform_impl(void *buffer, size_t offset, size_t size) override; + virtual Expected sync_write_raw_buffer(const MemoryView &buffer) override + { + return sync_write_raw_buffer(buffer, []() { return false; }); + } + virtual Expected sync_write_raw_buffer(const MemoryView &buffer, const std::function &should_cancel) = 0; -private: - friend class VDeviceInputStreamWrapper; - - explicit VDeviceInputStream( - std::vector devices, - std::vector> &&streams, - const scheduler_ng_handle_t &network_group_handle, + explicit InputVDeviceBaseStream( + std::vector> &&streams, EventPtr &&network_group_activated_event, const LayerInfo &layer_info, - NetworkGroupSchedulerWeakPtr network_group_scheduler, - hailo_stream_interface_t stream_interface, hailo_status &status) : - InputStreamBase(layer_info, stream_interface, std::move(network_group_activated_event), status), - m_network_group_handle(network_group_handle), - m_network_group_scheduler(network_group_scheduler), - m_devices(devices), + InputStreamBase(layer_info, streams[0].get().get_interface(), std::move(network_group_activated_event), status), m_streams(std::move(streams)), m_is_stream_activated(false), m_next_transfer_stream_index(0), - m_acc_frames(0), - m_stream_interface(stream_interface) + m_acc_frames(0) {} - Expected sync_write_raw_buffer_impl(const MemoryView &buffer, scheduler_ng_handle_t network_group_handle); - hailo_status abort_impl(scheduler_ng_handle_t network_group_handle); - hailo_status clear_abort_impl(scheduler_ng_handle_t network_group_handle); - virtual hailo_status flush() override; - - static Expected> create_input_stream_from_net_group( - std::vector> &resources_managers, - const LayerInfo &edge_layer, const std::string &stream_name, const scheduler_ng_handle_t &network_group_handle, - EventPtr &&network_group_activated_event, NetworkGroupSchedulerWeakPtr network_group_scheduler); - - scheduler_ng_handle_t m_network_group_handle; - NetworkGroupSchedulerWeakPtr m_network_group_scheduler; - std::vector m_devices; - std::vector> m_streams; + std::vector> m_streams; bool m_is_stream_activated; uint32_t m_next_transfer_stream_index; uint32_t m_acc_frames; - hailo_stream_interface_t m_stream_interface; + +private: + friend class VDeviceInputStreamMultiplexerWrapper; + + virtual hailo_status flush() override; }; -class VDeviceOutputStream : public OutputStreamBase { +class OutputVDeviceBaseStream : public OutputStreamBase { public: - VDeviceOutputStream(VDeviceOutputStream &&other) : + OutputVDeviceBaseStream(OutputVDeviceBaseStream &&other) : OutputStreamBase(std::move(other)), - m_network_group_handle(std::move(other.m_network_group_handle)), - m_network_group_scheduler(std::move(other.m_network_group_scheduler)), - m_devices(std::move(other.m_devices)), m_streams(std::move(other.m_streams)), m_is_stream_activated(std::exchange(other.m_is_stream_activated, false)), m_next_transfer_stream_index(other.m_next_transfer_stream_index), - m_acc_frames(other.m_acc_frames), - m_stream_interface(other.m_stream_interface) + m_acc_frames(other.m_acc_frames) {} - virtual ~VDeviceOutputStream(); + virtual ~OutputVDeviceBaseStream(); - static Expected> create(std::vector> &resources_managers, - const LayerInfo &edge_layer, const std::string &stream_name, const scheduler_ng_handle_t &network_group_handle, + static Expected> create(std::vector> &&low_level_streams, + const LayerInfo &edge_layer, const scheduler_ng_handle_t &network_group_handle, EventPtr network_group_activated_event, NetworkGroupSchedulerWeakPtr network_group_scheduler); virtual hailo_status activate_stream(uint16_t dynamic_batch_size) override; virtual hailo_status deactivate_stream() override; - virtual hailo_stream_interface_t get_interface() const override { return m_stream_interface; } + virtual hailo_stream_interface_t get_interface() const override; virtual std::chrono::milliseconds get_timeout() const override; virtual hailo_status set_timeout(std::chrono::milliseconds timeout) override; - virtual hailo_status abort() override; - virtual hailo_status clear_abort() override; - virtual bool is_scheduled() override; virtual Expected get_buffer_frames_size() const override; virtual Expected get_pending_frames_count() const override; + virtual hailo_status abort() override = 0; + virtual hailo_status clear_abort() override = 0; + virtual bool is_scheduled() override = 0; virtual hailo_status register_for_d2h_interrupts(const std::function &callback) override { for (auto &stream : m_streams) { - auto status = stream->register_for_d2h_interrupts(callback); + auto status = stream.get().register_for_d2h_interrupts(callback); CHECK_SUCCESS(status); } return HAILO_SUCCESS; @@ -144,48 +138,27 @@ public: protected: virtual Expected sync_read_raw_buffer(MemoryView &buffer) override; -private: - friend class VDeviceOutputStreamWrapper; - - explicit VDeviceOutputStream( - std::vector devices, - std::vector> &&streams, - const scheduler_ng_handle_t &network_group_handle, + explicit OutputVDeviceBaseStream( + std::vector> &&streams, const LayerInfo &layer_info, EventPtr &&network_group_activated_event, - NetworkGroupSchedulerWeakPtr network_group_scheduler, - hailo_stream_interface_t stream_interface, hailo_status &status) : OutputStreamBase(layer_info, std::move(network_group_activated_event), status), - m_network_group_handle(network_group_handle), - m_network_group_scheduler(network_group_scheduler), - m_devices(devices), m_streams(std::move(streams)), m_is_stream_activated(false), m_next_transfer_stream_index(0), - m_acc_frames(0), - m_stream_interface(stream_interface) + m_acc_frames(0) {} - hailo_status abort_impl(scheduler_ng_handle_t network_group_handle); - hailo_status clear_abort_impl(scheduler_ng_handle_t network_group_handle); virtual hailo_status read_all(MemoryView &buffer) override; - virtual hailo_status read(MemoryView buffer) override; - hailo_status read_impl(MemoryView buffer, scheduler_ng_handle_t network_group_handle); - - static Expected> create_output_stream_from_net_group( - std::vector> &resources_managers, const LayerInfo &edge_layer, - const std::string &stream_name, const scheduler_ng_handle_t &network_group_handle, EventPtr &&network_group_activated_event, - NetworkGroupSchedulerWeakPtr network_group_scheduler); - - scheduler_ng_handle_t m_network_group_handle; - NetworkGroupSchedulerWeakPtr m_network_group_scheduler; - std::vector m_devices; - std::vector> m_streams; + + std::vector> m_streams; bool m_is_stream_activated; uint32_t m_next_transfer_stream_index; uint32_t m_acc_frames; - hailo_stream_interface_t m_stream_interface; + +private: + friend class VDeviceOutputStreamMultiplexerWrapper; }; } /* namespace hailort */ diff --git a/hailort/libhailort/src/vdevice_stream_wrapper.cpp b/hailort/libhailort/src/vdevice_stream_multiplexer_wrapper.cpp similarity index 57% rename from hailort/libhailort/src/vdevice_stream_wrapper.cpp rename to hailort/libhailort/src/vdevice_stream_multiplexer_wrapper.cpp index face57b..365d7af 100644 --- a/hailort/libhailort/src/vdevice_stream_wrapper.cpp +++ b/hailort/libhailort/src/vdevice_stream_multiplexer_wrapper.cpp @@ -1,44 +1,47 @@ -#include "vdevice_stream_wrapper.hpp" +#include "vdevice_stream_multiplexer_wrapper.hpp" namespace hailort { -const hailo_stream_info_t &VDeviceInputStreamWrapper::get_info() const +const hailo_stream_info_t &VDeviceInputStreamMultiplexerWrapper::get_info() const { return m_vdevice_input_stream->get_info(); } -const CONTROL_PROTOCOL__nn_stream_config_t &VDeviceInputStreamWrapper::get_nn_stream_config() +const CONTROL_PROTOCOL__nn_stream_config_t &VDeviceInputStreamMultiplexerWrapper::get_nn_stream_config() { return m_vdevice_input_stream->get_nn_stream_config(); } -hailo_status VDeviceInputStreamWrapper::activate_stream(uint16_t dynamic_batch_size) +hailo_status VDeviceInputStreamMultiplexerWrapper::activate_stream(uint16_t dynamic_batch_size) { return m_vdevice_input_stream->activate_stream(dynamic_batch_size); } -hailo_status VDeviceInputStreamWrapper::deactivate_stream() +hailo_status VDeviceInputStreamMultiplexerWrapper::deactivate_stream() { return m_vdevice_input_stream->deactivate_stream(); } -hailo_stream_interface_t VDeviceInputStreamWrapper::get_interface() const +hailo_stream_interface_t VDeviceInputStreamMultiplexerWrapper::get_interface() const { return m_vdevice_input_stream->get_interface(); } -std::chrono::milliseconds VDeviceInputStreamWrapper::get_timeout() const +std::chrono::milliseconds VDeviceInputStreamMultiplexerWrapper::get_timeout() const { return m_vdevice_input_stream->get_timeout(); } -hailo_status VDeviceInputStreamWrapper::abort() +hailo_status VDeviceInputStreamMultiplexerWrapper::abort() { if (is_scheduled()) { auto status = m_multiplexer->disable_network_group(m_network_group_multiplexer_handle); CHECK_SUCCESS(status); + *m_is_aborted = true; + m_vdevice_input_stream->notify_all(); + // TODO: HRT-7638 status = m_multiplexer->run_once_for_stream(name(), INPUT_RUN_ONCE_HANDLE__ABORT, m_network_group_multiplexer_handle); CHECK_SUCCESS(status); @@ -46,87 +49,91 @@ hailo_status VDeviceInputStreamWrapper::abort() return HAILO_SUCCESS; } - auto status = m_vdevice_input_stream->abort_impl(m_network_group_scheduler_handle); + auto status = m_vdevice_input_stream->abort(); CHECK_SUCCESS(status); return HAILO_SUCCESS; } -hailo_status VDeviceInputStreamWrapper::clear_abort() +hailo_status VDeviceInputStreamMultiplexerWrapper::clear_abort() { if (is_scheduled()) { auto status = m_multiplexer->enable_network_group(m_network_group_multiplexer_handle); CHECK_SUCCESS(status); + *m_is_aborted = false; + status = m_multiplexer->run_once_for_stream(name(), INPUT_RUN_ONCE_HANDLE__CLEAR_ABORT, m_network_group_multiplexer_handle); CHECK_SUCCESS(status); + m_vdevice_input_stream->notify_all(); + return HAILO_SUCCESS; } - auto status = m_vdevice_input_stream->clear_abort_impl(m_network_group_scheduler_handle); + auto status = m_vdevice_input_stream->clear_abort(); CHECK_SUCCESS(status); return HAILO_SUCCESS; } -bool VDeviceInputStreamWrapper::is_scheduled() +bool VDeviceInputStreamMultiplexerWrapper::is_scheduled() { return m_vdevice_input_stream->is_scheduled(); } -Expected VDeviceInputStreamWrapper::send_pending_buffer() +hailo_status VDeviceInputStreamMultiplexerWrapper::send_pending_buffer(size_t device_index) { - return m_vdevice_input_stream->send_pending_buffer(); + return m_vdevice_input_stream->send_pending_buffer(device_index); } -Expected VDeviceInputStreamWrapper::get_buffer_frames_size() const +Expected VDeviceInputStreamMultiplexerWrapper::get_buffer_frames_size() const { return m_vdevice_input_stream->get_buffer_frames_size(); } -Expected VDeviceInputStreamWrapper::get_pending_frames_count() const +Expected VDeviceInputStreamMultiplexerWrapper::get_pending_frames_count() const { return m_vdevice_input_stream->get_pending_frames_count(); } -Expected VDeviceInputStreamWrapper::sync_write_raw_buffer(const MemoryView &buffer) +Expected VDeviceInputStreamMultiplexerWrapper::sync_write_raw_buffer(const MemoryView &buffer) { if (is_scheduled()) { auto status = m_multiplexer->wait_for_write(m_network_group_multiplexer_handle); - if (HAILO_STREAM_INTERNAL_ABORT == status) { + if (HAILO_STREAM_ABORTED_BY_USER == status) { return make_unexpected(status); } CHECK_SUCCESS_AS_EXPECTED(status); } - auto exp = m_vdevice_input_stream->sync_write_raw_buffer_impl(buffer, m_network_group_scheduler_handle); - if (HAILO_STREAM_INTERNAL_ABORT == exp.status()) { + auto exp = m_vdevice_input_stream->sync_write_raw_buffer(buffer, [this]() { return m_is_aborted->load(); }); + if (HAILO_STREAM_ABORTED_BY_USER == exp.status()) { return make_unexpected(exp.status()); } CHECK_EXPECTED(exp); if (is_scheduled()) { - auto status = m_multiplexer->signal_write_finish(); + auto status = m_multiplexer->signal_write_finish(m_network_group_multiplexer_handle); CHECK_SUCCESS_AS_EXPECTED(status); } return exp; } -hailo_status VDeviceInputStreamWrapper::sync_write_all_raw_buffer_no_transform_impl(void *buffer, size_t offset, size_t size) +hailo_status VDeviceInputStreamMultiplexerWrapper::sync_write_all_raw_buffer_no_transform_impl(void *buffer, size_t offset, size_t size) { ASSERT(NULL != buffer); return sync_write_raw_buffer(MemoryView(static_cast(buffer) + offset, size)).status(); } -hailo_status VDeviceInputStreamWrapper::set_timeout(std::chrono::milliseconds timeout) +hailo_status VDeviceInputStreamMultiplexerWrapper::set_timeout(std::chrono::milliseconds timeout) { return m_vdevice_input_stream->set_timeout(timeout); } -hailo_status VDeviceInputStreamWrapper::flush() +hailo_status VDeviceInputStreamMultiplexerWrapper::flush() { if (is_scheduled()) { auto status = m_multiplexer->run_once_for_stream(name(), INPUT_RUN_ONCE_HANDLE__FLUSH, m_network_group_multiplexer_handle); @@ -138,12 +145,12 @@ hailo_status VDeviceInputStreamWrapper::flush() return m_vdevice_input_stream->flush(); } -Expected> VDeviceInputStreamWrapper::create(std::shared_ptr vdevice_input_stream, +Expected> VDeviceInputStreamMultiplexerWrapper::create(std::shared_ptr vdevice_input_stream, std::string network_name, std::shared_ptr multiplexer, scheduler_ng_handle_t network_group_scheduler_handle, multiplexer_ng_handle_t network_group_multiplexer_handle) { hailo_status status = HAILO_UNINITIALIZED; - std::unique_ptr wrapper(new (std::nothrow) VDeviceInputStreamWrapper(vdevice_input_stream, network_name, multiplexer, + std::unique_ptr wrapper(new (std::nothrow) VDeviceInputStreamMultiplexerWrapper(vdevice_input_stream, network_name, multiplexer, network_group_scheduler_handle, network_group_multiplexer_handle, status)); CHECK_NOT_NULL_AS_EXPECTED(wrapper, HAILO_OUT_OF_HOST_MEMORY); CHECK_SUCCESS_AS_EXPECTED(status); @@ -151,7 +158,7 @@ Expected> VDeviceInputStreamWrapper:: return wrapper; } -Expected> VDeviceInputStreamWrapper::clone(multiplexer_ng_handle_t network_group_multiplexer_handle) +Expected> VDeviceInputStreamMultiplexerWrapper::clone(multiplexer_ng_handle_t network_group_multiplexer_handle) { auto wrapper = create(m_vdevice_input_stream, m_network_name, m_multiplexer, m_network_group_scheduler_handle, network_group_multiplexer_handle); CHECK_EXPECTED(wrapper); @@ -159,7 +166,7 @@ Expected> VDeviceInputStreamWrapper:: return wrapper; } -VDeviceInputStreamWrapper::VDeviceInputStreamWrapper(std::shared_ptr &vdevice_input_stream, +VDeviceInputStreamMultiplexerWrapper::VDeviceInputStreamMultiplexerWrapper(std::shared_ptr &vdevice_input_stream, std::string network_name, std::shared_ptr multiplexer, scheduler_ng_handle_t network_group_scheduler_handle, multiplexer_ng_handle_t network_group_multiplexer_handle, hailo_status &status) : InputStreamBase(vdevice_input_stream->get_info(), @@ -168,8 +175,15 @@ VDeviceInputStreamWrapper::VDeviceInputStreamWrapper(std::shared_ptr(false); + if (nullptr == m_is_aborted) { + status = HAILO_OUT_OF_HOST_MEMORY; + LOGGER__ERROR("Failed to allocate memory! status = {}", status); + return; + } status = multiplexer->register_run_once_for_stream(vdevice_input_stream->name(), INPUT_RUN_ONCE_HANDLE__FLUSH, [this] { return m_vdevice_input_stream->flush(); @@ -181,7 +195,7 @@ VDeviceInputStreamWrapper::VDeviceInputStreamWrapper(std::shared_ptrregister_run_once_for_stream(vdevice_input_stream->name(), INPUT_RUN_ONCE_HANDLE__ABORT, [this] { - return m_vdevice_input_stream->abort_impl(m_network_group_scheduler_handle); + return m_vdevice_input_stream->abort(); }); if (HAILO_SUCCESS != status) { LOGGER__ERROR("register_run_once_for_stream failed! status = {}", status); @@ -190,7 +204,7 @@ VDeviceInputStreamWrapper::VDeviceInputStreamWrapper(std::shared_ptrregister_run_once_for_stream(vdevice_input_stream->name(), INPUT_RUN_ONCE_HANDLE__CLEAR_ABORT, [this] { - return m_vdevice_input_stream->clear_abort_impl(m_network_group_scheduler_handle); + return m_vdevice_input_stream->clear_abort(); }); if (HAILO_SUCCESS != status) { LOGGER__ERROR("register_run_once_for_stream failed! status = {}", status); @@ -198,37 +212,37 @@ VDeviceInputStreamWrapper::VDeviceInputStreamWrapper(std::shared_ptrget_info(); } -const CONTROL_PROTOCOL__nn_stream_config_t &VDeviceOutputStreamWrapper::get_nn_stream_config() +const CONTROL_PROTOCOL__nn_stream_config_t &VDeviceOutputStreamMultiplexerWrapper::get_nn_stream_config() { return m_vdevice_output_stream->get_nn_stream_config(); } -hailo_status VDeviceOutputStreamWrapper::activate_stream(uint16_t dynamic_batch_size) +hailo_status VDeviceOutputStreamMultiplexerWrapper::activate_stream(uint16_t dynamic_batch_size) { return m_vdevice_output_stream->activate_stream(dynamic_batch_size); } -hailo_status VDeviceOutputStreamWrapper::deactivate_stream() +hailo_status VDeviceOutputStreamMultiplexerWrapper::deactivate_stream() { return m_vdevice_output_stream->deactivate_stream(); } -hailo_stream_interface_t VDeviceOutputStreamWrapper::get_interface() const +hailo_stream_interface_t VDeviceOutputStreamMultiplexerWrapper::get_interface() const { return m_vdevice_output_stream->get_interface(); } -std::chrono::milliseconds VDeviceOutputStreamWrapper::get_timeout() const +std::chrono::milliseconds VDeviceOutputStreamMultiplexerWrapper::get_timeout() const { return m_vdevice_output_stream->get_timeout(); } -hailo_status VDeviceOutputStreamWrapper::abort() +hailo_status VDeviceOutputStreamMultiplexerWrapper::abort() { if (is_scheduled()) { auto status = m_multiplexer->disable_network_group(m_network_group_multiplexer_handle); @@ -241,13 +255,13 @@ hailo_status VDeviceOutputStreamWrapper::abort() return HAILO_SUCCESS; } - auto status = m_vdevice_output_stream->abort_impl(m_network_group_scheduler_handle); + auto status = m_vdevice_output_stream->abort(); CHECK_SUCCESS(status); return HAILO_SUCCESS; } -hailo_status VDeviceOutputStreamWrapper::clear_abort() +hailo_status VDeviceOutputStreamMultiplexerWrapper::clear_abort() { if (is_scheduled()) { auto status = m_multiplexer->enable_network_group(m_network_group_multiplexer_handle); @@ -259,78 +273,93 @@ hailo_status VDeviceOutputStreamWrapper::clear_abort() return HAILO_SUCCESS; } - auto status = m_vdevice_output_stream->clear_abort_impl(m_network_group_scheduler_handle); + auto status = m_vdevice_output_stream->clear_abort(); CHECK_SUCCESS(status); return HAILO_SUCCESS; } -bool VDeviceOutputStreamWrapper::is_scheduled() +bool VDeviceOutputStreamMultiplexerWrapper::is_scheduled() { return m_vdevice_output_stream->is_scheduled(); } -Expected VDeviceOutputStreamWrapper::get_buffer_frames_size() const +Expected VDeviceOutputStreamMultiplexerWrapper::get_buffer_frames_size() const { return m_vdevice_output_stream->get_buffer_frames_size(); } -Expected VDeviceOutputStreamWrapper::get_pending_frames_count() const +Expected VDeviceOutputStreamMultiplexerWrapper::get_pending_frames_count() const { return m_vdevice_output_stream->get_pending_frames_count(); } -Expected VDeviceOutputStreamWrapper::sync_read_raw_buffer(MemoryView &buffer) +Expected VDeviceOutputStreamMultiplexerWrapper::sync_read_raw_buffer(MemoryView &buffer) { return m_vdevice_output_stream->sync_read_raw_buffer(buffer); } -hailo_status VDeviceOutputStreamWrapper::read_all(MemoryView &buffer) +hailo_status VDeviceOutputStreamMultiplexerWrapper::read_all(MemoryView &buffer) { return m_vdevice_output_stream->read_all(buffer); } -hailo_status VDeviceOutputStreamWrapper::read(MemoryView buffer) +hailo_status VDeviceOutputStreamMultiplexerWrapper::read(MemoryView buffer) { + uint32_t frames_to_drain_count = 0; if (is_scheduled()) { - auto status = m_multiplexer->wait_for_read(m_network_group_multiplexer_handle, name()); - if (HAILO_STREAM_INTERNAL_ABORT == status) { + auto expected_drain_count = m_multiplexer->wait_for_read(m_network_group_multiplexer_handle, name(), + m_vdevice_output_stream->get_timeout()); + if (HAILO_STREAM_ABORTED_BY_USER == expected_drain_count.status()) { + return expected_drain_count.status(); + } + CHECK_EXPECTED_AS_STATUS(expected_drain_count); + + frames_to_drain_count = expected_drain_count.release(); + } + + for (uint32_t i = 0; i < frames_to_drain_count; i++) { + auto status = m_vdevice_output_stream->read(buffer); + if ((HAILO_STREAM_ABORTED_BY_USER == status) || (HAILO_STREAM_NOT_ACTIVATED == status)) { return status; } CHECK_SUCCESS(status); } - auto status = m_vdevice_output_stream->read_impl(buffer, m_network_group_scheduler_handle); - if ((HAILO_STREAM_INTERNAL_ABORT == status) || (HAILO_STREAM_NOT_ACTIVATED == status)) { + auto status = m_vdevice_output_stream->read(buffer); + if ((HAILO_STREAM_ABORTED_BY_USER == status) || (HAILO_STREAM_NOT_ACTIVATED == status)) { return status; } CHECK_SUCCESS(status); if (is_scheduled()) { status = m_multiplexer->signal_read_finish(m_network_group_multiplexer_handle); + if (HAILO_STREAM_ABORTED_BY_USER == status) { + return status; + } CHECK_SUCCESS(status); } return HAILO_SUCCESS; } -hailo_status VDeviceOutputStreamWrapper::set_timeout(std::chrono::milliseconds timeout) +hailo_status VDeviceOutputStreamMultiplexerWrapper::set_timeout(std::chrono::milliseconds timeout) { return m_vdevice_output_stream->set_timeout(timeout); } -Expected> VDeviceOutputStreamWrapper::create(std::shared_ptr vdevice_output_stream, +Expected> VDeviceOutputStreamMultiplexerWrapper::create(std::shared_ptr vdevice_output_stream, std::string network_name, std::shared_ptr multiplexer, scheduler_ng_handle_t network_group_scheduler_handle, multiplexer_ng_handle_t network_group_multiplexer_handle) { hailo_status status = HAILO_UNINITIALIZED; - std::unique_ptr wrapper(new (std::nothrow) VDeviceOutputStreamWrapper(vdevice_output_stream, network_name, multiplexer, + std::unique_ptr wrapper(new (std::nothrow) VDeviceOutputStreamMultiplexerWrapper(vdevice_output_stream, network_name, multiplexer, network_group_scheduler_handle, network_group_multiplexer_handle, status)); CHECK_NOT_NULL_AS_EXPECTED(wrapper, HAILO_OUT_OF_HOST_MEMORY); return wrapper; } -Expected> VDeviceOutputStreamWrapper::clone(scheduler_ng_handle_t network_group_multiplexer_handle) +Expected> VDeviceOutputStreamMultiplexerWrapper::clone(scheduler_ng_handle_t network_group_multiplexer_handle) { auto wrapper = create(m_vdevice_output_stream, m_network_name, m_multiplexer, m_network_group_scheduler_handle, network_group_multiplexer_handle); CHECK_EXPECTED(wrapper); @@ -338,7 +367,7 @@ Expected> VDeviceOutputStreamWrapper return wrapper; } -VDeviceOutputStreamWrapper::VDeviceOutputStreamWrapper(std::shared_ptr &vdevice_output_stream, +VDeviceOutputStreamMultiplexerWrapper::VDeviceOutputStreamMultiplexerWrapper(std::shared_ptr &vdevice_output_stream, std::string network_name, std::shared_ptr multiplexer, scheduler_ng_handle_t network_group_scheduler_handle, multiplexer_ng_handle_t network_group_multiplexer_handle, hailo_status &status) : OutputStreamBase(vdevice_output_stream->get_layer_info(), vdevice_output_stream->get_info(), @@ -351,7 +380,7 @@ VDeviceOutputStreamWrapper::VDeviceOutputStreamWrapper(std::shared_ptrregister_run_once_for_stream(vdevice_output_stream->name(), OUTPUT_RUN_ONCE_HANDLE__ABORT, [this] { - return m_vdevice_output_stream->abort_impl(m_network_group_scheduler_handle); + return m_vdevice_output_stream->abort(); }); if (HAILO_SUCCESS != status) { LOGGER__ERROR("register_run_once_for_stream failed! status = {}", status); @@ -360,7 +389,7 @@ VDeviceOutputStreamWrapper::VDeviceOutputStreamWrapper(std::shared_ptrregister_run_once_for_stream(vdevice_output_stream->name(), OUTPUT_RUN_ONCE_HANDLE__CLEAR_ABORT, [this] { - return m_vdevice_output_stream->clear_abort_impl(m_network_group_scheduler_handle); + return m_vdevice_output_stream->clear_abort(); }); if (HAILO_SUCCESS != status) { LOGGER__ERROR("register_run_once_for_stream failed! status = {}", status); diff --git a/hailort/libhailort/src/vdevice_stream_wrapper.hpp b/hailort/libhailort/src/vdevice_stream_multiplexer_wrapper.hpp similarity index 63% rename from hailort/libhailort/src/vdevice_stream_wrapper.hpp rename to hailort/libhailort/src/vdevice_stream_multiplexer_wrapper.hpp index 390c5ac..ddb9cba 100644 --- a/hailort/libhailort/src/vdevice_stream_wrapper.hpp +++ b/hailort/libhailort/src/vdevice_stream_multiplexer_wrapper.hpp @@ -3,17 +3,17 @@ * Distributed under the MIT license (https://opensource.org/licenses/MIT) **/ /** - * @file vdevice_stream_wrapper.hpp + * @file vdevice_stream_multiplexer_wrapper.hpp * @brief Wrapper classes for VDeviceInputStream and VDeviceOutputStream **/ -#ifndef HAILO_VDEVICE_STREAM_WRAPPER_HPP_ -#define HAILO_VDEVICE_STREAM_WRAPPER_HPP_ +#ifndef HAILO_VDEVICE_STREAM_MULTIPLEXER_WRAPPER_HPP_ +#define HAILO_VDEVICE_STREAM_MULTIPLEXER_WRAPPER_HPP_ #include "vdevice_stream.hpp" #include "stream_internal.hpp" #include "hailo/expected.hpp" -#include "context_switch/pipeline_multiplexer.hpp" +#include "pipeline_multiplexer.hpp" namespace hailort { @@ -29,18 +29,18 @@ enum output_run_once_handle_t { OUTPUT_RUN_ONCE_HANDLE__CLEAR_ABORT }; -class VDeviceInputStreamWrapper : public InputStreamBase { +class VDeviceInputStreamMultiplexerWrapper : public InputStreamBase { public: - virtual ~VDeviceInputStreamWrapper() = default; - VDeviceInputStreamWrapper(const VDeviceInputStreamWrapper &other) = delete; - VDeviceInputStreamWrapper &operator=(const VDeviceInputStreamWrapper &other) = delete; - VDeviceInputStreamWrapper &operator=(VDeviceInputStreamWrapper &&other) = delete; - VDeviceInputStreamWrapper(VDeviceInputStreamWrapper &&other) = default; + virtual ~VDeviceInputStreamMultiplexerWrapper() = default; + VDeviceInputStreamMultiplexerWrapper(const VDeviceInputStreamMultiplexerWrapper &other) = delete; + VDeviceInputStreamMultiplexerWrapper &operator=(const VDeviceInputStreamMultiplexerWrapper &other) = delete; + VDeviceInputStreamMultiplexerWrapper &operator=(VDeviceInputStreamMultiplexerWrapper &&other) = delete; + VDeviceInputStreamMultiplexerWrapper(VDeviceInputStreamMultiplexerWrapper &&other) = default; - static Expected> create(std::shared_ptr vdevice_input_stream, + static Expected> create(std::shared_ptr vdevice_input_stream, std::string network_name, std::shared_ptr multiplexer, scheduler_ng_handle_t network_group_scheduler_handle, multiplexer_ng_handle_t network_group_multiplexer_handle = 0); - Expected> clone(multiplexer_ng_handle_t network_group_multiplexer_handle); + Expected> clone(multiplexer_ng_handle_t network_group_multiplexer_handle); virtual const hailo_stream_info_t &get_info() const override; virtual const CONTROL_PROTOCOL__nn_stream_config_t &get_nn_stream_config() override; @@ -52,7 +52,7 @@ public: virtual hailo_status clear_abort() override; virtual bool is_scheduled() override; - virtual Expected send_pending_buffer() override; + virtual hailo_status send_pending_buffer(size_t device_index = 0) override; virtual Expected get_buffer_frames_size() const override; virtual Expected get_pending_frames_count() const override; @@ -61,32 +61,34 @@ protected: virtual hailo_status sync_write_all_raw_buffer_no_transform_impl(void *buffer, size_t offset, size_t size) override; private: - VDeviceInputStreamWrapper(std::shared_ptr &vdevice_input_stream, + VDeviceInputStreamMultiplexerWrapper(std::shared_ptr &vdevice_input_stream, std::string network_name, std::shared_ptr multiplexer, scheduler_ng_handle_t network_group_scheduler_handle, multiplexer_ng_handle_t network_group_multiplexer_handle, hailo_status &status); virtual hailo_status set_timeout(std::chrono::milliseconds timeout) override; virtual hailo_status flush() override; - std::shared_ptr m_vdevice_input_stream; + std::shared_ptr m_vdevice_input_stream; std::shared_ptr m_multiplexer; scheduler_ng_handle_t m_network_group_scheduler_handle; multiplexer_ng_handle_t m_network_group_multiplexer_handle; std::string m_network_name; + + std::unique_ptr m_is_aborted; }; -class VDeviceOutputStreamWrapper : public OutputStreamBase { +class VDeviceOutputStreamMultiplexerWrapper : public OutputStreamBase { public: - virtual ~VDeviceOutputStreamWrapper() noexcept = default; - VDeviceOutputStreamWrapper(const VDeviceOutputStreamWrapper &other) = delete; - VDeviceOutputStreamWrapper &operator=(const VDeviceOutputStreamWrapper &other) = delete; - VDeviceOutputStreamWrapper &operator=(VDeviceOutputStreamWrapper &&other) = delete; - VDeviceOutputStreamWrapper(VDeviceOutputStreamWrapper &&other) = default; + virtual ~VDeviceOutputStreamMultiplexerWrapper() noexcept = default; + VDeviceOutputStreamMultiplexerWrapper(const VDeviceOutputStreamMultiplexerWrapper &other) = delete; + VDeviceOutputStreamMultiplexerWrapper &operator=(const VDeviceOutputStreamMultiplexerWrapper &other) = delete; + VDeviceOutputStreamMultiplexerWrapper &operator=(VDeviceOutputStreamMultiplexerWrapper &&other) = delete; + VDeviceOutputStreamMultiplexerWrapper(VDeviceOutputStreamMultiplexerWrapper &&other) = default; - static Expected> create(std::shared_ptr vdevice_output_stream, + static Expected> create(std::shared_ptr vdevice_output_stream, std::string network_name, std::shared_ptr multiplexer, scheduler_ng_handle_t network_group_scheduler_handle, multiplexer_ng_handle_t network_group_multiplexer_handle = 0); - Expected> clone(multiplexer_ng_handle_t network_group_multiplexer_handle); + Expected> clone(multiplexer_ng_handle_t network_group_multiplexer_handle); virtual const hailo_stream_info_t &get_info() const override; virtual const CONTROL_PROTOCOL__nn_stream_config_t &get_nn_stream_config() override; @@ -109,7 +111,7 @@ protected: virtual Expected sync_read_raw_buffer(MemoryView &buffer) override; private: - VDeviceOutputStreamWrapper(std::shared_ptr &vdevice_output_stream, + VDeviceOutputStreamMultiplexerWrapper(std::shared_ptr &vdevice_output_stream, std::string network_name, std::shared_ptr multiplexer, scheduler_ng_handle_t network_group_scheduler_handle, multiplexer_ng_handle_t network_group_multiplexer_handle, hailo_status &status); @@ -117,7 +119,7 @@ private: virtual hailo_status read_all(MemoryView &buffer) override; virtual hailo_status read(MemoryView buffer) override; - std::shared_ptr m_vdevice_output_stream; + std::shared_ptr m_vdevice_output_stream; std::shared_ptr m_multiplexer; scheduler_ng_handle_t m_network_group_scheduler_handle; multiplexer_ng_handle_t m_network_group_multiplexer_handle; @@ -127,4 +129,4 @@ private: } /* namespace hailort */ -#endif /* HAILO_VDEVICE_STREAM_WRAPPER_HPP_ */ +#endif /* HAILO_VDEVICE_STREAM_MULTIPLEXER_WRAPPER_HPP_ */ diff --git a/hailort/libhailort/src/vdma/continuous_buffer.cpp b/hailort/libhailort/src/vdma/continuous_buffer.cpp index 562cdcc..53a26da 100644 --- a/hailort/libhailort/src/vdma/continuous_buffer.cpp +++ b/hailort/libhailort/src/vdma/continuous_buffer.cpp @@ -96,7 +96,7 @@ uint32_t ContinuousBuffer::descs_count() const return descriptors_in_buffer(m_size); } -hailo_status ContinuousBuffer::read(void *buf_dst, size_t count, size_t offset) +hailo_status ContinuousBuffer::read(void *buf_dst, size_t count, size_t offset, bool /* should_sync */) { CHECK((count + offset) <= m_size, HAILO_INSUFFICIENT_BUFFER, "Requested size {} from offset {} is more than the buffer size {}", count, offset, m_size); diff --git a/hailort/libhailort/src/vdma/continuous_buffer.hpp b/hailort/libhailort/src/vdma/continuous_buffer.hpp index 481d9ce..0e5f088 100644 --- a/hailort/libhailort/src/vdma/continuous_buffer.hpp +++ b/hailort/libhailort/src/vdma/continuous_buffer.hpp @@ -50,7 +50,7 @@ public: virtual uint16_t desc_page_size() const override; virtual uint32_t descs_count() const override; - virtual hailo_status read(void *buf_dst, size_t count, size_t offset) override; + virtual hailo_status read(void *buf_dst, size_t count, size_t offset, bool should_sync) override; virtual hailo_status write(const void *buf_src, size_t count, size_t offset) override; virtual Expected program_descriptors(size_t transfer_size, VdmaInterruptsDomain first_desc_interrupts_domain, diff --git a/hailort/libhailort/src/vdma/mapped_buffer.cpp b/hailort/libhailort/src/vdma/mapped_buffer.cpp index fa1d0fc..bfe0e40 100644 --- a/hailort/libhailort/src/vdma/mapped_buffer.cpp +++ b/hailort/libhailort/src/vdma/mapped_buffer.cpp @@ -1,5 +1,4 @@ #include "mapped_buffer.hpp" -#include "microprofile.h" namespace hailort { namespace vdma { @@ -72,7 +71,7 @@ hailo_status MappedBuffer::write(const void *buf_src, size_t count, size_t offse return HAILO_SUCCESS; } -hailo_status MappedBuffer::read(void *buf_dst, size_t count, size_t offset) +hailo_status MappedBuffer::read(void *buf_dst, size_t count, size_t offset, bool should_sync) { if ((count + offset) > m_size) { LOGGER__ERROR("Requested size {} from offset {} is more than the MappedBuffer size {}", count, offset, m_size); @@ -80,11 +79,10 @@ hailo_status MappedBuffer::read(void *buf_dst, size_t count, size_t offset) } if (count > 0) { - auto dst_vdma_address = (uint8_t*)m_vdma_mapped_buffer->get() + offset; - auto status = m_driver.vdma_buffer_sync(m_handle, HailoRTDriver::DmaDirection::D2H, dst_vdma_address, count); - if (HAILO_SUCCESS != status) { - LOGGER__ERROR("Failed synching vdma buffer on read"); - return status; + const auto dst_vdma_address = (uint8_t*)m_vdma_mapped_buffer->get() + offset; + if (should_sync) { + const auto status = m_driver.vdma_buffer_sync(m_handle, HailoRTDriver::DmaDirection::D2H, dst_vdma_address, count); + CHECK_SUCCESS(status, "Failed synching vdma buffer on read"); } memcpy(buf_dst, dst_vdma_address, count); @@ -95,7 +93,6 @@ hailo_status MappedBuffer::read(void *buf_dst, size_t count, size_t offset) hailo_status MappedBuffer::write_cyclic(const void *buf_src, size_t count, size_t offset) { - MICROPROFILE_SCOPEI("vDMA", "Write buffer", 0); if (count > m_size) { LOGGER__ERROR("Requested size({}) is more than the MappedBuffer size {}", count, m_size); return HAILO_INSUFFICIENT_BUFFER; @@ -119,9 +116,8 @@ hailo_status MappedBuffer::write_cyclic(const void *buf_src, size_t count, size_ return HAILO_SUCCESS; } -hailo_status MappedBuffer::read_cyclic(void *buf_dst, size_t count, size_t offset) +hailo_status MappedBuffer::read_cyclic(void *buf_dst, size_t count, size_t offset, bool should_sync) { - MICROPROFILE_SCOPEI("vDMA", "Read buffer", 0); if (count > m_size) { LOGGER__ERROR("Requested size({}) is more than the MappedBuffer size {}", count, m_size); return HAILO_INSUFFICIENT_BUFFER; @@ -129,14 +125,14 @@ hailo_status MappedBuffer::read_cyclic(void *buf_dst, size_t count, size_t offse auto size_to_end = m_size - offset; auto copy_size = std::min(size_to_end, count); - auto status = read(buf_dst, copy_size, offset); + auto status = read(buf_dst, copy_size, offset, should_sync); if (HAILO_SUCCESS != status) { return status; } auto remaining_size = count - copy_size; if (remaining_size > 0) { - status = read((uint8_t*)buf_dst + copy_size, remaining_size, 0); + status = read((uint8_t*)buf_dst + copy_size, remaining_size, 0, should_sync); if (HAILO_SUCCESS != status) { return status; } diff --git a/hailort/libhailort/src/vdma/mapped_buffer.hpp b/hailort/libhailort/src/vdma/mapped_buffer.hpp index b5b4c18..5fa81d7 100644 --- a/hailort/libhailort/src/vdma/mapped_buffer.hpp +++ b/hailort/libhailort/src/vdma/mapped_buffer.hpp @@ -67,8 +67,10 @@ public: * @param[out] buf_dst The buffer to copy the data to * @param[in] count Number of bytes to copy to buf_dst * @param[in] offset The offset relative to this MappedBuffer to copy the data from + * @param[in] should_sync If the backing memory is vdma and it's written to by a device, sync should be true + * so that the read will be consistent with the backing memory */ - hailo_status read(void *buf_dst, size_t count, size_t offset); + hailo_status read(void *buf_dst, size_t count, size_t offset, bool should_sync = true); /** * Copy data from buf_src parameter to this MappedBuffer. @@ -95,8 +97,10 @@ public: * @param[out] buf_dst The buffer to copy the data to * @param[in] count Number of bytes to copy to buf_dst * @param[in] offset The offset relative to this MappedBuffer to copy the data from + * @param[in] should_sync If the backing memory is vdma and it's written to by a device, sync should be true + * so that the read will be consistent with the backing memory */ - hailo_status read_cyclic(void *buf_dst, size_t count, size_t offset); + hailo_status read_cyclic(void *buf_dst, size_t count, size_t offset, bool should_sync = true); private: diff --git a/hailort/libhailort/src/vdma/sg_buffer.cpp b/hailort/libhailort/src/vdma/sg_buffer.cpp index c02066f..d2d0f68 100644 --- a/hailort/libhailort/src/vdma/sg_buffer.cpp +++ b/hailort/libhailort/src/vdma/sg_buffer.cpp @@ -58,9 +58,9 @@ ExpectedRef SgBuffer::get_desc_list() return std::ref(m_desc_list); } -hailo_status SgBuffer::read(void *buf_dst, size_t count, size_t offset) +hailo_status SgBuffer::read(void *buf_dst, size_t count, size_t offset, bool should_sync) { - return m_mapped_buffer.read(buf_dst, count, offset); + return m_mapped_buffer.read(buf_dst, count, offset, should_sync); } hailo_status SgBuffer::write(const void *buf_src, size_t count, size_t offset) @@ -68,9 +68,9 @@ hailo_status SgBuffer::write(const void *buf_src, size_t count, size_t offset) return m_mapped_buffer.write(buf_src, count, offset); } -hailo_status SgBuffer::read_cyclic(void *buf_dst, size_t count, size_t offset) +hailo_status SgBuffer::read_cyclic(void *buf_dst, size_t count, size_t offset, bool should_sync) { - return m_mapped_buffer.read_cyclic(buf_dst, count, offset); + return m_mapped_buffer.read_cyclic(buf_dst, count, offset, should_sync); } hailo_status SgBuffer::write_cyclic(const void *buf_src, size_t count, size_t offset) @@ -78,6 +78,12 @@ hailo_status SgBuffer::write_cyclic(const void *buf_src, size_t count, size_t of return m_mapped_buffer.write_cyclic(buf_src, count, offset); } +// TODO: Remove after HRT-7838 +void* SgBuffer::get_user_address() +{ + return m_mapped_buffer.user_address(); +} + Expected SgBuffer::program_descriptors(size_t transfer_size, VdmaInterruptsDomain first_desc_interrupts_domain, VdmaInterruptsDomain last_desc_interrupts_domain, size_t desc_offset, bool is_circular) { @@ -94,5 +100,10 @@ hailo_status SgBuffer::reprogram_device_interrupts_for_end_of_batch(size_t trans return m_desc_list.reprogram_descriptor_interrupts_domain(last_desc_index_in_batch, new_interrupts_domain); } +hailo_status SgBuffer::reprogram_buffer_offset(size_t new_start_offset, uint8_t channel_index) +{ + return m_desc_list.configure_to_use_buffer(m_mapped_buffer, channel_index, new_start_offset); +} + } } \ No newline at end of file diff --git a/hailort/libhailort/src/vdma/sg_buffer.hpp b/hailort/libhailort/src/vdma/sg_buffer.hpp index fb79fcb..6f097b6 100644 --- a/hailort/libhailort/src/vdma/sg_buffer.hpp +++ b/hailort/libhailort/src/vdma/sg_buffer.hpp @@ -47,17 +47,23 @@ public: uint8_t depth() const; ExpectedRef get_desc_list(); + // TODO: Remove after HRT-7838 + void *get_user_address(); - virtual hailo_status read(void *buf_dst, size_t count, size_t offset) override; + virtual hailo_status read(void *buf_dst, size_t count, size_t offset, bool should_sync) override; virtual hailo_status write(const void *buf_src, size_t count, size_t offset) override; - hailo_status read_cyclic(void *buf_dst, size_t count, size_t offset); + hailo_status read_cyclic(void *buf_dst, size_t count, size_t offset, bool should_sync = true); hailo_status write_cyclic(const void *buf_src, size_t count, size_t offset); virtual Expected program_descriptors(size_t transfer_size, VdmaInterruptsDomain first_desc_interrupts_domain, VdmaInterruptsDomain last_desc_interrupts_domain, size_t desc_offset, bool is_circular) override; virtual hailo_status reprogram_device_interrupts_for_end_of_batch(size_t transfer_size, uint16_t batch_size, VdmaInterruptsDomain new_interrupts_domain) override; + + // TODO: after HRT-8519 the VdmaDescriptorList will be owned by the vdma channel and this function can be removed + // (VdmaChannel::reprogram_buffer_offset will call VdmaDescriptorList::configure_to_use_buffer directly) + hailo_status reprogram_buffer_offset(size_t new_start_offset, uint8_t channel_index); private: SgBuffer(VdmaDescriptorList &&desc_list, MappedBuffer &&mapped_buffer) : diff --git a/hailort/libhailort/src/vdma/vdma_buffer.hpp b/hailort/libhailort/src/vdma/vdma_buffer.hpp index 2474a91..fabb4cb 100644 --- a/hailort/libhailort/src/vdma/vdma_buffer.hpp +++ b/hailort/libhailort/src/vdma/vdma_buffer.hpp @@ -47,7 +47,7 @@ public: return static_cast(DESCRIPTORS_IN_BUFFER(buffer_size, page_size)); } - virtual hailo_status read(void *buf_dst, size_t count, size_t offset) = 0; + virtual hailo_status read(void *buf_dst, size_t count, size_t offset, bool should_sync = true) = 0; virtual hailo_status write(const void *buf_src, size_t count, size_t offset) = 0; virtual Expected program_descriptors(size_t transfer_size, VdmaInterruptsDomain first_desc_interrupts_domain, diff --git a/hailort/libhailort/src/vdma/vdma_mapped_buffer_impl.cpp b/hailort/libhailort/src/vdma/vdma_mapped_buffer_impl.cpp index 1188b64..f299f46 100644 --- a/hailort/libhailort/src/vdma/vdma_mapped_buffer_impl.cpp +++ b/hailort/libhailort/src/vdma/vdma_mapped_buffer_impl.cpp @@ -37,6 +37,8 @@ VdmaMappedBufferImpl::~VdmaMappedBufferImpl() #elif defined(__QNX__) +#include + const int VdmaMappedBufferImpl::INVALID_FD = -1; const shm_handle_t VdmaMappedBufferImpl::INVALID_HANDLE = (shm_handle_t)-1; const char* VdmaMappedBufferImpl::VDMA_BUFFER_TYPE_MEMORY_NAME = "/memory/below4G/ram/below1G"; diff --git a/hailort/libhailort/src/vdma_channel.cpp b/hailort/libhailort/src/vdma_channel.cpp index 1dad777..211afbb 100644 --- a/hailort/libhailort/src/vdma_channel.cpp +++ b/hailort/libhailort/src/vdma_channel.cpp @@ -3,7 +3,6 @@ #include "hw_consts.hpp" #include "common/logger_macros.hpp" #include "common/utils.hpp" -#include "microprofile.h" #include "vdma/sg_buffer.hpp" #include "vdma_descriptor_list.hpp" @@ -40,7 +39,7 @@ void VdmaChannel::State::lock() int err = pthread_mutex_lock(&m_state_lock); if (0 != err) { LOGGER__ERROR("Failed destory vdma channel mutex, errno {}", err); - assert(true); + assert(false); } #else EnterCriticalSection(&m_state_lock); @@ -59,7 +58,7 @@ void VdmaChannel::State::unlock() } Expected VdmaChannel::create(vdma::ChannelId channel_id, Direction direction, HailoRTDriver &driver, - uint16_t requested_desc_page_size, uint32_t stream_index, LatencyMeterPtr latency_meter, uint16_t transfers_per_axi_intr) + uint16_t requested_desc_page_size, const std::string &stream_name, LatencyMeterPtr latency_meter, uint16_t transfers_per_axi_intr) { CHECK_AS_EXPECTED(Direction::BOTH != direction, HAILO_INVALID_ARGUMENT); @@ -72,7 +71,7 @@ Expected VdmaChannel::create(vdma::ChannelId channel_id, Direction CHECK_AS_EXPECTED(channel_id.engine_index < driver.dma_engines_count(), HAILO_INVALID_ARGUMENT, "Invalid DMA engine index {}, max {}", channel_id.engine_index, driver.dma_engines_count()); - VdmaChannel object(channel_id, direction, driver, stream_index, latency_meter, desc_page_size_value, + VdmaChannel object(channel_id, direction, driver, stream_name, latency_meter, desc_page_size_value, transfers_per_axi_intr, status); if (HAILO_SUCCESS != status) { LOGGER__ERROR("Failed creating VdmaChannel"); @@ -82,13 +81,14 @@ Expected VdmaChannel::create(vdma::ChannelId channel_id, Direction } VdmaChannel::VdmaChannel(vdma::ChannelId channel_id, Direction direction, HailoRTDriver &driver, - uint32_t stream_index, LatencyMeterPtr latency_meter, uint16_t desc_page_size, uint16_t transfers_per_axi_intr, + const std::string &stream_name, LatencyMeterPtr latency_meter, uint16_t desc_page_size, uint16_t transfers_per_axi_intr, hailo_status &status) : m_d2h_callback_thread(nullptr), m_channel_id(channel_id), m_direction(direction), m_driver(driver), m_host_registers(driver, channel_id, direction), - m_device_registers(driver, channel_id, other_direction(direction)), m_desc_page_size(desc_page_size), - m_stream_index(stream_index), m_latency_meter(latency_meter), m_channel_enabled(false), m_channel_is_active(false), + m_device_registers(driver, channel_id, other_direction(direction)), + m_desc_page_size(desc_page_size), + m_stream_name(stream_name), m_latency_meter(latency_meter), m_channel_enabled(false), m_transfers_per_axi_intr(transfers_per_axi_intr), m_pending_buffers_sizes(0), m_pending_num_avail_offset(0), m_is_waiting_for_channel_completion(false), m_is_aborted_by_internal_source(false) { @@ -107,7 +107,7 @@ VdmaChannel::VdmaChannel(vdma::ChannelId channel_id, Direction direction, HailoR m_channel_handle = channel_handle_memory.release(); *m_channel_handle = HailoRTDriver::INVALID_VDMA_CHANNEL_HANDLE; - // The channel will become active after calling start_allocated_channel(). + // The fw activates the channel (in ResourcesManager::enable_state_machine) // The driver cleans the channel's state, in case the last shutdown wasn't successful. m_channel_enabled = true; @@ -147,29 +147,24 @@ VdmaChannel::VdmaChannel(VdmaChannel &&other) noexcept: m_device_registers(std::move(other.m_device_registers)), m_desc_page_size(other.m_desc_page_size), m_buffer(std::move(other.m_buffer)), - m_stream_index(std::move(other.m_stream_index)), + m_stream_name(std::move(other.m_stream_name)), m_latency_meter(std::move(other.m_latency_meter)), m_state(std::move(other.m_state)), m_channel_handle(std::move(other.m_channel_handle)), m_channel_enabled(std::exchange(other.m_channel_enabled, false)), - m_channel_is_active(std::exchange(other.m_channel_is_active, false)), m_transfers_per_axi_intr(std::move(other.m_transfers_per_axi_intr)), m_pending_buffers_sizes(std::move(other.m_pending_buffers_sizes)), - m_pending_num_avail_offset(std::move(other.m_pending_num_avail_offset)), + m_pending_num_avail_offset(other.m_pending_num_avail_offset.exchange(0)), m_is_waiting_for_channel_completion(other.m_is_waiting_for_channel_completion.exchange(false)), m_is_aborted_by_internal_source(other.m_is_aborted_by_internal_source.exchange(false)) {} hailo_status VdmaChannel::stop_channel() { - { - std::unique_lock lock(m_is_active_flag_mutex); - m_channel_is_active = false; - } - if (!m_state) { const auto status = unregister_fw_controlled_channel(); CHECK_SUCCESS(status, "Failed to disable channel {}", m_channel_id); + } else { std::unique_lock state_guard(*m_state); const auto status = unregister_fw_controlled_channel(); @@ -178,9 +173,16 @@ hailo_status VdmaChannel::stop_channel() if (Direction::D2H == m_direction) { unregister_for_d2h_interrupts(state_guard); } else { + if (m_state->m_should_reprogram_buffer || !m_pending_buffers_sizes.empty()) { + // If we've already reprogrammed the buffer or there are pending buffers, we'll set m_previous_tail + const auto curr_tail = CB_TAIL(m_state->m_descs); + m_state->m_previous_tail = (curr_tail + m_state->m_previous_tail) & m_state->m_descs.size_mask; + m_state->m_should_reprogram_buffer = true; + } // For H2D channels we reset counters as we want to allow writes to the start of the buffer while the channel is stopped reset_internal_counters(); } + } return HAILO_SUCCESS; } @@ -198,7 +200,11 @@ Expected VdmaChannel::get_boundary_buffer_ hailo_status VdmaChannel::abort() { - m_is_aborted_by_internal_source = true; + { + std::lock_guard state_guard(*m_state); + m_is_aborted_by_internal_source = true; + } + if (Direction::H2D == m_direction) { m_can_write_buffer_cv.notify_all(); } else { @@ -210,7 +216,10 @@ hailo_status VdmaChannel::abort() hailo_status VdmaChannel::clear_abort() { auto status = m_driver.vdma_channel_clear_abort(m_channel_id, *m_channel_handle); - m_is_aborted_by_internal_source = false; + { + std::lock_guard state_guard(*m_state); + m_is_aborted_by_internal_source = false; + } return status; } @@ -316,6 +325,8 @@ hailo_status VdmaChannel::allocate_resources(uint32_t descs_count) CB_INIT(m_state->m_descs, descs_count); CB_INIT(m_state->m_buffers, pending_buffers_size); + m_state->m_previous_tail = 0; + m_state->m_should_reprogram_buffer = false; // Allocate descriptor list (host side) auto status = allocate_buffer(descs_count * m_desc_page_size); @@ -336,32 +347,48 @@ void VdmaChannel::reset_internal_counters() m_state->m_accumulated_transfers = 0; } -hailo_status VdmaChannel::start_allocated_channel(uint32_t transfer_size) +hailo_status VdmaChannel::complete_channel_activation(uint32_t transfer_size) { /* descriptor buffer must be allocated */ assert(m_buffer); assert(m_state); std::lock_guard state_guard(*m_state); - reset_internal_counters(); - auto status = start_channel(); - CHECK_SUCCESS(status, "failed to start channel {}", m_channel_id); + CHECK(HailoRTDriver::INVALID_VDMA_CHANNEL_HANDLE != *m_channel_handle, + HAILO_INTERNAL_FAILURE, "Vdma channel must be registered before activation"); + + reset_internal_counters(); if ((Direction::D2H == m_direction) && (transfer_size != 0)) { - status = prepare_d2h_pending_descriptors(transfer_size); + auto status = prepare_d2h_pending_descriptors(transfer_size); if (HAILO_SUCCESS != status) { stop_channel(); } return status; } - m_channel_is_active = true; + + // We should have no active transfers now + if (m_state->m_should_reprogram_buffer) { + auto status = m_buffer->reprogram_buffer_offset(m_state->m_previous_tail * m_desc_page_size, m_channel_id.channel_index); + CHECK_SUCCESS(status); + } return HAILO_SUCCESS; } hailo_status VdmaChannel::register_fw_controlled_channel() { - return register_channel_to_driver(HailoRTDriver::INVALID_DRIVER_BUFFER_HANDLE_VALUE); + return register_channel_to_driver(); +} + +void VdmaChannel::notify_all() +{ + { + // Acquire mutex to make sure the notify_all will wake the blocking threads on the cv + std::lock_guard state_guard(*m_state); + } + m_can_write_buffer_cv.notify_all(); + m_can_read_buffer_cv.notify_all(); } hailo_status VdmaChannel::register_for_d2h_interrupts(const std::function &callback) @@ -397,8 +424,8 @@ void VdmaChannel::wait_d2h_callback(const std::function &callbac } while (true) { auto status = wait_for_channel_completion(HAILO_INFINITE_TIMEOUT, callback); - if (HAILO_SUCCESS == status || (HAILO_STREAM_INTERNAL_ABORT == status)) { - // Ignore HAILO_STREAM_INTERNAL_ABORT as we want to keep waiting for interrupts until channel is stopped + if (HAILO_SUCCESS == status || (HAILO_STREAM_ABORTED_BY_USER == status)) { + // Ignore HAILO_STREAM_ABORTED_BY_USER as we want to keep waiting for interrupts until channel is stopped continue; } else if (HAILO_STREAM_NOT_ACTIVATED == status) { // Finish gracefully @@ -425,14 +452,14 @@ hailo_status VdmaChannel::wait(size_t buffer_size, std::chrono::milliseconds tim hailo_status status = HAILO_SUCCESS; // Best effort bool was_successful = m_can_read_buffer_cv.wait_for(state_guard, timeout, [this, buffer_size, &status] () { if ((!m_channel_enabled) || (m_is_aborted_by_internal_source)) { - status = HAILO_STREAM_INTERNAL_ABORT; + status = HAILO_STREAM_ABORTED_BY_USER; return true; // return true so that the wait will finish } return is_ready_for_transfer_d2h(buffer_size); }); - if (HAILO_STREAM_INTERNAL_ABORT == status) { + if (HAILO_STREAM_ABORTED_BY_USER == status) { LOGGER__INFO("wait_for in d2h wait was aborted!"); - return HAILO_STREAM_INTERNAL_ABORT; + return HAILO_STREAM_ABORTED_BY_USER; } CHECK(was_successful, HAILO_TIMEOUT); return HAILO_SUCCESS; @@ -452,6 +479,11 @@ hailo_status VdmaChannel::transfer(void *buf, size_t count) assert(m_state); std::lock_guard state_guard(*m_state); + if (m_is_aborted_by_internal_source) { + LOGGER__INFO("Tried to write to aborted channel {}", m_channel_id); + return HAILO_STREAM_ABORTED_BY_USER; + } + if (Direction::H2D == m_direction) { status = transfer_h2d(buf, count); if (HAILO_STREAM_NOT_ACTIVATED == status) { @@ -489,7 +521,7 @@ hailo_status VdmaChannel::write_buffer_impl(const MemoryView &buffer) assert(CB_AVAIL(m_state->m_descs, desc_avail, CB_TAIL(m_state->m_descs)) >= static_cast(desired_desc_num)); /* Copy buffer into the PLDA data struct */ - auto offset = desc_avail * m_desc_page_size; + auto offset = ((desc_avail + m_state->m_previous_tail) & m_state->m_descs.size_mask) * m_desc_page_size; auto status = m_buffer->write_cyclic(buffer.data(), buffer.size(), offset); CHECK_SUCCESS(status); @@ -500,24 +532,76 @@ hailo_status VdmaChannel::write_buffer_impl(const MemoryView &buffer) return HAILO_SUCCESS; } -hailo_status VdmaChannel::write_buffer(const MemoryView &buffer, std::chrono::milliseconds timeout) +Expected VdmaChannel::get_buffer_state() +{ + BufferState result; + result.num_avail = static_cast(CB_HEAD(m_state->m_descs)); + result.num_processed = static_cast(CB_TAIL(m_state->m_descs)); + auto hw_num_avail = m_host_registers.get_num_available(); + CHECK_EXPECTED(hw_num_avail); + result.hw_num_avail = hw_num_avail.release(); + auto hw_num_processed = get_hw_num_processed(); + CHECK_EXPECTED(hw_num_processed); + result.hw_num_processed = hw_num_processed.release(); + + // Get a snapshot of the buffer + auto vdma_buffer_copy = Buffer::create(m_buffer->size()); + CHECK_EXPECTED(vdma_buffer_copy); + // If this a D2H channel, we need to sync the vdma buffer so that we'll get an updated view of the buffer + const auto sync_needed = Direction::D2H == m_direction; + const auto status = m_buffer->read_cyclic(vdma_buffer_copy->data(), vdma_buffer_copy->size(), 0, sync_needed); + CHECK_SUCCESS_AS_EXPECTED(status); + + for (size_t offset = 0; offset < vdma_buffer_copy->size(); offset += m_desc_page_size) { + auto chunk = Buffer::create(vdma_buffer_copy->data() + offset, m_desc_page_size); + CHECK_EXPECTED(chunk); + const auto abs_index = offset / m_desc_page_size; + const auto desc_num = (abs_index >= static_cast(m_state->m_previous_tail)) ? + abs_index - m_state->m_previous_tail : + m_state->m_descs.size - m_state->m_previous_tail + abs_index; + result.desc_buffer_pairing.emplace_back(static_cast(desc_num), chunk.release()); + } + + return result; +} + +hailo_status VdmaChannel::write_buffer(const MemoryView &buffer, std::chrono::milliseconds timeout, + const std::function &should_cancel) { assert(m_state); std::unique_lock state_guard(*m_state); size_t desired_desc_num = m_buffer->descriptors_in_buffer(buffer.size()); hailo_status channel_completion_status = HAILO_SUCCESS; - bool was_successful = m_can_write_buffer_cv.wait_for(state_guard, timeout, [this, desired_desc_num, timeout, &state_guard, - &channel_completion_status] () { + bool was_successful = m_can_write_buffer_cv.wait_for(state_guard, timeout, [this, desired_desc_num, timeout, &should_cancel, + &state_guard, &channel_completion_status] () { if ((!m_channel_enabled) || (m_is_aborted_by_internal_source)) { return true; } + if (should_cancel()) { + channel_completion_status = HAILO_STREAM_ABORTED_BY_USER; + return true; + } + + // Limit writes to not surpass size of m_buffers + int written_buffers_count = static_cast(m_pending_buffers_sizes.size()); + int sent_buffers_count = CB_PROG(m_state->m_buffers, CB_HEAD(m_state->m_buffers), CB_TAIL(m_state->m_buffers)); + if (written_buffers_count + sent_buffers_count >= CB_SIZE(m_state->m_buffers)) { + return false; + } + // TODO (HRT-7252): Clean this code while (true) { int buffers_head = CB_HEAD(m_state->m_buffers); int buffers_tail = CB_TAIL(m_state->m_buffers); - if (CB_AVAIL(m_state->m_buffers, buffers_head, buffers_tail)) { + bool has_space_in_buffers = CB_AVAIL(m_state->m_buffers, buffers_head, buffers_tail); + + uint32_t desc_avail = (get_num_available() + m_pending_num_avail_offset) & m_state->m_descs.size_mask; + int num_free = CB_AVAIL(m_state->m_descs, desc_avail, CB_TAIL(m_state->m_descs)); + bool has_desc_space = (num_free >= static_cast(desired_desc_num)); + + if (has_space_in_buffers && has_desc_space) { break; } @@ -527,22 +611,23 @@ hailo_status VdmaChannel::write_buffer(const MemoryView &buffer, std::chrono::mi state_guard.unlock(); channel_completion_status = wait_for_channel_completion(timeout); + state_guard.lock(); if (HAILO_SUCCESS != channel_completion_status) { LOGGER__INFO("wait_for_channel_completion failed with status={}", channel_completion_status); return true; } - state_guard.lock(); } - uint32_t desc_avail = (get_num_available() + m_pending_num_avail_offset) & m_state->m_descs.size_mask; - int num_free = CB_AVAIL(m_state->m_descs, desc_avail, CB_TAIL(m_state->m_descs)); - return (num_free >= static_cast(desired_desc_num)); + return true; }); - if ((!m_channel_enabled) || (m_is_aborted_by_internal_source) || (HAILO_STREAM_INTERNAL_ABORT == channel_completion_status)) { + if ((!m_channel_enabled) || (m_is_aborted_by_internal_source) || (HAILO_STREAM_ABORTED_BY_USER == channel_completion_status)) { LOGGER__INFO("wait_for in write_buffer was aborted!"); - return HAILO_STREAM_INTERNAL_ABORT; + return HAILO_STREAM_ABORTED_BY_USER; } CHECK(was_successful, HAILO_TIMEOUT, "Waiting for descriptors in write_buffer has reached a timeout!"); + if (HAILO_STREAM_ABORTED_BY_USER == channel_completion_status) { + return HAILO_STREAM_ABORTED_BY_USER; + } CHECK_SUCCESS(channel_completion_status); return write_buffer_impl(buffer); @@ -570,7 +655,6 @@ hailo_status VdmaChannel::send_pending_buffer_impl() return status; } CHECK_SUCCESS(status); - m_state->m_accumulated_transfers = (m_state->m_accumulated_transfers + 1) % m_transfers_per_axi_intr; size_t desired_desc_num = m_buffer->descriptors_in_buffer(m_pending_buffers_sizes.front()); @@ -581,65 +665,37 @@ hailo_status VdmaChannel::send_pending_buffer_impl() return HAILO_SUCCESS; } -Expected VdmaChannel::send_pending_buffer() +hailo_status VdmaChannel::send_pending_buffer() { - size_t next_buffer_desc_num = 0; { assert(m_state); assert(m_buffer); std::lock_guard state_guard(*m_state); - // Save before calling send_pending_buffer_impl because we pop from m_pending_buffers_sizes there - next_buffer_desc_num = m_buffer->descriptors_in_buffer(m_pending_buffers_sizes.front()); - auto status = send_pending_buffer_impl(); if (HAILO_STREAM_NOT_ACTIVATED == status) { LOGGER__INFO("stream is not activated"); - return make_unexpected(HAILO_STREAM_NOT_ACTIVATED); + return HAILO_STREAM_NOT_ACTIVATED; } else { - CHECK_SUCCESS_AS_EXPECTED(status); + CHECK_SUCCESS(status); } } m_can_write_buffer_cv.notify_one(); - return PendingBufferState(*this, next_buffer_desc_num); + return HAILO_SUCCESS; } -hailo_status PendingBufferState::finish(std::chrono::milliseconds timeout, std::unique_lock &lock) +hailo_status VdmaChannel::sync_state(std::chrono::milliseconds timeout) { - unlock_guard> unlock(lock); - - while (true) { - { - std::lock_guard state_guard(*m_vdma_channel.m_state); - - // Make sure that only one thread is waiting for channel completion - if (m_vdma_channel.m_is_waiting_for_channel_completion) { - break; - } - - // When all pending buffers have been sent but no buffers were processed yet (there are no free descriptors) we want to wait - // for channel completion to make free room to the next buffers - // TODO: This assumes the next buffer is the same size as the current one, so consider moving this to the write_buffer function - int num_free = CB_AVAIL(m_vdma_channel.m_state->m_descs, m_vdma_channel.get_num_available(), CB_TAIL(m_vdma_channel.m_state->m_descs)); - - // We use m_next_buffer_desc_num to check if the next buffer has enough descriptors - bool should_free_descs = (0 == m_vdma_channel.m_pending_num_avail_offset) && (num_free < static_cast(m_next_buffer_desc_num)); - m_vdma_channel.m_is_waiting_for_channel_completion = should_free_descs; - if (!should_free_descs) { - break; - } - } + { + std::lock_guard state_guard(*m_state); - auto status = m_vdma_channel.wait_for_channel_completion(timeout); - if (HAILO_STREAM_INTERNAL_ABORT == status) { - LOGGER__INFO("wait_for_channel_completion has failed with status=HAILO_STREAM_INTERNAL_ABORT"); - return status; + // Make sure that only one thread is waiting for channel completion + if (m_is_waiting_for_channel_completion) { + return HAILO_SUCCESS; } - CHECK_SUCCESS(status); } - - return HAILO_SUCCESS; + return wait_for_channel_completion(timeout); } hailo_status VdmaChannel::flush(const std::chrono::milliseconds &timeout) @@ -818,35 +874,33 @@ VdmaChannel::Direction VdmaChannel::other_direction(Direction direction) hailo_status VdmaChannel::unregister_fw_controlled_channel() { assert(m_channel_handle); + + if (m_state) { + // m_state is locked from stop_channel + m_state->m_channel_is_active = false; + } + if (HailoRTDriver::INVALID_VDMA_CHANNEL_HANDLE != *m_channel_handle) { auto status = m_driver.vdma_channel_disable(m_channel_id, *m_channel_handle); *m_channel_handle = HailoRTDriver::INVALID_VDMA_CHANNEL_HANDLE; CHECK_SUCCESS(status, "Failed to disable channel {}", m_channel_id); } + return HAILO_SUCCESS; } -hailo_status VdmaChannel::register_channel_to_driver(uintptr_t desc_list_handle) +hailo_status VdmaChannel::register_channel_to_driver() { const bool measure_latency = (nullptr != m_latency_meter); - const uintptr_t desc_handle = desc_list_handle; - auto channel_handle = m_driver.vdma_channel_enable(m_channel_id, m_direction, desc_handle, measure_latency); + auto channel_handle = m_driver.vdma_channel_enable(m_channel_id, m_direction, measure_latency); CHECK_EXPECTED_AS_STATUS(channel_handle, "Failed to enable channel {}", m_channel_id); *m_channel_handle = channel_handle.release(); - return HAILO_SUCCESS; -} - -hailo_status VdmaChannel::start_channel() -{ - auto is_aborted_exp = is_aborted(); - assert(is_aborted_exp); - assert(is_aborted_exp.value()); - auto status = register_channel_to_driver(m_buffer->get_desc_list()->get().handle()); - CHECK_SUCCESS(status, "Failed to enable channel {}", m_channel_id); - - m_channel_is_active = true; + if (m_state) { + std::lock_guard state_guard(*m_state); + m_state->m_channel_is_active = true; + } return HAILO_SUCCESS; } @@ -917,12 +971,15 @@ hailo_status VdmaChannel::trigger_channel_completion(uint16_t hw_num_processed, assert(m_buffer); std::lock_guard state_guard(*m_state); + if (m_is_aborted_by_internal_source) { + return HAILO_STREAM_ABORTED_BY_USER; + } + int processed_no = 0; int head = CB_HEAD(m_state->m_buffers); int tail = CB_TAIL(m_state->m_buffers); int prog = CB_PROG(m_state->m_buffers, head, tail); int last_tail = -1; - auto channel_error = m_host_registers.get_channel_error(); CHECK_EXPECTED_AS_STATUS(channel_error, "Fail to read vdma channel error register"); CHECK(0 == channel_error.value(), HAILO_INTERNAL_FAILURE, "Vdma channel {} in error state {}", m_channel_id, @@ -1032,8 +1089,6 @@ bool VdmaChannel::is_ready_for_transfer_d2h(size_t buffer_size) hailo_status VdmaChannel::prepare_descriptors(size_t transfer_size, VdmaInterruptsDomain first_desc_interrupts_domain, VdmaInterruptsDomain last_desc_interrupts_domain) { - MICROPROFILE_SCOPEI("vDMA Channel", "Trigger vDMA", 0); - assert(m_buffer); assert(m_state); auto desc_info = m_buffer->get_desc_list(); @@ -1136,8 +1191,9 @@ hailo_status VdmaChannel::wait_for_channel_completion(std::chrono::milliseconds auto is_aborted_exp = is_aborted(); CHECK_EXPECTED_AS_STATUS(is_aborted_exp); if (is_aborted_exp.value()) { - std::unique_lock lock(m_is_active_flag_mutex); - if (!m_channel_is_active) { + assert(m_state); + std::lock_guard state_guard(*m_state); + if (!m_state->m_channel_is_active) { return HAILO_STREAM_NOT_ACTIVATED; } @@ -1145,13 +1201,16 @@ hailo_status VdmaChannel::wait_for_channel_completion(std::chrono::milliseconds return HAILO_STREAM_ABORTED; } } - if ((HAILO_STREAM_INTERNAL_ABORT == hw_num_processed.status()) || + if ((HAILO_STREAM_ABORTED_BY_USER == hw_num_processed.status()) || (HAILO_STREAM_NOT_ACTIVATED == hw_num_processed.status())) { return hw_num_processed.status(); } CHECK_EXPECTED_AS_STATUS(hw_num_processed); auto status = trigger_channel_completion(hw_num_processed.value(), callback); + if (HAILO_STREAM_ABORTED_BY_USER == status) { + return status; + } CHECK_SUCCESS(status); return HAILO_SUCCESS; @@ -1162,7 +1221,7 @@ Expected VdmaChannel::wait_interrupts(std::chrono::milliseconds timeou assert(m_state); auto irq_data = m_driver.wait_channel_interrupts(m_channel_id, *m_channel_handle, timeout); - if ((HAILO_STREAM_INTERNAL_ABORT == irq_data.status()) || + if ((HAILO_STREAM_ABORTED_BY_USER == irq_data.status()) || (HAILO_STREAM_NOT_ACTIVATED == irq_data.status())) { LOGGER__INFO("Wait channel interrupts was aborted!"); return make_unexpected(irq_data.status()); @@ -1210,7 +1269,7 @@ Expected VdmaChannel::update_latency_meter(const ChannelInterruptTimes m_latency_meter->add_start_sample(irq_timestamp.timestamp); } else { - m_latency_meter->add_end_sample(m_stream_index, irq_timestamp.timestamp); + m_latency_meter->add_end_sample(m_stream_name, irq_timestamp.timestamp); } break; } diff --git a/hailort/libhailort/src/vdma_channel.hpp b/hailort/libhailort/src/vdma_channel.hpp index 1388ae0..ad65e92 100644 --- a/hailort/libhailort/src/vdma_channel.hpp +++ b/hailort/libhailort/src/vdma_channel.hpp @@ -30,26 +30,13 @@ namespace hailort { -class VdmaChannel; -class PendingBufferState final -{ -public: - PendingBufferState(VdmaChannel &vdma_channel, size_t next_buffer_desc_num) : m_vdma_channel(vdma_channel), - m_next_buffer_desc_num(next_buffer_desc_num) {} - hailo_status finish(std::chrono::milliseconds timeout, std::unique_lock &lock); - -private: - VdmaChannel &m_vdma_channel; - size_t m_next_buffer_desc_num; -}; - class VdmaChannel final { public: using Direction = HailoRTDriver::DmaDirection; static Expected create(vdma::ChannelId channel_id, Direction direction, HailoRTDriver &driver, - uint16_t requested_desc_page_size, uint32_t stream_index = 0, LatencyMeterPtr latency_meter = nullptr, + uint16_t requested_desc_page_size, const std::string &stream_name = "", LatencyMeterPtr latency_meter = nullptr, uint16_t transfers_per_axi_intr = 1); ~VdmaChannel(); @@ -64,23 +51,24 @@ public: hailo_status wait(size_t buffer_size, std::chrono::milliseconds timeout); hailo_status transfer(void *buf, size_t count); - hailo_status write_buffer(const MemoryView &buffer, std::chrono::milliseconds timeout); - Expected send_pending_buffer(); + // Either write_buffer + send_pending_buffer or transfer (h2d) should be used on a given channel, not both + hailo_status write_buffer(const MemoryView &buffer, std::chrono::milliseconds timeout, const std::function &should_cancel); + hailo_status send_pending_buffer(); hailo_status trigger_channel_completion(uint16_t hw_num_processed, const std::function &callback); hailo_status allocate_resources(uint32_t descs_count); - /* For channels controlled by the HailoRT, the HailoRT needs to use this function to start the channel (it registers the channel to driver - and starts the vDMA channel. Used for boundary channels */ - hailo_status start_allocated_channel(uint32_t transfer_size); + // Call for boundary channels, after the fw has activted them (via ResourcesManager::enable_state_machine) + hailo_status complete_channel_activation(uint32_t transfer_size); + // Libhailort registers the channels to the driver and the FW is responsible for opening and closing them hailo_status register_fw_controlled_channel(); hailo_status unregister_fw_controlled_channel(); + // For D2H channels, we don't buffer data + // Hence there's nothing to be "flushed" and the function will return with HAILO_SUCCESS hailo_status flush(const std::chrono::milliseconds &timeout); hailo_status set_num_avail_value(uint16_t new_value); hailo_status set_transfers_per_axi_intr(uint16_t transfers_per_axi_intr); hailo_status inc_num_available_for_ddr(uint16_t value, uint32_t size_mask); Expected get_hw_num_processed_ddr(uint32_t size_mask); - /* For channels controlled by the FW (inter context and cfg channels), the hailort needs only to register the channel to the driver. - The FW would be responsible to open and close the channel */ - hailo_status register_channel_to_driver(uintptr_t desc_list_handle); + hailo_status stop_channel(); uint16_t get_page_size(); Expected get_boundary_buffer_info(uint32_t transfer_size); @@ -88,6 +76,21 @@ public: hailo_status abort(); hailo_status clear_abort(); + class BufferState { + public: + std::vector> desc_buffer_pairing; + uint16_t num_avail; + uint16_t num_processed; + uint16_t hw_num_avail; + uint16_t hw_num_processed; + }; + // Assumes that the channel is idle; doesn't block changes to the channel + // To be used for debugging purposes + Expected get_buffer_state(); + + // To be used for debugging purposes + hailo_status sync_state(std::chrono::milliseconds timeout); + vdma::ChannelId get_channel_id() const { return m_channel_id; @@ -108,7 +111,7 @@ public: hailo_status register_for_d2h_interrupts(const std::function &callback); - friend class PendingBufferState; + void notify_all(); private: struct PendingBuffer { @@ -135,15 +138,23 @@ private: // TODO: Consider C11 stdatomic circbuf_t m_descs; int m_d2h_read_desc_index; + // TODO: We want to refactor this class + VdmaChannel so that logic related to write_buffer + send_pending_buffer will + // be in another class. + // Points to the tail of the desc list when the channel is stopped (starts at zero) + // When calling VdmaChannel::write_buffer, buffers will be appended relative to this index (+ the current num_avail) + // We'll set it if there are pending buffers to be sent or if m_should_reprogram_buffer is set + int m_previous_tail; + bool m_should_reprogram_buffer; // Contains the last num_processed of the last interrupt (only used on latency measurement) uint16_t m_last_timestamp_num_processed; size_t m_accumulated_transfers; - bool pending_reads; + bool m_channel_is_active; }; + hailo_status register_channel_to_driver(); hailo_status unregister_for_d2h_interrupts(std::unique_lock &lock); - VdmaChannel(vdma::ChannelId channel_id, Direction direction, HailoRTDriver &driver, uint32_t stream_index, + VdmaChannel(vdma::ChannelId channel_id, Direction direction, HailoRTDriver &driver, const std::string &stream_name, LatencyMeterPtr latency_meter, uint16_t desc_page_size, uint16_t transfers_per_axi_intr, hailo_status &status); hailo_status allocate_buffer(const uint32_t buffer_size); @@ -184,7 +195,6 @@ private: Expected update_latency_meter(const ChannelInterruptTimestampList ×tamp_list); static bool is_desc_between(uint16_t begin, uint16_t end, uint16_t desc); Expected is_aborted(); - hailo_status start_channel(); const vdma::ChannelId m_channel_id; Direction m_direction; @@ -198,7 +208,7 @@ private: // TODO: remove the unique_ptr, instead allocate the buffer in the ctor (needs to move ddr channel to // other class) std::unique_ptr m_buffer; - uint32_t m_stream_index; + const std::string m_stream_name; LatencyMeterPtr m_latency_meter; MmapBuffer m_state; @@ -207,13 +217,11 @@ private: MmapBuffer m_channel_handle; bool m_channel_enabled; - bool m_channel_is_active; - std::mutex m_is_active_flag_mutex; uint16_t m_transfers_per_axi_intr; // Using CircularArray because it won't allocate or free memory wile pushing and poping. The fact that it is circural is not relevant here CircularArray m_pending_buffers_sizes; - uint16_t m_pending_num_avail_offset; + std::atomic_uint16_t m_pending_num_avail_offset; std::condition_variable_any m_can_write_buffer_cv; std::condition_variable_any m_can_read_buffer_cv; std::atomic_bool m_is_waiting_for_channel_completion; diff --git a/hailort/libhailort/src/vdma_descriptor_list.cpp b/hailort/libhailort/src/vdma_descriptor_list.cpp index a74133e..b160246 100644 --- a/hailort/libhailort/src/vdma_descriptor_list.cpp +++ b/hailort/libhailort/src/vdma_descriptor_list.cpp @@ -108,21 +108,22 @@ Expected VdmaDescriptorList::calculate_desc_list_depth(size_t count) return static_cast(depth); } -hailo_status VdmaDescriptorList::configure_to_use_buffer(vdma::MappedBuffer& buffer, uint8_t channel_index) +hailo_status VdmaDescriptorList::configure_to_use_buffer(vdma::MappedBuffer& buffer, uint8_t channel_index, size_t offset) { return m_driver.descriptors_list_bind_vdma_buffer(m_desc_handle, buffer.handle(), m_desc_page_size, - channel_index); + channel_index, offset); } -hailo_status VdmaDescriptorList::configure_to_use_buffer(vdma::MappedBuffer& buffer) +hailo_status VdmaDescriptorList::configure_to_use_buffer(vdma::MappedBuffer& buffer, size_t offset) { - return configure_to_use_buffer(buffer, HailoRTDriver::INVALID_VDMA_CHANNEL_INDEX); + return configure_to_use_buffer(buffer, HailoRTDriver::INVALID_VDMA_CHANNEL_INDEX, offset); } Expected VdmaDescriptorList::program_descriptors(size_t transfer_size, VdmaInterruptsDomain first_desc_interrupts_domain, VdmaInterruptsDomain last_desc_interrupts_domain, size_t desc_offset, bool is_circular) { + assert(transfer_size > 0); const auto required_descriptors = descriptors_in_buffer(transfer_size); // Required_descriptors + desc_offset can't reach m_count. We need to keep at least 1 free desc at all time. if ((!is_circular) && ((required_descriptors + desc_offset) >= m_count)){ @@ -293,7 +294,7 @@ uint32_t VdmaDescriptorList::get_interrupts_bitmask(VdmaInterruptsDomain interru device_bitmask = DRAM_DMA_DEVICE_INTERRUPTS_BITMASK; break; default: - assert(true); + assert(false); } uint32_t bitmask = 0; diff --git a/hailort/libhailort/src/vdma_descriptor_list.hpp b/hailort/libhailort/src/vdma_descriptor_list.hpp index 5958216..6a42241 100644 --- a/hailort/libhailort/src/vdma_descriptor_list.hpp +++ b/hailort/libhailort/src/vdma_descriptor_list.hpp @@ -120,9 +120,11 @@ public: return m_desc_handle; } - hailo_status configure_to_use_buffer(vdma::MappedBuffer& buffer, uint8_t channel_index); + // offset in buffer to which the first desc in this VdmaDescriptorList will point + // offset must be a multiple of desc_page_size() + hailo_status configure_to_use_buffer(vdma::MappedBuffer& buffer, uint8_t channel_index, size_t offset = 0); // On hailo8, we allow configuring buffer without specific channel index. - hailo_status configure_to_use_buffer(vdma::MappedBuffer& buffer); + hailo_status configure_to_use_buffer(vdma::MappedBuffer& buffer, size_t offset = 0); Expected program_descriptors(size_t transfer_size, VdmaInterruptsDomain first_desc_interrupts_domain, VdmaInterruptsDomain last_desc_interrupts_domain, size_t desc_offset, bool is_circular); diff --git a/hailort/libhailort/src/vdma_device.cpp b/hailort/libhailort/src/vdma_device.cpp index f252d91..bf27195 100644 --- a/hailort/libhailort/src/vdma_device.cpp +++ b/hailort/libhailort/src/vdma_device.cpp @@ -14,7 +14,8 @@ #include "context_switch/multi_context/vdma_config_manager.hpp" #include "pcie_device.hpp" #include "core_device.hpp" - +#include "control.hpp" +#include "context_switch/resource_manager_builder.hpp" #include #include @@ -22,10 +23,17 @@ namespace hailort { -VdmaDevice::VdmaDevice(HailoRTDriver &&driver, Device::Type type) : +#ifndef HAILO_EMULATOR +static constexpr std::chrono::milliseconds DEFAULT_TIMEOUT(1000); +#else /* ifndef HAILO_EMULATOR */ +static constexpr std::chrono::milliseconds DEFAULT_TIMEOUT(50000); +#endif /* ifndef HAILO_EMULATOR */ + +VdmaDevice::VdmaDevice(HailoRTDriver &&driver, Device::Type type, const std::string &device_id) : DeviceBase::DeviceBase(type), - m_driver(std::move(driver)) + m_driver(std::move(driver)), m_is_configured(false) { + activate_notifications(device_id); } Expected> VdmaDevice::create(const std::string &device_id) @@ -38,7 +46,7 @@ Expected> VdmaDevice::create(const std::string &devi } else if (auto pcie_info = PcieDevice::parse_pcie_device_info(device_id, DONT_LOG_ON_FAILURE)) { auto device = PcieDevice::create(pcie_info.release()); - CHECK_EXPECTED(device);; + CHECK_EXPECTED(device); return std::unique_ptr(device.release()); } else { @@ -54,7 +62,16 @@ hailo_status VdmaDevice::wait_for_wakeup() Expected VdmaDevice::read_notification() { - return m_driver.read_notification(); + auto notification_buffer = m_driver.read_notification(); + if (!notification_buffer.has_value()) { + return make_unexpected(notification_buffer.status()); + } + + D2H_EVENT_MESSAGE_t notification; + CHECK_AS_EXPECTED(sizeof(notification) >= notification_buffer->size(), HAILO_GET_D2H_EVENT_MESSAGE_FAIL, + "buffer len is not valid = {}", notification_buffer->size()); + memcpy(¬ification, notification_buffer->data(), notification_buffer->size()); + return notification; } hailo_status VdmaDevice::disable_notifications() @@ -62,6 +79,169 @@ hailo_status VdmaDevice::disable_notifications() return m_driver.disable_notifications(); } +hailo_status VdmaDevice::fw_interact_impl(uint8_t *request_buffer, size_t request_size, + uint8_t *response_buffer, size_t *response_size, hailo_cpu_id_t cpu_id) +{ + uint8_t request_md5[PCIE_EXPECTED_MD5_LENGTH]; + MD5_CTX ctx; + + MD5_Init(&ctx); + MD5_Update(&ctx, request_buffer, request_size); + MD5_Final(request_md5, &ctx); + + uint8_t response_md5[PCIE_EXPECTED_MD5_LENGTH]; + uint8_t expected_response_md5[PCIE_EXPECTED_MD5_LENGTH]; + + auto status = m_driver.fw_control(request_buffer, request_size, request_md5, + response_buffer, response_size, response_md5, + DEFAULT_TIMEOUT, cpu_id); + CHECK_SUCCESS(status, "Failed to send fw control"); + + MD5_Init(&ctx); + MD5_Update(&ctx, response_buffer, (*response_size)); + MD5_Final(expected_response_md5, &ctx); + + auto memcmp_result = memcmp(expected_response_md5, response_md5, sizeof(response_md5)); + CHECK(0 == memcmp_result, HAILO_INTERNAL_FAILURE, "MD5 validation of control response failed."); + + return HAILO_SUCCESS; +} + +Expected VdmaDevice::add_hef(Hef &hef, const NetworkGroupsParamsMap &configure_params) +{ + auto status = mark_as_used(); + CHECK_SUCCESS_AS_EXPECTED(status); + + if (!m_is_configured) { + // TODO: Do we need this control after fixing HRT-7519? + // Reset context_switch state machine - it may have been in an active state if a previous VdmaDevice + // wasn't dtor'd (due to SIGKILL for example) + static const auto REMOVE_NN_CONFIG_DURING_RESET = false; + status = Control::reset_context_switch_state_machine(*this, REMOVE_NN_CONFIG_DURING_RESET); + CHECK_SUCCESS_AS_EXPECTED(status); + + status = Control::clear_configured_apps(*this); + CHECK_SUCCESS_AS_EXPECTED(status, "Failed to clear configured network groups with status {}", status); + + m_is_configured = true; + } + + auto device_arch = get_architecture(); + CHECK_EXPECTED(device_arch); + + auto partial_clusters_layout_bitmap_exp = Control::get_partial_clusters_layout_bitmap(*this); + CHECK_EXPECTED(partial_clusters_layout_bitmap_exp); + auto partial_clusters_layout_bitmap = partial_clusters_layout_bitmap_exp.release(); + + auto &hef_net_groups = hef.pimpl->network_groups(); + ConfiguredNetworkGroupVector added_network_groups; + // TODO: can be optimized (add another loop the allocate the network group we're adding) + added_network_groups.reserve(hef_net_groups.size()); + auto configure_params_copy = configure_params; + for (const auto &hef_net_group : hef_net_groups) { + const std::string &network_group_name = HefUtils::get_network_group_name(*hef_net_group, SupportedFeatures()); + auto hef_core_ops = hef.pimpl->core_ops(network_group_name); + assert(hef_core_ops.size() == 1); + std::vector> network_group_metadata_ptrs; + network_group_metadata_ptrs.reserve(hef_core_ops.size()); + const auto prev_network_group_count = m_network_groups.size(); + const auto total_network_group_count = prev_network_group_count + hef_core_ops.size(); + CHECK_AS_EXPECTED(CONTROL_PROTOCOL__MAX_CONTEXT_SWITCH_APPLICATIONS >= total_network_group_count, + HAILO_INVALID_OPERATION, + "Can't add {} network groups from HEF. Currently {} network groups are configured; maximum allowed network groups: {}.", + hef_core_ops.size(), prev_network_group_count, CONTROL_PROTOCOL__MAX_CONTEXT_SWITCH_APPLICATIONS); + + auto hef_arch = hef.pimpl->get_device_arch(); + + auto current_net_group_index = static_cast(prev_network_group_count); + for (const auto &core_op : hef_core_ops) { + auto expected_partial_core_op = Hef::Impl::get_core_op_per_arch(core_op, hef_arch, device_arch.value(), + partial_clusters_layout_bitmap); + CHECK_EXPECTED(expected_partial_core_op); + auto partial_core_op = expected_partial_core_op.release(); + status = Hef::Impl::validate_core_op_unique_layer_names(*partial_core_op); + CHECK_SUCCESS_AS_EXPECTED(status); + + // TODO: keep metadata per core_op (HRT-8639) + // TODO: decide about core_op names - align with the Compiler + auto network_group_metadata = hef.pimpl->get_network_group_metadata(network_group_name, partial_clusters_layout_bitmap); + CHECK_EXPECTED(network_group_metadata); + + auto network_group_metadata_ptr = make_shared_nothrow(network_group_metadata.release()); + CHECK_AS_EXPECTED(nullptr != network_group_metadata_ptr, HAILO_OUT_OF_HOST_MEMORY); + network_group_metadata_ptrs.push_back(network_group_metadata_ptr); + } + + /* If NG params are present, use them + If no configure params are given, use default*/ + ConfigureNetworkParams config_params{}; + if (contains(configure_params, network_group_name)) { + config_params = configure_params_copy.at(network_group_name); + configure_params_copy.erase(network_group_name); + } else if (configure_params.empty()) { + auto stream_interface = get_default_streams_interface(); + CHECK_EXPECTED(stream_interface); + auto config_params_exp = hef.create_configure_params(stream_interface.value(), network_group_name); + CHECK_EXPECTED(config_params_exp); + config_params = config_params_exp.release(); + } else { + continue; + } + /* Validate batch size (network group batch size vs network batch size) */ + status = Hef::Impl::update_network_batch_size(config_params); + CHECK_SUCCESS_AS_EXPECTED(status); + auto network_group = create_configured_network_group(network_group_metadata_ptrs, + hef, config_params, current_net_group_index); + CHECK_EXPECTED(network_group); + added_network_groups.emplace_back(network_group.release()); + current_net_group_index++; + } + std::string unmatched_keys = ""; + for (const auto &pair : configure_params_copy) { + unmatched_keys.append(" "); + unmatched_keys.append(pair.first); + } + CHECK_AS_EXPECTED(unmatched_keys.size() == 0, HAILO_INVALID_ARGUMENT, + "Some network group names in the configuration are not found in the hef file:{}", unmatched_keys); + + return added_network_groups; +} + +Expected> VdmaDevice::create_configured_network_group( + const std::vector> &network_group_metadatas, + Hef &hef, const ConfigureNetworkParams &config_params, + uint8_t network_group_index) +{ + // TODO: keep metadata per core_op (HRT-8639) + assert(network_group_metadatas.size() == 1); + auto network_group_metadata = network_group_metadatas[0]; + + /* build HEF supported features */ + auto resource_manager = ResourcesManagerBuilder::build(network_group_index, + *this, get_driver(), config_params, network_group_metadata, hef.pimpl->get_device_arch()); + CHECK_EXPECTED(resource_manager); + + auto net_flow_ops = hef.pimpl->post_process_ops(network_group_metadata->network_group_name()); + + auto net_group = VdmaConfigNetworkGroup::create(m_active_net_group_holder, config_params, + resource_manager.release(), hef.hash(), network_group_metadata, std::move(net_flow_ops)); + + auto net_group_ptr = make_shared_nothrow(net_group.release()); + CHECK_AS_EXPECTED(nullptr != net_group_ptr, HAILO_OUT_OF_HOST_MEMORY); + + // TODO: move this func into VdmaConfigNetworkGroup c'tor + auto status = net_group_ptr->create_streams_from_config_params(*this); + CHECK_SUCCESS_AS_EXPECTED(status); + + m_network_groups.emplace_back(net_group_ptr); + + // Check that all boundary streams were created + status = hef.pimpl->validate_boundary_streams_were_created(network_group_metadata->network_group_name(), *net_group_ptr); + CHECK_SUCCESS_AS_EXPECTED(status); + + return Expected>(net_group_ptr); +} + Expected VdmaDevice::read_log(MemoryView &buffer, hailo_cpu_id_t cpu_id) { size_t read_bytes = 0; @@ -94,4 +274,18 @@ hailo_status VdmaDevice::mark_as_used() return m_driver.mark_as_used(); } +VdmaDevice::~VdmaDevice() +{ + auto status = stop_notification_fetch_thread(); + if (HAILO_SUCCESS != status) { + LOGGER__WARNING("Stopping notification thread ungracefully"); + } + if (m_is_configured) { + status = Control::clear_configured_apps(*this); + if (HAILO_SUCCESS != status) { + LOGGER__ERROR("Failed to clear conigured network groups with status {}", status); + } + } +} + } /* namespace hailort */ diff --git a/hailort/libhailort/src/vdma_device.hpp b/hailort/libhailort/src/vdma_device.hpp index c084f77..f25a6e0 100644 --- a/hailort/libhailort/src/vdma_device.hpp +++ b/hailort/libhailort/src/vdma_device.hpp @@ -14,6 +14,7 @@ #include "hailo/hailort.h" #include "hailo/expected.hpp" #include "device_internal.hpp" +#include "context_switch/network_group_internal.hpp" #include "os/hailort_driver.hpp" namespace hailort @@ -21,10 +22,9 @@ namespace hailort class VdmaDevice : public DeviceBase { public: - static Expected> create(const std::string &device_id); - virtual ~VdmaDevice() = default; + virtual ~VdmaDevice(); virtual hailo_status wait_for_wakeup() override; virtual void increment_control_sequence() override; @@ -39,12 +39,24 @@ public: }; protected: - VdmaDevice(HailoRTDriver &&driver, Type type); + VdmaDevice(HailoRTDriver &&driver, Type type, const std::string &device_id); virtual Expected read_notification() override; virtual hailo_status disable_notifications() override; + virtual hailo_status fw_interact_impl(uint8_t *request_buffer, size_t request_size, + uint8_t *response_buffer, size_t *response_size, hailo_cpu_id_t cpu_id) override; + virtual Expected add_hef(Hef &hef, const NetworkGroupsParamsMap &configure_params) override; HailoRTDriver m_driver; + std::vector> m_network_groups; + ActiveNetGroupHolder m_active_net_group_holder; + bool m_is_configured; + +private: + Expected> create_configured_network_group( + const std::vector> &network_group_metadatas, + Hef &hef, const ConfigureNetworkParams &config_params, + uint8_t network_group_index); }; } /* namespace hailort */ diff --git a/hailort/libhailort/src/vdma_stream.cpp b/hailort/libhailort/src/vdma_stream.cpp index 72e1a2b..ee31511 100644 --- a/hailort/libhailort/src/vdma_stream.cpp +++ b/hailort/libhailort/src/vdma_stream.cpp @@ -105,7 +105,9 @@ hailo_status VdmaInputStream::clear_abort() hailo_status VdmaInputStream::flush() { - return m_channel->flush((m_channel_timeout * m_dynamic_batch_size)); + const auto dynamic_batch_size = (CONTROL_PROTOCOL__IGNORE_DYNAMIC_BATCH_SIZE == m_dynamic_batch_size) ? + 1 : m_dynamic_batch_size; + return m_channel->flush(m_channel_timeout * dynamic_batch_size); } hailo_status VdmaInputStream::activate_stream(uint16_t dynamic_batch_size) @@ -113,7 +115,7 @@ hailo_status VdmaInputStream::activate_stream(uint16_t dynamic_batch_size) auto status = set_dynamic_batch_size(dynamic_batch_size); CHECK_SUCCESS(status); - status = m_channel->start_allocated_channel(0); + status = m_channel->complete_channel_activation(0); CHECK_SUCCESS(status); this->is_stream_activated = true; @@ -126,20 +128,18 @@ hailo_status VdmaInputStream::deactivate_stream() return HAILO_SUCCESS; } - /* Flush is best effort */ + // Flush is best effort auto status = m_channel->flush(VDMA_FLUSH_TIMEOUT); - if (HAILO_STREAM_INTERNAL_ABORT == status) { + if (HAILO_STREAM_ABORTED_BY_USER == status) { LOGGER__INFO("Flush input_channel is not needed because channel was aborted. (channel {})", m_channel->get_channel_id()); status = HAILO_SUCCESS; } else if (HAILO_SUCCESS != status) { LOGGER__ERROR("Failed to flush input_channel. (status {} channel {})", status, m_channel->get_channel_id()); } - /* Close channel is best effort. */ - auto stop_channel_status = m_channel->stop_channel(); - if (HAILO_SUCCESS != stop_channel_status) { - LOGGER__ERROR("Failed to stop channel with error status {}", stop_channel_status); - status = (status == HAILO_SUCCESS) ? stop_channel_status : status; + status = m_channel->stop_channel(); + if (HAILO_SUCCESS != status) { + LOGGER__ERROR("Failed to stop channel with status {}", status); } this->is_stream_activated = false; @@ -151,41 +151,49 @@ Expected VdmaInputStream::sync_write_raw_buffer(const MemoryView &buffer hailo_status status = HAILO_UNINITIALIZED; status = m_channel->wait(buffer.size(), m_channel_timeout); - if ((status == HAILO_STREAM_INTERNAL_ABORT) || (status == HAILO_STREAM_NOT_ACTIVATED)) { + if ((status == HAILO_STREAM_ABORTED_BY_USER) || (status == HAILO_STREAM_NOT_ACTIVATED)) { return make_unexpected(status); } + CHECK_AS_EXPECTED(HAILO_TIMEOUT != status, HAILO_TIMEOUT, + "{} (H2D) failed with status={} (timeout={}ms)", name(), HAILO_TIMEOUT, m_channel_timeout.count()); CHECK_SUCCESS_AS_EXPECTED(status); status = m_channel->transfer((void*)buffer.data(), buffer.size()); - if ((status == HAILO_STREAM_INTERNAL_ABORT) || (status == HAILO_STREAM_NOT_ACTIVATED)) { + if ((status == HAILO_STREAM_ABORTED_BY_USER) || (status == HAILO_STREAM_NOT_ACTIVATED)) { return make_unexpected(status); } + CHECK_AS_EXPECTED(HAILO_TIMEOUT != status, HAILO_TIMEOUT, + "{} (H2D) failed with status={} (timeout={}ms)", name(), HAILO_TIMEOUT, m_channel_timeout.count()); CHECK_SUCCESS_AS_EXPECTED(status); return buffer.size(); } -hailo_status VdmaInputStream::write_buffer_only(const MemoryView &buffer) +hailo_status VdmaInputStream::write_buffer_only(const MemoryView &buffer, + const std::function &should_cancel) { std::unique_lock lock(m_write_only_mutex); - return m_channel->write_buffer(buffer, m_channel_timeout); + return m_channel->write_buffer(buffer, m_channel_timeout, should_cancel); } -Expected VdmaInputStream::send_pending_buffer() +hailo_status VdmaInputStream::send_pending_buffer(size_t device_index) { std::unique_lock lock(m_send_pending_mutex); + CHECK(0 == device_index, HAILO_INVALID_OPERATION); hailo_status status = m_channel->wait(get_frame_size(), m_channel_timeout); - if ((HAILO_STREAM_INTERNAL_ABORT == status) || (HAILO_STREAM_NOT_ACTIVATED == status)) { - return make_unexpected(status); + if ((HAILO_STREAM_ABORTED_BY_USER == status) || (HAILO_STREAM_NOT_ACTIVATED == status)) { + return status; } - CHECK_SUCCESS_AS_EXPECTED(status); + CHECK(HAILO_TIMEOUT != status, HAILO_TIMEOUT, + "{} (H2D) failed with status={} (timeout={}ms)", name(), HAILO_TIMEOUT, m_channel_timeout.count()); + CHECK_SUCCESS(status); return m_channel->send_pending_buffer(); } uint16_t VdmaInputStream::get_dynamic_batch_size() const { - return m_dynamic_batch_size; + return std::max(m_dynamic_batch_size, static_cast(1)); } const char* VdmaInputStream::get_dev_id() const @@ -193,6 +201,16 @@ const char* VdmaInputStream::get_dev_id() const return m_device->get_dev_id(); } +Expected VdmaInputStream::get_buffer_state() +{ + return m_channel->get_buffer_state(); +} + +hailo_status VdmaInputStream::sync_channel_state() +{ + return m_channel->sync_state(get_timeout()); +} + Expected VdmaInputStream::get_buffer_frames_size() const { return m_channel->get_transfers_count_in_buffer(m_stream_info.hw_frame_size); @@ -212,6 +230,13 @@ hailo_status VdmaInputStream::sync_write_all_raw_buffer_no_transform_impl(void * hailo_status VdmaInputStream::set_dynamic_batch_size(uint16_t dynamic_batch_size) { + // TODO: use std::max in the configure stage + if (CONTROL_PROTOCOL__IGNORE_DYNAMIC_BATCH_SIZE == m_max_batch_size) { + LOGGER__TRACE("max_batch_size is CONTROL_PROTOCOL__IGNORE_DYNAMIC_BATCH_SIZE; " + "Ignoring value of dynamic_batch_size {}", m_dynamic_batch_size); + return HAILO_SUCCESS; + } + CHECK(dynamic_batch_size <= m_max_batch_size, HAILO_INVALID_ARGUMENT, "Dynamic batch size ({}) must be <= than the configured batch size ({})", dynamic_batch_size, m_max_batch_size); @@ -325,7 +350,7 @@ hailo_status VdmaOutputStream::clear_abort() uint16_t VdmaOutputStream::get_dynamic_batch_size() const { - return m_dynamic_batch_size; + return std::max(m_dynamic_batch_size, static_cast(1)); } const char* VdmaOutputStream::get_dev_id() const @@ -333,12 +358,17 @@ const char* VdmaOutputStream::get_dev_id() const return m_device->get_dev_id(); } +Expected VdmaOutputStream::get_buffer_state() +{ + return m_channel->get_buffer_state(); +} + hailo_status VdmaOutputStream::activate_stream(uint16_t dynamic_batch_size) { auto status = set_dynamic_batch_size(dynamic_batch_size); CHECK_SUCCESS(status); - - status = m_channel->start_allocated_channel(m_transfer_size); + + status = m_channel->complete_channel_activation(m_transfer_size); CHECK_SUCCESS(status); this->is_stream_activated = true; @@ -358,7 +388,9 @@ hailo_status VdmaOutputStream::deactivate_stream() } auto status = m_channel->stop_channel(); - CHECK_SUCCESS(status); + if (HAILO_SUCCESS != status) { + LOGGER__ERROR("Failed to stop channel with status {}", status); + } this->is_stream_activated = false; return HAILO_SUCCESS; @@ -369,15 +401,19 @@ Expected VdmaOutputStream::sync_read_raw_buffer(MemoryView &buffer) hailo_status status = HAILO_UNINITIALIZED; status = m_channel->wait(buffer.size(), m_transfer_timeout); - if ((status == HAILO_STREAM_INTERNAL_ABORT) || (status == HAILO_STREAM_NOT_ACTIVATED)) { + if ((status == HAILO_STREAM_ABORTED_BY_USER) || (status == HAILO_STREAM_NOT_ACTIVATED)) { return make_unexpected(status); } + CHECK_AS_EXPECTED(HAILO_TIMEOUT != status, HAILO_TIMEOUT, + "{} (D2H) failed with status={} (timeout={}ms)", name(), HAILO_TIMEOUT, m_transfer_timeout.count()); CHECK_SUCCESS_AS_EXPECTED(status); status = m_channel->transfer(buffer.data(), buffer.size()); - if ((status == HAILO_STREAM_NOT_ACTIVATED) || (status == HAILO_STREAM_INTERNAL_ABORT)) { + if ((status == HAILO_STREAM_NOT_ACTIVATED) || (status == HAILO_STREAM_ABORTED_BY_USER)) { return make_unexpected(status); } + CHECK_AS_EXPECTED(HAILO_TIMEOUT != status, HAILO_TIMEOUT, + "{} (D2H) failed with status={} (timeout={}ms)", name(), HAILO_TIMEOUT, m_transfer_timeout.count()); CHECK_SUCCESS_AS_EXPECTED(status); return buffer.size(); @@ -401,6 +437,13 @@ uint32_t VdmaOutputStream::get_transfer_size(const hailo_stream_info_t &stream_i hailo_status VdmaOutputStream::set_dynamic_batch_size(uint16_t dynamic_batch_size) { + // TODO: use std::max in the configure stage + if (CONTROL_PROTOCOL__IGNORE_DYNAMIC_BATCH_SIZE == m_max_batch_size) { + LOGGER__TRACE("max_batch_size is CONTROL_PROTOCOL__IGNORE_DYNAMIC_BATCH_SIZE; " + "Ignoring value of dynamic_batch_size {}", m_dynamic_batch_size); + return HAILO_SUCCESS; + } + CHECK(dynamic_batch_size <= m_max_batch_size, HAILO_INVALID_ARGUMENT, "Dynamic batch size ({}) must be <= than the configured batch size ({})", dynamic_batch_size, m_max_batch_size); diff --git a/hailort/libhailort/src/vdma_stream.hpp b/hailort/libhailort/src/vdma_stream.hpp index 8e4664b..f39ed34 100644 --- a/hailort/libhailort/src/vdma_stream.hpp +++ b/hailort/libhailort/src/vdma_stream.hpp @@ -34,13 +34,22 @@ public: virtual hailo_status abort() override; virtual hailo_status clear_abort() override; virtual hailo_status flush() override; - hailo_status write_buffer_only(const MemoryView &buffer); - Expected send_pending_buffer(); + hailo_status write_buffer_only(const MemoryView &buffer, const std::function &should_cancel = []() { return false; }); + hailo_status send_pending_buffer(size_t device_index = 0); uint16_t get_dynamic_batch_size() const; const char* get_dev_id() const; + Expected get_buffer_state(); virtual Expected get_buffer_frames_size() const override; virtual Expected get_pending_frames_count() const override; + // To be used for debugging purposes + hailo_status sync_channel_state(); + + void notify_all() + { + return m_channel->notify_all(); + } + protected: VdmaInputStream(VdmaDevice &device, std::shared_ptr channel, const LayerInfo &edge_layer, EventPtr network_group_activated_event, uint16_t batch_size, @@ -65,7 +74,8 @@ private: std::mutex m_write_only_mutex; std::mutex m_send_pending_mutex; - friend class VDeviceInputStream; + friend class InputVDeviceBaseStream; + friend class InputVDeviceNativeStream; }; class VdmaOutputStream : public OutputStreamBase { @@ -83,6 +93,7 @@ public: virtual hailo_status clear_abort() override; uint16_t get_dynamic_batch_size() const; const char* get_dev_id() const; + Expected get_buffer_state(); virtual Expected get_buffer_frames_size() const override; virtual Expected get_pending_frames_count() const override; @@ -112,7 +123,7 @@ private: const uint32_t m_transfer_size; std::mutex m_read_mutex; - friend class VDeviceOutputStream; + friend class OutputVDeviceBaseStream; }; diff --git a/hailort/libhailort/src/vstream.cpp b/hailort/libhailort/src/vstream.cpp index 4b6859b..ee960c1 100644 --- a/hailort/libhailort/src/vstream.cpp +++ b/hailort/libhailort/src/vstream.cpp @@ -107,6 +107,8 @@ Expected PreInferElement::action(PipelineBuffer &&input, Pipelin if (HAILO_SHUTDOWN_EVENT_SIGNALED == transformed_buffer.status()) { return make_unexpected(transformed_buffer.status()); } + CHECK_AS_EXPECTED(HAILO_TIMEOUT != transformed_buffer.status(), HAILO_TIMEOUT, + "{} (H2D) failed with status={} (timeout={}ms)", name(), HAILO_TIMEOUT, m_timeout.count()); CHECK_EXPECTED(transformed_buffer); auto dst = transformed_buffer->as_view(); @@ -204,6 +206,107 @@ static hailo_nms_info_t fuse_nms_info(const std::vector &nms_i return fused_info; } +Expected nms_element_to_op(const NetFlowYoloNmsElement &element, + const std::vector &shapes, const std::vector &formats, + const std::vector &quant_infos) +{ + std::vector> anchors; + // Each layer anchors vector is structured as {w,h} pairs. + auto bbox_decoders = element.bbox_decoders; + std::sort(bbox_decoders.begin(), bbox_decoders.end(), [](auto &bbox_decoder_0, auto &bbox_decoder_1) { + return bbox_decoder_0.stream_name < bbox_decoder_1.stream_name; + }); + for (auto &bbox_decoder : bbox_decoders) { + std::vector layer_anchors; + layer_anchors.reserve(bbox_decoder.h.size() + bbox_decoder.w.size()); + assert(bbox_decoder.h.size() == bbox_decoder.w.size()); + for (size_t i = 0; i < bbox_decoder.h.size(); ++i) { + layer_anchors.push_back(bbox_decoder.w[i]); + layer_anchors.push_back(bbox_decoder.h[i]); + } + anchors.push_back(layer_anchors); + } + + // TODO: Get it from NetFlowYoloNmsElement when adding support for these params. + static const bool should_dequantize = true; + static const bool should_sigmoid = false; + return net_flow::YOLOv5PostProcessingOp::create(anchors, shapes, formats,quant_infos, + element.image_height, element.image_width, element.nms_score_th, + element.nms_iou_th, element.classes, should_dequantize, element.max_proposals_per_class, should_sigmoid); +} + +Expected> NmsPostProcessMuxElement::create(const NetFlowYoloNmsElement &element, + const std::vector &shapes, const std::vector &formats, + const std::vector &quant_infos, hailo_format_t output_format, + hailo_nms_info_t nms_info, const std::string &name, std::chrono::milliseconds timeout, size_t buffer_pool_size, + hailo_pipeline_elem_stats_flags_t elem_flags, hailo_vstream_stats_flags_t vstream_flags, EventPtr shutdown_event, + std::shared_ptr> pipeline_status) +{ + auto buffer_pool = BufferPool::create(HailoRTCommon::get_nms_host_frame_size(nms_info, output_format), + buffer_pool_size, shutdown_event, elem_flags, vstream_flags); + CHECK_EXPECTED(buffer_pool, "Failed creating BufferPool"); + + auto duration_collector = DurationCollector::create(elem_flags); + CHECK_EXPECTED(duration_collector); + + auto expected_nms_op = nms_element_to_op(element, shapes, formats, quant_infos); + auto nms_elem_ptr = make_shared_nothrow(expected_nms_op.release(), buffer_pool.release(), + name, timeout, duration_collector.release(), std::move(pipeline_status)); + CHECK_AS_EXPECTED(nullptr != nms_elem_ptr, HAILO_OUT_OF_HOST_MEMORY); + + LOGGER__INFO("Created {}", nms_elem_ptr->name()); + + return nms_elem_ptr; +} + +Expected> NmsPostProcessMuxElement::create(const NetFlowYoloNmsElement &op, + const std::vector &shapes, const std::vector &formats, + const std::vector &quant_infos, hailo_nms_info_t nms_info, const std::string &name, + const hailo_vstream_params_t &vstream_params, EventPtr shutdown_event, std::shared_ptr> pipeline_status) +{ + return NmsPostProcessMuxElement::create(op, shapes, formats, quant_infos, vstream_params.user_buffer_format, nms_info, name, std::chrono::milliseconds(vstream_params.timeout_ms), + vstream_params.queue_size, vstream_params.pipeline_elements_stats_flags, vstream_params.vstream_stats_flags, shutdown_event, + pipeline_status); +} + +NmsPostProcessMuxElement::NmsPostProcessMuxElement(const net_flow::YOLOv5PostProcessingOp &op, BufferPoolPtr &&pool, + const std::string &name, std::chrono::milliseconds timeout, + DurationCollector &&duration_collector, + std::shared_ptr> &&pipeline_status) : + BaseMuxElement(3, name, timeout, std::move(duration_collector), std::move(pipeline_status)), + m_nms_op(op), + m_pool(std::move(pool)) +{} + +std::vector NmsPostProcessMuxElement::get_queue_size_accumulators() +{ + if (nullptr == m_pool->get_queue_size_accumulator()) { + return std::vector(); + } + return {m_pool->get_queue_size_accumulator()}; +} + +Expected NmsPostProcessMuxElement::action(std::vector &&inputs, PipelineBuffer &&optional) +{ + std::vector input_views; + + input_views.reserve(inputs.size()); + for (auto &input_buf : inputs) { + input_views.push_back(input_buf.as_view()); + } + + auto acquired_buffer = m_pool->get_available_buffer(std::move(optional), m_timeout); + if (HAILO_SHUTDOWN_EVENT_SIGNALED == acquired_buffer.status()) { + return make_unexpected(acquired_buffer.status()); + } + CHECK_EXPECTED(acquired_buffer); + m_duration_collector.start_measurement(); + auto post_process_result = m_nms_op.execute(input_views, acquired_buffer.value().as_view()); + m_duration_collector.complete_measurement(); + CHECK_SUCCESS_AS_EXPECTED(post_process_result); + return acquired_buffer; +} + Expected> NmsMuxElement::create(const std::vector &nms_infos, const std::string &name, std::chrono::milliseconds timeout, size_t buffer_pool_size, hailo_pipeline_elem_stats_flags_t elem_flags, hailo_vstream_stats_flags_t vstream_flags, EventPtr shutdown_event, @@ -268,6 +371,8 @@ Expected NmsMuxElement::action(std::vector &&inp if (HAILO_SHUTDOWN_EVENT_SIGNALED == acquired_buffer.status()) { return make_unexpected(acquired_buffer.status()); } + CHECK_AS_EXPECTED(HAILO_TIMEOUT != acquired_buffer.status(), HAILO_TIMEOUT, + "{} failed with status={} (timeout={}ms)", name(), HAILO_TIMEOUT, m_timeout.count()); CHECK_EXPECTED(acquired_buffer); m_duration_collector.start_measurement(); @@ -471,6 +576,12 @@ hailo_status BaseVStream::stop_and_clear() status = m_entry_element->clear(); CHECK_SUCCESS(status, "Failed clearing vstream {}", name()); + + const auto curr_pipeline_status = m_pipeline_status->load(); + if (HAILO_SUCCESS != curr_pipeline_status) { + LOGGER__TRACE("Overwritting current pipeline status {}", curr_pipeline_status); + m_pipeline_status->store(HAILO_SUCCESS); + } return HAILO_SUCCESS; } @@ -586,6 +697,11 @@ hailo_status InputVStream::abort() return m_vstream->abort(); } +hailo_status InputVStream::resume() +{ + return m_vstream->resume(); +} + size_t InputVStream::get_frame_size() const { return m_vstream->get_frame_size(); @@ -696,6 +812,11 @@ hailo_status OutputVStream::abort() return m_vstream->abort(); } +hailo_status OutputVStream::resume() +{ + return m_vstream->resume(); +} + hailo_status OutputVStream::clear(std::vector> &vstreams) { for (auto &vstream : vstreams) { @@ -907,9 +1028,9 @@ hailo_status InputVStreamImpl::write(const MemoryView &buffer) LOGGER__INFO("Sending to VStream was shutdown!"); status = m_pipeline_status->load(); } - if (HAILO_STREAM_INTERNAL_ABORT == status) { + if (HAILO_STREAM_ABORTED_BY_USER == status) { LOGGER__INFO("Sending to VStream was aborted!"); - return HAILO_STREAM_INTERNAL_ABORT; + return HAILO_STREAM_ABORTED_BY_USER; } return status; } @@ -926,7 +1047,6 @@ hailo_status InputVStreamImpl::flush() } #ifdef HAILO_SUPPORT_MULTI_PROCESS -// TODO: HRT-6606 #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wreturn-type" Expected> InputVStreamClient::create(uint32_t input_vstream_handle) @@ -935,14 +1055,23 @@ Expected> InputVStreamClient::create(uint32_ ch_args.SetMaxReceiveMessageSize(-1); auto channel = grpc::CreateCustomChannel(HAILO_DEFAULT_UDS_ADDR, grpc::InsecureChannelCredentials(), ch_args); CHECK_AS_EXPECTED(channel != nullptr, HAILO_INTERNAL_FAILURE); + auto client = std::unique_ptr(new HailoRtRpcClient(channel)); CHECK_AS_EXPECTED(client != nullptr, HAILO_OUT_OF_HOST_MEMORY); - return std::shared_ptr(new InputVStreamClient(std::move(client), std::move(input_vstream_handle))); + + auto user_buffer_format = client->InputVStream_get_user_buffer_format(input_vstream_handle); + CHECK_EXPECTED(user_buffer_format); + + auto vstream_info = client->InputVStream_get_info(input_vstream_handle); + CHECK_EXPECTED(vstream_info); + + return std::shared_ptr(new InputVStreamClient(std::move(client), std::move(input_vstream_handle), + user_buffer_format.release(), vstream_info.release())); } -// TODO: HRT-6606 -InputVStreamClient::InputVStreamClient(std::unique_ptr client, uint32_t input_vstream_handle) - : m_client(std::move(client)), m_handle(std::move(input_vstream_handle)) {} +InputVStreamClient::InputVStreamClient(std::unique_ptr client, uint32_t input_vstream_handle, hailo_format_t &&user_buffer_format, + hailo_vstream_info_t &&info) + : m_client(std::move(client)), m_handle(std::move(input_vstream_handle)), m_user_buffer_format(user_buffer_format), m_info(info) {} InputVStreamClient::~InputVStreamClient() { @@ -978,7 +1107,7 @@ hailo_status InputVStreamClient::resume() size_t InputVStreamClient::get_frame_size() const { - auto frame_size = m_client->InputVStream_get_frame_size(m_handle); + auto frame_size = m_client->InputVStream_get_frame_size(m_handle); if (!frame_size) { LOGGER__CRITICAL("InputVStream_get_frame_size failed with status={}", frame_size.status()); return 0; @@ -988,14 +1117,12 @@ size_t InputVStreamClient::get_frame_size() const const hailo_vstream_info_t &InputVStreamClient::get_info() const { - // TODO: HRT-6606 - assert(false); + return m_info; } const hailo_format_t &InputVStreamClient::get_user_buffer_format() const { - // TODO: HRT-6606 - assert(false); + return m_user_buffer_format; } std::string InputVStreamClient::name() const @@ -1010,48 +1137,39 @@ std::string InputVStreamClient::name() const std::string InputVStreamClient::network_name() const { - // TODO: HRT-6606 - assert(false); + auto expected_name = m_client->InputVStream_network_name(m_handle); + if (!expected_name) { + LOGGER__CRITICAL("InputVStream_name failed with status={}", expected_name.status()); + return ""; + } + return expected_name.release(); } const std::map &InputVStreamClient::get_fps_accumulators() const { - // TODO: HRT-6606 - assert(false); + LOGGER__ERROR("InputVStream::get_fps_accumulators function is not supported when using multi-process service"); + return m_fps_accumulators; } const std::map &InputVStreamClient::get_latency_accumulators() const { - // TODO: HRT-6606 - assert(false); + LOGGER__ERROR("InputVStream::get_latency_accumulators function is not supported when using multi-process service"); + return m_latency_accumulators; } const std::map> &InputVStreamClient::get_queue_size_accumulators() const { - // TODO: HRT-6606 - assert(false); + LOGGER__ERROR("InputVStream::get_queue_size_accumulators function is not supported when using multi-process service"); + return m_queue_size_accumulators; } AccumulatorPtr InputVStreamClient::get_pipeline_latency_accumulator() const { - // TODO: HRT-6606 - assert(false); + LOGGER__ERROR("InputVStream::get_pipeline_latency_accumulator function is not supported when using multi-process service"); + return m_pipeline_latency_accumulator; } const std::vector> &InputVStreamClient::get_pipeline() const { - // TODO: HRT-6606 - assert(false); -} - -hailo_status InputVStreamClient::start_vstream() -{ - return HAILO_NOT_IMPLEMENTED; -} -hailo_status InputVStreamClient::stop_vstream() -{ - return HAILO_NOT_IMPLEMENTED; -} -hailo_status InputVStreamClient::stop_and_clear() -{ - return HAILO_NOT_IMPLEMENTED; + LOGGER__ERROR("InputVStream::get_pipeline function is not supported when using multi-process service"); + return m_pipeline; } #pragma GCC diagnostic pop @@ -1183,16 +1301,15 @@ hailo_status OutputVStreamImpl::read(MemoryView buffer) LOGGER__INFO("Receiving to VStream was shutdown!"); status = m_pipeline_status->load(); } - if (HAILO_STREAM_INTERNAL_ABORT == status) { + if (HAILO_STREAM_ABORTED_BY_USER == status) { LOGGER__INFO("Receiving to VStream was aborted!"); m_entry_element->wait_for_finish(); - return HAILO_STREAM_INTERNAL_ABORT; + return HAILO_STREAM_ABORTED_BY_USER; } return status; } #ifdef HAILO_SUPPORT_MULTI_PROCESS -// TODO: HRT-6606 #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wreturn-type" Expected> OutputVStreamClient::create(uint32_t outputs_vstream_handle) @@ -1201,13 +1318,23 @@ Expected> OutputVStreamClient::create(uint3 ch_args.SetMaxReceiveMessageSize(-1); auto channel = grpc::CreateCustomChannel(HAILO_DEFAULT_UDS_ADDR, grpc::InsecureChannelCredentials(), ch_args); CHECK_AS_EXPECTED(channel != nullptr, HAILO_INTERNAL_FAILURE); + auto client = std::unique_ptr(new HailoRtRpcClient(channel)); CHECK_AS_EXPECTED(client != nullptr, HAILO_OUT_OF_HOST_MEMORY); - return std::shared_ptr(new OutputVStreamClient(std::move(client), std::move(outputs_vstream_handle))); + + auto user_buffer_format = client->OutputVStream_get_user_buffer_format(outputs_vstream_handle); + CHECK_EXPECTED(user_buffer_format); + + auto info = client->OutputVStream_get_info(outputs_vstream_handle); + CHECK_EXPECTED(info); + + return std::shared_ptr(new OutputVStreamClient(std::move(client), std::move(outputs_vstream_handle), + user_buffer_format.release(), info.release())); } -OutputVStreamClient::OutputVStreamClient(std::unique_ptr client, uint32_t outputs_vstream_handle) - : m_client(std::move(client)), m_handle(std::move(outputs_vstream_handle)) {} +OutputVStreamClient::OutputVStreamClient(std::unique_ptr client, uint32_t outputs_vstream_handle, hailo_format_t &&user_buffer_format, + hailo_vstream_info_t &&info) + : m_client(std::move(client)), m_handle(std::move(outputs_vstream_handle)), m_user_buffer_format(user_buffer_format), m_info(info) {} OutputVStreamClient::~OutputVStreamClient() { @@ -1248,14 +1375,12 @@ size_t OutputVStreamClient::get_frame_size() const const hailo_vstream_info_t &OutputVStreamClient::get_info() const { - // TODO: HRT-6606 - assert(false); + return m_info; } const hailo_format_t &OutputVStreamClient::get_user_buffer_format() const { - // TODO: HRT-6606 - assert(false); + return m_user_buffer_format; } std::string OutputVStreamClient::name() const @@ -1270,64 +1395,63 @@ std::string OutputVStreamClient::name() const std::string OutputVStreamClient::network_name() const { - // TODO: HRT-6606 - assert(false); + auto expected_name = m_client->OutputVStream_network_name(m_handle); + if (!expected_name) { + LOGGER__CRITICAL("InputVStream_name failed with status={}", expected_name.status()); + return ""; + } + return expected_name.release(); } const std::map &OutputVStreamClient::get_fps_accumulators() const { - // TODO: HRT-6606 - assert(false); + LOGGER__ERROR("OutputVStream::get_fps_accumulators function is not supported when using multi-process service"); + return m_fps_accumulators; } const std::map &OutputVStreamClient::get_latency_accumulators() const { - // TODO: HRT-6606 - assert(false); + LOGGER__ERROR("OutputVStream::get_latency_accumulators functoin is not supported when using multi-process service"); + return m_latency_accumulators; } const std::map> &OutputVStreamClient::get_queue_size_accumulators() const { - // TODO: HRT-6606 - assert(false); + LOGGER__ERROR("OutputVStream::get_queue_size_accumulators function is not supported when using multi-process service"); + return m_queue_size_accumulators; } AccumulatorPtr OutputVStreamClient::get_pipeline_latency_accumulator() const { - // TODO: HRT-6606 - assert(false); + LOGGER__ERROR("OutputVStream::get_pipeline_latency_accumulator function is not supported when using multi-process service"); + return m_pipeline_latency_accumulator; } const std::vector> &OutputVStreamClient::get_pipeline() const { - // TODO: HRT-6606 - assert(false); + LOGGER__ERROR("OutputVStream::get_pipeline function is not supported when using multi-process service"); + return m_pipeline; } -hailo_status OutputVStreamClient::start_vstream() -{ - return HAILO_NOT_IMPLEMENTED; -} -hailo_status OutputVStreamClient::stop_vstream() -{ - return HAILO_NOT_IMPLEMENTED; -} -hailo_status OutputVStreamClient::stop_and_clear() -{ - return HAILO_NOT_IMPLEMENTED; -} #pragma GCC diagnostic pop #endif // HAILO_SUPPORT_MULTI_PROCESS -Expected> HwReadElement::create(OutputStream &stream, const std::string &name, std::chrono::milliseconds timeout, +Expected> HwReadElement::create(std::shared_ptr stream, const std::string &name, std::chrono::milliseconds timeout, size_t buffer_pool_size, hailo_pipeline_elem_stats_flags_t elem_flags, hailo_vstream_stats_flags_t vstream_flags, EventPtr shutdown_event, - std::shared_ptr> pipeline_status) + std::shared_ptr> pipeline_status, std::unique_ptr transform_context) { - auto buffer_pool = BufferPool::create(stream.get_frame_size(), buffer_pool_size, shutdown_event, elem_flags, vstream_flags); + auto buffer_pool = BufferPool::create(stream->get_frame_size(), buffer_pool_size, shutdown_event, elem_flags, vstream_flags); CHECK_EXPECTED(buffer_pool, "Failed creating BufferPool for {}", name); + BufferPoolPtr transform_pool = nullptr; + if (transform_context) { + auto expected_transform_pool = BufferPool::create(transform_context->get_dst_frame_size(), buffer_pool_size, shutdown_event, elem_flags, vstream_flags); + CHECK_EXPECTED(expected_transform_pool, "Failed creating BufferPool for {}", name); + transform_pool = expected_transform_pool.release(); + } + auto duration_collector = DurationCollector::create(elem_flags); CHECK_EXPECTED(duration_collector); auto hw_read_elem_ptr = make_shared_nothrow(stream, buffer_pool.release(), name, timeout, - duration_collector.release(), shutdown_event, std::move(pipeline_status)); + duration_collector.release(), shutdown_event, std::move(pipeline_status), transform_pool, std::move(transform_context)); CHECK_AS_EXPECTED(nullptr != hw_read_elem_ptr, HAILO_OUT_OF_HOST_MEMORY); LOGGER__INFO("Created {}", hw_read_elem_ptr->name()); @@ -1335,60 +1459,70 @@ Expected> HwReadElement::create(OutputStream &str return hw_read_elem_ptr; } -HwReadElement::HwReadElement(OutputStream &stream, BufferPoolPtr buffer_pool, const std::string &name, +HwReadElement::HwReadElement(std::shared_ptr stream, BufferPoolPtr buffer_pool, const std::string &name, std::chrono::milliseconds timeout, DurationCollector &&duration_collector, - EventPtr shutdown_event, std::shared_ptr> &&pipeline_status) : + EventPtr shutdown_event, std::shared_ptr> &&pipeline_status, + BufferPoolPtr transform_pool, std::unique_ptr transform_context) : SourceElement(name, std::move(duration_collector), std::move(pipeline_status)), m_stream(stream), m_pool(buffer_pool), + m_transform_pool(transform_pool), m_timeout(timeout), m_shutdown_event(shutdown_event), - m_activation_wait_or_shutdown(stream.get_network_group_activated_event(), shutdown_event) + m_activation_wait_or_shutdown(stream->get_network_group_activated_event(), shutdown_event), + m_transform_context(std::move(transform_context)) {} uint32_t HwReadElement::get_invalid_frames_count() { - return m_stream.get_invalid_frames_count(); + return m_stream->get_invalid_frames_count(); } std::string HwReadElement::description() const { std::stringstream element_description; - element_description << "(" << this->name() << " | hw_frame_size: " << m_stream.get_info().hw_frame_size << ")"; + element_description << "(" << this->name() << " | hw_frame_size: " << m_stream->get_info().hw_frame_size << ")"; return element_description.str(); } -hailo_status HwReadElement::post_deactivate() +hailo_status HwReadElement::execute_post_deactivate() { - auto status = m_stream.clear_abort(); + auto status = m_stream->clear_abort(); CHECK(((HAILO_SUCCESS == status) || (HAILO_STREAM_NOT_ACTIVATED == status)), status, "Failed to clear abort stream in {}", name()); return HAILO_SUCCESS; } -hailo_status HwReadElement::clear() +hailo_status HwReadElement::execute_clear() { return HAILO_SUCCESS; } -hailo_status HwReadElement::flush() +hailo_status HwReadElement::execute_flush() { return HAILO_INVALID_OPERATION; } -hailo_status HwReadElement::abort() +hailo_status HwReadElement::execute_abort() { - return m_stream.abort(); + auto status = m_stream->abort(); + CHECK(((status == HAILO_SUCCESS) || (status == HAILO_STREAM_NOT_ACTIVATED)), status, + "Failed to execute abort stream in {}", name()); + return HAILO_SUCCESS; } -void HwReadElement::wait_for_finish() +hailo_status HwReadElement::execute_resume() { + auto status = m_stream->clear_abort(); + CHECK(((status == HAILO_SUCCESS) || (status == HAILO_STREAM_NOT_ACTIVATED)), status, + "Failed to execute resume stream in {}", name()); + return HAILO_SUCCESS; } -hailo_status HwReadElement::resume() +hailo_status HwReadElement::execute_wait_for_finish() { - return m_stream.clear_abort(); + return HAILO_SUCCESS; } std::vector HwReadElement::get_queue_size_accumulators() @@ -1410,10 +1544,10 @@ Expected HwReadElement::run_pull(PipelineBuffer &&optional, cons if (HAILO_SHUTDOWN_EVENT_SIGNALED == buffer.status()) { return make_unexpected(buffer.status()); } - CHECK_EXPECTED(buffer); + CHECK_EXPECTED(buffer, "{} (D2H) failed with status={}", name(), buffer.status()); while (true) { - if (!m_stream.is_scheduled()) { + if (!m_stream->is_scheduled()) { auto status = m_activation_wait_or_shutdown.wait(m_timeout); if (HAILO_SHUTDOWN_EVENT_SIGNALED == status) { return make_unexpected(HAILO_SHUTDOWN_EVENT_SIGNALED); @@ -1431,39 +1565,49 @@ Expected HwReadElement::run_pull(PipelineBuffer &&optional, cons MemoryView buffer_view(buffer.value().as_view()); m_duration_collector.start_measurement(); - auto status = m_stream.read(buffer_view); - m_duration_collector.complete_measurement(); + auto status = m_stream->read(buffer_view); if (HAILO_INVALID_FRAME == status) { - m_stream.increase_invalid_frames_count(1); + m_stream->increase_invalid_frames_count(1); status = HAILO_SUCCESS; } if (HAILO_STREAM_NOT_ACTIVATED == status) { // Try again continue; } - if (HAILO_STREAM_INTERNAL_ABORT == status) { + if (HAILO_STREAM_ABORTED_BY_USER == status) { LOGGER__INFO("Reading from stream was aborted!"); - return make_unexpected(HAILO_STREAM_INTERNAL_ABORT); + return make_unexpected(HAILO_STREAM_ABORTED_BY_USER); + } + CHECK_SUCCESS_AS_EXPECTED(status, "{} (D2H) failed with status={}", name(), status); + m_duration_collector.complete_measurement(); + + // TODO: This is for rare cases where a transormation is needed before another pipeline element + // Should be handled by the computational graph, and not here. + if (m_transform_context) { + auto transform_buffer = m_transform_pool->get_available_buffer(PipelineBuffer(), m_timeout); + CHECK_EXPECTED(buffer); + status = m_transform_context->transform(buffer_view, transform_buffer.value().as_view()); + CHECK_SUCCESS_AS_EXPECTED(status); + return transform_buffer.release(); } - CHECK_SUCCESS_AS_EXPECTED(status); return buffer.release(); } } -hailo_status HwReadElement::activate() +hailo_status HwReadElement::execute_activate() { return HAILO_SUCCESS; } -hailo_status HwReadElement::deactivate() +hailo_status HwReadElement::execute_deactivate() { auto signal_shutdown_status = m_shutdown_event->signal(); if (HAILO_SUCCESS != signal_shutdown_status) { LOGGER__ERROR("Signaling {} shutdown event failed with {}", name(), signal_shutdown_status); } - auto abort_status = m_stream.abort(); + auto abort_status = m_stream->abort(); if ((HAILO_SUCCESS != abort_status) && (HAILO_STREAM_NOT_ACTIVATED != abort_status)) { LOGGER__ERROR("Abort {} failed with {}", name(), abort_status); return abort_status; @@ -1472,7 +1616,7 @@ hailo_status HwReadElement::deactivate() return signal_shutdown_status; } -Expected> HwWriteElement::create(InputStream &stream, const std::string &name, +Expected> HwWriteElement::create(std::shared_ptr stream, const std::string &name, hailo_pipeline_elem_stats_flags_t elem_flags, std::shared_ptr> pipeline_status) { @@ -1491,7 +1635,7 @@ Expected> HwWriteElement::create(InputStream &st return hw_write_elem_ptr; } -HwWriteElement::HwWriteElement(InputStream &stream, const std::string &name, DurationCollector &&duration_collector, +HwWriteElement::HwWriteElement(std::shared_ptr stream, const std::string &name, DurationCollector &&duration_collector, std::shared_ptr> &&pipeline_status, EventPtr got_flush_event) : SinkElement(name, std::move(duration_collector), std::move(pipeline_status)), m_stream(stream), m_got_flush_event(got_flush_event) @@ -1505,9 +1649,9 @@ Expected HwWriteElement::run_pull(PipelineBuffer &&/*optional*/, hailo_status HwWriteElement::run_push(PipelineBuffer &&buffer) { if (PipelineBuffer::Type::FLUSH == buffer.get_type()) { - hailo_status flush_status = m_stream.flush(); - if (HAILO_STREAM_INTERNAL_ABORT == flush_status) { - LOGGER__INFO("Failed flushing input stream {} because stream was aborted", m_stream.to_string()); + hailo_status flush_status = m_stream->flush(); + if (HAILO_STREAM_ABORTED_BY_USER == flush_status) { + LOGGER__INFO("Failed flushing input stream {} because stream was aborted", m_stream->to_string()); } else if (HAILO_SUCCESS != flush_status) { LOGGER__ERROR("flush has failed in {} with status {}", name(), flush_status); } @@ -1517,52 +1661,58 @@ hailo_status HwWriteElement::run_push(PipelineBuffer &&buffer) } m_duration_collector.start_measurement(); - const auto status = m_stream.write(MemoryView(buffer.data(), buffer.size())); + const auto status = m_stream->write(MemoryView(buffer.data(), buffer.size())); m_duration_collector.complete_measurement(); - return status; + if (HAILO_STREAM_ABORTED_BY_USER == status) { + LOGGER__INFO("Failed to send on input stream {} because stream was aborted", m_stream->to_string()); + return HAILO_STREAM_ABORTED_BY_USER; + } + CHECK_SUCCESS(status, "{} (H2D) failed with status={}", name(), status); + + return HAILO_SUCCESS; } -hailo_status HwWriteElement::activate() +hailo_status HwWriteElement::execute_activate() { return HAILO_SUCCESS; } -hailo_status HwWriteElement::deactivate() +hailo_status HwWriteElement::execute_deactivate() { // The flush operation will block until all buffers currently in the pipeline will be processed. // We assume that no buffers are sent after the call for deactivate. - hailo_status flush_status = m_stream.flush(); - if (HAILO_STREAM_INTERNAL_ABORT == flush_status) { - LOGGER__INFO("Failed flushing input stream {} because stream was aborted", m_stream.to_string()); + hailo_status flush_status = m_stream->flush(); + if (HAILO_STREAM_ABORTED_BY_USER == flush_status) { + LOGGER__INFO("Failed flushing input stream {} because stream was aborted", m_stream->to_string()); // TODO: HRT-3621 return HAILO_SUCCESS; } else if (HAILO_SUCCESS != flush_status) { LOGGER__ERROR("flush has failed in {} with status {}", name(), flush_status); } - auto abort_status = m_stream.abort(); + auto abort_status = m_stream->abort(); CHECK(((abort_status == HAILO_SUCCESS) || (abort_status == HAILO_STREAM_NOT_ACTIVATED)), abort_status, "Failed to abort stream in {}", name()); return HAILO_SUCCESS; } -hailo_status HwWriteElement::post_deactivate() +hailo_status HwWriteElement::execute_post_deactivate() { - auto status = m_stream.clear_abort(); + auto status = m_stream->clear_abort(); CHECK(((status == HAILO_SUCCESS) || (status == HAILO_STREAM_NOT_ACTIVATED)), status, "Failed to clear abort stream in {}", name()); return HAILO_SUCCESS; } -hailo_status HwWriteElement::clear() +hailo_status HwWriteElement::execute_clear() { return HAILO_SUCCESS; } -hailo_status HwWriteElement::flush() +hailo_status HwWriteElement::execute_flush() { - hailo_status status = m_got_flush_event->wait(m_stream.get_timeout()); + hailo_status status = m_got_flush_event->wait(m_stream->get_timeout()); CHECK_SUCCESS(status); status = m_got_flush_event->reset(); @@ -1571,24 +1721,31 @@ hailo_status HwWriteElement::flush() return HAILO_SUCCESS; } -hailo_status HwWriteElement::abort() +hailo_status HwWriteElement::execute_abort() { - return m_stream.abort(); + auto status = m_stream->abort(); + CHECK(((status == HAILO_SUCCESS) || (status == HAILO_STREAM_NOT_ACTIVATED)), status, + "Failed to execute abort stream in {}", name()); + return HAILO_SUCCESS; } -void HwWriteElement::wait_for_finish() +hailo_status HwWriteElement::execute_resume() { + auto status = m_stream->clear_abort(); + CHECK(((status == HAILO_SUCCESS) || (status == HAILO_STREAM_NOT_ACTIVATED)), status, + "Failed to execute resume stream in {}", name()); + return HAILO_SUCCESS; } -hailo_status HwWriteElement::resume() +hailo_status HwWriteElement::execute_wait_for_finish() { - return m_stream.clear_abort(); + return HAILO_SUCCESS; } std::string HwWriteElement::description() const { std::stringstream element_description; - element_description << "(" << this->name() << " | hw_frame_size: " << m_stream.get_info().hw_frame_size << ")"; + element_description << "(" << this->name() << " | hw_frame_size: " << m_stream->get_info().hw_frame_size << ")"; return element_description.str(); } @@ -1614,7 +1771,7 @@ CopyBufferElement::CopyBufferElement(const std::string &name, DurationCollector PipelinePad &CopyBufferElement::next_pad() { // Note: The next elem to be run is downstream from this elem (i.e. buffers are pushed) - return *m_sources[0].next(); + return *m_sinks[0].prev(); } Expected CopyBufferElement::action(PipelineBuffer &&input, PipelineBuffer &&optional) @@ -1688,7 +1845,7 @@ Expected> VStreamsBuilder::create_output_vstreams(Con return net_group.create_output_vstreams(outputs_params); } -Expected> VStreamsBuilderUtils::create_inputs(InputStream &input_stream, const hailo_vstream_info_t &vstream_info, +Expected> VStreamsBuilderUtils::create_inputs(std::shared_ptr input_stream, const hailo_vstream_info_t &vstream_info, const hailo_vstream_params_t &vstream_params) { // TODO (HRT-4522): Support this measurement @@ -1699,8 +1856,8 @@ Expected> VStreamsBuilderUtils::create_inputs(InputStr std::vector vstreams; EventPtr network_group_activated_event = nullptr; - if (!input_stream.is_scheduled()) { - network_group_activated_event = input_stream.get_network_group_activated_event(); + if (!input_stream->is_scheduled()) { + network_group_activated_event = input_stream->get_network_group_activated_event(); } auto shutdown_event = Event::create_shared(Event::State::not_signalled); @@ -1715,39 +1872,39 @@ Expected> VStreamsBuilderUtils::create_inputs(InputStr auto user_timeout = std::chrono::milliseconds(vstream_params.timeout_ms); auto hw_write_elem = HwWriteElement::create(input_stream, - PipelineObject::create_element_name("HwWriteElement", input_stream.name(), input_stream.get_info().index), + PipelineObject::create_element_name("HwWriteElement", input_stream->name(), input_stream->get_info().index), vstream_params.pipeline_elements_stats_flags, pipeline_status); CHECK_EXPECTED(hw_write_elem); elements.insert(elements.begin(), hw_write_elem.value()); - auto should_transform = InputTransformContext::is_transformation_required(input_stream.get_info().shape, - vstream_params.user_buffer_format, input_stream.get_info().hw_shape, input_stream.get_info().format, - input_stream.get_info().quant_info); + auto should_transform = InputTransformContext::is_transformation_required(input_stream->get_info().shape, + vstream_params.user_buffer_format, input_stream->get_info().hw_shape, input_stream->get_info().format, + input_stream->get_info().quant_info); if (should_transform) { std::shared_ptr elem_after_post_infer = hw_write_elem.value(); auto queue_elem = PushQueueElement::create( - PipelineObject::create_element_name("PushQueueElement", input_stream.get_info().name, input_stream.get_info().index), + PipelineObject::create_element_name("PushQueueElement", input_stream->get_info().name, input_stream->get_info().index), vstream_params, shutdown_event, pipeline_status); CHECK_EXPECTED(queue_elem); elements.insert(elements.begin(), queue_elem.value()); CHECK_SUCCESS_AS_EXPECTED(PipelinePad::link_pads(queue_elem.value(), hw_write_elem.value())); - auto pre_infer_elem = PreInferElement::create(input_stream.get_info().shape, vstream_params.user_buffer_format, - input_stream.get_info().hw_shape, input_stream.get_info().format, input_stream.get_info().quant_info, - PipelineObject::create_element_name("PreInferElement", input_stream.get_info().name, input_stream.get_info().index), - vstream_params, shutdown_event, pipeline_status); + auto pre_infer_elem = PreInferElement::create(input_stream->get_info().shape, vstream_params.user_buffer_format, + input_stream->get_info().hw_shape, input_stream->get_info().format, input_stream->get_info().quant_info, + PipelineObject::create_element_name("PreInferElement", input_stream->get_info().name, input_stream->get_info().index), + vstream_params, shutdown_event, pipeline_status); CHECK_EXPECTED(pre_infer_elem); elements.insert(elements.begin(), pre_infer_elem.value()); CHECK_SUCCESS_AS_EXPECTED(PipelinePad::link_pads(pre_infer_elem.value(), queue_elem.value())); - input_stream.set_timeout(user_timeout); + input_stream->set_timeout(user_timeout); auto vstream = InputVStream::create(vstream_info, vstream_params, pre_infer_elem.release(), hw_write_elem.release(), std::move(elements), std::move(pipeline_status), shutdown_event, network_group_activated_event, pipeline_latency_accumulator.release()); CHECK_EXPECTED(vstream); vstreams.emplace_back(vstream.release()); } else { - input_stream.set_timeout(user_timeout); + input_stream->set_timeout(user_timeout); auto vstream = InputVStream::create(vstream_info, vstream_params, hw_write_elem.value(), hw_write_elem.value(), std::move(elements), std::move(pipeline_status), shutdown_event, network_group_activated_event, pipeline_latency_accumulator.release()); CHECK_EXPECTED(vstream); @@ -1761,15 +1918,15 @@ Expected> VStreamsBuilderUtils::create_inputs(InputStr return vstreams; } -Expected> VStreamsBuilderUtils::create_outputs(OutputStream &output_stream, +Expected> VStreamsBuilderUtils::create_outputs(std::shared_ptr output_stream, NameToVStreamParamsMap &vstreams_params_map, const std::map &output_vstream_infos) { std::vector> elements; std::vector vstreams; EventPtr network_group_activated_event = nullptr; - if (!output_stream.is_scheduled()) { - network_group_activated_event = output_stream.get_network_group_activated_event(); + if (!output_stream->is_scheduled()) { + network_group_activated_event = output_stream->get_network_group_activated_event(); } auto shutdown_event = Event::create_shared(Event::State::not_signalled); @@ -1796,61 +1953,61 @@ Expected> VStreamsBuilderUtils::create_outputs(Output "Pipeline FPS statistics measurement is not implemented"); auto hw_read_elem = HwReadElement::create(output_stream, - PipelineObject::create_element_name("HwReadElement", output_stream.name(), output_stream.get_info().index), + PipelineObject::create_element_name("HwReadElement", output_stream->name(), output_stream->get_info().index), HAILO_INFINITE_TIMEOUT, buffer_pool_size, hw_read_element_stats_flags, hw_read_stream_stats_flags, shutdown_event, pipeline_status); CHECK_EXPECTED(hw_read_elem); elements.push_back(hw_read_elem.value()); - if (output_stream.get_info().is_mux) { + if (output_stream->get_info().is_mux) { hailo_status status = add_demux(output_stream, vstreams_params_map, std::move(elements), vstreams, hw_read_elem.value(), shutdown_event, pipeline_status, output_vstream_infos); CHECK_SUCCESS_AS_EXPECTED(status); } else { - auto vstream_info = output_vstream_infos.find(output_stream.name()); + auto vstream_info = output_vstream_infos.find(output_stream->name()); CHECK_AS_EXPECTED(vstream_info != output_vstream_infos.end(), HAILO_NOT_FOUND, - "Failed to find vstream info of {}", output_stream.name()); + "Failed to find vstream info of {}", output_stream->name()); assert(1 == vstreams_params_map.size()); - auto vstream_params = expand_vstream_params_autos(output_stream.get_info(), vstreams_params_map.begin()->second); + auto vstream_params = expand_vstream_params_autos(output_stream->get_info(), vstreams_params_map.begin()->second); auto pipeline_latency_accumulator = create_pipeline_latency_accumulator(vstream_params); CHECK_EXPECTED(pipeline_latency_accumulator); - auto should_transform = OutputTransformContext::is_transformation_required(output_stream.get_info().hw_shape, - output_stream.get_info().format, output_stream.get_info().shape, - vstream_params.user_buffer_format, output_stream.get_info().quant_info); + auto should_transform = OutputTransformContext::is_transformation_required(output_stream->get_info().hw_shape, + output_stream->get_info().format, output_stream->get_info().shape, + vstream_params.user_buffer_format, output_stream->get_info().quant_info); if (should_transform) { auto hw_read_queue_elem = PullQueueElement::create( - PipelineObject::create_element_name("PullQueueElement_hw_read", output_stream.name(), output_stream.get_info().index), + PipelineObject::create_element_name("PullQueueElement_hw_read", output_stream->name(), output_stream->get_info().index), vstream_params, shutdown_event, pipeline_status); CHECK_EXPECTED(hw_read_queue_elem); elements.push_back(hw_read_queue_elem.value()); CHECK_SUCCESS_AS_EXPECTED(PipelinePad::link_pads(hw_read_elem.value(), hw_read_queue_elem.value())); - auto post_infer_elem = PostInferElement::create(output_stream.get_info().hw_shape, output_stream.get_info().format, - output_stream.get_info().shape, vstream_params.user_buffer_format, output_stream.get_info().quant_info, output_stream.get_info().nms_info, - PipelineObject::create_element_name("PostInferElement", output_stream.name(), output_stream.get_info().index), + auto post_infer_elem = PostInferElement::create(output_stream->get_info().hw_shape, output_stream->get_info().format, + output_stream->get_info().shape, vstream_params.user_buffer_format, output_stream->get_info().quant_info, output_stream->get_info().nms_info, + PipelineObject::create_element_name("PostInferElement", output_stream->name(), output_stream->get_info().index), vstream_params, pipeline_status); CHECK_EXPECTED(post_infer_elem); elements.push_back(post_infer_elem.value()); CHECK_SUCCESS_AS_EXPECTED(PipelinePad::link_pads(hw_read_queue_elem.value(), post_infer_elem.value())); auto post_infer_queue_elem = UserBufferQueueElement::create( - PipelineObject::create_element_name("UserBufferQueueElement_post_infer", output_stream.name(), output_stream.get_info().index), + PipelineObject::create_element_name("UserBufferQueueElement_post_infer", output_stream->name(), output_stream->get_info().index), vstream_params, shutdown_event, pipeline_status); CHECK_EXPECTED(post_infer_queue_elem); elements.push_back(post_infer_queue_elem.value()); CHECK_SUCCESS_AS_EXPECTED(PipelinePad::link_pads(post_infer_elem.value(), post_infer_queue_elem.value())); - output_stream.set_timeout(std::chrono::milliseconds(HAILO_INFINITE)); + output_stream->set_timeout(std::chrono::milliseconds(HAILO_INFINITE)); hw_read_queue_elem->get()->set_timeout(std::chrono::milliseconds(HAILO_INFINITE)); auto vstream = OutputVStream::create(vstream_info->second, vstream_params, post_infer_queue_elem.release(), std::move(elements), std::move(pipeline_status), shutdown_event, network_group_activated_event, pipeline_latency_accumulator.release()); CHECK_EXPECTED(vstream); vstreams.emplace_back(vstream.release()); } else { - output_stream.set_timeout(std::chrono::milliseconds(vstream_params.timeout_ms)); + output_stream->set_timeout(std::chrono::milliseconds(vstream_params.timeout_ms)); auto vstream = OutputVStream::create(vstream_info->second, vstream_params, hw_read_elem.release(), std::move(elements), std::move(pipeline_status), shutdown_event, network_group_activated_event, pipeline_latency_accumulator.release()); CHECK_EXPECTED(vstream); @@ -1879,12 +2036,12 @@ static bool are_formats_equal(const hailo_format_t &format1, const hailo_format_ return ((format1.order == format2.order) && (format1.flags == format2.flags) && (format1.type == format2.type)); } -Expected> VStreamsBuilderUtils::create_output_nms(OutputStreamRefVector &output_streams, +Expected> VStreamsBuilderUtils::create_output_nms(OutputStreamPtrVector &output_streams, hailo_vstream_params_t vstreams_params, const std::map &output_vstream_infos) { for (const auto &out_stream : output_streams) { - CHECK_AS_EXPECTED(are_formats_equal(output_streams[0].get().get_info().format, out_stream.get().get_info().format), + CHECK_AS_EXPECTED(are_formats_equal(output_streams[0]->get_info().format, out_stream->get_info().format), HAILO_INVALID_ARGUMENT, "All nms streams of the same virtual output must have the same format"); } @@ -1908,18 +2065,53 @@ Expected> VStreamsBuilderUtils::create_output_nms(Out return vstreams; } -hailo_status VStreamsBuilderUtils::add_demux(OutputStream &output_stream, NameToVStreamParamsMap &vstreams_params_map, +Expected> VStreamsBuilderUtils::create_output_post_process_nms(OutputStreamPtrVector &output_streams, + hailo_vstream_params_t vstreams_params, + const std::map &output_vstream_infos, + const NetFlowYoloNmsElement &nms_op) +{ + static const auto EXPECTED_OUTPUTS = 3; + CHECK_AS_EXPECTED(output_streams.size() == EXPECTED_OUTPUTS, + HAILO_INVALID_ARGUMENT, "Core expected to have exactly {} outputs when using NMS post-processing", EXPECTED_OUTPUTS); + + std::sort(output_streams.begin(), output_streams.end(), [](auto &stream_0, auto &stream_1) { + std::string name0(stream_0->get_info().name); + std::string name1(stream_1->get_info().name); + return name0 < name1; + }); + + auto shutdown_event = Event::create_shared(Event::State::not_signalled); + CHECK_AS_EXPECTED(nullptr != shutdown_event, HAILO_OUT_OF_HOST_MEMORY); + + auto pipeline_status = make_shared_nothrow>(HAILO_SUCCESS); + CHECK_AS_EXPECTED(nullptr != pipeline_status, HAILO_OUT_OF_HOST_MEMORY); + + std::vector> elements; + std::vector vstreams; + + hailo_status status = add_nms_post_process(output_streams, vstreams_params, elements, vstreams, shutdown_event, + pipeline_status, output_vstream_infos, nms_op); + CHECK_SUCCESS_AS_EXPECTED(status); + + for (const auto &vstream : vstreams) { + LOGGER__INFO("{}", vstream.get_pipeline_description()); + } + + return vstreams; +} + +hailo_status VStreamsBuilderUtils::add_demux(std::shared_ptr output_stream, NameToVStreamParamsMap &vstreams_params_map, std::vector> &&base_elements, std::vector &vstreams, std::shared_ptr hw_read_elem, EventPtr shutdown_event, std::shared_ptr> pipeline_status, const std::map &output_vstream_infos) { - auto expected_demuxer = OutputDemuxer::create(output_stream); + auto expected_demuxer = OutputDemuxer::create(*output_stream); CHECK_EXPECTED_AS_STATUS(expected_demuxer); std::shared_ptr demuxer_ptr = expected_demuxer.release(); CHECK(nullptr != demuxer_ptr, HAILO_OUT_OF_HOST_MEMORY); - auto status = output_stream.set_timeout(HAILO_INFINITE_TIMEOUT); + auto status = output_stream->set_timeout(HAILO_INFINITE_TIMEOUT); CHECK_SUCCESS(status); // Note: In case of multiple values in vstreams_params_map (e.g. in the case of demux), we'll set the @@ -1934,15 +2126,15 @@ hailo_status VStreamsBuilderUtils::add_demux(OutputStream &output_stream, NameTo } auto demux_elem = TransformDemuxElement::create(demuxer_ptr, - PipelineObject::create_element_name("TransformDemuxElement", output_stream.name(), output_stream.get_info().index), + PipelineObject::create_element_name("TransformDemuxElement", output_stream->name(), output_stream->get_info().index), std::chrono::milliseconds(HAILO_INFINITE), buffer_pool_size, demux_elem_stats_flags, demux_vstream_stats_flags, shutdown_event, pipeline_status); CHECK_EXPECTED_AS_STATUS(demux_elem); base_elements.push_back(demux_elem.value()); CHECK_SUCCESS(PipelinePad::link_pads(hw_read_elem, demux_elem.value())); EventPtr network_group_activated_event = nullptr; - if (!output_stream.is_scheduled()) { - network_group_activated_event = output_stream.get_network_group_activated_event(); + if (!output_stream->is_scheduled()) { + network_group_activated_event = output_stream->get_network_group_activated_event(); } uint32_t i = 0; @@ -1955,7 +2147,7 @@ hailo_status VStreamsBuilderUtils::add_demux(OutputStream &output_stream, NameTo CHECK(vstream_info != output_vstream_infos.end(), HAILO_NOT_FOUND, "Failed to find vstream info of {}", edge_info.name); - const auto vstream_params = expand_vstream_params_autos(output_stream.get_info(), name_params_pair->second); + const auto vstream_params = expand_vstream_params_autos(output_stream->get_info(), name_params_pair->second); // For each mux vstream, we create a copy of the previous elements auto current_vstream_elements = base_elements; @@ -2016,7 +2208,7 @@ hailo_status VStreamsBuilderUtils::add_demux(OutputStream &output_stream, NameTo return HAILO_SUCCESS; } -hailo_status VStreamsBuilderUtils::add_nms_fuse(OutputStreamRefVector &output_streams, hailo_vstream_params_t &vstreams_params, +hailo_status VStreamsBuilderUtils::add_nms_fuse(OutputStreamPtrVector &output_streams, hailo_vstream_params_t &vstreams_params, std::vector> &elements, std::vector &vstreams, EventPtr shutdown_event, std::shared_ptr> pipeline_status, const std::map &output_vstream_infos) @@ -2024,13 +2216,13 @@ hailo_status VStreamsBuilderUtils::add_nms_fuse(OutputStreamRefVector &output_st std::vector nms_infos; nms_infos.reserve(output_streams.size()); for (const auto &out_stream : output_streams) { - CHECK(out_stream.get().get_info().nms_info.defuse_info.class_group_index <= output_streams.size(), + CHECK(out_stream->get_info().nms_info.defuse_info.class_group_index <= output_streams.size(), HAILO_INVALID_ARGUMENT, "Not all defused nms outputs were grouped correctly!"); - nms_infos.emplace_back(out_stream.get().get_info().nms_info); + nms_infos.emplace_back(out_stream->get_info().nms_info); } // To get the fused layer name and src stream format, we use the stream info of one of the defuses - auto first_defused_stream_info = output_streams[0].get().get_info(); + auto first_defused_stream_info = output_streams[0]->get_info(); auto fused_layer_name = first_defused_stream_info.nms_info.defuse_info.original_name; auto src_stream_format = first_defused_stream_info.format; @@ -2046,7 +2238,7 @@ hailo_status VStreamsBuilderUtils::add_nms_fuse(OutputStreamRefVector &output_st auto fused_layer_nms_info = nms_elem.value()->get_fused_nms_info(); for (uint32_t i = 0; i < output_streams.size(); ++i) { - const auto &curr_stream_info = output_streams[i].get().get_info(); + const auto &curr_stream_info = output_streams[i]->get_info(); auto hw_read_elem = HwReadElement::create(output_streams[i], PipelineObject::create_element_name("HwReadElement", curr_stream_info.name, curr_stream_info.index), @@ -2072,8 +2264,8 @@ hailo_status VStreamsBuilderUtils::add_nms_fuse(OutputStreamRefVector &output_st vstreams_params.user_buffer_format, vstream_info->second.quant_info); EventPtr network_group_activated_event = nullptr; - if (!output_streams[0].get().is_scheduled()) { - network_group_activated_event = output_streams[0].get().get_network_group_activated_event(); + if (!output_streams[0]->is_scheduled()) { + network_group_activated_event = output_streams[0]->get_network_group_activated_event(); } if (should_transform) { @@ -2113,6 +2305,111 @@ hailo_status VStreamsBuilderUtils::add_nms_fuse(OutputStreamRefVector &output_st return HAILO_SUCCESS; } +hailo_status VStreamsBuilderUtils::add_nms_post_process(OutputStreamPtrVector &output_streams, hailo_vstream_params_t &vstreams_params, + std::vector> &elements, std::vector &vstreams, + EventPtr shutdown_event, std::shared_ptr> pipeline_status, + const std::map &output_vstream_infos, + const NetFlowYoloNmsElement &nms_op) +{ + auto first_stream_info = output_streams[0]->get_info(); + if (vstreams_params.user_buffer_format.type == HAILO_FORMAT_TYPE_AUTO) { + vstreams_params.user_buffer_format.type = HAILO_FORMAT_TYPE_FLOAT32; + } + if (vstreams_params.user_buffer_format.order == HAILO_FORMAT_ORDER_AUTO) { + vstreams_params.user_buffer_format.order = HAILO_FORMAT_ORDER_HAILO_NMS; + } + vstreams_params = expand_vstream_params_autos(first_stream_info, vstreams_params); + CHECK(vstreams_params.user_buffer_format.type == HAILO_FORMAT_TYPE_FLOAT32, HAILO_INVALID_ARGUMENT, + "NMS output format type must be HAILO_FORMAT_TYPE_FLOAT32"); + CHECK(vstreams_params.user_buffer_format.order == HAILO_FORMAT_ORDER_HAILO_NMS, HAILO_INVALID_ARGUMENT, + "NMS output format order must be HAILO_FORMAT_ORDER_HAILO_NMS"); + + hailo_nms_info_t nms_info = { + nms_op.classes, + nms_op.max_proposals_per_class, + sizeof(hailo_bbox_float32_t), + nms_op.input_division_factor, + false, + hailo_nms_defuse_info_t() + }; + + std::vector shapes; + shapes.reserve(output_streams.size()); + std::vector formats; + formats.reserve(output_streams.size()); + std::vector quant_infos; + quant_infos.reserve(output_streams.size()); + for (uint32_t i = 0; i < output_streams.size(); ++i) { + const auto &curr_stream_info = output_streams[i]->get_info(); + shapes.push_back(curr_stream_info.shape); + formats.push_back(curr_stream_info.format); + quant_infos.push_back(curr_stream_info.quant_info); + } + + const auto &output_pads = nms_op.output_pads; + assert(output_pads.size() == 1); + auto vstream_info = output_vstream_infos.find(output_pads[0].name); + CHECK(vstream_info != output_vstream_infos.end(), HAILO_NOT_FOUND, + "Failed to find vstream info of {}", nms_op.name); + + auto nms_elem = NmsPostProcessMuxElement::create(nms_op, shapes, formats, quant_infos, nms_info, + PipelineObject::create_element_name("NmsPostProcessMuxElement", nms_op.name, 0), + vstreams_params, shutdown_event, pipeline_status); + CHECK_EXPECTED_AS_STATUS(nms_elem); + + hailo_format_t nms_src_format; + nms_src_format.flags = HAILO_FORMAT_FLAGS_QUANTIZED; + nms_src_format.order = HAILO_FORMAT_ORDER_NHWC; + nms_src_format.type = first_stream_info.format.type; + + for (uint32_t i = 0; i < output_streams.size(); ++i) { + const auto &curr_stream_info = output_streams[i]->get_info(); + + auto should_transform = OutputTransformContext::is_transformation_required(curr_stream_info.hw_shape, curr_stream_info.format, + curr_stream_info.shape, nms_src_format, vstream_info->second.quant_info); + + std::unique_ptr transform_context = nullptr; + + if (should_transform) { + auto expected_transform_context = OutputTransformContext::create(curr_stream_info.hw_shape, curr_stream_info.format, + curr_stream_info.shape, nms_src_format, vstream_info->second.quant_info, nms_info); + CHECK_EXPECTED_AS_STATUS(expected_transform_context); + transform_context = expected_transform_context.release(); + } + + auto hw_read_elem = HwReadElement::create(output_streams[i], + PipelineObject::create_element_name("HwReadElement", curr_stream_info.name, curr_stream_info.index), + HAILO_INFINITE_TIMEOUT, vstreams_params.queue_size, vstreams_params.pipeline_elements_stats_flags, + vstreams_params.vstream_stats_flags, shutdown_event, pipeline_status, std::move(transform_context)); + CHECK_EXPECTED_AS_STATUS(hw_read_elem); + elements.push_back(hw_read_elem.value()); + + auto nms_source_queue_elem = PullQueueElement::create( + PipelineObject::create_element_name("PullQueueElement_nms_source", curr_stream_info.name, curr_stream_info.index), + vstreams_params, shutdown_event, pipeline_status); + CHECK_EXPECTED_AS_STATUS(nms_source_queue_elem); + elements.push_back(nms_source_queue_elem.value()); + CHECK_SUCCESS(PipelinePad::link_pads(hw_read_elem.value(), nms_source_queue_elem.value())); + CHECK_SUCCESS(PipelinePad::link_pads(nms_source_queue_elem.value(), nms_elem.value(), 0, i)); + } + elements.push_back(nms_elem.value()); + + auto pipeline_latency_accumulator = create_pipeline_latency_accumulator(vstreams_params); + CHECK_EXPECTED_AS_STATUS(pipeline_latency_accumulator); + + EventPtr network_group_activated_event = nullptr; + if (!output_streams[0]->is_scheduled()) { + network_group_activated_event = output_streams[0]->get_network_group_activated_event(); + } + + auto vstream = OutputVStream::create(vstream_info->second, vstreams_params, nms_elem.release(), std::move(elements), + std::move(pipeline_status), shutdown_event, network_group_activated_event, pipeline_latency_accumulator.release()); + CHECK_EXPECTED_AS_STATUS(vstream); + vstreams.emplace_back(vstream.release()); + + return HAILO_SUCCESS; +} + Expected VStreamsBuilderUtils::create_pipeline_latency_accumulator(const hailo_vstream_params_t &vstreams_params) { AccumulatorPtr pipeline_latency_accumulator = nullptr; diff --git a/hailort/libhailort/src/vstream_internal.hpp b/hailort/libhailort/src/vstream_internal.hpp index 875cbfe..a4ff6e2 100644 --- a/hailort/libhailort/src/vstream_internal.hpp +++ b/hailort/libhailort/src/vstream_internal.hpp @@ -27,9 +27,11 @@ #define _HAILO_VSTREAM_INTERNAL_HPP_ #include "pipeline.hpp" +#include "hef_internal.hpp" +#include "net_flow/ops/yolo_post_processing.hpp" #include "hailo/transform.hpp" #include "hailo/stream.hpp" -#include "hailo/network_group.hpp" +#include "context_switch/network_group_internal.hpp" #ifdef HAILO_SUPPORT_MULTI_PROCESS #include "hailort_rpc_client.hpp" @@ -225,16 +227,14 @@ public: virtual AccumulatorPtr get_pipeline_latency_accumulator() const override; virtual const std::vector> &get_pipeline() const override; -protected: - virtual hailo_status start_vstream() override; - virtual hailo_status stop_vstream() override; - virtual hailo_status stop_and_clear() override; - private: - InputVStreamClient(std::unique_ptr client, uint32_t input_vstream_handle); + InputVStreamClient(std::unique_ptr client, uint32_t input_vstream_handle, hailo_format_t &&user_buffer_format, + hailo_vstream_info_t &&info); std::unique_ptr m_client; uint32_t m_handle; + hailo_format_t m_user_buffer_format; + hailo_vstream_info_t m_info; }; class OutputVStreamClient : public OutputVStreamInternal @@ -262,16 +262,14 @@ public: virtual AccumulatorPtr get_pipeline_latency_accumulator() const override; virtual const std::vector> &get_pipeline() const override; -protected: - virtual hailo_status start_vstream() override; - virtual hailo_status stop_vstream() override; - virtual hailo_status stop_and_clear() override; - private: - OutputVStreamClient(std::unique_ptr client, uint32_t outputs_vstream_handle); + OutputVStreamClient(std::unique_ptr client, uint32_t outputs_vstream_handle, hailo_format_t &&user_buffer_format, + hailo_vstream_info_t &&info); std::unique_ptr m_client; uint32_t m_handle; + hailo_format_t m_user_buffer_format; + hailo_vstream_info_t m_info; }; #endif // HAILO_SUPPORT_MULTI_PROCESS @@ -328,6 +326,33 @@ private: std::unique_ptr m_transform_context; }; +class NmsPostProcessMuxElement : public BaseMuxElement +{ +public: + static Expected> create(const NetFlowYoloNmsElement &nms_op, + const std::vector &shapes, const std::vector &formats, + const std::vector &quant_infos, hailo_format_t format, hailo_nms_info_t nms_info, + const std::string &name, std::chrono::milliseconds timeout, size_t buffer_pool_size, + hailo_pipeline_elem_stats_flags_t elem_flags, hailo_vstream_stats_flags_t vstream_flags, EventPtr shutdown_event, + std::shared_ptr> pipeline_status); + static Expected> create(const NetFlowYoloNmsElement &nms_op, + const std::vector &shapes, const std::vector &formats, + const std::vector &quant_infos, hailo_nms_info_t nms_info, const std::string &name, + const hailo_vstream_params_t &vstream_params, EventPtr shutdown_event, std::shared_ptr> pipeline_status); + NmsPostProcessMuxElement(const net_flow::YOLOv5PostProcessingOp &nms_op, BufferPoolPtr &&pool, const std::string &name, + std::chrono::milliseconds timeout, DurationCollector &&duration_collector, + std::shared_ptr> &&pipeline_status); + + virtual std::vector get_queue_size_accumulators() override; + +protected: + virtual Expected action(std::vector &&inputs, PipelineBuffer &&optional) override; + +private: + net_flow::YOLOv5PostProcessingOp m_nms_op; + BufferPoolPtr m_pool; +}; + class NmsMuxElement : public BaseMuxElement { public: @@ -343,7 +368,7 @@ public: virtual std::vector get_queue_size_accumulators() override; protected: - virtual Expected action(std::vector &&inputs, PipelineBuffer &&optional) override; + virtual Expected action(std::vector &&inputs, PipelineBuffer &&optional) override; private: std::vector m_nms_infos; @@ -373,59 +398,62 @@ private: class HwReadElement : public SourceElement { public: - static Expected> create(OutputStream &stream, const std::string &name, std::chrono::milliseconds timeout, + static Expected> create(std::shared_ptr stream, const std::string &name, std::chrono::milliseconds timeout, size_t buffer_pool_size, hailo_pipeline_elem_stats_flags_t elem_flags, hailo_vstream_stats_flags_t vstream_flags, EventPtr shutdown_event, - std::shared_ptr> pipeline_status); - HwReadElement(OutputStream &stream, BufferPoolPtr buffer_pool, const std::string &name, std::chrono::milliseconds timeout, - DurationCollector &&duration_collector, EventPtr shutdown_event, std::shared_ptr> &&pipeline_status); + std::shared_ptr> pipeline_status, std::unique_ptr m_transform_context = nullptr); + HwReadElement(std::shared_ptr stream, BufferPoolPtr buffer_pool, const std::string &name, std::chrono::milliseconds timeout, + DurationCollector &&duration_collector, EventPtr shutdown_event, std::shared_ptr> &&pipeline_status, + BufferPoolPtr transform_pool = nullptr, std::unique_ptr transform_context = nullptr); virtual ~HwReadElement() = default; virtual std::vector get_queue_size_accumulators() override; virtual hailo_status run_push(PipelineBuffer &&buffer) override; virtual Expected run_pull(PipelineBuffer &&optional, const PipelinePad &source) override; - virtual hailo_status activate() override; - virtual hailo_status deactivate() override; - virtual hailo_status post_deactivate() override; - virtual hailo_status clear() override; - virtual hailo_status flush() override; - virtual hailo_status abort() override; - virtual void wait_for_finish() override; - virtual hailo_status resume() override; + virtual hailo_status execute_activate() override; + virtual hailo_status execute_deactivate() override; + virtual hailo_status execute_post_deactivate() override; + virtual hailo_status execute_clear() override; + virtual hailo_status execute_flush() override; + virtual hailo_status execute_abort() override; + virtual hailo_status execute_resume() override; + virtual hailo_status execute_wait_for_finish() override; uint32_t get_invalid_frames_count(); virtual std::string description() const override; private: - OutputStream &m_stream; + std::shared_ptr m_stream; BufferPoolPtr m_pool; + BufferPoolPtr m_transform_pool; std::chrono::milliseconds m_timeout; EventPtr m_shutdown_event; WaitOrShutdown m_activation_wait_or_shutdown; + std::unique_ptr m_transform_context; }; class HwWriteElement : public SinkElement { public: - static Expected> create(InputStream &stream, const std::string &name, + static Expected> create(std::shared_ptr stream, const std::string &name, hailo_pipeline_elem_stats_flags_t elem_flags, std::shared_ptr> pipeline_status); - HwWriteElement(InputStream &stream, const std::string &name, DurationCollector &&duration_collector, + HwWriteElement(std::shared_ptr stream, const std::string &name, DurationCollector &&duration_collector, std::shared_ptr> &&pipeline_status, EventPtr got_flush_event); virtual ~HwWriteElement() = default; virtual hailo_status run_push(PipelineBuffer &&buffer) override; virtual Expected run_pull(PipelineBuffer &&optional, const PipelinePad &source) override; - virtual hailo_status activate() override; - virtual hailo_status deactivate() override; - virtual hailo_status post_deactivate() override; - virtual hailo_status clear() override; - virtual hailo_status flush() override; - virtual hailo_status abort() override; - virtual void wait_for_finish() override; - virtual hailo_status resume() override; + virtual hailo_status execute_activate() override; + virtual hailo_status execute_deactivate() override; + virtual hailo_status execute_post_deactivate() override; + virtual hailo_status execute_clear() override; + virtual hailo_status execute_flush() override; + virtual hailo_status execute_abort() override; + virtual hailo_status execute_resume() override; + virtual hailo_status execute_wait_for_finish() override; virtual std::string description() const override; private: - InputStream &m_stream; + std::shared_ptr m_stream; EventPtr m_got_flush_event; }; @@ -444,23 +472,32 @@ protected: class VStreamsBuilderUtils { public: - static Expected> create_inputs(InputStream &input_stream, const hailo_vstream_info_t &input_vstream_infos, + static Expected> create_inputs(std::shared_ptr input_stream, const hailo_vstream_info_t &input_vstream_infos, const hailo_vstream_params_t &vstreams_params); - static Expected> create_outputs(OutputStream &output_stream, + static Expected> create_outputs(std::shared_ptr output_stream, NameToVStreamParamsMap &vstreams_params_map, const std::map &output_vstream_infos); static InputVStream create_input(std::shared_ptr input_vstream); static OutputVStream create_output(std::shared_ptr output_vstream); - static Expected> create_output_nms(OutputStreamRefVector &output_streams, + static Expected> create_output_nms(OutputStreamPtrVector &output_streams, hailo_vstream_params_t vstreams_params, const std::map &output_vstream_infos); - static hailo_status add_demux(OutputStream &output_stream, NameToVStreamParamsMap &vstreams_params_map, + static Expected> create_output_post_process_nms(OutputStreamPtrVector &output_streams, + hailo_vstream_params_t vstreams_params, + const std::map &output_vstream_infos, + const NetFlowYoloNmsElement &nms_op); + static hailo_status add_demux(std::shared_ptr output_stream, NameToVStreamParamsMap &vstreams_params_map, std::vector> &&elements, std::vector &vstreams, std::shared_ptr hw_read_elem, EventPtr shutdown_event, std::shared_ptr> pipeline_status, const std::map &output_vstream_infos); - static hailo_status add_nms_fuse(OutputStreamRefVector &output_streams, hailo_vstream_params_t &vstreams_params, + static hailo_status add_nms_fuse(OutputStreamPtrVector &output_streams, hailo_vstream_params_t &vstreams_params, std::vector> &elements, std::vector &vstreams, EventPtr shutdown_event, std::shared_ptr> pipeline_status, const std::map &output_vstream_infos); + static hailo_status add_nms_post_process(OutputStreamPtrVector &output_streams, hailo_vstream_params_t &vstreams_params, + std::vector> &elements, std::vector &vstreams, + EventPtr shutdown_event, std::shared_ptr> pipeline_status, + const std::map &output_vstream_infos, + const NetFlowYoloNmsElement &nms_op); static Expected create_pipeline_latency_accumulator(const hailo_vstream_params_t &vstreams_params); }; diff --git a/hailort/pre_build/external/CMakeLists.txt b/hailort/pre_build/external/CMakeLists.txt index 373775c..8c76412 100644 --- a/hailort/pre_build/external/CMakeLists.txt +++ b/hailort/pre_build/external/CMakeLists.txt @@ -16,7 +16,7 @@ function(git_clone proj repo tag) ) endfunction() -git_clone(pybind11 https://github.com/pybind/pybind11.git 8de7772cc72daca8e947b79b83fea46214931604) +git_clone(pybind11 https://github.com/pybind/pybind11.git 80dc998efced8ceb2be59756668a7e90e8bef917) git_clone(Catch2 https://github.com/catchorg/Catch2.git c4e3767e265808590986d5db6ca1b5532a7f3d13) git_clone(CLI11 https://github.com/hailo-ai/CLI11.git 635773b0a1d76a1744c122b98eda6702c909edb2) git_clone(spdlog https://github.com/gabime/spdlog.git e2789531912a5c6ab28a90387f97c52963eec08a) @@ -26,8 +26,7 @@ git_clone(json https://github.com/ArthurSonzogni/nlohmann_json_cmak git_clone(DotWriter https://github.com/hailo-ai/DotWriter.git e5fa8f281adca10dd342b1d32e981499b8681daf) git_clone(benchmark https://github.com/google/benchmark.git f91b6b42b1b9854772a90ae9501464a161707d1e) git_clone(pevents https://github.com/neosmart/pevents.git 1209b1fd1bd2e75daab4380cf43d280b90b45366) -git_clone(microprofile https://github.com/jonasmr/microprofile 03c34f96840defe0f4c196309628815d02b98059) if(HAILO_BUILD_SERVICE) git_clone(grpc https://github.com/grpc/grpc 53d69cc581c5b7305708587f4f1939278477c28a) -endif() \ No newline at end of file +endif() diff --git a/hailort/prepare_externals.cmake b/hailort/prepare_externals.cmake new file mode 100644 index 0000000..399cde2 --- /dev/null +++ b/hailort/prepare_externals.cmake @@ -0,0 +1,22 @@ +cmake_minimum_required(VERSION 3.0.0) + +message(STATUS "Building pre_build") + +include(${CMAKE_CURRENT_LIST_DIR}/cmake/execute_cmake.cmake) +set(HAILO_EXTERNAL_DIR ${CMAKE_CURRENT_LIST_DIR}/external) +set(HAILO_PRE_BUILD_BUILD_TOOLS ${CMAKE_CURRENT_LIST_DIR}/pre_build/build/tools) +set(PRE_BUILD_BUILD_TYPE "Release") + +execute_cmake( + SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/pre_build + BUILD_DIR ${CMAKE_CURRENT_LIST_DIR}/pre_build/build + CONFIGURE_ARGS + -DCMAKE_BUILD_TYPE=${PRE_BUILD_BUILD_TYPE} + -DCMAKE_INSTALL_PREFIX=${CMAKE_CURRENT_LIST_DIR}/pre_build/install + -DHAILO_EXTERNAL_DIR=${HAILO_EXTERNAL_DIR} + -DHAILO_OFFLINE_COMPILATION=${HAILO_OFFLINE_COMPILATION} + -DHAILO_BUILD_SERVICE=${HAILO_BUILD_SERVICE} + BUILD_ARGS + --config ${PRE_BUILD_BUILD_TYPE} --target install ${CMAKE_EXTRA_BUILD_ARGS} + PARALLEL_BUILD +) diff --git a/hailort/rpc/hailort_rpc.proto b/hailort/rpc/hailort_rpc.proto index 7873cb4..ac76f2b 100644 --- a/hailort/rpc/hailort_rpc.proto +++ b/hailort/rpc/hailort_rpc.proto @@ -2,18 +2,20 @@ syntax = "proto3"; option optimize_for = LITE_RUNTIME; -service HailoRtRpc { +service ProtoHailoRtRpc { rpc client_keep_alive (keepalive_Request) returns (empty) {} rpc get_service_version (get_service_version_Request) returns (get_service_version_Reply) {} rpc VDevice_create (VDevice_create_Request) returns (VDevice_create_Reply) {} rpc VDevice_release (Release_Request) returns (Release_Reply) {} rpc VDevice_configure (VDevice_configure_Request) returns (VDevice_configure_Reply) {} rpc VDevice_get_physical_devices_ids (VDevice_get_physical_devices_ids_Request) returns (VDevice_get_physical_devices_ids_Reply) {} + rpc VDevice_get_default_streams_interface (VDevice_get_default_streams_interface_Request) returns (VDevice_get_default_streams_interface_Reply) {} rpc ConfiguredNetworkGroup_release (Release_Request) returns (Release_Reply) {} rpc ConfiguredNetworkGroup_make_input_vstream_params (ConfiguredNetworkGroup_make_input_vstream_params_Request) returns (ConfiguredNetworkGroup_make_input_vstream_params_Reply) {} rpc ConfiguredNetworkGroup_make_output_vstream_params (ConfiguredNetworkGroup_make_output_vstream_params_Request) returns (ConfiguredNetworkGroup_make_output_vstream_params_Reply) {} - rpc ConfiguredNetworkGroup_get_name (ConfiguredNetworkGroup_get_name_Request) returns (ConfiguredNetworkGroup_get_name_Reply) {} + rpc ConfiguredNetworkGroup_make_output_vstream_params_groups (ConfiguredNetworkGroup_make_output_vstream_params_groups_Request) returns (ConfiguredNetworkGroup_make_output_vstream_params_groups_Reply) {} + rpc ConfiguredNetworkGroup_name (ConfiguredNetworkGroup_name_Request) returns (ConfiguredNetworkGroup_name_Reply) {} rpc ConfiguredNetworkGroup_get_network_infos (ConfiguredNetworkGroup_get_network_infos_Request) returns (ConfiguredNetworkGroup_get_network_infos_Reply) {} rpc ConfiguredNetworkGroup_get_all_stream_infos (ConfiguredNetworkGroup_get_all_stream_infos_Request) returns (ConfiguredNetworkGroup_get_all_stream_infos_Reply) {} rpc ConfiguredNetworkGroup_get_default_stream_interface (ConfiguredNetworkGroup_get_default_stream_interface_Request) returns (ConfiguredNetworkGroup_get_default_stream_interface_Reply) {} @@ -24,6 +26,8 @@ service HailoRtRpc { rpc ConfiguredNetworkGroup_set_scheduler_timeout (ConfiguredNetworkGroup_set_scheduler_timeout_Request) returns (ConfiguredNetworkGroup_set_scheduler_timeout_Reply) {} rpc ConfiguredNetworkGroup_set_scheduler_threshold (ConfiguredNetworkGroup_set_scheduler_threshold_Request) returns (ConfiguredNetworkGroup_set_scheduler_threshold_Reply) {} rpc ConfiguredNetworkGroup_get_latency_measurement (ConfiguredNetworkGroup_get_latency_measurement_Request) returns (ConfiguredNetworkGroup_get_latency_measurement_Reply) {} + rpc ConfiguredNetworkGroup_is_multi_context (ConfiguredNetworkGroup_is_multi_context_Request) returns (ConfiguredNetworkGroup_is_multi_context_Reply) {} + rpc ConfiguredNetworkGroup_get_config_params(ConfiguredNetworkGroup_get_config_params_Request) returns (ConfiguredNetworkGroup_get_config_params_Reply) {} rpc InputVStreams_create (VStream_create_Request) returns (VStreams_create_Reply) {} rpc InputVStream_release (Release_Request) returns (Release_Reply) {} @@ -36,10 +40,16 @@ service HailoRtRpc { rpc InputVStream_flush (InputVStream_flush_Request) returns (InputVStream_flush_Reply) {} rpc InputVStream_name (VStream_name_Request) returns (VStream_name_Reply) {} rpc OutputVStream_name (VStream_name_Request) returns (VStream_name_Reply) {} + rpc InputVStream_network_name (VStream_network_name_Request) returns (VStream_network_name_Reply) {} + rpc OutputVStream_network_name (VStream_network_name_Request) returns (VStream_network_name_Reply) {} rpc InputVStream_abort (VStream_abort_Request) returns (VStream_abort_Reply) {} rpc OutputVStream_abort (VStream_abort_Request) returns (VStream_abort_Reply) {} rpc InputVStream_resume (VStream_resume_Request) returns (VStream_resume_Reply) {} rpc OutputVStream_resume (VStream_resume_Request) returns (VStream_resume_Reply) {} + rpc InputVStream_get_user_buffer_format (VStream_get_user_buffer_format_Request) returns (VStream_get_user_buffer_format_Reply) {} + rpc OutputVStream_get_user_buffer_format (VStream_get_user_buffer_format_Request) returns (VStream_get_user_buffer_format_Reply) {} + rpc InputVStream_get_info (VStream_get_info_Request) returns (VStream_get_info_Reply) {} + rpc OutputVStream_get_info (VStream_get_info_Request) returns (VStream_get_info_Reply) {} } message empty {} @@ -48,14 +58,14 @@ message keepalive_Request { uint32 process_id = 1; } -message HailoVDeviceParams { +message ProtoVDeviceParams { uint32 device_count = 1; repeated string device_ids = 2; uint32 scheduling_algorithm = 3; string group_id = 4; } -message HailoVersion { +message ProtoHailoVersion { uint32 major_version = 1; uint32 minor_version = 2; uint32 revision_version = 3; @@ -66,11 +76,11 @@ message get_service_version_Request { message get_service_version_Reply { uint32 status = 1; - HailoVersion hailo_version = 2; + ProtoHailoVersion hailo_version = 2; } message VDevice_create_Request { - HailoVDeviceParams hailo_vdevice_params = 1; + ProtoVDeviceParams hailo_vdevice_params = 1; uint32 pid = 2; } @@ -94,129 +104,129 @@ message VStreams_create_Reply { message VStream_create_Request { uint32 net_group = 1; - repeated NamedVStreamParams vstreams_params = 2; + repeated ProtoNamedVStreamParams vstreams_params = 2; uint32 pid = 3; } -message HailoFormat { +message ProtoHailoFormat { uint32 type = 1; uint32 order = 2; uint32 flags = 3; } -message VStreamParams { - HailoFormat user_buffer_format = 1; +message ProtoVStreamParams { + ProtoHailoFormat user_buffer_format = 1; uint32 timeout_ms = 2; uint32 queue_size = 3; uint32 vstream_stats_flags = 4; uint32 pipeline_elements_stats_flags = 5; } -message NamedVStreamParams { +message ProtoNamedVStreamParams { string name = 1; - VStreamParams params = 2; + ProtoVStreamParams params = 2; } -message ThreeDImageShape { +message ProtoThreeDImageShape { uint32 height = 1; uint32 width = 2; uint32 features = 3; } -message StreamShape { - ThreeDImageShape shape = 1; - ThreeDImageShape hw_shape = 2; +message ProtoStreamShape { + ProtoThreeDImageShape shape = 1; + ProtoThreeDImageShape hw_shape = 2; } -message NmsDefuseInfo { +message ProtoNmsDefuseInfo { uint32 class_group_index = 1; string original_name = 2; } -message NmsInfo { +message ProtoNmsInfo { uint32 number_of_classes = 1; uint32 max_bboxes_per_class = 2; uint32 bbox_size = 3; uint32 chunks_per_frame = 4; bool is_defused = 5; - NmsDefuseInfo defuse_info = 6; + ProtoNmsDefuseInfo defuse_info = 6; } -message QuantInfo { +message ProtoQuantInfo { float qp_zp = 1; float qp_scale = 2; float limvals_min = 3; float limvals_max = 4; } -message StreamInfo { - StreamShape stream_shape = 1; - NmsInfo nms_info = 2; +message ProtoStreamInfo { + ProtoStreamShape stream_shape = 1; + ProtoNmsInfo nms_info = 2; uint32 hw_data_bytes = 3; uint32 hw_frame_size = 4; - HailoFormat format = 5; + ProtoHailoFormat format = 5; uint32 direction = 6; uint32 index = 7; string name = 8; - QuantInfo quant_info = 9; + ProtoQuantInfo quant_info = 9; bool is_mux = 10; } -message StreamsParams { +message ProtoStreamsParams { uint32 stream_interface = 1; uint32 direction = 2; } -message NamedStreamParams { +message ProtoNamedStreamParams { string name = 1; - StreamsParams params = 2; + ProtoStreamsParams params = 2; } -message NetworkParams { +message ProtoNetworkParams { uint32 batch_size = 1; } -message NamedNetworkParams { +message ProtoNamedNetworkParams { string name = 1; - NetworkParams params = 2; + ProtoNetworkParams params = 2; } -message NmsShape { +message ProtoNmsShape { uint32 number_of_classes = 1; uint32 max_bbox_per_class = 2; } -message VStreamInfo { +message ProtoVStreamInfo { string name = 1; string network_name = 2; uint32 direction = 3; - HailoFormat format = 4; - ThreeDImageShape shape = 5; - NmsShape nms_shape = 6; - QuantInfo quant_info = 7; + ProtoHailoFormat format = 4; + ProtoThreeDImageShape shape = 5; + ProtoNmsShape nms_shape = 6; + ProtoQuantInfo quant_info = 7; } -message HailoConfigureNetworkParams { +message ProtoConfigureNetworkParams { uint32 batch_size = 1; uint32 power_mode = 2; uint32 latency = 3; - repeated NamedStreamParams stream_params_map = 4; - repeated NamedNetworkParams network_params_map = 5; + repeated ProtoNamedStreamParams stream_params_map = 4; + repeated ProtoNamedNetworkParams network_params_map = 5; } -message NamedConfigureNetworkParams { +message ProtoNamedConfigureNetworkParams { string name = 1; - HailoConfigureNetworkParams params = 2; + ProtoConfigureNetworkParams params = 2; } -message VStreamGroup { +message ProtoVStreamGroup { repeated string vstream_group = 1; } message VDevice_configure_Request { uint32 handle = 1; bytes hef = 2; - repeated NamedConfigureNetworkParams configure_params_map = 3; + repeated ProtoNamedConfigureNetworkParams configure_params_map = 3; uint32 pid = 4; } @@ -234,6 +244,15 @@ message VDevice_get_physical_devices_ids_Reply { repeated string devices_ids = 2; } +message VDevice_get_default_streams_interface_Request { + uint32 handle = 1; +} + +message VDevice_get_default_streams_interface_Reply { + uint32 status = 1; + uint32 stream_interface = 2; +} + message ConfiguredNetworkGroup_make_input_vstream_params_Request { uint32 handle = 1; bool quantized = 2; @@ -243,10 +262,14 @@ message ConfiguredNetworkGroup_make_input_vstream_params_Request { string network_name = 6; } +message ProtoNamedVStreamParamsMap { + repeated ProtoNamedVStreamParams vstream_params_map = 1; +} + message ConfiguredNetworkGroup_make_input_vstream_params_Reply { uint32 status = 1; - repeated NamedVStreamParams vstream_params_map = 2; -} + ProtoNamedVStreamParamsMap vstream_params_map = 2; +} message ConfiguredNetworkGroup_make_output_vstream_params_Request { uint32 handle = 1; @@ -259,14 +282,27 @@ message ConfiguredNetworkGroup_make_output_vstream_params_Request { message ConfiguredNetworkGroup_make_output_vstream_params_Reply { uint32 status = 1; - repeated NamedVStreamParams vstream_params_map = 2; + ProtoNamedVStreamParamsMap vstream_params_map = 2; +} + +message ConfiguredNetworkGroup_make_output_vstream_params_groups_Request { + uint32 handle = 1; + bool quantized = 2; + uint32 format_type = 3; + uint32 timeout_ms = 4; + uint32 queue_size = 5; +} + +message ConfiguredNetworkGroup_make_output_vstream_params_groups_Reply { + uint32 status = 1; + repeated ProtoNamedVStreamParamsMap vstream_params_groups = 2; } -message ConfiguredNetworkGroup_get_name_Request { +message ConfiguredNetworkGroup_name_Request { uint32 handle = 1; } -message ConfiguredNetworkGroup_get_name_Reply { +message ConfiguredNetworkGroup_name_Reply { uint32 status = 1; string network_group_name = 2; } @@ -287,7 +323,7 @@ message ConfiguredNetworkGroup_get_all_stream_infos_Request { message ConfiguredNetworkGroup_get_all_stream_infos_Reply { uint32 status = 1; - repeated StreamInfo stream_infos = 2; + repeated ProtoStreamInfo stream_infos = 2; } message ConfiguredNetworkGroup_get_default_stream_interface_Request { @@ -305,7 +341,7 @@ message ConfiguredNetworkGroup_get_output_vstream_groups_Request { message ConfiguredNetworkGroup_get_output_vstream_groups_Reply { uint32 status = 1; - repeated VStreamGroup output_vstream_groups = 2; + repeated ProtoVStreamGroup output_vstream_groups = 2; } message ConfiguredNetworkGroup_get_vstream_infos_Request { @@ -320,7 +356,7 @@ message ConfiguredNetworkGroup_get_latency_measurement_Request { message ConfiguredNetworkGroup_get_vstream_infos_Reply { uint32 status = 1; - repeated VStreamInfo vstream_infos = 2; + repeated ProtoVStreamInfo vstream_infos = 2; } message ConfiguredNetworkGroup_set_scheduler_timeout_Request { @@ -348,6 +384,24 @@ message ConfiguredNetworkGroup_get_latency_measurement_Reply { uint32 avg_hw_latency = 2; } +message ConfiguredNetworkGroup_is_multi_context_Request { + uint32 handle = 1; +} + +message ConfiguredNetworkGroup_is_multi_context_Reply { + uint32 status = 1; + bool is_multi_context = 2; +} + +message ConfiguredNetworkGroup_get_config_params_Request { + uint32 handle = 1; +} + +message ConfiguredNetworkGroup_get_config_params_Reply { + uint32 status = 1; + ProtoConfigureNetworkParams params = 2; +} + message InputVStream_write_Request { uint32 handle = 1; bytes data = 2; @@ -393,6 +447,15 @@ message VStream_name_Reply { string name = 2; } +message VStream_network_name_Request { + uint32 handle = 1; +} + +message VStream_network_name_Reply { + uint32 status = 1; + string network_name = 2; +} + message VStream_abort_Request { uint32 handle = 1; } @@ -407,4 +470,22 @@ message VStream_resume_Request { message VStream_resume_Reply { uint32 status = 1; +} + +message VStream_get_user_buffer_format_Request { + uint32 handle = 1; +} + +message VStream_get_user_buffer_format_Reply { + uint32 status = 1; + ProtoHailoFormat user_buffer_format = 2; +} + +message VStream_get_info_Request { + uint32 handle = 1; +} + +message VStream_get_info_Reply { + uint32 status = 1; + ProtoVStreamInfo vstream_info = 2; } \ No newline at end of file diff --git a/hailort/scripts/download_firmware_eth.cmd b/hailort/scripts/download_firmware_eth.cmd new file mode 100644 index 0000000..dec6da5 --- /dev/null +++ b/hailort/scripts/download_firmware_eth.cmd @@ -0,0 +1,12 @@ +:: cmd +@ECHO OFF + +set BASE_URI=https://hailo-hailort.s3.eu-west-2.amazonaws.com +set HRT_VERSION=4.12.0 +set FW_DIR=Hailo8/%HRT_VERSION%/FW +set FW=hailo8_fw.%HRT_VERSION%_eth.bin + +:: download firmware from AWS +ECHO Downloading Hailo Firmware from S3 +powershell -c "wget %BASE_URI%/%FW_DIR%/%FW% -outfile %FW%" + diff --git a/hailort/scripts/download_firmware_eth.sh b/hailort/scripts/download_firmware_eth.sh new file mode 100755 index 0000000..c2c36c9 --- /dev/null +++ b/hailort/scripts/download_firmware_eth.sh @@ -0,0 +1,17 @@ +#!/bin/bash +set -e + +readonly BASE_URI="https://hailo-hailort.s3.eu-west-2.amazonaws.com" +readonly HRT_VERSION=4.12.0 +readonly FW_AWS_DIR="Hailo8/${HRT_VERSION}/FW" +readonly FW="hailo8_fw.${HRT_VERSION}_eth.bin" + +function download_fw(){ + wget -N ${BASE_URI}/${FW_AWS_DIR}/${FW} +} + +function main(){ + download_fw +} + +main diff --git a/hailort/scripts/download_hefs.cmd b/hailort/scripts/download_hefs.cmd index 2be01f1..b949cc7 100644 --- a/hailort/scripts/download_hefs.cmd +++ b/hailort/scripts/download_hefs.cmd @@ -1,7 +1,7 @@ :: cmd @ECHO OFF set BASE_URI=https://hailo-hailort.s3.eu-west-2.amazonaws.com -set HRT_VERSION=4.10.0 +set HRT_VERSION=4.12.0 set REMOTE_HEF_DIR=Hailo8/%HRT_VERSION%/HEFS set LOCAL_EXAMPLES_HEF_DIR=..\libhailort\examples\hefs set LOCAL_TUTORIALS_HEF_DIR=..\libhailort\bindings\python\platform\tutorials\hefs diff --git a/hailort/scripts/download_hefs.sh b/hailort/scripts/download_hefs.sh index 6295d04..80a6ef8 100755 --- a/hailort/scripts/download_hefs.sh +++ b/hailort/scripts/download_hefs.sh @@ -2,7 +2,7 @@ set -e readonly BASE_URI="https://hailo-hailort.s3.eu-west-2.amazonaws.com" -readonly HRT_VERSION=4.10.0 +readonly HRT_VERSION=4.12.0 readonly REMOTE_HEF_DIR="Hailo8/${HRT_VERSION}/HEFS" readonly LOCAL_EXAMPLES_HEF_DIR="../libhailort/examples/hefs" readonly LOCAL_TUTORIALS_HEF_DIR="../libhailort/bindings/python/platform/tutorials/hefs/" diff --git a/hailort/tools/hw_debug/CMakeLists.txt b/hailort/tools/hw_debug/CMakeLists.txt new file mode 100644 index 0000000..15217cc --- /dev/null +++ b/hailort/tools/hw_debug/CMakeLists.txt @@ -0,0 +1,53 @@ +cmake_minimum_required(VERSION 3.0.0) + +set(FILES + main.cpp + shell.cpp + readline_wrapper.cpp + driver_memory.cpp + memory_commands.cpp + mercury_fields.cpp + + # Depends on hailort_driver and its dependencies + ${HAILO_OS_DIR}/hailort_driver.cpp + ${HAILO_OS_DIR}/file_descriptor.cpp + ${HAILO_FULL_OS_DIR}/driver_scan.cpp + # TODO: HRT-3816 remove mmap header + ${HAILO_OS_DIR}/mmap_buffer.cpp +) + +if(WIN32) + # hailort_driver.cpp in windows depends on string_conversion + set(FILES ${FILES} + ${HAILORT_COMMON_OS_DIR}/string_conversion.cpp) +endif() + +add_executable(debalex ${FILES}) +target_compile_options(debalex PRIVATE ${HAILORT_COMPILE_OPTIONS}) +set_property(TARGET debalex PROPERTY CXX_STANDARD 14) +target_link_libraries(debalex PRIVATE + libhailort + spdlog::spdlog + CLI11::CLI11 + ) +target_include_directories(debalex + PRIVATE + ${HAILORT_COMMON_DIR} + ${HAILORT_SRC_DIR} + ${DRIVER_INC_DIR} +) + +if(CMAKE_SYSTEM_NAME STREQUAL QNX) + target_link_libraries(debalex PRIVATE pci) +endif() + +find_path(READLINE_INCLUDE_DIR NAMES readline/readline.h) +find_library(READLINE_LIBRARY NAMES readline) + +if(READLINE_INCLUDE_DIR AND READLINE_LIBRARY) + target_link_libraries(debalex PRIVATE ${READLINE_LIBRARY}) + target_include_directories(debalex PRIVATE ${READLINE_INCLUDE_DIR}) + add_definitions(-DUSE_READLINE) +else() + message(WARNING "Could not find readline library. To better UI, please install it by calling `sudo apt install libreadline6-dev`") +endif() diff --git a/hailort/tools/hw_debug/driver_memory.cpp b/hailort/tools/hw_debug/driver_memory.cpp new file mode 100644 index 0000000..7a1270e --- /dev/null +++ b/hailort/tools/hw_debug/driver_memory.cpp @@ -0,0 +1,127 @@ +/** + * @file driver_memory.cpp + * @brief Implements MemorySource over HailoRT driver, reads/write all interfaces. + */ + +#include "driver_memory.hpp" +#include "mercury_fields.hpp" + +DriverMemorySource::DriverMemorySource(std::shared_ptr driver, HailoRTDriver::MemoryType memory_type) : + m_driver(driver), + m_memory_type(memory_type) +{} + +hailo_status DriverMemorySource::read(uint64_t offset, uint8_t *data, size_t size) +{ + return m_driver->read_memory(m_memory_type, offset, data, size); +} + +hailo_status DriverMemorySource::write(uint64_t offset, const uint8_t *data, size_t size) +{ + return m_driver->write_memory(m_memory_type, offset, data, size); +} + +size_t DriverMemorySource::total_size() const +{ + // TODO HRT-7984: return the actual size + return std::numeric_limits::max(); +} + + +static constexpr size_t VDMA_CHANNELS_COUNT = 32; + +#pragma pack(push, 1) +struct VdmaDataPerDirection { + // Control + uint64_t start_abort : 1; + uint64_t pause_resume : 1; + uint64_t abort_on_err : 1; + uint64_t reserved0 : 2; + uint64_t irq_on_err : 1; + uint64_t irq_on_host : 1; + uint64_t irq_on_device : 1; + + // Depth id + uint64_t id : 3; + uint64_t depth : 4; + uint64_t reserved1 : 1; + + uint64_t num_available : 16; + uint64_t num_processed : 16; + uint64_t num_ongoing : 16; + + uint64_t error : 8; + uint64_t reserved2 : 8; + uint64_t desc_address : 48; +}; +static_assert(0x10 == sizeof(VdmaDataPerDirection), "Invalid VdmaDataPerDirection size"); + +struct VdmaChannelData { + VdmaDataPerDirection h2d; + VdmaDataPerDirection d2h; +}; +#pragma pack(pop) + +class VdmaChannelField : public Field { +public: + VdmaChannelField() : + Field("channel", "vDMA channel register") + {} + + virtual size_t elements_count() const + { + return VDMA_CHANNELS_COUNT; + }; + + virtual std::string print_element(MemorySource& memory, size_t index) const + { + assert(index < elements_count()); + VdmaChannelData data{}; + auto status = memory.read(index * sizeof(data), reinterpret_cast(&data), sizeof(data)); + if (HAILO_SUCCESS != status) { + throw std::runtime_error(fmt::format("Failed reading memory, status {}", status)); + } + + return fmt::format("channel[{}] (offset=0x{:X} size=0x{:X}):\n", index, index * sizeof(data), sizeof(data)) + + fmt::format(" host: {}\n", print_direction(data.h2d)) + + fmt::format(" device: {}\n", print_direction(data.d2h)); + } + +private: + static std::string print_direction(const VdmaDataPerDirection &data) + { + return fmt::format( + "control=({} | {}) id={} depth={:02} num_avail=0x{:04X} num_proc=0x{:04X} num_ongoing=0x{:04X} err=0x{:02X} desc_address=0x{:016X}", + data.start_abort ? "START" : "ABORT", + data.pause_resume ? "PAUSE" : "RESUME", + data.id, + data.depth, + data.num_available, + data.num_processed, + data.num_ongoing, + data.error, + data.desc_address << DESC_ADDRESS_SHIFT); + } + + static constexpr size_t DESC_ADDRESS_SHIFT = 16; +}; + +VdmaMemorySource::VdmaMemorySource(std::shared_ptr driver, MemoryType memory_type) : + DriverMemorySource(std::move(driver), memory_type) +{ + add_field(std::make_shared()); +} + +size_t VdmaMemorySource::total_size() const +{ + return VDMA_CHANNELS_COUNT * sizeof(VdmaChannelData); +} + +DramDmaEngineMemorySource::DramDmaEngineMemorySource(std::shared_ptr driver, MemoryType memory_type) : + DriverMemorySource(std::move(driver), memory_type) +{ + add_field(std::make_shared()); + add_field(std::make_shared()); + add_field(std::make_shared()); + add_field(std::make_shared()); +} \ No newline at end of file diff --git a/hailort/tools/hw_debug/driver_memory.hpp b/hailort/tools/hw_debug/driver_memory.hpp new file mode 100644 index 0000000..60e6a65 --- /dev/null +++ b/hailort/tools/hw_debug/driver_memory.hpp @@ -0,0 +1,39 @@ +/** + * @file driver_memory.hpp + * @brief Implements MemorySource over HailoRT driver, reads/write all interfaces. + */ + +#ifndef _HW_DEBUG_DRIVER_MEMORY_HPP_ +#define _HW_DEBUG_DRIVER_MEMORY_HPP_ + +#include "memory_commands.hpp" +#include "os/hailort_driver.hpp" + +using hailort::HailoRTDriver; +using MemoryType = HailoRTDriver::MemoryType; + +class DriverMemorySource : public MemorySource { +public: + DriverMemorySource(std::shared_ptr driver, MemoryType memory_type); + + hailo_status read(uint64_t offset, uint8_t *data, size_t size) override; + hailo_status write(uint64_t offset, const uint8_t *data, size_t size) override; + size_t total_size() const override; + +private: + std::shared_ptr m_driver; + MemoryType m_memory_type; +}; + +class VdmaMemorySource : public DriverMemorySource { +public: + VdmaMemorySource(std::shared_ptr driver, MemoryType memory_type); + size_t total_size() const override; +}; + +class DramDmaEngineMemorySource : public DriverMemorySource { +public: + DramDmaEngineMemorySource(std::shared_ptr driver, MemoryType memory_type); +}; + +#endif /* _HW_DEBUG_DRIVER_MEMORY_HPP_ */ diff --git a/hailort/tools/hw_debug/hw_consts/mercury/dram_dma_engine_config_macros.h b/hailort/tools/hw_debug/hw_consts/mercury/dram_dma_engine_config_macros.h new file mode 100644 index 0000000..889f3cc --- /dev/null +++ b/hailort/tools/hw_debug/hw_consts/mercury/dram_dma_engine_config_macros.h @@ -0,0 +1,2270 @@ +/*------------------------------------------------------------------------------------- +// Copyright (c) 2022 by Hailotech This model is the confidential and +// proprietary property of Hailotech and the possession or use of this +// file requires a written license from Hailotech. +-------------------------------------------------------------------------------------*/ + + + +#include + +#ifndef DRAM_DMA_ENGINE_CONFIG_MACRO_H +#define DRAM_DMA_ENGINE_CONFIG_MACRO_H + + +/*----------------------------------------------------------------------------------------------------*/ +/* QDDCENABLE : val */ +/* Description: Enable per channel,when disabled do not give credits to vDMA */ +#define DRAM_DMA_ENGINE_CONFIG__QDDCENABLE__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QDDCENABLE__VAL__WIDTH (1) +#define DRAM_DMA_ENGINE_CONFIG__QDDCENABLE__VAL__MASK (0x00000001L) +#define DRAM_DMA_ENGINE_CONFIG__QDDCENABLE__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QDDCENABLE__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x00000001L) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QDDCENABLE__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | (((uint32_t)(value) << 0) & 0x00000001L)) +#define DRAM_DMA_ENGINE_CONFIG__QDDCENABLE__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | ((uint32_t)(1) << 0)) +#define DRAM_DMA_ENGINE_CONFIG__QDDCENABLE__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | ((uint32_t)(0) << 0)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QDDCRESET : val */ +/* Description: Soft reset per channel,when write 1'b1 should clear all internal credits/counter/status. Should be set when channel is disabled,usually with vDMA channel reset (abort). Write 1'b0 should do nothing. Read always return 1'b0. Implemented as external register type. */ +#define DRAM_DMA_ENGINE_CONFIG__QDDCRESET__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QDDCRESET__VAL__WIDTH (1) +#define DRAM_DMA_ENGINE_CONFIG__QDDCRESET__VAL__MASK (0x00000001L) +#define DRAM_DMA_ENGINE_CONFIG__QDDCRESET__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QDDCRESET__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x00000001L) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QDDCRESET__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | (((uint32_t)(value) << 0) & 0x00000001L)) +#define DRAM_DMA_ENGINE_CONFIG__QDDCRESET__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | ((uint32_t)(1) << 0)) +#define DRAM_DMA_ENGINE_CONFIG__QDDCRESET__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | ((uint32_t)(0) << 0)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QDDCMODE : val */ +/* Description: 0 - CONT_MODE. 1 - BURST_MODE */ +#define DRAM_DMA_ENGINE_CONFIG__QDDCMODE__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QDDCMODE__VAL__WIDTH (1) +#define DRAM_DMA_ENGINE_CONFIG__QDDCMODE__VAL__MASK (0x00000001L) +#define DRAM_DMA_ENGINE_CONFIG__QDDCMODE__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QDDCMODE__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x00000001L) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QDDCMODE__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | (((uint32_t)(value) << 0) & 0x00000001L)) +#define DRAM_DMA_ENGINE_CONFIG__QDDCMODE__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | ((uint32_t)(1) << 0)) +#define DRAM_DMA_ENGINE_CONFIG__QDDCMODE__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | ((uint32_t)(0) << 0)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QDDCADDBURSTVAL : val */ +/* Description: Writing to this register increment the remain burst counter in QDDC by QddcAddBurstVal x 8 Bytes: RemainBurstCount += QddcAddBurstVal. Reading this register should return the current available credit counter (RemainBurstCount) in 2s complement format - can be negative. Implemented as external register type. */ +#define DRAM_DMA_ENGINE_CONFIG__QDDCADDBURSTVAL__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QDDCADDBURSTVAL__VAL__WIDTH (27) +#define DRAM_DMA_ENGINE_CONFIG__QDDCADDBURSTVAL__VAL__MASK (0x07FFFFFFL) +#define DRAM_DMA_ENGINE_CONFIG__QDDCADDBURSTVAL__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QDDCADDBURSTVAL__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x07FFFFFFL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QDDCADDBURSTVAL__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x07FFFFFFL) | (((uint32_t)(value) << 0) & 0x07FFFFFFL)) +#define DRAM_DMA_ENGINE_CONFIG__QDDCADDBURSTVAL__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x07FFFFFFL) | 0x07FFFFFFL) +#define DRAM_DMA_ENGINE_CONFIG__QDDCADDBURSTVAL__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x07FFFFFFL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QDDCMAXDESC : val */ +/* Description: Maximum in flight descriptors,this is a TH for number of descriptors the QM might give the vDMA. 3'd0 - 1 descriptor (debug mode). 3'd1 - N_QM_DESC*1/8 (2). 3'd2 - N_QM_DESC*2/8 (4). 3'd3 - N_QM_DESC*3/8 (6). 3'd4 - N_QM_DESC*2/4 (8). 3'd5 - N_QM_DESC*5/8 (10). 3'd6 - N_QM_DESC*6/8 (12). 3'd7 - N_QM_DESC-1 (15-maximum),default. */ +#define DRAM_DMA_ENGINE_CONFIG__QDDCMAXDESC__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QDDCMAXDESC__VAL__WIDTH (3) +#define DRAM_DMA_ENGINE_CONFIG__QDDCMAXDESC__VAL__MASK (0x00000007L) +#define DRAM_DMA_ENGINE_CONFIG__QDDCMAXDESC__VAL__RESET (0x00000007L) +#define DRAM_DMA_ENGINE_CONFIG__QDDCMAXDESC__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x00000007L) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QDDCMAXDESC__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x00000007L) | (((uint32_t)(value) << 0) & 0x00000007L)) +#define DRAM_DMA_ENGINE_CONFIG__QDDCMAXDESC__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000007L) | 0x00000007L) +#define DRAM_DMA_ENGINE_CONFIG__QDDCMAXDESC__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000007L)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QDDCSHMIFOID : val */ +/* Description: The RX-SHMIFO ID. Used to know the SHMIFO base address (from a global parameter/define) and used to select the correct SHMIFO credit signal (nn_core_inbound_buffer_ready_pulse). 0-19: for DSM-RX 0-19. 20-23: for CSM 0-3. 24-30: reserved. 31: NULL ignore any credit from NN Core. */ +#define DRAM_DMA_ENGINE_CONFIG__QDDCSHMIFOID__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QDDCSHMIFOID__VAL__WIDTH (5) +#define DRAM_DMA_ENGINE_CONFIG__QDDCSHMIFOID__VAL__MASK (0x0000001FL) +#define DRAM_DMA_ENGINE_CONFIG__QDDCSHMIFOID__VAL__RESET (0x0000001FL) +#define DRAM_DMA_ENGINE_CONFIG__QDDCSHMIFOID__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x0000001FL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QDDCSHMIFOID__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x0000001FL) | (((uint32_t)(value) << 0) & 0x0000001FL)) +#define DRAM_DMA_ENGINE_CONFIG__QDDCSHMIFOID__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x0000001FL) | 0x0000001FL) +#define DRAM_DMA_ENGINE_CONFIG__QDDCSHMIFOID__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x0000001FL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QDDCSHMIFOCREDITSIZE : val */ +/* Description: The credit size in 8B granularity minus 1. 0 - indicates 8B 1 - indicates 16B ... 10'd1023 - indicates 8kB */ +#define DRAM_DMA_ENGINE_CONFIG__QDDCSHMIFOCREDITSIZE__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QDDCSHMIFOCREDITSIZE__VAL__WIDTH (10) +#define DRAM_DMA_ENGINE_CONFIG__QDDCSHMIFOCREDITSIZE__VAL__MASK (0x000003FFL) +#define DRAM_DMA_ENGINE_CONFIG__QDDCSHMIFOCREDITSIZE__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QDDCSHMIFOCREDITSIZE__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x000003FFL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QDDCSHMIFOCREDITSIZE__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x000003FFL) | (((uint32_t)(value) << 0) & 0x000003FFL)) +#define DRAM_DMA_ENGINE_CONFIG__QDDCSHMIFOCREDITSIZE__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x000003FFL) | 0x000003FFL) +#define DRAM_DMA_ENGINE_CONFIG__QDDCSHMIFOCREDITSIZE__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x000003FFL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QDDCSHMIFOINITCREDIT : val */ +/* Description: Writing to this register set the amount of credit from SHMIFO RX (AvailableCredits),used to configure the initial amount of credits,reading this register should return the value of AvailableCredits. Implemented as external register type. */ +#define DRAM_DMA_ENGINE_CONFIG__QDDCSHMIFOINITCREDIT__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QDDCSHMIFOINITCREDIT__VAL__WIDTH (13) +#define DRAM_DMA_ENGINE_CONFIG__QDDCSHMIFOINITCREDIT__VAL__MASK (0x00001FFFL) +#define DRAM_DMA_ENGINE_CONFIG__QDDCSHMIFOINITCREDIT__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QDDCSHMIFOINITCREDIT__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x00001FFFL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QDDCSHMIFOINITCREDIT__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x00001FFFL) | (((uint32_t)(value) << 0) & 0x00001FFFL)) +#define DRAM_DMA_ENGINE_CONFIG__QDDCSHMIFOINITCREDIT__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00001FFFL) | 0x00001FFFL) +#define DRAM_DMA_ENGINE_CONFIG__QDDCSHMIFOINITCREDIT__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00001FFFL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QSDCENABLE : val */ +/* Description: Enable per channel,when disabled do not give credits to vDMA */ +#define DRAM_DMA_ENGINE_CONFIG__QSDCENABLE__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QSDCENABLE__VAL__WIDTH (1) +#define DRAM_DMA_ENGINE_CONFIG__QSDCENABLE__VAL__MASK (0x00000001L) +#define DRAM_DMA_ENGINE_CONFIG__QSDCENABLE__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QSDCENABLE__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x00000001L) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QSDCENABLE__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | (((uint32_t)(value) << 0) & 0x00000001L)) +#define DRAM_DMA_ENGINE_CONFIG__QSDCENABLE__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | ((uint32_t)(1) << 0)) +#define DRAM_DMA_ENGINE_CONFIG__QSDCENABLE__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | ((uint32_t)(0) << 0)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QSDCRESET : val */ +/* Description: Soft reset per channel,when write 1'b1 should clear all internal credits/counter/status. Should be set when channel is disabled,usually with vDMA channel reset (abort). Write 1'b0 should do nothing. Read always return 1'b0. Implemented as external register type. */ +#define DRAM_DMA_ENGINE_CONFIG__QSDCRESET__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QSDCRESET__VAL__WIDTH (1) +#define DRAM_DMA_ENGINE_CONFIG__QSDCRESET__VAL__MASK (0x00000001L) +#define DRAM_DMA_ENGINE_CONFIG__QSDCRESET__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QSDCRESET__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x00000001L) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QSDCRESET__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | (((uint32_t)(value) << 0) & 0x00000001L)) +#define DRAM_DMA_ENGINE_CONFIG__QSDCRESET__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | ((uint32_t)(1) << 0)) +#define DRAM_DMA_ENGINE_CONFIG__QSDCRESET__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | ((uint32_t)(0) << 0)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QSDCMAXDESC : val */ +/* Description: Maximum in flight descriptors,this is a TH for number of descriptors the QM might give the vDMA. 3'd0 - 1 descriptor (debug mode). 3'd1 - N_QM_DESC*1/8 (2). 3'd2 - N_QM_DESC*2/8 (4). 3'd3 - N_QM_DESC*3/8 (6). 3'd4 - N_QM_DESC*4/8 (8). 3'd5 - N_QM_DESC*5/8 (10). 3'd6 - N_QM_DESC*6/8 (12). 3'd7 - N_QM_DESC-1 (15-maximum),default. */ +#define DRAM_DMA_ENGINE_CONFIG__QSDCMAXDESC__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QSDCMAXDESC__VAL__WIDTH (3) +#define DRAM_DMA_ENGINE_CONFIG__QSDCMAXDESC__VAL__MASK (0x00000007L) +#define DRAM_DMA_ENGINE_CONFIG__QSDCMAXDESC__VAL__RESET (0x00000007L) +#define DRAM_DMA_ENGINE_CONFIG__QSDCMAXDESC__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x00000007L) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QSDCMAXDESC__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x00000007L) | (((uint32_t)(value) << 0) & 0x00000007L)) +#define DRAM_DMA_ENGINE_CONFIG__QSDCMAXDESC__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000007L) | 0x00000007L) +#define DRAM_DMA_ENGINE_CONFIG__QSDCMAXDESC__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000007L)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QSDCSHMIFOID : val */ +/* Description: The TX-SHMIFO ID. Used to know the SHMIFO base address (from a global parameter/define) and used to select the correct SHMIFO credit signal (nn_core_outbound_buffer_valid_pulse). 0-19: for DSM-TX 0-19. 20-30: reserved. 31: NULL ignore any credit from NN Core. */ +#define DRAM_DMA_ENGINE_CONFIG__QSDCSHMIFOID__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QSDCSHMIFOID__VAL__WIDTH (5) +#define DRAM_DMA_ENGINE_CONFIG__QSDCSHMIFOID__VAL__MASK (0x0000001FL) +#define DRAM_DMA_ENGINE_CONFIG__QSDCSHMIFOID__VAL__RESET (0x0000001FL) +#define DRAM_DMA_ENGINE_CONFIG__QSDCSHMIFOID__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x0000001FL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QSDCSHMIFOID__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x0000001FL) | (((uint32_t)(value) << 0) & 0x0000001FL)) +#define DRAM_DMA_ENGINE_CONFIG__QSDCSHMIFOID__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x0000001FL) | 0x0000001FL) +#define DRAM_DMA_ENGINE_CONFIG__QSDCSHMIFOID__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x0000001FL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QSDCSHMIFOCREDITSIZE : val */ +/* Description: The credit size in 8B granularity minus 1. 0 - indicates 8B 1 - indicates 16B ... 10'd1023 - indicates 8kB */ +#define DRAM_DMA_ENGINE_CONFIG__QSDCSHMIFOCREDITSIZE__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QSDCSHMIFOCREDITSIZE__VAL__WIDTH (10) +#define DRAM_DMA_ENGINE_CONFIG__QSDCSHMIFOCREDITSIZE__VAL__MASK (0x000003FFL) +#define DRAM_DMA_ENGINE_CONFIG__QSDCSHMIFOCREDITSIZE__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QSDCSHMIFOCREDITSIZE__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x000003FFL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QSDCSHMIFOCREDITSIZE__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x000003FFL) | (((uint32_t)(value) << 0) & 0x000003FFL)) +#define DRAM_DMA_ENGINE_CONFIG__QSDCSHMIFOCREDITSIZE__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x000003FFL) | 0x000003FFL) +#define DRAM_DMA_ENGINE_CONFIG__QSDCSHMIFOCREDITSIZE__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x000003FFL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QSDCFULLNUMPATTERNS : val */ +/* Description: Number of patterns per pattern ID minus one. 0 - one pattern,1 - two patterns,...,3 - four patterns. */ +#define DRAM_DMA_ENGINE_CONFIG__QSDCFULLNUMPATTERNS__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QSDCFULLNUMPATTERNS__VAL__WIDTH (2) +#define DRAM_DMA_ENGINE_CONFIG__QSDCFULLNUMPATTERNS__VAL__MASK (0x00000003L) +#define DRAM_DMA_ENGINE_CONFIG__QSDCFULLNUMPATTERNS__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QSDCFULLNUMPATTERNS__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x00000003L) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QSDCFULLNUMPATTERNS__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x00000003L) | (((uint32_t)(value) << 0) & 0x00000003L)) +#define DRAM_DMA_ENGINE_CONFIG__QSDCFULLNUMPATTERNS__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000003L) | 0x00000003L) +#define DRAM_DMA_ENGINE_CONFIG__QSDCFULLNUMPATTERNS__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000003L)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QSDCFULLPATTERNNUMLINES : val */ +/* Description: Number of lines per pattern. */ +#define DRAM_DMA_ENGINE_CONFIG__QSDCFULLPATTERNNUMLINES__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QSDCFULLPATTERNNUMLINES__VAL__WIDTH (18) +#define DRAM_DMA_ENGINE_CONFIG__QSDCFULLPATTERNNUMLINES__VAL__MASK (0x0003FFFFL) +#define DRAM_DMA_ENGINE_CONFIG__QSDCFULLPATTERNNUMLINES__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QSDCFULLPATTERNNUMLINES__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x0003FFFFL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QSDCFULLPATTERNNUMLINES__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x0003FFFFL) | (((uint32_t)(value) << 0) & 0x0003FFFFL)) +#define DRAM_DMA_ENGINE_CONFIG__QSDCFULLPATTERNNUMLINES__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x0003FFFFL) | 0x0003FFFFL) +#define DRAM_DMA_ENGINE_CONFIG__QSDCFULLPATTERNNUMLINES__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x0003FFFFL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QSDCFULLPATTERNNUMPAGES : val */ +/* Description: Number of pages per line. */ +#define DRAM_DMA_ENGINE_CONFIG__QSDCFULLPATTERNNUMPAGES__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QSDCFULLPATTERNNUMPAGES__VAL__WIDTH (18) +#define DRAM_DMA_ENGINE_CONFIG__QSDCFULLPATTERNNUMPAGES__VAL__MASK (0x0003FFFFL) +#define DRAM_DMA_ENGINE_CONFIG__QSDCFULLPATTERNNUMPAGES__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QSDCFULLPATTERNNUMPAGES__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x0003FFFFL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QSDCFULLPATTERNNUMPAGES__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x0003FFFFL) | (((uint32_t)(value) << 0) & 0x0003FFFFL)) +#define DRAM_DMA_ENGINE_CONFIG__QSDCFULLPATTERNNUMPAGES__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x0003FFFFL) | 0x0003FFFFL) +#define DRAM_DMA_ENGINE_CONFIG__QSDCFULLPATTERNNUMPAGES__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x0003FFFFL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QSDCFULLPATTERNPAGESIZE : val */ +/* Description: page size in 8B granularity,minus one,per pattern. 0-8B,1-16B,...,511-4kB */ +#define DRAM_DMA_ENGINE_CONFIG__QSDCFULLPATTERNPAGESIZE__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QSDCFULLPATTERNPAGESIZE__VAL__WIDTH (9) +#define DRAM_DMA_ENGINE_CONFIG__QSDCFULLPATTERNPAGESIZE__VAL__MASK (0x000001FFL) +#define DRAM_DMA_ENGINE_CONFIG__QSDCFULLPATTERNPAGESIZE__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QSDCFULLPATTERNPAGESIZE__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x000001FFL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QSDCFULLPATTERNPAGESIZE__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x000001FFL) | (((uint32_t)(value) << 0) & 0x000001FFL)) +#define DRAM_DMA_ENGINE_CONFIG__QSDCFULLPATTERNPAGESIZE__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x000001FFL) | 0x000001FFL) +#define DRAM_DMA_ENGINE_CONFIG__QSDCFULLPATTERNPAGESIZE__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x000001FFL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QSDCFULLPATTERNRESIDUEPAGESIZE : val */ +/* Description: Residue page size in 8B granularity,minus one,per pattern. 0-8B,1-16B,...,511-4kB */ +#define DRAM_DMA_ENGINE_CONFIG__QSDCFULLPATTERNRESIDUEPAGESIZE__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QSDCFULLPATTERNRESIDUEPAGESIZE__VAL__WIDTH (9) +#define DRAM_DMA_ENGINE_CONFIG__QSDCFULLPATTERNRESIDUEPAGESIZE__VAL__MASK (0x000001FFL) +#define DRAM_DMA_ENGINE_CONFIG__QSDCFULLPATTERNRESIDUEPAGESIZE__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QSDCFULLPATTERNRESIDUEPAGESIZE__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x000001FFL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QSDCFULLPATTERNRESIDUEPAGESIZE__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x000001FFL) | (((uint32_t)(value) << 0) & 0x000001FFL)) +#define DRAM_DMA_ENGINE_CONFIG__QSDCFULLPATTERNRESIDUEPAGESIZE__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x000001FFL) | 0x000001FFL) +#define DRAM_DMA_ENGINE_CONFIG__QSDCFULLPATTERNRESIDUEPAGESIZE__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x000001FFL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QSDCSIMPPATTERNNUMPAGES : val */ +/* Description: Number of pages per line (simplified pattern has single line/pattern). */ +#define DRAM_DMA_ENGINE_CONFIG__QSDCSIMPPATTERNNUMPAGES__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QSDCSIMPPATTERNNUMPAGES__VAL__WIDTH (18) +#define DRAM_DMA_ENGINE_CONFIG__QSDCSIMPPATTERNNUMPAGES__VAL__MASK (0x0003FFFFL) +#define DRAM_DMA_ENGINE_CONFIG__QSDCSIMPPATTERNNUMPAGES__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QSDCSIMPPATTERNNUMPAGES__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x0003FFFFL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QSDCSIMPPATTERNNUMPAGES__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x0003FFFFL) | (((uint32_t)(value) << 0) & 0x0003FFFFL)) +#define DRAM_DMA_ENGINE_CONFIG__QSDCSIMPPATTERNNUMPAGES__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x0003FFFFL) | 0x0003FFFFL) +#define DRAM_DMA_ENGINE_CONFIG__QSDCSIMPPATTERNNUMPAGES__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x0003FFFFL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QSDCSIMPPATTERNPAGESIZE : val */ +/* Description: Log2(Page size/512B),valid values are 0 to PAGE_SIZE_MAX-10. 0 - 512B,1 - 1kB,2 - 2kB,3 - 4kB */ +#define DRAM_DMA_ENGINE_CONFIG__QSDCSIMPPATTERNPAGESIZE__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QSDCSIMPPATTERNPAGESIZE__VAL__WIDTH (2) +#define DRAM_DMA_ENGINE_CONFIG__QSDCSIMPPATTERNPAGESIZE__VAL__MASK (0x00000003L) +#define DRAM_DMA_ENGINE_CONFIG__QSDCSIMPPATTERNPAGESIZE__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QSDCSIMPPATTERNPAGESIZE__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x00000003L) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QSDCSIMPPATTERNPAGESIZE__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x00000003L) | (((uint32_t)(value) << 0) & 0x00000003L)) +#define DRAM_DMA_ENGINE_CONFIG__QSDCSIMPPATTERNPAGESIZE__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000003L) | 0x00000003L) +#define DRAM_DMA_ENGINE_CONFIG__QSDCSIMPPATTERNPAGESIZE__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000003L)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QSDCSIMPPATTERNRESIDUEPAGESIZE : val */ +/* Description: Residue page size in 8B granularity,minus one,per pattern. 0-8B,1-16B,...,511-4kB */ +#define DRAM_DMA_ENGINE_CONFIG__QSDCSIMPPATTERNRESIDUEPAGESIZE__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QSDCSIMPPATTERNRESIDUEPAGESIZE__VAL__WIDTH (9) +#define DRAM_DMA_ENGINE_CONFIG__QSDCSIMPPATTERNRESIDUEPAGESIZE__VAL__MASK (0x000001FFL) +#define DRAM_DMA_ENGINE_CONFIG__QSDCSIMPPATTERNRESIDUEPAGESIZE__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QSDCSIMPPATTERNRESIDUEPAGESIZE__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x000001FFL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QSDCSIMPPATTERNRESIDUEPAGESIZE__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x000001FFL) | (((uint32_t)(value) << 0) & 0x000001FFL)) +#define DRAM_DMA_ENGINE_CONFIG__QSDCSIMPPATTERNRESIDUEPAGESIZE__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x000001FFL) | 0x000001FFL) +#define DRAM_DMA_ENGINE_CONFIG__QSDCSIMPPATTERNRESIDUEPAGESIZE__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x000001FFL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QDMCENABLE : val */ +/* Description: Enable per channel,when disabled do not give credits to vDMA */ +#define DRAM_DMA_ENGINE_CONFIG__QDMCENABLE__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QDMCENABLE__VAL__WIDTH (1) +#define DRAM_DMA_ENGINE_CONFIG__QDMCENABLE__VAL__MASK (0x00000001L) +#define DRAM_DMA_ENGINE_CONFIG__QDMCENABLE__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QDMCENABLE__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x00000001L) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QDMCENABLE__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | (((uint32_t)(value) << 0) & 0x00000001L)) +#define DRAM_DMA_ENGINE_CONFIG__QDMCENABLE__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | ((uint32_t)(1) << 0)) +#define DRAM_DMA_ENGINE_CONFIG__QDMCENABLE__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | ((uint32_t)(0) << 0)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QDMCRESET : val */ +/* Description: Soft reset per channel,when write 1'b1 should clear all internal credits/counter/status. Should be set when channel is disabled,usually with vDMA channel reset (abort). Write 1'b0 should do nothing. Read always return 1'b0. Implemented as external register type. */ +#define DRAM_DMA_ENGINE_CONFIG__QDMCRESET__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QDMCRESET__VAL__WIDTH (1) +#define DRAM_DMA_ENGINE_CONFIG__QDMCRESET__VAL__MASK (0x00000001L) +#define DRAM_DMA_ENGINE_CONFIG__QDMCRESET__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QDMCRESET__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x00000001L) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QDMCRESET__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | (((uint32_t)(value) << 0) & 0x00000001L)) +#define DRAM_DMA_ENGINE_CONFIG__QDMCRESET__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | ((uint32_t)(1) << 0)) +#define DRAM_DMA_ENGINE_CONFIG__QDMCRESET__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | ((uint32_t)(0) << 0)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QDMCMEMBASEADDR : val */ +/* Description: Base address to the CCB in the DDR memory space. aligned to minimum page size of 512B. */ +#define DRAM_DMA_ENGINE_CONFIG__QDMCMEMBASEADDR__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QDMCMEMBASEADDR__VAL__WIDTH (26) +#define DRAM_DMA_ENGINE_CONFIG__QDMCMEMBASEADDR__VAL__MASK (0x03FFFFFFL) +#define DRAM_DMA_ENGINE_CONFIG__QDMCMEMBASEADDR__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QDMCMEMBASEADDR__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x03FFFFFFL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QDMCMEMBASEADDR__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x03FFFFFFL) | (((uint32_t)(value) << 0) & 0x03FFFFFFL)) +#define DRAM_DMA_ENGINE_CONFIG__QDMCMEMBASEADDR__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x03FFFFFFL) | 0x03FFFFFFL) +#define DRAM_DMA_ENGINE_CONFIG__QDMCMEMBASEADDR__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x03FFFFFFL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QDMCMEMCCBSIZELOG2 : val */ +/* Description: The CCB size Log2(memory size/512B): 1 - 1kB (2 pages). 2 - 2kB. valid values are 1 to W_CCB_DESC_INDEX */ +#define DRAM_DMA_ENGINE_CONFIG__QDMCMEMCCBSIZELOG2__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QDMCMEMCCBSIZELOG2__VAL__WIDTH (5) +#define DRAM_DMA_ENGINE_CONFIG__QDMCMEMCCBSIZELOG2__VAL__MASK (0x0000001FL) +#define DRAM_DMA_ENGINE_CONFIG__QDMCMEMCCBSIZELOG2__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QDMCMEMCCBSIZELOG2__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x0000001FL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QDMCMEMCCBSIZELOG2__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x0000001FL) | (((uint32_t)(value) << 0) & 0x0000001FL)) +#define DRAM_DMA_ENGINE_CONFIG__QDMCMEMCCBSIZELOG2__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x0000001FL) | 0x0000001FL) +#define DRAM_DMA_ENGINE_CONFIG__QDMCMEMCCBSIZELOG2__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x0000001FL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QDMCDESCCSINTERRUPT : val */ +/* Description: When > 0 the QDMC will interrupt the CS manager every written QdmcDescCsInterrupt descriptors. */ +#define DRAM_DMA_ENGINE_CONFIG__QDMCDESCCSINTERRUPT__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QDMCDESCCSINTERRUPT__VAL__WIDTH (18) +#define DRAM_DMA_ENGINE_CONFIG__QDMCDESCCSINTERRUPT__VAL__MASK (0x0003FFFFL) +#define DRAM_DMA_ENGINE_CONFIG__QDMCDESCCSINTERRUPT__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QDMCDESCCSINTERRUPT__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x0003FFFFL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QDMCDESCCSINTERRUPT__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x0003FFFFL) | (((uint32_t)(value) << 0) & 0x0003FFFFL)) +#define DRAM_DMA_ENGINE_CONFIG__QDMCDESCCSINTERRUPT__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x0003FFFFL) | 0x0003FFFFL) +#define DRAM_DMA_ENGINE_CONFIG__QDMCDESCCSINTERRUPT__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x0003FFFFL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QDMCBANKINTERLEAVEMODE : val */ +/* Description: Select the bank interleave mode: 2'd0 - interleave 8 banks (default),2'd1 - Interleave 4 banks,2'd2 - Interleave 2 banks,2'd3 - no interleave. */ +#define DRAM_DMA_ENGINE_CONFIG__QDMCBANKINTERLEAVEMODE__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QDMCBANKINTERLEAVEMODE__VAL__WIDTH (2) +#define DRAM_DMA_ENGINE_CONFIG__QDMCBANKINTERLEAVEMODE__VAL__MASK (0x00000003L) +#define DRAM_DMA_ENGINE_CONFIG__QDMCBANKINTERLEAVEMODE__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QDMCBANKINTERLEAVEMODE__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x00000003L) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QDMCBANKINTERLEAVEMODE__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x00000003L) | (((uint32_t)(value) << 0) & 0x00000003L)) +#define DRAM_DMA_ENGINE_CONFIG__QDMCBANKINTERLEAVEMODE__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000003L) | 0x00000003L) +#define DRAM_DMA_ENGINE_CONFIG__QDMCBANKINTERLEAVEMODE__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000003L)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QDMCMODE : val */ +/* Description: 0 - CONT_MODE. 1 - BURST_MODE */ +#define DRAM_DMA_ENGINE_CONFIG__QDMCMODE__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QDMCMODE__VAL__WIDTH (1) +#define DRAM_DMA_ENGINE_CONFIG__QDMCMODE__VAL__MASK (0x00000001L) +#define DRAM_DMA_ENGINE_CONFIG__QDMCMODE__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QDMCMODE__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x00000001L) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QDMCMODE__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | (((uint32_t)(value) << 0) & 0x00000001L)) +#define DRAM_DMA_ENGINE_CONFIG__QDMCMODE__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | ((uint32_t)(1) << 0)) +#define DRAM_DMA_ENGINE_CONFIG__QDMCMODE__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | ((uint32_t)(0) << 0)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QDMCADDBURSTVAL : val */ +/* Description: Writing to this register increment the available descriptor counter in QDMC by QdmcAddBurstVal descriptors: AvailableDescsCounter += QdmcAddBurstVal. Reading this register should return the current available descriptors counter (AvailableDescsCounter). Implemented as external register type. */ +#define DRAM_DMA_ENGINE_CONFIG__QDMCADDBURSTVAL__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QDMCADDBURSTVAL__VAL__WIDTH (18) +#define DRAM_DMA_ENGINE_CONFIG__QDMCADDBURSTVAL__VAL__MASK (0x0003FFFFL) +#define DRAM_DMA_ENGINE_CONFIG__QDMCADDBURSTVAL__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QDMCADDBURSTVAL__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x0003FFFFL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QDMCADDBURSTVAL__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x0003FFFFL) | (((uint32_t)(value) << 0) & 0x0003FFFFL)) +#define DRAM_DMA_ENGINE_CONFIG__QDMCADDBURSTVAL__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x0003FFFFL) | 0x0003FFFFL) +#define DRAM_DMA_ENGINE_CONFIG__QDMCADDBURSTVAL__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x0003FFFFL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QDMCMEMCCBSIZE : val */ +/* Description: The CCB size Log2(memory size/512B): 1 - 1kB (2 pages). 2 - 2kB. valid values are 1 to W_CCB_DESC_INDEX */ +#define DRAM_DMA_ENGINE_CONFIG__QDMCMEMCCBSIZE__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QDMCMEMCCBSIZE__VAL__WIDTH (18) +#define DRAM_DMA_ENGINE_CONFIG__QDMCMEMCCBSIZE__VAL__MASK (0x0003FFFFL) +#define DRAM_DMA_ENGINE_CONFIG__QDMCMEMCCBSIZE__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QDMCMEMCCBSIZE__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x0003FFFFL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QDMCMEMCCBSIZE__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x0003FFFFL) | (((uint32_t)(value) << 0) & 0x0003FFFFL)) +#define DRAM_DMA_ENGINE_CONFIG__QDMCMEMCCBSIZE__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x0003FFFFL) | 0x0003FFFFL) +#define DRAM_DMA_ENGINE_CONFIG__QDMCMEMCCBSIZE__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x0003FFFFL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QDMCDESCPERIPHINTERRUPT : val */ +/* Description: When > 0 the QDMC will interrupt the peripheral every written QdmcDescPeriphInterrupt descriptors. */ +#define DRAM_DMA_ENGINE_CONFIG__QDMCDESCPERIPHINTERRUPT__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QDMCDESCPERIPHINTERRUPT__VAL__WIDTH (18) +#define DRAM_DMA_ENGINE_CONFIG__QDMCDESCPERIPHINTERRUPT__VAL__MASK (0x0003FFFFL) +#define DRAM_DMA_ENGINE_CONFIG__QDMCDESCPERIPHINTERRUPT__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QDMCDESCPERIPHINTERRUPT__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x0003FFFFL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QDMCDESCPERIPHINTERRUPT__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x0003FFFFL) | (((uint32_t)(value) << 0) & 0x0003FFFFL)) +#define DRAM_DMA_ENGINE_CONFIG__QDMCDESCPERIPHINTERRUPT__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x0003FFFFL) | 0x0003FFFFL) +#define DRAM_DMA_ENGINE_CONFIG__QDMCDESCPERIPHINTERRUPT__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x0003FFFFL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QDMCCCBPROCESSEDINDEX : val */ +/* Description: Used by the peripheral to indicates how many data is ready in the CCB (process). This is the CcbIndex (free pointer in CCB). */ +#define DRAM_DMA_ENGINE_CONFIG__QDMCCCBPROCESSEDINDEX__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QDMCCCBPROCESSEDINDEX__VAL__WIDTH (18) +#define DRAM_DMA_ENGINE_CONFIG__QDMCCCBPROCESSEDINDEX__VAL__MASK (0x0003FFFFL) +#define DRAM_DMA_ENGINE_CONFIG__QDMCCCBPROCESSEDINDEX__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QDMCCCBPROCESSEDINDEX__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x0003FFFFL) >> 0) + +/*----------------------------------------------------------------------------------------------------*/ +/* QSMCENABLE : val */ +/* Description: Enable per channel,when disabled do not give credits to vDMA */ +#define DRAM_DMA_ENGINE_CONFIG__QSMCENABLE__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QSMCENABLE__VAL__WIDTH (1) +#define DRAM_DMA_ENGINE_CONFIG__QSMCENABLE__VAL__MASK (0x00000001L) +#define DRAM_DMA_ENGINE_CONFIG__QSMCENABLE__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QSMCENABLE__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x00000001L) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QSMCENABLE__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | (((uint32_t)(value) << 0) & 0x00000001L)) +#define DRAM_DMA_ENGINE_CONFIG__QSMCENABLE__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | ((uint32_t)(1) << 0)) +#define DRAM_DMA_ENGINE_CONFIG__QSMCENABLE__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | ((uint32_t)(0) << 0)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QSMCRESET : val */ +/* Description: Soft reset per channel,when write 1'b1 should clear all internal credits/counter/status. Should be set when channel is disabled,usually with vDMA channel reset (abort). Write 1'b0 should do nothing. Read always return 1'b0. Implemented as external register type. */ +#define DRAM_DMA_ENGINE_CONFIG__QSMCRESET__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QSMCRESET__VAL__WIDTH (1) +#define DRAM_DMA_ENGINE_CONFIG__QSMCRESET__VAL__MASK (0x00000001L) +#define DRAM_DMA_ENGINE_CONFIG__QSMCRESET__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QSMCRESET__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x00000001L) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QSMCRESET__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | (((uint32_t)(value) << 0) & 0x00000001L)) +#define DRAM_DMA_ENGINE_CONFIG__QSMCRESET__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | ((uint32_t)(1) << 0)) +#define DRAM_DMA_ENGINE_CONFIG__QSMCRESET__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | ((uint32_t)(0) << 0)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QSMCMODE : val */ +/* Description: QSMC mode of operation: 2'd0 - CONT_MODE 2'd1 - reserved. 2'd2 - BURST_MODE 2'd3 - C2C_MODE */ +#define DRAM_DMA_ENGINE_CONFIG__QSMCMODE__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QSMCMODE__VAL__WIDTH (2) +#define DRAM_DMA_ENGINE_CONFIG__QSMCMODE__VAL__MASK (0x00000003L) +#define DRAM_DMA_ENGINE_CONFIG__QSMCMODE__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QSMCMODE__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x00000003L) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QSMCMODE__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x00000003L) | (((uint32_t)(value) << 0) & 0x00000003L)) +#define DRAM_DMA_ENGINE_CONFIG__QSMCMODE__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000003L) | 0x00000003L) +#define DRAM_DMA_ENGINE_CONFIG__QSMCMODE__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000003L)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QSMCC2CSEL : val */ +/* Description: Selector for Channel-to-Channel credit input,selects QDMC channel as source for HW available descriptors */ +#define DRAM_DMA_ENGINE_CONFIG__QSMCC2CSEL__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QSMCC2CSEL__VAL__WIDTH (6) +#define DRAM_DMA_ENGINE_CONFIG__QSMCC2CSEL__VAL__MASK (0x0000003FL) +#define DRAM_DMA_ENGINE_CONFIG__QSMCC2CSEL__VAL__RESET (0x0000003FL) +#define DRAM_DMA_ENGINE_CONFIG__QSMCC2CSEL__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x0000003FL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QSMCC2CSEL__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x0000003FL) | (((uint32_t)(value) << 0) & 0x0000003FL)) +#define DRAM_DMA_ENGINE_CONFIG__QSMCC2CSEL__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x0000003FL) | 0x0000003FL) +#define DRAM_DMA_ENGINE_CONFIG__QSMCC2CSEL__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x0000003FL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QSMCADDBURSTVAL : val */ +/* Description: Writing to this register increment the available descriptor counter in QSMC by QsmcAddBurstVal descriptors: AvailableDescsCounter += QsmcAddBurstVal. Reading this register should return the current available descriptors counter (AvailableDescsCounter). Implemented as external register type. */ +#define DRAM_DMA_ENGINE_CONFIG__QSMCADDBURSTVAL__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QSMCADDBURSTVAL__VAL__WIDTH (18) +#define DRAM_DMA_ENGINE_CONFIG__QSMCADDBURSTVAL__VAL__MASK (0x0003FFFFL) +#define DRAM_DMA_ENGINE_CONFIG__QSMCADDBURSTVAL__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QSMCADDBURSTVAL__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x0003FFFFL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QSMCADDBURSTVAL__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x0003FFFFL) | (((uint32_t)(value) << 0) & 0x0003FFFFL)) +#define DRAM_DMA_ENGINE_CONFIG__QSMCADDBURSTVAL__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x0003FFFFL) | 0x0003FFFFL) +#define DRAM_DMA_ENGINE_CONFIG__QSMCADDBURSTVAL__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x0003FFFFL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QSMCMEMBASEADDR : val */ +/* Description: Base address to the CCB in the DDR memory space. aligned to minimum page size of 512B. */ +#define DRAM_DMA_ENGINE_CONFIG__QSMCMEMBASEADDR__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QSMCMEMBASEADDR__VAL__WIDTH (26) +#define DRAM_DMA_ENGINE_CONFIG__QSMCMEMBASEADDR__VAL__MASK (0x03FFFFFFL) +#define DRAM_DMA_ENGINE_CONFIG__QSMCMEMBASEADDR__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QSMCMEMBASEADDR__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x03FFFFFFL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QSMCMEMBASEADDR__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x03FFFFFFL) | (((uint32_t)(value) << 0) & 0x03FFFFFFL)) +#define DRAM_DMA_ENGINE_CONFIG__QSMCMEMBASEADDR__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x03FFFFFFL) | 0x03FFFFFFL) +#define DRAM_DMA_ENGINE_CONFIG__QSMCMEMBASEADDR__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x03FFFFFFL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QSMCMEMCCBSIZE : val */ +/* Description: The CCB size minus one in page size granularity. 0 - 1 desc 1 - 2 desc ... N_CCB_MAX_DESC-1 - N_CCB_MAX_DESC desc. */ +#define DRAM_DMA_ENGINE_CONFIG__QSMCMEMCCBSIZE__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QSMCMEMCCBSIZE__VAL__WIDTH (18) +#define DRAM_DMA_ENGINE_CONFIG__QSMCMEMCCBSIZE__VAL__MASK (0x0003FFFFL) +#define DRAM_DMA_ENGINE_CONFIG__QSMCMEMCCBSIZE__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QSMCMEMCCBSIZE__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x0003FFFFL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QSMCMEMCCBSIZE__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x0003FFFFL) | (((uint32_t)(value) << 0) & 0x0003FFFFL)) +#define DRAM_DMA_ENGINE_CONFIG__QSMCMEMCCBSIZE__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x0003FFFFL) | 0x0003FFFFL) +#define DRAM_DMA_ENGINE_CONFIG__QSMCMEMCCBSIZE__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x0003FFFFL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QSMCPAGESIZE : val */ +/* Description: M2D Memory page size. Valid values are: 0 - 512B,1 - 1KB,2 - 2KB,3 - 4KB,4 - 1536B. */ +#define DRAM_DMA_ENGINE_CONFIG__QSMCPAGESIZE__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QSMCPAGESIZE__VAL__WIDTH (3) +#define DRAM_DMA_ENGINE_CONFIG__QSMCPAGESIZE__VAL__MASK (0x00000007L) +#define DRAM_DMA_ENGINE_CONFIG__QSMCPAGESIZE__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QSMCPAGESIZE__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x00000007L) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QSMCPAGESIZE__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x00000007L) | (((uint32_t)(value) << 0) & 0x00000007L)) +#define DRAM_DMA_ENGINE_CONFIG__QSMCPAGESIZE__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000007L) | 0x00000007L) +#define DRAM_DMA_ENGINE_CONFIG__QSMCPAGESIZE__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000007L)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QSMCSIMPPATTERNNUMPAGES : val */ +/* Description: Number of pages per line (simplified pattern has single line/pattern). */ +#define DRAM_DMA_ENGINE_CONFIG__QSMCSIMPPATTERNNUMPAGES__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QSMCSIMPPATTERNNUMPAGES__VAL__WIDTH (18) +#define DRAM_DMA_ENGINE_CONFIG__QSMCSIMPPATTERNNUMPAGES__VAL__MASK (0x0003FFFFL) +#define DRAM_DMA_ENGINE_CONFIG__QSMCSIMPPATTERNNUMPAGES__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QSMCSIMPPATTERNNUMPAGES__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x0003FFFFL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QSMCSIMPPATTERNNUMPAGES__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x0003FFFFL) | (((uint32_t)(value) << 0) & 0x0003FFFFL)) +#define DRAM_DMA_ENGINE_CONFIG__QSMCSIMPPATTERNNUMPAGES__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x0003FFFFL) | 0x0003FFFFL) +#define DRAM_DMA_ENGINE_CONFIG__QSMCSIMPPATTERNNUMPAGES__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x0003FFFFL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QSMCSIMPPATTERNRESIDUEPAGESIZE : val */ +/* Description: Residue page size in 8B granularity,minus one,per pattern. 0-8B,1-16B,...,511-4kB */ +#define DRAM_DMA_ENGINE_CONFIG__QSMCSIMPPATTERNRESIDUEPAGESIZE__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QSMCSIMPPATTERNRESIDUEPAGESIZE__VAL__WIDTH (9) +#define DRAM_DMA_ENGINE_CONFIG__QSMCSIMPPATTERNRESIDUEPAGESIZE__VAL__MASK (0x000001FFL) +#define DRAM_DMA_ENGINE_CONFIG__QSMCSIMPPATTERNRESIDUEPAGESIZE__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QSMCSIMPPATTERNRESIDUEPAGESIZE__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x000001FFL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QSMCSIMPPATTERNRESIDUEPAGESIZE__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x000001FFL) | (((uint32_t)(value) << 0) & 0x000001FFL)) +#define DRAM_DMA_ENGINE_CONFIG__QSMCSIMPPATTERNRESIDUEPAGESIZE__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x000001FFL) | 0x000001FFL) +#define DRAM_DMA_ENGINE_CONFIG__QSMCSIMPPATTERNRESIDUEPAGESIZE__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x000001FFL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QSMCBANKINTERLEAVEMODE : val */ +/* Description: Select the bank interleave mode: 2'd0 - interleave 8 banks (default),2'd1 - Interleave 4 banks,2'd2 - Interleave 2 banks,2'd3 - no interleave. */ +#define DRAM_DMA_ENGINE_CONFIG__QSMCBANKINTERLEAVEMODE__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QSMCBANKINTERLEAVEMODE__VAL__WIDTH (2) +#define DRAM_DMA_ENGINE_CONFIG__QSMCBANKINTERLEAVEMODE__VAL__MASK (0x00000003L) +#define DRAM_DMA_ENGINE_CONFIG__QSMCBANKINTERLEAVEMODE__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QSMCBANKINTERLEAVEMODE__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x00000003L) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QSMCBANKINTERLEAVEMODE__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x00000003L) | (((uint32_t)(value) << 0) & 0x00000003L)) +#define DRAM_DMA_ENGINE_CONFIG__QSMCBANKINTERLEAVEMODE__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000003L) | 0x00000003L) +#define DRAM_DMA_ENGINE_CONFIG__QSMCBANKINTERLEAVEMODE__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000003L)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QSMCDESCPERIPHINTERRUPT : val */ +/* Description: When > 0 the QSMC will interrupt the peripheral every read QsmcDescPeriphInterrupt descriptors. */ +#define DRAM_DMA_ENGINE_CONFIG__QSMCDESCPERIPHINTERRUPT__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QSMCDESCPERIPHINTERRUPT__VAL__WIDTH (18) +#define DRAM_DMA_ENGINE_CONFIG__QSMCDESCPERIPHINTERRUPT__VAL__MASK (0x0003FFFFL) +#define DRAM_DMA_ENGINE_CONFIG__QSMCDESCPERIPHINTERRUPT__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QSMCDESCPERIPHINTERRUPT__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x0003FFFFL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QSMCDESCPERIPHINTERRUPT__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x0003FFFFL) | (((uint32_t)(value) << 0) & 0x0003FFFFL)) +#define DRAM_DMA_ENGINE_CONFIG__QSMCDESCPERIPHINTERRUPT__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x0003FFFFL) | 0x0003FFFFL) +#define DRAM_DMA_ENGINE_CONFIG__QSMCDESCPERIPHINTERRUPT__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x0003FFFFL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QSMCCCBFREEINDEX : val */ +/* Description: Used by the peripheral to indicates how many data is ready in the CCB for write (process). This is the CcbIndex (free pointer in CCB). */ +#define DRAM_DMA_ENGINE_CONFIG__QSMCCCBFREEINDEX__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QSMCCCBFREEINDEX__VAL__WIDTH (18) +#define DRAM_DMA_ENGINE_CONFIG__QSMCCCBFREEINDEX__VAL__MASK (0x0003FFFFL) +#define DRAM_DMA_ENGINE_CONFIG__QSMCCCBFREEINDEX__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QSMCCCBFREEINDEX__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x0003FFFFL) >> 0) + +/*----------------------------------------------------------------------------------------------------*/ +/* ENGINE_CS_INTR_MASK : val */ +/* Description: INT register bits[15:0] per M2D channel,indicating one of the following events: a. Internal desc - QSMC processed last CCB descriptor. Implemented by set the interrupt when CCB-free-index is wrapped (become zero),might be used for CONF channel - to indicates conf is done. bits[31:16] per D2M channel indicating one of the following events: Internal desc - QDMC processed descriptors per QdmcDescCsInterrupt (OR) External desc - domain#0 (local) source/destination event. */ +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_CS_INTR_MASK__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_CS_INTR_MASK__VAL__WIDTH (32) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_CS_INTR_MASK__VAL__MASK (0xFFFFFFFFL) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_CS_INTR_MASK__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_CS_INTR_MASK__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0xFFFFFFFFL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_CS_INTR_MASK__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0xFFFFFFFFL) | (((uint32_t)(value) << 0) & 0xFFFFFFFFL)) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_CS_INTR_MASK__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0xFFFFFFFFL) | 0xFFFFFFFFL) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_CS_INTR_MASK__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0xFFFFFFFFL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* ENGINE_CS_INTR_STATUS : val */ +/* Description: INT register bits[15:0] per M2D channel,indicating one of the following events: a. Internal desc - QSMC processed last CCB descriptor. Implemented by set the interrupt when CCB-free-index is wrapped (become zero),might be used for CONF channel - to indicates conf is done. bits[31:16] per D2M channel indicating one of the following events: Internal desc - QDMC processed descriptors per QdmcDescCsInterrupt (OR) External desc - domain#0 (local) source/destination event. */ +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_CS_INTR_STATUS__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_CS_INTR_STATUS__VAL__WIDTH (32) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_CS_INTR_STATUS__VAL__MASK (0xFFFFFFFFL) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_CS_INTR_STATUS__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_CS_INTR_STATUS__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0xFFFFFFFFL) >> 0) + +/*----------------------------------------------------------------------------------------------------*/ +/* ENGINE_CS_INTR_W1C : val */ +/* Description: INT register bits[15:0] per M2D channel,indicating one of the following events: a. Internal desc - QSMC processed last CCB descriptor. Implemented by set the interrupt when CCB-free-index is wrapped (become zero),might be used for CONF channel - to indicates conf is done. bits[31:16] per D2M channel indicating one of the following events: Internal desc - QDMC processed descriptors per QdmcDescCsInterrupt (OR) External desc - domain#0 (local) source/destination event. */ +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_CS_INTR_W1C__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_CS_INTR_W1C__VAL__WIDTH (32) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_CS_INTR_W1C__VAL__MASK (0xFFFFFFFFL) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_CS_INTR_W1C__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_CS_INTR_W1C__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0xFFFFFFFFL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_CS_INTR_W1C__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0xFFFFFFFFL) | (((uint32_t)(value) << 0) & 0xFFFFFFFFL)) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_CS_INTR_W1C__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0xFFFFFFFFL) | 0xFFFFFFFFL) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_CS_INTR_W1C__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0xFFFFFFFFL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* ENGINE_CS_INTR_W1S : val */ +/* Description: INT register bits[15:0] per M2D channel,indicating one of the following events: a. Internal desc - QSMC processed last CCB descriptor. Implemented by set the interrupt when CCB-free-index is wrapped (become zero),might be used for CONF channel - to indicates conf is done. bits[31:16] per D2M channel indicating one of the following events: Internal desc - QDMC processed descriptors per QdmcDescCsInterrupt (OR) External desc - domain#0 (local) source/destination event. */ +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_CS_INTR_W1S__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_CS_INTR_W1S__VAL__WIDTH (32) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_CS_INTR_W1S__VAL__MASK (0xFFFFFFFFL) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_CS_INTR_W1S__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_CS_INTR_W1S__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0xFFFFFFFFL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_CS_INTR_W1S__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0xFFFFFFFFL) | (((uint32_t)(value) << 0) & 0xFFFFFFFFL)) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_CS_INTR_W1S__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0xFFFFFFFFL) | 0xFFFFFFFFL) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_CS_INTR_W1S__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0xFFFFFFFFL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* ENGINE_AP_INTR_MASK : val */ +/* Description: INT register bit per direction/channel indicating one of the following events: Internal desc - QDMC processed descriptors per QdmcDescPeriphInterrupt (D2M enhanced channels only) (OR) Internal desc - QSMC processed descriptors per QsmcDescPeriphInterrupt (M2D enhanced channels only) (OR) External desc - domain#1 (host) source/destination event */ +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_AP_INTR_MASK__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_AP_INTR_MASK__VAL__WIDTH (32) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_AP_INTR_MASK__VAL__MASK (0xFFFFFFFFL) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_AP_INTR_MASK__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_AP_INTR_MASK__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0xFFFFFFFFL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_AP_INTR_MASK__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0xFFFFFFFFL) | (((uint32_t)(value) << 0) & 0xFFFFFFFFL)) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_AP_INTR_MASK__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0xFFFFFFFFL) | 0xFFFFFFFFL) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_AP_INTR_MASK__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0xFFFFFFFFL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* ENGINE_AP_INTR_STATUS : val */ +/* Description: INT register bit per direction/channel indicating one of the following events: Internal desc - QDMC processed descriptors per QdmcDescPeriphInterrupt (D2M enhanced channels only) (OR) Internal desc - QSMC processed descriptors per QsmcDescPeriphInterrupt (M2D enhanced channels only) (OR) External desc - domain#1 (host) source/destination event */ +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_AP_INTR_STATUS__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_AP_INTR_STATUS__VAL__WIDTH (32) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_AP_INTR_STATUS__VAL__MASK (0xFFFFFFFFL) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_AP_INTR_STATUS__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_AP_INTR_STATUS__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0xFFFFFFFFL) >> 0) + +/*----------------------------------------------------------------------------------------------------*/ +/* ENGINE_AP_INTR_W1C : val */ +/* Description: INT register bit per direction/channel indicating one of the following events: Internal desc - QDMC processed descriptors per QdmcDescPeriphInterrupt (D2M enhanced channels only) (OR) Internal desc - QSMC processed descriptors per QsmcDescPeriphInterrupt (M2D enhanced channels only) (OR) External desc - domain#1 (host) source/destination event */ +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_AP_INTR_W1C__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_AP_INTR_W1C__VAL__WIDTH (32) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_AP_INTR_W1C__VAL__MASK (0xFFFFFFFFL) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_AP_INTR_W1C__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_AP_INTR_W1C__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0xFFFFFFFFL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_AP_INTR_W1C__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0xFFFFFFFFL) | (((uint32_t)(value) << 0) & 0xFFFFFFFFL)) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_AP_INTR_W1C__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0xFFFFFFFFL) | 0xFFFFFFFFL) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_AP_INTR_W1C__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0xFFFFFFFFL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* ENGINE_AP_INTR_W1S : val */ +/* Description: INT register bit per direction/channel indicating one of the following events: Internal desc - QDMC processed descriptors per QdmcDescPeriphInterrupt (D2M enhanced channels only) (OR) Internal desc - QSMC processed descriptors per QsmcDescPeriphInterrupt (M2D enhanced channels only) (OR) External desc - domain#1 (host) source/destination event */ +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_AP_INTR_W1S__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_AP_INTR_W1S__VAL__WIDTH (32) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_AP_INTR_W1S__VAL__MASK (0xFFFFFFFFL) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_AP_INTR_W1S__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_AP_INTR_W1S__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0xFFFFFFFFL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_AP_INTR_W1S__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0xFFFFFFFFL) | (((uint32_t)(value) << 0) & 0xFFFFFFFFL)) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_AP_INTR_W1S__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0xFFFFFFFFL) | 0xFFFFFFFFL) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_AP_INTR_W1S__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0xFFFFFFFFL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* ENGINE_DSP_INTR_MASK : val */ +/* Description: INT register */ +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_DSP_INTR_MASK__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_DSP_INTR_MASK__VAL__WIDTH (8) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_DSP_INTR_MASK__VAL__MASK (0x000000FFL) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_DSP_INTR_MASK__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_DSP_INTR_MASK__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x000000FFL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_DSP_INTR_MASK__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL) | (((uint32_t)(value) << 0) & 0x000000FFL)) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_DSP_INTR_MASK__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL) | 0x000000FFL) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_DSP_INTR_MASK__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* ENGINE_DSP_INTR_STATUS : val */ +/* Description: INT register */ +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_DSP_INTR_STATUS__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_DSP_INTR_STATUS__VAL__WIDTH (8) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_DSP_INTR_STATUS__VAL__MASK (0x000000FFL) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_DSP_INTR_STATUS__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_DSP_INTR_STATUS__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x000000FFL) >> 0) + +/*----------------------------------------------------------------------------------------------------*/ +/* ENGINE_DSP_INTR_W1C : val */ +/* Description: INT register */ +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_DSP_INTR_W1C__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_DSP_INTR_W1C__VAL__WIDTH (8) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_DSP_INTR_W1C__VAL__MASK (0x000000FFL) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_DSP_INTR_W1C__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_DSP_INTR_W1C__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x000000FFL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_DSP_INTR_W1C__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL) | (((uint32_t)(value) << 0) & 0x000000FFL)) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_DSP_INTR_W1C__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL) | 0x000000FFL) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_DSP_INTR_W1C__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* ENGINE_DSP_INTR_W1S : val */ +/* Description: INT register */ +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_DSP_INTR_W1S__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_DSP_INTR_W1S__VAL__WIDTH (8) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_DSP_INTR_W1S__VAL__MASK (0x000000FFL) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_DSP_INTR_W1S__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_DSP_INTR_W1S__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x000000FFL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_DSP_INTR_W1S__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL) | (((uint32_t)(value) << 0) & 0x000000FFL)) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_DSP_INTR_W1S__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL) | 0x000000FFL) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_DSP_INTR_W1S__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* ENGINE_ERR_INTR_MASK : desc_err */ +/* Description: Summary of desc_err_intr register. */ +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ERR_INTR_MASK__DESC_ERR__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ERR_INTR_MASK__DESC_ERR__WIDTH (1) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ERR_INTR_MASK__DESC_ERR__MASK (0x00000001L) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ERR_INTR_MASK__DESC_ERR__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ERR_INTR_MASK__DESC_ERR__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x00000001L) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ERR_INTR_MASK__DESC_ERR__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | (((uint32_t)(value) << 0) & 0x00000001L)) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ERR_INTR_MASK__DESC_ERR__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | ((uint32_t)(1) << 0)) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ERR_INTR_MASK__DESC_ERR__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | ((uint32_t)(0) << 0)) + +/* ENGINE_ERR_INTR_MASK : qddc_crd_ovf_err */ +/* Description: Summary of qddc_crd_ovf_err_intr register. */ +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ERR_INTR_MASK__QDDC_CRD_OVF_ERR__SHIFT (1) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ERR_INTR_MASK__QDDC_CRD_OVF_ERR__WIDTH (1) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ERR_INTR_MASK__QDDC_CRD_OVF_ERR__MASK (0x00000002L) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ERR_INTR_MASK__QDDC_CRD_OVF_ERR__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ERR_INTR_MASK__QDDC_CRD_OVF_ERR__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x00000002L) >> 1) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ERR_INTR_MASK__QDDC_CRD_OVF_ERR__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x00000002L) | (((uint32_t)(value) << 1) & 0x00000002L)) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ERR_INTR_MASK__QDDC_CRD_OVF_ERR__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000002L) | ((uint32_t)(1) << 1)) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ERR_INTR_MASK__QDDC_CRD_OVF_ERR__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000002L) | ((uint32_t)(0) << 1)) + +/* ENGINE_ERR_INTR_MASK : qsdc_crd_ovf_err */ +/* Description: Summary of qsdc_crd_ovf_err_intr register. */ +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ERR_INTR_MASK__QSDC_CRD_OVF_ERR__SHIFT (2) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ERR_INTR_MASK__QSDC_CRD_OVF_ERR__WIDTH (1) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ERR_INTR_MASK__QSDC_CRD_OVF_ERR__MASK (0x00000004L) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ERR_INTR_MASK__QSDC_CRD_OVF_ERR__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ERR_INTR_MASK__QSDC_CRD_OVF_ERR__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x00000004L) >> 2) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ERR_INTR_MASK__QSDC_CRD_OVF_ERR__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x00000004L) | (((uint32_t)(value) << 2) & 0x00000004L)) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ERR_INTR_MASK__QSDC_CRD_OVF_ERR__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000004L) | ((uint32_t)(1) << 2)) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ERR_INTR_MASK__QSDC_CRD_OVF_ERR__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000004L) | ((uint32_t)(0) << 2)) + +/*----------------------------------------------------------------------------------------------------*/ +/* ENGINE_ERR_INTR_STATUS : desc_err */ +/* Description: Summary of desc_err_intr register. */ +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ERR_INTR_STATUS__DESC_ERR__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ERR_INTR_STATUS__DESC_ERR__WIDTH (1) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ERR_INTR_STATUS__DESC_ERR__MASK (0x00000001L) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ERR_INTR_STATUS__DESC_ERR__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ERR_INTR_STATUS__DESC_ERR__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x00000001L) >> 0) + +/* ENGINE_ERR_INTR_STATUS : qddc_crd_ovf_err */ +/* Description: Summary of qddc_crd_ovf_err_intr register. */ +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ERR_INTR_STATUS__QDDC_CRD_OVF_ERR__SHIFT (1) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ERR_INTR_STATUS__QDDC_CRD_OVF_ERR__WIDTH (1) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ERR_INTR_STATUS__QDDC_CRD_OVF_ERR__MASK (0x00000002L) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ERR_INTR_STATUS__QDDC_CRD_OVF_ERR__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ERR_INTR_STATUS__QDDC_CRD_OVF_ERR__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x00000002L) >> 1) + +/* ENGINE_ERR_INTR_STATUS : qsdc_crd_ovf_err */ +/* Description: Summary of qsdc_crd_ovf_err_intr register. */ +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ERR_INTR_STATUS__QSDC_CRD_OVF_ERR__SHIFT (2) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ERR_INTR_STATUS__QSDC_CRD_OVF_ERR__WIDTH (1) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ERR_INTR_STATUS__QSDC_CRD_OVF_ERR__MASK (0x00000004L) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ERR_INTR_STATUS__QSDC_CRD_OVF_ERR__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ERR_INTR_STATUS__QSDC_CRD_OVF_ERR__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x00000004L) >> 2) + +/*----------------------------------------------------------------------------------------------------*/ +/* DESC_ERR_INTR_MASK : DescStatus */ +/* Description: Interrupt bit per DESC_STATUS fields of vDMA descriptor which returned unexpected value (Note that successful descriptor returns status of 8'h1). Refer to EngErrInterruptSource register for the error origin. */ +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_MASK__DESCSTATUS__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_MASK__DESCSTATUS__WIDTH (8) +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_MASK__DESCSTATUS__MASK (0x000000FFL) +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_MASK__DESCSTATUS__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_MASK__DESCSTATUS__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x000000FFL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_MASK__DESCSTATUS__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL) | (((uint32_t)(value) << 0) & 0x000000FFL)) +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_MASK__DESCSTATUS__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL) | 0x000000FFL) +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_MASK__DESCSTATUS__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL)) + +/* DESC_ERR_INTR_MASK : RemainPageSize */ +/* Description: non-zero REMAINING_PAGE_SIZE. Refer to EngErrInterruptSource register for the error origin. Refer to EngErrRemainPageSize register for the returned value. */ +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_MASK__REMAINPAGESIZE__SHIFT (8) +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_MASK__REMAINPAGESIZE__WIDTH (1) +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_MASK__REMAINPAGESIZE__MASK (0x00000100L) +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_MASK__REMAINPAGESIZE__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_MASK__REMAINPAGESIZE__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x00000100L) >> 8) +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_MASK__REMAINPAGESIZE__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x00000100L) | (((uint32_t)(value) << 8) & 0x00000100L)) +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_MASK__REMAINPAGESIZE__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000100L) | ((uint32_t)(1) << 8)) +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_MASK__REMAINPAGESIZE__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000100L) | ((uint32_t)(0) << 8)) + +/* DESC_ERR_INTR_MASK : SrcDescWdataPar */ +/* Description: Source descriptor complete with error status. Refer to EngErrInterruptSource register for the error origin. */ +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_MASK__SRCDESCWDATAPAR__SHIFT (9) +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_MASK__SRCDESCWDATAPAR__WIDTH (1) +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_MASK__SRCDESCWDATAPAR__MASK (0x00000200L) +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_MASK__SRCDESCWDATAPAR__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_MASK__SRCDESCWDATAPAR__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x00000200L) >> 9) +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_MASK__SRCDESCWDATAPAR__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x00000200L) | (((uint32_t)(value) << 9) & 0x00000200L)) +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_MASK__SRCDESCWDATAPAR__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000200L) | ((uint32_t)(1) << 9)) +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_MASK__SRCDESCWDATAPAR__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000200L) | ((uint32_t)(0) << 9)) + +/* DESC_ERR_INTR_MASK : DstDescWdataPar */ +/* Description: Destination descriptor complete with error status. Refer to EngErrInterruptSource register for the error origin. */ +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_MASK__DSTDESCWDATAPAR__SHIFT (10) +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_MASK__DSTDESCWDATAPAR__WIDTH (1) +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_MASK__DSTDESCWDATAPAR__MASK (0x00000400L) +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_MASK__DSTDESCWDATAPAR__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_MASK__DSTDESCWDATAPAR__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x00000400L) >> 10) +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_MASK__DSTDESCWDATAPAR__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x00000400L) | (((uint32_t)(value) << 10) & 0x00000400L)) +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_MASK__DSTDESCWDATAPAR__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000400L) | ((uint32_t)(1) << 10)) +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_MASK__DSTDESCWDATAPAR__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000400L) | ((uint32_t)(0) << 10)) + +/*----------------------------------------------------------------------------------------------------*/ +/* DESC_ERR_INTR_STATUS : DescStatus */ +/* Description: Interrupt bit per DESC_STATUS fields of vDMA descriptor which returned unexpected value (Note that successful descriptor returns status of 8'h1). Refer to EngErrInterruptSource register for the error origin. */ +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_STATUS__DESCSTATUS__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_STATUS__DESCSTATUS__WIDTH (8) +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_STATUS__DESCSTATUS__MASK (0x000000FFL) +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_STATUS__DESCSTATUS__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_STATUS__DESCSTATUS__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x000000FFL) >> 0) + +/* DESC_ERR_INTR_STATUS : RemainPageSize */ +/* Description: non-zero REMAINING_PAGE_SIZE. Refer to EngErrInterruptSource register for the error origin. Refer to EngErrRemainPageSize register for the returned value. */ +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_STATUS__REMAINPAGESIZE__SHIFT (8) +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_STATUS__REMAINPAGESIZE__WIDTH (1) +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_STATUS__REMAINPAGESIZE__MASK (0x00000100L) +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_STATUS__REMAINPAGESIZE__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_STATUS__REMAINPAGESIZE__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x00000100L) >> 8) + +/* DESC_ERR_INTR_STATUS : SrcDescWdataPar */ +/* Description: Source descriptor complete with error status. Refer to EngErrInterruptSource register for the error origin. */ +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_STATUS__SRCDESCWDATAPAR__SHIFT (9) +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_STATUS__SRCDESCWDATAPAR__WIDTH (1) +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_STATUS__SRCDESCWDATAPAR__MASK (0x00000200L) +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_STATUS__SRCDESCWDATAPAR__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_STATUS__SRCDESCWDATAPAR__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x00000200L) >> 9) + +/* DESC_ERR_INTR_STATUS : DstDescWdataPar */ +/* Description: Destination descriptor complete with error status. Refer to EngErrInterruptSource register for the error origin. */ +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_STATUS__DSTDESCWDATAPAR__SHIFT (10) +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_STATUS__DSTDESCWDATAPAR__WIDTH (1) +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_STATUS__DSTDESCWDATAPAR__MASK (0x00000400L) +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_STATUS__DSTDESCWDATAPAR__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_STATUS__DSTDESCWDATAPAR__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x00000400L) >> 10) + +/*----------------------------------------------------------------------------------------------------*/ +/* DESC_ERR_INTR_W1C : DescStatus */ +/* Description: Interrupt bit per DESC_STATUS fields of vDMA descriptor which returned unexpected value (Note that successful descriptor returns status of 8'h1). Refer to EngErrInterruptSource register for the error origin. */ +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_W1C__DESCSTATUS__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_W1C__DESCSTATUS__WIDTH (8) +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_W1C__DESCSTATUS__MASK (0x000000FFL) +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_W1C__DESCSTATUS__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_W1C__DESCSTATUS__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x000000FFL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_W1C__DESCSTATUS__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL) | (((uint32_t)(value) << 0) & 0x000000FFL)) +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_W1C__DESCSTATUS__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL) | 0x000000FFL) +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_W1C__DESCSTATUS__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* DESC_ERR_INTR_W1S : DescStatus */ +/* Description: Interrupt bit per DESC_STATUS fields of vDMA descriptor which returned unexpected value (Note that successful descriptor returns status of 8'h1). Refer to EngErrInterruptSource register for the error origin. */ +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_W1S__DESCSTATUS__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_W1S__DESCSTATUS__WIDTH (8) +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_W1S__DESCSTATUS__MASK (0x000000FFL) +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_W1S__DESCSTATUS__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_W1S__DESCSTATUS__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x000000FFL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_W1S__DESCSTATUS__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL) | (((uint32_t)(value) << 0) & 0x000000FFL)) +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_W1S__DESCSTATUS__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL) | 0x000000FFL) +#define DRAM_DMA_ENGINE_CONFIG__DESC_ERR_INTR_W1S__DESCSTATUS__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QDDC_CRD_OVF_ERR_INTR_MASK : ch */ +/* Description: Interrupt bit per QDDC channel indicating overflow or underflow in Core credit counter. */ +#define DRAM_DMA_ENGINE_CONFIG__QDDC_CRD_OVF_ERR_INTR_MASK__CH__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QDDC_CRD_OVF_ERR_INTR_MASK__CH__WIDTH (16) +#define DRAM_DMA_ENGINE_CONFIG__QDDC_CRD_OVF_ERR_INTR_MASK__CH__MASK (0x0000FFFFL) +#define DRAM_DMA_ENGINE_CONFIG__QDDC_CRD_OVF_ERR_INTR_MASK__CH__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QDDC_CRD_OVF_ERR_INTR_MASK__CH__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x0000FFFFL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QDDC_CRD_OVF_ERR_INTR_MASK__CH__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x0000FFFFL) | (((uint32_t)(value) << 0) & 0x0000FFFFL)) +#define DRAM_DMA_ENGINE_CONFIG__QDDC_CRD_OVF_ERR_INTR_MASK__CH__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x0000FFFFL) | 0x0000FFFFL) +#define DRAM_DMA_ENGINE_CONFIG__QDDC_CRD_OVF_ERR_INTR_MASK__CH__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x0000FFFFL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QDDC_CRD_OVF_ERR_INTR_STATUS : ch */ +/* Description: Interrupt bit per QDDC channel indicating overflow or underflow in Core credit counter. */ +#define DRAM_DMA_ENGINE_CONFIG__QDDC_CRD_OVF_ERR_INTR_STATUS__CH__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QDDC_CRD_OVF_ERR_INTR_STATUS__CH__WIDTH (16) +#define DRAM_DMA_ENGINE_CONFIG__QDDC_CRD_OVF_ERR_INTR_STATUS__CH__MASK (0x0000FFFFL) +#define DRAM_DMA_ENGINE_CONFIG__QDDC_CRD_OVF_ERR_INTR_STATUS__CH__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QDDC_CRD_OVF_ERR_INTR_STATUS__CH__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x0000FFFFL) >> 0) + +/*----------------------------------------------------------------------------------------------------*/ +/* QDDC_CRD_OVF_ERR_INTR_W1C : ch */ +/* Description: Interrupt bit per QDDC channel indicating overflow or underflow in Core credit counter. */ +#define DRAM_DMA_ENGINE_CONFIG__QDDC_CRD_OVF_ERR_INTR_W1C__CH__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QDDC_CRD_OVF_ERR_INTR_W1C__CH__WIDTH (16) +#define DRAM_DMA_ENGINE_CONFIG__QDDC_CRD_OVF_ERR_INTR_W1C__CH__MASK (0x0000FFFFL) +#define DRAM_DMA_ENGINE_CONFIG__QDDC_CRD_OVF_ERR_INTR_W1C__CH__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QDDC_CRD_OVF_ERR_INTR_W1C__CH__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x0000FFFFL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QDDC_CRD_OVF_ERR_INTR_W1C__CH__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x0000FFFFL) | (((uint32_t)(value) << 0) & 0x0000FFFFL)) +#define DRAM_DMA_ENGINE_CONFIG__QDDC_CRD_OVF_ERR_INTR_W1C__CH__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x0000FFFFL) | 0x0000FFFFL) +#define DRAM_DMA_ENGINE_CONFIG__QDDC_CRD_OVF_ERR_INTR_W1C__CH__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x0000FFFFL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QDDC_CRD_OVF_ERR_INTR_W1S : ch */ +/* Description: Interrupt bit per QDDC channel indicating overflow or underflow in Core credit counter. */ +#define DRAM_DMA_ENGINE_CONFIG__QDDC_CRD_OVF_ERR_INTR_W1S__CH__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QDDC_CRD_OVF_ERR_INTR_W1S__CH__WIDTH (16) +#define DRAM_DMA_ENGINE_CONFIG__QDDC_CRD_OVF_ERR_INTR_W1S__CH__MASK (0x0000FFFFL) +#define DRAM_DMA_ENGINE_CONFIG__QDDC_CRD_OVF_ERR_INTR_W1S__CH__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QDDC_CRD_OVF_ERR_INTR_W1S__CH__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x0000FFFFL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QDDC_CRD_OVF_ERR_INTR_W1S__CH__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x0000FFFFL) | (((uint32_t)(value) << 0) & 0x0000FFFFL)) +#define DRAM_DMA_ENGINE_CONFIG__QDDC_CRD_OVF_ERR_INTR_W1S__CH__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x0000FFFFL) | 0x0000FFFFL) +#define DRAM_DMA_ENGINE_CONFIG__QDDC_CRD_OVF_ERR_INTR_W1S__CH__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x0000FFFFL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QSDC_CRD_OVF_ERR_INTR_MASK : ch */ +/* Description: Interrupt bit per QSDC channel indicating overflow or underflow in Core credit counter. */ +#define DRAM_DMA_ENGINE_CONFIG__QSDC_CRD_OVF_ERR_INTR_MASK__CH__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QSDC_CRD_OVF_ERR_INTR_MASK__CH__WIDTH (16) +#define DRAM_DMA_ENGINE_CONFIG__QSDC_CRD_OVF_ERR_INTR_MASK__CH__MASK (0x0000FFFFL) +#define DRAM_DMA_ENGINE_CONFIG__QSDC_CRD_OVF_ERR_INTR_MASK__CH__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QSDC_CRD_OVF_ERR_INTR_MASK__CH__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x0000FFFFL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QSDC_CRD_OVF_ERR_INTR_MASK__CH__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x0000FFFFL) | (((uint32_t)(value) << 0) & 0x0000FFFFL)) +#define DRAM_DMA_ENGINE_CONFIG__QSDC_CRD_OVF_ERR_INTR_MASK__CH__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x0000FFFFL) | 0x0000FFFFL) +#define DRAM_DMA_ENGINE_CONFIG__QSDC_CRD_OVF_ERR_INTR_MASK__CH__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x0000FFFFL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QSDC_CRD_OVF_ERR_INTR_STATUS : ch */ +/* Description: Interrupt bit per QSDC channel indicating overflow or underflow in Core credit counter. */ +#define DRAM_DMA_ENGINE_CONFIG__QSDC_CRD_OVF_ERR_INTR_STATUS__CH__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QSDC_CRD_OVF_ERR_INTR_STATUS__CH__WIDTH (16) +#define DRAM_DMA_ENGINE_CONFIG__QSDC_CRD_OVF_ERR_INTR_STATUS__CH__MASK (0x0000FFFFL) +#define DRAM_DMA_ENGINE_CONFIG__QSDC_CRD_OVF_ERR_INTR_STATUS__CH__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QSDC_CRD_OVF_ERR_INTR_STATUS__CH__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x0000FFFFL) >> 0) + +/*----------------------------------------------------------------------------------------------------*/ +/* QSDC_CRD_OVF_ERR_INTR_W1C : ch */ +/* Description: Interrupt bit per QSDC channel indicating overflow or underflow in Core credit counter. */ +#define DRAM_DMA_ENGINE_CONFIG__QSDC_CRD_OVF_ERR_INTR_W1C__CH__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QSDC_CRD_OVF_ERR_INTR_W1C__CH__WIDTH (16) +#define DRAM_DMA_ENGINE_CONFIG__QSDC_CRD_OVF_ERR_INTR_W1C__CH__MASK (0x0000FFFFL) +#define DRAM_DMA_ENGINE_CONFIG__QSDC_CRD_OVF_ERR_INTR_W1C__CH__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QSDC_CRD_OVF_ERR_INTR_W1C__CH__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x0000FFFFL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QSDC_CRD_OVF_ERR_INTR_W1C__CH__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x0000FFFFL) | (((uint32_t)(value) << 0) & 0x0000FFFFL)) +#define DRAM_DMA_ENGINE_CONFIG__QSDC_CRD_OVF_ERR_INTR_W1C__CH__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x0000FFFFL) | 0x0000FFFFL) +#define DRAM_DMA_ENGINE_CONFIG__QSDC_CRD_OVF_ERR_INTR_W1C__CH__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x0000FFFFL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QSDC_CRD_OVF_ERR_INTR_W1S : ch */ +/* Description: Interrupt bit per QSDC channel indicating overflow or underflow in Core credit counter. */ +#define DRAM_DMA_ENGINE_CONFIG__QSDC_CRD_OVF_ERR_INTR_W1S__CH__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QSDC_CRD_OVF_ERR_INTR_W1S__CH__WIDTH (16) +#define DRAM_DMA_ENGINE_CONFIG__QSDC_CRD_OVF_ERR_INTR_W1S__CH__MASK (0x0000FFFFL) +#define DRAM_DMA_ENGINE_CONFIG__QSDC_CRD_OVF_ERR_INTR_W1S__CH__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QSDC_CRD_OVF_ERR_INTR_W1S__CH__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x0000FFFFL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QSDC_CRD_OVF_ERR_INTR_W1S__CH__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x0000FFFFL) | (((uint32_t)(value) << 0) & 0x0000FFFFL)) +#define DRAM_DMA_ENGINE_CONFIG__QSDC_CRD_OVF_ERR_INTR_W1S__CH__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x0000FFFFL) | 0x0000FFFFL) +#define DRAM_DMA_ENGINE_CONFIG__QSDC_CRD_OVF_ERR_INTR_W1S__CH__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x0000FFFFL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* ENGERRINTERRUPTSOURCE : ChannelID */ +#define DRAM_DMA_ENGINE_CONFIG__ENGERRINTERRUPTSOURCE__CHANNELID__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__ENGERRINTERRUPTSOURCE__CHANNELID__WIDTH (4) +#define DRAM_DMA_ENGINE_CONFIG__ENGERRINTERRUPTSOURCE__CHANNELID__MASK (0x0000000FL) +#define DRAM_DMA_ENGINE_CONFIG__ENGERRINTERRUPTSOURCE__CHANNELID__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__ENGERRINTERRUPTSOURCE__CHANNELID__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x0000000FL) >> 0) + +/* ENGERRINTERRUPTSOURCE : Direction */ +/* Description: 0 - Destination. 1 - Source. */ +#define DRAM_DMA_ENGINE_CONFIG__ENGERRINTERRUPTSOURCE__DIRECTION__SHIFT (4) +#define DRAM_DMA_ENGINE_CONFIG__ENGERRINTERRUPTSOURCE__DIRECTION__WIDTH (1) +#define DRAM_DMA_ENGINE_CONFIG__ENGERRINTERRUPTSOURCE__DIRECTION__MASK (0x00000010L) +#define DRAM_DMA_ENGINE_CONFIG__ENGERRINTERRUPTSOURCE__DIRECTION__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__ENGERRINTERRUPTSOURCE__DIRECTION__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x00000010L) >> 4) + +/* ENGERRINTERRUPTSOURCE : Domain */ +/* Description: 0 - Device. 1 - Memory. */ +#define DRAM_DMA_ENGINE_CONFIG__ENGERRINTERRUPTSOURCE__DOMAIN__SHIFT (5) +#define DRAM_DMA_ENGINE_CONFIG__ENGERRINTERRUPTSOURCE__DOMAIN__WIDTH (1) +#define DRAM_DMA_ENGINE_CONFIG__ENGERRINTERRUPTSOURCE__DOMAIN__MASK (0x00000020L) +#define DRAM_DMA_ENGINE_CONFIG__ENGERRINTERRUPTSOURCE__DOMAIN__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__ENGERRINTERRUPTSOURCE__DOMAIN__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x00000020L) >> 5) + +/*----------------------------------------------------------------------------------------------------*/ +/* ENGERRREMAINPAGESIZE : val */ +/* Description: In case of non-zero REMAINING_PAGE_SIZE this register holds the latched value until cleared by writing to this register */ +#define DRAM_DMA_ENGINE_CONFIG__ENGERRREMAINPAGESIZE__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__ENGERRREMAINPAGESIZE__VAL__WIDTH (24) +#define DRAM_DMA_ENGINE_CONFIG__ENGERRREMAINPAGESIZE__VAL__MASK (0x00FFFFFFL) +#define DRAM_DMA_ENGINE_CONFIG__ENGERRREMAINPAGESIZE__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__ENGERRREMAINPAGESIZE__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x00FFFFFFL) >> 0) + +/*----------------------------------------------------------------------------------------------------*/ +/* ENGTRANSFERPAGESIZE : size */ +/* Description: TRANSFERRED_PAGE_SIZE value of last descriptor write to QDMC */ +#define DRAM_DMA_ENGINE_CONFIG__ENGTRANSFERPAGESIZE__SIZE__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__ENGTRANSFERPAGESIZE__SIZE__WIDTH (24) +#define DRAM_DMA_ENGINE_CONFIG__ENGTRANSFERPAGESIZE__SIZE__MASK (0x00FFFFFFL) +#define DRAM_DMA_ENGINE_CONFIG__ENGTRANSFERPAGESIZE__SIZE__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__ENGTRANSFERPAGESIZE__SIZE__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x00FFFFFFL) >> 0) + +/* ENGTRANSFERPAGESIZE : ch_id */ +/* Description: QDMC Channel ID */ +#define DRAM_DMA_ENGINE_CONFIG__ENGTRANSFERPAGESIZE__CH_ID__SHIFT (24) +#define DRAM_DMA_ENGINE_CONFIG__ENGTRANSFERPAGESIZE__CH_ID__WIDTH (4) +#define DRAM_DMA_ENGINE_CONFIG__ENGTRANSFERPAGESIZE__CH_ID__MASK (0x0F000000L) +#define DRAM_DMA_ENGINE_CONFIG__ENGTRANSFERPAGESIZE__CH_ID__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__ENGTRANSFERPAGESIZE__CH_ID__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x0F000000L) >> 24) + +/*----------------------------------------------------------------------------------------------------*/ +/* VDMASOFTRESET : val */ +/* Description: Apply soft reset to vDMA. Must be cleared in order to release vDMA from soft reset. */ +#define DRAM_DMA_ENGINE_CONFIG__VDMASOFTRESET__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__VDMASOFTRESET__VAL__WIDTH (1) +#define DRAM_DMA_ENGINE_CONFIG__VDMASOFTRESET__VAL__MASK (0x00000001L) +#define DRAM_DMA_ENGINE_CONFIG__VDMASOFTRESET__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__VDMASOFTRESET__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x00000001L) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__VDMASOFTRESET__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | (((uint32_t)(value) << 0) & 0x00000001L)) +#define DRAM_DMA_ENGINE_CONFIG__VDMASOFTRESET__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | ((uint32_t)(1) << 0)) +#define DRAM_DMA_ENGINE_CONFIG__VDMASOFTRESET__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | ((uint32_t)(0) << 0)) + +/* VDMASOFTRESET : par */ +#define DRAM_DMA_ENGINE_CONFIG__VDMASOFTRESET__PAR__SHIFT (31) +#define DRAM_DMA_ENGINE_CONFIG__VDMASOFTRESET__PAR__WIDTH (1) +#define DRAM_DMA_ENGINE_CONFIG__VDMASOFTRESET__PAR__MASK (0x80000000L) +#define DRAM_DMA_ENGINE_CONFIG__VDMASOFTRESET__PAR__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__VDMASOFTRESET__PAR__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x80000000L) >> 31) +#define DRAM_DMA_ENGINE_CONFIG__VDMASOFTRESET__PAR__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x80000000L) | (((uint32_t)(value) << 31) & 0x80000000L)) +#define DRAM_DMA_ENGINE_CONFIG__VDMASOFTRESET__PAR__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x80000000L) | ((uint32_t)(1) << 31)) +#define DRAM_DMA_ENGINE_CONFIG__VDMASOFTRESET__PAR__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x80000000L) | ((uint32_t)(0) << 31)) + +/*----------------------------------------------------------------------------------------------------*/ +/* VDMA_SHAREDBUS : cs_mask */ +/* Description: Bit mask on vDMA Sharedbus interrupt source for CS */ +#define DRAM_DMA_ENGINE_CONFIG__VDMA_SHAREDBUS__CS_MASK__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_SHAREDBUS__CS_MASK__WIDTH (4) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_SHAREDBUS__CS_MASK__MASK (0x0000000FL) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_SHAREDBUS__CS_MASK__RESET (0x0000000AL) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_SHAREDBUS__CS_MASK__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x0000000FL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_SHAREDBUS__CS_MASK__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x0000000FL) | (((uint32_t)(value) << 0) & 0x0000000FL)) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_SHAREDBUS__CS_MASK__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x0000000FL) | 0x0000000FL) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_SHAREDBUS__CS_MASK__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x0000000FL)) + +/* VDMA_SHAREDBUS : ap_mask */ +/* Description: Bit mask on vDMA Sharedbus interrupt source for AP */ +#define DRAM_DMA_ENGINE_CONFIG__VDMA_SHAREDBUS__AP_MASK__SHIFT (4) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_SHAREDBUS__AP_MASK__WIDTH (4) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_SHAREDBUS__AP_MASK__MASK (0x000000F0L) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_SHAREDBUS__AP_MASK__RESET (0x00000050L) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_SHAREDBUS__AP_MASK__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x000000F0L) >> 4) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_SHAREDBUS__AP_MASK__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x000000F0L) | (((uint32_t)(value) << 4) & 0x000000F0L)) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_SHAREDBUS__AP_MASK__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x000000F0L) | 0x000000F0L) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_SHAREDBUS__AP_MASK__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x000000F0L)) + +/*----------------------------------------------------------------------------------------------------*/ +/* CFG_QDDC_REDUNDANT_EN : val */ +/* Description: Redundancy mode enable bit per QM pair. bit i makes QM[i*2+1] a redundancy for QM[i*2] */ +#define DRAM_DMA_ENGINE_CONFIG__CFG_QDDC_REDUNDANT_EN__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__CFG_QDDC_REDUNDANT_EN__VAL__WIDTH (8) +#define DRAM_DMA_ENGINE_CONFIG__CFG_QDDC_REDUNDANT_EN__VAL__MASK (0x000000FFL) +#define DRAM_DMA_ENGINE_CONFIG__CFG_QDDC_REDUNDANT_EN__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__CFG_QDDC_REDUNDANT_EN__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x000000FFL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__CFG_QDDC_REDUNDANT_EN__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL) | (((uint32_t)(value) << 0) & 0x000000FFL)) +#define DRAM_DMA_ENGINE_CONFIG__CFG_QDDC_REDUNDANT_EN__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL) | 0x000000FFL) +#define DRAM_DMA_ENGINE_CONFIG__CFG_QDDC_REDUNDANT_EN__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* CFG_QSDC_REDUNDANT_EN : val */ +/* Description: Redundancy mode enable bit per QM pair. bit i makes QM[i*2+1] a redundancy for QM[i*2] */ +#define DRAM_DMA_ENGINE_CONFIG__CFG_QSDC_REDUNDANT_EN__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__CFG_QSDC_REDUNDANT_EN__VAL__WIDTH (8) +#define DRAM_DMA_ENGINE_CONFIG__CFG_QSDC_REDUNDANT_EN__VAL__MASK (0x000000FFL) +#define DRAM_DMA_ENGINE_CONFIG__CFG_QSDC_REDUNDANT_EN__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__CFG_QSDC_REDUNDANT_EN__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x000000FFL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__CFG_QSDC_REDUNDANT_EN__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL) | (((uint32_t)(value) << 0) & 0x000000FFL)) +#define DRAM_DMA_ENGINE_CONFIG__CFG_QSDC_REDUNDANT_EN__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL) | 0x000000FFL) +#define DRAM_DMA_ENGINE_CONFIG__CFG_QSDC_REDUNDANT_EN__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* CFG_QDMC_REDUNDANT_EN : val */ +/* Description: Redundancy mode enable bit per QM pair. bit i makes QM[i*2+1] a redundancy for QM[i*2] */ +#define DRAM_DMA_ENGINE_CONFIG__CFG_QDMC_REDUNDANT_EN__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__CFG_QDMC_REDUNDANT_EN__VAL__WIDTH (8) +#define DRAM_DMA_ENGINE_CONFIG__CFG_QDMC_REDUNDANT_EN__VAL__MASK (0x000000FFL) +#define DRAM_DMA_ENGINE_CONFIG__CFG_QDMC_REDUNDANT_EN__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__CFG_QDMC_REDUNDANT_EN__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x000000FFL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__CFG_QDMC_REDUNDANT_EN__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL) | (((uint32_t)(value) << 0) & 0x000000FFL)) +#define DRAM_DMA_ENGINE_CONFIG__CFG_QDMC_REDUNDANT_EN__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL) | 0x000000FFL) +#define DRAM_DMA_ENGINE_CONFIG__CFG_QDMC_REDUNDANT_EN__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* CFG_QSMC_REDUNDANT_EN : val */ +/* Description: Redundancy mode enable bit per QM pair. bit i makes QM[i*2+1] a redundancy for QM[i*2] */ +#define DRAM_DMA_ENGINE_CONFIG__CFG_QSMC_REDUNDANT_EN__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__CFG_QSMC_REDUNDANT_EN__VAL__WIDTH (8) +#define DRAM_DMA_ENGINE_CONFIG__CFG_QSMC_REDUNDANT_EN__VAL__MASK (0x000000FFL) +#define DRAM_DMA_ENGINE_CONFIG__CFG_QSMC_REDUNDANT_EN__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__CFG_QSMC_REDUNDANT_EN__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x000000FFL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__CFG_QSMC_REDUNDANT_EN__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL) | (((uint32_t)(value) << 0) & 0x000000FFL)) +#define DRAM_DMA_ENGINE_CONFIG__CFG_QSMC_REDUNDANT_EN__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL) | 0x000000FFL) +#define DRAM_DMA_ENGINE_CONFIG__CFG_QSMC_REDUNDANT_EN__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QDDC_REDUNDANT_ASF_INT_MASK : val */ +/* Description: Redundancy mode compare mismatch for QM pair i */ +#define DRAM_DMA_ENGINE_CONFIG__QDDC_REDUNDANT_ASF_INT_MASK__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QDDC_REDUNDANT_ASF_INT_MASK__VAL__WIDTH (8) +#define DRAM_DMA_ENGINE_CONFIG__QDDC_REDUNDANT_ASF_INT_MASK__VAL__MASK (0x000000FFL) +#define DRAM_DMA_ENGINE_CONFIG__QDDC_REDUNDANT_ASF_INT_MASK__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QDDC_REDUNDANT_ASF_INT_MASK__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x000000FFL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QDDC_REDUNDANT_ASF_INT_MASK__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL) | (((uint32_t)(value) << 0) & 0x000000FFL)) +#define DRAM_DMA_ENGINE_CONFIG__QDDC_REDUNDANT_ASF_INT_MASK__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL) | 0x000000FFL) +#define DRAM_DMA_ENGINE_CONFIG__QDDC_REDUNDANT_ASF_INT_MASK__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QDDC_REDUNDANT_ASF_INT_STATUS : val */ +/* Description: Redundancy mode compare mismatch for QM pair i */ +#define DRAM_DMA_ENGINE_CONFIG__QDDC_REDUNDANT_ASF_INT_STATUS__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QDDC_REDUNDANT_ASF_INT_STATUS__VAL__WIDTH (8) +#define DRAM_DMA_ENGINE_CONFIG__QDDC_REDUNDANT_ASF_INT_STATUS__VAL__MASK (0x000000FFL) +#define DRAM_DMA_ENGINE_CONFIG__QDDC_REDUNDANT_ASF_INT_STATUS__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QDDC_REDUNDANT_ASF_INT_STATUS__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x000000FFL) >> 0) + +/*----------------------------------------------------------------------------------------------------*/ +/* QDDC_REDUNDANT_ASF_INT_W1C : val */ +/* Description: Redundancy mode compare mismatch for QM pair i */ +#define DRAM_DMA_ENGINE_CONFIG__QDDC_REDUNDANT_ASF_INT_W1C__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QDDC_REDUNDANT_ASF_INT_W1C__VAL__WIDTH (8) +#define DRAM_DMA_ENGINE_CONFIG__QDDC_REDUNDANT_ASF_INT_W1C__VAL__MASK (0x000000FFL) +#define DRAM_DMA_ENGINE_CONFIG__QDDC_REDUNDANT_ASF_INT_W1C__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QDDC_REDUNDANT_ASF_INT_W1C__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x000000FFL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QDDC_REDUNDANT_ASF_INT_W1C__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL) | (((uint32_t)(value) << 0) & 0x000000FFL)) +#define DRAM_DMA_ENGINE_CONFIG__QDDC_REDUNDANT_ASF_INT_W1C__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL) | 0x000000FFL) +#define DRAM_DMA_ENGINE_CONFIG__QDDC_REDUNDANT_ASF_INT_W1C__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QDDC_REDUNDANT_ASF_INT_W1S : val */ +/* Description: Redundancy mode compare mismatch for QM pair i */ +#define DRAM_DMA_ENGINE_CONFIG__QDDC_REDUNDANT_ASF_INT_W1S__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QDDC_REDUNDANT_ASF_INT_W1S__VAL__WIDTH (8) +#define DRAM_DMA_ENGINE_CONFIG__QDDC_REDUNDANT_ASF_INT_W1S__VAL__MASK (0x000000FFL) +#define DRAM_DMA_ENGINE_CONFIG__QDDC_REDUNDANT_ASF_INT_W1S__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QDDC_REDUNDANT_ASF_INT_W1S__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x000000FFL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QDDC_REDUNDANT_ASF_INT_W1S__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL) | (((uint32_t)(value) << 0) & 0x000000FFL)) +#define DRAM_DMA_ENGINE_CONFIG__QDDC_REDUNDANT_ASF_INT_W1S__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL) | 0x000000FFL) +#define DRAM_DMA_ENGINE_CONFIG__QDDC_REDUNDANT_ASF_INT_W1S__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QSDC_REDUNDANT_ASF_INT_MASK : val */ +/* Description: Redundancy mode compare mismatch for QM pair i */ +#define DRAM_DMA_ENGINE_CONFIG__QSDC_REDUNDANT_ASF_INT_MASK__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QSDC_REDUNDANT_ASF_INT_MASK__VAL__WIDTH (8) +#define DRAM_DMA_ENGINE_CONFIG__QSDC_REDUNDANT_ASF_INT_MASK__VAL__MASK (0x000000FFL) +#define DRAM_DMA_ENGINE_CONFIG__QSDC_REDUNDANT_ASF_INT_MASK__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QSDC_REDUNDANT_ASF_INT_MASK__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x000000FFL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QSDC_REDUNDANT_ASF_INT_MASK__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL) | (((uint32_t)(value) << 0) & 0x000000FFL)) +#define DRAM_DMA_ENGINE_CONFIG__QSDC_REDUNDANT_ASF_INT_MASK__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL) | 0x000000FFL) +#define DRAM_DMA_ENGINE_CONFIG__QSDC_REDUNDANT_ASF_INT_MASK__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QSDC_REDUNDANT_ASF_INT_STATUS : val */ +/* Description: Redundancy mode compare mismatch for QM pair i */ +#define DRAM_DMA_ENGINE_CONFIG__QSDC_REDUNDANT_ASF_INT_STATUS__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QSDC_REDUNDANT_ASF_INT_STATUS__VAL__WIDTH (8) +#define DRAM_DMA_ENGINE_CONFIG__QSDC_REDUNDANT_ASF_INT_STATUS__VAL__MASK (0x000000FFL) +#define DRAM_DMA_ENGINE_CONFIG__QSDC_REDUNDANT_ASF_INT_STATUS__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QSDC_REDUNDANT_ASF_INT_STATUS__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x000000FFL) >> 0) + +/*----------------------------------------------------------------------------------------------------*/ +/* QSDC_REDUNDANT_ASF_INT_W1C : val */ +/* Description: Redundancy mode compare mismatch for QM pair i */ +#define DRAM_DMA_ENGINE_CONFIG__QSDC_REDUNDANT_ASF_INT_W1C__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QSDC_REDUNDANT_ASF_INT_W1C__VAL__WIDTH (8) +#define DRAM_DMA_ENGINE_CONFIG__QSDC_REDUNDANT_ASF_INT_W1C__VAL__MASK (0x000000FFL) +#define DRAM_DMA_ENGINE_CONFIG__QSDC_REDUNDANT_ASF_INT_W1C__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QSDC_REDUNDANT_ASF_INT_W1C__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x000000FFL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QSDC_REDUNDANT_ASF_INT_W1C__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL) | (((uint32_t)(value) << 0) & 0x000000FFL)) +#define DRAM_DMA_ENGINE_CONFIG__QSDC_REDUNDANT_ASF_INT_W1C__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL) | 0x000000FFL) +#define DRAM_DMA_ENGINE_CONFIG__QSDC_REDUNDANT_ASF_INT_W1C__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QSDC_REDUNDANT_ASF_INT_W1S : val */ +/* Description: Redundancy mode compare mismatch for QM pair i */ +#define DRAM_DMA_ENGINE_CONFIG__QSDC_REDUNDANT_ASF_INT_W1S__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QSDC_REDUNDANT_ASF_INT_W1S__VAL__WIDTH (8) +#define DRAM_DMA_ENGINE_CONFIG__QSDC_REDUNDANT_ASF_INT_W1S__VAL__MASK (0x000000FFL) +#define DRAM_DMA_ENGINE_CONFIG__QSDC_REDUNDANT_ASF_INT_W1S__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QSDC_REDUNDANT_ASF_INT_W1S__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x000000FFL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QSDC_REDUNDANT_ASF_INT_W1S__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL) | (((uint32_t)(value) << 0) & 0x000000FFL)) +#define DRAM_DMA_ENGINE_CONFIG__QSDC_REDUNDANT_ASF_INT_W1S__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL) | 0x000000FFL) +#define DRAM_DMA_ENGINE_CONFIG__QSDC_REDUNDANT_ASF_INT_W1S__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QDMC_REDUNDANT_ASF_INT_MASK : val */ +/* Description: Redundancy mode compare mismatch for QM pair i */ +#define DRAM_DMA_ENGINE_CONFIG__QDMC_REDUNDANT_ASF_INT_MASK__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QDMC_REDUNDANT_ASF_INT_MASK__VAL__WIDTH (8) +#define DRAM_DMA_ENGINE_CONFIG__QDMC_REDUNDANT_ASF_INT_MASK__VAL__MASK (0x000000FFL) +#define DRAM_DMA_ENGINE_CONFIG__QDMC_REDUNDANT_ASF_INT_MASK__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QDMC_REDUNDANT_ASF_INT_MASK__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x000000FFL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QDMC_REDUNDANT_ASF_INT_MASK__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL) | (((uint32_t)(value) << 0) & 0x000000FFL)) +#define DRAM_DMA_ENGINE_CONFIG__QDMC_REDUNDANT_ASF_INT_MASK__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL) | 0x000000FFL) +#define DRAM_DMA_ENGINE_CONFIG__QDMC_REDUNDANT_ASF_INT_MASK__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QDMC_REDUNDANT_ASF_INT_STATUS : val */ +/* Description: Redundancy mode compare mismatch for QM pair i */ +#define DRAM_DMA_ENGINE_CONFIG__QDMC_REDUNDANT_ASF_INT_STATUS__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QDMC_REDUNDANT_ASF_INT_STATUS__VAL__WIDTH (8) +#define DRAM_DMA_ENGINE_CONFIG__QDMC_REDUNDANT_ASF_INT_STATUS__VAL__MASK (0x000000FFL) +#define DRAM_DMA_ENGINE_CONFIG__QDMC_REDUNDANT_ASF_INT_STATUS__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QDMC_REDUNDANT_ASF_INT_STATUS__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x000000FFL) >> 0) + +/*----------------------------------------------------------------------------------------------------*/ +/* QDMC_REDUNDANT_ASF_INT_W1C : val */ +/* Description: Redundancy mode compare mismatch for QM pair i */ +#define DRAM_DMA_ENGINE_CONFIG__QDMC_REDUNDANT_ASF_INT_W1C__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QDMC_REDUNDANT_ASF_INT_W1C__VAL__WIDTH (8) +#define DRAM_DMA_ENGINE_CONFIG__QDMC_REDUNDANT_ASF_INT_W1C__VAL__MASK (0x000000FFL) +#define DRAM_DMA_ENGINE_CONFIG__QDMC_REDUNDANT_ASF_INT_W1C__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QDMC_REDUNDANT_ASF_INT_W1C__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x000000FFL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QDMC_REDUNDANT_ASF_INT_W1C__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL) | (((uint32_t)(value) << 0) & 0x000000FFL)) +#define DRAM_DMA_ENGINE_CONFIG__QDMC_REDUNDANT_ASF_INT_W1C__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL) | 0x000000FFL) +#define DRAM_DMA_ENGINE_CONFIG__QDMC_REDUNDANT_ASF_INT_W1C__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QDMC_REDUNDANT_ASF_INT_W1S : val */ +/* Description: Redundancy mode compare mismatch for QM pair i */ +#define DRAM_DMA_ENGINE_CONFIG__QDMC_REDUNDANT_ASF_INT_W1S__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QDMC_REDUNDANT_ASF_INT_W1S__VAL__WIDTH (8) +#define DRAM_DMA_ENGINE_CONFIG__QDMC_REDUNDANT_ASF_INT_W1S__VAL__MASK (0x000000FFL) +#define DRAM_DMA_ENGINE_CONFIG__QDMC_REDUNDANT_ASF_INT_W1S__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QDMC_REDUNDANT_ASF_INT_W1S__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x000000FFL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QDMC_REDUNDANT_ASF_INT_W1S__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL) | (((uint32_t)(value) << 0) & 0x000000FFL)) +#define DRAM_DMA_ENGINE_CONFIG__QDMC_REDUNDANT_ASF_INT_W1S__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL) | 0x000000FFL) +#define DRAM_DMA_ENGINE_CONFIG__QDMC_REDUNDANT_ASF_INT_W1S__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QSMC_REDUNDANT_ASF_INT_MASK : val */ +/* Description: Redundancy mode compare mismatch for QM pair i */ +#define DRAM_DMA_ENGINE_CONFIG__QSMC_REDUNDANT_ASF_INT_MASK__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QSMC_REDUNDANT_ASF_INT_MASK__VAL__WIDTH (8) +#define DRAM_DMA_ENGINE_CONFIG__QSMC_REDUNDANT_ASF_INT_MASK__VAL__MASK (0x000000FFL) +#define DRAM_DMA_ENGINE_CONFIG__QSMC_REDUNDANT_ASF_INT_MASK__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QSMC_REDUNDANT_ASF_INT_MASK__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x000000FFL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QSMC_REDUNDANT_ASF_INT_MASK__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL) | (((uint32_t)(value) << 0) & 0x000000FFL)) +#define DRAM_DMA_ENGINE_CONFIG__QSMC_REDUNDANT_ASF_INT_MASK__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL) | 0x000000FFL) +#define DRAM_DMA_ENGINE_CONFIG__QSMC_REDUNDANT_ASF_INT_MASK__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QSMC_REDUNDANT_ASF_INT_STATUS : val */ +/* Description: Redundancy mode compare mismatch for QM pair i */ +#define DRAM_DMA_ENGINE_CONFIG__QSMC_REDUNDANT_ASF_INT_STATUS__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QSMC_REDUNDANT_ASF_INT_STATUS__VAL__WIDTH (8) +#define DRAM_DMA_ENGINE_CONFIG__QSMC_REDUNDANT_ASF_INT_STATUS__VAL__MASK (0x000000FFL) +#define DRAM_DMA_ENGINE_CONFIG__QSMC_REDUNDANT_ASF_INT_STATUS__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QSMC_REDUNDANT_ASF_INT_STATUS__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x000000FFL) >> 0) + +/*----------------------------------------------------------------------------------------------------*/ +/* QSMC_REDUNDANT_ASF_INT_W1C : val */ +/* Description: Redundancy mode compare mismatch for QM pair i */ +#define DRAM_DMA_ENGINE_CONFIG__QSMC_REDUNDANT_ASF_INT_W1C__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QSMC_REDUNDANT_ASF_INT_W1C__VAL__WIDTH (8) +#define DRAM_DMA_ENGINE_CONFIG__QSMC_REDUNDANT_ASF_INT_W1C__VAL__MASK (0x000000FFL) +#define DRAM_DMA_ENGINE_CONFIG__QSMC_REDUNDANT_ASF_INT_W1C__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QSMC_REDUNDANT_ASF_INT_W1C__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x000000FFL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QSMC_REDUNDANT_ASF_INT_W1C__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL) | (((uint32_t)(value) << 0) & 0x000000FFL)) +#define DRAM_DMA_ENGINE_CONFIG__QSMC_REDUNDANT_ASF_INT_W1C__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL) | 0x000000FFL) +#define DRAM_DMA_ENGINE_CONFIG__QSMC_REDUNDANT_ASF_INT_W1C__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QSMC_REDUNDANT_ASF_INT_W1S : val */ +/* Description: Redundancy mode compare mismatch for QM pair i */ +#define DRAM_DMA_ENGINE_CONFIG__QSMC_REDUNDANT_ASF_INT_W1S__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QSMC_REDUNDANT_ASF_INT_W1S__VAL__WIDTH (8) +#define DRAM_DMA_ENGINE_CONFIG__QSMC_REDUNDANT_ASF_INT_W1S__VAL__MASK (0x000000FFL) +#define DRAM_DMA_ENGINE_CONFIG__QSMC_REDUNDANT_ASF_INT_W1S__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QSMC_REDUNDANT_ASF_INT_W1S__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x000000FFL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QSMC_REDUNDANT_ASF_INT_W1S__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL) | (((uint32_t)(value) << 0) & 0x000000FFL)) +#define DRAM_DMA_ENGINE_CONFIG__QSMC_REDUNDANT_ASF_INT_W1S__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL) | 0x000000FFL) +#define DRAM_DMA_ENGINE_CONFIG__QSMC_REDUNDANT_ASF_INT_W1S__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x000000FFL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* PRIOISLP : val */ +/* Description: Indicates channel priority is low priority. */ +#define DRAM_DMA_ENGINE_CONFIG__PRIOISLP__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__PRIOISLP__VAL__WIDTH (32) +#define DRAM_DMA_ENGINE_CONFIG__PRIOISLP__VAL__MASK (0xFFFFFFFFL) +#define DRAM_DMA_ENGINE_CONFIG__PRIOISLP__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__PRIOISLP__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0xFFFFFFFFL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__PRIOISLP__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0xFFFFFFFFL) | (((uint32_t)(value) << 0) & 0xFFFFFFFFL)) +#define DRAM_DMA_ENGINE_CONFIG__PRIOISLP__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0xFFFFFFFFL) | 0xFFFFFFFFL) +#define DRAM_DMA_ENGINE_CONFIG__PRIOISLP__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0xFFFFFFFFL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* READLPTOQOSVALUE : val */ +/* Description: The QOS toward DDR-AXI master for low priority read. */ +#define DRAM_DMA_ENGINE_CONFIG__READLPTOQOSVALUE__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__READLPTOQOSVALUE__VAL__WIDTH (3) +#define DRAM_DMA_ENGINE_CONFIG__READLPTOQOSVALUE__VAL__MASK (0x00000007L) +#define DRAM_DMA_ENGINE_CONFIG__READLPTOQOSVALUE__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__READLPTOQOSVALUE__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x00000007L) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__READLPTOQOSVALUE__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x00000007L) | (((uint32_t)(value) << 0) & 0x00000007L)) +#define DRAM_DMA_ENGINE_CONFIG__READLPTOQOSVALUE__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000007L) | 0x00000007L) +#define DRAM_DMA_ENGINE_CONFIG__READLPTOQOSVALUE__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000007L)) + +/*----------------------------------------------------------------------------------------------------*/ +/* READHPTOQOSVALUE : val */ +/* Description: The QOS toward DDR-AXI master for high priority read. */ +#define DRAM_DMA_ENGINE_CONFIG__READHPTOQOSVALUE__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__READHPTOQOSVALUE__VAL__WIDTH (3) +#define DRAM_DMA_ENGINE_CONFIG__READHPTOQOSVALUE__VAL__MASK (0x00000007L) +#define DRAM_DMA_ENGINE_CONFIG__READHPTOQOSVALUE__VAL__RESET (0x00000002L) +#define DRAM_DMA_ENGINE_CONFIG__READHPTOQOSVALUE__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x00000007L) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__READHPTOQOSVALUE__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x00000007L) | (((uint32_t)(value) << 0) & 0x00000007L)) +#define DRAM_DMA_ENGINE_CONFIG__READHPTOQOSVALUE__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000007L) | 0x00000007L) +#define DRAM_DMA_ENGINE_CONFIG__READHPTOQOSVALUE__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000007L)) + +/*----------------------------------------------------------------------------------------------------*/ +/* WRITELPTOQOSVALUE : val */ +/* Description: The QOS toward DDR-AXI master for low priority write. */ +#define DRAM_DMA_ENGINE_CONFIG__WRITELPTOQOSVALUE__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__WRITELPTOQOSVALUE__VAL__WIDTH (3) +#define DRAM_DMA_ENGINE_CONFIG__WRITELPTOQOSVALUE__VAL__MASK (0x00000007L) +#define DRAM_DMA_ENGINE_CONFIG__WRITELPTOQOSVALUE__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__WRITELPTOQOSVALUE__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x00000007L) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__WRITELPTOQOSVALUE__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x00000007L) | (((uint32_t)(value) << 0) & 0x00000007L)) +#define DRAM_DMA_ENGINE_CONFIG__WRITELPTOQOSVALUE__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000007L) | 0x00000007L) +#define DRAM_DMA_ENGINE_CONFIG__WRITELPTOQOSVALUE__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000007L)) + +/*----------------------------------------------------------------------------------------------------*/ +/* WRITEHPTOQOSVALUE : val */ +/* Description: The QOS toward DDR-AXI master for high priority write. */ +#define DRAM_DMA_ENGINE_CONFIG__WRITEHPTOQOSVALUE__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__WRITEHPTOQOSVALUE__VAL__WIDTH (3) +#define DRAM_DMA_ENGINE_CONFIG__WRITEHPTOQOSVALUE__VAL__MASK (0x00000007L) +#define DRAM_DMA_ENGINE_CONFIG__WRITEHPTOQOSVALUE__VAL__RESET (0x00000002L) +#define DRAM_DMA_ENGINE_CONFIG__WRITEHPTOQOSVALUE__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x00000007L) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__WRITEHPTOQOSVALUE__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x00000007L) | (((uint32_t)(value) << 0) & 0x00000007L)) +#define DRAM_DMA_ENGINE_CONFIG__WRITEHPTOQOSVALUE__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000007L) | 0x00000007L) +#define DRAM_DMA_ENGINE_CONFIG__WRITEHPTOQOSVALUE__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000007L)) + +/*----------------------------------------------------------------------------------------------------*/ +/* DESCREADQOSVALUE : val */ +/* Description: The QOS toward DDR-desc-AXI master for read. */ +#define DRAM_DMA_ENGINE_CONFIG__DESCREADQOSVALUE__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__DESCREADQOSVALUE__VAL__WIDTH (3) +#define DRAM_DMA_ENGINE_CONFIG__DESCREADQOSVALUE__VAL__MASK (0x00000007L) +#define DRAM_DMA_ENGINE_CONFIG__DESCREADQOSVALUE__VAL__RESET (0x00000002L) +#define DRAM_DMA_ENGINE_CONFIG__DESCREADQOSVALUE__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x00000007L) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__DESCREADQOSVALUE__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x00000007L) | (((uint32_t)(value) << 0) & 0x00000007L)) +#define DRAM_DMA_ENGINE_CONFIG__DESCREADQOSVALUE__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000007L) | 0x00000007L) +#define DRAM_DMA_ENGINE_CONFIG__DESCREADQOSVALUE__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000007L)) + +/*----------------------------------------------------------------------------------------------------*/ +/* DESCWRITEQOSVALUE : val */ +/* Description: The QOS toward DDR-desc-AXI master for write. */ +#define DRAM_DMA_ENGINE_CONFIG__DESCWRITEQOSVALUE__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__DESCWRITEQOSVALUE__VAL__WIDTH (3) +#define DRAM_DMA_ENGINE_CONFIG__DESCWRITEQOSVALUE__VAL__MASK (0x00000007L) +#define DRAM_DMA_ENGINE_CONFIG__DESCWRITEQOSVALUE__VAL__RESET (0x00000002L) +#define DRAM_DMA_ENGINE_CONFIG__DESCWRITEQOSVALUE__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x00000007L) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__DESCWRITEQOSVALUE__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x00000007L) | (((uint32_t)(value) << 0) & 0x00000007L)) +#define DRAM_DMA_ENGINE_CONFIG__DESCWRITEQOSVALUE__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000007L) | 0x00000007L) +#define DRAM_DMA_ENGINE_CONFIG__DESCWRITEQOSVALUE__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000007L)) + +/*----------------------------------------------------------------------------------------------------*/ +/* VDMA_ARB : prio_en */ +/* Description: Enable 2 level priority based channel arbitration in vDMA */ +#define DRAM_DMA_ENGINE_CONFIG__VDMA_ARB__PRIO_EN__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_ARB__PRIO_EN__WIDTH (1) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_ARB__PRIO_EN__MASK (0x00000001L) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_ARB__PRIO_EN__RESET (0x00000001L) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_ARB__PRIO_EN__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x00000001L) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_ARB__PRIO_EN__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | (((uint32_t)(value) << 0) & 0x00000001L)) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_ARB__PRIO_EN__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | ((uint32_t)(1) << 0)) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_ARB__PRIO_EN__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | ((uint32_t)(0) << 0)) + +/* VDMA_ARB : interleave_en */ +/* Description: Enable arbitration order to interleave between M2D and D2M channels */ +#define DRAM_DMA_ENGINE_CONFIG__VDMA_ARB__INTERLEAVE_EN__SHIFT (1) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_ARB__INTERLEAVE_EN__WIDTH (1) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_ARB__INTERLEAVE_EN__MASK (0x00000002L) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_ARB__INTERLEAVE_EN__RESET (0x00000002L) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_ARB__INTERLEAVE_EN__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x00000002L) >> 1) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_ARB__INTERLEAVE_EN__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x00000002L) | (((uint32_t)(value) << 1) & 0x00000002L)) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_ARB__INTERLEAVE_EN__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000002L) | ((uint32_t)(1) << 1)) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_ARB__INTERLEAVE_EN__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000002L) | ((uint32_t)(0) << 1)) + +/* VDMA_ARB : par */ +#define DRAM_DMA_ENGINE_CONFIG__VDMA_ARB__PAR__SHIFT (31) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_ARB__PAR__WIDTH (1) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_ARB__PAR__MASK (0x80000000L) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_ARB__PAR__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_ARB__PAR__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x80000000L) >> 31) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_ARB__PAR__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x80000000L) | (((uint32_t)(value) << 31) & 0x80000000L)) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_ARB__PAR__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x80000000L) | ((uint32_t)(1) << 31)) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_ARB__PAR__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x80000000L) | ((uint32_t)(0) << 31)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QM_CFG_CG_DELAY : val */ +/* Description: Clock cycles to keep clock running after enable condition is met */ +#define DRAM_DMA_ENGINE_CONFIG__QM_CFG_CG_DELAY__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QM_CFG_CG_DELAY__VAL__WIDTH (4) +#define DRAM_DMA_ENGINE_CONFIG__QM_CFG_CG_DELAY__VAL__MASK (0x0000000FL) +#define DRAM_DMA_ENGINE_CONFIG__QM_CFG_CG_DELAY__VAL__RESET (0x00000001L) +#define DRAM_DMA_ENGINE_CONFIG__QM_CFG_CG_DELAY__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x0000000FL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QM_CFG_CG_DELAY__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x0000000FL) | (((uint32_t)(value) << 0) & 0x0000000FL)) +#define DRAM_DMA_ENGINE_CONFIG__QM_CFG_CG_DELAY__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x0000000FL) | 0x0000000FL) +#define DRAM_DMA_ENGINE_CONFIG__QM_CFG_CG_DELAY__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x0000000FL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QDDC_CFG_CG_BYPASS : val */ +/* Description: Bypass QDDC CG */ +#define DRAM_DMA_ENGINE_CONFIG__QDDC_CFG_CG_BYPASS__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QDDC_CFG_CG_BYPASS__VAL__WIDTH (16) +#define DRAM_DMA_ENGINE_CONFIG__QDDC_CFG_CG_BYPASS__VAL__MASK (0x0000FFFFL) +#define DRAM_DMA_ENGINE_CONFIG__QDDC_CFG_CG_BYPASS__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QDDC_CFG_CG_BYPASS__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x0000FFFFL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QDDC_CFG_CG_BYPASS__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x0000FFFFL) | (((uint32_t)(value) << 0) & 0x0000FFFFL)) +#define DRAM_DMA_ENGINE_CONFIG__QDDC_CFG_CG_BYPASS__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x0000FFFFL) | 0x0000FFFFL) +#define DRAM_DMA_ENGINE_CONFIG__QDDC_CFG_CG_BYPASS__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x0000FFFFL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QSDC_CFG_CG_BYPASS : val */ +/* Description: Bypass QSDC CG */ +#define DRAM_DMA_ENGINE_CONFIG__QSDC_CFG_CG_BYPASS__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QSDC_CFG_CG_BYPASS__VAL__WIDTH (16) +#define DRAM_DMA_ENGINE_CONFIG__QSDC_CFG_CG_BYPASS__VAL__MASK (0x0000FFFFL) +#define DRAM_DMA_ENGINE_CONFIG__QSDC_CFG_CG_BYPASS__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QSDC_CFG_CG_BYPASS__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x0000FFFFL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QSDC_CFG_CG_BYPASS__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x0000FFFFL) | (((uint32_t)(value) << 0) & 0x0000FFFFL)) +#define DRAM_DMA_ENGINE_CONFIG__QSDC_CFG_CG_BYPASS__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x0000FFFFL) | 0x0000FFFFL) +#define DRAM_DMA_ENGINE_CONFIG__QSDC_CFG_CG_BYPASS__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x0000FFFFL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QDMC_CFG_CG_BYPASS : val */ +/* Description: Bypass QDMC CG */ +#define DRAM_DMA_ENGINE_CONFIG__QDMC_CFG_CG_BYPASS__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QDMC_CFG_CG_BYPASS__VAL__WIDTH (16) +#define DRAM_DMA_ENGINE_CONFIG__QDMC_CFG_CG_BYPASS__VAL__MASK (0x0000FFFFL) +#define DRAM_DMA_ENGINE_CONFIG__QDMC_CFG_CG_BYPASS__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QDMC_CFG_CG_BYPASS__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x0000FFFFL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QDMC_CFG_CG_BYPASS__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x0000FFFFL) | (((uint32_t)(value) << 0) & 0x0000FFFFL)) +#define DRAM_DMA_ENGINE_CONFIG__QDMC_CFG_CG_BYPASS__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x0000FFFFL) | 0x0000FFFFL) +#define DRAM_DMA_ENGINE_CONFIG__QDMC_CFG_CG_BYPASS__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x0000FFFFL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* QSMC_CFG_CG_BYPASS : val */ +/* Description: Bypass QSMC CG */ +#define DRAM_DMA_ENGINE_CONFIG__QSMC_CFG_CG_BYPASS__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__QSMC_CFG_CG_BYPASS__VAL__WIDTH (16) +#define DRAM_DMA_ENGINE_CONFIG__QSMC_CFG_CG_BYPASS__VAL__MASK (0x0000FFFFL) +#define DRAM_DMA_ENGINE_CONFIG__QSMC_CFG_CG_BYPASS__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__QSMC_CFG_CG_BYPASS__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x0000FFFFL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__QSMC_CFG_CG_BYPASS__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x0000FFFFL) | (((uint32_t)(value) << 0) & 0x0000FFFFL)) +#define DRAM_DMA_ENGINE_CONFIG__QSMC_CFG_CG_BYPASS__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x0000FFFFL) | 0x0000FFFFL) +#define DRAM_DMA_ENGINE_CONFIG__QSMC_CFG_CG_BYPASS__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x0000FFFFL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* ENGINE_ASF_INT_MASK : parity_error_in_regfile */ +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ASF_INT_MASK__PARITY_ERROR_IN_REGFILE__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ASF_INT_MASK__PARITY_ERROR_IN_REGFILE__WIDTH (1) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ASF_INT_MASK__PARITY_ERROR_IN_REGFILE__MASK (0x00000001L) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ASF_INT_MASK__PARITY_ERROR_IN_REGFILE__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ASF_INT_MASK__PARITY_ERROR_IN_REGFILE__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x00000001L) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ASF_INT_MASK__PARITY_ERROR_IN_REGFILE__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | (((uint32_t)(value) << 0) & 0x00000001L)) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ASF_INT_MASK__PARITY_ERROR_IN_REGFILE__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | ((uint32_t)(1) << 0)) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ASF_INT_MASK__PARITY_ERROR_IN_REGFILE__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | ((uint32_t)(0) << 0)) + +/*----------------------------------------------------------------------------------------------------*/ +/* ENGINE_ASF_INT_STATUS : parity_error_in_regfile */ +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ASF_INT_STATUS__PARITY_ERROR_IN_REGFILE__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ASF_INT_STATUS__PARITY_ERROR_IN_REGFILE__WIDTH (1) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ASF_INT_STATUS__PARITY_ERROR_IN_REGFILE__MASK (0x00000001L) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ASF_INT_STATUS__PARITY_ERROR_IN_REGFILE__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ASF_INT_STATUS__PARITY_ERROR_IN_REGFILE__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x00000001L) >> 0) + +/*----------------------------------------------------------------------------------------------------*/ +/* ENGINE_ASF_INT_W1C : parity_error_in_regfile */ +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ASF_INT_W1C__PARITY_ERROR_IN_REGFILE__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ASF_INT_W1C__PARITY_ERROR_IN_REGFILE__WIDTH (1) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ASF_INT_W1C__PARITY_ERROR_IN_REGFILE__MASK (0x00000001L) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ASF_INT_W1C__PARITY_ERROR_IN_REGFILE__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ASF_INT_W1C__PARITY_ERROR_IN_REGFILE__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x00000001L) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ASF_INT_W1C__PARITY_ERROR_IN_REGFILE__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | (((uint32_t)(value) << 0) & 0x00000001L)) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ASF_INT_W1C__PARITY_ERROR_IN_REGFILE__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | ((uint32_t)(1) << 0)) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ASF_INT_W1C__PARITY_ERROR_IN_REGFILE__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | ((uint32_t)(0) << 0)) + +/*----------------------------------------------------------------------------------------------------*/ +/* ENGINE_ASF_INT_W1S : parity_error_in_regfile */ +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ASF_INT_W1S__PARITY_ERROR_IN_REGFILE__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ASF_INT_W1S__PARITY_ERROR_IN_REGFILE__WIDTH (1) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ASF_INT_W1S__PARITY_ERROR_IN_REGFILE__MASK (0x00000001L) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ASF_INT_W1S__PARITY_ERROR_IN_REGFILE__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ASF_INT_W1S__PARITY_ERROR_IN_REGFILE__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x00000001L) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ASF_INT_W1S__PARITY_ERROR_IN_REGFILE__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | (((uint32_t)(value) << 0) & 0x00000001L)) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ASF_INT_W1S__PARITY_ERROR_IN_REGFILE__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | ((uint32_t)(1) << 0)) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_ASF_INT_W1S__PARITY_ERROR_IN_REGFILE__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | ((uint32_t)(0) << 0)) + +/*----------------------------------------------------------------------------------------------------*/ +/* ENGINE_RW_PARITY_BIST_MODE : val */ +/* Description: write 1 if want to work in rw_parity bist mode in which the parity bit is written by APB wdata and not from HW calculation */ +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_RW_PARITY_BIST_MODE__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_RW_PARITY_BIST_MODE__VAL__WIDTH (1) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_RW_PARITY_BIST_MODE__VAL__MASK (0x00000001L) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_RW_PARITY_BIST_MODE__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_RW_PARITY_BIST_MODE__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x00000001L) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_RW_PARITY_BIST_MODE__VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | (((uint32_t)(value) << 0) & 0x00000001L)) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_RW_PARITY_BIST_MODE__VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | ((uint32_t)(1) << 0)) +#define DRAM_DMA_ENGINE_CONFIG__ENGINE_RW_PARITY_BIST_MODE__VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | ((uint32_t)(0) << 0)) + +/*----------------------------------------------------------------------------------------------------*/ +/* VDMA_STOP_LP : dis */ +/* Description: Write 1 if want to disable LP Stop feature */ +#define DRAM_DMA_ENGINE_CONFIG__VDMA_STOP_LP__DIS__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_STOP_LP__DIS__WIDTH (1) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_STOP_LP__DIS__MASK (0x00000001L) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_STOP_LP__DIS__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_STOP_LP__DIS__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x00000001L) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_STOP_LP__DIS__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | (((uint32_t)(value) << 0) & 0x00000001L)) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_STOP_LP__DIS__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | ((uint32_t)(1) << 0)) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_STOP_LP__DIS__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | ((uint32_t)(0) << 0)) + +/* VDMA_STOP_LP : force_val */ +/* Description: Force Stop LP state when feature is enabled */ +#define DRAM_DMA_ENGINE_CONFIG__VDMA_STOP_LP__FORCE_VAL__SHIFT (1) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_STOP_LP__FORCE_VAL__WIDTH (1) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_STOP_LP__FORCE_VAL__MASK (0x00000002L) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_STOP_LP__FORCE_VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_STOP_LP__FORCE_VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x00000002L) >> 1) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_STOP_LP__FORCE_VAL__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x00000002L) | (((uint32_t)(value) << 1) & 0x00000002L)) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_STOP_LP__FORCE_VAL__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000002L) | ((uint32_t)(1) << 1)) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_STOP_LP__FORCE_VAL__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000002L) | ((uint32_t)(0) << 1)) + +/*----------------------------------------------------------------------------------------------------*/ +/* VDMA_SCH : stop_th */ +/* Description: Stop scheduling for this many cycles after each successful allocation */ +#define DRAM_DMA_ENGINE_CONFIG__VDMA_SCH__STOP_TH__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_SCH__STOP_TH__WIDTH (7) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_SCH__STOP_TH__MASK (0x0000007FL) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_SCH__STOP_TH__RESET (0x00000007L) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_SCH__STOP_TH__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x0000007FL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_SCH__STOP_TH__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x0000007FL) | (((uint32_t)(value) << 0) & 0x0000007FL)) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_SCH__STOP_TH__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x0000007FL) | 0x0000007FL) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_SCH__STOP_TH__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x0000007FL)) + +/* VDMA_SCH : stop_en */ +/* Description: Enable periodic scheduling stopping mechanism */ +#define DRAM_DMA_ENGINE_CONFIG__VDMA_SCH__STOP_EN__SHIFT (7) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_SCH__STOP_EN__WIDTH (1) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_SCH__STOP_EN__MASK (0x00000080L) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_SCH__STOP_EN__RESET (0x00000080L) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_SCH__STOP_EN__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x00000080L) >> 7) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_SCH__STOP_EN__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x00000080L) | (((uint32_t)(value) << 7) & 0x00000080L)) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_SCH__STOP_EN__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000080L) | ((uint32_t)(1) << 7)) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_SCH__STOP_EN__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000080L) | ((uint32_t)(0) << 7)) + +/* VDMA_SCH : tsf24_mode */ +/* Description: Apply fix to increase maximum transfers to 24 */ +#define DRAM_DMA_ENGINE_CONFIG__VDMA_SCH__TSF24_MODE__SHIFT (8) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_SCH__TSF24_MODE__WIDTH (1) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_SCH__TSF24_MODE__MASK (0x00000100L) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_SCH__TSF24_MODE__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_SCH__TSF24_MODE__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x00000100L) >> 8) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_SCH__TSF24_MODE__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x00000100L) | (((uint32_t)(value) << 8) & 0x00000100L)) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_SCH__TSF24_MODE__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000100L) | ((uint32_t)(1) << 8)) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_SCH__TSF24_MODE__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000100L) | ((uint32_t)(0) << 8)) + +/* VDMA_SCH : tsf_af_threshold */ +/* Description: Almost Full at 13 allocated TSF (12+8=20). In tsf24_mode should be set to 12. */ +#define DRAM_DMA_ENGINE_CONFIG__VDMA_SCH__TSF_AF_THRESHOLD__SHIFT (9) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_SCH__TSF_AF_THRESHOLD__WIDTH (5) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_SCH__TSF_AF_THRESHOLD__MASK (0x00003E00L) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_SCH__TSF_AF_THRESHOLD__RESET (0x00002800L) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_SCH__TSF_AF_THRESHOLD__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x00003E00L) >> 9) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_SCH__TSF_AF_THRESHOLD__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x00003E00L) | (((uint32_t)(value) << 9) & 0x00003E00L)) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_SCH__TSF_AF_THRESHOLD__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00003E00L) | 0x00003E00L) +#define DRAM_DMA_ENGINE_CONFIG__VDMA_SCH__TSF_AF_THRESHOLD__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00003E00L)) + +/*----------------------------------------------------------------------------------------------------*/ +/* CFG_SRC_DESC_TRACE : en */ +/* Description: Enable tracing of descriptors read from Source QMs */ +#define DRAM_DMA_ENGINE_CONFIG__CFG_SRC_DESC_TRACE__EN__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__CFG_SRC_DESC_TRACE__EN__WIDTH (1) +#define DRAM_DMA_ENGINE_CONFIG__CFG_SRC_DESC_TRACE__EN__MASK (0x00000001L) +#define DRAM_DMA_ENGINE_CONFIG__CFG_SRC_DESC_TRACE__EN__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__CFG_SRC_DESC_TRACE__EN__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x00000001L) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__CFG_SRC_DESC_TRACE__EN__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | (((uint32_t)(value) << 0) & 0x00000001L)) +#define DRAM_DMA_ENGINE_CONFIG__CFG_SRC_DESC_TRACE__EN__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | ((uint32_t)(1) << 0)) +#define DRAM_DMA_ENGINE_CONFIG__CFG_SRC_DESC_TRACE__EN__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | ((uint32_t)(0) << 0)) + +/* CFG_SRC_DESC_TRACE : stop_on_wrap */ +/* Description: Stop when reaching end of tracing buffer */ +#define DRAM_DMA_ENGINE_CONFIG__CFG_SRC_DESC_TRACE__STOP_ON_WRAP__SHIFT (1) +#define DRAM_DMA_ENGINE_CONFIG__CFG_SRC_DESC_TRACE__STOP_ON_WRAP__WIDTH (1) +#define DRAM_DMA_ENGINE_CONFIG__CFG_SRC_DESC_TRACE__STOP_ON_WRAP__MASK (0x00000002L) +#define DRAM_DMA_ENGINE_CONFIG__CFG_SRC_DESC_TRACE__STOP_ON_WRAP__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__CFG_SRC_DESC_TRACE__STOP_ON_WRAP__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x00000002L) >> 1) +#define DRAM_DMA_ENGINE_CONFIG__CFG_SRC_DESC_TRACE__STOP_ON_WRAP__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x00000002L) | (((uint32_t)(value) << 1) & 0x00000002L)) +#define DRAM_DMA_ENGINE_CONFIG__CFG_SRC_DESC_TRACE__STOP_ON_WRAP__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000002L) | ((uint32_t)(1) << 1)) +#define DRAM_DMA_ENGINE_CONFIG__CFG_SRC_DESC_TRACE__STOP_ON_WRAP__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000002L) | ((uint32_t)(0) << 1)) + +/* CFG_SRC_DESC_TRACE : mprot */ +/* Description: AWPROT value */ +#define DRAM_DMA_ENGINE_CONFIG__CFG_SRC_DESC_TRACE__MPROT__SHIFT (2) +#define DRAM_DMA_ENGINE_CONFIG__CFG_SRC_DESC_TRACE__MPROT__WIDTH (3) +#define DRAM_DMA_ENGINE_CONFIG__CFG_SRC_DESC_TRACE__MPROT__MASK (0x0000001CL) +#define DRAM_DMA_ENGINE_CONFIG__CFG_SRC_DESC_TRACE__MPROT__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__CFG_SRC_DESC_TRACE__MPROT__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x0000001CL) >> 2) +#define DRAM_DMA_ENGINE_CONFIG__CFG_SRC_DESC_TRACE__MPROT__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x0000001CL) | (((uint32_t)(value) << 2) & 0x0000001CL)) +#define DRAM_DMA_ENGINE_CONFIG__CFG_SRC_DESC_TRACE__MPROT__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x0000001CL) | 0x0000001CL) +#define DRAM_DMA_ENGINE_CONFIG__CFG_SRC_DESC_TRACE__MPROT__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x0000001CL)) + +/* CFG_SRC_DESC_TRACE : mcache */ +/* Description: AWCACHE value */ +#define DRAM_DMA_ENGINE_CONFIG__CFG_SRC_DESC_TRACE__MCACHE__SHIFT (5) +#define DRAM_DMA_ENGINE_CONFIG__CFG_SRC_DESC_TRACE__MCACHE__WIDTH (4) +#define DRAM_DMA_ENGINE_CONFIG__CFG_SRC_DESC_TRACE__MCACHE__MASK (0x000001E0L) +#define DRAM_DMA_ENGINE_CONFIG__CFG_SRC_DESC_TRACE__MCACHE__RESET (0x00000020L) +#define DRAM_DMA_ENGINE_CONFIG__CFG_SRC_DESC_TRACE__MCACHE__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x000001E0L) >> 5) +#define DRAM_DMA_ENGINE_CONFIG__CFG_SRC_DESC_TRACE__MCACHE__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x000001E0L) | (((uint32_t)(value) << 5) & 0x000001E0L)) +#define DRAM_DMA_ENGINE_CONFIG__CFG_SRC_DESC_TRACE__MCACHE__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x000001E0L) | 0x000001E0L) +#define DRAM_DMA_ENGINE_CONFIG__CFG_SRC_DESC_TRACE__MCACHE__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x000001E0L)) + +/* CFG_SRC_DESC_TRACE : buff_size_m1 */ +/* Description: Buffer size minus 1 in 16B descriptors */ +#define DRAM_DMA_ENGINE_CONFIG__CFG_SRC_DESC_TRACE__BUFF_SIZE_M1__SHIFT (16) +#define DRAM_DMA_ENGINE_CONFIG__CFG_SRC_DESC_TRACE__BUFF_SIZE_M1__WIDTH (16) +#define DRAM_DMA_ENGINE_CONFIG__CFG_SRC_DESC_TRACE__BUFF_SIZE_M1__MASK (0xFFFF0000L) +#define DRAM_DMA_ENGINE_CONFIG__CFG_SRC_DESC_TRACE__BUFF_SIZE_M1__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__CFG_SRC_DESC_TRACE__BUFF_SIZE_M1__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0xFFFF0000L) >> 16) +#define DRAM_DMA_ENGINE_CONFIG__CFG_SRC_DESC_TRACE__BUFF_SIZE_M1__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0xFFFF0000L) | (((uint32_t)(value) << 16) & 0xFFFF0000L)) +#define DRAM_DMA_ENGINE_CONFIG__CFG_SRC_DESC_TRACE__BUFF_SIZE_M1__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0xFFFF0000L) | 0xFFFF0000L) +#define DRAM_DMA_ENGINE_CONFIG__CFG_SRC_DESC_TRACE__BUFF_SIZE_M1__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0xFFFF0000L)) + +/*----------------------------------------------------------------------------------------------------*/ +/* CFG_SRC_DESC_TRACE_BASE_ADDR : base_addr */ +/* Description: Buffer base address bits 34:4 aligned to 16B */ +#define DRAM_DMA_ENGINE_CONFIG__CFG_SRC_DESC_TRACE_BASE_ADDR__BASE_ADDR__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__CFG_SRC_DESC_TRACE_BASE_ADDR__BASE_ADDR__WIDTH (31) +#define DRAM_DMA_ENGINE_CONFIG__CFG_SRC_DESC_TRACE_BASE_ADDR__BASE_ADDR__MASK (0x7FFFFFFFL) +#define DRAM_DMA_ENGINE_CONFIG__CFG_SRC_DESC_TRACE_BASE_ADDR__BASE_ADDR__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__CFG_SRC_DESC_TRACE_BASE_ADDR__BASE_ADDR__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x7FFFFFFFL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__CFG_SRC_DESC_TRACE_BASE_ADDR__BASE_ADDR__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x7FFFFFFFL) | (((uint32_t)(value) << 0) & 0x7FFFFFFFL)) +#define DRAM_DMA_ENGINE_CONFIG__CFG_SRC_DESC_TRACE_BASE_ADDR__BASE_ADDR__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x7FFFFFFFL) | 0x7FFFFFFFL) +#define DRAM_DMA_ENGINE_CONFIG__CFG_SRC_DESC_TRACE_BASE_ADDR__BASE_ADDR__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x7FFFFFFFL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* CFG_DST_DESC_TRACE : en */ +/* Description: Enable tracing of descriptors read from Source QMs */ +#define DRAM_DMA_ENGINE_CONFIG__CFG_DST_DESC_TRACE__EN__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__CFG_DST_DESC_TRACE__EN__WIDTH (1) +#define DRAM_DMA_ENGINE_CONFIG__CFG_DST_DESC_TRACE__EN__MASK (0x00000001L) +#define DRAM_DMA_ENGINE_CONFIG__CFG_DST_DESC_TRACE__EN__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__CFG_DST_DESC_TRACE__EN__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x00000001L) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__CFG_DST_DESC_TRACE__EN__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | (((uint32_t)(value) << 0) & 0x00000001L)) +#define DRAM_DMA_ENGINE_CONFIG__CFG_DST_DESC_TRACE__EN__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | ((uint32_t)(1) << 0)) +#define DRAM_DMA_ENGINE_CONFIG__CFG_DST_DESC_TRACE__EN__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | ((uint32_t)(0) << 0)) + +/* CFG_DST_DESC_TRACE : stop_on_wrap */ +/* Description: Stop when reaching end of tracing buffer */ +#define DRAM_DMA_ENGINE_CONFIG__CFG_DST_DESC_TRACE__STOP_ON_WRAP__SHIFT (1) +#define DRAM_DMA_ENGINE_CONFIG__CFG_DST_DESC_TRACE__STOP_ON_WRAP__WIDTH (1) +#define DRAM_DMA_ENGINE_CONFIG__CFG_DST_DESC_TRACE__STOP_ON_WRAP__MASK (0x00000002L) +#define DRAM_DMA_ENGINE_CONFIG__CFG_DST_DESC_TRACE__STOP_ON_WRAP__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__CFG_DST_DESC_TRACE__STOP_ON_WRAP__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x00000002L) >> 1) +#define DRAM_DMA_ENGINE_CONFIG__CFG_DST_DESC_TRACE__STOP_ON_WRAP__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x00000002L) | (((uint32_t)(value) << 1) & 0x00000002L)) +#define DRAM_DMA_ENGINE_CONFIG__CFG_DST_DESC_TRACE__STOP_ON_WRAP__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000002L) | ((uint32_t)(1) << 1)) +#define DRAM_DMA_ENGINE_CONFIG__CFG_DST_DESC_TRACE__STOP_ON_WRAP__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000002L) | ((uint32_t)(0) << 1)) + +/* CFG_DST_DESC_TRACE : mprot */ +/* Description: AWPROT value */ +#define DRAM_DMA_ENGINE_CONFIG__CFG_DST_DESC_TRACE__MPROT__SHIFT (2) +#define DRAM_DMA_ENGINE_CONFIG__CFG_DST_DESC_TRACE__MPROT__WIDTH (3) +#define DRAM_DMA_ENGINE_CONFIG__CFG_DST_DESC_TRACE__MPROT__MASK (0x0000001CL) +#define DRAM_DMA_ENGINE_CONFIG__CFG_DST_DESC_TRACE__MPROT__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__CFG_DST_DESC_TRACE__MPROT__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x0000001CL) >> 2) +#define DRAM_DMA_ENGINE_CONFIG__CFG_DST_DESC_TRACE__MPROT__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x0000001CL) | (((uint32_t)(value) << 2) & 0x0000001CL)) +#define DRAM_DMA_ENGINE_CONFIG__CFG_DST_DESC_TRACE__MPROT__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x0000001CL) | 0x0000001CL) +#define DRAM_DMA_ENGINE_CONFIG__CFG_DST_DESC_TRACE__MPROT__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x0000001CL)) + +/* CFG_DST_DESC_TRACE : mcache */ +/* Description: AWCACHE value. MER-3804 ECO: Note that bit 3 is double booked for timeout ExtRef default value which needs to be 1. In case debug tracing is enabled */ +#define DRAM_DMA_ENGINE_CONFIG__CFG_DST_DESC_TRACE__MCACHE__SHIFT (5) +#define DRAM_DMA_ENGINE_CONFIG__CFG_DST_DESC_TRACE__MCACHE__WIDTH (4) +#define DRAM_DMA_ENGINE_CONFIG__CFG_DST_DESC_TRACE__MCACHE__MASK (0x000001E0L) +#define DRAM_DMA_ENGINE_CONFIG__CFG_DST_DESC_TRACE__MCACHE__RESET (0x00000120L) +#define DRAM_DMA_ENGINE_CONFIG__CFG_DST_DESC_TRACE__MCACHE__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x000001E0L) >> 5) +#define DRAM_DMA_ENGINE_CONFIG__CFG_DST_DESC_TRACE__MCACHE__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x000001E0L) | (((uint32_t)(value) << 5) & 0x000001E0L)) +#define DRAM_DMA_ENGINE_CONFIG__CFG_DST_DESC_TRACE__MCACHE__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x000001E0L) | 0x000001E0L) +#define DRAM_DMA_ENGINE_CONFIG__CFG_DST_DESC_TRACE__MCACHE__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x000001E0L)) + +/* CFG_DST_DESC_TRACE : buff_size_m1 */ +/* Description: Buffer size minus 1 in 16B descriptors */ +#define DRAM_DMA_ENGINE_CONFIG__CFG_DST_DESC_TRACE__BUFF_SIZE_M1__SHIFT (16) +#define DRAM_DMA_ENGINE_CONFIG__CFG_DST_DESC_TRACE__BUFF_SIZE_M1__WIDTH (16) +#define DRAM_DMA_ENGINE_CONFIG__CFG_DST_DESC_TRACE__BUFF_SIZE_M1__MASK (0xFFFF0000L) +#define DRAM_DMA_ENGINE_CONFIG__CFG_DST_DESC_TRACE__BUFF_SIZE_M1__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__CFG_DST_DESC_TRACE__BUFF_SIZE_M1__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0xFFFF0000L) >> 16) +#define DRAM_DMA_ENGINE_CONFIG__CFG_DST_DESC_TRACE__BUFF_SIZE_M1__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0xFFFF0000L) | (((uint32_t)(value) << 16) & 0xFFFF0000L)) +#define DRAM_DMA_ENGINE_CONFIG__CFG_DST_DESC_TRACE__BUFF_SIZE_M1__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0xFFFF0000L) | 0xFFFF0000L) +#define DRAM_DMA_ENGINE_CONFIG__CFG_DST_DESC_TRACE__BUFF_SIZE_M1__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0xFFFF0000L)) + +/*----------------------------------------------------------------------------------------------------*/ +/* CFG_DST_DESC_TRACE_BASE_ADDR : base_addr */ +/* Description: Buffer base address bits 34:4 aligned to 16B. MER-3804 ECO: Note that bits 17:16 are double booked for timeout ExtRef mux. In case debug tracing and ExtRef are required to be turned on this constrain the base address bits 17:16 to be the same as the timestamp mux */ +#define DRAM_DMA_ENGINE_CONFIG__CFG_DST_DESC_TRACE_BASE_ADDR__BASE_ADDR__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__CFG_DST_DESC_TRACE_BASE_ADDR__BASE_ADDR__WIDTH (31) +#define DRAM_DMA_ENGINE_CONFIG__CFG_DST_DESC_TRACE_BASE_ADDR__BASE_ADDR__MASK (0x7FFFFFFFL) +#define DRAM_DMA_ENGINE_CONFIG__CFG_DST_DESC_TRACE_BASE_ADDR__BASE_ADDR__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__CFG_DST_DESC_TRACE_BASE_ADDR__BASE_ADDR__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x7FFFFFFFL) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__CFG_DST_DESC_TRACE_BASE_ADDR__BASE_ADDR__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x7FFFFFFFL) | (((uint32_t)(value) << 0) & 0x7FFFFFFFL)) +#define DRAM_DMA_ENGINE_CONFIG__CFG_DST_DESC_TRACE_BASE_ADDR__BASE_ADDR__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x7FFFFFFFL) | 0x7FFFFFFFL) +#define DRAM_DMA_ENGINE_CONFIG__CFG_DST_DESC_TRACE_BASE_ADDR__BASE_ADDR__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x7FFFFFFFL)) + +/*----------------------------------------------------------------------------------------------------*/ +/* CFG_DEBUG_TIMESTAMP : en */ +/* Description: Write 1 to enable timestamp counter for debug logic */ +#define DRAM_DMA_ENGINE_CONFIG__CFG_DEBUG_TIMESTAMP__EN__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__CFG_DEBUG_TIMESTAMP__EN__WIDTH (1) +#define DRAM_DMA_ENGINE_CONFIG__CFG_DEBUG_TIMESTAMP__EN__MASK (0x00000001L) +#define DRAM_DMA_ENGINE_CONFIG__CFG_DEBUG_TIMESTAMP__EN__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__CFG_DEBUG_TIMESTAMP__EN__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x00000001L) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__CFG_DEBUG_TIMESTAMP__EN__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | (((uint32_t)(value) << 0) & 0x00000001L)) +#define DRAM_DMA_ENGINE_CONFIG__CFG_DEBUG_TIMESTAMP__EN__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | ((uint32_t)(1) << 0)) +#define DRAM_DMA_ENGINE_CONFIG__CFG_DEBUG_TIMESTAMP__EN__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | ((uint32_t)(0) << 0)) + +/* CFG_DEBUG_TIMESTAMP : clr */ +/* Description: Write 1 to clear timestamp counter. After writing 1 to this field need to write 0 immediately */ +#define DRAM_DMA_ENGINE_CONFIG__CFG_DEBUG_TIMESTAMP__CLR__SHIFT (1) +#define DRAM_DMA_ENGINE_CONFIG__CFG_DEBUG_TIMESTAMP__CLR__WIDTH (1) +#define DRAM_DMA_ENGINE_CONFIG__CFG_DEBUG_TIMESTAMP__CLR__MASK (0x00000002L) +#define DRAM_DMA_ENGINE_CONFIG__CFG_DEBUG_TIMESTAMP__CLR__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__CFG_DEBUG_TIMESTAMP__CLR__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x00000002L) >> 1) +#define DRAM_DMA_ENGINE_CONFIG__CFG_DEBUG_TIMESTAMP__CLR__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x00000002L) | (((uint32_t)(value) << 1) & 0x00000002L)) +#define DRAM_DMA_ENGINE_CONFIG__CFG_DEBUG_TIMESTAMP__CLR__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000002L) | ((uint32_t)(1) << 1)) +#define DRAM_DMA_ENGINE_CONFIG__CFG_DEBUG_TIMESTAMP__CLR__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000002L) | ((uint32_t)(0) << 1)) + +/*----------------------------------------------------------------------------------------------------*/ +/* DEBUG_TIMESTAMP : val */ +#define DRAM_DMA_ENGINE_CONFIG__DEBUG_TIMESTAMP__VAL__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__DEBUG_TIMESTAMP__VAL__WIDTH (32) +#define DRAM_DMA_ENGINE_CONFIG__DEBUG_TIMESTAMP__VAL__MASK (0xFFFFFFFFL) +#define DRAM_DMA_ENGINE_CONFIG__DEBUG_TIMESTAMP__VAL__RESET (0x00000000L) +#define DRAM_DMA_ENGINE_CONFIG__DEBUG_TIMESTAMP__VAL__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0xFFFFFFFFL) >> 0) + +/*----------------------------------------------------------------------------------------------------*/ +/* AUTO_ADDRESS_ERR_CB_INDICATION : enable */ +/* Description: default is 1, meaning the address error is enabled, to hide the address error indication, set to 0 */ +#define DRAM_DMA_ENGINE_CONFIG__AUTO_ADDRESS_ERR_CB_INDICATION__ENABLE__SHIFT (0) +#define DRAM_DMA_ENGINE_CONFIG__AUTO_ADDRESS_ERR_CB_INDICATION__ENABLE__WIDTH (1) +#define DRAM_DMA_ENGINE_CONFIG__AUTO_ADDRESS_ERR_CB_INDICATION__ENABLE__MASK (0x00000001L) +#define DRAM_DMA_ENGINE_CONFIG__AUTO_ADDRESS_ERR_CB_INDICATION__ENABLE__RESET (0x00000001L) +#define DRAM_DMA_ENGINE_CONFIG__AUTO_ADDRESS_ERR_CB_INDICATION__ENABLE__READ(reg_offset) \ + (((uint32_t)(reg_offset) & 0x00000001L) >> 0) +#define DRAM_DMA_ENGINE_CONFIG__AUTO_ADDRESS_ERR_CB_INDICATION__ENABLE__MODIFY(reg_offset, value) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | (((uint32_t)(value) << 0) & 0x00000001L)) +#define DRAM_DMA_ENGINE_CONFIG__AUTO_ADDRESS_ERR_CB_INDICATION__ENABLE__SET(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | ((uint32_t)(1) << 0)) +#define DRAM_DMA_ENGINE_CONFIG__AUTO_ADDRESS_ERR_CB_INDICATION__ENABLE__CLR(reg_offset) \ + (reg_offset) = (((reg_offset) & ~0x00000001L) | ((uint32_t)(0) << 0)) + + +#endif /* DRAM_DMA_ENGINE_CONFIG_MACRO_H */ diff --git a/hailort/tools/hw_debug/hw_consts/mercury/dram_dma_engine_config_regs.h b/hailort/tools/hw_debug/hw_consts/mercury/dram_dma_engine_config_regs.h new file mode 100644 index 0000000..5c2c014 --- /dev/null +++ b/hailort/tools/hw_debug/hw_consts/mercury/dram_dma_engine_config_regs.h @@ -0,0 +1,143 @@ +/*------------------------------------------------------------------------------------- +// Copyright (c) 2022 by Hailotech This model is the confidential and +// proprietary property of Hailotech and the possession or use of this +// file requires a written license from Hailotech. +-------------------------------------------------------------------------------------*/ + + + +#include + +#ifndef DRAM_DMA_ENGINE_CONFIG_REGS_H +#define DRAM_DMA_ENGINE_CONFIG_REGS_H + +#include "dram_dma_package_macros.h" +#include "dram_dma_engine_config_macros.h" + +typedef struct DRAM_DMA_ENGINE_CONFIG_regs_s { + volatile uint32_t QddcEnable[DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_DIR_CH]; /* offset: 0x0 ; repeat: [16] */ + volatile uint32_t QddcReset[DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_DIR_CH]; /* offset: 0x40 ; repeat: [16] */ + volatile uint32_t QddcMode[DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_DIR_CH]; /* offset: 0x80 ; repeat: [16] */ + volatile uint32_t QddcAddBurstVal[DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_DIR_CH]; /* offset: 0xc0 ; repeat: [16] */ + volatile uint32_t QddcMaxDesc[DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_DIR_CH]; /* offset: 0x100 ; repeat: [16] */ + volatile uint32_t QddcShmifoId[DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_DIR_CH]; /* offset: 0x140 ; repeat: [16] */ + volatile uint32_t QddcShmifoCreditSize[DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_DIR_CH]; /* offset: 0x180 ; repeat: [16] */ + volatile uint32_t QddcShmifoInitCredit[DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_DIR_CH]; /* offset: 0x1c0 ; repeat: [16] */ + volatile uint32_t QsdcEnable[DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_DIR_CH]; /* offset: 0x200 ; repeat: [16] */ + volatile uint32_t QsdcReset[DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_DIR_CH]; /* offset: 0x240 ; repeat: [16] */ + volatile uint32_t QsdcMaxDesc[DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_DIR_CH]; /* offset: 0x280 ; repeat: [16] */ + volatile uint32_t QsdcShmifoId[DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_DIR_CH]; /* offset: 0x2c0 ; repeat: [16] */ + volatile uint32_t QsdcShmifoCreditSize[DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_DIR_CH]; /* offset: 0x300 ; repeat: [16] */ + volatile uint32_t QsdcFullNumPatterns[DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_FULL_PATTERN]; /* offset: 0x340 ; repeat: [4] */ + volatile uint32_t QsdcFullPatternNumLines[DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_FULL_PATTERN][DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_MAX_PATTERNS];/* offset: 0x350 ; repeat: [4, 4] */ + volatile uint32_t QsdcFullPatternNumPages[DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_FULL_PATTERN][DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_MAX_PATTERNS];/* offset: 0x390 ; repeat: [4, 4] */ + volatile uint32_t QsdcFullPatternPageSize[DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_FULL_PATTERN][DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_MAX_PATTERNS];/* offset: 0x3d0 ; repeat: [4, 4] */ + volatile uint32_t QsdcFullPatternResiduePageSize[DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_FULL_PATTERN][DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_MAX_PATTERNS];/* offset: 0x410 ; repeat: [4, 4] */ + volatile uint32_t QsdcSimpPatternNumPages[DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_SIMP_PATTERN]; /* offset: 0x450 ; repeat: [12] */ + volatile uint32_t QsdcSimpPatternPageSize[DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_SIMP_PATTERN]; /* offset: 0x480 ; repeat: [12] */ + volatile uint32_t QsdcSimpPatternResiduePageSize[DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_SIMP_PATTERN]; /* offset: 0x4b0 ; repeat: [12] */ + volatile uint32_t QdmcEnable[DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_DIR_CH]; /* offset: 0x4e0 ; repeat: [16] */ + volatile uint32_t QdmcReset[DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_DIR_CH]; /* offset: 0x520 ; repeat: [16] */ + volatile uint32_t QdmcMemBaseAddr[DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_DIR_CH]; /* offset: 0x560 ; repeat: [16] */ + volatile uint32_t QdmcMemCcbSizeLog2[DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_REGULAR_CH]; /* offset: 0x5a0 ; repeat: [12] */ + volatile uint32_t QdmcDescCsInterrupt[DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_DIR_CH]; /* offset: 0x5d0 ; repeat: [16] */ + volatile uint32_t QdmcBankInterleaveMode[DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_DIR_CH]; /* offset: 0x610 ; repeat: [16] */ + volatile uint32_t QdmcMode[DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_ENHANCED_CH]; /* offset: 0x650 ; repeat: [4] */ + volatile uint32_t QdmcAddBurstVal[DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_ENHANCED_CH]; /* offset: 0x660 ; repeat: [4] */ + volatile uint32_t QdmcMemCcbSize[DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_ENHANCED_CH]; /* offset: 0x670 ; repeat: [4] */ + volatile uint32_t QdmcDescPeriphInterrupt[DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_ENHANCED_CH]; /* offset: 0x680 ; repeat: [4] */ + volatile uint32_t QdmcCcbProcessedIndex[DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_ENHANCED_CH]; /* offset: 0x690 ; repeat: [4] */ + volatile uint32_t QsmcEnable[DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_DIR_CH]; /* offset: 0x6a0 ; repeat: [16] */ + volatile uint32_t QsmcReset[DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_DIR_CH]; /* offset: 0x6e0 ; repeat: [16] */ + volatile uint32_t QsmcMode[DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_DIR_CH]; /* offset: 0x720 ; repeat: [16] */ + volatile uint32_t QsmcC2cSel[DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_DIR_CH]; /* offset: 0x760 ; repeat: [16] */ + volatile uint32_t QsmcAddBurstVal[DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_DIR_CH]; /* offset: 0x7a0 ; repeat: [16] */ + volatile uint32_t QsmcMemBaseAddr[DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_DIR_CH]; /* offset: 0x7e0 ; repeat: [16] */ + volatile uint32_t QsmcMemCcbSize[DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_DIR_CH]; /* offset: 0x820 ; repeat: [16] */ + volatile uint32_t QsmcPageSize[DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_DIR_CH]; /* offset: 0x860 ; repeat: [16] */ + volatile uint32_t QsmcSimpPatternNumPages[DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_DIR_CH]; /* offset: 0x8a0 ; repeat: [16] */ + volatile uint32_t QsmcSimpPatternResiduePageSize[DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_DIR_CH]; /* offset: 0x8e0 ; repeat: [16] */ + volatile uint32_t QsmcBankInterleaveMode[DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_DIR_CH]; /* offset: 0x920 ; repeat: [16] */ + volatile uint32_t QsmcDescPeriphInterrupt[DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_ENHANCED_CH]; /* offset: 0x960 ; repeat: [4] */ + volatile uint32_t QsmcCcbFreeIndex[DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_ENHANCED_CH]; /* offset: 0x970 ; repeat: [4] */ + volatile uint32_t engine_cs_intr_mask; /* offset: 0x980 ; repeat: [1] */ + volatile uint32_t engine_cs_intr_status; /* offset: 0x984 ; repeat: [1] */ + volatile uint32_t engine_cs_intr_w1c; /* offset: 0x988 ; repeat: [1] */ + volatile uint32_t engine_cs_intr_w1s; /* offset: 0x98c ; repeat: [1] */ + volatile uint32_t engine_ap_intr_mask; /* offset: 0x990 ; repeat: [1] */ + volatile uint32_t engine_ap_intr_status; /* offset: 0x994 ; repeat: [1] */ + volatile uint32_t engine_ap_intr_w1c; /* offset: 0x998 ; repeat: [1] */ + volatile uint32_t engine_ap_intr_w1s; /* offset: 0x99c ; repeat: [1] */ + volatile uint32_t engine_dsp_intr_mask; /* offset: 0x9a0 ; repeat: [1] */ + volatile uint32_t engine_dsp_intr_status; /* offset: 0x9a4 ; repeat: [1] */ + volatile uint32_t engine_dsp_intr_w1c; /* offset: 0x9a8 ; repeat: [1] */ + volatile uint32_t engine_dsp_intr_w1s; /* offset: 0x9ac ; repeat: [1] */ + volatile uint32_t engine_err_intr_mask; /* offset: 0x9b0 ; repeat: [1] */ + volatile uint32_t engine_err_intr_status; /* offset: 0x9b4 ; repeat: [1] */ + volatile uint32_t desc_err_intr_mask; /* offset: 0x9b8 ; repeat: [1] */ + volatile uint32_t desc_err_intr_status; /* offset: 0x9bc ; repeat: [1] */ + volatile uint32_t desc_err_intr_w1c; /* offset: 0x9c0 ; repeat: [1] */ + volatile uint32_t desc_err_intr_w1s; /* offset: 0x9c4 ; repeat: [1] */ + volatile uint32_t qddc_crd_ovf_err_intr_mask; /* offset: 0x9c8 ; repeat: [1] */ + volatile uint32_t qddc_crd_ovf_err_intr_status; /* offset: 0x9cc ; repeat: [1] */ + volatile uint32_t qddc_crd_ovf_err_intr_w1c; /* offset: 0x9d0 ; repeat: [1] */ + volatile uint32_t qddc_crd_ovf_err_intr_w1s; /* offset: 0x9d4 ; repeat: [1] */ + volatile uint32_t qsdc_crd_ovf_err_intr_mask; /* offset: 0x9d8 ; repeat: [1] */ + volatile uint32_t qsdc_crd_ovf_err_intr_status; /* offset: 0x9dc ; repeat: [1] */ + volatile uint32_t qsdc_crd_ovf_err_intr_w1c; /* offset: 0x9e0 ; repeat: [1] */ + volatile uint32_t qsdc_crd_ovf_err_intr_w1s; /* offset: 0x9e4 ; repeat: [1] */ + volatile uint32_t EngErrInterruptSource; /* offset: 0x9e8 ; repeat: [1] */ + volatile uint32_t EngErrRemainPageSize; /* offset: 0x9ec ; repeat: [1] */ + volatile uint32_t EngTransferPageSize; /* offset: 0x9f0 ; repeat: [1] */ + volatile uint32_t VdmaSoftReset; /* offset: 0x9f4 ; repeat: [1] */ + volatile uint32_t vdma_sharedbus; /* offset: 0x9f8 ; repeat: [1] */ + volatile uint32_t cfg_qddc_redundant_en; /* offset: 0x9fc ; repeat: [1] */ + volatile uint32_t cfg_qsdc_redundant_en; /* offset: 0xa00 ; repeat: [1] */ + volatile uint32_t cfg_qdmc_redundant_en; /* offset: 0xa04 ; repeat: [1] */ + volatile uint32_t cfg_qsmc_redundant_en; /* offset: 0xa08 ; repeat: [1] */ + volatile uint32_t qddc_redundant_asf_int_mask; /* offset: 0xa0c ; repeat: [1] */ + volatile uint32_t qddc_redundant_asf_int_status; /* offset: 0xa10 ; repeat: [1] */ + volatile uint32_t qddc_redundant_asf_int_w1c; /* offset: 0xa14 ; repeat: [1] */ + volatile uint32_t qddc_redundant_asf_int_w1s; /* offset: 0xa18 ; repeat: [1] */ + volatile uint32_t qsdc_redundant_asf_int_mask; /* offset: 0xa1c ; repeat: [1] */ + volatile uint32_t qsdc_redundant_asf_int_status; /* offset: 0xa20 ; repeat: [1] */ + volatile uint32_t qsdc_redundant_asf_int_w1c; /* offset: 0xa24 ; repeat: [1] */ + volatile uint32_t qsdc_redundant_asf_int_w1s; /* offset: 0xa28 ; repeat: [1] */ + volatile uint32_t qdmc_redundant_asf_int_mask; /* offset: 0xa2c ; repeat: [1] */ + volatile uint32_t qdmc_redundant_asf_int_status; /* offset: 0xa30 ; repeat: [1] */ + volatile uint32_t qdmc_redundant_asf_int_w1c; /* offset: 0xa34 ; repeat: [1] */ + volatile uint32_t qdmc_redundant_asf_int_w1s; /* offset: 0xa38 ; repeat: [1] */ + volatile uint32_t qsmc_redundant_asf_int_mask; /* offset: 0xa3c ; repeat: [1] */ + volatile uint32_t qsmc_redundant_asf_int_status; /* offset: 0xa40 ; repeat: [1] */ + volatile uint32_t qsmc_redundant_asf_int_w1c; /* offset: 0xa44 ; repeat: [1] */ + volatile uint32_t qsmc_redundant_asf_int_w1s; /* offset: 0xa48 ; repeat: [1] */ + volatile uint32_t PrioIsLp; /* offset: 0xa4c ; repeat: [1] */ + volatile uint32_t ReadLpToQosValue; /* offset: 0xa50 ; repeat: [1] */ + volatile uint32_t ReadHpToQosValue; /* offset: 0xa54 ; repeat: [1] */ + volatile uint32_t WriteLpToQosValue; /* offset: 0xa58 ; repeat: [1] */ + volatile uint32_t WriteHpToQosValue; /* offset: 0xa5c ; repeat: [1] */ + volatile uint32_t DescReadQosValue; /* offset: 0xa60 ; repeat: [1] */ + volatile uint32_t DescWriteQosValue; /* offset: 0xa64 ; repeat: [1] */ + volatile uint32_t vdma_arb; /* offset: 0xa68 ; repeat: [1] */ + volatile uint32_t qm_cfg_cg_delay; /* offset: 0xa6c ; repeat: [1] */ + volatile uint32_t qddc_cfg_cg_bypass; /* offset: 0xa70 ; repeat: [1] */ + volatile uint32_t qsdc_cfg_cg_bypass; /* offset: 0xa74 ; repeat: [1] */ + volatile uint32_t qdmc_cfg_cg_bypass; /* offset: 0xa78 ; repeat: [1] */ + volatile uint32_t qsmc_cfg_cg_bypass; /* offset: 0xa7c ; repeat: [1] */ + volatile uint32_t engine_asf_int_mask; /* offset: 0xa80 ; repeat: [1] */ + volatile uint32_t engine_asf_int_status; /* offset: 0xa84 ; repeat: [1] */ + volatile uint32_t engine_asf_int_w1c; /* offset: 0xa88 ; repeat: [1] */ + volatile uint32_t engine_asf_int_w1s; /* offset: 0xa8c ; repeat: [1] */ + volatile uint32_t engine_rw_parity_bist_mode; /* offset: 0xa90 ; repeat: [1] */ + volatile uint32_t vdma_stop_lp; /* offset: 0xa94 ; repeat: [1] */ + volatile uint32_t vdma_sch; /* offset: 0xa98 ; repeat: [1] */ + volatile uint32_t cfg_src_desc_trace; /* offset: 0xa9c ; repeat: [1] */ + volatile uint32_t cfg_src_desc_trace_base_addr; /* offset: 0xaa0 ; repeat: [1] */ + volatile uint32_t cfg_dst_desc_trace; /* offset: 0xaa4 ; repeat: [1] */ + volatile uint32_t cfg_dst_desc_trace_base_addr; /* offset: 0xaa8 ; repeat: [1] */ + volatile uint32_t cfg_debug_timestamp; /* offset: 0xaac ; repeat: [1] */ + volatile uint32_t debug_timestamp; /* offset: 0xab0 ; repeat: [1] */ + volatile uint32_t auto_address_err_cb_indication; /* offset: 0xab4 ; repeat: [1] */ +} DRAM_DMA_ENGINE_CONFIG_t; + +#endif /* DRAM_DMA_ENGINE_CONFIG_REGS_H */ diff --git a/hailort/tools/hw_debug/hw_consts/mercury/dram_dma_package_macros.h b/hailort/tools/hw_debug/hw_consts/mercury/dram_dma_package_macros.h new file mode 100644 index 0000000..705f9a5 --- /dev/null +++ b/hailort/tools/hw_debug/hw_consts/mercury/dram_dma_package_macros.h @@ -0,0 +1,92 @@ +/*------------------------------------------------------------------------------------- +// Copyright (c) 2022 by Hailotech This model is the confidential and +// proprietary property of Hailotech and the possession or use of this +// file requires a written license from Hailotech. +-------------------------------------------------------------------------------------*/ + + + +#include + +#ifndef DRAM_DMA_PACKAGE_MACROS_H +#define DRAM_DMA_PACKAGE_MACROS_H + +/* HW constants and parameters for package "dram_dma" */ + +#define DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_AXI_QOS_BITS (3) +#define DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_CH (32) +#define DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_CH_RX_CREDIT (4096) +#define DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_CH_TX_CREDIT (2048) +#define DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_DD_DESC (16) +#define DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_DESC (16) +#define DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_DIR_CH (16) +#define DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_DM_DESC (16) +#define DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_ENHANCED_CH (4) +#define DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_FULL_PATTERN (4) +#define DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_MAX_PATTERNS (4) +#define DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_PATTERNS_MAX_LINES (262144) +#define DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_PATTERNS_MAX_PAGES (262144) +#define DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_REGULAR_CH (12) +#define DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_RX_SHMIFO (24) +#define DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_SD_DESC (16) +#define DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_SIMP_PATTERN (12) +#define DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_SM_DESC (16) +#define DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_SW_CH (16) +#define DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_SW_INT (4) +#define DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_TX_SHMIFO (20) +#define DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__PAGE_SIZE_MAX (13) +#define DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__PAGE_SIZE_MAX_8B (10) +#define DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__W_BURST_SIZE (29) +#define DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__W_BURST_SIZE_8B (26) +#define DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__W_C2C_SEL (6) +#define DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__W_CCB_DESC_INDEX (18) +#define DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__W_CCB_DESC_INDEX_LOG (5) +#define DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__W_CFG_DATA (32) +#define DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__W_CH (5) +#define DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__W_CH_CREDIT_SIZE (10) +#define DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__W_CH_RX_CREDIT (13) +#define DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__W_CH_TX_CREDIT (12) +#define DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__W_CORE_ADDR (35) +#define DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__W_CORE_BASE_ADDR (29) +#define DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__W_CSR_CFG_ADDR (13) +#define DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__W_DDR_ADDR (35) +#define DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__W_DDR_BASE_ADDR (26) +#define DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__W_DD_DESC (4) +#define DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__W_DESC (4) +#define DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__W_DESC_DEMUX_ADDR (43) +#define DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__W_DIR_CH (4) +#define DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__W_DM_DESC (4) +#define DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__W_ENG_CFG_ADDR (14) +#define DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__W_MAX_PATTERNS (2) +#define DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__W_PATTERNS_MAX_LINES (18) +#define DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__W_PATTERNS_MAX_PAGES (18) +#define DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__W_SD_DESC (4) +#define DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__W_SHMIFO (5) +#define DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__W_SM_DESC (4) +#define DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__W_SW_CH (4) +#define DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__W_VDMA_AXI_ADDR (64) +#define DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__W_VDMA_AXI_DATA_DATA (64) +#define DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__W_VDMA_AXI_DATA_DESC (128) +#define DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__W_VDMA_AXI_ID_DATA0 (2) +#define DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__W_VDMA_AXI_ID_DATA1 (4) +#define DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__W_VDMA_AXI_ID_DESC (3) +#define DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__W_VDMA_CFG_ADDR (10) +#define DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__W_VDMA_MEM_ADDR (5) +#define DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__W_VDMA_MEM_DATA (256) +#define DRAM_DMA_PACKAGE__DRAM_DMA_WRAPPER__ADDR_ALLSTRB_OFFSET (56) +#define DRAM_DMA_PACKAGE__DRAM_DMA_WRAPPER__ADDR_APCMD_OFFSET (55) +#define DRAM_DMA_PACKAGE__DRAM_DMA_WRAPPER__FPGA_N_HW_DMA_ENG (0) +#define DRAM_DMA_PACKAGE__DRAM_DMA_WRAPPER__N_DESC_AXI (1) +#define DRAM_DMA_PACKAGE__DRAM_DMA_WRAPPER__N_DMA_ENG (4) +#define DRAM_DMA_PACKAGE__DRAM_DMA_WRAPPER__N_HMASTER (4) +#define DRAM_DMA_PACKAGE__DRAM_DMA_WRAPPER__N_HW_DMA_ENG (3) +#define DRAM_DMA_PACKAGE__DRAM_DMA_WRAPPER__N_SW_DMA_ENG (1) +#define DRAM_DMA_PACKAGE__DRAM_DMA_WRAPPER__N_TOT_DMA_DIR_CH (48) +#define DRAM_DMA_PACKAGE__DRAM_DMA_WRAPPER__N_VISION_CH (10) +#define DRAM_DMA_PACKAGE__DRAM_DMA_WRAPPER__W_CFG_ADDR (16) +#define DRAM_DMA_PACKAGE__DRAM_DMA_WRAPPER__W_CFG_DATA (32) +#define DRAM_DMA_PACKAGE__DRAM_DMA_WRAPPER__W_CSR_CFG_ADDR (12) +#define DRAM_DMA_PACKAGE__DRAM_DMA_WRAPPER__W_TOT_DMA_DIR_CH (6) + + +#endif /* DRAM_DMA_PACKAGE_MACROS_H */ diff --git a/hailort/tools/hw_debug/main.cpp b/hailort/tools/hw_debug/main.cpp new file mode 100644 index 0000000..74d33c4 --- /dev/null +++ b/hailort/tools/hw_debug/main.cpp @@ -0,0 +1,152 @@ +/** + * @file main.cpp + * @brief Main function, and shell build for the tool. + */ + +#include "shell.hpp" +#include "readline_wrapper.hpp" +#include "memory_commands.hpp" +#include "driver_memory.hpp" + +#include "CLI/CLI.hpp" + +#include + +using namespace hailort; + +static constexpr const char *LOGO = + R"( _____ _ _ __ __ )" "\n" + R"(| __ \ | | | | \ \ / / )" "\n" + R"(| | | | ___| |__ __ _| | ___ \ V / )" "\n" + R"(| | | |/ _ \ '_ \ / _` | |/ _ \ > < )" "\n" + R"(| |__| | __/ |_) | (_| | | __// . \ )" "\n" + R"(|_____/ \___|_.__/ \__,_|_|\___/_/ \_\ )" "\n"; + + +static std::shared_ptr add_memory_subshell(Shell &base_shell, + const std::string &name, const std::string &short_name, std::shared_ptr mem) +{ + auto subshell = base_shell.add_subshell(name, short_name); + subshell->add_command(std::make_unique>(mem)); + subshell->add_command(std::make_unique>(mem)); + subshell->add_command(std::make_unique>(mem)); + + subshell->add_command(std::make_unique>(mem)); + subshell->add_command(std::make_unique>(mem)); + subshell->add_command(std::make_unique>(mem)); + + if (!mem->get_fields().empty()) { + subshell->add_command(std::make_unique(mem)); + } + + return subshell; +} + +template +static std::shared_ptr add_driver_memory_subshell(Shell &base_shell, + const std::string &name, const std::string &short_name, + std::shared_ptr driver, MemoryType memory_type) +{ + auto mem = std::make_shared(driver, memory_type); + return add_memory_subshell(base_shell, name, short_name, mem); +} + +static std::unique_ptr create_pcie_accelerator_shell(std::shared_ptr driver_ptr) +{ + auto shell = std::make_unique("> "); + add_driver_memory_subshell(*shell, "vdma", "v", driver_ptr, MemoryType::VDMA0); + add_driver_memory_subshell(*shell, "bar0", "b0", driver_ptr, MemoryType::PCIE_BAR0); + add_driver_memory_subshell(*shell, "bar2", "b2", driver_ptr, MemoryType::PCIE_BAR2); + add_driver_memory_subshell(*shell, "bar4", "b4", driver_ptr, MemoryType::PCIE_BAR4); + add_driver_memory_subshell(*shell, "mem", "m", driver_ptr, MemoryType::DIRECT_MEMORY); + return shell; +} + +static std::unique_ptr create_vpu_shell(std::shared_ptr driver_ptr) +{ + auto shell = std::make_unique("> "); + add_driver_memory_subshell(*shell, "vdma0", "v0", driver_ptr, MemoryType::VDMA0); + add_driver_memory_subshell(*shell, "vdma1", "v1", driver_ptr, MemoryType::VDMA1); + add_driver_memory_subshell(*shell, "vdma2", "v2", driver_ptr, MemoryType::VDMA2); + add_driver_memory_subshell(*shell, "engine0", "e0", driver_ptr, MemoryType::DMA_ENGINE0); + add_driver_memory_subshell(*shell, "engine1", "e1", driver_ptr, MemoryType::DMA_ENGINE1); + add_driver_memory_subshell(*shell, "engine2", "e2", driver_ptr, MemoryType::DMA_ENGINE2); + add_driver_memory_subshell(*shell, "mem", "m", driver_ptr, MemoryType::DIRECT_MEMORY); + return shell; +} + +static std::vector get_available_device_ids() +{ + auto scan_results = HailoRTDriver::scan_devices(); + if (!scan_results) { + throw std::runtime_error("Failed scan pci"); + } + if (scan_results->empty()) { + throw std::runtime_error("No hailo devices on the system..."); + } + + std::vector device_ids; + for (const auto &scan_result : scan_results.value()) { + device_ids.push_back(scan_result.device_id); + } + return device_ids; +} + +std::string get_device_filepath(const std::string &device_id) +{ + auto scan_results = HailoRTDriver::scan_devices(); + if (!scan_results) { + throw std::runtime_error("Failed scan pci"); + } + + auto device_found = std::find_if(scan_results->cbegin(), scan_results->cend(), + [&device_id](const auto &compared_scan_result) { + return device_id == compared_scan_result.device_id; + }); + if (device_found == std::end(scan_results.value())) { + throw std::runtime_error("Requested device not found"); + } + + return device_found->dev_path; +} + +std::shared_ptr create_driver_object(const std::string &device_id) +{ + auto device_path = get_device_filepath(device_id); + auto hailort_driver = HailoRTDriver::create(device_path); + if (!hailort_driver) { + throw std::runtime_error("Failed create hailort driver object"); + } + return std::make_shared(hailort_driver.release()); +} + +int main(int argc, char **argv) +{ + try { + ReadLineWrapper::init_library(); + + auto available_device_ids = get_available_device_ids(); + + CLI::App app{"Debalex"}; + std::string device_id = available_device_ids[0]; + app.add_option("-s,--device-id", device_id, "Device id") + ->check(CLI::IsMember(available_device_ids)); + CLI11_PARSE(app, argc, argv); + + auto driver = create_driver_object(device_id); + + + auto shell = + driver->dma_type() == HailoRTDriver::DmaType::PCIE ? + create_pcie_accelerator_shell(driver) : + create_vpu_shell(driver); + + std::cout << LOGO << std::endl; + shell->run_forever(); + return 0; + } + catch (const std::exception &exc) { + std::cerr << "Failure: " << exc.what(); + return 1; + } +} diff --git a/hailort/tools/hw_debug/memory_commands.cpp b/hailort/tools/hw_debug/memory_commands.cpp new file mode 100644 index 0000000..b753503 --- /dev/null +++ b/hailort/tools/hw_debug/memory_commands.cpp @@ -0,0 +1,106 @@ +/** + * @file memory_commands.cpp + * @brief Commands to access (read/write) some memory (for example - channel registers, descriptors, physical, etc.) + */ +#include "memory_commands.hpp" + +#include +#include + +Field::Field(std::string &&name, std::string &&description) : + m_name(std::move(name)), + m_description(std::move(description)) +{} + + +const std::string &Field::name() const +{ + return m_name; +} + +const std::string &Field::description() const +{ + return m_description; +} + +const std::map> &MemorySource::get_fields() const +{ + return m_fields; +} + +void MemorySource::add_field(std::shared_ptr field) +{ + assert(m_fields.find(field->name()) == m_fields.end()); + m_fields[field->name()] = field; +} + +constexpr size_t PrintCommand::PRINT_ALL; + +PrintCommand::PrintCommand(std::shared_ptr memory) : + ShellCommand("print", "p", get_help(memory->get_fields())), + m_memory(memory) +{} + +ShellResult PrintCommand::execute(const std::vector &args) +{ + if (args.size() != 1) { + return ShellResult("Invalid params\n"); + } + + std::string field_name{}; + size_t index{}; + std::tie(field_name, index) = parse_field(args[0]); + + const auto &fields = m_memory->get_fields(); + auto field_it = fields.find(field_name); + if (fields.end() == field_it) { + throw std::runtime_error(fmt::format("Field {} does not exist", field_name)); + } + const auto &field = field_it->second; + + if (index == PRINT_ALL) { + std::vector results; + results.reserve(field->elements_count()); + for (size_t i = 0; i < field->elements_count(); i++) { + results.emplace_back(ShellResult(field->print_element(*m_memory, i))); + } + return ShellResult(results); + } + else { + if (index >= field->elements_count()) { + throw std::runtime_error(fmt::format("Index {} is out of range (max {})", index, field->elements_count())); + } + return ShellResult(field->print_element(*m_memory, index)); + } +} + +std::pair PrintCommand::parse_field(const std::string &field_arg) +{ + static const std::regex field_name_pattern("([a-zA-Z]+)"); + static const std::regex array_access_pattern("([a-zA-Z]+)\\[([0-9]+)\\]"); + std::smatch match; + + if (std::regex_match(field_arg, match, field_name_pattern)) { + assert(match.size() == 2); + const auto field = match[1]; + return std::make_pair(field, PRINT_ALL); + } + else if (std::regex_match(field_arg, match, array_access_pattern)) { + assert(match.size() == 3); + const auto &field = match[1]; + const auto index = std::atoi(match[2].str().c_str()); + return std::make_pair(field, index); + } + else { + throw std::runtime_error(fmt::format("Invalid syntax {}", field_arg)); + } +} + +std::string PrintCommand::get_help(const std::map> &fields) +{ + std::string help = "Pretty print some field, usage: print []. Fields:\n"; + for (auto field : fields) { + help += fmt::format("\t{} - {}\n", field.second->name(), field.second->description()); + } + return help; +} diff --git a/hailort/tools/hw_debug/memory_commands.hpp b/hailort/tools/hw_debug/memory_commands.hpp new file mode 100644 index 0000000..95dc913 --- /dev/null +++ b/hailort/tools/hw_debug/memory_commands.hpp @@ -0,0 +1,211 @@ +/** + * @file memory_commands.hpp + * @brief Commands to access (read/write) some memory (for example - channel registers, descriptors, physical, etc.) + */ + +#ifndef _HW_DEBUG_MEMORY_COMMANDS_H_ +#define _HW_DEBUG_MEMORY_COMMANDS_H_ + +#include "shell.hpp" +#include "hailo/hailort.h" +#include "hailo/expected.hpp" +#include "spdlog/fmt/fmt.h" + +#include +#include +#include +#include + +class MemorySource; + +class Field { +public: + explicit Field(std::string &&name, std::string &&description); + virtual ~Field() = default; + + Field(const Field &other) = delete; + Field &operator=(const Field &other) = delete; + + const std::string &name() const; + const std::string &description() const; + + virtual size_t elements_count() const = 0; + virtual std::string print_element(MemorySource& memory, size_t index) const = 0; +private: + const std::string m_name; + const std::string m_description; +}; + +class MemorySource { +public: + virtual ~MemorySource() = default; + + virtual hailo_status read(uint64_t offset, uint8_t *data, size_t size) = 0; + virtual hailo_status write(uint64_t offset, const uint8_t *data, size_t size) = 0; + virtual size_t total_size() const = 0; + + template + T read(uint64_t offset) + { + static_assert(std::is_trivial::value, "Non trivial type"); + T value{}; + auto status = read(offset, reinterpret_cast(&value), sizeof(value)); + if (HAILO_SUCCESS != status) { + throw std::runtime_error(fmt::format("Failed read at {} (size {})", offset, sizeof(value))); + } + return value; + } + + const std::map> &get_fields() const; +protected: + void add_field(std::shared_ptr field); + +private: + std::map> m_fields; +}; + +template +class MemoryWriteCommand : public ShellCommand { +public: + static_assert(std::is_integral::value, "MemoryWriteCommand works only with integers"); + + MemoryWriteCommand(std::shared_ptr memory) : + ShellCommand(get_name(), get_short_name(), get_help()), + m_memory(memory) + {} + + ShellResult execute(const std::vector &args) { + if (args.size() != 2) { + return ShellResult("Invalid params\n"); + } + + uint64_t offset; + if (sscanf(args[0].c_str(), "%" SCNx64, &offset) != 1) { + return ShellResult(fmt::format("Invalid offset {}\n")); + } + + uint32_t data; + if (sscanf(args[1].c_str(), "%" SCNx32, &data) != 1) { + return ShellResult(fmt::format("Invalid data {}\n", args[1])); + } + + if ((offset % sizeof(IntType)) != 0) { + return ShellResult(fmt::format("Offset {:x} must be a multiple of {}\n", offset, sizeof(IntType))); + } + + if (offset + sizeof(IntType) > m_memory->total_size()) { + return ShellResult(fmt::format("Offset {:x} too large (max {:x})\n", offset, m_memory->total_size())); + } + + if (data > std::numeric_limits::max()) { + return ShellResult(fmt::format("data {:x} too large\n", data)); + } + IntType data_as_int = static_cast(data); + auto status = m_memory->write(offset, reinterpret_cast(&data_as_int), sizeof(data_as_int)); + if (HAILO_SUCCESS != status) { + return ShellResult(fmt::format("Failed write memory {}\n", status)); + } + + return ShellResult(""); + } + +private: + std::shared_ptr m_memory; + + static size_t get_bits() { return sizeof(IntType) * 8; } + static std::string get_name() { return fmt::format("write{}", get_bits()); } + static std::string get_short_name() { return fmt::format("w{}", get_bits()); } + static std::string get_help() + { + return fmt::format("Writes memory in {} granularity. Usage: {} . Offset and data are hex integers.", get_bits(), + get_name()); + } +}; + +template +class MemoryReadCommand : public ShellCommand { +public: + static_assert(std::is_integral::value, "MemoryReadCommand works only with integers"); + + MemoryReadCommand(std::shared_ptr memory) : + ShellCommand(get_name(), get_short_name(), get_help()), + m_memory(memory) + {} + + ShellResult execute(const std::vector &args) { + if (args.size() != 2) { + return ShellResult("Invalid params\n"); + } + + uint64_t offset; + if (sscanf(args[0].c_str(), "%" SCNx64, &offset) != 1) { + return ShellResult(fmt::format("Invalid offset {}\n", args[0])); + } + + uint32_t size; + if (sscanf(args[1].c_str(), "%" SCNx32, &size) != 1) { + return ShellResult(fmt::format("Invalid size {}\n", args[1])); + } + + if ((offset % sizeof(IntType)) != 0) { + return ShellResult(fmt::format("Offset {:x} must be a multiple of {}\n", offset, sizeof(IntType))); + } + + if ((size % sizeof(IntType)) != 0) { + return ShellResult(fmt::format("Size {:x} must be a multiple of {}\n", size, sizeof(IntType))); + } + + if (offset + size > m_memory->total_size()) { + return ShellResult(fmt::format("Offset {:x} and size {:x} too large (max {:x})\n", offset, size, + m_memory->total_size())); + } + + std::vector data(size, 0); + auto status = m_memory->read(offset, data.data(), data.size()); + if (HAILO_SUCCESS != status) { + return ShellResult(fmt::format("Failed read memory {}\n", status)); + } + + std::stringstream result; + result << std::hex << std::setfill('0'); + for (size_t i = 0; i < size; i += sizeof(IntType)) { + if ((i % 16) == 0) { + // Print address + result << std::endl << std::setw(8) << (offset + i) << "\t"; + } + IntType *ptr = reinterpret_cast(data.data() + i); + result << " " << std::setw(sizeof(IntType) * 2) << static_cast(*ptr); + } + result << std::endl; + return result.str(); + } + +private: + std::shared_ptr m_memory; + + static size_t get_bits() { return sizeof(IntType) * 8; } + static std::string get_name() { return fmt::format("read{}", get_bits()); } + static std::string get_short_name() { return fmt::format("r{}", get_bits()); } + static std::string get_help() + { + return fmt::format("Reads memory in {} granularity. Usage: {} . Offset and size are hex integers.", + get_bits(), get_name()); + } +}; + +class PrintCommand : public ShellCommand { +public: + PrintCommand(std::shared_ptr memory); + virtual ShellResult execute(const std::vector &args) override; + +private: + // Returns pair of field name and the index + static std::pair parse_field(const std::string &field_arg); + static std::string get_help(const std::map> &fields); + + std::shared_ptr m_memory; + + static constexpr size_t PRINT_ALL = std::numeric_limits::max(); +}; + +#endif /* _HW_DEBUG_MEMORY_COMMANDS_H_ */ diff --git a/hailort/tools/hw_debug/mercury_fields.cpp b/hailort/tools/hw_debug/mercury_fields.cpp new file mode 100644 index 0000000..07561e2 --- /dev/null +++ b/hailort/tools/hw_debug/mercury_fields.cpp @@ -0,0 +1,171 @@ +/** + * @file mercury_fields.cpp + * @brief Contains all memory fields related to mercury + */ + +#include "mercury_fields.hpp" +#include "hw_consts/mercury/dram_dma_engine_config_regs.h" + +// Implement our own offsetof to allow access to array +#define my_offsetof(type,field) ((size_t)(&(((type*)(0))->field))) +#define dram_dma_offsetof(field) my_offsetof(DRAM_DMA_ENGINE_CONFIG_t, field) + + +static constexpr auto CCB_ADDRESS_SHIFT = 9; + + +QddcField::QddcField() : + Field("qddc", "Queue dest device channel (qddc)") +{} + +size_t QddcField::elements_count() const +{ + return DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_DIR_CH; +} + +std::string QddcField::print_element(MemorySource& memory, size_t index) const +{ + return fmt::format("qddc[{}] enabled={} mode={} shmifo_id={}\n", index, + is_enabled(memory, index), mode(memory, index), shmifo_id(memory, index)); +} + +bool QddcField::is_enabled(MemorySource &memory, size_t index) const +{ + return (1 == memory.read(dram_dma_offsetof(QddcEnable[index]))); +} + +uint32_t QddcField::shmifo_id(MemorySource &memory, size_t index) const +{ + return memory.read(dram_dma_offsetof(QddcShmifoId[index])); +} + +std::string QddcField::mode(MemorySource &memory, size_t index) const +{ + const auto mode = memory.read(dram_dma_offsetof(QddcMode[index])); + switch (mode) { + case 0: return "CONTINUOUS"; + case 1: return "BURST"; + default: + return fmt::format("Unknown {}", mode); + } +} + +QsdcField::QsdcField() : + Field("qsdc", "Queue source device channel (qsdc)") +{} + +size_t QsdcField::elements_count() const +{ + return DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_DIR_CH; +} + +std::string QsdcField::print_element(MemorySource& memory, size_t index) const +{ + return fmt::format("qsdc[{}] enabled={} shmifo_id={}\n", index, + is_enabled(memory, index), shmifo_id(memory, index)); +} + +bool QsdcField::is_enabled(MemorySource &memory, size_t index) const +{ + return (1 == memory.read(dram_dma_offsetof(QsdcEnable[index]))); +} + +uint32_t QsdcField::shmifo_id(MemorySource &memory, size_t index) const +{ + return memory.read(dram_dma_offsetof(QsdcShmifoId[index])); +} + +QdmcField::QdmcField() : + Field("qdmc", "Queue dest memory channel (qdmc)") +{} + +size_t QdmcField::elements_count() const +{ + return DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_DIR_CH; +} + +std::string QdmcField::print_element(MemorySource& memory, size_t index) const +{ + return fmt::format("qdmc[{}] enabled={} address=0x{:x} desc_count={} desc_per_irq={}\n", index, + is_enabled(memory, index), base_address(memory, index), descriptors_count(memory, index), + descriptors_per_irq(memory, index)); +} + +bool QdmcField::is_enabled(MemorySource &memory, size_t index) const +{ + return (1 == memory.read(dram_dma_offsetof(QdmcEnable[index]))); +} + +uint64_t QdmcField::base_address(MemorySource &memory, size_t index) const +{ + const uint64_t address = memory.read(dram_dma_offsetof(QdmcMemBaseAddr[index])); + return address << CCB_ADDRESS_SHIFT; +} + +uint32_t QdmcField::descriptors_count(MemorySource &memory, size_t index) const +{ + if (index > DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_REGULAR_CH) { + return memory.read(dram_dma_offsetof(QdmcMemCcbSize[index - DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_REGULAR_CH])); + } + else { + const auto desc_count_log2 = memory.read(dram_dma_offsetof(QdmcMemCcbSizeLog2[index])); + uint32_t size = 1; + for (uint32_t i = 0; i < desc_count_log2; i++) { + size <<= 1; + } + return size; + } +} + +uint32_t QdmcField::descriptors_per_irq(MemorySource &memory, size_t index) const +{ + return memory.read(dram_dma_offsetof(QdmcDescCsInterrupt[index])); +} + +QsmcField::QsmcField() : + Field("qsmc", "Queue source memory channel (qsmc)") +{} + +size_t QsmcField::elements_count() const +{ + return DRAM_DMA_PACKAGE__DRAM_DMA_ENGINE__N_DIR_CH; +} + +std::string QsmcField::print_element(MemorySource& memory, size_t index) const +{ + return fmt::format("qdmc[{}] mode={} enabled={} address=0x{:x} desc_count={}\n", index, + mode(memory, index), is_enabled(memory, index), base_address(memory, index), descriptors_count(memory, index)); +} + +bool QsmcField::is_enabled(MemorySource &memory, size_t index) const +{ + return (1 == memory.read(dram_dma_offsetof(QsmcEnable[index]))); +} + +uint64_t QsmcField::base_address(MemorySource &memory, size_t index) const +{ + const uint64_t address = memory.read(dram_dma_offsetof(QsmcMemBaseAddr[index])); + return address << CCB_ADDRESS_SHIFT; +} + +uint32_t QsmcField::descriptors_count(MemorySource &memory, size_t index) const +{ + const auto desc_count = memory.read(dram_dma_offsetof(QsmcMemCcbSize[index])); + return desc_count + 1; // The reg contains desc_count-1 +} + +std::string QsmcField::mode(MemorySource &memory, size_t index) const +{ + const auto mode = memory.read(dram_dma_offsetof(QsmcMode[index])); + switch (mode) { + case 0: return "CONTINUOUS"; + case 2: return "BURST"; + case 3: // C2C mode + { + auto c2c_sel = memory.read(dram_dma_offsetof(QsmcC2cSel[index])); + return fmt::format("C2C (from {})", c2c_sel); + } + default: + return fmt::format("Unknown {}", mode); + } +} diff --git a/hailort/tools/hw_debug/mercury_fields.hpp b/hailort/tools/hw_debug/mercury_fields.hpp new file mode 100644 index 0000000..29709d7 --- /dev/null +++ b/hailort/tools/hw_debug/mercury_fields.hpp @@ -0,0 +1,66 @@ +/** + * @file mercury_fields.hpp + * @brief Contains all memory fields related to mercury + */ + +#ifndef _HW_DEBUG_MERCURY_FIELDS_H_ +#define _HW_DEBUG_MERCURY_FIELDS_H_ + +#include "memory_commands.hpp" + + +class QddcField : public Field { +public: + QddcField(); + + virtual size_t elements_count() const override; + virtual std::string print_element(MemorySource& memory, size_t index) const override; + +private: + bool is_enabled(MemorySource &memory, size_t index) const; + uint32_t shmifo_id(MemorySource &memory, size_t index) const; + std::string mode(MemorySource &memory, size_t index) const; +}; + +class QsdcField : public Field { +public: + QsdcField(); + + virtual size_t elements_count() const override; + virtual std::string print_element(MemorySource& memory, size_t index) const override; + +private: + bool is_enabled(MemorySource &memory, size_t index) const; + uint32_t shmifo_id(MemorySource &memory, size_t index) const; +}; + + +class QdmcField : public Field { +public: + QdmcField(); + + virtual size_t elements_count() const override; + virtual std::string print_element(MemorySource& memory, size_t index) const override; + +private: + bool is_enabled(MemorySource &memory, size_t index) const; + uint64_t base_address(MemorySource &memory, size_t index) const; + uint32_t descriptors_count(MemorySource &memory, size_t index) const; + uint32_t descriptors_per_irq(MemorySource &memory, size_t index) const; +}; + +class QsmcField : public Field { +public: + QsmcField(); + + virtual size_t elements_count() const override; + virtual std::string print_element(MemorySource& memory, size_t index) const override; + +private: + bool is_enabled(MemorySource &memory, size_t index) const; + uint64_t base_address(MemorySource &memory, size_t index) const; + uint32_t descriptors_count(MemorySource &memory, size_t index) const; + std::string mode(MemorySource &memory, size_t index) const; +}; + +#endif /* _HW_DEBUG_MERCURY_FIELDS_H_ */ diff --git a/hailort/tools/hw_debug/readline_wrapper.cpp b/hailort/tools/hw_debug/readline_wrapper.cpp new file mode 100644 index 0000000..03ab84c --- /dev/null +++ b/hailort/tools/hw_debug/readline_wrapper.cpp @@ -0,0 +1,110 @@ +/** + * @file readline_wrapper.cpp + * @brief Wrapper to the readline library, either use the library, or create simple implementation. + */ + +#include "readline_wrapper.hpp" +#include + + +#ifdef USE_READLINE +#include +#include +#include + +static void int_handler(int) +{ + printf("\n"); // Move to a new line + rl_on_new_line(); // Regenerate the prompt on a newline + rl_replace_line("", 0); // Clear the previous text + rl_redisplay(); +} + +static ReadLineWrapper::AutoCompleter g_auto_completer = nullptr; + +static char *name_generator(const char *text, int index) +{ + if (!g_auto_completer) { + return nullptr; + } + + auto results = g_auto_completer(std::string(text)); + if (static_cast(index) >= results.size()) { + return nullptr; + } + + return strdup(results[index].c_str()); +} + +static char **name_completion(const char *text, int start, int) +{ + if (start > 0) { + // We use autocomplete only for the first arg (command name). + return nullptr; + } + + rl_attempted_completion_over = 1; + return rl_completion_matches(text, name_generator); +} + +void ReadLineWrapper::init_library() +{ + rl_attempted_completion_function = name_completion; + signal(SIGINT, int_handler); +} + +std::string ReadLineWrapper::readline(const std::string &prompt) +{ + auto line_raw = ::readline(prompt.c_str()); + if (line_raw == nullptr) { + // Ctrl+D handle + printf("\n"); + return ""; + } + + const std::string line(line_raw); + free(line_raw); + return line; +} + +void ReadLineWrapper::add_history(const std::string &line) +{ + ::add_history(line.c_str()); +} + +void ReadLineWrapper::set_auto_completer(AutoCompleter completer) +{ + g_auto_completer = completer; +} + +void ReadLineWrapper::remove_auto_completer() +{ + g_auto_completer = nullptr; +} + +#else + +void ReadLineWrapper::init_library() +{} + +// Non readline implementation +std::string ReadLineWrapper::readline(const std::string &prompt) +{ + std::cout << prompt; + std::string command; + std::getline(std::cin, command); + return command; +} + +void ReadLineWrapper::add_history(const std::string &) +{ + // No history, just NOP. +} + +void ReadLineWrapper::set_auto_completer(AutoCompleter) +{} + +void ReadLineWrapper::remove_auto_completer() +{} + +#endif \ No newline at end of file diff --git a/hailort/tools/hw_debug/readline_wrapper.hpp b/hailort/tools/hw_debug/readline_wrapper.hpp new file mode 100644 index 0000000..eae25c8 --- /dev/null +++ b/hailort/tools/hw_debug/readline_wrapper.hpp @@ -0,0 +1,26 @@ +/** + * @file readline_wrapper.hpp + * @brief Wrapper to the readline library, either use the library, or create simple implementation. + */ + +#ifndef _HW_DEBUG_READLINE_WRAPPER_H_ +#define _HW_DEBUG_READLINE_WRAPPER_H_ + +#include +#include +#include + +class ReadLineWrapper final { +public: + ReadLineWrapper() = delete; + + static void init_library(); + static std::string readline(const std::string &prompt); + static void add_history(const std::string &line); + + using AutoCompleter = std::function(const std::string &text)>; + static void set_auto_completer(AutoCompleter completer); + static void remove_auto_completer(); +}; + +#endif /* _HW_DEBUG_READLINE_WRAPPER_H_ */ \ No newline at end of file diff --git a/hailort/tools/hw_debug/shell.cpp b/hailort/tools/hw_debug/shell.cpp new file mode 100644 index 0000000..ee5ca38 --- /dev/null +++ b/hailort/tools/hw_debug/shell.cpp @@ -0,0 +1,197 @@ +/** + * @file shell.cpp + * @brief Generic shell - contains commands and sub-shells. The shell implements + * a parse-execute commands loop. + */ +#include "shell.hpp" +#include "readline_wrapper.hpp" +#include "spdlog/fmt/fmt.h" + +#include +#include + +static std::vector split_string(std::string s, const std::string &delimiter = " ") +{ + std::vector parts; + auto pos = std::string::npos; + while ((pos = s.find(delimiter)) != std::string::npos) { + parts.push_back(s.substr(0, pos)); + s.erase(0, pos + delimiter.size()); + } + parts.push_back(s); + return parts; +} + +ShellCommand::ShellCommand(const std::string &name, const std::string &short_name, const std::string &help) : + m_name(name), + m_short_name(short_name), + m_help(help) +{} + +Shell::Shell(const std::string &prompt) : + m_prompt(prompt), + m_commands(), + m_should_quit(false) +{ + add_command(std::make_unique(*this)); + add_command(std::make_unique(*this)); +} + +void Shell::add_command(std::unique_ptr shell_command) +{ + assert(nullptr == get_command_by_name(shell_command->name())); + assert(nullptr == get_command_by_name(shell_command->short_name())); + + m_commands.emplace_back(std::move(shell_command)); +} + +std::shared_ptr Shell::add_subshell(const std::string &name, const std::string &short_name) +{ + auto subshell_cmd = std::make_unique(name, short_name, + fmt::format("Start {} subshell", name)); + auto shell = subshell_cmd->get_shell(); + add_command(std::move(subshell_cmd)); + return shell; +} + +void Shell::run_forever() +{ + ReadLineWrapper::set_auto_completer([this](const std::string &text) { + return autocomplete(text); + }); + + std::cout << get_help() << std::endl; + while (!m_should_quit) { + std::string name; + std::vector args; + std::tie(name, args) = ask_user_command(); + + auto cmd = get_command_by_name(name); + if (cmd == nullptr) { + std::cout << fmt::format("Command {} not found...", name) << std::endl; + continue; + } + + try { + auto cmd_result = cmd->execute(args); + cmd_result.print(std::cout); + } catch (const std::runtime_error &exc) { + std::cerr << fmt::format("Error: {}", exc.what()) << std::endl; + } + } + + ReadLineWrapper::remove_auto_completer(); + + // Disable quit for next run + m_should_quit = false; +} + +std::vector Shell::autocomplete(const std::string &text) +{ + std::vector names; + for (const auto &cmd : m_commands) { + if (text.empty() || (cmd->name().rfind(text, 0) == 0)) { + names.emplace_back(cmd->name()); + } + + if (text.empty() || (cmd->short_name().rfind(text, 0) == 0)) { + names.emplace_back(cmd->short_name()); + } + } + + return names; +} + +std::pair> Shell::ask_user_command() +{ + while (true) { + auto line = ReadLineWrapper::readline(m_prompt); + auto parts = split_and_trim_line(line); + if (parts.empty()) { + continue; + } + + ReadLineWrapper::add_history(line); + const auto name = parts[0]; + const std::vector args(parts.begin() + 1, parts.end()); + return std::make_pair(name, args); + } +} + +std::vector Shell::split_and_trim_line(const std::string &line) +{ + auto parts = split_string(line, " "); + + // remove spaces + for (auto &part : parts) { + part.erase(std::remove_if(part.begin(), part.end(), [](char c) { + return std::isspace(c); + }), part.end()); + } + + // Remove empty commands + parts.erase(std::remove_if(parts.begin(), parts.end(), [](const std::string &s) { + return s.empty(); + }), parts.end()); + + return parts; +} + +std::string Shell::get_help() const +{ + std::string result; + for (const auto &cmd : m_commands) { + auto full_name = fmt::format("{}({})", cmd->name(), cmd->short_name()); + result += fmt::format("{:<30}{}\n", full_name, cmd->help()); + } + return result; +} + +ShellCommand *Shell::get_command_by_name(const std::string &name) +{ + for (const auto &cmd : m_commands) { + if ((name == cmd->name()) || (name == cmd->short_name())) { + return cmd.get(); + } + } + return nullptr; +} + +Shell::Help::Help(Shell &shell) : + ShellCommand("help", "h", "Show help on all commands"), + m_shell(shell) +{} + +ShellResult Shell::Help::execute(const std::vector &) +{ + return m_shell.get_help(); +} + +Shell::Quit::Quit(Shell &shell) : + ShellCommand("quit", "q", "Quit current shell"), + m_shell(shell) +{} + +ShellResult Shell::Quit::execute(const std::vector &) +{ + m_shell.m_should_quit = true; + return ShellResult(""); +} + + +StartSubshellCommand::StartSubshellCommand(const std::string &name, const std::string &short_name, + const std::string &help) : + ShellCommand(name, short_name, help), + m_shell(std::make_shared(fmt::format("({})> ", name))) +{} + +ShellResult StartSubshellCommand::execute(const std::vector &) +{ + m_shell->run_forever(); + return ShellResult(""); +} + +std::shared_ptr StartSubshellCommand::get_shell() +{ + return m_shell; +} diff --git a/hailort/tools/hw_debug/shell.hpp b/hailort/tools/hw_debug/shell.hpp new file mode 100644 index 0000000..a06e42a --- /dev/null +++ b/hailort/tools/hw_debug/shell.hpp @@ -0,0 +1,116 @@ +/** + * @file shell.hpp + * @brief Generic shell - contains commands and sub-shells. The shell implements + * a parse-execute commands loop. + */ + +#ifndef _HW_DEBUG_SHELL_H_ +#define _HW_DEBUG_SHELL_H_ + +#include +#include +#include +#include +#include + +// Result returned from each command. Currently wrapper to the output string. +class ShellResult final { +public: + ShellResult(const std::string &str) : + m_str(str) + {} + + ShellResult(const std::vector &results) + { + std::stringstream out; + for (const auto &result : results) { + result.print(out); + } + m_str = out.str(); + } + + void print(std::ostream &out) const + { + out << m_str; + } + +private: + std::string m_str; +}; + +// Base abstract class for some shell command. +class ShellCommand { +public: + virtual ~ShellCommand() = default; + + ShellCommand(const std::string &name, const std::string &short_name, + const std::string &help); + + std::string name() const { return m_name; } + std::string short_name() const { return m_short_name; } + std::string help() const { return m_help; } + + virtual ShellResult execute(const std::vector &args) = 0; +private: + const std::string m_name; + const std::string m_short_name; + const std::string m_help; +}; + +class Shell final { +public: + explicit Shell(const std::string &prompt); + + Shell(const Shell &other) = delete; + Shell &operator=(const Shell &other) = delete; + + void add_command(std::unique_ptr shell_command); + std::shared_ptr add_subshell(const std::string &name, const std::string &short_name); + void run_forever(); + std::vector autocomplete(const std::string &text); + +private: + + class Help : public ShellCommand { + public: + Help(Shell &shell); + ShellResult execute(const std::vector &args) override; + private: + Shell &m_shell; + }; + + class Quit : public ShellCommand { + public: + Quit(Shell &shell); + ShellResult execute(const std::vector &args) override; + private: + Shell &m_shell; + }; + + // pair of command name and its arguments. + std::pair> ask_user_command(); + static std::vector split_and_trim_line(const std::string &line); + + std::string get_help() const; + // Gets a command or nullptr if it doesn't exists. + ShellCommand *get_command_by_name(const std::string &name); + + const std::string m_prompt; + std::vector> m_commands; + bool m_should_quit; +}; + + +// This command starts a new subshell +class StartSubshellCommand : public ShellCommand { +public: + StartSubshellCommand(const std::string &name, const std::string &short_name, + const std::string &help); + ShellResult execute(const std::vector &) override; + + std::shared_ptr get_shell(); +private: + std::shared_ptr m_shell; +}; + +#endif /* _HW_DEBUG_SHELL_H_ */ \ No newline at end of file -- 2.34.1