blob: 40fc909d214987f3eaa0ae387dbb9a577fd73548 [file] [log] [blame]
Kristofer Jonsson116a6352020-08-20 17:25:23 +02001/*
2 * Copyright (c) 2020 Arm Limited. All rights reserved.
3 *
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
53 for (auto it = shape->begin(); it != shape->end(); ++it) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +020054 size *= *it;
55 }
56
57 return size;
58}
59
Kristofer Jonsson5e632c22020-11-25 10:58:38 +010060size_t getTensorTypeSize(const enum tflite::TensorType type) {
61 switch (type) {
62 case tflite::TensorType::TensorType_UINT8:
63 case tflite::TensorType::TensorType_INT8:
64 return 1;
65 case tflite::TensorType::TensorType_INT16:
66 return 2;
Henrik Hoglind031f4c12021-03-25 08:32:23 +010067 case tflite::TensorType::TensorType_FLOAT32:
68 return 4;
Kristofer Jonsson5e632c22020-11-25 10:58:38 +010069 default:
70 throw EthosU::Exception("Unsupported tensor type");
71 }
72}
73
Kristofer Jonsson79689c52020-10-16 14:42:19 +020074vector<size_t> getSubGraphDims(const tflite::SubGraph *subgraph, const flatbuffers::Vector<int32_t> *tensorMap) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +020075 vector<size_t> dims;
76
Kristofer Jonsson79689c52020-10-16 14:42:19 +020077 for (auto index = tensorMap->begin(); index != tensorMap->end(); ++index) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +020078 auto tensor = subgraph->tensors()->Get(*index);
79 size_t size = getShapeSize(tensor->shape());
Kristofer Jonsson5e632c22020-11-25 10:58:38 +010080 size *= getTensorTypeSize(tensor->type());
Kristofer Jonssonb74492c2020-09-10 13:26:01 +020081
Kristofer Jonsson79689c52020-10-16 14:42:19 +020082 if (size > 0) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +020083 dims.push_back(size);
84 }
85 }
86
87 return dims;
88}
89
Kristofer Jonsson79689c52020-10-16 14:42:19 +020090} // namespace
Kristofer Jonsson116a6352020-08-20 17:25:23 +020091
Kristofer Jonsson79689c52020-10-16 14:42:19 +020092namespace EthosU {
Kristofer Jonsson116a6352020-08-20 17:25:23 +020093
Kristofer Jonssonb74492c2020-09-10 13:26:01 +020094/****************************************************************************
95 * Exception
96 ****************************************************************************/
97
Kristofer Jonsson79689c52020-10-16 14:42:19 +020098Exception::Exception(const char *msg) : msg(msg) {}
Kristofer Jonsson116a6352020-08-20 17:25:23 +020099
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200100Exception::~Exception() throw() {}
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200101
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200102const char *Exception::what() const throw() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200103 return msg.c_str();
104}
105
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200106/****************************************************************************
107 * Device
108 ****************************************************************************/
109
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200110Device::Device(const char *device) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200111 fd = open(device, O_RDWR | O_NONBLOCK);
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200112 if (fd < 0) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200113 throw Exception("Failed to open device");
114 }
115}
116
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200117Device::~Device() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200118 close(fd);
119}
120
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200121int Device::ioctl(unsigned long cmd, void *data) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200122 return eioctl(fd, cmd, data);
123}
124
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200125/****************************************************************************
126 * Buffer
127 ****************************************************************************/
128
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200129Buffer::Buffer(Device &device, const size_t capacity) : fd(-1), dataPtr(nullptr), dataCapacity(capacity) {
130 ethosu_uapi_buffer_create uapi = {static_cast<uint32_t>(dataCapacity)};
131 fd = device.ioctl(ETHOSU_IOCTL_BUFFER_CREATE, static_cast<void *>(&uapi));
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200132
133 void *d = ::mmap(nullptr, dataCapacity, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200134 if (d == MAP_FAILED) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200135 throw Exception("MMap failed");
136 }
137
138 dataPtr = reinterpret_cast<char *>(d);
139}
140
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200141Buffer::~Buffer() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200142 close(fd);
143}
144
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200145size_t Buffer::capacity() const {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200146 return dataCapacity;
147}
148
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200149void Buffer::clear() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200150 resize(0, 0);
151}
152
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200153char *Buffer::data() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200154 return dataPtr + offset();
155}
156
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200157void Buffer::resize(size_t size, size_t offset) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200158 ethosu_uapi_buffer uapi;
159 uapi.offset = offset;
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200160 uapi.size = size;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200161 eioctl(fd, ETHOSU_IOCTL_BUFFER_SET, static_cast<void *>(&uapi));
162}
163
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200164size_t Buffer::offset() const {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200165 ethosu_uapi_buffer uapi;
166 eioctl(fd, ETHOSU_IOCTL_BUFFER_GET, static_cast<void *>(&uapi));
167 return uapi.offset;
168}
169
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200170size_t Buffer::size() const {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200171 ethosu_uapi_buffer uapi;
172 eioctl(fd, ETHOSU_IOCTL_BUFFER_GET, static_cast<void *>(&uapi));
173 return uapi.size;
174}
175
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200176int Buffer::getFd() const {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200177 return fd;
178}
179
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200180/****************************************************************************
181 * Network
182 ****************************************************************************/
183
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200184Network::Network(Device &device, shared_ptr<Buffer> &buffer) : fd(-1), buffer(buffer) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200185 // Create buffer handle
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200186 ethosu_uapi_network_create uapi;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200187 uapi.fd = buffer->getFd();
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200188 fd = device.ioctl(ETHOSU_IOCTL_NETWORK_CREATE, static_cast<void *>(&uapi));
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200189
190 // Create model handle
191 const tflite::Model *model = tflite::GetModel(reinterpret_cast<void *>(buffer->data()));
192
193 // Get input dimensions for first subgraph
194 auto *subgraph = *model->subgraphs()->begin();
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200195 ifmDims = getSubGraphDims(subgraph, subgraph->inputs());
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200196
197 // Get output dimensions for last subgraph
198 subgraph = *model->subgraphs()->rbegin();
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200199 ofmDims = getSubGraphDims(subgraph, subgraph->outputs());
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200200}
201
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200202Network::~Network() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200203 close(fd);
204}
205
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200206int Network::ioctl(unsigned long cmd, void *data) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200207 return eioctl(fd, cmd, data);
208}
209
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200210shared_ptr<Buffer> Network::getBuffer() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200211 return buffer;
212}
213
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200214const std::vector<size_t> &Network::getIfmDims() const {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200215 return ifmDims;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200216}
217
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200218size_t Network::getIfmSize() const {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200219 size_t size = 0;
220
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200221 for (auto s : ifmDims) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200222 size += s;
223 }
224
225 return size;
226}
227
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200228const std::vector<size_t> &Network::getOfmDims() const {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200229 return ofmDims;
230}
231
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200232size_t Network::getOfmSize() const {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200233 size_t size = 0;
234
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200235 for (auto s : ofmDims) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200236 size += s;
237 }
238
239 return size;
240}
241
242/****************************************************************************
243 * Inference
244 ****************************************************************************/
245
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200246Inference::~Inference() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200247 close(fd);
248}
249
Per Åstrand2354d3e2020-10-24 20:17:10 +0200250void Inference::create(std::vector<uint32_t> &counterConfigs, bool cycleCounterEnable = false) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200251 ethosu_uapi_inference_create uapi;
252
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200253 if (ifmBuffers.size() > ETHOSU_FD_MAX) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200254 throw Exception("IFM buffer overflow");
255 }
256
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200257 if (ofmBuffers.size() > ETHOSU_FD_MAX) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200258 throw Exception("OFM buffer overflow");
259 }
260
Per Åstrand2354d3e2020-10-24 20:17:10 +0200261 if (counterConfigs.size() != ETHOSU_PMU_EVENT_MAX) {
262 throw Exception("Wrong size of counter configurations");
263 }
264
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200265 uapi.ifm_count = 0;
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200266 for (auto it : ifmBuffers) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200267 uapi.ifm_fd[uapi.ifm_count++] = it->getFd();
268 }
269
270 uapi.ofm_count = 0;
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200271 for (auto it : ofmBuffers) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200272 uapi.ofm_fd[uapi.ofm_count++] = it->getFd();
273 }
274
Per Åstrand2354d3e2020-10-24 20:17:10 +0200275 for (int i = 0; i < ETHOSU_PMU_EVENT_MAX; i++) {
276 uapi.pmu_config.events[i] = counterConfigs[i];
277 }
278
279 uapi.pmu_config.cycle_count = cycleCounterEnable;
280
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200281 fd = network->ioctl(ETHOSU_IOCTL_INFERENCE_CREATE, static_cast<void *>(&uapi));
282}
283
Per Åstrand2354d3e2020-10-24 20:17:10 +0200284std::vector<uint32_t> Inference::initializeCounterConfig() {
285 return std::vector<uint32_t>(ETHOSU_PMU_EVENT_MAX, 0);
286}
287
288uint32_t Inference::getMaxPmuEventCounters() {
289 return ETHOSU_PMU_EVENT_MAX;
290}
291
292int Inference::wait(int timeoutSec) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200293 pollfd pfd;
294
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200295 pfd.fd = fd;
296 pfd.events = POLLIN | POLLERR;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200297 pfd.revents = 0;
298
299 int ret = ::poll(&pfd, 1, timeoutSec * 1000);
300
301 cout << "Poll. ret=" << ret << ", revents=" << pfd.revents << endl;
Per Åstrand2354d3e2020-10-24 20:17:10 +0200302
303 return ret;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200304}
305
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200306bool Inference::failed() {
Per Åstrand2354d3e2020-10-24 20:17:10 +0200307 ethosu_uapi_result_status uapi;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200308
Per Åstrand2354d3e2020-10-24 20:17:10 +0200309 eioctl(fd, ETHOSU_IOCTL_INFERENCE_STATUS, static_cast<void *>(&uapi));
310
311 return uapi.status != ETHOSU_UAPI_STATUS_OK;
312}
313
314const std::vector<uint32_t> Inference::getPmuCounters() {
315 ethosu_uapi_result_status uapi;
316 std::vector<uint32_t> counterValues = std::vector<uint32_t>(ETHOSU_PMU_EVENT_MAX, 0);
317
318 eioctl(fd, ETHOSU_IOCTL_INFERENCE_STATUS, static_cast<void *>(&uapi));
319
320 for (int i = 0; i < ETHOSU_PMU_EVENT_MAX; i++) {
321 if (uapi.pmu_config.events[i]) {
322 counterValues.at(i) = uapi.pmu_count.events[i];
323 }
324 }
325
326 return counterValues;
327}
328
329uint64_t Inference::getCycleCounter() {
330 ethosu_uapi_result_status uapi;
331
332 eioctl(fd, ETHOSU_IOCTL_INFERENCE_STATUS, static_cast<void *>(&uapi));
333
334 return uapi.pmu_count.cycle_count;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200335}
336
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200337int Inference::getFd() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200338 return fd;
339}
340
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200341shared_ptr<Network> Inference::getNetwork() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200342 return network;
343}
344
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200345vector<shared_ptr<Buffer>> &Inference::getIfmBuffers() {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200346 return ifmBuffers;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200347}
348
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200349vector<shared_ptr<Buffer>> &Inference::getOfmBuffers() {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200350 return ofmBuffers;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200351}
352
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200353} // namespace EthosU