blob: 9de26af968f09e6e0daf2254db0da93722e0e4a4 [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 Jonsson79689c52020-10-16 14:42:19 +020060vector<size_t> getSubGraphDims(const tflite::SubGraph *subgraph, const flatbuffers::Vector<int32_t> *tensorMap) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +020061 vector<size_t> dims;
62
Kristofer Jonsson79689c52020-10-16 14:42:19 +020063 for (auto index = tensorMap->begin(); index != tensorMap->end(); ++index) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +020064 auto tensor = subgraph->tensors()->Get(*index);
65 size_t size = getShapeSize(tensor->shape());
66
Kristofer Jonsson79689c52020-10-16 14:42:19 +020067 if (size > 0) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +020068 dims.push_back(size);
69 }
70 }
71
72 return dims;
73}
74
Kristofer Jonsson79689c52020-10-16 14:42:19 +020075} // namespace
Kristofer Jonsson116a6352020-08-20 17:25:23 +020076
Kristofer Jonsson79689c52020-10-16 14:42:19 +020077namespace EthosU {
Kristofer Jonsson116a6352020-08-20 17:25:23 +020078
Kristofer Jonssonb74492c2020-09-10 13:26:01 +020079/****************************************************************************
80 * Exception
81 ****************************************************************************/
82
Kristofer Jonsson79689c52020-10-16 14:42:19 +020083Exception::Exception(const char *msg) : msg(msg) {}
Kristofer Jonsson116a6352020-08-20 17:25:23 +020084
Kristofer Jonsson79689c52020-10-16 14:42:19 +020085Exception::~Exception() throw() {}
Kristofer Jonsson116a6352020-08-20 17:25:23 +020086
Kristofer Jonsson79689c52020-10-16 14:42:19 +020087const char *Exception::what() const throw() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +020088 return msg.c_str();
89}
90
Kristofer Jonssonb74492c2020-09-10 13:26:01 +020091/****************************************************************************
92 * Device
93 ****************************************************************************/
94
Kristofer Jonsson79689c52020-10-16 14:42:19 +020095Device::Device(const char *device) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +020096 fd = open(device, O_RDWR | O_NONBLOCK);
Kristofer Jonsson79689c52020-10-16 14:42:19 +020097 if (fd < 0) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +020098 throw Exception("Failed to open device");
99 }
100}
101
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200102Device::~Device() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200103 close(fd);
104}
105
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200106int Device::ioctl(unsigned long cmd, void *data) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200107 return eioctl(fd, cmd, data);
108}
109
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200110/****************************************************************************
111 * Buffer
112 ****************************************************************************/
113
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200114Buffer::Buffer(Device &device, const size_t capacity) : fd(-1), dataPtr(nullptr), dataCapacity(capacity) {
115 ethosu_uapi_buffer_create uapi = {static_cast<uint32_t>(dataCapacity)};
116 fd = device.ioctl(ETHOSU_IOCTL_BUFFER_CREATE, static_cast<void *>(&uapi));
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200117
118 void *d = ::mmap(nullptr, dataCapacity, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200119 if (d == MAP_FAILED) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200120 throw Exception("MMap failed");
121 }
122
123 dataPtr = reinterpret_cast<char *>(d);
124}
125
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200126Buffer::~Buffer() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200127 close(fd);
128}
129
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200130size_t Buffer::capacity() const {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200131 return dataCapacity;
132}
133
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200134void Buffer::clear() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200135 resize(0, 0);
136}
137
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200138char *Buffer::data() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200139 return dataPtr + offset();
140}
141
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200142void Buffer::resize(size_t size, size_t offset) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200143 ethosu_uapi_buffer uapi;
144 uapi.offset = offset;
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200145 uapi.size = size;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200146 eioctl(fd, ETHOSU_IOCTL_BUFFER_SET, static_cast<void *>(&uapi));
147}
148
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200149size_t Buffer::offset() const {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200150 ethosu_uapi_buffer uapi;
151 eioctl(fd, ETHOSU_IOCTL_BUFFER_GET, static_cast<void *>(&uapi));
152 return uapi.offset;
153}
154
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200155size_t Buffer::size() const {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200156 ethosu_uapi_buffer uapi;
157 eioctl(fd, ETHOSU_IOCTL_BUFFER_GET, static_cast<void *>(&uapi));
158 return uapi.size;
159}
160
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200161int Buffer::getFd() const {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200162 return fd;
163}
164
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200165/****************************************************************************
166 * Network
167 ****************************************************************************/
168
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200169Network::Network(Device &device, shared_ptr<Buffer> &buffer) : fd(-1), buffer(buffer) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200170 // Create buffer handle
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200171 ethosu_uapi_network_create uapi;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200172 uapi.fd = buffer->getFd();
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200173 fd = device.ioctl(ETHOSU_IOCTL_NETWORK_CREATE, static_cast<void *>(&uapi));
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200174
175 // Create model handle
176 const tflite::Model *model = tflite::GetModel(reinterpret_cast<void *>(buffer->data()));
177
178 // Get input dimensions for first subgraph
179 auto *subgraph = *model->subgraphs()->begin();
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200180 ifmDims = getSubGraphDims(subgraph, subgraph->inputs());
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200181
182 // Get output dimensions for last subgraph
183 subgraph = *model->subgraphs()->rbegin();
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200184 ofmDims = getSubGraphDims(subgraph, subgraph->outputs());
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200185}
186
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200187Network::~Network() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200188 close(fd);
189}
190
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200191int Network::ioctl(unsigned long cmd, void *data) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200192 return eioctl(fd, cmd, data);
193}
194
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200195shared_ptr<Buffer> Network::getBuffer() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200196 return buffer;
197}
198
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200199const std::vector<size_t> &Network::getIfmDims() const {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200200 return ifmDims;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200201}
202
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200203size_t Network::getIfmSize() const {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200204 size_t size = 0;
205
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200206 for (auto s : ifmDims) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200207 size += s;
208 }
209
210 return size;
211}
212
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200213const std::vector<size_t> &Network::getOfmDims() const {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200214 return ofmDims;
215}
216
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200217size_t Network::getOfmSize() const {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200218 size_t size = 0;
219
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200220 for (auto s : ofmDims) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200221 size += s;
222 }
223
224 return size;
225}
226
227/****************************************************************************
228 * Inference
229 ****************************************************************************/
230
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200231Inference::~Inference() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200232 close(fd);
233}
234
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200235void Inference::create() {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200236 ethosu_uapi_inference_create uapi;
237
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200238 if (ifmBuffers.size() > ETHOSU_FD_MAX) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200239 throw Exception("IFM buffer overflow");
240 }
241
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200242 if (ofmBuffers.size() > ETHOSU_FD_MAX) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200243 throw Exception("OFM buffer overflow");
244 }
245
246 uapi.ifm_count = 0;
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200247 for (auto it : ifmBuffers) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200248 uapi.ifm_fd[uapi.ifm_count++] = it->getFd();
249 }
250
251 uapi.ofm_count = 0;
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200252 for (auto it : ofmBuffers) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200253 uapi.ofm_fd[uapi.ofm_count++] = it->getFd();
254 }
255
256 fd = network->ioctl(ETHOSU_IOCTL_INFERENCE_CREATE, static_cast<void *>(&uapi));
257}
258
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200259void Inference::wait(int timeoutSec) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200260 pollfd pfd;
261
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200262 pfd.fd = fd;
263 pfd.events = POLLIN | POLLERR;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200264 pfd.revents = 0;
265
266 int ret = ::poll(&pfd, 1, timeoutSec * 1000);
267
268 cout << "Poll. ret=" << ret << ", revents=" << pfd.revents << endl;
269}
270
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200271bool Inference::failed() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200272 ethosu_uapi_status status = static_cast<ethosu_uapi_status>(eioctl(fd, ETHOSU_IOCTL_INFERENCE_STATUS));
273
274 return status != ETHOSU_UAPI_STATUS_OK;
275}
276
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200277int Inference::getFd() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200278 return fd;
279}
280
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200281shared_ptr<Network> Inference::getNetwork() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200282 return network;
283}
284
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200285vector<shared_ptr<Buffer>> &Inference::getIfmBuffers() {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200286 return ifmBuffers;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200287}
288
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200289vector<shared_ptr<Buffer>> &Inference::getOfmBuffers() {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200290 return ofmBuffers;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200291}
292
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200293} // namespace EthosU