blob: ea1f7f41cb91ada2ae2523dd556b7bf358ade277 [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)),
179 HardwareConfiguration(uapi.hw_cfg.macs_per_cc,
180 uapi.hw_cfg.cmd_stream_version,
181 uapi.hw_cfg.shram_size,
182 bool(uapi.hw_cfg.custom_dma)),
183 SemanticVersion(uapi.driver_major_rev, uapi.driver_minor_rev, uapi.driver_patch_rev));
184 return capabilities;
185}
186
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200187/****************************************************************************
188 * Buffer
189 ****************************************************************************/
190
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200191Buffer::Buffer(Device &device, const size_t capacity) : fd(-1), dataPtr(nullptr), dataCapacity(capacity) {
192 ethosu_uapi_buffer_create uapi = {static_cast<uint32_t>(dataCapacity)};
193 fd = device.ioctl(ETHOSU_IOCTL_BUFFER_CREATE, static_cast<void *>(&uapi));
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200194
195 void *d = ::mmap(nullptr, dataCapacity, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200196 if (d == MAP_FAILED) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200197 throw Exception("MMap failed");
198 }
199
200 dataPtr = reinterpret_cast<char *>(d);
201}
202
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200203Buffer::~Buffer() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200204 close(fd);
205}
206
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200207size_t Buffer::capacity() const {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200208 return dataCapacity;
209}
210
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200211void Buffer::clear() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200212 resize(0, 0);
213}
214
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200215char *Buffer::data() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200216 return dataPtr + offset();
217}
218
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200219void Buffer::resize(size_t size, size_t offset) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200220 ethosu_uapi_buffer uapi;
221 uapi.offset = offset;
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200222 uapi.size = size;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200223 eioctl(fd, ETHOSU_IOCTL_BUFFER_SET, static_cast<void *>(&uapi));
224}
225
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200226size_t Buffer::offset() const {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200227 ethosu_uapi_buffer uapi;
228 eioctl(fd, ETHOSU_IOCTL_BUFFER_GET, static_cast<void *>(&uapi));
229 return uapi.offset;
230}
231
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200232size_t Buffer::size() const {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200233 ethosu_uapi_buffer uapi;
234 eioctl(fd, ETHOSU_IOCTL_BUFFER_GET, static_cast<void *>(&uapi));
235 return uapi.size;
236}
237
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200238int Buffer::getFd() const {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200239 return fd;
240}
241
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200242/****************************************************************************
243 * Network
244 ****************************************************************************/
245
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200246Network::Network(Device &device, shared_ptr<Buffer> &buffer) : fd(-1), buffer(buffer) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200247 // Create buffer handle
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200248 ethosu_uapi_network_create uapi;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200249 uapi.fd = buffer->getFd();
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200250 fd = device.ioctl(ETHOSU_IOCTL_NETWORK_CREATE, static_cast<void *>(&uapi));
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200251
252 // Create model handle
253 const tflite::Model *model = tflite::GetModel(reinterpret_cast<void *>(buffer->data()));
254
Jonny Svärd2c017132021-04-12 15:56:44 +0200255 if (model->subgraphs() == nullptr) {
256 throw EthosU::Exception("Failed to get subgraphs: nullptr");
257 }
258
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200259 // Get input dimensions for first subgraph
260 auto *subgraph = *model->subgraphs()->begin();
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200261 ifmDims = getSubGraphDims(subgraph, subgraph->inputs());
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200262
263 // Get output dimensions for last subgraph
264 subgraph = *model->subgraphs()->rbegin();
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200265 ofmDims = getSubGraphDims(subgraph, subgraph->outputs());
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200266}
267
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200268Network::~Network() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200269 close(fd);
270}
271
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200272int Network::ioctl(unsigned long cmd, void *data) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200273 return eioctl(fd, cmd, data);
274}
275
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200276shared_ptr<Buffer> Network::getBuffer() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200277 return buffer;
278}
279
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200280const std::vector<size_t> &Network::getIfmDims() const {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200281 return ifmDims;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200282}
283
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200284size_t Network::getIfmSize() const {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200285 size_t size = 0;
286
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200287 for (auto s : ifmDims) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200288 size += s;
289 }
290
291 return size;
292}
293
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200294const std::vector<size_t> &Network::getOfmDims() const {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200295 return ofmDims;
296}
297
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200298size_t Network::getOfmSize() const {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200299 size_t size = 0;
300
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200301 for (auto s : ofmDims) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200302 size += s;
303 }
304
305 return size;
306}
307
308/****************************************************************************
309 * Inference
310 ****************************************************************************/
311
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200312Inference::~Inference() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200313 close(fd);
314}
315
Per Åstrand2354d3e2020-10-24 20:17:10 +0200316void Inference::create(std::vector<uint32_t> &counterConfigs, bool cycleCounterEnable = false) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200317 ethosu_uapi_inference_create uapi;
318
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200319 if (ifmBuffers.size() > ETHOSU_FD_MAX) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200320 throw Exception("IFM buffer overflow");
321 }
322
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200323 if (ofmBuffers.size() > ETHOSU_FD_MAX) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200324 throw Exception("OFM buffer overflow");
325 }
326
Per Åstrand2354d3e2020-10-24 20:17:10 +0200327 if (counterConfigs.size() != ETHOSU_PMU_EVENT_MAX) {
328 throw Exception("Wrong size of counter configurations");
329 }
330
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200331 uapi.ifm_count = 0;
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200332 for (auto it : ifmBuffers) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200333 uapi.ifm_fd[uapi.ifm_count++] = it->getFd();
334 }
335
336 uapi.ofm_count = 0;
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200337 for (auto it : ofmBuffers) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200338 uapi.ofm_fd[uapi.ofm_count++] = it->getFd();
339 }
340
Per Åstrand2354d3e2020-10-24 20:17:10 +0200341 for (int i = 0; i < ETHOSU_PMU_EVENT_MAX; i++) {
342 uapi.pmu_config.events[i] = counterConfigs[i];
343 }
344
345 uapi.pmu_config.cycle_count = cycleCounterEnable;
346
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200347 fd = network->ioctl(ETHOSU_IOCTL_INFERENCE_CREATE, static_cast<void *>(&uapi));
348}
349
Per Åstrand2354d3e2020-10-24 20:17:10 +0200350std::vector<uint32_t> Inference::initializeCounterConfig() {
351 return std::vector<uint32_t>(ETHOSU_PMU_EVENT_MAX, 0);
352}
353
354uint32_t Inference::getMaxPmuEventCounters() {
355 return ETHOSU_PMU_EVENT_MAX;
356}
357
358int Inference::wait(int timeoutSec) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200359 pollfd pfd;
360
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200361 pfd.fd = fd;
362 pfd.events = POLLIN | POLLERR;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200363 pfd.revents = 0;
364
365 int ret = ::poll(&pfd, 1, timeoutSec * 1000);
366
367 cout << "Poll. ret=" << ret << ", revents=" << pfd.revents << endl;
Per Åstrand2354d3e2020-10-24 20:17:10 +0200368
369 return ret;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200370}
371
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200372bool Inference::failed() {
Per Åstrand2354d3e2020-10-24 20:17:10 +0200373 ethosu_uapi_result_status uapi;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200374
Per Åstrand2354d3e2020-10-24 20:17:10 +0200375 eioctl(fd, ETHOSU_IOCTL_INFERENCE_STATUS, static_cast<void *>(&uapi));
376
377 return uapi.status != ETHOSU_UAPI_STATUS_OK;
378}
379
380const std::vector<uint32_t> Inference::getPmuCounters() {
381 ethosu_uapi_result_status uapi;
382 std::vector<uint32_t> counterValues = std::vector<uint32_t>(ETHOSU_PMU_EVENT_MAX, 0);
383
384 eioctl(fd, ETHOSU_IOCTL_INFERENCE_STATUS, static_cast<void *>(&uapi));
385
386 for (int i = 0; i < ETHOSU_PMU_EVENT_MAX; i++) {
387 if (uapi.pmu_config.events[i]) {
388 counterValues.at(i) = uapi.pmu_count.events[i];
389 }
390 }
391
392 return counterValues;
393}
394
395uint64_t Inference::getCycleCounter() {
396 ethosu_uapi_result_status uapi;
397
398 eioctl(fd, ETHOSU_IOCTL_INFERENCE_STATUS, static_cast<void *>(&uapi));
399
400 return uapi.pmu_count.cycle_count;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200401}
402
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200403int Inference::getFd() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200404 return fd;
405}
406
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200407shared_ptr<Network> Inference::getNetwork() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200408 return network;
409}
410
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200411vector<shared_ptr<Buffer>> &Inference::getIfmBuffers() {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200412 return ifmBuffers;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200413}
414
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200415vector<shared_ptr<Buffer>> &Inference::getOfmBuffers() {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200416 return ofmBuffers;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200417}
418
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200419} // namespace EthosU