blob: 39e39f04be81c892964af2131009ec04adc545a7 [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
28#include <sys/ioctl.h>
29#include <sys/mman.h>
30#include <fcntl.h>
31#include <poll.h>
32#include <unistd.h>
33
34using namespace std;
35
36namespace
37{
38int eioctl(int fd, unsigned long cmd, void *data = nullptr)
39{
40 int ret = ::ioctl(fd, cmd, data);
41 if (ret < 0)
42 {
43 throw EthosU::Exception("IOCTL failed");
44 }
45
46 return ret;
47}
Kristofer Jonssonb74492c2020-09-10 13:26:01 +020048
49/****************************************************************************
50 * TFL micro helpers
51 ****************************************************************************/
52
53size_t getShapeSize(const flatbuffers::Vector<int32_t> *shape)
54{
55 size_t size = 1;
56
57 for (auto it = shape->begin(); it != shape->end(); ++it)
58 {
59 size *= *it;
60 }
61
62 return size;
63}
64
65vector<size_t> getSubGraphDims(const tflite::SubGraph *subgraph, const flatbuffers::Vector<int32_t> *tensorMap)
66{
67 vector<size_t> dims;
68
69 for (auto index = tensorMap->begin(); index != tensorMap->end(); ++index)
70 {
71 auto tensor = subgraph->tensors()->Get(*index);
72 size_t size = getShapeSize(tensor->shape());
73
74 if (size > 0)
75 {
76 dims.push_back(size);
77 }
78 }
79
80 return dims;
81}
82
Kristofer Jonsson116a6352020-08-20 17:25:23 +020083}
84
85namespace EthosU
86{
87
Kristofer Jonssonb74492c2020-09-10 13:26:01 +020088/****************************************************************************
89 * Exception
90 ****************************************************************************/
91
Kristofer Jonsson116a6352020-08-20 17:25:23 +020092Exception::Exception(const char *msg) :
93 msg(msg)
94{}
95
96Exception::~Exception() throw()
97{}
98
99const char *Exception::what() const throw()
100{
101 return msg.c_str();
102}
103
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200104/****************************************************************************
105 * Device
106 ****************************************************************************/
107
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200108Device::Device(const char *device)
109{
110 fd = open(device, O_RDWR | O_NONBLOCK);
111 if (fd < 0)
112 {
113 throw Exception("Failed to open device");
114 }
115}
116
117Device::~Device()
118{
119 close(fd);
120}
121
122int Device::ioctl(unsigned long cmd, void *data)
123{
124 return eioctl(fd, cmd, data);
125}
126
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200127/****************************************************************************
128 * Buffer
129 ****************************************************************************/
130
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200131Buffer::Buffer(Device &device, const size_t capacity) :
132 fd(-1),
133 dataPtr(nullptr),
134 dataCapacity(capacity)
135{
136 ethosu_uapi_buffer_create uapi = { static_cast<uint32_t>(dataCapacity) };
137 fd = device.ioctl(ETHOSU_IOCTL_BUFFER_CREATE, static_cast<void *>(&uapi));
138
139 void *d = ::mmap(nullptr, dataCapacity, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
140 if (d == MAP_FAILED)
141 {
142 throw Exception("MMap failed");
143 }
144
145 dataPtr = reinterpret_cast<char *>(d);
146}
147
148Buffer::~Buffer()
149{
150 close(fd);
151}
152
153size_t Buffer::capacity() const
154{
155 return dataCapacity;
156}
157
158void Buffer::clear()
159{
160 resize(0, 0);
161}
162
163char *Buffer::data()
164{
165 return dataPtr + offset();
166}
167
168void Buffer::resize(size_t size, size_t offset)
169{
170 ethosu_uapi_buffer uapi;
171 uapi.offset = offset;
172 uapi.size = size;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200173 eioctl(fd, ETHOSU_IOCTL_BUFFER_SET, static_cast<void *>(&uapi));
174}
175
176size_t Buffer::offset() const
177{
178 ethosu_uapi_buffer uapi;
179 eioctl(fd, ETHOSU_IOCTL_BUFFER_GET, static_cast<void *>(&uapi));
180 return uapi.offset;
181}
182
183size_t Buffer::size() const
184{
185 ethosu_uapi_buffer uapi;
186 eioctl(fd, ETHOSU_IOCTL_BUFFER_GET, static_cast<void *>(&uapi));
187 return uapi.size;
188}
189
190int Buffer::getFd() const
191{
192 return fd;
193}
194
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200195/****************************************************************************
196 * Network
197 ****************************************************************************/
198
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200199Network::Network(Device &device, shared_ptr<Buffer> &buffer) :
200 fd(-1),
201 buffer(buffer)
202{
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200203 // Create buffer handle
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200204 ethosu_uapi_network_create uapi;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200205 uapi.fd = buffer->getFd();
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200206 fd = device.ioctl(ETHOSU_IOCTL_NETWORK_CREATE, static_cast<void *>(&uapi));
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200207
208 // Create model handle
209 const tflite::Model *model = tflite::GetModel(reinterpret_cast<void *>(buffer->data()));
210
211 // Get input dimensions for first subgraph
212 auto *subgraph = *model->subgraphs()->begin();
213 ifmDims = getSubGraphDims(subgraph, subgraph->inputs());
214
215 // Get output dimensions for last subgraph
216 subgraph = *model->subgraphs()->rbegin();
217 ofmDims = getSubGraphDims(subgraph, subgraph->outputs());
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200218}
219
220Network::~Network()
221{
222 close(fd);
223}
224
225int Network::ioctl(unsigned long cmd, void *data)
226{
227 return eioctl(fd, cmd, data);
228}
229
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200230shared_ptr<Buffer> Network::getBuffer()
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200231{
232 return buffer;
233}
234
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200235const std::vector<size_t> &Network::getIfmDims() const
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200236{
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200237 return ifmDims;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200238}
239
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200240size_t Network::getIfmSize() const
241{
242 size_t size = 0;
243
244 for (auto s: ifmDims)
245 {
246 size += s;
247 }
248
249 return size;
250}
251
252const std::vector<size_t> &Network::getOfmDims() const
253{
254 return ofmDims;
255}
256
257size_t Network::getOfmSize() const
258{
259 size_t size = 0;
260
261 for (auto s: ofmDims)
262 {
263 size += s;
264 }
265
266 return size;
267}
268
269/****************************************************************************
270 * Inference
271 ****************************************************************************/
272
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200273Inference::~Inference()
274{
275 close(fd);
276}
277
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200278void Inference::create()
279{
280 ethosu_uapi_inference_create uapi;
281
282 if (ifmBuffers.size() > ETHOSU_FD_MAX)
283 {
284 throw Exception("IFM buffer overflow");
285 }
286
287 if (ofmBuffers.size() > ETHOSU_FD_MAX)
288 {
289 throw Exception("OFM buffer overflow");
290 }
291
292 uapi.ifm_count = 0;
293 for (auto it: ifmBuffers)
294 {
295 uapi.ifm_fd[uapi.ifm_count++] = it->getFd();
296 }
297
298 uapi.ofm_count = 0;
299 for (auto it: ofmBuffers)
300 {
301 uapi.ofm_fd[uapi.ofm_count++] = it->getFd();
302 }
303
304 fd = network->ioctl(ETHOSU_IOCTL_INFERENCE_CREATE, static_cast<void *>(&uapi));
305}
306
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200307void Inference::wait(int timeoutSec)
308{
309 pollfd pfd;
310
311 pfd.fd = fd;
312 pfd.events = POLLIN | POLLERR;
313 pfd.revents = 0;
314
315 int ret = ::poll(&pfd, 1, timeoutSec * 1000);
316
317 cout << "Poll. ret=" << ret << ", revents=" << pfd.revents << endl;
318}
319
320bool Inference::failed()
321{
322 ethosu_uapi_status status = static_cast<ethosu_uapi_status>(eioctl(fd, ETHOSU_IOCTL_INFERENCE_STATUS));
323
324 return status != ETHOSU_UAPI_STATUS_OK;
325}
326
327int Inference::getFd()
328{
329 return fd;
330}
331
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200332shared_ptr<Network> Inference::getNetwork()
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200333{
334 return network;
335}
336
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200337vector<shared_ptr<Buffer>> &Inference::getIfmBuffers()
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200338{
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200339 return ifmBuffers;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200340}
341
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200342vector<shared_ptr<Buffer>> &Inference::getOfmBuffers()
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200343{
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200344 return ofmBuffers;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200345}
346
347}