1 /*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define LOG_TAG "Memory"
18
19 #include "Memory.h"
20
21 #include <CpuExecutor.h>
22 #include <LegacyUtils.h>
23 #include <android-base/scopeguard.h>
24 #include <nnapi/IBurst.h>
25 #include <nnapi/SharedMemory.h>
26 #include <nnapi/TypeUtils.h>
27 #include <nnapi/Types.h>
28 #include <nnapi/Validation.h>
29
30 #include <algorithm>
31 #include <memory>
32 #include <set>
33 #include <tuple>
34 #include <utility>
35 #include <vector>
36
37 #include "CompilationBuilder.h"
38 #include "Manager.h"
39 #include "TypeManager.h"
40
41 #ifdef __ANDROID__
42 #include <android/hardware_buffer.h>
43 #endif // __ANDROID__
44
45 namespace android {
46 namespace nn {
47 namespace {
48
49 // The validator for a client-managed single-dimensional memory pool with a known size.
50 // The memory may be used for request inputs, request outputs, or model constants.
51 class SizedMemoryValidator : public MemoryValidatorBase {
52 public:
SizedMemoryValidator(uint32_t size)53 explicit SizedMemoryValidator(uint32_t size) : kSize(size) {}
54
validate(const CompilationBuilder *,IOType,uint32_t,const ANeuralNetworksOperandType *,uint32_t offset,uint32_t length) const55 bool validate(const CompilationBuilder*, IOType, uint32_t, const ANeuralNetworksOperandType*,
56 uint32_t offset, uint32_t length) const override {
57 NN_RET_CHECK(offset + length <= kSize) << "request size larger than the memory size.";
58 NN_RET_CHECK(offset != 0 || length != 0) << "memory size cannot be implied.";
59 return true;
60 }
61
getMetadata() const62 Metadata getMetadata() const override { return {.logicalSize = kSize}; }
updateMetadata(const Metadata & metadata)63 bool updateMetadata(const Metadata& metadata) override {
64 return metadata.logicalSize == 0 || metadata.logicalSize == kSize;
65 }
66
67 private:
68 const uint32_t kSize;
69 };
70
71 // The validator for an AHardwareBuffer with Non-BLOB format.
72 // We require the memory only used for request inputs or request outputs,
73 // with both offset and length set to zero.
74 class AHardwareBufferNonBlobValidator : public MemoryValidatorBase {
75 public:
76 AHardwareBufferNonBlobValidator() = default;
77
validate(const CompilationBuilder * compilation,IOType,uint32_t,const ANeuralNetworksOperandType *,uint32_t offset,uint32_t length) const78 bool validate(const CompilationBuilder* compilation, IOType, uint32_t,
79 const ANeuralNetworksOperandType*, uint32_t offset,
80 uint32_t length) const override {
81 NN_RET_CHECK(compilation != nullptr)
82 << "cannot use Non-BLOB AHardwareBuffer as model constant";
83 NN_RET_CHECK(offset == 0 && length == 0)
84 << "non-zero offset (" << offset << ") and/or length (" << length
85 << ") for Non-BLOB format AHardwareBuffer.";
86 return true;
87 }
88
getMetadata() const89 Metadata getMetadata() const override { return {}; }
updateMetadata(const Metadata &)90 bool updateMetadata(const Metadata&) override { return true; }
91 };
92
93 // The validator for a memory created from ANNMemory_createFromDesc.
94 // We require the memory only used as one of the pre-specified roles,
95 // with both offset and length set to zero.
96 class DeviceMemoryValidator : public MemoryValidatorBase {
97 public:
DeviceMemoryValidator(std::set<CompilationRole> roles,Operand operand,std::vector<uint32_t> dimensions)98 DeviceMemoryValidator(std::set<CompilationRole> roles, Operand operand,
99 std::vector<uint32_t> dimensions)
100 : kCompilationRoles(std::move(roles)),
101 kOperand(std::move(operand)),
102 kInitialDimensions(std::move(dimensions)),
103 mUpdatedDimensions(kInitialDimensions) {}
104
validate(const CompilationBuilder * compilation,IOType ioType,uint32_t index,const ANeuralNetworksOperandType * type,uint32_t offset,uint32_t length) const105 bool validate(const CompilationBuilder* compilation, IOType ioType, uint32_t index,
106 const ANeuralNetworksOperandType* type, uint32_t offset,
107 uint32_t length) const override {
108 NN_RET_CHECK(kCompilationRoles.count({compilation, ioType, index}) > 0)
109 << "invalid compilation role.";
110 NN_RET_CHECK(offset == 0 && length == 0)
111 << "non-zero offset and/or length for driver-allocated memory.";
112 if (type) {
113 const bool isTensor = TypeManager::get()->isTensorType(kOperand.type);
114 NN_RET_CHECK(isTensor || type->dimensionCount == 0)
115 << "invalid dimensions for scalar memory.";
116 std::vector<uint32_t> dimensions(type->dimensions,
117 type->dimensions + type->dimensionCount);
118 // We only check against kInitialDimensions here.
119 // For input memories, mUpdatedDimensions will be checked in validateInputDimensions
120 // at the beginning of a computation.
121 const auto combined = combineDimensions(dimensions, kInitialDimensions);
122 NN_RET_CHECK(combined.has_value())
123 << "incompatible dimensions between request and memory. (request: "
124 << toString(dimensions) << ", memory: " << toString(kInitialDimensions) << ")";
125 }
126 return true;
127 }
128
validateInputDimensions(const std::vector<uint32_t> & dimensions) const129 bool validateInputDimensions(const std::vector<uint32_t>& dimensions) const override {
130 NN_RET_CHECK(mInitialized) << "using an uninitialized memory as input";
131 NN_RET_CHECK(dimensions == mUpdatedDimensions)
132 << "incompatible input dimensions between request and memory. (request: "
133 << toString(dimensions) << ", memory: " << toString(mUpdatedDimensions) << ")";
134 return true;
135 }
136
getMetadata() const137 Metadata getMetadata() const override {
138 return {.logicalSize = TypeManager::get()->getSizeOfData(kOperand.type, mUpdatedDimensions),
139 .dimensions = mUpdatedDimensions,
140 .operand = kOperand};
141 }
142
updateMetadata(const Metadata & metadata)143 bool updateMetadata(const Metadata& metadata) override {
144 NN_RET_CHECK(!metadata.operand.has_value() ||
145 (metadata.operand->type == kOperand.type &&
146 metadata.operand->scale == kOperand.scale &&
147 metadata.operand->zeroPoint == kOperand.zeroPoint &&
148 metadata.operand->extraParams == kOperand.extraParams));
149
150 NN_RET_CHECK(metadata.dimensions.empty() ||
151 TypeManager::get()->isTensorType(kOperand.type));
152 auto combined = combineDimensions(metadata.dimensions, kInitialDimensions);
153 NN_RET_CHECK(combined.has_value());
154 NN_RET_CHECK(metadata.logicalSize == 0 ||
155 metadata.logicalSize ==
156 TypeManager::get()->getSizeOfData(kOperand.type, combined.value()));
157 mUpdatedDimensions = std::move(combined.value());
158 return true;
159 }
160
createdWithUnknownShape() const161 bool createdWithUnknownShape() const override {
162 return TypeManager::get()->getSizeOfData(kOperand.type, kInitialDimensions) == 0;
163 }
164
setInitialized(bool initialized)165 void setInitialized(bool initialized) override { mInitialized = initialized; }
isInitialized() const166 bool isInitialized() const override { return mInitialized; }
167
168 private:
169 const std::set<CompilationRole> kCompilationRoles;
170
171 // Keep track of the data type, scale, zero point, and extra parameters of the target operand.
172 // Other fields will be ignored, including dimensions, lifetime, location, etc.
173 const Operand kOperand;
174
175 // The dimensions of the memory when the memory object is created.
176 // May have unknown dimensions or rank.
177 const std::vector<uint32_t> kInitialDimensions;
178
179 // The updated dimensions after a successful execution or memory copying.
180 std::vector<uint32_t> mUpdatedDimensions;
181
182 bool mInitialized = false;
183 };
184
185 } // namespace
186
RuntimeMemory(SharedMemory memory)187 RuntimeMemory::RuntimeMemory(SharedMemory memory) : kMemory(std::move(memory)) {
188 CHECK(kMemory != nullptr);
189 mValidator = std::make_unique<SizedMemoryValidator>(nn::getSize(kMemory));
190 }
191
RuntimeMemory(SharedMemory memory,std::unique_ptr<MemoryValidatorBase> validator)192 RuntimeMemory::RuntimeMemory(SharedMemory memory, std::unique_ptr<MemoryValidatorBase> validator)
193 : kMemory(std::move(memory)), mValidator(std::move(validator)) {
194 CHECK(kMemory != nullptr);
195 }
196
RuntimeMemory(SharedBuffer buffer)197 RuntimeMemory::RuntimeMemory(SharedBuffer buffer) : kBuffer(std::move(buffer)) {}
198
getMemoryPool() const199 Request::MemoryPool RuntimeMemory::getMemoryPool() const {
200 if (kBuffer != nullptr) {
201 return kBuffer->getToken();
202 }
203 return kMemory;
204 }
205
getRunTimePoolInfo() const206 std::optional<RunTimePoolInfo> RuntimeMemory::getRunTimePoolInfo() const {
207 std::lock_guard<std::mutex> guard(mMutex);
208 if (!mHasCachedRunTimePoolInfo) {
209 mCachedRunTimePoolInfo = RunTimePoolInfo::createFromMemory(kMemory);
210 mHasCachedRunTimePoolInfo = true;
211 }
212 return mCachedRunTimePoolInfo;
213 }
214
hold(const IBurst::OptionalCacheHold & cacheHold) const215 void RuntimeMemory::hold(const IBurst::OptionalCacheHold& cacheHold) const {
216 if (cacheHold != nullptr) {
217 std::lock_guard<std::mutex> guard(mMutex);
218 mHold.insert(cacheHold);
219 }
220 }
221
copyHidlMemories(const std::optional<RunTimePoolInfo> & src,const std::optional<RunTimePoolInfo> & dst)222 static int copyHidlMemories(const std::optional<RunTimePoolInfo>& src,
223 const std::optional<RunTimePoolInfo>& dst) {
224 if (!src.has_value() || !dst.has_value()) {
225 LOG(ERROR) << "ANeuralNetworksMemory_copy -- unable to map memory";
226 return ANEURALNETWORKS_UNMAPPABLE;
227 }
228 if (src->getSize() != dst->getSize()) {
229 LOG(ERROR) << "ANeuralNetworksMemory_copy -- incompatible memory size";
230 return ANEURALNETWORKS_BAD_DATA;
231 }
232 CHECK(src->getBuffer() != nullptr);
233 CHECK(dst->getBuffer() != nullptr);
234 std::copy(src->getBuffer(), src->getBuffer() + src->getSize(), dst->getBuffer());
235 dst->flush();
236 return ANEURALNETWORKS_NO_ERROR;
237 }
238
copyIBufferToMemory(const SharedBuffer & src,const SharedMemory & dst)239 int copyIBufferToMemory(const SharedBuffer& src, const SharedMemory& dst) {
240 const auto ret = src->copyTo(dst);
241 if (!ret.has_value()) {
242 LOG(ERROR) << "ANeuralNetworksMemory_copy failure: " << ret.error().message;
243 return convertErrorStatusToResultCode(ret.error().code);
244 }
245 return ANEURALNETWORKS_NO_ERROR;
246 }
247
copyMemoryToIBuffer(const SharedMemory & src,const SharedBuffer & dst,const std::vector<uint32_t> & dimensions)248 int copyMemoryToIBuffer(const SharedMemory& src, const SharedBuffer& dst,
249 const std::vector<uint32_t>& dimensions) {
250 const auto ret = dst->copyFrom(src, dimensions);
251 if (!ret.has_value()) {
252 LOG(ERROR) << "ANeuralNetworksMemory_copy failure: " << ret.error().message;
253 return convertErrorStatusToResultCode(ret.error().code);
254 }
255 return ANEURALNETWORKS_NO_ERROR;
256 }
257
copyIBuffers(const SharedBuffer & src,const SharedBuffer & dst,const MemoryValidatorBase::Metadata & srcMetadata)258 static int copyIBuffers(const SharedBuffer& src, const SharedBuffer& dst,
259 const MemoryValidatorBase::Metadata& srcMetadata) {
260 #ifdef __ANDROID__
261 const auto [n, runtimeMemory] = MemoryRuntimeAHWB::create(srcMetadata.logicalSize);
262 #else // __ANDROID__
263 const auto [n, runtimeMemory] = MemoryAshmem::create(srcMetadata.logicalSize);
264 #endif // __ANDROID__
265 NN_RETURN_IF_ERROR(n);
266 const SharedMemory& memory = runtimeMemory->getMemory();
267 if (!validate(memory).ok()) return ANEURALNETWORKS_OUT_OF_MEMORY;
268 NN_RETURN_IF_ERROR(copyIBufferToMemory(src, memory));
269 NN_RETURN_IF_ERROR(copyMemoryToIBuffer(memory, dst, srcMetadata.dimensions));
270 return ANEURALNETWORKS_NO_ERROR;
271 }
272
copyInternal(const RuntimeMemory & src,const RuntimeMemory & dst)273 static int copyInternal(const RuntimeMemory& src, const RuntimeMemory& dst) {
274 if (&src == &dst) return ANEURALNETWORKS_NO_ERROR;
275
276 if (!src.getValidator().isInitialized()) {
277 LOG(ERROR) << "ANeuralNetworksMemory_copy -- uninitialized source memory";
278 return ANEURALNETWORKS_BAD_DATA;
279 }
280
281 const auto srcMetadata = src.getValidator().getMetadata();
282 if (!dst.getValidator().updateMetadata(srcMetadata)) {
283 LOG(ERROR) << "ANeuralNetworksMemory_copy -- incompatible memories";
284 return ANEURALNETWORKS_BAD_DATA;
285 }
286
287 bool srcHasMemory = validate(src.getMemory()).ok();
288 bool dstHasMemory = validate(dst.getMemory()).ok();
289 bool srcHasIBuffer = src.getIBuffer() != nullptr;
290 bool dstHasIBuffer = dst.getIBuffer() != nullptr;
291 if (srcHasIBuffer && dstHasIBuffer) {
292 return copyIBuffers(src.getIBuffer(), dst.getIBuffer(), srcMetadata);
293 } else if (srcHasMemory && dstHasMemory) {
294 return copyHidlMemories(src.getRunTimePoolInfo(), dst.getRunTimePoolInfo());
295 } else if (srcHasMemory && dstHasIBuffer) {
296 return copyMemoryToIBuffer(src.getMemory(), dst.getIBuffer(), srcMetadata.dimensions);
297 } else if (srcHasIBuffer && dstHasMemory) {
298 return copyIBufferToMemory(src.getIBuffer(), dst.getMemory());
299 }
300 return ANEURALNETWORKS_OP_FAILED;
301 }
302
copy(const RuntimeMemory & src,const RuntimeMemory & dst)303 int RuntimeMemory::copy(const RuntimeMemory& src, const RuntimeMemory& dst) {
304 int n = copyInternal(src, dst);
305 dst.getValidator().setInitialized(n == ANEURALNETWORKS_NO_ERROR);
306 return n;
307 }
308
badState(const char * name) const309 bool MemoryBuilder::badState(const char* name) const {
310 if (mFinished) {
311 LOG(ERROR) << "ANeuralNetworksMemoryDesc_" << name << " can't modify after finished";
312 return true;
313 }
314 return false;
315 }
316
addRole(const CompilationBuilder & compilation,IOType ioType,uint32_t index,float prob)317 int MemoryBuilder::addRole(const CompilationBuilder& compilation, IOType ioType, uint32_t index,
318 float prob) {
319 const char* tag = ioType == IOType::INPUT ? "addInputRole" : "addOutputRole";
320 if (badState(tag)) {
321 return ANEURALNETWORKS_BAD_STATE;
322 }
323 if (mRoles.count({&compilation, ioType, index}) > 0) {
324 LOG(ERROR) << "ANeuralNetworksMemoryDesc_" << tag
325 << " -- the same operand is specified twice.";
326 return ANEURALNETWORKS_BAD_DATA;
327 }
328
329 std::vector<std::tuple<const RuntimePreparedModel*, IOType, uint32_t>> roles;
330 auto callback = [&roles](const auto* preparedModel, IOType type, uint32_t index) {
331 roles.emplace_back(preparedModel, type, index);
332 };
333 if (ioType == IOType::INPUT) {
334 if (compilation.forEachStepRoleOfInput(index, callback) != ANEURALNETWORKS_NO_ERROR) {
335 return ANEURALNETWORKS_BAD_DATA;
336 }
337 } else {
338 if (compilation.forEachStepRoleOfOutput(index, callback) != ANEURALNETWORKS_NO_ERROR) {
339 return ANEURALNETWORKS_BAD_DATA;
340 }
341 }
342
343 const ModelBuilder* model = compilation.getModel();
344 CHECK(model != nullptr);
345 Operand operand;
346 if (ioType == IOType::INPUT) {
347 if (index >= model->inputCount()) {
348 LOG(ERROR) << "ANeuralNetworksMemoryDesc_addInputRole -- input index out of range.";
349 return ANEURALNETWORKS_BAD_DATA;
350 }
351 operand = model->getInputOperand(index);
352 } else {
353 if (index >= model->outputCount()) {
354 LOG(ERROR) << "ANeuralNetworksMemoryDesc_addOutputRole -- output index out of range.";
355 return ANEURALNETWORKS_BAD_DATA;
356 }
357 operand = model->getOutputOperand(index);
358 }
359 if (mOperand.has_value()) {
360 if (operand.type != mOperand->type || operand.scale != mOperand->scale ||
361 operand.zeroPoint != mOperand->zeroPoint ||
362 operand.extraParams != mOperand->extraParams) {
363 LOG(ERROR) << "ANeuralNetworksMemoryDesc_" << tag
364 << " -- incompatible operand metadata.";
365 return ANEURALNETWORKS_BAD_DATA;
366 }
367 }
368 if (!TypeManager::get()->isTensorType(operand.type) && !mDesc.dimensions.empty()) {
369 LOG(ERROR) << "ANeuralNetworksMemoryDesc_" << tag << " -- incompatible dimensions.";
370 return ANEURALNETWORKS_BAD_DATA;
371 }
372 auto combined = combineDimensions(mDesc.dimensions, operand.dimensions);
373 if (!combined.has_value()) {
374 LOG(ERROR) << "ANeuralNetworksMemoryDesc_" << tag << " -- incompatible dimensions.";
375 return ANEURALNETWORKS_BAD_DATA;
376 }
377
378 if (prob > 1.0f || prob <= 0.0f) {
379 LOG(ERROR) << "ANeuralNetworksMemoryDesc_" << tag << " -- invalid frequency " << prob;
380 return ANEURALNETWORKS_BAD_DATA;
381 }
382
383 mRoles.emplace(&compilation, ioType, index);
384 for (const auto& [preparedModel, type, ind] : roles) {
385 uint32_t modelIndex = mDesc.preparedModels.add(preparedModel);
386 BufferRole role = {.modelIndex = modelIndex, .ioIndex = ind, .probability = prob};
387 if (type == IOType::INPUT) {
388 mDesc.inputRoles.push_back(role);
389 } else {
390 mDesc.outputRoles.push_back(role);
391 }
392 }
393 mOperand = std::move(operand);
394 mDesc.dimensions = std::move(combined.value());
395 return ANEURALNETWORKS_NO_ERROR;
396 }
397
setDimensions(const std::vector<uint32_t> & dimensions)398 int MemoryBuilder::setDimensions(const std::vector<uint32_t>& dimensions) {
399 if (badState("setDimensions")) return ANEURALNETWORKS_BAD_STATE;
400 if (mOperand.has_value() && !TypeManager::get()->isTensorType(mOperand->type) &&
401 !dimensions.empty()) {
402 LOG(ERROR) << "ANeuralNetworksMemoryDesc_setDimensions -- incompatible dimensions for "
403 "scalars.";
404 return ANEURALNETWORKS_BAD_DATA;
405 }
406 auto combined = combineDimensions(mDesc.dimensions, dimensions);
407 if (!combined.has_value()) {
408 LOG(ERROR) << "ANeuralNetworksMemoryDesc_setDimensions -- incompatible dimensions.";
409 return ANEURALNETWORKS_BAD_DATA;
410 }
411 mDesc.dimensions = std::move(combined.value());
412 return ANEURALNETWORKS_NO_ERROR;
413 }
414
logMemoryDescriptorToInfo(const MemoryDescriptor & desc,const Operand & operand)415 static void logMemoryDescriptorToInfo(const MemoryDescriptor& desc, const Operand& operand) {
416 LOG(INFO) << "MemoryDescriptor start";
417 LOG(INFO) << " Data type: " << operand.type;
418 LOG(INFO) << " Scale: " << operand.scale;
419 LOG(INFO) << " Zero point: " << operand.zeroPoint;
420 LOG(INFO) << " Extra params: " << operand.extraParams;
421 LOG(INFO) << " Dimensions: " << toString(desc.dimensions);
422 LOG(INFO) << " Prepared models [" << desc.preparedModels.size() << "]:";
423 for (const auto* preparedModel : desc.preparedModels) {
424 LOG(INFO) << " service = " << preparedModel->getDevice()->getName();
425 }
426 LOG(INFO) << " Input roles [" << desc.inputRoles.size() << "]:";
427 for (const auto& usage : desc.inputRoles) {
428 LOG(INFO) << " " << usage;
429 }
430 LOG(INFO) << " Output roles [" << desc.outputRoles.size() << "]:";
431 for (const auto& usage : desc.outputRoles) {
432 LOG(INFO) << " " << usage;
433 }
434 LOG(INFO) << "MemoryDescriptor end";
435 }
436
getDevices(const MemoryDescriptor & desc)437 static std::set<const Device*> getDevices(const MemoryDescriptor& desc) {
438 std::set<const Device*> devices;
439 for (const auto* preparedModel : desc.preparedModels) {
440 const auto* device = preparedModel->getDevice();
441 devices.insert(device);
442 }
443 return devices;
444 }
445
finish()446 int MemoryBuilder::finish() {
447 if (badState("finish")) return ANEURALNETWORKS_BAD_STATE;
448 if (mRoles.empty()) {
449 LOG(ERROR) << "ANeuralNetworksMemoryDesc_finish -- no role has been specified.";
450 return ANEURALNETWORKS_BAD_DATA;
451 }
452 CHECK(mOperand.has_value());
453 if (VLOG_IS_ON(MEMORY)) {
454 logMemoryDescriptorToInfo(mDesc, mOperand.value());
455 }
456 std::set<const Device*> devices = getDevices(mDesc);
457 if (devices.empty()) {
458 // This can happen with interpreted control flow.
459 mAllocator = nullptr;
460 } else if (devices.size() == 1) {
461 mAllocator = *devices.begin();
462 VLOG(MEMORY) << "Using " << mAllocator->getName() << " as allocator.";
463 } else {
464 LOG(INFO) << "MemoryBuilder::finish -- cannot handle multiple devices.";
465 mAllocator = nullptr;
466 }
467 #ifdef __ANDROID__
468 mSupportsAhwb = std::all_of(devices.begin(), devices.end(), [](const auto* device) {
469 return isCompliantVersion(kHalVersionV1_3ToApi.canonical, device->getFeatureLevel());
470 });
471 #else // __ANDROID__
472 mSupportsAhwb = false;
473 #endif // __ANDROID__
474 mShouldFallback = std::none_of(mRoles.begin(), mRoles.end(), [](const auto& role) {
475 const auto* cb = std::get<const CompilationBuilder*>(role);
476 return cb->createdWithExplicitDeviceList();
477 });
478 const uint32_t size = TypeManager::get()->getSizeOfData(mOperand->type, mDesc.dimensions);
479 mShouldFallback &= (size != 0);
480 mFinished = true;
481 return ANEURALNETWORKS_NO_ERROR;
482 }
483
allocate() const484 std::pair<int, std::unique_ptr<RuntimeMemory>> MemoryBuilder::allocate() const {
485 if (!mFinished) {
486 LOG(ERROR) << "ANeuralNetworksMemory_createFromDesc -- passed an unfinished descriptor";
487 return {ANEURALNETWORKS_BAD_STATE, nullptr};
488 }
489
490 int n = ANEURALNETWORKS_OP_FAILED;
491 std::unique_ptr<RuntimeMemory> memory;
492 CHECK(mOperand.has_value());
493
494 // Try allocate the memory on device.
495 if (mAllocator != nullptr) {
496 std::tie(n, memory) = mAllocator->allocate(mDesc, mOperand->type);
497 }
498
499 // If failed, fallback to ashmem or BLOB mode AHWB.
500 if (n != ANEURALNETWORKS_NO_ERROR && mShouldFallback) {
501 const uint32_t size = TypeManager::get()->getSizeOfData(mOperand->type, mDesc.dimensions);
502 if (mSupportsAhwb) {
503 VLOG(MEMORY) << "MemoryBuilder::allocate -- fallback to BLOB mode AHWB.";
504 std::tie(n, memory) = MemoryRuntimeAHWB::create(size);
505 } else {
506 VLOG(MEMORY) << "MemoryBuilder::allocate -- fallback to ashmem.";
507 std::tie(n, memory) = MemoryAshmem::create(size);
508 }
509 }
510
511 if (n == ANEURALNETWORKS_NO_ERROR) {
512 CHECK(memory != nullptr);
513 auto validator =
514 std::make_unique<DeviceMemoryValidator>(mRoles, mOperand.value(), mDesc.dimensions);
515 memory->setValidator(std::move(validator));
516 }
517 return {n, std::move(memory)};
518 }
519
create(uint32_t size)520 std::pair<int, std::unique_ptr<MemoryAshmem>> MemoryAshmem::create(uint32_t size) {
521 auto memory = createSharedMemory(size);
522 if (!memory.has_value()) {
523 LOG(ERROR) << "RuntimeMemory::create() failed: " << memory.error().message;
524 return {convertErrorStatusToResultCode(memory.error().code), nullptr};
525 }
526 auto mapping = map(memory.value());
527 if (!mapping.has_value()) {
528 LOG(ERROR) << "RuntimeMemory::create() map failed: " << mapping.error().message;
529 return {convertErrorStatusToResultCode(mapping.error().code), nullptr};
530 }
531 return {ANEURALNETWORKS_NO_ERROR,
532 std::make_unique<MemoryAshmem>(std::move(memory).value(), std::move(mapping).value())};
533 }
534
getPointer() const535 uint8_t* MemoryAshmem::getPointer() const {
536 return static_cast<uint8_t*>(std::get<void*>(kMapping.pointer));
537 }
538
MemoryAshmem(SharedMemory memory,Mapping mapping)539 MemoryAshmem::MemoryAshmem(SharedMemory memory, Mapping mapping)
540 : RuntimeMemory(std::move(memory)), kMapping(std::move(mapping)) {}
541
create(size_t size,int prot,int fd,size_t offset)542 std::pair<int, std::unique_ptr<MemoryFd>> MemoryFd::create(size_t size, int prot, int fd,
543 size_t offset) {
544 auto memory = createSharedMemoryFromFd(size, prot, fd, offset);
545 if (!memory.has_value()) {
546 LOG(ERROR) << "Failed to create memory from fd: " << memory.error().message;
547 return {convertErrorStatusToResultCode(memory.error().code), nullptr};
548 }
549 return {ANEURALNETWORKS_NO_ERROR, std::make_unique<MemoryFd>(std::move(memory).value())};
550 }
551
MemoryFd(SharedMemory memory)552 MemoryFd::MemoryFd(SharedMemory memory) : RuntimeMemory(std::move(memory)) {}
553
create(const AHardwareBuffer & ahwb)554 std::pair<int, std::unique_ptr<MemoryAHWB>> MemoryAHWB::create(const AHardwareBuffer& ahwb) {
555 #ifdef __ANDROID__
556 auto memory = createSharedMemoryFromAHWB(const_cast<AHardwareBuffer*>(&ahwb),
557 /*takeOwnership=*/false);
558 if (!memory.has_value()) {
559 LOG(ERROR) << "Failed to create memory from AHWB: " << memory.error().message;
560 return {convertErrorStatusToResultCode(memory.error().code), nullptr};
561 }
562
563 std::unique_ptr<MemoryValidatorBase> validator;
564 if (isAhwbBlob(memory.value())) {
565 validator = std::make_unique<SizedMemoryValidator>(nn::getSize(memory.value()));
566 } else {
567 validator = std::make_unique<AHardwareBufferNonBlobValidator>();
568 }
569
570 auto memoryAHWB = std::make_unique<MemoryAHWB>(std::move(memory).value(), std::move(validator));
571 return {ANEURALNETWORKS_NO_ERROR, std::move(memoryAHWB)};
572 #else // __ANDROID__
573 LOG(FATAL) << "std::pair<int, std::unique_ptr<MemoryAHWB>> MemoryAHWB::create(const "
574 "AHardwareBuffer& ahwb): Not Available on Host Build";
575 (void)ahwb;
576 return {ANEURALNETWORKS_OP_FAILED, nullptr};
577 #endif // __ANDROID__
578 }
579
create(uint32_t size)580 std::pair<int, std::unique_ptr<MemoryRuntimeAHWB>> MemoryRuntimeAHWB::create(uint32_t size) {
581 #ifdef __ANDROID__
582 AHardwareBuffer* ahwb = nullptr;
583 const auto usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN | AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN;
584 const AHardwareBuffer_Desc desc = {
585 .width = size,
586 .height = 1,
587 .layers = 1,
588 .format = AHARDWAREBUFFER_FORMAT_BLOB,
589 .usage = usage,
590 .stride = size,
591 };
592 int err = AHardwareBuffer_allocate(&desc, &ahwb);
593 if (err != 0 || ahwb == nullptr) {
594 LOG(ERROR) << "Failed to allocate BLOB mode AHWB.";
595 return {ANEURALNETWORKS_OP_FAILED, nullptr};
596 }
597
598 auto memory = createSharedMemoryFromAHWB(ahwb, /*takeOWnership=*/true);
599 if (!memory.has_value()) {
600 LOG(ERROR) << "Failed to allocate BLOB mode AHWB: " << memory.error().message;
601 return {convertErrorStatusToResultCode(memory.error().code), nullptr};
602 }
603 auto mapping = map(memory.value());
604 if (!mapping.has_value()) {
605 LOG(ERROR) << "Failed to map BLOB mode AHWB: " << mapping.error().message;
606 return {convertErrorStatusToResultCode(mapping.error().code), nullptr};
607 }
608 auto memoryAHWB = std::make_unique<MemoryRuntimeAHWB>(std::move(memory).value(),
609 std::move(mapping).value());
610 return {ANEURALNETWORKS_NO_ERROR, std::move(memoryAHWB)};
611 #else // __ANDROID__
612 LOG(FATAL) << "std::pair<int, std::unique_ptr<MemoryRuntimeAHWB>> "
613 "MemoryRuntimeAHWB::create(uint32_t size): Not Available on Host Build";
614 (void)size;
615 return {ANEURALNETWORKS_OP_FAILED, nullptr};
616 #endif // __ANDROID__
617 }
618
getPointer() const619 uint8_t* MemoryRuntimeAHWB::getPointer() const {
620 return static_cast<uint8_t*>(std::get<void*>(kMapping.pointer));
621 }
622
MemoryRuntimeAHWB(SharedMemory memory,Mapping mapping)623 MemoryRuntimeAHWB::MemoryRuntimeAHWB(SharedMemory memory, Mapping mapping)
624 : RuntimeMemory(std::move(memory)), kMapping(std::move(mapping)) {}
625
create(SharedBuffer buffer)626 std::pair<int, std::unique_ptr<MemoryFromDevice>> MemoryFromDevice::create(SharedBuffer buffer) {
627 if (buffer == nullptr) {
628 LOG(ERROR) << "nullptr IBuffer for device memory.";
629 return {ANEURALNETWORKS_OP_FAILED, nullptr};
630 }
631 return {ANEURALNETWORKS_NO_ERROR, std::make_unique<MemoryFromDevice>(std::move(buffer))};
632 }
633
MemoryFromDevice(SharedBuffer buffer)634 MemoryFromDevice::MemoryFromDevice(SharedBuffer buffer) : RuntimeMemory(std::move(buffer)) {}
635
636 } // namespace nn
637 } // namespace android
638