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_ABORTED_BY_USER != 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_ABORTED_BY_USER != 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;
94 size_t frame_index = 0;
95 size_t frame_size = 0;
96 size_t stream_index = 0;
97 void *current_buffer = NULL;
98 void *buffers[MAX_EDGE_LAYERS * MAX_ONGOING_TRANSFERS] = {0};
99 size_t allocated_buffers = 0;
101 // We launch "ongoing_transfers" async operations for both input and output streams. On each async callback, we launch
102 // some new operation with the same buffer.
103 for (stream_index = 0; stream_index < number_output_streams; stream_index++) {
104 frame_size = hailo_get_output_stream_frame_size(output_streams[stream_index]);
106 // ongoing_transfers is less than or equal to the stream's max async queue size, so we can start parallel reads.
107 for (frame_index = 0; frame_index < ongoing_transfers; frame_index++) {
108 // Buffers read from async operation must be page aligned.
109 current_buffer = page_aligned_alloc(frame_size);
110 REQUIRE_ACTION(INVALID_ADDR != current_buffer, status=HAILO_OUT_OF_HOST_MEMORY, l_shutdown, "allocation failed");
111 buffers[allocated_buffers++] = current_buffer;
113 status = hailo_stream_read_raw_buffer_async(output_streams[stream_index], current_buffer, frame_size,
114 output_done_callback, output_streams[stream_index]);
115 REQUIRE_SUCCESS(status, l_shutdown, "Failed read async with status=%d", status);
119 for (stream_index = 0; stream_index < number_input_streams; stream_index++) {
120 frame_size = hailo_get_input_stream_frame_size(input_streams[stream_index]);
122 // ongoing_transfers is less than or equal to the stream's max async queue size, so we can start parallel writes.
123 for (frame_index = 0; frame_index < ongoing_transfers; frame_index++) {
124 // Buffers written to async operation must be page aligned.
125 current_buffer = page_aligned_alloc(frame_size);
126 REQUIRE_ACTION(INVALID_ADDR != current_buffer, status=HAILO_OUT_OF_HOST_MEMORY, l_shutdown, "allocation failed");
127 buffers[allocated_buffers++] = current_buffer;
129 status = hailo_stream_write_raw_buffer_async(input_streams[stream_index], current_buffer, frame_size,
130 input_done_callback, input_streams[stream_index]);
131 REQUIRE_SUCCESS(status, l_shutdown, "Failed write async with status=%d", status);
135 // After all async operations are launched, the inference will continue until we shutdown the network.
136 hailo_sleep(INFER_TIME_SECONDS);
138 status = HAILO_SUCCESS;
140 // Calling hailo_shutdown_network_group will ensure that all async operations are done. All pending async I/O
141 // operations will be canceled and their callbacks called with status=HAILO_STREAM_ABORTED_BY_USER.
142 (void) hailo_shutdown_network_group(network_group);
144 // There are no async I/O operations ongoing so it is safe to free the buffers now.
145 for (i = 0; i < allocated_buffers; i++) page_aligned_free(buffers[i], frame_size);
150 static hailo_status configure_device(hailo_device device, const char *hef_file,
151 hailo_configured_network_group *network_group)
153 hailo_status status = HAILO_UNINITIALIZED;
154 hailo_hef hef = NULL;
155 hailo_configure_params_t configure_params = {0};
157 size_t network_group_size = 1;
160 status = hailo_create_hef_file(&hef, hef_file);
161 REQUIRE_SUCCESS(status, l_exit, "Failed reading hef file %s", hef_file);
163 // Create configure params
164 status = hailo_init_configure_params_by_device(hef, device, &configure_params);
165 REQUIRE_SUCCESS(status, l_exit, "Failed init configure params");
166 REQUIRE_ACTION(configure_params.network_group_params_count == 1, status=HAILO_INVALID_ARGUMENT, l_exit,
167 "Unexpected network group size");
169 // Set HAILO_STREAM_FLAGS_ASYNC for all streams in order to use async api.
170 for (i = 0; i < configure_params.network_group_params[0].stream_params_by_name_count; i++) {
171 configure_params.network_group_params[0].stream_params_by_name[i].stream_params.flags = HAILO_STREAM_FLAGS_ASYNC;
174 status = hailo_configure_device(device, hef, &configure_params, network_group, &network_group_size);
175 REQUIRE_SUCCESS(status, l_release_hef, "Failed configuring device");
177 status = HAILO_SUCCESS;
179 (void) hailo_release_hef(hef);
186 hailo_status status = HAILO_UNINITIALIZED;
187 hailo_device device = NULL;
188 hailo_configured_network_group network_group = NULL;
189 hailo_stream_info_t input_streams_info[MAX_EDGE_LAYERS_PER_DIR] = {0};
190 hailo_stream_info_t output_streams_info[MAX_EDGE_LAYERS_PER_DIR] = {0};
191 hailo_input_stream input_streams[MAX_EDGE_LAYERS_PER_DIR] = {NULL};
192 hailo_output_stream output_streams[MAX_EDGE_LAYERS_PER_DIR] = {NULL};
193 size_t number_input_streams = 0;
194 size_t number_output_streams = 0;
196 size_t queue_size = 0;
197 size_t ongoing_transfers = MAX_ONGOING_TRANSFERS;
198 hailo_activated_network_group activated_network_group = NULL;
200 // Create device object.
201 status = hailo_create_device_by_id(NULL, &device);
202 REQUIRE_SUCCESS(status, l_exit, "Failed to create device");
204 // Configure device with HEF.
205 status = configure_device(device, HEF_FILE, &network_group);
206 REQUIRE_SUCCESS(status, l_release_device, "Failed configure_device");
208 // Get input/output stream objects.
209 status = hailo_network_group_get_input_stream_infos(network_group, input_streams_info, MAX_EDGE_LAYERS_PER_DIR,
210 &number_input_streams);
211 REQUIRE_SUCCESS(status, l_release_device, "Failed getting input streams infos");
213 status = hailo_network_group_get_output_stream_infos(network_group, output_streams_info, MAX_EDGE_LAYERS_PER_DIR,
214 &number_output_streams);
215 REQUIRE_SUCCESS(status, l_release_device, "Failed getting output streams infos");
217 for (index = 0; index < number_input_streams; index++) {
218 status = hailo_get_input_stream(network_group, input_streams_info[index].name, &input_streams[index]);
219 REQUIRE_SUCCESS(status, l_release_device, "Failed getting input stream %s", input_streams_info[index].name);
221 status = hailo_input_stream_get_async_max_queue_size(input_streams[index], &queue_size);
222 REQUIRE_SUCCESS(status, l_release_device, "Failed getting queue size");
224 ongoing_transfers = MIN(queue_size, ongoing_transfers);
227 for (index = 0; index < number_output_streams; index++) {
228 status = hailo_get_output_stream(network_group, output_streams_info[index].name, &output_streams[index]);
229 REQUIRE_SUCCESS(status, l_release_device, "Failed getting output stream %s", output_streams_info[index].name);
231 status = hailo_output_stream_get_async_max_queue_size(output_streams[index], &queue_size);
232 REQUIRE_SUCCESS(status, l_release_device, "Failed getting queue size");
234 ongoing_transfers = MIN(queue_size, ongoing_transfers);
237 // Activate network group
238 status = hailo_activate_network_group(network_group, NULL, &activated_network_group);
239 REQUIRE_SUCCESS(status, l_release_device, "Failed activate network group");
242 status = infer(network_group, number_input_streams, input_streams, number_output_streams, output_streams,
244 REQUIRE_SUCCESS(status, l_deactivate, "Failed performing inference");
246 status = HAILO_SUCCESS;
247 printf("Inference ran successfully\n");
250 (void) hailo_deactivate_network_group(activated_network_group);
252 (void) hailo_release_device(device);