diff --git a/CMakeLists.txt b/CMakeLists.txt index c95ca7f1..f44f4fc5 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 2f4ae556..1ae56479 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,8 @@ 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 diff --git a/common/include/context_switch_defs.h b/common/include/context_switch_defs.h index 7a15520f..40d5445b 100644 --- a/common/include/context_switch_defs.h +++ b/common/include/context_switch_defs.h @@ -101,6 +101,8 @@ typedef enum __attribute__((packed)) { 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, /* Must be last */ CONTEXT_SWITCH_DEFS__ACTION_TYPE_COUNT @@ -270,7 +272,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,6 +315,16 @@ typedef struct { uint32_t buffered_rows_count; } CONTEXT_SWITCH_DEFS__activate_ddr_buffer_output_data_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 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; @@ -321,6 +332,8 @@ typedef union { 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_DEFS__open_boundary_input_channel_data_t open_boundary_input_channel_data; + CONTEXT_SWITCH_DEFS__open_boundary_output_channel_data_t open_boundary_output_channel_data; } CONTEXT_SWITCH_COMMON__activate_edge_layer_action_t; typedef struct { diff --git a/common/include/control_protocol.h b/common/include/control_protocol.h index a08768c1..ced20910 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) @@ -1041,11 +1040,9 @@ typedef enum { 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; @@ -1136,6 +1133,8 @@ 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 context_type_length; + uint8_t context_type; // CONTROL_PROTOCOL__context_switch_context_type_t uint32_t cfg_channels_count_length; uint8_t cfg_channels_count; uint32_t config_channel_infos_length; @@ -1331,6 +1330,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; @@ -1721,9 +1724,39 @@ 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; + +// TODO: After HRT-8111, CONTROL_PROTOCOL__CONTEXT_SWITCH_NUMBER_OF_NON_DYNAMIC_CONTEXTS should include the +// batch switching context. I.e. it's index should come before the first dynamic context; probably: +// - ACTIVATION +// - BATCH_SWITCHING +// - PRELIMINARY +// - first dynamic... (i.e. CONTROL_PROTOCOL__CONTEXT_SWITCH_NUMBER_OF_NON_DYNAMIC_CONTEXTS == 3) +typedef enum { + CONTROL_PROTOCOL__CONTEXT_SWITCH_INDEX_ACTIVATION_CONTEXT = 0, + 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_DYNAMIC_CONTEXTS (128) +#define CONTROL_PROTOCOL__MAX_TOTAL_CONTEXTS (CONTROL_PROTOCOL__MAX_DYNAMIC_CONTEXTS + CONTROL_PROTOCOL__MAX_CONTEXT_SWITCH_APPLICATIONS * CONTROL_PROTOCOL__CONTEXT_SWITCH_NUMBER_OF_NON_DYNAMIC_CONTEXTS) + typedef struct { bool is_first_control_per_context; bool is_last_control_per_context; + uint8_t context_type; // CONTROL_PROTOCOL__context_switch_context_type_t 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; @@ -1733,6 +1766,10 @@ typedef struct { uint8_t context_network_data[CONTROL_PROTOCOL__CONTEXT_NETWORK_DATA_SINGLE_CONTROL_MAX_SIZE]; } CONTROL_PROTOCOL__context_switch_context_info_single_control_t; +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); + + /* Context switch user structs */ #define CONTROL_PROTOCOL__CONTEXT_NETWORK_DATA_MAX_SIZE (8 * 1024) diff --git a/common/include/firmware_header_utils.h b/common/include/firmware_header_utils.h index 1a001f05..63241010 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 edea0ac7..75c6c45b 100644 --- a/common/include/firmware_status.h +++ b/common/include/firmware_status.h @@ -404,6 +404,8 @@ 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_MODULE__X(FIRMWARE_MODULE__POWER_MEASUREMENT)\ FIRMWARE_STATUS__X(HAILO_POWER_MEASUREMENT_STATUS_POWER_INIT_ERROR)\ @@ -745,6 +747,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)\ @@ -1049,6 +1056,12 @@ 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)\ + typedef enum { diff --git a/hailort/CMakeLists.txt b/hailort/CMakeLists.txt index fa343092..1fae9307 100644 --- a/hailort/CMakeLists.txt +++ b/hailort/CMakeLists.txt @@ -1,8 +1,28 @@ 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_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) + +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=11 ) add_definitions( -DFIRMWARE_VERSION_REVISION=0 ) if(HAILO_BUILD_SERVICE) add_definitions( -DHAILO_SUPPORT_MULTI_PROCESS ) @@ -116,32 +136,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) diff --git a/hailort/LICENSE-3RD-PARTY.md b/hailort/LICENSE-3RD-PARTY.md index 46aead9e..d1b7129a 100644 --- a/hailort/LICENSE-3RD-PARTY.md +++ b/hailort/LICENSE-3RD-PARTY.md @@ -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/filesystem.hpp b/hailort/common/filesystem.hpp index 3afe4e8b..16a1e3c6 100644 --- a/hailort/common/filesystem.hpp +++ b/hailort/common/filesystem.hpp @@ -117,6 +117,11 @@ class LockedFile { 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/os/posix/filesystem.cpp b/hailort/common/os/posix/filesystem.cpp index a22d2375..00fdf137 100644 --- a/hailort/common/os/posix/filesystem.cpp +++ b/hailort/common/os/posix/filesystem.cpp @@ -145,7 +145,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); @@ -211,12 +216,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/utils.hpp b/hailort/common/utils.hpp index f74cb217..5834c17b 100644 --- a/hailort/common/utils.hpp +++ b/hailort/common/utils.hpp @@ -250,16 +250,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 3b25845a..85ec7166 100644 --- a/hailort/drivers/common/hailo_ioctl_common.h +++ b/hailort/drivers/common/hailo_ioctl_common.h @@ -152,9 +152,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 +218,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 +230,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 +305,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 +327,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 +367,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 +380,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 +413,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 84237133..7c0c9d9f 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/hailort_rpc_service.cpp b/hailort/hailort_service/hailort_rpc_service.cpp index c24c6264..cd8dc7fe 100644 --- a/hailort/hailort_service/hailort_rpc_service.cpp +++ b/hailort/hailort_service/hailort_rpc_service.cpp @@ -293,34 +293,39 @@ grpc::Status HailoRtRpcService::ConfiguredNetworkGroup_get_output_vstream_groups return grpc::Status::OK; } +void serialize_vstream_info(const hailo_vstream_info_t &info, 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); +} + 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); + serialize_vstream_info(info, &info_proto); vstream_infos_proto->Add(std::move(info_proto)); } } @@ -493,9 +498,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(); @@ -673,7 +678,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 +691,7 @@ 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; } @@ -740,5 +745,69 @@ grpc::Status HailoRtRpcService::OutputVStream_resume(grpc::ServerContext*, const 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) +{ + 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_get_info(grpc::ServerContext*, const VStream_get_info_Request *request, + VStream_get_info_Reply *reply) +{ + 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 ed521764..dc9682a4 100644 --- a/hailort/hailort_service/hailort_rpc_service.hpp +++ b/hailort/hailort_service/hailort_rpc_service.hpp @@ -76,7 +76,14 @@ class HailoRtRpcService final : public HailoRtRpc::Service { 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 +92,9 @@ class HailoRtRpcService final : public HailoRtRpc::Service { 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_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; diff --git a/hailort/hailortcli/CMakeLists.txt b/hailort/hailortcli/CMakeLists.txt index 1cb49565..04ec74cb 100644 --- a/hailort/hailortcli/CMakeLists.txt +++ b/hailort/hailortcli/CMakeLists.txt @@ -61,8 +61,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 d9a00123..8619880a 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 f0f77546..dae8600b 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 729b5dc2..2002a8d7 100644 --- a/hailort/hailortcli/command.hpp +++ b/hailort/hailortcli/command.hpp @@ -64,11 +64,12 @@ class DeviceCommand : public Command { 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 27b45eca..16fb5ac3 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 8c8ce43f..4a3c6bd8 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 @@ class CliCommon final 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 0eb16c43..f7144014 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); } @@ -283,6 +296,14 @@ 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_COUNT: // Fallthrough // Handling CONTEXT_SWITCH_DEFS__ACTION_TYPE_COUNT is needed because we compile this file with -Wswitch-enum @@ -326,24 +347,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 +385,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 +393,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 +409,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 +434,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 +608,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 65638a12..fca2c0b1 100644 --- a/hailort/hailortcli/download_action_list_command.hpp +++ b/hailort/hailortcli/download_action_list_command.hpp @@ -56,8 +56,9 @@ class DownloadActionListCommand : public DeviceCommand 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); }; @@ -95,7 +96,9 @@ static std::pair mapping[] = { {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_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"}, }; 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"); @@ -132,5 +135,7 @@ 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 f30f111f..6c5ef40d 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 757df330..23e3681b 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 c7fc5dc5..efd59e9d 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 c3b589b6..5dc68c9b 100644 --- a/hailort/hailortcli/hailortcli.cpp +++ b/hailort/hailortcli/hailortcli.cpp @@ -96,9 +96,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 diff --git a/hailort/hailortcli/mon_command.cpp b/hailort/hailortcli/mon_command.cpp index 38daf1d3..ada7b27f 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,10 @@ 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 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 +48,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 +58,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 +119,90 @@ 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); + CHECK_AS_EXPECTED(ret == 0, HAILO_INTERNAL_FAILURE,"Failed to get_terminal_line_width, with errno: {}", errno); + + 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/run_command.cpp b/hailort/hailortcli/run_command.cpp index 8eff84f1..7c706054 100644 --- a/hailort/hailortcli/run_command.cpp +++ b/hailort/hailortcli/run_command.cpp @@ -48,6 +48,8 @@ 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_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 +88,7 @@ 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); } static void add_run_command_params(CLI::App *run_subcommand, inference_runner_params& params) @@ -118,7 +120,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, @@ -213,11 +215,12 @@ static void add_run_command_params(CLI::App *run_subcommand, inference_runner_pa ->default_val("runtime_data.json") ->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"; + batch_to_measure_help << "Batch to be measured (non-negative integer)" << std::endl + << "The last batch will be measured if '" << RUNTIME_DATA_BATCH_TO_MEASURE_OPT_LAST << "' 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); + params.runtime_data.batch_to_measure_str, batch_to_measure_help.str()) + ->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 +260,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 +281,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); + } } }); } @@ -433,17 +439,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 +555,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) @@ -1051,7 +1060,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 +1173,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) @@ -1188,54 +1197,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 +1224,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 +1242,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 +1283,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 +1291,89 @@ 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(); + } + + // 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"); + +#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) { + DownloadActionListCommand::execute(device.get(), params.runtime_data.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 806ba055..5eaf8347 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 @@ class RunCommand : public Command { 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 @@ class NetworkBatchValidator : public CLI::Validator { 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 @@ class NetworkBatchValidator : public CLI::Validator { }; } -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/sensor_config_command.cpp b/hailort/hailortcli/sensor_config_command.cpp index 0342edf7..37232aa9 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 2ef61548..d6659cd4 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 11) set(HAILORT_REVISION_VERSION 0) # Add the cmake folder so the modules there are found diff --git a/hailort/libhailort/bindings/gstreamer/CMakeLists.txt b/hailort/libhailort/bindings/gstreamer/CMakeLists.txt index e5f782b1..e76fbef6 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.11.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 621cf1ee..bf852294 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 ff982304..cf654fce 100644 --- a/hailort/libhailort/bindings/gstreamer/gst-hailo/common.hpp +++ b/hailort/libhailort/bindings/gstreamer/gst-hailo/common.hpp @@ -52,7 +52,9 @@ using namespace hailort; #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 171a3510..bdc44b74 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); @@ -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", @@ -192,8 +196,8 @@ 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); @@ -438,6 +442,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 +516,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 +530,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, @@ -661,7 +681,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 +858,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 7ff211d7..c6f6f99a 100644 --- a/hailort/libhailort/bindings/gstreamer/gst-hailo/gsthailonet.hpp +++ b/hailort/libhailort/bindings/gstreamer/gst-hailo/gsthailonet.hpp @@ -53,7 +53,8 @@ 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_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 @@ struct HailoNetProperties final 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 9c6835c5..5a0624b7 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 892610a8..56e0b96a 100644 --- a/hailort/libhailort/bindings/gstreamer/gst-hailo/gsthailorecv.hpp +++ b/hailort/libhailort/bindings/gstreamer/gst-hailo/gsthailorecv.hpp @@ -92,6 +92,7 @@ class HailoRecvImpl final { 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 cebeee16..eec8b0c9 100644 --- a/hailort/libhailort/bindings/gstreamer/gst-hailo/gsthailosend.cpp +++ b/hailort/libhailort/bindings/gstreamer/gst-hailo/gsthailosend.cpp @@ -254,6 +254,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 +312,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 3e2167a3..5ea816b3 100644 --- a/hailort/libhailort/bindings/gstreamer/gst-hailo/gsthailosend.hpp +++ b/hailort/libhailort/bindings/gstreamer/gst-hailo/gsthailosend.hpp @@ -71,6 +71,7 @@ class HailoSendImpl final 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 9808c591..8d6881f7 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 { @@ -56,7 +57,7 @@ Expected> create_shared_vdevice(const void *element, co } 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,6 +66,7 @@ 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()); @@ -72,7 +74,7 @@ Expected> create_shared_vdevice(const void *element, ui } 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,6 +83,7 @@ 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()); @@ -88,36 +91,36 @@ Expected> create_unique_vdevice(const void *element, ui } 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(); @@ -243,39 +246,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; 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 93f86b1a..cef30b9f 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 @@ class NetworkGroupHandle final 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); @@ -100,9 +99,9 @@ class NetworkGroupHandle final private: Expected get_configure_params(Hef &hef, 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/platform/hailo_platform/pyhailort/pyhailort.py b/hailort/libhailort/bindings/python/platform/hailo_platform/pyhailort/pyhailort.py index 921b6237..6d909cfe 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 @@ -1233,7 +1232,7 @@ class HailoFormatFlags(_pyhailort.FormatFlags): SUPPORTED_PROTOCOL_VERSION = 2 SUPPORTED_FW_MAJOR = 4 -SUPPORTED_FW_MINOR = 10 +SUPPORTED_FW_MINOR = 11 SUPPORTED_FW_REVISION = 0 MEGA_MULTIPLIER = 1000.0 * 1000.0 @@ -1250,9 +1249,11 @@ def __str__(self): 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 +1304,9 @@ def get_hw_arch_str(device_arch): 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 +1458,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 = ' py::str { return py::str(board_info.board_name, board_info.board_name_length); @@ -413,6 +412,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) ; @@ -792,6 +792,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; }); diff --git a/hailort/libhailort/bindings/python/src/vdevice_api.hpp b/hailort/libhailort/bindings/python/src/vdevice_api.hpp index 0468b765..746b72d1 100644 --- a/hailort/libhailort/bindings/python/src/vdevice_api.hpp +++ b/hailort/libhailort/bindings/python/src/vdevice_api.hpp @@ -49,7 +49,18 @@ class VDeviceWrapper { 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 @@ class VDeviceWrapper { 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 3c5abf64..98520bda 100644 --- a/hailort/libhailort/cmake/toolchains/toolchains.yaml +++ b/hailort/libhailort/cmake/toolchains/toolchains.yaml @@ -34,7 +34,7 @@ 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/24544175/+files/libpython3.9-dev_3.9.15-1+bionic1_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 aae94614..b0cfdda1 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 768b0808..4d3c8807 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,15 @@ 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. +> **_NOTE:_** 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 --target --config release --target cpp_vstreams_example +``` + ## Running the examples One can run the example using the following commands, from the examples directory: ```sh - build// [params..] + build/// [params..] ``` diff --git a/hailort/libhailort/examples/c/CMakeLists.txt b/hailort/libhailort/examples/c/CMakeLists.txt index ec29225a..97275f72 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 00000000..0daff607 --- /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.11.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 4275bfee..7688d228 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 00000000..1ebdbd89 --- /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.11.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 aca18fcf..51478c8f 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 @@ int main(int argc, char **argv) (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 00000000..8c897512 --- /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.11.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 99% rename from hailort/libhailort/examples/c/multi_device_example.c rename to hailort/libhailort/examples/c/multi_device_example/multi_device_example.c index 787168b4..5225e3d0 100644 --- a/hailort/libhailort/examples/c/multi_device_example.c +++ b/hailort/libhailort/examples/c/multi_device_example/multi_device_example.c @@ -149,6 +149,8 @@ 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 = (uint32_t)actual_count; status = hailo_create_vdevice(¶ms, &vdevice); REQUIRE_SUCCESS(status, l_exit, "Failed to create vdevice"); 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 00000000..5ec3d79f --- /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.11.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 09d26c9d..552d07c1 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 00000000..e4e5689d --- /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.11.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 03a0ff18..b68687f9 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 00000000..f185bc9b --- /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.11.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 00000000..ca417a5b --- /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.11.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 99% 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 e1ac03f2..3fd9f4a8 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 @@ -192,7 +192,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"); 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 00000000..2b7087f3 --- /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.11.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 190d087f..5d56190f 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 00000000..a779d87d --- /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.11.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 e75ef410..04c50768 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 60d822c3..4dad5326 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 00000000..a0cd0046 --- /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.11.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 00000000..bf526973 --- /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.11.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 98% rename from hailort/libhailort/examples/cpp/multi_device_example.cpp rename to hailort/libhailort/examples/cpp/multi_device_example/multi_device_example.cpp index 02ee32aa..23ba591c 100644 --- a/hailort/libhailort/examples/cpp/multi_device_example.cpp +++ b/hailort/libhailort/examples/cpp/multi_device_example/multi_device_example.cpp @@ -139,6 +139,7 @@ int main() return status; } + 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/multi_network_vstream_example/CMakeLists.txt b/hailort/libhailort/examples/cpp/multi_network_vstream_example/CMakeLists.txt new file mode 100644 index 00000000..8ed0a903 --- /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.11.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 eb52fb39..493393c3 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 00000000..4fe01b96 --- /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.11.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 60405075..bb5323de 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 68% rename from hailort/libhailort/examples/cpp/multi_process_example.sh rename to hailort/libhailort/examples/cpp/multi_process_example/multi_process_example.sh index 7d1386b0..7b7e6fd9 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 00000000..f2dee3c6 --- /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.11.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 21c5ce20..f3d3d186 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 00000000..aa850fcc --- /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.11.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 00000000..588e20a8 --- /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.11.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 98% 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 b1002281..757b4eac 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 @@ -92,7 +92,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); 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 00000000..a8a75415 --- /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.11.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 7155e917..26d890d6 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 00000000..73265977 --- /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.11.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 5488e140..9e93cac9 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/include/hailo/device.hpp b/hailort/libhailort/include/hailo/device.hpp index 2fb15216..63dcbe3c 100644 --- a/hailort/libhailort/include/hailo/device.hpp +++ b/hailort/libhailort/include/hailo/device.hpp @@ -344,51 +344,6 @@ class HAILORTAPI Device */ 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. * @@ -690,11 +645,11 @@ class HAILORTAPI Device 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); diff --git a/hailort/libhailort/include/hailo/hailort.h b/hailort/libhailort/include/hailo/hailort.h index 746e3741..0613d778 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 */ @@ -439,6 +439,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 +451,7 @@ typedef struct { typedef struct { bool is_release; + bool extended_context_switch_buffer; hailo_firmware_version_t fw_version; } hailo_core_information_t; @@ -2428,6 +2430,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 +2629,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. */ diff --git a/hailort/libhailort/include/hailo/hef.hpp b/hailort/libhailort/include/hailo/hef.hpp index 94287deb..5d77614b 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; diff --git a/hailort/libhailort/include/hailo/vstream.hpp b/hailort/libhailort/include/hailo/vstream.hpp index d0299e49..85661856 100644 --- a/hailort/libhailort/include/hailo/vstream.hpp +++ b/hailort/libhailort/include/hailo/vstream.hpp @@ -69,12 +69,19 @@ class HAILORTAPI InputVStream 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 @@ class HAILORTAPI OutputVStream 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. diff --git a/hailort/libhailort/scheduler_mon.proto b/hailort/libhailort/scheduler_mon.proto index 25043a3b..01155f80 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 dd7a9aaf..312ba068 100644 --- a/hailort/libhailort/src/CMakeLists.txt +++ b/hailort/libhailort/src/CMakeLists.txt @@ -55,7 +55,6 @@ set(HAILORT_CPP_SOURCES d2h_events_parser.cpp mipi_stream.cpp - hlpcie.cpp vdma_channel.cpp vdma_descriptor_list.cpp vdma_device.cpp @@ -136,7 +135,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/channel_allocator.cpp b/hailort/libhailort/src/channel_allocator.cpp index 45c776f2..8ef93be1 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; } } @@ -82,18 +82,17 @@ const std::set &ChannelAllocator::get_boundary_channel_ids() co return m_boundary_channel_ids; } -const std::set &ChannelAllocator::get_fw_managed_channel_ids() const +const std::set &ChannelAllocator::get_internal_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 778ae8a5..8d3ef314 100644 --- a/hailort/libhailort/src/channel_allocator.hpp +++ b/hailort/libhailort/src/channel_allocator.hpp @@ -32,7 +32,7 @@ class ChannelAllocator final 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 +44,7 @@ class ChannelAllocator final // 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/context_switch/hcp_config_activated_network_group.cpp b/hailort/libhailort/src/context_switch/hcp_config_activated_network_group.cpp index 80b4f960..7a5fb7de 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 @@ -53,8 +53,8 @@ HcpConfigActivatedNetworkGroup::HcpConfigActivatedNetworkGroup( 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), + 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), @@ -66,13 +66,43 @@ HcpConfigActivatedNetworkGroup::HcpConfigActivatedNetworkGroup( return; } m_active_net_group_holder.set(*this); + + status = activate_low_level_streams(CONTROL_PROTOCOL__IGNORE_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; + } } HcpConfigActivatedNetworkGroup::~HcpConfigActivatedNetworkGroup() { - if (m_is_active) { - m_active_net_group_holder.clear(); - deactivate_resources(); + if (!m_is_active) { + return; + } + m_active_net_group_holder.clear(); + + if (nullptr == m_network_group_activated_event) { + return; + } + + m_network_group_activated_event->reset(); + + for (auto &name_pair : m_input_streams) { + const auto status = name_pair.second->flush(); + if (HAILO_SUCCESS != status) { + LOGGER__ERROR("Failed to flush input stream {} with status {}", name_pair.first, status); + } + } + + const auto status = deactivate_low_level_streams(); + if (HAILO_SUCCESS != status) { + LOGGER__ERROR("Failed to deactivate low level streams"); } } diff --git a/hailort/libhailort/src/context_switch/hcp_config_manager.cpp b/hailort/libhailort/src/context_switch/hcp_config_manager.cpp index 8dd2b256..a6d03fe1 100644 --- a/hailort/libhailort/src/context_switch/hcp_config_manager.cpp +++ b/hailort/libhailort/src/context_switch/hcp_config_manager.cpp @@ -31,7 +31,6 @@ #include "hailo/hef.hpp" #include "control.hpp" #include "pcie_device.hpp" -#include "hlpcie.hpp" #include #include @@ -53,6 +52,7 @@ Expected HcpConfigManager::add_hef(Hef &hef, auto &hef_network_groups = hef.pimpl->network_groups(); auto current_net_group_index = static_cast(m_net_groups.size()); 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(); @@ -62,53 +62,47 @@ Expected HcpConfigManager::add_hef(Hef &hef, 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"); + for (const auto &base_network_group_proto : hef_network_groups) { + CHECK_NOT_NULL_AS_EXPECTED(base_network_group_proto, HAILO_INTERNAL_FAILURE); + + auto network_group_proto = Hef::Impl::get_net_group_per_arch(*base_network_group_proto, hef_arch, device_arch, + partial_clusters_layout_bitmap); + CHECK_EXPECTED(network_group_proto); + + const std::string network_group_name = network_group_proto->get().network_group_metadata().network_group_name(); + + /* 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 = m_device.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 { - network_group_ptr = net_group.get(); + continue; } - 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), + CHECK(1 == network_group_proto->get().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, + network_group_name, network_group_proto->get().contexts_size()); + CHECK_AS_EXPECTED(!(Hef::Impl::contains_ddr_layers(network_group_proto->get())), 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); + network_group_name); + status = Hef::Impl::validate_net_group_unique_layer_names(network_group_proto->get()); CHECK_SUCCESS_AS_EXPECTED(status); /* Update preliminary_config and dynamic_contexts recepies */ - auto &proto_preliminary_config = network_group_ptr->preliminary_config(); + auto &proto_preliminary_config = network_group_proto->get().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()); + auto network_group_metadata = hef.pimpl->get_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(), @@ -135,7 +129,7 @@ Expected HcpConfigManager::add_hef(Hef &hef, 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); + status = validate_boundary_streams_were_created(hef, network_group_name, *net_group_shared_ptr); CHECK_SUCCESS_AS_EXPECTED(status); } std::string unmatched_keys = ""; 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 a93e9369..57403fce 100644 --- a/hailort/libhailort/src/context_switch/multi_context/resource_manager.hpp +++ b/hailort/libhailort/src/context_switch/multi_context/resource_manager.hpp @@ -39,6 +39,10 @@ namespace hailort { +constexpr std::chrono::seconds VDMA_FLUSH_TIMEOUT(10); + +#define DEFAULT_ACTUAL_BATCH_SIZE (1) + class ResourcesManager final { public: @@ -51,20 +55,7 @@ class ResourcesManager final 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)) {} + 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); @@ -80,9 +71,20 @@ class ResourcesManager final using context_info_t = CONTROL_PROTOCOL__context_switch_context_info_t; - Expected> add_new_context() + Expected> add_new_context(CONTROL_PROTOCOL__context_switch_context_type_t type) { - return std::ref(*m_contexts.emplace(m_contexts.end())); + CHECK_AS_EXPECTED(type < CONTROL_PROTOCOL__CONTEXT_SWITCH_CONTEXT_TYPE_COUNT, HAILO_INVALID_ARGUMENT); + CHECK_AS_EXPECTED(m_total_context_count < std::numeric_limits::max(), HAILO_INVALID_CONTEXT_COUNT); + + m_contexts.emplace_back(); + auto &context_info = m_contexts.back(); + context_info.context_type = static_cast(type); + m_total_context_count++; + if (CONTROL_PROTOCOL__CONTEXT_SWITCH_CONTEXT_TYPE_DYNAMIC == type) { + m_dynamic_context_count++; + } + + return std::ref(context_info); } const std::vector& get_contexts() @@ -144,14 +146,17 @@ class ResourcesManager final 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 flush_boundary_input_channels(); hailo_status enable_state_machine(uint16_t dynamic_batch_size); + void mark_d2h_callbacks_for_shutdown(); + void unmark_d2h_callbacks_for_shutdown(); 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); @@ -176,9 +181,11 @@ class ResourcesManager final 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 @@ -187,13 +194,7 @@ class ResourcesManager final 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); }; } /* 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 330d6993..0a0f235c 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 @@ -62,21 +62,11 @@ class VdmaConfigActivatedNetworkGroup : public ActivatedNetworkGroupBase 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); - 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; 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 3b617622..6a0647bb 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 @@ -19,7 +19,6 @@ #include "hailo/vdevice.hpp" #include "hailo/expected.hpp" #include "common/utils.hpp" -#include "hlpcie.hpp" #include "vdma_channel.hpp" #include "network_group_scheduler.hpp" @@ -31,8 +30,6 @@ namespace hailort { -#define DISABLE_MULTIPLEXER_ENV_VAR "HAILO_DISABLE_MULTIPLEXER" - class VDeviceBase; class VdmaConfigManager : public ConfigManager @@ -56,6 +53,13 @@ class VdmaConfigManager : public ConfigManager VdmaConfigManager(std::vector> &&devices, bool is_vdevice, NetworkGroupSchedulerWeakPtr network_group_scheduler, hailo_status &status); + Expected get_default_configured_params(Hef &hef, + const std::string &network_group_name); + Expected> create_configured_network_group( + std::shared_ptr network_group_metadata, const ProtoHEFNetworkGroup &network_group_proto, + Hef &hef, const ConfigureNetworkParams &config_params, uint8_t network_group_index, + bool &was_hef_already_configured); + // TODO: (SDK-16665) Dont need is_active flag for dtor? std::vector> m_devices; std::vector> m_net_groups; diff --git a/hailort/libhailort/src/context_switch/network_group.cpp b/hailort/libhailort/src/context_switch/network_group.cpp index 6de284d2..04d0d3cd 100644 --- a/hailort/libhailort/src/context_switch/network_group.cpp +++ b/hailort/libhailort/src/context_switch/network_group.cpp @@ -20,37 +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, 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) @@ -67,6 +55,29 @@ hailo_status ActivatedNetworkGroupBase::activate_low_level_streams(uint16_t dyna return HAILO_SUCCESS; } +hailo_status ActivatedNetworkGroupBase::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; +} + uint32_t ActivatedNetworkGroupBase::get_invalid_frames_count() { uint32_t total_invalid_frames_count = 0; @@ -76,27 +87,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*/) @@ -316,14 +306,25 @@ 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; + + /* 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::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, + CHECK_AS_EXPECTED((CONTROL_PROTOCOL__IGNORE_DYNAMIC_BATCH_SIZE == dynamic_batch_size) || + (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); diff --git a/hailort/libhailort/src/context_switch/network_group_internal.hpp b/hailort/libhailort/src/context_switch/network_group_internal.hpp index 9e26cabc..d5aa2704 100644 --- a/hailort/libhailort/src/context_switch/network_group_internal.hpp +++ b/hailort/libhailort/src/context_switch/network_group_internal.hpp @@ -52,25 +52,23 @@ class ActivatedNetworkGroupBase : public ActivatedNetworkGroup 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, EventPtr &&network_group_activated_event, hailo_status &status); - -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); + hailo_status deactivate_low_level_streams(); + EventPtr m_network_group_activated_event; std::map> &m_input_streams; std::map> &m_output_streams; - EventPtr m_network_group_activated_event; + +private: + hailo_status validate_network_group_params(const hailo_activate_network_group_params_t &network_group_params); }; class ConfiguredNetworkGroupBase : public ConfiguredNetworkGroup diff --git a/hailort/libhailort/src/context_switch/pipeline_multiplexer.cpp b/hailort/libhailort/src/context_switch/pipeline_multiplexer.cpp index a2bdda54..97131f4e 100644 --- a/hailort/libhailort/src/context_switch/pipeline_multiplexer.cpp +++ b/hailort/libhailort/src/context_switch/pipeline_multiplexer.cpp @@ -22,6 +22,15 @@ PipelineMultiplexer::PipelineMultiplexer() : m_read_streams_count(0) {} +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); @@ -79,6 +88,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; } @@ -149,7 +162,8 @@ 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) +hailo_status 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); @@ -157,7 +171,9 @@ hailo_status PipelineMultiplexer::wait_for_read(multiplexer_ng_handle_t network_ 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] { + if (m_should_ng_stop[network_group_handle]) { return true; } @@ -176,6 +192,9 @@ hailo_status PipelineMultiplexer::wait_for_read(multiplexer_ng_handle_t network_ return true; }); + if (!wait_res) { + return HAILO_TIMEOUT; + } if (m_should_ng_stop[network_group_handle]) { return HAILO_STREAM_INTERNAL_ABORT; } diff --git a/hailort/libhailort/src/context_switch/pipeline_multiplexer.hpp b/hailort/libhailort/src/context_switch/pipeline_multiplexer.hpp index 8b483e70..f58478d7 100644 --- a/hailort/libhailort/src/context_switch/pipeline_multiplexer.hpp +++ b/hailort/libhailort/src/context_switch/pipeline_multiplexer.hpp @@ -22,6 +22,8 @@ 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; @@ -42,7 +44,8 @@ class PipelineMultiplexer 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 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 @@ class PipelineMultiplexer 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; diff --git a/hailort/libhailort/src/context_switch/resource_manager.cpp b/hailort/libhailort/src/context_switch/resource_manager.cpp index 1e4cd53f..4a70c69c 100644 --- a/hailort/libhailort/src/context_switch/resource_manager.cpp +++ b/hailort/libhailort/src/context_switch/resource_manager.cpp @@ -159,6 +159,52 @@ Expected ResourcesManager::create(VdmaDevice &vdma_device, Hai return resources_manager; } +ResourcesManager::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_contexts(), + 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_inter_context_buffers(), + m_ddr_channels_pairs(), + 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() +{} + +ResourcesManager::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_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)) +{} + 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,16 +249,16 @@ 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; @@ -224,6 +270,7 @@ Expected> ResourcesManager::create_boundary_vdma_ch { auto network_batch_size = get_network_batch_size(network_name); CHECK_EXPECTED(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(); @@ -296,8 +343,8 @@ 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{}; @@ -354,15 +401,13 @@ hailo_status ResourcesManager::free_channel_index(const LayerIdentifier &layer_i 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]); + update_config_buffer_info(m_preliminary_config, m_contexts[CONTROL_PROTOCOL__CONTEXT_SWITCH_INDEX_PRELIMINARY_CONTEXT]); } 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; + assert(m_dynamic_config.size() == m_dynamic_context_count); + int ctxt_index = CONTROL_PROTOCOL__CONTEXT_SWITCH_INDEX_FIRST_DYNAMIC_CONTEXT; for (auto &cfg_context : m_dynamic_config) { update_config_buffer_info(cfg_context, m_contexts[ctxt_index]); ctxt_index++; @@ -400,11 +445,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 +462,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); } @@ -436,7 +488,11 @@ Expected ResourcesManager::get_network_batch_size(const std::string &n 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; } } @@ -463,6 +519,39 @@ Expected ResourcesManager::read_intermediate_buffer(const IntermediateBu } +hailo_status ResourcesManager::flush_boundary_input_channels() +{ + // Best effort + auto status = HAILO_SUCCESS; + for (auto &ch : m_boundary_channels) { + // Nothing to flush for D2H channels, the function will return with success + const auto flush_status = ch.second->flush(VDMA_FLUSH_TIMEOUT); + if (HAILO_STREAM_INTERNAL_ABORT == flush_status) { + status = HAILO_STREAM_INTERNAL_ABORT; + } + else if (HAILO_SUCCESS != flush_status) { + status = flush_status; + LOGGER__ERROR("Failed to flush input stream {} vdma channel", ch.first); + } + } + + return status; +} + +void ResourcesManager::mark_d2h_callbacks_for_shutdown() +{ + for (auto &ch : m_boundary_channels) { + ch.second->mark_d2h_callbacks_for_shutdown(); + } +} + +void ResourcesManager::unmark_d2h_callbacks_for_shutdown() +{ + for (auto &ch : m_boundary_channels) { + ch.second->unmark_d2h_callbacks_for_shutdown(); + } +} + 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); 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 93445567..0691c901 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 @@ -50,14 +50,12 @@ VdmaConfigActivatedNetworkGroup::VdmaConfigActivatedNetworkGroup( EventPtr &&network_group_activated_event, AccumulatorPtr deactivation_time_accumulator, 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_deactivation_time_accumulator(deactivation_time_accumulator), m_keep_nn_config_during_reset(false) { @@ -88,6 +86,23 @@ VdmaConfigActivatedNetworkGroup::VdmaConfigActivatedNetworkGroup( return; } } + + // TODO: remove this after fixing (HRT-8477) + for (auto &resources_manager : m_resources_managers) { + resources_manager->unmark_d2h_callbacks_for_shutdown(); + } + + 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; + } } VdmaConfigActivatedNetworkGroup::VdmaConfigActivatedNetworkGroup(VdmaConfigActivatedNetworkGroup &&other) noexcept : @@ -96,8 +111,6 @@ VdmaConfigActivatedNetworkGroup::VdmaConfigActivatedNetworkGroup(VdmaConfigActiv 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_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)) {} @@ -112,19 +125,42 @@ VdmaConfigActivatedNetworkGroup::~VdmaConfigActivatedNetworkGroup() const auto start_time = std::chrono::steady_clock::now(); m_active_net_group_holder.clear(); - deactivate_resources(); + + m_network_group_activated_event->reset(); + + // TODO: We call flush_boundary_input_channels instead of the input stream's flush function + // in order to control the timeout (which can be inifinite in some cases) (HRT-8227) + for (auto &resources_manager : m_resources_managers) { + status = resources_manager->flush_boundary_input_channels(); + if (HAILO_STREAM_INTERNAL_ABORT == status) { + LOGGER__DEBUG("Failed to flush boundary input channels with status {}", status); + } + else if (HAILO_SUCCESS != status) { + LOGGER__ERROR("Failed to flush boundary input channels with status {}", status); + } + } + + // TODO: remove this after fixing (HRT-8477) + for (auto &resources_manager : m_resources_managers) { + resources_manager->mark_d2h_callbacks_for_shutdown(); + } 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"); + LOGGER__ERROR("Failed to reset context switch with status {}", status); } } + status = deactivate_low_level_streams(); + if (HAILO_SUCCESS != status) { + LOGGER__ERROR("Failed to deactivate low level streams with status {}", status); + } + 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"); + LOGGER__ERROR("Failed to stop fw managed vdma channels with status {}", status); } } diff --git a/hailort/libhailort/src/context_switch/vdma_config_manager.cpp b/hailort/libhailort/src/context_switch/vdma_config_manager.cpp index c4d33981..10fa4436 100644 --- a/hailort/libhailort/src/context_switch/vdma_config_manager.cpp +++ b/hailort/libhailort/src/context_switch/vdma_config_manager.cpp @@ -27,7 +27,6 @@ #include "pipeline_multiplexer.hpp" #include "pcie_device.hpp" -#include "hlpcie.hpp" #include #include @@ -118,6 +117,134 @@ VdmaConfigManager::~VdmaConfigManager() } } +Expected> VdmaConfigManager::create_configured_network_group( + std::shared_ptr network_group_metadata, + const ProtoHEFNetworkGroup &network_group_proto, Hef &hef, const ConfigureNetworkParams &config_params, + uint8_t network_group_index, bool &was_hef_already_configured) +{ + auto status = Hef::Impl::validate_net_group_unique_layer_names(network_group_proto); + CHECK_SUCCESS_AS_EXPECTED(status); + + 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(); + + /* Validate batch size is identical for all networks in case scheduler is enabled */ + uint16_t ref_batch_size = UINT16_MAX; + if (network_group_scheduler) { + for (const auto &network_params_pair : config_params.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); + } + } + + if (m_is_vdevice && network_group_scheduler && PipelineMultiplexer::should_use_multiplexer()) { + for (auto &network_group : m_net_groups) { + if (network_group->equals(hef, network_group_metadata->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_metadata->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_proto, network_group_index, + device.get(), device.get().get_driver(), config_params, network_group_metadata, 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, m_network_group_scheduler); + + 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_metadata->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); + + return Expected>(net_group_wrapper_ptr); +} + +Expected VdmaConfigManager::get_default_configured_params(Hef &hef, + const std::string &network_group_name) +{ + auto first_streams_interface = m_devices[0].get().get_default_streams_interface(); + CHECK_EXPECTED(first_streams_interface); +#ifndef NDEBUG + // Check that all physical 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 = hef.create_configure_params(first_streams_interface.value(), network_group_name); + CHECK_EXPECTED(config_params); + return config_params.release(); +} + Expected VdmaConfigManager::add_hef(Hef &hef, const NetworkGroupsParamsMap &configure_params) { @@ -142,61 +269,37 @@ Expected VdmaConfigManager::add_hef(Hef &hef, bool was_hef_already_configured = false; 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 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(); + for (const auto &base_network_group_proto : hef_network_groups) { + CHECK_NOT_NULL_AS_EXPECTED(base_network_group_proto, HAILO_INTERNAL_FAILURE); + auto network_group_proto = Hef::Impl::get_net_group_per_arch(*base_network_group_proto, hef_arch, device_arch, + partial_clusters_layout_bitmap); + CHECK_EXPECTED(network_group_proto); - 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"); + const std::string network_group_name = network_group_proto->get().network_group_metadata().network_group_name(); + /* 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 { - 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); + } else if (configure_params.empty()) { + auto config_params_exp = get_default_configured_params(hef, 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 = update_network_batch_size(config_params); + auto 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); @@ -205,99 +308,11 @@ Expected VdmaConfigManager::add_hef(Hef &hef, 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); + auto network_group = create_configured_network_group(network_group_metadata_ptr, network_group_proto->get(), hef, + config_params, current_net_group_index, was_hef_already_configured); + CHECK_EXPECTED(network_group); 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)); + added_network_groups.emplace_back(network_group.release()); } std::string unmatched_keys = ""; for (const auto &pair : configure_params_copy) { @@ -348,6 +363,8 @@ Expected VdmaConfigManager::add_hef(Hef &hef, hailo_status VdmaConfigManager::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 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 3eac9b9e..2fc49f70 100644 --- a/hailort/libhailort/src/context_switch/vdma_config_network_group.cpp +++ b/hailort/libhailort/src/context_switch/vdma_config_network_group.cpp @@ -66,7 +66,7 @@ Expected VdmaConfigNetworkGroup::get_default_streams_i 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 + // Check that all physical devices has the same interface for (auto &resoucres_manager : m_resources_managers) { auto iface = resoucres_manager->get_default_streams_interface(); CHECK_EXPECTED(iface); diff --git a/hailort/libhailort/src/control.cpp b/hailort/libhailort/src/control.cpp index 7bb2105e..ec93dd1a 100644 --- a/hailort/libhailort/src/control.cpp +++ b/hailort/libhailort/src/control.cpp @@ -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, @@ -2375,7 +2381,7 @@ hailo_status Control::context_switch_set_context_info(Device &device, CONTROL_PROTOCOL__context_switch_context_info_t *context_info) { hailo_status status = HAILO_UNINITIALIZED; - CONTROL_PROTOCOL__context_switch_context_info_single_control_t context_info_single_control = {}; + 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; @@ -2398,9 +2404,13 @@ hailo_status Control::context_switch_set_context_info(Device &device, } /* 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.context_type) == sizeof(context_info->context_type), + "mismatch in sizes of context_type"); + context_info_single_control.context_type = context_info->context_type; + 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), @@ -2472,9 +2482,9 @@ hailo_status Control::write_context_switch_info(Device &device, /* 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); + const auto dynamic_contexts_count = context_switch_info->context_switch_main_header.application_header[network_group_index].dynamic_contexts_count; + const auto total_contexts_in_app = static_cast(dynamic_contexts_count + + CONTROL_PROTOCOL__CONTEXT_SWITCH_NUMBER_OF_NON_DYNAMIC_CONTEXTS); /* 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) { @@ -2609,9 +2619,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 +2634,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 +2690,9 @@ hailo_status Control::download_context_action_list_chunk(Device &device, uint8_t 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 +2712,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); diff --git a/hailort/libhailort/src/control.hpp b/hailort/libhailort/src/control.hpp index 3e7e1495..b1491ef0 100644 --- a/hailort/libhailort/src/control.hpp +++ b/hailort/libhailort/src/control.hpp @@ -274,7 +274,10 @@ class Control final * 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 + * @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 +285,10 @@ class Control final * @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 @@ -391,9 +396,10 @@ class Control final 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); static hailo_status change_context_switch_status(Device &device, diff --git a/hailort/libhailort/src/control_protocol.cpp b/hailort/libhailort/src/control_protocol.cpp index ee0c6689..aefc5684 100644 --- a/hailort/libhailort/src/control_protocol.cpp +++ b/hailort/libhailort/src/control_protocol.cpp @@ -1677,7 +1677,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, 9); /* is_first_control_per_context */ request->parameters.context_switch_set_context_info_request.is_first_control_per_context_length = @@ -1691,6 +1691,12 @@ 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; + /* 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; + /* 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)); @@ -1793,7 +1799,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 +1812,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; diff --git a/hailort/libhailort/src/control_protocol.hpp b/hailort/libhailort/src/control_protocol.hpp index 26e18d04..9ec0d8aa 100644 --- a/hailort/libhailort/src/control_protocol.hpp +++ b/hailort/libhailort/src/control_protocol.hpp @@ -46,6 +46,7 @@ typedef struct { } CONTEXT_SWITCH__context_control_slicing_data_t; typedef struct { + uint8_t context_type; // CONTROL_PROTOCOL__context_switch_context_type_t 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; @@ -55,6 +56,9 @@ typedef struct { CONTEXT_SWITCH__context_control_slicing_data_t control_slicing_data; } CONTROL_PROTOCOL__context_switch_context_info_t; +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 { CONTROL_PROTOCOL__context_switch_main_header_t context_switch_main_header; CONTROL_PROTOCOL__context_switch_context_info_t context[CONTROL_PROTOCOL__MAX_TOTAL_CONTEXTS]; @@ -126,8 +130,9 @@ HAILO_COMMON_STATUS_t CONTROL_PROTOCOL__pack_context_switch_set_context_info_req 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, diff --git a/hailort/libhailort/src/core_device.cpp b/hailort/libhailort/src/core_device.cpp index 2a156060..9390d4c4 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 @@ -39,8 +38,7 @@ Expected> CoreDevice::create() CoreDevice::CoreDevice(HailoRTDriver &&driver, hailo_status &status) : - VdmaDevice::VdmaDevice(std::move(driver), Device::Type::CORE), - m_context_switch_manager(nullptr) + VdmaDevice::VdmaDevice(std::move(driver), Device::Type::CORE) { status = update_fw_state(); if (HAILO_SUCCESS != status) { @@ -57,39 +55,6 @@ 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 +65,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 f7e97fd4..21413e0a 100644 --- a/hailort/libhailort/src/core_device.hpp +++ b/hailort/libhailort/src/core_device.hpp @@ -48,20 +48,10 @@ class CoreDevice : public VdmaDevice { 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; }; diff --git a/hailort/libhailort/src/device.cpp b/hailort/libhailort/src/device.cpp index 530e59e2..00e0cdca 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), @@ -467,31 +443,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 +472,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); diff --git a/hailort/libhailort/src/device_internal.cpp b/hailort/libhailort/src/device_internal.cpp index 1b0a3a4f..285aace4 100644 --- a/hailort/libhailort/src/device_internal.cpp +++ b/hailort/libhailort/src/device_internal.cpp @@ -226,6 +226,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/hailort.cpp b/hailort/libhailort/src/hailort.cpp index ed3ce33d..5e301f7c 100644 --- a/hailort/libhailort/src/hailort.cpp +++ b/hailort/libhailort/src/hailort.cpp @@ -557,39 +557,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 +580,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 +589,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; diff --git a/hailort/libhailort/src/hailort_defaults.hpp b/hailort/libhailort/src/hailort_defaults.hpp index 0787fadc..f1c8a2ea 100644 --- a/hailort/libhailort/src/hailort_defaults.hpp +++ b/hailort/libhailort/src/hailort_defaults.hpp @@ -360,6 +360,7 @@ class HailoRTDefaults { hailo_vdevice_params_t params = {}; params.device_count = HAILO_DEFAULT_DEVICE_COUNT; + params.scheduling_algorithm = HAILO_SCHEDULING_ALGORITHM_ROUND_ROBIN; IGNORE_DEPRECATION_WARNINGS_BEGIN params.device_infos = nullptr; diff --git a/hailort/libhailort/src/hailort_rpc_client.cpp b/hailort/libhailort/src/hailort_rpc_client.cpp index 4dbd731c..2dff0eaa 100644 --- a/hailort/libhailort/src/hailort_rpc_client.cpp +++ b/hailort/libhailort/src/hailort_rpc_client.cpp @@ -360,17 +360,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 +510,48 @@ Expected>> HailoRtRpcClient::ConfiguredNetw return result; } +hailo_vstream_info_t deserialize_vstream_info(const VStreamInfo &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; @@ -757,7 +763,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 +775,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 +787,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 +799,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 638309cd..8c03c8db 100644 --- a/hailort/libhailort/src/hailort_rpc_client.hpp +++ b/hailort/libhailort/src/hailort_rpc_client.hpp @@ -51,7 +51,7 @@ class HailoRtRpcClient final { 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); @@ -82,10 +82,15 @@ class HailoRtRpcClient final { 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; }; diff --git a/hailort/libhailort/src/hef.cpp b/hailort/libhailort/src/hef.cpp index b2b2657e..1faa7bf1 100644 --- a/hailort/libhailort/src/hef.cpp +++ b/hailort/libhailort/src/hef.cpp @@ -19,7 +19,6 @@ #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" @@ -66,7 +65,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 +76,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); } @@ -2283,6 +2282,55 @@ static hailo_status fill_context_recepies_for_multi_context(const ProtoHEFNetwor return HAILO_SUCCESS; } +static hailo_status fill_activation_config_recepies_for_multi_context( + CONTROL_PROTOCOL__context_switch_context_info_t &context_info, ResourcesManager &resources_manager, + const ProtoHEFNetworkGroup &network_group_proto, std::shared_ptr network_group_metadata) +{ + uint8_t *context_meta_data_head_pointer = context_info.context_network_data; + + // We'll go over all the edge layers in all of the contexts and select boundary (input/output) edge layers + for (uint8_t context_index = 0; context_index < network_group_proto.contexts_size(); ++context_index) { + const auto &context_metadata = network_group_proto.contexts(context_index).metadata(); + 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); + + const auto boundary_output_layers = network_group_metadata->get_boundary_output_layer_infos(context_index); + for (const auto &output_layer_info : boundary_output_layers) { + const auto status = fill_boundary_output_layer(&context_info, &context_meta_data_head_pointer, + resources_manager, output_layer_info); + CHECK_SUCCESS(status); + } + + const auto boundary_input_layers = network_group_metadata->get_boundary_input_layer_infos(context_index); + for (const auto &input_layer_info : boundary_input_layers) { + const auto status = fill_boundary_input_layer(&context_info, &context_meta_data_head_pointer, + resources_manager, input_layer_info); + CHECK_SUCCESS(status); + } + } + + // The activation context has only one action - EdgeLayerActivationActionsPositionMarker + // It's placed in a none trigger (all actions must be placed in a trigger group), and signals the fw + // to add open boundary channel actions at the start of the context. + const auto trigger = ContextSwitchTrigger::create_none_trigger(); + CHECK_EXPECTED_AS_STATUS(trigger); + auto status = trigger->add_to_trigger_group(&context_info, &context_meta_data_head_pointer); + CHECK_SUCCESS(status); + + auto action = EdgeLayerActivationActionsPositionMarker::create(); + CHECK_EXPECTED_AS_STATUS(action); + status = action.value()->execute(&context_info, &context_meta_data_head_pointer); + CHECK_SUCCESS(status); + + // 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; +} + 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, @@ -2350,17 +2398,22 @@ Expected> Hef::Impl::create_resources_manager( parsing_info.release(), net_group_index); CHECK_EXPECTED(resources_manager); - auto preliminary_context = resources_manager->add_new_context(); - CHECK_EXPECTED(preliminary_context); + auto activation_context = resources_manager->add_new_context(CONTROL_PROTOCOL__CONTEXT_SWITCH_CONTEXT_TYPE_ACTIVATION); + CHECK_EXPECTED(activation_context); + auto status = fill_activation_config_recepies_for_multi_context(activation_context.value().get(), + resources_manager.value(), network_group_proto, network_group_metadata); + CHECK_SUCCESS_AS_EXPECTED(status); - auto status = fill_preliminary_config_recepies_for_multi_context(hw_arch, preliminary_context.value().get(), + auto preliminary_context = resources_manager->add_new_context(CONTROL_PROTOCOL__CONTEXT_SWITCH_CONTEXT_TYPE_PRELIMINARY); + CHECK_EXPECTED(preliminary_context); + 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(); + auto new_context = resources_manager->add_new_context(CONTROL_PROTOCOL__CONTEXT_SWITCH_CONTEXT_TYPE_DYNAMIC); CHECK_EXPECTED(new_context); status = fill_context_recepies_for_multi_context(network_group_proto, hw_arch, new_context.value().get(), resources_manager.value(), @@ -2369,7 +2422,7 @@ Expected> Hef::Impl::create_resources_manager( } resources_manager->update_dynamic_contexts_buffer_info(); - status = resources_manager->create_fw_managed_vdma_channels(); + status = resources_manager->create_internal_vdma_channels(); CHECK_SUCCESS_AS_EXPECTED(status); auto resources_manager_ptr = make_shared_nothrow(resources_manager.release()); @@ -2378,6 +2431,24 @@ Expected> Hef::Impl::create_resources_manager( return resources_manager_ptr; } +ExpectedRef Hef::Impl::get_net_group_per_arch(const ProtoHEFNetworkGroup &base_net_group, + ProtoHEFHwArch hef_arch, hailo_device_architecture_t device_arch, uint32_t partial_clusters_layout_bitmap) +{ + 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 : base_net_group.partial_network_groups()) { + if ((partial_clusters_layout_bitmap == partial_network_group.layout().partial_clusters_layout_bitmap()) || + ((HAILO_ARCH_HAILO8 == device_arch))) { + return std::ref(partial_network_group.network_group()); + } + } + LOGGER__ERROR("There is no matching partial_clusters_layout_bitmap configuration in the given HEF"); + return make_unexpected(HAILO_INVALID_HEF); + } else { + return std::ref(base_net_group); + } +} + Expected> Hef::Impl::get_sorted_output_names(const std::string &net_group_name) { auto network_group_metadata = get_network_group_metadata(net_group_name); @@ -2640,6 +2711,11 @@ Expected ContextSwitchTrigger::serialize(const Prot return make_unexpected(HAILO_INTERNAL_FAILURE); } +Expected ContextSwitchTrigger::create_none_trigger() +{ + return ContextSwitchTrigger(HEF_METADATA__build_none_trigger()); +} + Expected ContextSwitchTrigger::create(const ProtoHEFTrigger &proto_trigger) { auto serialized_trigger = serialize(proto_trigger); diff --git a/hailort/libhailort/src/hef_internal.hpp b/hailort/libhailort/src/hef_internal.hpp index 0fb83ad8..7eb77ca9 100644 --- a/hailort/libhailort/src/hef_internal.hpp +++ b/hailort/libhailort/src/hef_internal.hpp @@ -328,6 +328,9 @@ class Hef::Impl final std::shared_ptr network_group_metadata, const ProtoHEFHwArch &hw_arch); + static ExpectedRef get_net_group_per_arch(const ProtoHEFNetworkGroup &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); @@ -528,6 +531,7 @@ class HefUtils final class ContextSwitchTrigger final { public: + static Expected create_none_trigger(); static Expected create(const ProtoHEFTrigger &proto_trigger); ContextSwitchTrigger(ContextSwitchTrigger &&) = default; ContextSwitchTrigger(const ContextSwitchTrigger &) = delete; diff --git a/hailort/libhailort/src/hlpcie.cpp b/hailort/libhailort/src/hlpcie.cpp deleted file mode 100644 index 634f68c7..00000000 --- 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 7136342a..00000000 --- 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 173a0cf9..9bcb9cd8 100644 --- a/hailort/libhailort/src/inference_pipeline.cpp +++ b/hailort/libhailort/src/inference_pipeline.cpp @@ -13,6 +13,7 @@ #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 +125,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); diff --git a/hailort/libhailort/src/network_group_client.cpp b/hailort/libhailort/src/network_group_client.cpp index b8ac31d3..f877489a 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,7 +32,7 @@ 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); } } diff --git a/hailort/libhailort/src/network_group_scheduler.cpp b/hailort/libhailort/src/network_group_scheduler.cpp index d92bd81b..962f5ae1 100644 --- a/hailort/libhailort/src/network_group_scheduler.cpp +++ b/hailort/libhailort/src/network_group_scheduler.cpp @@ -17,10 +17,31 @@ namespace hailort { +#define SINGLE_CONTEXT_BATCH_SIZE (1) + +void increase_counter(std::unordered_map> &counter, + const scheduler_ng_handle_t &network_group_handle, const std::string &stream_name) +{ + assert(contains(counter, network_group_handle)); + assert(contains(counter[network_group_handle], stream_name)); + counter[network_group_handle][stream_name]++; +} + +void decrease_counter(std::unordered_map> &counter, + const scheduler_ng_handle_t &network_group_handle, const std::string &stream_name) +{ + assert(contains(counter, network_group_handle)); + assert(contains(counter[network_group_handle], stream_name)); + assert(0 < counter[network_group_handle][stream_name]); + counter[network_group_handle][stream_name]--; +} + + 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), + m_changing_current_batch_size(), m_algorithm(algorithm), m_before_read_write_mutex(), m_current_batch_size(0), @@ -158,23 +179,23 @@ 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]; + auto curr_ng_active_time = 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; + curr_ng_active_time += time_diff; m_last_measured_activation_timestamp[m_current_network_group] = 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_requested_read_frames[network_group_handle].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); } @@ -187,8 +208,8 @@ 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]) { + assert(contains(m_requested_write_frames, network_group_handle)); + for (auto &streams_requested_write_pair : m_requested_write_frames[network_group_handle]) { auto &stream_name = streams_requested_write_pair.first; auto stream_frames_info = net_frames_info->add_streams_frames_infos(); @@ -201,8 +222,8 @@ 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]) { + assert(contains(m_requested_read_frames, network_group_handle)); + for (auto &streams_requested_read_pair : m_requested_read_frames[network_group_handle]) { auto &stream_name = streams_requested_read_pair.first; auto stream_frames_info = net_frames_info->add_streams_frames_infos(); @@ -288,6 +309,7 @@ Expected NetworkGroupScheduler::add_network_group(std::we 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); + m_changing_current_batch_size[network_group_handle] = false; auto added_cng_ptr = added_cng.lock(); CHECK_AS_EXPECTED(added_cng_ptr, HAILO_INTERNAL_FAILURE); @@ -301,7 +323,7 @@ Expected NetworkGroupScheduler::add_network_group(std::we auto batch_size = cng_base->get_stream_batch_size(stream_infos.value()[0].name); CHECK_EXPECTED(batch_size); - if (batch_size.value() > HAILO_DEFAULT_BATCH_SIZE) { + if (batch_size.value() > SINGLE_CONTEXT_BATCH_SIZE) { m_max_batch_size[network_group_handle] = batch_size.release(); } } @@ -311,22 +333,22 @@ Expected NetworkGroupScheduler::add_network_group(std::we 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; + m_requested_write_frames[network_group_handle][stream_info.name] = 0; + m_finished_write_frames[network_group_handle][stream_info.name] = 0; + m_h2d_requested_transferred_frames[network_group_handle][stream_info.name] = 0; + m_current_cycle_requested_transferred_frames_h2d[network_group_handle][stream_info.name] = 0; + m_h2d_finished_transferred_frames[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; + m_requested_read_frames[network_group_handle][stream_info.name] = 0; + m_ongoing_read_frames[network_group_handle][stream_info.name] = 0; + m_finished_read_frames[network_group_handle][stream_info.name] = 0; + m_current_cycle_finished_read_frames_d2h[network_group_handle][stream_info.name] = 0; + m_d2h_finished_transferred_frames[network_group_handle][stream_info.name] = 0; } } } @@ -360,8 +382,8 @@ hailo_status NetworkGroupScheduler::wait_for_write(const scheduler_ng_handle_t & 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); + increase_counter(m_requested_write_frames, network_group_handle, stream_name); + status = refresh_write_events_for_other_inputs_if_needed(network_group_handle); CHECK_SUCCESS(status); break; } @@ -409,7 +431,21 @@ bool NetworkGroupScheduler::has_enough_space_in_read_buffers(const scheduler_ng_ 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]); + auto total_writes = total_written_frames_count(network_group_handle); + 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 NetworkGroupScheduler::total_written_frames_count(const scheduler_ng_handle_t &network_group_handle) +{ + std::unordered_map write_sum; + for (const auto &name_counter_pair : m_requested_write_frames[network_group_handle]) { + write_sum[name_counter_pair.first] = name_counter_pair.second + m_finished_write_frames[network_group_handle][name_counter_pair.first] + + m_h2d_requested_transferred_frames[network_group_handle][name_counter_pair.first] + + m_h2d_finished_transferred_frames[network_group_handle][name_counter_pair.first]; + } + return write_sum; } bool NetworkGroupScheduler::should_ng_stop(const scheduler_ng_handle_t &network_group_handle) @@ -430,19 +466,18 @@ Expected NetworkGroupScheduler::should_wait_for_write(const scheduler_ng_h return make_unexpected(HAILO_STREAM_INTERNAL_ABORT); } - assert(contains(m_requested_write, network_group_handle)); - assert(contains(m_sent_pending_buffer, network_group_handle)); + assert(contains(m_requested_write_frames, 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 = m_requested_write_frames[network_group_handle][stream_name] + m_finished_write_frames[network_group_handle][stream_name]; + bool has_written_max_batch_size = (is_ng_multicontext(network_group_handle) && (m_max_batch_size[network_group_handle] == pre_transfer_h2d_frames)); - bool should_stop_writing_because_switching = ((nullptr != m_ang) && m_is_switching_network_group && + bool should_stop_writing_because_switching = ((nullptr != m_ang) && (m_is_switching_network_group || m_changing_current_batch_size[network_group_handle]) && (network_group_handle == m_current_network_group) && has_input_written_most_frames(network_group_handle, 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; + auto total_written_frames = total_written_frames_count(network_group_handle)[stream_name]; + auto min_finished_read = get_min_value_of_unordered_map(m_finished_read_frames[network_group_handle]); + auto ongoing_frames = (min_finished_read < total_written_frames) ? (total_written_frames - min_finished_read) : 0; bool has_enough_space_for_writes = has_enough_space_in_read_buffers(network_group_handle, ongoing_frames); if (has_written_max_batch_size || should_stop_writing_because_switching || (!has_enough_space_for_writes)) { @@ -452,12 +487,13 @@ 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) +hailo_status NetworkGroupScheduler::refresh_write_events_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]); + auto written_frames = total_written_frames_count(network_group_handle); + auto max_write = get_max_value_of_unordered_map(written_frames); 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) { + if (written_frames[name_event_pair.first] < max_write) { auto status = name_event_pair.second->signal(); CHECK_SUCCESS(status); } @@ -475,9 +511,8 @@ hailo_status NetworkGroupScheduler::signal_write_finish(const scheduler_ng_handl return HAILO_STREAM_INTERNAL_ABORT; } - 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]++; + increase_counter(m_finished_write_frames, network_group_handle, stream_name); + decrease_counter(m_requested_write_frames, network_group_handle, stream_name); auto status = switch_network_group_if_idle(network_group_handle, lock); CHECK_SUCCESS(status); @@ -512,17 +547,15 @@ hailo_status NetworkGroupScheduler::switch_network_group_if_idle(const scheduler return HAILO_SUCCESS; } - auto status = try_change_multicontext_ng_batch_size(network_group_handle, read_write_lock); - CHECK_SUCCESS(status); - return HAILO_SUCCESS; } +// TODO: Use max(m_d2h_finished_transferred_frames) == 0 instead bool NetworkGroupScheduler::has_pending_frames(const scheduler_ng_handle_t &network_group_handle) { - 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) { + uint32_t h2d_transferred_frames_count = get_h2d_transferred_frames_count(network_group_handle); + for (auto &name_counter_pair : m_finished_read_frames[network_group_handle]) { + if (name_counter_pair.second < h2d_transferred_frames_count) { return true; } } @@ -533,33 +566,49 @@ hailo_status NetworkGroupScheduler::try_change_multicontext_ng_batch_size(const 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); + if ((get_pre_transfer_h2d_frames_count(m_current_network_group) > 0) && + (get_pre_transfer_h2d_frames_count(m_current_network_group) != m_current_batch_size)) { + /* Wait for all requested_writes to finish */ + m_changing_current_batch_size[network_group_handle] = true; + m_write_read_cv.wait(read_write_lock, [this]() { + return 0 == get_max_value_of_unordered_map(m_requested_write_frames[m_current_network_group]); + }); + /* memcpy the frames in all inputs to offset 0 */ + auto cng = m_cngs[network_group_handle].lock(); + CHECK(cng, HAILO_INTERNAL_FAILURE); + for (auto &input_stream : cng->get_input_streams()) { + InputStreamBase &vdevice_input = static_cast(input_stream.get()); + // Needed because after re-activation num_avail will be 0 + // TODO: Remove after HRT-7838 + auto status = vdevice_input.reset_offset_of_pending_frames(); + CHECK_SUCCESS(status); + } } + hailo_status status = activate_network_group(network_group_handle, read_write_lock, true); + CHECK_SUCCESS(status); } 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) + std::unique_lock &read_write_lock, bool /*keep_nn_config*/) { - for (auto &name_counter_pair : m_current_sent_pending_buffer[network_group_handle]) { + for (auto &name_counter_pair : m_current_cycle_requested_transferred_frames_h2d[network_group_handle]) { name_counter_pair.second = 0; } - for (auto &name_counter_pair : m_current_finished_read[network_group_handle]) { + for (auto &name_counter_pair : m_current_cycle_finished_read_frames_d2h[network_group_handle]) { name_counter_pair.second = 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()); + batch_size = static_cast(get_pre_transfer_h2d_frames_count(network_group_handle)); } if (CONTROL_PROTOCOL__IGNORE_DYNAMIC_BATCH_SIZE == batch_size) { - batch_size = 1; + batch_size = SINGLE_CONTEXT_BATCH_SIZE; } bool has_same_batch_size_as_previous = (m_current_batch_size == batch_size); @@ -567,11 +616,11 @@ hailo_status NetworkGroupScheduler::activate_network_group(const scheduler_ng_ha 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); - } - + // TODO (HRT-8480): Enable this flow + // 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(); @@ -584,9 +633,6 @@ hailo_status NetworkGroupScheduler::activate_network_group(const scheduler_ng_ha m_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)) { assert(m_cngs.size() > network_group_handle); auto cng = m_cngs[network_group_handle].lock(); @@ -601,11 +647,11 @@ hailo_status NetworkGroupScheduler::activate_network_group(const scheduler_ng_ha // Register to get interrupts - has to be after network group is activated for (auto &output_stream : cng->get_output_streams()) { OutputStreamBase &vdevice_output = static_cast(output_stream.get()); - status = vdevice_output.register_for_d2h_interrupts( + auto 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_d2h_finished_transferred_frames[network_group_handle][name] += frames; } m_write_read_cv.notify_all(); }); @@ -616,6 +662,12 @@ hailo_status NetworkGroupScheduler::activate_network_group(const scheduler_ng_ha m_last_run_time_stamp[network_group_handle] = std::chrono::steady_clock::now(); // Mark timestamp on activation m_current_network_group = network_group_handle; + // Finished switching batch size + m_changing_current_batch_size[network_group_handle] = false; + + auto status = refresh_all_write_events(); + CHECK_SUCCESS(status); + 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"); @@ -626,7 +678,7 @@ hailo_status NetworkGroupScheduler::activate_network_group(const scheduler_ng_ha return HAILO_SUCCESS; } -hailo_status NetworkGroupScheduler::allow_all_writes() +hailo_status NetworkGroupScheduler::refresh_all_write_events() { for (auto &handle_dict_pair : m_write_buffer_events) { for (auto &name_event_pair : handle_dict_pair.second) { @@ -646,9 +698,10 @@ hailo_status NetworkGroupScheduler::send_all_pending_buffers(const scheduler_ng_ 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))) { + for (auto &name_counter_pair : m_finished_write_frames[network_group_handle]) { + if ((name_counter_pair.second > 0) + && ((!is_ng_multicontext(network_group_handle)) || + (m_current_cycle_requested_transferred_frames_h2d[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"); @@ -659,7 +712,7 @@ hailo_status NetworkGroupScheduler::send_all_pending_buffers(const scheduler_ng_ finished_sending_count++; } } - if (finished_sending_count == m_written_buffer[network_group_handle].size()) { + if (finished_sending_count == m_finished_write_frames[network_group_handle].size()) { break; } } @@ -681,21 +734,19 @@ hailo_status NetworkGroupScheduler::send_pending_buffer(const scheduler_ng_handl 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]++; + increase_counter(m_h2d_requested_transferred_frames, network_group_handle, stream_name); + increase_counter(m_current_cycle_requested_transferred_frames_h2d, network_group_handle, stream_name); + decrease_counter(m_finished_write_frames, 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); + auto status = pending_buffer_state->finish(vdevice_input.get_timeout(), read_write_lock, MAX(SINGLE_CONTEXT_BATCH_SIZE, m_max_batch_size[network_group_handle])); if (HAILO_STREAM_INTERNAL_ABORT == status) { LOGGER__INFO("finish has failed with status=HAILO_STREAM_INTERNAL_ABORT"); 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]++; + increase_counter(m_h2d_finished_transferred_frames, network_group_handle, stream_name); + decrease_counter(m_h2d_requested_transferred_frames, network_group_handle, stream_name); if (should_ng_stop(network_group_handle)) { return HAILO_STREAM_INTERNAL_ABORT; @@ -741,15 +792,15 @@ hailo_status NetworkGroupScheduler::switch_network_group_if_should_be_next(const bool NetworkGroupScheduler::is_network_group_ready(const scheduler_ng_handle_t &network_group_handle, bool check_threshold) { - assert(contains(m_written_buffer, network_group_handle)); + assert(contains(m_finished_write_frames, network_group_handle)); assert(contains(m_min_threshold_per_stream, network_group_handle)); assert(contains(m_last_run_time_stamp, network_group_handle)); // 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]; + uint32_t written_frames = get_max_value_of_unordered_map(total_written_frames_count(network_group_handle)); + for (const auto &name_counter_pair : m_d2h_finished_transferred_frames[network_group_handle]) { + uint32_t finished_read_frames = m_finished_read_frames[network_group_handle][name_counter_pair.first]; if ((finished_read_frames + name_counter_pair.second) < written_frames) { has_pending_writes = true; break; @@ -758,18 +809,23 @@ bool NetworkGroupScheduler::is_network_group_ready(const scheduler_ng_handle_t & // 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) { + for (const auto &name_counter_pair : m_requested_read_frames[network_group_handle]) { + if (name_counter_pair.second > 0) { has_pending_reads = true; break; } } if (check_threshold) { - for (auto &name_counter_pair : m_written_buffer[network_group_handle]) { + for (auto &name_counter_pair : m_requested_write_frames[network_group_handle]) { + auto threshold = m_min_threshold_per_stream[network_group_handle][name_counter_pair.first].load(); + if (DEFAULT_SCHEDULER_MIN_THRESHOLD == threshold) { + threshold = 1; + } + // 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]) && + auto write_requests = name_counter_pair.second + m_finished_write_frames[network_group_handle][name_counter_pair.first]; + if ((write_requests < threshold) && ((*(m_timeout_per_network_group[network_group_handle]) > (std::chrono::steady_clock::now() - m_last_run_time_stamp[network_group_handle])))) { return false; } @@ -779,19 +835,17 @@ bool NetworkGroupScheduler::is_network_group_ready(const scheduler_ng_handle_t & return has_pending_writes && has_pending_reads && (!has_pending_frames(network_group_handle)); } -hailo_status NetworkGroupScheduler::wait_for_read(const scheduler_ng_handle_t &network_group_handle, const std::string &stream_name) +hailo_status NetworkGroupScheduler::wait_for_read(const scheduler_ng_handle_t &network_group_handle, const std::string &stream_name, + const std::chrono::milliseconds &timeout) { { 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]++; + increase_counter(m_requested_read_frames, network_group_handle, stream_name); hailo_status status = HAILO_UNINITIALIZED; - m_write_read_cv.wait(lock, [this, network_group_handle, stream_name, &status, &lock] { + auto wait_res = m_write_read_cv.wait_for(lock, timeout, [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 @@ -809,12 +863,16 @@ hailo_status NetworkGroupScheduler::wait_for_read(const scheduler_ng_handle_t &n return can_stream_read(network_group_handle, stream_name); }); + if (!wait_res) { + return HAILO_TIMEOUT; + } if (HAILO_STREAM_INTERNAL_ABORT == status) { return status; } CHECK_SUCCESS(status); - m_allowed_read[network_group_handle][stream_name]++; + increase_counter(m_ongoing_read_frames, network_group_handle, stream_name); + decrease_counter(m_requested_read_frames, network_group_handle, stream_name); } m_write_read_cv.notify_all(); @@ -823,39 +881,45 @@ hailo_status NetworkGroupScheduler::wait_for_read(const scheduler_ng_handle_t &n 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]); + assert(contains(m_ongoing_read_frames, network_group_handle)); + assert(contains(m_finished_read_frames, network_group_handle)); + uint32_t d2h_transferred_frames = m_ongoing_read_frames[network_group_handle][stream_name] + m_finished_read_frames[network_group_handle][stream_name]; + return d2h_transferred_frames < get_h2d_transferred_frames_count(network_group_handle); +} + +uint32_t NetworkGroupScheduler::get_h2d_transferred_frames_count(const scheduler_ng_handle_t &network_group_handle) +{ + std::unordered_map transferred_frames; + for (const auto &name_counter_pair : m_h2d_requested_transferred_frames[network_group_handle]) { + transferred_frames[name_counter_pair.first] = name_counter_pair.second + m_h2d_finished_transferred_frames[network_group_handle][name_counter_pair.first]; + } + return get_max_value_of_unordered_map(transferred_frames); } hailo_status NetworkGroupScheduler::signal_read_finish(const scheduler_ng_handle_t &network_group_handle, const std::string &stream_name) { { 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]--; + if (m_d2h_finished_transferred_frames[network_group_handle][stream_name] > 0) { + m_d2h_finished_transferred_frames[network_group_handle][stream_name]--; } - m_finished_read[network_group_handle][stream_name]++; - m_current_finished_read[network_group_handle][stream_name]++; + increase_counter(m_finished_read_frames, network_group_handle, stream_name); + increase_counter(m_current_cycle_finished_read_frames_d2h, network_group_handle, stream_name); + decrease_counter(m_ongoing_read_frames, network_group_handle, stream_name); m_fps_accumulator[network_group_handle]++; hailo_status status = choose_next_network_group(); CHECK_SUCCESS(status); - 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); - } + status = try_change_multicontext_ng_batch_size(network_group_handle, lock); + CHECK_SUCCESS(status); + + decrease_current_ng_counters(); } - auto status = allow_all_writes(); + auto status = refresh_all_write_events(); CHECK_SUCCESS(status); m_write_read_cv.notify_all(); @@ -869,7 +933,7 @@ bool NetworkGroupScheduler::has_ng_finished(scheduler_ng_handle_t network_group_ } if (is_ng_multicontext(network_group_handle)) { - for (auto &name_counter_pair : m_current_finished_read[network_group_handle]) { + for (auto &name_counter_pair : m_current_cycle_finished_read_frames_d2h[network_group_handle]) { if (name_counter_pair.second < m_current_batch_size) { return false; } @@ -878,8 +942,8 @@ 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]) { + uint32_t written_frames = get_max_value_of_unordered_map(total_written_frames_count(network_group_handle)); + for (auto &name_counter_pair : m_finished_read_frames[network_group_handle]) { if (name_counter_pair.second < written_frames) { return false; } @@ -894,17 +958,28 @@ bool NetworkGroupScheduler::has_ng_drained_everything(scheduler_ng_handle_t netw 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) { + for (auto &name_counter_pair : m_requested_write_frames[network_group_handle]) { + if (name_counter_pair.second > 0) { + return false; + } + } + for (auto &name_counter_pair : m_finished_write_frames[network_group_handle]) { + if (name_counter_pair.second > 0) { + return false; + } + } + for (auto &name_counter_pair : m_h2d_requested_transferred_frames[network_group_handle]) { + if (name_counter_pair.second > 0) { 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) { + assert(contains(m_h2d_finished_transferred_frames, network_group_handle)); + assert(contains(m_d2h_finished_transferred_frames, network_group_handle)); + assert(contains(m_finished_read_frames, network_group_handle)); + uint32_t written_frames = get_max_value_of_unordered_map(m_h2d_finished_transferred_frames[network_group_handle]); + for (const auto &name_counter_pair : m_d2h_finished_transferred_frames[network_group_handle]) { + if ((m_finished_read_frames[network_group_handle][name_counter_pair.first] + name_counter_pair.second) < written_frames) { return false; } } @@ -918,61 +993,21 @@ void NetworkGroupScheduler::decrease_current_ng_counters() } // 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]) { + for (auto &name_counter_pair : m_h2d_finished_transferred_frames[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]) { + for (auto &name_counter_pair : m_finished_read_frames[m_current_network_group]) { if (name_counter_pair.second <= 1) { return; } } - 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]) { + for (auto &name_counter_pair : m_h2d_finished_transferred_frames[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]) { + for (auto &name_counter_pair : m_finished_read_frames[m_current_network_group]) { name_counter_pair.second--; } } @@ -982,14 +1017,13 @@ bool NetworkGroupScheduler::is_ng_multicontext(const scheduler_ng_handle_t &netw return (CONTROL_PROTOCOL__IGNORE_DYNAMIC_BATCH_SIZE != m_max_batch_size[network_group_handle]); } -uint32_t NetworkGroupScheduler::get_buffered_frames_count() +uint32_t NetworkGroupScheduler::get_pre_transfer_h2d_frames_count(const scheduler_ng_handle_t &network_group_handle) { - 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]; + std::unordered_map write_sum; + for (const auto &name_counter_pair : m_requested_write_frames[network_group_handle]) { + write_sum[name_counter_pair.first] = name_counter_pair.second + m_finished_write_frames[network_group_handle][name_counter_pair.first]; } - - return get_max_value_of_unordered_map(buffered_frames); + return get_max_value_of_unordered_map(write_sum); } hailo_status NetworkGroupScheduler::enable_stream(const scheduler_ng_handle_t &network_group_handle, const std::string &stream_name) @@ -1019,12 +1053,9 @@ hailo_status NetworkGroupScheduler::disable_stream(const scheduler_ng_handle_t & 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); - } + // Signal write events to exit infinite timeout on wait_for_write for this network group + auto status = refresh_all_write_events(); + CHECK_SUCCESS(status); } m_write_read_cv.notify_all(); return HAILO_SUCCESS; @@ -1056,10 +1087,15 @@ hailo_status NetworkGroupScheduler::set_threshold(const scheduler_ng_handle_t &n (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)); + assert(contains(m_max_batch_size, network_group_handle)); + + CHECK((CONTROL_PROTOCOL__IGNORE_DYNAMIC_BATCH_SIZE == m_max_batch_size[network_group_handle]) || + (threshold <= m_max_batch_size[network_group_handle]), HAILO_INVALID_ARGUMENT, "Threshold must be equal or lower than the maximum batch size!"); + 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; } diff --git a/hailort/libhailort/src/network_group_scheduler.hpp b/hailort/libhailort/src/network_group_scheduler.hpp index f8f86fb7..32fff1c5 100644 --- a/hailort/libhailort/src/network_group_scheduler.hpp +++ b/hailort/libhailort/src/network_group_scheduler.hpp @@ -20,7 +20,7 @@ #include #define DEFAULT_SCHEDULER_TIMEOUT (std::chrono::milliseconds(0)) -#define DEFAULT_SCHEDULER_MIN_THRESHOLD (1) +#define DEFAULT_SCHEDULER_MIN_THRESHOLD (0) namespace hailort { @@ -58,7 +58,8 @@ class NetworkGroupScheduler hailo_status wait_for_write(const scheduler_ng_handle_t &network_group_handle, const std::string &stream_name); 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 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); hailo_status enable_stream(const scheduler_ng_handle_t &network_group_handle, const std::string &stream_name); @@ -75,6 +76,7 @@ class NetworkGroupScheduler std::atomic_bool m_is_switching_network_group; scheduler_ng_handle_t m_current_network_group; scheduler_ng_handle_t m_next_network_group; + std::map m_changing_current_batch_size; std::vector> m_cngs; std::unique_ptr m_ang; @@ -89,11 +91,12 @@ class NetworkGroupScheduler hailo_status try_change_multicontext_ng_batch_size(const scheduler_ng_handle_t &network_group_handle, std::unique_lock &read_write_lock); bool has_input_written_most_frames(const scheduler_ng_handle_t &network_group_handle, const std::string &stream_name); + std::unordered_map total_written_frames_count(const scheduler_ng_handle_t &network_group_handle); 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 refresh_all_write_events(); + hailo_status refresh_write_events_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); @@ -103,9 +106,10 @@ class NetworkGroupScheduler 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(); + void decrease_current_ng_counters(); + uint32_t get_pre_transfer_h2d_frames_count(const scheduler_ng_handle_t &network_group_handle); + uint32_t get_h2d_transferred_frames_count(const scheduler_ng_handle_t &network_group_handle); std::string get_network_group_name(scheduler_ng_handle_t network_group_handle); hailo_status start_mon(); @@ -125,17 +129,20 @@ class NetworkGroupScheduler 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_requested_write_frames; // 'wait_for_write()' has been called + std::unordered_map> m_finished_write_frames; // 'signal_finished_write()' has been called - frame is written in buffer (writes are a-sync) + + std::unordered_map> m_h2d_requested_transferred_frames; // 'send_pending_buffer()' has been called + std::unordered_map> m_h2d_finished_transferred_frames; // Frame has been transferred to device (intrpt was raised) + + std::unordered_map> m_requested_read_frames; // 'wait_for_read()' has been called + std::unordered_map> m_ongoing_read_frames; // 'wait_for_read()' has finished, the user is blocking on read (reads are sync) + + std::unordered_map> m_d2h_finished_transferred_frames; // Frame has been transferred from device (intrpt was raised) + std::unordered_map> m_finished_read_frames; // 'signal_finish_read()' has been called - user finished getting the frame + + std::unordered_map> m_current_cycle_requested_transferred_frames_h2d; // Relevant for multi-context - last batch + std::unordered_map> m_current_cycle_finished_read_frames_d2h; // Relevant for multi-context - last batch std::unordered_map> m_min_threshold_per_stream; diff --git a/hailort/libhailort/src/os/CMakeLists.txt b/hailort/libhailort/src/os/CMakeLists.txt index 1f866a62..4e52af3d 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 4536cfeb..c8620aa5 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 470e24bd..f9ecbb2b 100755 --- a/hailort/libhailort/src/os/hailort_driver.hpp +++ b/hailort/libhailort/src/os/hailort_driver.hpp @@ -13,10 +13,9 @@ #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 #include @@ -54,15 +53,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 +81,7 @@ class HailoRTDriver final 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 +90,30 @@ class HailoRTDriver final 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 +124,10 @@ class HailoRTDriver final 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 +137,14 @@ class HailoRTDriver final 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], @@ -234,11 +228,6 @@ class HailoRTDriver final 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 +263,11 @@ class HailoRTDriver final 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 +278,8 @@ class HailoRTDriver final 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 +288,10 @@ class HailoRTDriver final 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 f6cd762e..a7009fb6 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) @@ -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, }; @@ -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); 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 05b5de31..bc7f731a 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 00000000..a91fc088 --- /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 531778ae..00000000 --- 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 00000000..88d68ec8 --- /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 bf29c92b..a72bdd8c 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 @@ class CDeviceFile 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 @@ class CDeviceFile } } 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)) { @@ -964,11 +824,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 51482d33..002b2da1 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,18 @@ 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 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)); 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; } @@ -165,20 +125,9 @@ Expected PcieDevice::pcie_device_info_to_string(const hailo_pcie_de 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) + 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); @@ -210,14 +159,6 @@ PcieDevice::~PcieDevice() } } -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 +166,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 +176,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 +264,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 44989231..c516079d 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" @@ -32,9 +31,6 @@ class PcieDevice : public VdmaDevice { 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 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; virtual hailo_status direct_read_memory(uint32_t address, void *buffer, uint32_t size) override; @@ -52,7 +48,6 @@ class PcieDevice : public VdmaDevice { return false; } } - virtual ExpectedRef get_config_manager() override; // TODO: used for tests void set_is_control_version_supported(bool value); @@ -69,15 +64,10 @@ class PcieDevice : public VdmaDevice { 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 1b478e6a..dc2f0e58 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 { @@ -397,9 +396,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 +510,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 +567,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 PipelineElement::resume() +{ + return execute_resume(); +} + +hailo_status PipelineElement::wait_for_finish() +{ + return execute_wait_for_finish(); +} + +hailo_status PipelineElement::execute_activate() +{ + return execute([&](auto *pad){ return pad->activate(); }); +} + +hailo_status PipelineElement::execute_deactivate() +{ + return execute([&](auto *pad){ return pad->deactivate(); }); +} + +hailo_status PipelineElement::execute_post_deactivate() +{ + return execute([&](auto *pad){ return pad->post_deactivate(); }); +} + +hailo_status PipelineElement::execute_clear() +{ + return execute([&](auto *pad){ return pad->clear(); }); +} + +hailo_status PipelineElement::execute_flush() +{ + return execute([&](auto *pad){ return pad->flush(); }); +} -hailo_status FilterElement::activate() +hailo_status PipelineElement::execute_abort() { - return next_pad().activate(); + return execute([&](auto *pad){ return pad->abort(); }); } -hailo_status FilterElement::deactivate() +hailo_status PipelineElement::execute_resume() { - return next_pad().deactivate(); + return execute([&](auto *pad){ return pad->resume(); }); } -hailo_status FilterElement::post_deactivate() +hailo_status PipelineElement::execute_wait_for_finish() { - return next_pad().post_deactivate(); + return execute([&](auto *pad){ return pad->wait_for_finish(); }); } -hailo_status FilterElement::clear() +hailo_status PipelineElement::execute(std::function func) { - return next_pad().clear(); + for (auto pad : execution_pads()) { + auto status = func(pad); + CHECK_SUCCESS(status); + } + return HAILO_SUCCESS; } -hailo_status FilterElement::abort() +std::vector SourceElement::execution_pads() { - return next_pad().abort(); + std::vector result{&source()}; + return result; } -hailo_status FilterElement::resume() +std::vector SinkElement::execution_pads() { - return next_pad().resume(); + 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 +682,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_INTERNAL_ABORT) { + LOGGER__INFO("run_push of {} was aborted!", name()); return status; } CHECK_SUCCESS(status); @@ -662,11 +732,6 @@ BaseQueueElement::BaseQueueElement(SpscQueue &&queue, EventPtr s 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()); @@ -719,8 +784,6 @@ void BaseQueueElement::start_thread() } } } - // TODO: Should we use MicroProfileShutdown? - MicroProfileOnThreadExit(); }); } @@ -745,9 +808,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 +819,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 +831,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 +847,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 BaseQueueElement::resume() +hailo_status PushQueueElement::execute_abort() +{ + auto status = m_shutdown_event->reset(); + CHECK_SUCCESS(status); + m_pipeline_status->store(HAILO_STREAM_INTERNAL_ABORT); + status = PipelineElement::execute_abort(); + CHECK_SUCCESS(status); + return m_activation_event.signal(); +} + +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) @@ -896,7 +967,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_INTERNAL_ABORT) { + 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,13 +991,13 @@ 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)) { LOGGER__INFO("enqueue() in element {} was aborted, got status = {}", name(), status); @@ -1031,11 +1108,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 +1130,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); @@ -1181,9 +1253,9 @@ Expected UserBufferQueueElement::run_pull(PipelineBuffer &&optio 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); } @@ -1245,6 +1317,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 +1352,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)), @@ -1432,17 +1438,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 +1457,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 +1472,18 @@ 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(); -} - -hailo_status BaseDemuxElement::clear() -{ - return next_pad().clear(); + return PipelineElement::execute_post_deactivate(); } -hailo_status BaseDemuxElement::flush() -{ - return next_pad().flush(); -} - -hailo_status BaseDemuxElement::abort() +hailo_status BaseDemuxElement::execute_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(); + return PipelineElement::execute_abort(); } PipelinePad &BaseDemuxElement::next_pad() @@ -1512,4 +1498,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 9895c018..55d64ceb 100644 --- a/hailort/libhailort/src/pipeline.hpp +++ b/hailort/libhailort/src/pipeline.hpp @@ -200,14 +200,14 @@ class PipelinePad final : public PipelineObject 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 +248,14 @@ class PipelineElement : public PipelineObject 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 +285,18 @@ class PipelineElement : public PipelineObject 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 +306,9 @@ class SourceElement : public PipelineElement 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 +318,9 @@ class SinkElement : public PipelineElement 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 +330,9 @@ class IntermediateElement : public PipelineElement 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 +342,6 @@ class FilterElement : public IntermediateElement 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; @@ -342,13 +355,6 @@ 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; hailo_status set_timeout(std::chrono::milliseconds timeout); virtual std::string description() const override; @@ -363,6 +369,12 @@ class BaseQueueElement : public IntermediateElement 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 +414,12 @@ class PushQueueElement : public BaseQueueElement 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 +437,6 @@ class PullQueueElement : public BaseQueueElement 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 +456,7 @@ class PullQueueElement : public BaseQueueElement } protected: + virtual hailo_status execute_deactivate() override; virtual hailo_status run_in_thread() override; }; @@ -460,7 +472,6 @@ class UserBufferQueueElement : public PullQueueElement 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 +484,7 @@ class UserBufferQueueElement : public PullQueueElement } protected: + virtual hailo_status execute_clear() override; virtual hailo_status run_in_thread() override; private: @@ -488,17 +500,10 @@ class BaseMuxElement : public PipelineElement 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 +517,15 @@ class BaseDemuxElement : public PipelineElement 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/stream.cpp b/hailort/libhailort/src/stream.cpp index d758a696..7c93b6bf 100644 --- a/hailort/libhailort/src/stream.cpp +++ b/hailort/libhailort/src/stream.cpp @@ -13,7 +13,6 @@ #include "hailo/transform.hpp" #include "common/utils.hpp" #include "hef_internal.hpp" -#include "microprofile.h" #include @@ -27,16 +26,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 @@ -104,7 +100,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 51d9f606..06a6262a 100644 --- a/hailort/libhailort/src/stream_internal.hpp +++ b/hailort/libhailort/src/stream_internal.hpp @@ -85,6 +85,11 @@ class InputStreamBase : public InputStream return make_unexpected(HAILO_INVALID_OPERATION); } + virtual hailo_status reset_offset_of_pending_frames() + { + return HAILO_INVALID_OPERATION; + } + CONTROL_PROTOCOL__nn_stream_config_t m_nn_stream_config; protected: diff --git a/hailort/libhailort/src/transform.cpp b/hailort/libhailort/src/transform.cpp index ee50d201..45cf409f 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 @@ -1298,7 +1297,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 +1537,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 +1703,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 +1717,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 +1864,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 +1893,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/vdevice_stream.cpp b/hailort/libhailort/src/vdevice_stream.cpp index ab5b982f..0cd84ce8 100644 --- a/hailort/libhailort/src/vdevice_stream.cpp +++ b/hailort/libhailort/src/vdevice_stream.cpp @@ -181,7 +181,6 @@ Expected> VDeviceInputStream::create_input_s "vDevice internal streams should have the same stream interface"); } - 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)); @@ -288,6 +287,16 @@ hailo_status VDeviceInputStream::clear_abort_impl(scheduler_ng_handle_t network_ return status; } +hailo_status VDeviceInputStream::reset_offset_of_pending_frames() +{ + for (auto &stream : m_streams) { + auto status = stream->reset_offset_of_pending_frames(); + CHECK_SUCCESS(status); + } + + return HAILO_SUCCESS; +} + bool VDeviceInputStream::is_scheduled() { auto network_group_scheduler = m_network_group_scheduler.lock(); @@ -356,7 +365,8 @@ hailo_status VDeviceOutputStream::read_impl(MemoryView buffer, scheduler_ng_hand { 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()); + // All timeout values of m_streams should be the same + auto status = network_group_scheduler->wait_for_read(network_group_handle, name(), m_streams[0]->get_timeout()); if (HAILO_STREAM_INTERNAL_ABORT == status) { LOGGER__INFO("Read from stream was aborted."); return status; diff --git a/hailort/libhailort/src/vdevice_stream.hpp b/hailort/libhailort/src/vdevice_stream.hpp index 15524f71..7bcdf8e3 100644 --- a/hailort/libhailort/src/vdevice_stream.hpp +++ b/hailort/libhailort/src/vdevice_stream.hpp @@ -53,6 +53,7 @@ class VDeviceInputStream : public InputStreamBase { virtual Expected send_pending_buffer() override; virtual Expected get_buffer_frames_size() const override; virtual Expected get_pending_frames_count() const override; + virtual hailo_status reset_offset_of_pending_frames() override; protected: virtual Expected sync_write_raw_buffer(const MemoryView &buffer) override; diff --git a/hailort/libhailort/src/vdevice_stream_wrapper.cpp b/hailort/libhailort/src/vdevice_stream_wrapper.cpp index face57b7..5995ceb2 100644 --- a/hailort/libhailort/src/vdevice_stream_wrapper.cpp +++ b/hailort/libhailort/src/vdevice_stream_wrapper.cpp @@ -90,6 +90,11 @@ Expected VDeviceInputStreamWrapper::get_pending_frames_count() const return m_vdevice_input_stream->get_pending_frames_count(); } +hailo_status VDeviceInputStreamWrapper::reset_offset_of_pending_frames() +{ + return m_vdevice_input_stream->reset_offset_of_pending_frames(); +} + Expected VDeviceInputStreamWrapper::sync_write_raw_buffer(const MemoryView &buffer) { if (is_scheduled()) { @@ -292,7 +297,8 @@ hailo_status VDeviceOutputStreamWrapper::read_all(MemoryView &buffer) hailo_status VDeviceOutputStreamWrapper::read(MemoryView buffer) { if (is_scheduled()) { - auto status = m_multiplexer->wait_for_read(m_network_group_multiplexer_handle, name()); + auto status = m_multiplexer->wait_for_read(m_network_group_multiplexer_handle, name(), + m_vdevice_output_stream->get_timeout()); if (HAILO_STREAM_INTERNAL_ABORT == status) { return status; } diff --git a/hailort/libhailort/src/vdevice_stream_wrapper.hpp b/hailort/libhailort/src/vdevice_stream_wrapper.hpp index 390c5acc..7102528f 100644 --- a/hailort/libhailort/src/vdevice_stream_wrapper.hpp +++ b/hailort/libhailort/src/vdevice_stream_wrapper.hpp @@ -55,6 +55,7 @@ class VDeviceInputStreamWrapper : public InputStreamBase { virtual Expected send_pending_buffer() override; virtual Expected get_buffer_frames_size() const override; virtual Expected get_pending_frames_count() const override; + virtual hailo_status reset_offset_of_pending_frames() override; protected: virtual Expected sync_write_raw_buffer(const MemoryView &buffer) override; diff --git a/hailort/libhailort/src/vdma/mapped_buffer.cpp b/hailort/libhailort/src/vdma/mapped_buffer.cpp index fa1d0fc4..dfd8ebc7 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 { @@ -95,7 +94,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; @@ -121,7 +119,6 @@ hailo_status MappedBuffer::write_cyclic(const void *buf_src, size_t count, size_ hailo_status MappedBuffer::read_cyclic(void *buf_dst, size_t count, size_t offset) { - 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; diff --git a/hailort/libhailort/src/vdma/vdma_mapped_buffer_impl.cpp b/hailort/libhailort/src/vdma/vdma_mapped_buffer_impl.cpp index 1188b646..f299f465 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 1dad777f..5e91dd26 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); @@ -88,9 +87,9 @@ VdmaChannel::VdmaChannel(vdma::ChannelId channel_id, Direction direction, HailoR 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_stream_index(stream_index), 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) + m_is_aborted_by_internal_source(false), m_d2h_callbacks_marked_for_shutdown(false) { if (m_transfers_per_axi_intr == 0) { LOGGER__ERROR("Invalid transfers per axi interrupt"); @@ -107,7 +106,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; @@ -151,25 +150,22 @@ VdmaChannel::VdmaChannel(VdmaChannel &&other) noexcept: 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_buffer_for_frames_shift(std::move(other.m_buffer_for_frames_shift)), 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)) + m_is_aborted_by_internal_source(other.m_is_aborted_by_internal_source.exchange(false)), + m_d2h_callbacks_marked_for_shutdown(other.m_d2h_callbacks_marked_for_shutdown.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(); @@ -181,6 +177,7 @@ hailo_status VdmaChannel::stop_channel() // 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 +195,10 @@ 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 +210,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; } @@ -321,6 +324,14 @@ hailo_status VdmaChannel::allocate_resources(uint32_t descs_count) auto status = allocate_buffer(descs_count * m_desc_page_size); CHECK_SUCCESS(status, "Failed to allocate vDMA buffer for channel transfer! status={}", status); + if (Direction::H2D == m_direction) { + // Allocate helper-buffer for 'reset_offset_of_pending_frames' functionality + // TODO: Remove after HRT-7838 + auto helper_buffer = Buffer::create(descs_count * m_desc_page_size); + CHECK_EXPECTED_AS_STATUS(helper_buffer); + m_buffer_for_frames_shift = helper_buffer.release(); + } + clear_descriptor_list(); return HAILO_SUCCESS; @@ -336,32 +347,32 @@ 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; 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(); } hailo_status VdmaChannel::register_for_d2h_interrupts(const std::function &callback) @@ -452,6 +463,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_INTERNAL_ABORT; + } + if (Direction::H2D == m_direction) { status = transfer_h2d(buf, count); if (HAILO_STREAM_NOT_ACTIVATED == status) { @@ -533,8 +549,8 @@ hailo_status VdmaChannel::write_buffer(const MemoryView &buffer, std::chrono::mi } 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)); }); @@ -548,6 +564,27 @@ hailo_status VdmaChannel::write_buffer(const MemoryView &buffer, std::chrono::mi return write_buffer_impl(buffer); } +// TODO: Remove after HRT-7838 +hailo_status VdmaChannel::reset_offset_of_pending_frames() +{ + assert(Direction::H2D == m_direction); + std::lock_guard state_guard(*m_state); + + size_t read_offset = (get_num_available() * m_desc_page_size); + size_t write_offset = 0; + + // TODO: can be optimized - We copy unecessary data + size_t buffer_size = m_pending_num_avail_offset * m_desc_page_size; + + auto status = m_buffer->read_cyclic(m_buffer_for_frames_shift.data(), buffer_size, read_offset); + CHECK_SUCCESS(status); + + status = m_buffer->write_cyclic(m_buffer_for_frames_shift.data(), buffer_size, write_offset); + CHECK_SUCCESS(status); + + return HAILO_SUCCESS; +} + hailo_status VdmaChannel::send_pending_buffer_impl() { CHECK(!m_pending_buffers_sizes.empty(), HAILO_INVALID_OPERATION, "There are no pending buffers to send!"); @@ -570,7 +607,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()); @@ -605,7 +641,7 @@ Expected VdmaChannel::send_pending_buffer() return PendingBufferState(*this, next_buffer_desc_num); } -hailo_status PendingBufferState::finish(std::chrono::milliseconds timeout, std::unique_lock &lock) +hailo_status PendingBufferState::finish(std::chrono::milliseconds timeout, std::unique_lock &lock, uint16_t max_batch_size) { unlock_guard> unlock(lock); @@ -624,7 +660,7 @@ hailo_status PendingBufferState::finish(std::chrono::milliseconds timeout, std:: 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)); + bool should_free_descs = (num_free < (static_cast(m_next_buffer_desc_num) * max_batch_size)); m_vdma_channel.m_is_waiting_for_channel_completion = should_free_descs; if (!should_free_descs) { break; @@ -818,35 +854,43 @@ 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) +void VdmaChannel::mark_d2h_callbacks_for_shutdown() { - 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); - CHECK_EXPECTED_AS_STATUS(channel_handle, "Failed to enable channel {}", m_channel_id); + m_d2h_callbacks_marked_for_shutdown = true; +} - *m_channel_handle = channel_handle.release(); - return HAILO_SUCCESS; +void VdmaChannel::unmark_d2h_callbacks_for_shutdown() +{ + m_d2h_callbacks_marked_for_shutdown = false; } -hailo_status VdmaChannel::start_channel() +hailo_status VdmaChannel::register_channel_to_driver() { - auto is_aborted_exp = is_aborted(); - assert(is_aborted_exp); - assert(is_aborted_exp.value()); + const bool measure_latency = (nullptr != m_latency_meter); + 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); - 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_handle = channel_handle.release(); - 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; } @@ -1032,8 +1076,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,11 +1178,16 @@ 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; } + if (m_d2h_callbacks_marked_for_shutdown) { + // We're marked for shutdown => streams may be internally aborted + return HAILO_STREAM_INTERNAL_ABORT; + } LOGGER__CRITICAL("Channel {} was aborted by an external source!", m_channel_id); return HAILO_STREAM_ABORTED; } diff --git a/hailort/libhailort/src/vdma_channel.hpp b/hailort/libhailort/src/vdma_channel.hpp index 1388ae01..bb9c6fe0 100644 --- a/hailort/libhailort/src/vdma_channel.hpp +++ b/hailort/libhailort/src/vdma_channel.hpp @@ -36,7 +36,7 @@ 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); + hailo_status finish(std::chrono::milliseconds timeout, std::unique_lock &lock, uint16_t max_batch_size); private: VdmaChannel &m_vdma_channel; @@ -68,19 +68,21 @@ class VdmaChannel final Expected 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(); + void mark_d2h_callbacks_for_shutdown(); + void unmark_d2h_callbacks_for_shutdown(); + // 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); @@ -98,6 +100,8 @@ class VdmaChannel final Expected get_h2d_pending_frames_count(); Expected get_d2h_pending_descs_count(); + hailo_status reset_offset_of_pending_frames(); + VdmaChannel(const VdmaChannel &other) = delete; VdmaChannel &operator=(const VdmaChannel &other) = delete; VdmaChannel(VdmaChannel &&other) noexcept; @@ -138,9 +142,10 @@ class VdmaChannel final // 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, @@ -184,7 +189,6 @@ class VdmaChannel final 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; @@ -206,18 +210,20 @@ class VdmaChannel final // because multiple processes can enable/disable vdma channel (which changes the channel) MmapBuffer m_channel_handle; + // TODO: Remove after HRT-7838 + Buffer m_buffer_for_frames_shift; + 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; std::atomic_bool m_is_aborted_by_internal_source; + std::atomic_bool m_d2h_callbacks_marked_for_shutdown; }; } /* namespace hailort */ diff --git a/hailort/libhailort/src/vdma_descriptor_list.cpp b/hailort/libhailort/src/vdma_descriptor_list.cpp index a74133ee..ccee07fd 100644 --- a/hailort/libhailort/src/vdma_descriptor_list.cpp +++ b/hailort/libhailort/src/vdma_descriptor_list.cpp @@ -293,7 +293,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_device.cpp b/hailort/libhailort/src/vdma_device.cpp index f252d914..9db56778 100644 --- a/hailort/libhailort/src/vdma_device.cpp +++ b/hailort/libhailort/src/vdma_device.cpp @@ -22,6 +22,12 @@ namespace hailort { +#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) : DeviceBase::DeviceBase(type), m_driver(std::move(driver)) @@ -38,7 +44,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 +60,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 +77,50 @@ 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; +} + +ExpectedRef VdmaDevice::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 VdmaDevice::read_log(MemoryView &buffer, hailo_cpu_id_t cpu_id) { size_t read_bytes = 0; diff --git a/hailort/libhailort/src/vdma_device.hpp b/hailort/libhailort/src/vdma_device.hpp index c084f778..103c9ca4 100644 --- a/hailort/libhailort/src/vdma_device.hpp +++ b/hailort/libhailort/src/vdma_device.hpp @@ -43,8 +43,12 @@ class VdmaDevice : public DeviceBase { 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 ExpectedRef get_config_manager() override; HailoRTDriver m_driver; + std::unique_ptr m_context_switch_manager; }; } /* namespace hailort */ diff --git a/hailort/libhailort/src/vdma_stream.cpp b/hailort/libhailort/src/vdma_stream.cpp index 72e1a2b1..f0ef4666 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,10 @@ hailo_status VdmaInputStream::deactivate_stream() return HAILO_SUCCESS; } - /* Flush is best effort */ - auto status = m_channel->flush(VDMA_FLUSH_TIMEOUT); - if (HAILO_STREAM_INTERNAL_ABORT == 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; + const auto status = m_channel->stop_channel(); + if (HAILO_SUCCESS != status) { + LOGGER__ERROR("Failed to stop channel with status {}", status); } this->is_stream_activated = false; @@ -203,6 +195,11 @@ Expected VdmaInputStream::get_pending_frames_count() const return m_channel->get_h2d_pending_frames_count(); } +hailo_status VdmaInputStream::reset_offset_of_pending_frames() +{ + return m_channel->reset_offset_of_pending_frames(); +} + hailo_status VdmaInputStream::sync_write_all_raw_buffer_no_transform_impl(void *buffer, size_t offset, size_t size) { ASSERT(NULL != buffer); @@ -337,8 +334,8 @@ 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; diff --git a/hailort/libhailort/src/vdma_stream.hpp b/hailort/libhailort/src/vdma_stream.hpp index 8e4664b3..ad284546 100644 --- a/hailort/libhailort/src/vdma_stream.hpp +++ b/hailort/libhailort/src/vdma_stream.hpp @@ -18,7 +18,6 @@ namespace hailort { -constexpr std::chrono::seconds VDMA_FLUSH_TIMEOUT(10); class VdmaInputStream : public InputStreamBase { public: @@ -40,6 +39,7 @@ class VdmaInputStream : public InputStreamBase { const char* get_dev_id() const; virtual Expected get_buffer_frames_size() const override; virtual Expected get_pending_frames_count() const override; + virtual hailo_status reset_offset_of_pending_frames() override; protected: VdmaInputStream(VdmaDevice &device, std::shared_ptr channel, const LayerInfo &edge_layer, diff --git a/hailort/libhailort/src/vstream.cpp b/hailort/libhailort/src/vstream.cpp index 4b6859b7..9421419f 100644 --- a/hailort/libhailort/src/vstream.cpp +++ b/hailort/libhailort/src/vstream.cpp @@ -438,6 +438,9 @@ hailo_status BaseVStream::abort() hailo_status BaseVStream::resume() { + if (!m_is_aborted) { + return HAILO_SUCCESS; + } m_is_aborted = false; return m_entry_element->resume(); } @@ -586,6 +589,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 +704,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) { @@ -926,7 +939,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 +947,24 @@ 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 +1000,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 +1010,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 @@ -1201,13 +1221,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 +1278,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 @@ -1359,7 +1387,7 @@ std::string HwReadElement::description() const return element_description.str(); } -hailo_status HwReadElement::post_deactivate() +hailo_status HwReadElement::execute_post_deactivate() { auto status = m_stream.clear_abort(); CHECK(((HAILO_SUCCESS == status) || (HAILO_STREAM_NOT_ACTIVATED == status)), status, @@ -1367,28 +1395,29 @@ hailo_status HwReadElement::post_deactivate() 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(); } -void HwReadElement::wait_for_finish() +hailo_status HwReadElement::execute_resume() { + return m_stream.clear_abort(); } -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() @@ -1451,12 +1480,12 @@ Expected HwReadElement::run_pull(PipelineBuffer &&optional, cons } } -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) { @@ -1523,12 +1552,12 @@ hailo_status HwWriteElement::run_push(PipelineBuffer &&buffer) return status; } -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. @@ -1547,7 +1576,7 @@ hailo_status HwWriteElement::deactivate() return HAILO_SUCCESS; } -hailo_status HwWriteElement::post_deactivate() +hailo_status HwWriteElement::execute_post_deactivate() { auto status = m_stream.clear_abort(); CHECK(((status == HAILO_SUCCESS) || (status == HAILO_STREAM_NOT_ACTIVATED)), status, @@ -1555,12 +1584,12 @@ hailo_status HwWriteElement::post_deactivate() 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()); CHECK_SUCCESS(status); @@ -1571,18 +1600,19 @@ hailo_status HwWriteElement::flush() return HAILO_SUCCESS; } -hailo_status HwWriteElement::abort() +hailo_status HwWriteElement::execute_abort() { return m_stream.abort(); } -void HwWriteElement::wait_for_finish() +hailo_status HwWriteElement::execute_resume() { + return m_stream.clear_abort(); } -hailo_status HwWriteElement::resume() +hailo_status HwWriteElement::execute_wait_for_finish() { - return m_stream.clear_abort(); + return HAILO_SUCCESS; } std::string HwWriteElement::description() const diff --git a/hailort/libhailort/src/vstream_internal.hpp b/hailort/libhailort/src/vstream_internal.hpp index 875cbfe2..fe459149 100644 --- a/hailort/libhailort/src/vstream_internal.hpp +++ b/hailort/libhailort/src/vstream_internal.hpp @@ -231,10 +231,13 @@ class InputVStreamClient : public InputVStreamInternal 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 @@ -268,10 +271,13 @@ class OutputVStreamClient : public OutputVStreamInternal 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 @@ -384,14 +390,14 @@ class HwReadElement : public SourceElement 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; @@ -414,14 +420,14 @@ class HwWriteElement : public SinkElement 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: diff --git a/hailort/pre_build/external/CMakeLists.txt b/hailort/pre_build/external/CMakeLists.txt index 373775cc..f9c2f81f 100644 --- a/hailort/pre_build/external/CMakeLists.txt +++ b/hailort/pre_build/external/CMakeLists.txt @@ -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/rpc/hailort_rpc.proto b/hailort/rpc/hailort_rpc.proto index 7873cb4f..bd3fd35f 100644 --- a/hailort/rpc/hailort_rpc.proto +++ b/hailort/rpc/hailort_rpc.proto @@ -13,7 +13,7 @@ service HailoRtRpc { 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_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) {} @@ -40,6 +40,10 @@ service HailoRtRpc { 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 {} @@ -262,11 +266,11 @@ message ConfiguredNetworkGroup_make_output_vstream_params_Reply { repeated NamedVStreamParams vstream_params_map = 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; } @@ -407,4 +411,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; + HailoFormat user_buffer_format = 2; +} + +message VStream_get_info_Request { + uint32 handle = 1; +} + +message VStream_get_info_Reply { + uint32 status = 1; + VStreamInfo vstream_info = 2; } \ No newline at end of file diff --git a/hailort/scripts/download_hefs.cmd b/hailort/scripts/download_hefs.cmd index 2be01f11..e1d9af69 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.11.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 6295d040..27a97294 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.11.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 00000000..db22938e --- /dev/null +++ b/hailort/tools/hw_debug/CMakeLists.txt @@ -0,0 +1,52 @@ +cmake_minimum_required(VERSION 3.0.0) + +set(FILES + main.cpp + shell.cpp + readline_wrapper.cpp + driver_memory.cpp + memory_commands.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 00000000..1551129e --- /dev/null +++ b/hailort/tools/hw_debug/driver_memory.cpp @@ -0,0 +1,117 @@ +/** + * @file driver_memory.cpp + * @brief Implements MemorySource over HailoRT driver, reads/write all interfaces. + */ + +#include "driver_memory.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") + {} + + 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); +} \ 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 00000000..597b19c6 --- /dev/null +++ b/hailort/tools/hw_debug/driver_memory.hpp @@ -0,0 +1,34 @@ +/** + * @file driver_memory.hpp + * @brief Implements MemorySource over HailoRT driver, reads/write all interfaces. + */ + +#ifndef _HW_DEBUG_MEMORY_HPP_ +#define _HW_DEBUG_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; +}; + +#endif /* _HW_DEBUG_DRIVER_MEMORY_HPP_ */ diff --git a/hailort/tools/hw_debug/main.cpp b/hailort/tools/hw_debug/main.cpp new file mode 100644 index 00000000..84aef6c5 --- /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 00000000..9b66163e --- /dev/null +++ b/hailort/tools/hw_debug/memory_commands.cpp @@ -0,0 +1,88 @@ +/** + * @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(const std::string &name) : + m_name(name) +{} + + +std::string Field::name() const +{ + return m_name; +} + +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; +} + +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 >= 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 pattern("([a-zA-Z]+)\\[([0-9]+)\\]"); + std::smatch match; + if (std::regex_match(field_arg, match, 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: {"; + + size_t index = 0; + for (auto field : fields) { + help += field.first; + if (index != fields.size() - 1) { + help += ","; + } + index++; + } + help += "}."; + 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 00000000..877b5d3a --- /dev/null +++ b/hailort/tools/hw_debug/memory_commands.hpp @@ -0,0 +1,191 @@ +/** + * @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 "spdlog/fmt/fmt.h" + +#include +#include +#include +#include + +class MemorySource; + +class Field { +public: + explicit Field(const std::string &name); + virtual ~Field() = default; + + std::string name() 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; +}; + +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; + + 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; +}; + +#endif /* _HW_DEBUG_MEMORY_COMMANDS_H_ */ diff --git a/hailort/tools/hw_debug/readline_wrapper.cpp b/hailort/tools/hw_debug/readline_wrapper.cpp new file mode 100644 index 00000000..03ab84ce --- /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 00000000..eae25c82 --- /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 00000000..ee5ca38b --- /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 00000000..25fb9e28 --- /dev/null +++ b/hailort/tools/hw_debug/shell.hpp @@ -0,0 +1,106 @@ +/** + * @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 + +// Result returned from each command. Currently wrapper to the output string. +class ShellResult final { +public: + ShellResult(const std::string &str) : + m_str(str) + {} + + void print(std::ostream &out) + { + out << m_str; + } + +private: + const 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