blob: 1c1821d40b70e530536148dbea13e18b1848f5d4 [file] [log] [blame]
Kristofer Jonsson43ce4912020-11-20 09:42:53 +01001/*
Anton Moberg6a7703e2021-03-02 15:14:29 +01002 * Copyright (c) 2019-2021 Arm Limited. All rights reserved.
Kristofer Jonsson43ce4912020-11-20 09:42:53 +01003 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Licensed under the Apache License, Version 2.0 (the License); you may
7 * not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an AS IS BASIS, WITHOUT
14 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19/****************************************************************************
20 * Includes
21 ****************************************************************************/
22
Kristofer Jonsson43ce4912020-11-20 09:42:53 +010023#include "FreeRTOS.h"
24#include "queue.h"
Anton Moberg6a7703e2021-03-02 15:14:29 +010025#include "semphr.h"
Kristofer Jonsson43ce4912020-11-20 09:42:53 +010026#include "task.h"
27
Anton Moberg6a7703e2021-03-02 15:14:29 +010028#include <inttypes.h>
29#include <stdio.h>
30#include <vector>
31
Kristofer Jonsson43ce4912020-11-20 09:42:53 +010032#include "inference_process.hpp"
Kristofer Jonsson43ce4912020-11-20 09:42:53 +010033
Anton Moberg6a7703e2021-03-02 15:14:29 +010034// Model data (Defined & changable by modifiying compile definition in CMakeLists.txt)
35#include "input.h"
36#include "model.h"
37#include "output.h"
Kristofer Jonsson43ce4912020-11-20 09:42:53 +010038
39using namespace std;
40using namespace InferenceProcess;
41
42/****************************************************************************
Anton Moberg6a7703e2021-03-02 15:14:29 +010043 * Defines
44 ****************************************************************************/
45
46// Nr. of tasks to process inferences with. Task reserves driver & runs inference (Normally 1 per NPU, but not a must)
47#define NUM_INFERENCE_TASKS 1
48// Nr. of tasks to create jobs and recieve responses
Lior Dekeledaf2f82021-08-10 17:06:16 +030049#define NUM_JOB_TASKS 2
Anton Moberg6a7703e2021-03-02 15:14:29 +010050// Nr. of jobs to create per job task
51#define NUM_JOBS_PER_TASK 1
52
53// Tensor arena size
54#ifdef TENSOR_ARENA_SIZE // If defined in model.h
55#define TENSOR_ARENA_SIZE_PER_INFERENCE TENSOR_ARENA_SIZE
56#else // If not defined, use maximum available
57#define TENSOR_ARENA_SIZE_PER_INFERENCE 2000000 / NUM_INFERENCE_TASKS
58#endif
59
60/****************************************************************************
Kristofer Jonsson43ce4912020-11-20 09:42:53 +010061 * InferenceJob
62 ****************************************************************************/
63
Anton Moberg6a7703e2021-03-02 15:14:29 +010064struct ProcessTaskParams {
Lior Dekeledaf2f82021-08-10 17:06:16 +030065 ProcessTaskParams() : queueHandle(nullptr), tensorArena(nullptr), arenaSize(0) {}
Anton Moberg6a7703e2021-03-02 15:14:29 +010066 ProcessTaskParams(QueueHandle_t _queue, uint8_t *_tensorArena, size_t _arenaSize) :
67 queueHandle(_queue), tensorArena(_tensorArena), arenaSize(_arenaSize) {}
Anton Moberg1a679c42021-02-10 08:45:39 +010068
Anton Moberg6a7703e2021-03-02 15:14:29 +010069 QueueHandle_t queueHandle;
70 uint8_t *tensorArena;
71 size_t arenaSize;
Kristofer Jonsson43ce4912020-11-20 09:42:53 +010072};
73
Lior Dekeledaf2f82021-08-10 17:06:16 +030074namespace {
Anton Moberg6a7703e2021-03-02 15:14:29 +010075// Number of total completed jobs, needed to exit application correctly if NUM_JOB_TASKS > 1
Lior Dekeledaf2f82021-08-10 17:06:16 +030076int totalCompletedJobs = 0;
Kristofer Jonsson43ce4912020-11-20 09:42:53 +010077
Anton Moberg6a7703e2021-03-02 15:14:29 +010078// TensorArena static initialisation
Lior Dekeledaf2f82021-08-10 17:06:16 +030079const size_t arenaSize = TENSOR_ARENA_SIZE_PER_INFERENCE;
80
81// Declare below variables in global scope to avoid stack since FreeRTOS resets stack when the scheduler is started
82QueueHandle_t inferenceProcessQueue;
83ProcessTaskParams taskParams[NUM_INFERENCE_TASKS];
84} // namespace
85
Anton Moberg6a7703e2021-03-02 15:14:29 +010086__attribute__((section(".bss.tensor_arena"), aligned(16)))
87uint8_t inferenceProcessTensorArena[NUM_INFERENCE_TASKS][arenaSize];
Kristofer Jonsson43ce4912020-11-20 09:42:53 +010088
Anton Moberg6a7703e2021-03-02 15:14:29 +010089// Wrapper around InferenceProcess::InferenceJob. Adds responseQueue and status for FreeRTOS multi-tasking purposes.
90struct xInferenceJob : public InferenceJob {
91 QueueHandle_t responseQueue;
92 bool status;
93
94 xInferenceJob() : InferenceJob(), responseQueue(nullptr), status(false) {}
95 xInferenceJob(const string &_name,
96 const DataPtr &_networkModel,
97 const vector<DataPtr> &_input,
98 const vector<DataPtr> &_output,
99 const vector<DataPtr> &_expectedOutput,
100 const size_t _numBytesToPrint,
101 const vector<uint8_t> &_pmuEventConfig,
102 const uint32_t _pmuCycleCounterEnable,
103 QueueHandle_t _queue) :
104 InferenceJob(_name,
105 _networkModel,
106 _input,
107 _output,
108 _expectedOutput,
109 _numBytesToPrint,
110 _pmuEventConfig,
111 _pmuCycleCounterEnable),
112 responseQueue(_queue), status(false) {}
113};
114
115/****************************************************************************
116 * Mutex & Semaphore
117 * Overrides weak-linked symbols in ethosu_driver.c to implement thread handling
118 ****************************************************************************/
119
120extern "C" {
121
122void *ethosu_mutex_create(void) {
123 return xSemaphoreCreateMutex();
124}
125
126void ethosu_mutex_lock(void *mutex) {
127 SemaphoreHandle_t handle = reinterpret_cast<SemaphoreHandle_t>(mutex);
128 xSemaphoreTake(handle, portMAX_DELAY);
129}
130
131void ethosu_mutex_unlock(void *mutex) {
132 SemaphoreHandle_t handle = reinterpret_cast<SemaphoreHandle_t>(mutex);
133 xSemaphoreGive(handle);
134}
135
136void *ethosu_semaphore_create(void) {
137 return xSemaphoreCreateBinary();
138}
139
140void ethosu_semaphore_take(void *sem) {
141 SemaphoreHandle_t handle = reinterpret_cast<SemaphoreHandle_t>(sem);
142 xSemaphoreTake(handle, portMAX_DELAY);
143}
144
145void ethosu_semaphore_give(void *sem) {
146 SemaphoreHandle_t handle = reinterpret_cast<SemaphoreHandle_t>(sem);
147 xSemaphoreGive(handle);
148}
149}
Kristofer Jonsson43ce4912020-11-20 09:42:53 +0100150
151/****************************************************************************
152 * Functions
153 ****************************************************************************/
154
Anton Moberg6a7703e2021-03-02 15:14:29 +0100155// inferenceProcessTask - Run jobs from queue with available driver
Kristofer Jonsson43ce4912020-11-20 09:42:53 +0100156void inferenceProcessTask(void *pvParameters) {
Anton Moberg6a7703e2021-03-02 15:14:29 +0100157 ProcessTaskParams params = *reinterpret_cast<ProcessTaskParams *>(pvParameters);
Kristofer Jonsson43ce4912020-11-20 09:42:53 +0100158
Anton Moberg6a7703e2021-03-02 15:14:29 +0100159 class InferenceProcess inferenceProcess(params.tensorArena, params.arenaSize);
Kristofer Jonsson43ce4912020-11-20 09:42:53 +0100160
Anton Moberg6a7703e2021-03-02 15:14:29 +0100161 for (;;) {
162 xInferenceJob *xJob;
Kristofer Jonsson43ce4912020-11-20 09:42:53 +0100163
Anton Moberg6a7703e2021-03-02 15:14:29 +0100164 xQueueReceive(params.queueHandle, &xJob, portMAX_DELAY);
165 bool status = inferenceProcess.runJob(*xJob);
166 xJob->status = status;
167 xQueueSend(xJob->responseQueue, &xJob, portMAX_DELAY);
Kristofer Jonsson43ce4912020-11-20 09:42:53 +0100168 }
Anton Moberg6a7703e2021-03-02 15:14:29 +0100169 vTaskDelete(nullptr);
Kristofer Jonsson43ce4912020-11-20 09:42:53 +0100170}
171
Anton Moberg6a7703e2021-03-02 15:14:29 +0100172// inferenceSenderTask - Creates NUM_INFERNECE_JOBS jobs, queues them, and then listens for completion status
173void inferenceSenderTask(void *pvParameters) {
174 int ret = 0;
175
Kristofer Jonsson43ce4912020-11-20 09:42:53 +0100176 QueueHandle_t inferenceProcessQueue = reinterpret_cast<QueueHandle_t>(pvParameters);
Anton Moberg6a7703e2021-03-02 15:14:29 +0100177 xInferenceJob jobs[NUM_JOBS_PER_TASK];
Kristofer Jonsson43ce4912020-11-20 09:42:53 +0100178
179 // Create queue for response messages
Anton Moberg6a7703e2021-03-02 15:14:29 +0100180 QueueHandle_t senderQueue = xQueueCreate(NUM_JOBS_PER_TASK, sizeof(xInferenceJob *));
Kristofer Jonsson43ce4912020-11-20 09:42:53 +0100181
Anton Moberg6a7703e2021-03-02 15:14:29 +0100182 // Create and queue the jobs
183 for (int n = 0; n < NUM_JOBS_PER_TASK; n++) {
184 // Create job
185 xInferenceJob *job = &jobs[n];
186 job->name = string(modelName);
187 job->networkModel = DataPtr(networkModelData, sizeof(networkModelData));
188 job->input.push_back(DataPtr(inputData, sizeof(inputData)));
189 job->expectedOutput.push_back(DataPtr(expectedOutputData, sizeof(expectedOutputData)));
190 job->responseQueue = senderQueue;
191 // Send job
192 printf("Sending inference job: job=%p, name=%s\n", job, job->name.c_str());
193 xQueueSend(inferenceProcessQueue, &job, portMAX_DELAY);
194 }
Kristofer Jonsson43ce4912020-11-20 09:42:53 +0100195
Anton Moberg6a7703e2021-03-02 15:14:29 +0100196 // Listen for completion status
197 do {
198 xInferenceJob *pSendJob;
199 xQueueReceive(senderQueue, &pSendJob, portMAX_DELAY);
200 printf("inferenceSenderTask: received response for job: %s, status = %u\n",
201 pSendJob->name.c_str(),
202 pSendJob->status);
Kristofer Jonsson43ce4912020-11-20 09:42:53 +0100203
Anton Moberg6a7703e2021-03-02 15:14:29 +0100204 totalCompletedJobs++;
205 ret = (pSendJob->status);
206 if (pSendJob->status != 0) {
207 break;
208 }
209 } while (totalCompletedJobs < NUM_JOBS_PER_TASK * NUM_JOB_TASKS);
Kristofer Jonsson43ce4912020-11-20 09:42:53 +0100210
Anton Moberg6a7703e2021-03-02 15:14:29 +0100211 vQueueDelete(senderQueue);
Kristofer Jonsson43ce4912020-11-20 09:42:53 +0100212
Anton Moberg6a7703e2021-03-02 15:14:29 +0100213 printf("FreeRTOS application returning %d.\n", ret);
214 exit(ret);
Kristofer Jonsson43ce4912020-11-20 09:42:53 +0100215}
216
Anton Moberg6a7703e2021-03-02 15:14:29 +0100217/****************************************************************************
218 * Application
219 ****************************************************************************/
Anton Moberg6a7703e2021-03-02 15:14:29 +0100220// FreeRTOS application. NOTE: Additional tasks may require increased heap size.
Kristofer Jonsson43ce4912020-11-20 09:42:53 +0100221int main() {
Anton Moberg6a7703e2021-03-02 15:14:29 +0100222 BaseType_t ret;
223 inferenceProcessQueue = xQueueCreate(NUM_JOBS_PER_TASK, sizeof(xInferenceJob *));
Kristofer Jonsson43ce4912020-11-20 09:42:53 +0100224
Anton Moberg6a7703e2021-03-02 15:14:29 +0100225 // inferenceSender tasks to create and queue the jobs
226 for (int n = 0; n < NUM_JOB_TASKS; n++) {
227 ret = xTaskCreate(inferenceSenderTask, "inferenceSenderTask", 2 * 1024, inferenceProcessQueue, 2, nullptr);
228 if (ret != pdPASS) {
229 printf("FreeRTOS: Failed to create 'inferenceSenderTask%i'\n", n);
230 exit(1);
231 }
232 }
Kristofer Jonsson43ce4912020-11-20 09:42:53 +0100233
Anton Moberg6a7703e2021-03-02 15:14:29 +0100234 // Create inferenceProcess tasks to process the queued jobs
235 for (int n = 0; n < NUM_INFERENCE_TASKS; n++) {
236 taskParams[n] = ProcessTaskParams(inferenceProcessQueue, inferenceProcessTensorArena[n], arenaSize);
Kristofer Jonsson99f19422021-07-01 22:15:02 +0200237 ret = xTaskCreate(inferenceProcessTask, "inferenceProcessTask", 8 * 1024, &taskParams[n], 3, nullptr);
Anton Moberg6a7703e2021-03-02 15:14:29 +0100238 if (ret != pdPASS) {
239 printf("FreeRTOS: Failed to create 'inferenceProcessTask%i'\n", n);
240 exit(1);
241 }
242 }
243
244 // Start Scheduler
Kristofer Jonsson43ce4912020-11-20 09:42:53 +0100245 vTaskStartScheduler();
246
Anton Moberg6a7703e2021-03-02 15:14:29 +0100247 printf("FreeRTOS application failed to initialise \n");
248 exit(1);
249
Kristofer Jonsson43ce4912020-11-20 09:42:53 +0100250 return 0;
Lior Dekeledaf2f82021-08-10 17:06:16 +0300251}