2 * Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
3 * Distributed under the MIT license (https://opensource.org/licenses/MIT)
6 * @file raw_async_streams_single_thread_example.c
7 * This example demonstrates basic usage of HailoRT async streaming api with a single thread.
11 #include "hailo/hailort.h"
20 #define HEF_FILE ("hefs/shortcut_net.hef")
21 #define MAX_EDGE_LAYERS_PER_DIR (16)
22 #define MAX_EDGE_LAYERS (MAX_EDGE_LAYERS_PER_DIR * 2)
23 #define MAX_ONGOING_TRANSFERS (16)
24 #define INFER_TIME_SECONDS (5)
27 #define INVALID_ADDR (MAP_FAILED)
28 #define page_aligned_alloc(size) mmap(NULL, (size), PROT_WRITE | PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)
29 #define page_aligned_free(addr, size) munmap((addr), (size))
30 #elif defined(_MSC_VER)
31 #define INVALID_ADDR (NULL)
32 #define page_aligned_alloc(size) VirtualAlloc(NULL, (size), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE)
33 #define page_aligned_free(addr, size) VirtualFree((addr), 0, MEM_RELEASE)
34 #else /* defined(_MSC_VER) */
35 #pragma error("Aligned alloc not supported")
39 #define MIN(a, b) (((a) < (b)) ? (a) : (b))
43 static void output_done_callback(const hailo_stream_read_async_completion_info_t *completion_info)
45 hailo_output_stream stream = (hailo_output_stream)completion_info->opaque;
46 hailo_status status = HAILO_UNINITIALIZED;
48 switch (completion_info->status) {
50 // Real applications can forward the buffer to post-process/display. Here we just re-launch new async reads.
51 status = hailo_stream_read_raw_buffer_async(stream, completion_info->buffer_addr, completion_info->buffer_size,
52 output_done_callback, stream);
53 if ((HAILO_SUCCESS != status) && (HAILO_STREAM_NOT_ACTIVATED != status)) {
54 fprintf(stderr, "Failed read async with status=%d\n", status);
57 case HAILO_STREAM_ABORTED_BY_USER:
58 // Transfer was canceled, finish gracefully.
61 fprintf(stderr, "Got an unexpected status on callback. status=%d\n", completion_info->status);
65 static void input_done_callback(const hailo_stream_write_async_completion_info_t *completion_info)
67 hailo_input_stream stream = (hailo_input_stream)completion_info->opaque;
68 hailo_status status = HAILO_UNINITIALIZED;
70 switch (completion_info->status) {
72 // Real applications may free the buffer and replace it with new buffer ready to be sent. Here we just re-launch
74 status = hailo_stream_write_raw_buffer_async(stream, completion_info->buffer_addr, completion_info->buffer_size,
75 input_done_callback, stream);
76 if ((HAILO_SUCCESS != status) && (HAILO_STREAM_NOT_ACTIVATED != status)) {
77 fprintf(stderr, "Failed write async with status=%d\n", status);
80 case HAILO_STREAM_ABORTED_BY_USER:
81 // Transfer was canceled, finish gracefully.
84 fprintf(stderr, "Got an unexpected status on callback. status=%d\n", completion_info->status);
88 static hailo_status infer(hailo_configured_network_group network_group, size_t number_input_streams,
89 hailo_input_stream *input_streams, size_t number_output_streams, hailo_output_stream *output_streams,
90 size_t ongoing_transfers)
92 hailo_status status = HAILO_UNINITIALIZED;
93 hailo_activated_network_group activated_network_group = NULL;
95 size_t frame_index = 0;
96 size_t frame_size = 0;
97 size_t stream_index = 0;
98 void *current_buffer = NULL;
99 void *buffers[MAX_EDGE_LAYERS * MAX_ONGOING_TRANSFERS] = {0};
100 size_t allocated_buffers = 0;
102 status = hailo_activate_network_group(network_group, NULL, &activated_network_group);
103 REQUIRE_SUCCESS(status, l_exit, "Failed activate network group status=%d", status);
105 // We launch "ongoing_transfers" async operations for both input and output streams. On each async callback, we launch
106 // some new operation with the same buffer.
107 for (stream_index = 0; stream_index < number_output_streams; stream_index++) {
108 frame_size = hailo_get_output_stream_frame_size(output_streams[stream_index]);
110 // ongoing_transfers is less than or equal to the stream's max async queue size, so we can start parallel reads.
111 for (frame_index = 0; frame_index < ongoing_transfers; frame_index++) {
112 // Buffers read from async operation must be page aligned.
113 current_buffer = page_aligned_alloc(frame_size);
114 REQUIRE_ACTION(INVALID_ADDR != current_buffer, status=HAILO_OUT_OF_HOST_MEMORY, l_deactivate, "allocation failed");
115 buffers[allocated_buffers++] = current_buffer;
117 status = hailo_stream_read_raw_buffer_async(output_streams[stream_index], current_buffer, frame_size,
118 output_done_callback, output_streams[stream_index]);
119 REQUIRE_SUCCESS(status, l_deactivate, "Failed read async with status=%d", status);
123 for (stream_index = 0; stream_index < number_input_streams; stream_index++) {
124 frame_size = hailo_get_input_stream_frame_size(input_streams[stream_index]);
126 // ongoing_transfers is less than or equal to the stream's max async queue size, so we can start parallel writes.
127 for (frame_index = 0; frame_index < ongoing_transfers; frame_index++) {
128 // Buffers written to async operation must be page aligned.
129 current_buffer = page_aligned_alloc(frame_size);
130 REQUIRE_ACTION(INVALID_ADDR != current_buffer, status=HAILO_OUT_OF_HOST_MEMORY, l_deactivate, "allocation failed");
131 buffers[allocated_buffers++] = current_buffer;
133 status = hailo_stream_write_raw_buffer_async(input_streams[stream_index], current_buffer, frame_size,
134 input_done_callback, input_streams[stream_index]);
135 REQUIRE_SUCCESS(status, l_deactivate, "Failed write async with status=%d", status);
139 // After all async operations are launched, the inference will continue until we deactivate the network.
140 hailo_sleep(INFER_TIME_SECONDS);
142 status = HAILO_SUCCESS;
144 // Calling hailo_deactivate_network_group will make sure that all async operations are done. All pending async I/O
145 // operations will be canceled and their callbacks called with status=HAILO_STREAM_ABORTED_BY_USER.
146 (void) hailo_deactivate_network_group(activated_network_group);
148 // There are no async I/O operations ongoing so it is safe to free the buffers now.
149 for (i = 0; i < allocated_buffers; i++) page_aligned_free(buffers[i], frame_size);
155 static hailo_status configure_device(hailo_device device, const char *hef_file,
156 hailo_configured_network_group *network_group)
158 hailo_status status = HAILO_UNINITIALIZED;
159 hailo_hef hef = NULL;
160 hailo_configure_params_t configure_params = {0};
162 size_t network_group_size = 1;
165 status = hailo_create_hef_file(&hef, hef_file);
166 REQUIRE_SUCCESS(status, l_exit, "Failed reading hef file %s", hef_file);
168 // Create configure params
169 status = hailo_init_configure_params_by_device(hef, device, &configure_params);
170 REQUIRE_SUCCESS(status, l_exit, "Failed init configure params");
171 REQUIRE_ACTION(configure_params.network_group_params_count == 1, status=HAILO_INVALID_ARGUMENT, l_exit,
172 "Unexpected network group size");
174 // Set HAILO_STREAM_FLAGS_ASYNC for all streams in order to use async api.
175 for (i = 0; i < configure_params.network_group_params[0].stream_params_by_name_count; i++) {
176 configure_params.network_group_params[0].stream_params_by_name[i].stream_params.flags = HAILO_STREAM_FLAGS_ASYNC;
179 status = hailo_configure_device(device, hef, &configure_params, network_group, &network_group_size);
180 REQUIRE_SUCCESS(status, l_release_hef, "Failed configuring device");
182 status = HAILO_SUCCESS;
184 (void) hailo_release_hef(hef);
191 hailo_status status = HAILO_UNINITIALIZED;
192 hailo_device device = NULL;
193 hailo_configured_network_group network_group = NULL;
194 hailo_stream_info_t input_streams_info[MAX_EDGE_LAYERS_PER_DIR] = {0};
195 hailo_stream_info_t output_streams_info[MAX_EDGE_LAYERS_PER_DIR] = {0};
196 hailo_input_stream input_streams[MAX_EDGE_LAYERS_PER_DIR] = {NULL};
197 hailo_output_stream output_streams[MAX_EDGE_LAYERS_PER_DIR] = {NULL};
198 size_t number_input_streams = 0;
199 size_t number_output_streams = 0;
201 size_t queue_size = 0;
202 size_t ongoing_transfers = MAX_ONGOING_TRANSFERS;
204 // Create device object.
205 status = hailo_create_device_by_id(NULL, &device);
206 REQUIRE_SUCCESS(status, l_exit, "Failed to create device");
208 // Configure device with HEF.
209 status = configure_device(device, HEF_FILE, &network_group);
210 REQUIRE_SUCCESS(status, l_release_device, "Failed configure_device");
212 // Get input/output stream objects.
213 status = hailo_network_group_get_input_stream_infos(network_group, input_streams_info, MAX_EDGE_LAYERS_PER_DIR,
214 &number_input_streams);
215 REQUIRE_SUCCESS(status, l_release_device, "Failed getting input streams infos");
217 status = hailo_network_group_get_output_stream_infos(network_group, output_streams_info, MAX_EDGE_LAYERS_PER_DIR,
218 &number_output_streams);
219 REQUIRE_SUCCESS(status, l_release_device, "Failed getting output streams infos");
221 for (index = 0; index < number_input_streams; index++) {
222 status = hailo_get_input_stream(network_group, input_streams_info[index].name, &input_streams[index]);
223 REQUIRE_SUCCESS(status, l_release_device, "Failed getting input stream %s", input_streams_info[index].name);
225 status = hailo_input_stream_get_async_max_queue_size(input_streams[index], &queue_size);
226 REQUIRE_SUCCESS(status, l_release_device, "Failed getting queue size");
228 ongoing_transfers = MIN(queue_size, ongoing_transfers);
231 for (index = 0; index < number_output_streams; index++) {
232 status = hailo_get_output_stream(network_group, output_streams_info[index].name, &output_streams[index]);
233 REQUIRE_SUCCESS(status, l_release_device, "Failed getting output stream %s", output_streams_info[index].name);
235 status = hailo_output_stream_get_async_max_queue_size(output_streams[index], &queue_size);
236 REQUIRE_SUCCESS(status, l_release_device, "Failed getting queue size");
238 ongoing_transfers = MIN(queue_size, ongoing_transfers);
242 status = infer(network_group, number_input_streams, input_streams, number_output_streams, output_streams,
244 REQUIRE_SUCCESS(status, l_release_device, "Failed performing inference");
246 status = HAILO_SUCCESS;
247 printf("Inference ran successfully\n");
250 (void) hailo_release_device(device);