From: 김수진/동작제어Lab(SR)/Engineer/삼성전자 Date: Mon, 26 Mar 2018 11:02:27 +0000 (+0900) Subject: Add Memory.h, Memory.cpp without IMemory (#207) X-Git-Tag: 0.1~590 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=e8dd398547f093ff5c2e5a708a06f28769133447;p=platform%2Fcore%2Fml%2Fnnfw.git Add Memory.h, Memory.cpp without IMemory (#207) * Add Memory.h, Memory.cpp without IMemory This commit adds Memory.h and Memory.cpp without IMemory. Signed-off-by: sjsujinkim * Add getPointer of MemoryFd --- diff --git a/src/runtime/ref/nn/common/Utils.cpp b/src/runtime/ref/nn/common/Utils.cpp index 5b4679a..08fc067 100644 --- a/src/runtime/ref/nn/common/Utils.cpp +++ b/src/runtime/ref/nn/common/Utils.cpp @@ -214,12 +214,13 @@ uint32_t sizeOfData(OperandType type, const std::vector& dimensions) { } return size; } -#if 0 // REF-ANN + hidl_memory allocateSharedMemory(int64_t size) { hidl_memory memory; // TODO: should we align memory size to nearest page? doesn't seem necessary... const std::string& type = "ashmem"; +#if 0 // TODO-NNRT : Our allocator is needed. sp allocator = IAllocator::getService(type); allocator->allocate(size, [&](bool success, const hidl_memory& mem) { if (!success) { @@ -228,10 +229,10 @@ hidl_memory allocateSharedMemory(int64_t size) { memory = mem; } }); - +#endif return memory; } -#endif // REF-ANN + uint32_t alignBytesNeeded(uint32_t index, size_t length) { uint32_t pattern; if (length < 2) { diff --git a/src/runtime/ref/nn/common/include/Utils.h b/src/runtime/ref/nn/common/include/Utils.h index a673b72..e8afd34 100644 --- a/src/runtime/ref/nn/common/include/Utils.h +++ b/src/runtime/ref/nn/common/include/Utils.h @@ -95,12 +95,12 @@ inline uint32_t sizeOfData(const Operand& operand) { // Returns the name of the operation in ASCII. const char* getOperationName(OperationType opCode); - +#endif // REF-ANN // Memory is unmapped. // Memory is reference counted by hidl_memory instances, and is deallocated // once there are no more references. hidl_memory allocateSharedMemory(int64_t size); -#endif // REF-ANN + // Returns the number of padding bytes needed to align data of the // specified length. It aligns object of length: // 2, 3 on a 2 byte boundary, @@ -150,11 +150,11 @@ int validateOperandList(uint32_t count, const uint32_t* list, uint32_t operandCo const char* tag); bool validateModel(const Model& model); bool validateRequest(const Request& request, const Model& model); - +#endif // REF-ANN inline size_t getSizeFromInts(int lower, int higher) { return (uint32_t)(lower) + ((uint64_t)(uint32_t)(higher) << 32); } - +#if 0 // REF-ANN #ifdef NN_DEBUGGABLE uint32_t getProp(const char* str, uint32_t defaultValue = 0); #endif // NN_DEBUGGABLE diff --git a/src/runtime/ref/nn/runtime/CMakeLists.txt b/src/runtime/ref/nn/runtime/CMakeLists.txt index 038a160..a71f305 100644 --- a/src/runtime/ref/nn/runtime/CMakeLists.txt +++ b/src/runtime/ref/nn/runtime/CMakeLists.txt @@ -1,7 +1,8 @@ # Library `runtime` SET (RUNTIME_SRCS NeuralNetworks.cpp ModelBuilder.cpp - CompilationBuilder.cpp) + CompilationBuilder.cpp + Memory.cpp) SET (DEPEND_SRCS ${SRCS}) SET (DEPEND_INCS ${INC_DIRS}) diff --git a/src/runtime/ref/nn/runtime/Memory.cpp b/src/runtime/ref/nn/runtime/Memory.cpp new file mode 100644 index 0000000..add4010 --- /dev/null +++ b/src/runtime/ref/nn/runtime/Memory.cpp @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "Memory" + +#include "Memory.h" + +#include "HalInterfaces.h" +#include "Utils.h" + +#include "Log.h" + +#include // It's for 'close' and 'dup' + // TODO-NNRT : Remove this if included another header including this. + +namespace android { +namespace nn { + +int Memory::create(uint32_t size) { + mHidlMemory = allocateSharedMemory(size); +#if 0 // TODO-NNRT : Add mapMemory + mMemory = mapMemory(mHidlMemory); + if (mMemory == nullptr) { + LOG(ERROR) << "Memory::create failed"; + return ANEURALNETWORKS_OP_FAILED; + } +#endif // TODO-NNRT + return ANEURALNETWORKS_NO_ERROR; +} + +bool Memory::validateSize(uint32_t offset, uint32_t length) const { + if (offset + length > mHidlMemory.size()) { + LOG(ERROR) << "Request size larger than the memory size."; + return false; + } else { + return true; + } +} + +MemoryFd::~MemoryFd() { + // Delete the native_handle. + if (mHandle) { + int fd = mHandle->data[0]; + if (fd != -1) { + close(fd); + } + native_handle_delete(mHandle); + } +} + +int MemoryFd::set(size_t size, int prot, int fd, size_t offset) { + if (fd < 0) { + LOG(ERROR) << "ANeuralNetworksMemory_createFromFd invalid fd " << fd; + return ANEURALNETWORKS_UNEXPECTED_NULL; + } + if (size == 0 || fd < 0) { + LOG(ERROR) << "Invalid size or fd"; + return ANEURALNETWORKS_BAD_DATA; + } + int dupfd = dup(fd); + if (dupfd == -1) { + LOG(ERROR) << "Failed to dup the fd"; + return ANEURALNETWORKS_UNEXPECTED_NULL; + } + + if (mHandle) { + native_handle_delete(mHandle); + } + mHandle = native_handle_create(1, 3); + if (mHandle == nullptr) { + LOG(ERROR) << "Failed to create native_handle"; + return ANEURALNETWORKS_UNEXPECTED_NULL; + } + mHandle->data[0] = dupfd; + mHandle->data[1] = prot; + mHandle->data[2] = (int32_t)(uint32_t)(offset & 0xffffffff); +#if defined(__LP64__) + mHandle->data[3] = (int32_t)(uint32_t)(offset >> 32); +#else + mHandle->data[3] = 0; +#endif + mHidlMemory = hidl_memory("mmap_fd", mHandle, size); + return ANEURALNETWORKS_NO_ERROR; +} + +int MemoryFd::getPointer(uint8_t** buffer) const { + if (mHandle == nullptr) { + LOG(ERROR) << "Memory not initialized"; + return ANEURALNETWORKS_UNEXPECTED_NULL; + } + + int fd = mHandle->data[0]; + int prot = mHandle->data[1]; + size_t offset = getSizeFromInts(mHandle->data[2], mHandle->data[3]); + void* data = mmap(nullptr, mHidlMemory.size(), prot, MAP_SHARED, fd, offset); + if (data == MAP_FAILED) { + LOG(ERROR) << "Can't mmap the file descriptor."; + return ANEURALNETWORKS_UNMAPPABLE; + } else { + *buffer = static_cast(data); + return ANEURALNETWORKS_NO_ERROR; + } +} + +uint32_t MemoryTracker::add(const Memory* memory) { + VLOG(MODEL) << __func__ << " for " << memory; + // See if we already have this memory. If so, + // return its index. + auto i = mKnown.find(memory); + if (i != mKnown.end()) { + return i->second; + } + VLOG(MODEL) << "It's new"; + // It's a new one. Save it an assign an index to it. + size_t next = mKnown.size(); + if (next > 0xFFFFFFFF) { + LOG(ERROR) << "ANeuralNetworks more than 2^32 memories."; + return ANEURALNETWORKS_BAD_DATA; + } + uint32_t idx = static_cast(next); + mKnown[memory] = idx; + mMemories.push_back(memory); + return idx; +} + +} // namespace nn +} // namespace android diff --git a/src/runtime/ref/nn/runtime/Memory.h b/src/runtime/ref/nn/runtime/Memory.h new file mode 100644 index 0000000..c4e379f --- /dev/null +++ b/src/runtime/ref/nn/runtime/Memory.h @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_ML_NN_RUNTIME_MEMORY_H +#define ANDROID_ML_NN_RUNTIME_MEMORY_H + +#include "NeuralNetworks.h" +#include "Utils.h" + +#include +#include +#include + +namespace android { +namespace nn { + +class ModelBuilder; + +// Represents a memory region. +class Memory { +public: + Memory() {} + virtual ~Memory() {} + + // Disallow copy semantics to ensure the runtime object can only be freed + // once. Copy semantics could be enabled if some sort of reference counting + // or deep-copy system for runtime objects is added later. + Memory(const Memory&) = delete; + Memory& operator=(const Memory&) = delete; + + // Creates a shared memory object of the size specified in bytes. + int create(uint32_t size); + + hardware::hidl_memory getHidlMemory() const { return mHidlMemory; } + + // Returns a pointer to the underlying memory of this memory object. + virtual int getPointer(uint8_t** buffer) const { +#if 0 // TODO-NNRT : IMemory is needed + // TODO-NNRT : mMemory is just dummy. It needs to implement IMemory. + *buffer = static_cast(static_cast(mMemory->getPointer())); +#endif // TODO-NNRT + return ANEURALNETWORKS_NO_ERROR; + } + virtual bool validateSize(uint32_t offset, uint32_t length) const; +protected: + // The hidl_memory handle for this shared memory. We will pass this value when + // communicating with the drivers. + hardware::hidl_memory mHidlMemory; +#if 0 // TODO-NNRT : Imemory is needed. + sp mMemory; +#endif // TODO-NNRT +}; + +class MemoryFd : public Memory { +public: + MemoryFd() {} + ~MemoryFd(); + + // Disallow copy semantics to ensure the runtime object can only be freed + // once. Copy semantics could be enabled if some sort of reference counting + // or deep-copy system for runtime objects is added later. + MemoryFd(const MemoryFd&) = delete; + MemoryFd& operator=(const MemoryFd&) = delete; + + // Create the native_handle based on input size, prot, and fd. + // Existing native_handle will be deleted, and mHidlMemory will wrap + // the newly created native_handle. + int set(size_t size, int prot, int fd, size_t offset); + int getPointer(uint8_t** buffer) const override; +private: + native_handle_t* mHandle = nullptr; +}; + +// A utility class to accumulate mulitple Memory objects and assign each +// a distinct index number, starting with 0. +// +// The user of this class is responsible for avoiding concurrent calls +// to this class from multiple threads. +class MemoryTracker { +public: + // Adds the memory, if it does not already exists. Returns its index. + // The memories should survive the tracker. + uint32_t add(const Memory* memory); + // Returns the number of memories contained. + uint32_t size() const { return static_cast(mKnown.size()); } + // Returns the ith memory. + const Memory* operator[](size_t i) const { return mMemories[i]; } + +private: + // The vector of Memory pointers we are building. + std::vector mMemories; + // A faster way to see if we already have a memory than doing find(). + std::unordered_map mKnown; +}; + +} // namespace nn +} // namespace android + +#endif // ANDROID_ML_NN_RUNTIME_MEMORY_H