blob: 2c498a828aef74771e3dcbbfc8e925c72713e3e2 [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;
67 default:
68 throw EthosU::Exception("Unsupported tensor type");
69 }
70}
71
Kristofer Jonsson79689c52020-10-16 14:42:19 +020072vector<size_t> getSubGraphDims(const tflite::SubGraph *subgraph, const flatbuffers::Vector<int32_t> *tensorMap) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +020073 vector<size_t> dims;
74
Kristofer Jonsson79689c52020-10-16 14:42:19 +020075 for (auto index = tensorMap->begin(); index != tensorMap->end(); ++index) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +020076 auto tensor = subgraph->tensors()->Get(*index);
77 size_t size = getShapeSize(tensor->shape());
Kristofer Jonsson5e632c22020-11-25 10:58:38 +010078 size *= getTensorTypeSize(tensor->type());
Kristofer Jonssonb74492c2020-09-10 13:26:01 +020079
Kristofer Jonsson79689c52020-10-16 14:42:19 +020080 if (size > 0) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +020081 dims.push_back(size);
82 }
83 }
84
85 return dims;
86}
87
Kristofer Jonsson79689c52020-10-16 14:42:19 +020088} // namespace
Kristofer Jonsson116a6352020-08-20 17:25:23 +020089
Kristofer Jonsson79689c52020-10-16 14:42:19 +020090namespace EthosU {
Kristofer Jonsson116a6352020-08-20 17:25:23 +020091
Kristofer Jonssonb74492c2020-09-10 13:26:01 +020092/****************************************************************************
93 * Exception
94 ****************************************************************************/
95
Kristofer Jonsson79689c52020-10-16 14:42:19 +020096Exception::Exception(const char *msg) : msg(msg) {}
Kristofer Jonsson116a6352020-08-20 17:25:23 +020097
Kristofer Jonsson79689c52020-10-16 14:42:19 +020098Exception::~Exception() throw() {}
Kristofer Jonsson116a6352020-08-20 17:25:23 +020099
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200100const char *Exception::what() const throw() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200101 return msg.c_str();
102}
103
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200104/****************************************************************************
105 * Device
106 ****************************************************************************/
107
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200108Device::Device(const char *device) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200109 fd = open(device, O_RDWR | O_NONBLOCK);
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200110 if (fd < 0) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200111 throw Exception("Failed to open device");
112 }
113}
114
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200115Device::~Device() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200116 close(fd);
117}
118
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200119int Device::ioctl(unsigned long cmd, void *data) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200120 return eioctl(fd, cmd, data);
121}
122
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200123/****************************************************************************
124 * Buffer
125 ****************************************************************************/
126
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200127Buffer::Buffer(Device &device, const size_t capacity) : fd(-1), dataPtr(nullptr), dataCapacity(capacity) {
128 ethosu_uapi_buffer_create uapi = {static_cast<uint32_t>(dataCapacity)};
129 fd = device.ioctl(ETHOSU_IOCTL_BUFFER_CREATE, static_cast<void *>(&uapi));
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200130
131 void *d = ::mmap(nullptr, dataCapacity, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200132 if (d == MAP_FAILED) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200133 throw Exception("MMap failed");
134 }
135
136 dataPtr = reinterpret_cast<char *>(d);
137}
138
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200139Buffer::~Buffer() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200140 close(fd);
141}
142
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200143size_t Buffer::capacity() const {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200144 return dataCapacity;
145}
146
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200147void Buffer::clear() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200148 resize(0, 0);
149}
150
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200151char *Buffer::data() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200152 return dataPtr + offset();
153}
154
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200155void Buffer::resize(size_t size, size_t offset) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200156 ethosu_uapi_buffer uapi;
157 uapi.offset = offset;
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200158 uapi.size = size;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200159 eioctl(fd, ETHOSU_IOCTL_BUFFER_SET, static_cast<void *>(&uapi));
160}
161
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200162size_t Buffer::offset() const {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200163 ethosu_uapi_buffer uapi;
164 eioctl(fd, ETHOSU_IOCTL_BUFFER_GET, static_cast<void *>(&uapi));
165 return uapi.offset;
166}
167
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200168size_t Buffer::size() const {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200169 ethosu_uapi_buffer uapi;
170 eioctl(fd, ETHOSU_IOCTL_BUFFER_GET, static_cast<void *>(&uapi));
171 return uapi.size;
172}
173
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200174int Buffer::getFd() const {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200175 return fd;
176}
177
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200178/****************************************************************************
179 * Network
180 ****************************************************************************/
181
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200182Network::Network(Device &device, shared_ptr<Buffer> &buffer) : fd(-1), buffer(buffer) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200183 // Create buffer handle
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200184 ethosu_uapi_network_create uapi;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200185 uapi.fd = buffer->getFd();
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200186 fd = device.ioctl(ETHOSU_IOCTL_NETWORK_CREATE, static_cast<void *>(&uapi));
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200187
188 // Create model handle
189 const tflite::Model *model = tflite::GetModel(reinterpret_cast<void *>(buffer->data()));
190
191 // Get input dimensions for first subgraph
192 auto *subgraph = *model->subgraphs()->begin();
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200193 ifmDims = getSubGraphDims(subgraph, subgraph->inputs());
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200194
195 // Get output dimensions for last subgraph
196 subgraph = *model->subgraphs()->rbegin();
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200197 ofmDims = getSubGraphDims(subgraph, subgraph->outputs());
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200198}
199
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200200Network::~Network() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200201 close(fd);
202}
203
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200204int Network::ioctl(unsigned long cmd, void *data) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200205 return eioctl(fd, cmd, data);
206}
207
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200208shared_ptr<Buffer> Network::getBuffer() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200209 return buffer;
210}
211
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200212const std::vector<size_t> &Network::getIfmDims() const {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200213 return ifmDims;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200214}
215
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200216size_t Network::getIfmSize() const {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200217 size_t size = 0;
218
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200219 for (auto s : ifmDims) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200220 size += s;
221 }
222
223 return size;
224}
225
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200226const std::vector<size_t> &Network::getOfmDims() const {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200227 return ofmDims;
228}
229
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200230size_t Network::getOfmSize() 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 : ofmDims) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200234 size += s;
235 }
236
237 return size;
238}
239
240/****************************************************************************
241 * Inference
242 ****************************************************************************/
243
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200244Inference::~Inference() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200245 close(fd);
246}
247
Per Åstrand2354d3e2020-10-24 20:17:10 +0200248void Inference::create(std::vector<uint32_t> &counterConfigs, bool cycleCounterEnable = false) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200249 ethosu_uapi_inference_create uapi;
250
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200251 if (ifmBuffers.size() > ETHOSU_FD_MAX) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200252 throw Exception("IFM buffer overflow");
253 }
254
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200255 if (ofmBuffers.size() > ETHOSU_FD_MAX) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200256 throw Exception("OFM buffer overflow");
257 }
258
Per Åstrand2354d3e2020-10-24 20:17:10 +0200259 if (counterConfigs.size() != ETHOSU_PMU_EVENT_MAX) {
260 throw Exception("Wrong size of counter configurations");
261 }
262
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200263 uapi.ifm_count = 0;
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200264 for (auto it : ifmBuffers) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200265 uapi.ifm_fd[uapi.ifm_count++] = it->getFd();
266 }
267
268 uapi.ofm_count = 0;
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200269 for (auto it : ofmBuffers) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200270 uapi.ofm_fd[uapi.ofm_count++] = it->getFd();
271 }
272
Per Åstrand2354d3e2020-10-24 20:17:10 +0200273 for (int i = 0; i < ETHOSU_PMU_EVENT_MAX; i++) {
274 uapi.pmu_config.events[i] = counterConfigs[i];
275 }
276
277 uapi.pmu_config.cycle_count = cycleCounterEnable;
278
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200279 fd = network->ioctl(ETHOSU_IOCTL_INFERENCE_CREATE, static_cast<void *>(&uapi));
280}
281
Per Åstrand2354d3e2020-10-24 20:17:10 +0200282std::vector<uint32_t> Inference::initializeCounterConfig() {
283 return std::vector<uint32_t>(ETHOSU_PMU_EVENT_MAX, 0);
284}
285
286uint32_t Inference::getMaxPmuEventCounters() {
287 return ETHOSU_PMU_EVENT_MAX;
288}
289
290int Inference::wait(int timeoutSec) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200291 pollfd pfd;
292
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200293 pfd.fd = fd;
294 pfd.events = POLLIN | POLLERR;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200295 pfd.revents = 0;
296
297 int ret = ::poll(&pfd, 1, timeoutSec * 1000);
298
299 cout << "Poll. ret=" << ret << ", revents=" << pfd.revents << endl;
Per Åstrand2354d3e2020-10-24 20:17:10 +0200300
301 return ret;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200302}
303
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200304bool Inference::failed() {
Per Åstrand2354d3e2020-10-24 20:17:10 +0200305 ethosu_uapi_result_status uapi;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200306
Per Åstrand2354d3e2020-10-24 20:17:10 +0200307 eioctl(fd, ETHOSU_IOCTL_INFERENCE_STATUS, static_cast<void *>(&uapi));
308
309 return uapi.status != ETHOSU_UAPI_STATUS_OK;
310}
311
312const std::vector<uint32_t> Inference::getPmuCounters() {
313 ethosu_uapi_result_status uapi;
314 std::vector<uint32_t> counterValues = std::vector<uint32_t>(ETHOSU_PMU_EVENT_MAX, 0);
315
316 eioctl(fd, ETHOSU_IOCTL_INFERENCE_STATUS, static_cast<void *>(&uapi));
317
318 for (int i = 0; i < ETHOSU_PMU_EVENT_MAX; i++) {
319 if (uapi.pmu_config.events[i]) {
320 counterValues.at(i) = uapi.pmu_count.events[i];
321 }
322 }
323
324 return counterValues;
325}
326
327uint64_t Inference::getCycleCounter() {
328 ethosu_uapi_result_status uapi;
329
330 eioctl(fd, ETHOSU_IOCTL_INFERENCE_STATUS, static_cast<void *>(&uapi));
331
332 return uapi.pmu_count.cycle_count;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200333}
334
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200335int Inference::getFd() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200336 return fd;
337}
338
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200339shared_ptr<Network> Inference::getNetwork() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200340 return network;
341}
342
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200343vector<shared_ptr<Buffer>> &Inference::getIfmBuffers() {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200344 return ifmBuffers;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200345}
346
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200347vector<shared_ptr<Buffer>> &Inference::getOfmBuffers() {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200348 return ofmBuffers;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200349}
350
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200351} // namespace EthosU