blob: 997e12a2c0515f5150dcc04c6c7f42a04cf90161 [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/****************************************************************************
Davide Grohmann35ce6c82021-06-01 15:03:51 +0200115 * Semantic Version
116 ****************************************************************************/
117
118bool SemanticVersion::operator==(const SemanticVersion &other) {
119 return other.major == major && other.minor == minor && other.patch == patch;
120}
121
122bool SemanticVersion::operator<(const SemanticVersion &other) {
123 if (other.major > major)
124 return true;
125 if (other.minor > minor)
126 return true;
127 return other.patch > patch;
128}
129
130bool SemanticVersion::operator<=(const SemanticVersion &other) {
131 return *this < other || *this == other;
132}
133
134bool SemanticVersion::operator!=(const SemanticVersion &other) {
135 return !(*this == other);
136}
137
138bool SemanticVersion::operator>(const SemanticVersion &other) {
139 return !(*this <= other);
140}
141
142bool SemanticVersion::operator>=(const SemanticVersion &other) {
143 return !(*this < other);
144}
145
146ostream &operator<<(ostream &out, const SemanticVersion &v) {
147 return out << "{ major=" << unsigned(v.major) << ", minor=" << unsigned(v.minor) << ", patch=" << unsigned(v.patch)
148 << " }";
149}
150
151/****************************************************************************
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200152 * Device
153 ****************************************************************************/
154
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200155Device::Device(const char *device) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200156 fd = open(device, O_RDWR | O_NONBLOCK);
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200157 if (fd < 0) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200158 throw Exception("Failed to open device");
159 }
160}
161
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200162Device::~Device() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200163 close(fd);
164}
165
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200166int Device::ioctl(unsigned long cmd, void *data) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200167 return eioctl(fd, cmd, data);
168}
169
Davide Grohmann35ce6c82021-06-01 15:03:51 +0200170Capabilities Device::capabilities() {
171 ethosu_uapi_device_capabilities uapi;
172 (void)eioctl(fd, ETHOSU_IOCTL_CAPABILITIES_REQ, static_cast<void *>(&uapi));
173
174 Capabilities capabilities(
175 HardwareId(uapi.hw_id.version_status,
176 SemanticVersion(uapi.hw_id.version_major, uapi.hw_id.version_minor),
177 SemanticVersion(uapi.hw_id.product_major),
178 SemanticVersion(uapi.hw_id.arch_major_rev, uapi.hw_id.arch_minor_rev, uapi.hw_id.arch_patch_rev)),
Davide Grohmann40e23d12021-06-17 09:59:40 +0200179 HardwareConfiguration(uapi.hw_cfg.macs_per_cc, uapi.hw_cfg.cmd_stream_version, bool(uapi.hw_cfg.custom_dma)),
Davide Grohmann35ce6c82021-06-01 15:03:51 +0200180 SemanticVersion(uapi.driver_major_rev, uapi.driver_minor_rev, uapi.driver_patch_rev));
181 return capabilities;
182}
183
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200184/****************************************************************************
185 * Buffer
186 ****************************************************************************/
187
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200188Buffer::Buffer(Device &device, const size_t capacity) : fd(-1), dataPtr(nullptr), dataCapacity(capacity) {
189 ethosu_uapi_buffer_create uapi = {static_cast<uint32_t>(dataCapacity)};
190 fd = device.ioctl(ETHOSU_IOCTL_BUFFER_CREATE, static_cast<void *>(&uapi));
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200191
192 void *d = ::mmap(nullptr, dataCapacity, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200193 if (d == MAP_FAILED) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200194 throw Exception("MMap failed");
195 }
196
197 dataPtr = reinterpret_cast<char *>(d);
198}
199
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200200Buffer::~Buffer() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200201 close(fd);
202}
203
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200204size_t Buffer::capacity() const {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200205 return dataCapacity;
206}
207
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200208void Buffer::clear() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200209 resize(0, 0);
210}
211
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200212char *Buffer::data() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200213 return dataPtr + offset();
214}
215
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200216void Buffer::resize(size_t size, size_t offset) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200217 ethosu_uapi_buffer uapi;
218 uapi.offset = offset;
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200219 uapi.size = size;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200220 eioctl(fd, ETHOSU_IOCTL_BUFFER_SET, static_cast<void *>(&uapi));
221}
222
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200223size_t Buffer::offset() const {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200224 ethosu_uapi_buffer uapi;
225 eioctl(fd, ETHOSU_IOCTL_BUFFER_GET, static_cast<void *>(&uapi));
226 return uapi.offset;
227}
228
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200229size_t Buffer::size() const {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200230 ethosu_uapi_buffer uapi;
231 eioctl(fd, ETHOSU_IOCTL_BUFFER_GET, static_cast<void *>(&uapi));
232 return uapi.size;
233}
234
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200235int Buffer::getFd() const {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200236 return fd;
237}
238
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200239/****************************************************************************
240 * Network
241 ****************************************************************************/
242
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200243Network::Network(Device &device, shared_ptr<Buffer> &buffer) : fd(-1), buffer(buffer) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200244 // Create buffer handle
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200245 ethosu_uapi_network_create uapi;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200246 uapi.fd = buffer->getFd();
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200247 fd = device.ioctl(ETHOSU_IOCTL_NETWORK_CREATE, static_cast<void *>(&uapi));
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200248
249 // Create model handle
250 const tflite::Model *model = tflite::GetModel(reinterpret_cast<void *>(buffer->data()));
251
Jonny Svärd2c017132021-04-12 15:56:44 +0200252 if (model->subgraphs() == nullptr) {
253 throw EthosU::Exception("Failed to get subgraphs: nullptr");
254 }
255
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200256 // Get input dimensions for first subgraph
257 auto *subgraph = *model->subgraphs()->begin();
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200258 ifmDims = getSubGraphDims(subgraph, subgraph->inputs());
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200259
260 // Get output dimensions for last subgraph
261 subgraph = *model->subgraphs()->rbegin();
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200262 ofmDims = getSubGraphDims(subgraph, subgraph->outputs());
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200263}
264
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200265Network::~Network() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200266 close(fd);
267}
268
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200269int Network::ioctl(unsigned long cmd, void *data) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200270 return eioctl(fd, cmd, data);
271}
272
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200273shared_ptr<Buffer> Network::getBuffer() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200274 return buffer;
275}
276
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200277const std::vector<size_t> &Network::getIfmDims() const {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200278 return ifmDims;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200279}
280
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200281size_t Network::getIfmSize() const {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200282 size_t size = 0;
283
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200284 for (auto s : ifmDims) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200285 size += s;
286 }
287
288 return size;
289}
290
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200291const std::vector<size_t> &Network::getOfmDims() const {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200292 return ofmDims;
293}
294
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200295size_t Network::getOfmSize() const {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200296 size_t size = 0;
297
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200298 for (auto s : ofmDims) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200299 size += s;
300 }
301
302 return size;
303}
304
305/****************************************************************************
306 * Inference
307 ****************************************************************************/
308
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200309Inference::~Inference() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200310 close(fd);
311}
312
Per Åstrand2354d3e2020-10-24 20:17:10 +0200313void Inference::create(std::vector<uint32_t> &counterConfigs, bool cycleCounterEnable = false) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200314 ethosu_uapi_inference_create uapi;
315
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200316 if (ifmBuffers.size() > ETHOSU_FD_MAX) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200317 throw Exception("IFM buffer overflow");
318 }
319
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200320 if (ofmBuffers.size() > ETHOSU_FD_MAX) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200321 throw Exception("OFM buffer overflow");
322 }
323
Per Åstrand2354d3e2020-10-24 20:17:10 +0200324 if (counterConfigs.size() != ETHOSU_PMU_EVENT_MAX) {
325 throw Exception("Wrong size of counter configurations");
326 }
327
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200328 uapi.ifm_count = 0;
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200329 for (auto it : ifmBuffers) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200330 uapi.ifm_fd[uapi.ifm_count++] = it->getFd();
331 }
332
333 uapi.ofm_count = 0;
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200334 for (auto it : ofmBuffers) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200335 uapi.ofm_fd[uapi.ofm_count++] = it->getFd();
336 }
337
Per Åstrand2354d3e2020-10-24 20:17:10 +0200338 for (int i = 0; i < ETHOSU_PMU_EVENT_MAX; i++) {
339 uapi.pmu_config.events[i] = counterConfigs[i];
340 }
341
342 uapi.pmu_config.cycle_count = cycleCounterEnable;
343
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200344 fd = network->ioctl(ETHOSU_IOCTL_INFERENCE_CREATE, static_cast<void *>(&uapi));
345}
346
Per Åstrand2354d3e2020-10-24 20:17:10 +0200347std::vector<uint32_t> Inference::initializeCounterConfig() {
348 return std::vector<uint32_t>(ETHOSU_PMU_EVENT_MAX, 0);
349}
350
351uint32_t Inference::getMaxPmuEventCounters() {
352 return ETHOSU_PMU_EVENT_MAX;
353}
354
355int Inference::wait(int timeoutSec) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200356 pollfd pfd;
357
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200358 pfd.fd = fd;
359 pfd.events = POLLIN | POLLERR;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200360 pfd.revents = 0;
361
362 int ret = ::poll(&pfd, 1, timeoutSec * 1000);
363
364 cout << "Poll. ret=" << ret << ", revents=" << pfd.revents << endl;
Per Åstrand2354d3e2020-10-24 20:17:10 +0200365
366 return ret;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200367}
368
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200369bool Inference::failed() {
Per Åstrand2354d3e2020-10-24 20:17:10 +0200370 ethosu_uapi_result_status uapi;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200371
Per Åstrand2354d3e2020-10-24 20:17:10 +0200372 eioctl(fd, ETHOSU_IOCTL_INFERENCE_STATUS, static_cast<void *>(&uapi));
373
374 return uapi.status != ETHOSU_UAPI_STATUS_OK;
375}
376
377const std::vector<uint32_t> Inference::getPmuCounters() {
378 ethosu_uapi_result_status uapi;
379 std::vector<uint32_t> counterValues = std::vector<uint32_t>(ETHOSU_PMU_EVENT_MAX, 0);
380
381 eioctl(fd, ETHOSU_IOCTL_INFERENCE_STATUS, static_cast<void *>(&uapi));
382
383 for (int i = 0; i < ETHOSU_PMU_EVENT_MAX; i++) {
384 if (uapi.pmu_config.events[i]) {
385 counterValues.at(i) = uapi.pmu_count.events[i];
386 }
387 }
388
389 return counterValues;
390}
391
392uint64_t Inference::getCycleCounter() {
393 ethosu_uapi_result_status uapi;
394
395 eioctl(fd, ETHOSU_IOCTL_INFERENCE_STATUS, static_cast<void *>(&uapi));
396
397 return uapi.pmu_count.cycle_count;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200398}
399
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200400int Inference::getFd() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200401 return fd;
402}
403
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200404shared_ptr<Network> Inference::getNetwork() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200405 return network;
406}
407
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200408vector<shared_ptr<Buffer>> &Inference::getIfmBuffers() {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200409 return ifmBuffers;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200410}
411
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200412vector<shared_ptr<Buffer>> &Inference::getOfmBuffers() {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200413 return ofmBuffers;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200414}
415
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200416} // namespace EthosU