b5ce769c879bf2900879feffa21bd738d28d3a5f
[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_NOT_ACTIVATED != 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_NOT_ACTIVATED != 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     hailo_activated_network_group activated_network_group = NULL;
94     size_t i = 0;
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;
101
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);
104
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]);
109
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;
116
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);
120         }
121     }
122
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]);
125
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;
132
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);
136         }
137     }
138
139     // After all async operations are launched, the inference will continue until we deactivate the network.
140     hailo_sleep(INFER_TIME_SECONDS);
141
142     status = HAILO_SUCCESS;
143 l_deactivate:
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);
147
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);
150
151 l_exit:
152     return status;
153 }
154
155 static hailo_status configure_device(hailo_device device, const char *hef_file,
156     hailo_configured_network_group *network_group)
157 {
158     hailo_status status = HAILO_UNINITIALIZED;
159     hailo_hef hef = NULL;
160     hailo_configure_params_t configure_params = {0};
161     size_t i = 0;
162     size_t network_group_size = 1;
163
164     // Load HEF file.
165     status = hailo_create_hef_file(&hef, hef_file);
166     REQUIRE_SUCCESS(status, l_exit, "Failed reading hef file %s", hef_file);
167
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");
173
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;
177     }
178
179     status = hailo_configure_device(device, hef, &configure_params, network_group, &network_group_size);
180     REQUIRE_SUCCESS(status, l_release_hef, "Failed configuring device");
181
182     status = HAILO_SUCCESS;
183 l_release_hef:
184     (void) hailo_release_hef(hef);
185 l_exit:
186     return status;
187 }
188
189 int main()
190 {
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;
200     size_t index = 0;
201     size_t queue_size = 0;
202     size_t ongoing_transfers = MAX_ONGOING_TRANSFERS;
203
204     // Create device object.
205     status = hailo_create_device_by_id(NULL, &device);
206     REQUIRE_SUCCESS(status, l_exit, "Failed to create device");
207
208     // Configure device with HEF.
209     status = configure_device(device, HEF_FILE, &network_group);
210     REQUIRE_SUCCESS(status, l_release_device, "Failed configure_device");
211
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");
216
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");
220
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);
224
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");
227
228         ongoing_transfers = MIN(queue_size, ongoing_transfers);
229     }
230
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);
234
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");
237
238         ongoing_transfers = MIN(queue_size, ongoing_transfers);
239     }
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_release_device, "Failed performing inference");
245
246     status = HAILO_SUCCESS;
247     printf("Inference ran successfully\n");
248
249 l_release_device:
250     (void) hailo_release_device(device);
251 l_exit:
252     return (int)status;
253 }