1fa7838c9503b8bcdc860a05c77fcc7f360d1975
[platform/upstream/hailort.git] /
1 /**
2  * Copyright (c) 2020-2022 Hailo Technologies Ltd. All rights reserved.
3  * Distributed under the MIT license (https://opensource.org/licenses/MIT)
4  **/
5 /**
6  * @file raw_async_streams_single_thread_example.c
7  * This example demonstrates basic usage of HailoRT async streaming api with a single thread.
8  **/
9
10 #include "common.h"
11 #include "hailo/hailort.h"
12
13 #include <string.h>
14
15 #if defined(__unix__)
16 #include <sys/mman.h>
17 #endif
18
19
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)
25
26 #if defined(__unix__)
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")
36 #endif
37
38 #ifndef MIN
39 #define MIN(a, b) (((a) < (b)) ? (a) : (b))
40 #endif
41
42
43 static void output_done_callback(const hailo_stream_read_async_completion_info_t *completion_info)
44 {
45     hailo_output_stream stream = (hailo_output_stream)completion_info->opaque;
46     hailo_status status = HAILO_UNINITIALIZED;
47
48     switch (completion_info->status) {
49     case HAILO_SUCCESS:
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);
55         }
56         break;
57     case HAILO_STREAM_ABORTED_BY_USER:
58         // Transfer was canceled, finish gracefully.
59         break;
60     default:
61         fprintf(stderr, "Got an unexpected status on callback. status=%d\n", completion_info->status);
62     }
63 }
64
65 static void input_done_callback(const hailo_stream_write_async_completion_info_t *completion_info)
66 {
67     hailo_input_stream stream = (hailo_input_stream)completion_info->opaque;
68     hailo_status status = HAILO_UNINITIALIZED;
69
70     switch (completion_info->status) {
71     case HAILO_SUCCESS:
72         // Real applications may free the buffer and replace it with new buffer ready to be sent. Here we just re-launch
73         // new async writes.
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);
78         }
79         break;
80     case HAILO_STREAM_ABORTED_BY_USER:
81         // Transfer was canceled, finish gracefully.
82         break;
83     default:
84         fprintf(stderr, "Got an unexpected status on callback. status=%d\n", completion_info->status);
85     }
86 }
87
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)
91 {
92     hailo_status status = HAILO_UNINITIALIZED;
93     size_t i = 0;
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;
100
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]);
105
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;
112
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);
116         }
117     }
118
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]);
121
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;
128
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);
132         }
133     }
134
135     // After all async operations are launched, the inference will continue until we shutdown the network.
136     hailo_sleep(INFER_TIME_SECONDS);
137
138     status = HAILO_SUCCESS;
139 l_shutdown:
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);
143
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);
146
147     return status;
148 }
149
150 static hailo_status configure_device(hailo_device device, const char *hef_file,
151     hailo_configured_network_group *network_group)
152 {
153     hailo_status status = HAILO_UNINITIALIZED;
154     hailo_hef hef = NULL;
155     hailo_configure_params_t configure_params = {0};
156     size_t i = 0;
157     size_t network_group_size = 1;
158
159     // Load HEF file.
160     status = hailo_create_hef_file(&hef, hef_file);
161     REQUIRE_SUCCESS(status, l_exit, "Failed reading hef file %s", hef_file);
162
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");
168
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;
172     }
173
174     status = hailo_configure_device(device, hef, &configure_params, network_group, &network_group_size);
175     REQUIRE_SUCCESS(status, l_release_hef, "Failed configuring device");
176
177     status = HAILO_SUCCESS;
178 l_release_hef:
179     (void) hailo_release_hef(hef);
180 l_exit:
181     return status;
182 }
183
184 int main()
185 {
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;
195     size_t index = 0;
196     size_t queue_size = 0;
197     size_t ongoing_transfers = MAX_ONGOING_TRANSFERS;
198     hailo_activated_network_group activated_network_group = NULL;
199
200     // Create device object.
201     status = hailo_create_device_by_id(NULL, &device);
202     REQUIRE_SUCCESS(status, l_exit, "Failed to create device");
203
204     // Configure device with HEF.
205     status = configure_device(device, HEF_FILE, &network_group);
206     REQUIRE_SUCCESS(status, l_release_device, "Failed configure_device");
207
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");
212
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");
216
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);
220
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");
223
224         ongoing_transfers = MIN(queue_size, ongoing_transfers);
225     }
226
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);
230
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");
233
234         ongoing_transfers = MIN(queue_size, ongoing_transfers);
235     }
236
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");
240
241     // Run infer.
242     status = infer(network_group, number_input_streams, input_streams, number_output_streams, output_streams,
243         ongoing_transfers);
244     REQUIRE_SUCCESS(status, l_deactivate, "Failed performing inference");
245
246     status = HAILO_SUCCESS;
247     printf("Inference ran successfully\n");
248
249 l_deactivate:
250     (void) hailo_deactivate_network_group(activated_network_group);
251 l_release_device:
252     (void) hailo_release_device(device);
253 l_exit:
254     return (int)status;
255 }