blob: 1768271dc78948b8188c90ef8e3ed3c35cc743d2 [file] [log] [blame]
Kristofer Jonsson116a6352020-08-20 17:25:23 +02001/*
Anton Moberg4e5e0562021-03-31 11:11:36 +02002 * Copyright (c) 2020-2021 Arm Limited. All rights reserved.
Kristofer Jonsson116a6352020-08-20 17:25:23 +02003 *
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
Kristofer Jonssonb74492c2020-09-10 13:26:01 +020019#include "autogen/tflite_schema.hpp"
20
Kristofer Jonsson116a6352020-08-20 17:25:23 +020021#include <ethosu.hpp>
22#include <uapi/ethosu.h>
23
24#include <algorithm>
25#include <exception>
26#include <iostream>
27
Kristofer Jonsson116a6352020-08-20 17:25:23 +020028#include <fcntl.h>
29#include <poll.h>
Kristofer Jonsson79689c52020-10-16 14:42:19 +020030#include <sys/ioctl.h>
31#include <sys/mman.h>
Kristofer Jonsson116a6352020-08-20 17:25:23 +020032#include <unistd.h>
33
34using namespace std;
35
Kristofer Jonsson79689c52020-10-16 14:42:19 +020036namespace {
37int eioctl(int fd, unsigned long cmd, void *data = nullptr) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +020038 int ret = ::ioctl(fd, cmd, data);
Kristofer Jonsson79689c52020-10-16 14:42:19 +020039 if (ret < 0) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +020040 throw EthosU::Exception("IOCTL failed");
41 }
42
43 return ret;
44}
Kristofer Jonssonb74492c2020-09-10 13:26:01 +020045
46/****************************************************************************
47 * TFL micro helpers
48 ****************************************************************************/
49
Kristofer Jonsson79689c52020-10-16 14:42:19 +020050size_t getShapeSize(const flatbuffers::Vector<int32_t> *shape) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +020051 size_t size = 1;
Kristofer Jonsson79689c52020-10-16 14:42:19 +020052
Jonny Svärd2c017132021-04-12 15:56:44 +020053 if (shape == nullptr) {
54 throw EthosU::Exception("getShapeSize(): nullptr arg");
55 }
56
Kristofer Jonsson79689c52020-10-16 14:42:19 +020057 for (auto it = shape->begin(); it != shape->end(); ++it) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +020058 size *= *it;
59 }
60
61 return size;
62}
63
Kristofer Jonsson5e632c22020-11-25 10:58:38 +010064size_t getTensorTypeSize(const enum tflite::TensorType type) {
65 switch (type) {
66 case tflite::TensorType::TensorType_UINT8:
67 case tflite::TensorType::TensorType_INT8:
68 return 1;
69 case tflite::TensorType::TensorType_INT16:
70 return 2;
Henrik Hoglind031f4c12021-03-25 08:32:23 +010071 case tflite::TensorType::TensorType_FLOAT32:
72 return 4;
Kristofer Jonsson5e632c22020-11-25 10:58:38 +010073 default:
74 throw EthosU::Exception("Unsupported tensor type");
75 }
76}
77
Kristofer Jonsson79689c52020-10-16 14:42:19 +020078vector<size_t> getSubGraphDims(const tflite::SubGraph *subgraph, const flatbuffers::Vector<int32_t> *tensorMap) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +020079 vector<size_t> dims;
80
Jonny Svärd2c017132021-04-12 15:56:44 +020081 if (subgraph == nullptr || tensorMap == nullptr) {
82 throw EthosU::Exception("getSubGraphDims(): nullptr arg(s)");
83 }
84
Kristofer Jonsson79689c52020-10-16 14:42:19 +020085 for (auto index = tensorMap->begin(); index != tensorMap->end(); ++index) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +020086 auto tensor = subgraph->tensors()->Get(*index);
87 size_t size = getShapeSize(tensor->shape());
Kristofer Jonsson5e632c22020-11-25 10:58:38 +010088 size *= getTensorTypeSize(tensor->type());
Kristofer Jonssonb74492c2020-09-10 13:26:01 +020089
Kristofer Jonsson79689c52020-10-16 14:42:19 +020090 if (size > 0) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +020091 dims.push_back(size);
92 }
93 }
94
95 return dims;
96}
97
Kristofer Jonsson79689c52020-10-16 14:42:19 +020098} // namespace
Kristofer Jonsson116a6352020-08-20 17:25:23 +020099
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200100namespace EthosU {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200101
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200102/****************************************************************************
103 * Exception
104 ****************************************************************************/
105
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200106Exception::Exception(const char *msg) : msg(msg) {}
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200107
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200108Exception::~Exception() throw() {}
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200109
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200110const char *Exception::what() const throw() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200111 return msg.c_str();
112}
113
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200114/****************************************************************************
115 * Device
116 ****************************************************************************/
117
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200118Device::Device(const char *device) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200119 fd = open(device, O_RDWR | O_NONBLOCK);
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200120 if (fd < 0) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200121 throw Exception("Failed to open device");
122 }
123}
124
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200125Device::~Device() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200126 close(fd);
127}
128
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200129int Device::ioctl(unsigned long cmd, void *data) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200130 return eioctl(fd, cmd, data);
131}
132
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200133/****************************************************************************
134 * Buffer
135 ****************************************************************************/
136
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200137Buffer::Buffer(Device &device, const size_t capacity) : fd(-1), dataPtr(nullptr), dataCapacity(capacity) {
138 ethosu_uapi_buffer_create uapi = {static_cast<uint32_t>(dataCapacity)};
139 fd = device.ioctl(ETHOSU_IOCTL_BUFFER_CREATE, static_cast<void *>(&uapi));
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200140
141 void *d = ::mmap(nullptr, dataCapacity, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200142 if (d == MAP_FAILED) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200143 throw Exception("MMap failed");
144 }
145
146 dataPtr = reinterpret_cast<char *>(d);
147}
148
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200149Buffer::~Buffer() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200150 close(fd);
151}
152
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200153size_t Buffer::capacity() const {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200154 return dataCapacity;
155}
156
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200157void Buffer::clear() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200158 resize(0, 0);
159}
160
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200161char *Buffer::data() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200162 return dataPtr + offset();
163}
164
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200165void Buffer::resize(size_t size, size_t offset) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200166 ethosu_uapi_buffer uapi;
167 uapi.offset = offset;
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200168 uapi.size = size;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200169 eioctl(fd, ETHOSU_IOCTL_BUFFER_SET, static_cast<void *>(&uapi));
170}
171
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200172size_t Buffer::offset() const {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200173 ethosu_uapi_buffer uapi;
174 eioctl(fd, ETHOSU_IOCTL_BUFFER_GET, static_cast<void *>(&uapi));
175 return uapi.offset;
176}
177
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200178size_t Buffer::size() const {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200179 ethosu_uapi_buffer uapi;
180 eioctl(fd, ETHOSU_IOCTL_BUFFER_GET, static_cast<void *>(&uapi));
181 return uapi.size;
182}
183
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200184int Buffer::getFd() const {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200185 return fd;
186}
187
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200188/****************************************************************************
189 * Network
190 ****************************************************************************/
191
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200192Network::Network(Device &device, shared_ptr<Buffer> &buffer) : fd(-1), buffer(buffer) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200193 // Create buffer handle
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200194 ethosu_uapi_network_create uapi;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200195 uapi.fd = buffer->getFd();
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200196 fd = device.ioctl(ETHOSU_IOCTL_NETWORK_CREATE, static_cast<void *>(&uapi));
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200197
198 // Create model handle
199 const tflite::Model *model = tflite::GetModel(reinterpret_cast<void *>(buffer->data()));
200
Jonny Svärd2c017132021-04-12 15:56:44 +0200201 if (model->subgraphs() == nullptr) {
202 throw EthosU::Exception("Failed to get subgraphs: nullptr");
203 }
204
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200205 // Get input dimensions for first subgraph
206 auto *subgraph = *model->subgraphs()->begin();
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200207 ifmDims = getSubGraphDims(subgraph, subgraph->inputs());
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200208
209 // Get output dimensions for last subgraph
210 subgraph = *model->subgraphs()->rbegin();
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200211 ofmDims = getSubGraphDims(subgraph, subgraph->outputs());
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200212}
213
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200214Network::~Network() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200215 close(fd);
216}
217
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200218int Network::ioctl(unsigned long cmd, void *data) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200219 return eioctl(fd, cmd, data);
220}
221
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200222shared_ptr<Buffer> Network::getBuffer() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200223 return buffer;
224}
225
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200226const std::vector<size_t> &Network::getIfmDims() const {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200227 return ifmDims;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200228}
229
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200230size_t Network::getIfmSize() const {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200231 size_t size = 0;
232
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200233 for (auto s : ifmDims) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200234 size += s;
235 }
236
237 return size;
238}
239
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200240const std::vector<size_t> &Network::getOfmDims() const {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200241 return ofmDims;
242}
243
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200244size_t Network::getOfmSize() const {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200245 size_t size = 0;
246
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200247 for (auto s : ofmDims) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200248 size += s;
249 }
250
251 return size;
252}
253
254/****************************************************************************
255 * Inference
256 ****************************************************************************/
257
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200258Inference::~Inference() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200259 close(fd);
260}
261
Per Åstrand2354d3e2020-10-24 20:17:10 +0200262void Inference::create(std::vector<uint32_t> &counterConfigs, bool cycleCounterEnable = false) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200263 ethosu_uapi_inference_create uapi;
264
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200265 if (ifmBuffers.size() > ETHOSU_FD_MAX) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200266 throw Exception("IFM buffer overflow");
267 }
268
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200269 if (ofmBuffers.size() > ETHOSU_FD_MAX) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200270 throw Exception("OFM buffer overflow");
271 }
272
Per Åstrand2354d3e2020-10-24 20:17:10 +0200273 if (counterConfigs.size() != ETHOSU_PMU_EVENT_MAX) {
274 throw Exception("Wrong size of counter configurations");
275 }
276
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200277 uapi.ifm_count = 0;
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200278 for (auto it : ifmBuffers) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200279 uapi.ifm_fd[uapi.ifm_count++] = it->getFd();
280 }
281
282 uapi.ofm_count = 0;
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200283 for (auto it : ofmBuffers) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200284 uapi.ofm_fd[uapi.ofm_count++] = it->getFd();
285 }
286
Per Åstrand2354d3e2020-10-24 20:17:10 +0200287 for (int i = 0; i < ETHOSU_PMU_EVENT_MAX; i++) {
288 uapi.pmu_config.events[i] = counterConfigs[i];
289 }
290
291 uapi.pmu_config.cycle_count = cycleCounterEnable;
292
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200293 fd = network->ioctl(ETHOSU_IOCTL_INFERENCE_CREATE, static_cast<void *>(&uapi));
294}
295
Per Åstrand2354d3e2020-10-24 20:17:10 +0200296std::vector<uint32_t> Inference::initializeCounterConfig() {
297 return std::vector<uint32_t>(ETHOSU_PMU_EVENT_MAX, 0);
298}
299
300uint32_t Inference::getMaxPmuEventCounters() {
301 return ETHOSU_PMU_EVENT_MAX;
302}
303
304int Inference::wait(int timeoutSec) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200305 pollfd pfd;
306
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200307 pfd.fd = fd;
308 pfd.events = POLLIN | POLLERR;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200309 pfd.revents = 0;
310
311 int ret = ::poll(&pfd, 1, timeoutSec * 1000);
312
313 cout << "Poll. ret=" << ret << ", revents=" << pfd.revents << endl;
Per Åstrand2354d3e2020-10-24 20:17:10 +0200314
315 return ret;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200316}
317
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200318bool Inference::failed() {
Per Åstrand2354d3e2020-10-24 20:17:10 +0200319 ethosu_uapi_result_status uapi;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200320
Per Åstrand2354d3e2020-10-24 20:17:10 +0200321 eioctl(fd, ETHOSU_IOCTL_INFERENCE_STATUS, static_cast<void *>(&uapi));
322
323 return uapi.status != ETHOSU_UAPI_STATUS_OK;
324}
325
326const std::vector<uint32_t> Inference::getPmuCounters() {
327 ethosu_uapi_result_status uapi;
328 std::vector<uint32_t> counterValues = std::vector<uint32_t>(ETHOSU_PMU_EVENT_MAX, 0);
329
330 eioctl(fd, ETHOSU_IOCTL_INFERENCE_STATUS, static_cast<void *>(&uapi));
331
332 for (int i = 0; i < ETHOSU_PMU_EVENT_MAX; i++) {
333 if (uapi.pmu_config.events[i]) {
334 counterValues.at(i) = uapi.pmu_count.events[i];
335 }
336 }
337
338 return counterValues;
339}
340
341uint64_t Inference::getCycleCounter() {
342 ethosu_uapi_result_status uapi;
343
344 eioctl(fd, ETHOSU_IOCTL_INFERENCE_STATUS, static_cast<void *>(&uapi));
345
346 return uapi.pmu_count.cycle_count;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200347}
348
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200349int Inference::getFd() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200350 return fd;
351}
352
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200353shared_ptr<Network> Inference::getNetwork() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200354 return network;
355}
356
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200357vector<shared_ptr<Buffer>> &Inference::getIfmBuffers() {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200358 return ifmBuffers;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200359}
360
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200361vector<shared_ptr<Buffer>> &Inference::getOfmBuffers() {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200362 return ofmBuffers;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200363}
364
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200365} // namespace EthosU