blob: 026242930c2a5275c7e69cb14ece69fe3fed58c2 [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
Per Åstrandec3f2b02021-06-09 10:43:38 +020036namespace EthosU {
37__attribute__((weak)) int 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
Per Åstrandec3f2b02021-06-09 10:43:38 +020046__attribute__((weak)) int eopen(const char *pathname, int flags) {
47 int fd = ::open(pathname, flags);
48
49 if (fd < 0) {
50 throw Exception("Failed to open device");
51 }
52
53 return fd;
54}
55
56__attribute__((weak)) int epoll(struct pollfd *fds, nfds_t nfds, int timeout) {
57 return ::poll(fds, nfds, timeout);
58}
59
60__attribute__((weak)) int eclose(int fd) {
61 return ::close(fd);
62}
63__attribute((weak)) void *emmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) {
64 return ::mmap(addr, length, prot, flags, fd, offset);
65}
66
67__attribute__((weak)) int emunmap(void *addr, size_t length) {
68 return ::munmap(addr, length);
69}
70
71} // namespace EthosU
72
Kristofer Jonssonb74492c2020-09-10 13:26:01 +020073/****************************************************************************
74 * TFL micro helpers
75 ****************************************************************************/
Per Åstrandec3f2b02021-06-09 10:43:38 +020076namespace {
Kristofer Jonsson79689c52020-10-16 14:42:19 +020077size_t getShapeSize(const flatbuffers::Vector<int32_t> *shape) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +020078 size_t size = 1;
Kristofer Jonsson79689c52020-10-16 14:42:19 +020079
Jonny Svärd2c017132021-04-12 15:56:44 +020080 if (shape == nullptr) {
81 throw EthosU::Exception("getShapeSize(): nullptr arg");
82 }
83
Kristofer Jonsson79689c52020-10-16 14:42:19 +020084 for (auto it = shape->begin(); it != shape->end(); ++it) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +020085 size *= *it;
86 }
87
88 return size;
89}
90
Kristofer Jonsson5e632c22020-11-25 10:58:38 +010091size_t getTensorTypeSize(const enum tflite::TensorType type) {
92 switch (type) {
93 case tflite::TensorType::TensorType_UINT8:
94 case tflite::TensorType::TensorType_INT8:
95 return 1;
96 case tflite::TensorType::TensorType_INT16:
97 return 2;
Henrik Hoglind031f4c12021-03-25 08:32:23 +010098 case tflite::TensorType::TensorType_FLOAT32:
99 return 4;
Kristofer Jonsson5e632c22020-11-25 10:58:38 +0100100 default:
101 throw EthosU::Exception("Unsupported tensor type");
102 }
103}
104
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200105vector<size_t> getSubGraphDims(const tflite::SubGraph *subgraph, const flatbuffers::Vector<int32_t> *tensorMap) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200106 vector<size_t> dims;
107
Jonny Svärd2c017132021-04-12 15:56:44 +0200108 if (subgraph == nullptr || tensorMap == nullptr) {
109 throw EthosU::Exception("getSubGraphDims(): nullptr arg(s)");
110 }
111
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200112 for (auto index = tensorMap->begin(); index != tensorMap->end(); ++index) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200113 auto tensor = subgraph->tensors()->Get(*index);
114 size_t size = getShapeSize(tensor->shape());
Kristofer Jonsson5e632c22020-11-25 10:58:38 +0100115 size *= getTensorTypeSize(tensor->type());
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200116
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200117 if (size > 0) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200118 dims.push_back(size);
119 }
120 }
121
122 return dims;
123}
124
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200125} // namespace
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200126
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200127namespace EthosU {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200128
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200129/****************************************************************************
130 * Exception
131 ****************************************************************************/
132
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200133Exception::Exception(const char *msg) : msg(msg) {}
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200134
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200135Exception::~Exception() throw() {}
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200136
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200137const char *Exception::what() const throw() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200138 return msg.c_str();
139}
140
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200141/****************************************************************************
Davide Grohmann35ce6c82021-06-01 15:03:51 +0200142 * Semantic Version
143 ****************************************************************************/
144
145bool SemanticVersion::operator==(const SemanticVersion &other) {
146 return other.major == major && other.minor == minor && other.patch == patch;
147}
148
149bool SemanticVersion::operator<(const SemanticVersion &other) {
150 if (other.major > major)
151 return true;
152 if (other.minor > minor)
153 return true;
154 return other.patch > patch;
155}
156
157bool SemanticVersion::operator<=(const SemanticVersion &other) {
158 return *this < other || *this == other;
159}
160
161bool SemanticVersion::operator!=(const SemanticVersion &other) {
162 return !(*this == other);
163}
164
165bool SemanticVersion::operator>(const SemanticVersion &other) {
166 return !(*this <= other);
167}
168
169bool SemanticVersion::operator>=(const SemanticVersion &other) {
170 return !(*this < other);
171}
172
173ostream &operator<<(ostream &out, const SemanticVersion &v) {
174 return out << "{ major=" << unsigned(v.major) << ", minor=" << unsigned(v.minor) << ", patch=" << unsigned(v.patch)
175 << " }";
176}
177
178/****************************************************************************
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200179 * Device
180 ****************************************************************************/
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200181Device::Device(const char *device) {
Per Åstrandec3f2b02021-06-09 10:43:38 +0200182 fd = eopen(device, O_RDWR | O_NONBLOCK);
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200183}
184
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200185Device::~Device() {
Per Åstrandec3f2b02021-06-09 10:43:38 +0200186 eclose(fd);
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200187}
188
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200189int Device::ioctl(unsigned long cmd, void *data) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200190 return eioctl(fd, cmd, data);
191}
192
Davide Grohmann35ce6c82021-06-01 15:03:51 +0200193Capabilities Device::capabilities() {
194 ethosu_uapi_device_capabilities uapi;
195 (void)eioctl(fd, ETHOSU_IOCTL_CAPABILITIES_REQ, static_cast<void *>(&uapi));
196
197 Capabilities capabilities(
198 HardwareId(uapi.hw_id.version_status,
199 SemanticVersion(uapi.hw_id.version_major, uapi.hw_id.version_minor),
200 SemanticVersion(uapi.hw_id.product_major),
201 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 +0200202 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 +0200203 SemanticVersion(uapi.driver_major_rev, uapi.driver_minor_rev, uapi.driver_patch_rev));
204 return capabilities;
205}
206
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200207/****************************************************************************
208 * Buffer
209 ****************************************************************************/
210
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200211Buffer::Buffer(Device &device, const size_t capacity) : fd(-1), dataPtr(nullptr), dataCapacity(capacity) {
212 ethosu_uapi_buffer_create uapi = {static_cast<uint32_t>(dataCapacity)};
213 fd = device.ioctl(ETHOSU_IOCTL_BUFFER_CREATE, static_cast<void *>(&uapi));
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200214
Per Åstrandec3f2b02021-06-09 10:43:38 +0200215 void *d = emmap(nullptr, dataCapacity, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200216 if (d == MAP_FAILED) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200217 throw Exception("MMap failed");
218 }
219
220 dataPtr = reinterpret_cast<char *>(d);
221}
222
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200223Buffer::~Buffer() {
Per Åstrandec3f2b02021-06-09 10:43:38 +0200224 emunmap(dataPtr, dataCapacity);
225 eclose(fd);
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200226}
227
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200228size_t Buffer::capacity() const {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200229 return dataCapacity;
230}
231
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200232void Buffer::clear() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200233 resize(0, 0);
234}
235
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200236char *Buffer::data() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200237 return dataPtr + offset();
238}
239
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200240void Buffer::resize(size_t size, size_t offset) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200241 ethosu_uapi_buffer uapi;
242 uapi.offset = offset;
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200243 uapi.size = size;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200244 eioctl(fd, ETHOSU_IOCTL_BUFFER_SET, static_cast<void *>(&uapi));
245}
246
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200247size_t Buffer::offset() const {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200248 ethosu_uapi_buffer uapi;
249 eioctl(fd, ETHOSU_IOCTL_BUFFER_GET, static_cast<void *>(&uapi));
250 return uapi.offset;
251}
252
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200253size_t Buffer::size() const {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200254 ethosu_uapi_buffer uapi;
255 eioctl(fd, ETHOSU_IOCTL_BUFFER_GET, static_cast<void *>(&uapi));
256 return uapi.size;
257}
258
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200259int Buffer::getFd() const {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200260 return fd;
261}
262
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200263/****************************************************************************
264 * Network
265 ****************************************************************************/
266
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200267Network::Network(Device &device, shared_ptr<Buffer> &buffer) : fd(-1), buffer(buffer) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200268 // Create buffer handle
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200269 ethosu_uapi_network_create uapi;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200270 uapi.fd = buffer->getFd();
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200271 fd = device.ioctl(ETHOSU_IOCTL_NETWORK_CREATE, static_cast<void *>(&uapi));
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200272
273 // Create model handle
274 const tflite::Model *model = tflite::GetModel(reinterpret_cast<void *>(buffer->data()));
275
Jonny Svärd2c017132021-04-12 15:56:44 +0200276 if (model->subgraphs() == nullptr) {
277 throw EthosU::Exception("Failed to get subgraphs: nullptr");
278 }
279
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200280 // Get input dimensions for first subgraph
281 auto *subgraph = *model->subgraphs()->begin();
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200282 ifmDims = getSubGraphDims(subgraph, subgraph->inputs());
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200283
284 // Get output dimensions for last subgraph
285 subgraph = *model->subgraphs()->rbegin();
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200286 ofmDims = getSubGraphDims(subgraph, subgraph->outputs());
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200287}
288
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200289Network::~Network() {
Per Åstrandec3f2b02021-06-09 10:43:38 +0200290 eclose(fd);
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200291}
292
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200293int Network::ioctl(unsigned long cmd, void *data) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200294 return eioctl(fd, cmd, data);
295}
296
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200297shared_ptr<Buffer> Network::getBuffer() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200298 return buffer;
299}
300
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200301const std::vector<size_t> &Network::getIfmDims() const {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200302 return ifmDims;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200303}
304
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200305size_t Network::getIfmSize() const {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200306 size_t size = 0;
307
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200308 for (auto s : ifmDims) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200309 size += s;
310 }
311
312 return size;
313}
314
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200315const std::vector<size_t> &Network::getOfmDims() const {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200316 return ofmDims;
317}
318
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200319size_t Network::getOfmSize() const {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200320 size_t size = 0;
321
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200322 for (auto s : ofmDims) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200323 size += s;
324 }
325
326 return size;
327}
328
329/****************************************************************************
330 * Inference
331 ****************************************************************************/
332
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200333Inference::~Inference() {
Per Åstrandec3f2b02021-06-09 10:43:38 +0200334 eclose(fd);
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200335}
336
Per Åstrand2354d3e2020-10-24 20:17:10 +0200337void Inference::create(std::vector<uint32_t> &counterConfigs, bool cycleCounterEnable = false) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200338 ethosu_uapi_inference_create uapi;
339
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200340 if (ifmBuffers.size() > ETHOSU_FD_MAX) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200341 throw Exception("IFM buffer overflow");
342 }
343
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200344 if (ofmBuffers.size() > ETHOSU_FD_MAX) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200345 throw Exception("OFM buffer overflow");
346 }
347
Per Åstrand2354d3e2020-10-24 20:17:10 +0200348 if (counterConfigs.size() != ETHOSU_PMU_EVENT_MAX) {
349 throw Exception("Wrong size of counter configurations");
350 }
351
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200352 uapi.ifm_count = 0;
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200353 for (auto it : ifmBuffers) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200354 uapi.ifm_fd[uapi.ifm_count++] = it->getFd();
355 }
356
357 uapi.ofm_count = 0;
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200358 for (auto it : ofmBuffers) {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200359 uapi.ofm_fd[uapi.ofm_count++] = it->getFd();
360 }
361
Per Åstrand2354d3e2020-10-24 20:17:10 +0200362 for (int i = 0; i < ETHOSU_PMU_EVENT_MAX; i++) {
363 uapi.pmu_config.events[i] = counterConfigs[i];
364 }
365
366 uapi.pmu_config.cycle_count = cycleCounterEnable;
367
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200368 fd = network->ioctl(ETHOSU_IOCTL_INFERENCE_CREATE, static_cast<void *>(&uapi));
369}
370
Per Åstrand2354d3e2020-10-24 20:17:10 +0200371std::vector<uint32_t> Inference::initializeCounterConfig() {
372 return std::vector<uint32_t>(ETHOSU_PMU_EVENT_MAX, 0);
373}
374
375uint32_t Inference::getMaxPmuEventCounters() {
376 return ETHOSU_PMU_EVENT_MAX;
377}
378
379int Inference::wait(int timeoutSec) {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200380 pollfd pfd;
381
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200382 pfd.fd = fd;
383 pfd.events = POLLIN | POLLERR;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200384 pfd.revents = 0;
385
Per Åstrandec3f2b02021-06-09 10:43:38 +0200386 int ret = epoll(&pfd, 1, timeoutSec * 1000);
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200387
388 cout << "Poll. ret=" << ret << ", revents=" << pfd.revents << endl;
Per Åstrand2354d3e2020-10-24 20:17:10 +0200389
390 return ret;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200391}
392
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200393bool Inference::failed() {
Per Åstrand2354d3e2020-10-24 20:17:10 +0200394 ethosu_uapi_result_status uapi;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200395
Per Åstrand2354d3e2020-10-24 20:17:10 +0200396 eioctl(fd, ETHOSU_IOCTL_INFERENCE_STATUS, static_cast<void *>(&uapi));
397
398 return uapi.status != ETHOSU_UAPI_STATUS_OK;
399}
400
401const std::vector<uint32_t> Inference::getPmuCounters() {
402 ethosu_uapi_result_status uapi;
403 std::vector<uint32_t> counterValues = std::vector<uint32_t>(ETHOSU_PMU_EVENT_MAX, 0);
404
405 eioctl(fd, ETHOSU_IOCTL_INFERENCE_STATUS, static_cast<void *>(&uapi));
406
407 for (int i = 0; i < ETHOSU_PMU_EVENT_MAX; i++) {
408 if (uapi.pmu_config.events[i]) {
409 counterValues.at(i) = uapi.pmu_count.events[i];
410 }
411 }
412
413 return counterValues;
414}
415
416uint64_t Inference::getCycleCounter() {
417 ethosu_uapi_result_status uapi;
418
419 eioctl(fd, ETHOSU_IOCTL_INFERENCE_STATUS, static_cast<void *>(&uapi));
420
421 return uapi.pmu_count.cycle_count;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200422}
423
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200424int Inference::getFd() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200425 return fd;
426}
427
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200428shared_ptr<Network> Inference::getNetwork() {
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200429 return network;
430}
431
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200432vector<shared_ptr<Buffer>> &Inference::getIfmBuffers() {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200433 return ifmBuffers;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200434}
435
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200436vector<shared_ptr<Buffer>> &Inference::getOfmBuffers() {
Kristofer Jonssonb74492c2020-09-10 13:26:01 +0200437 return ofmBuffers;
Kristofer Jonsson116a6352020-08-20 17:25:23 +0200438}
439
Kristofer Jonsson79689c52020-10-16 14:42:19 +0200440} // namespace EthosU