Add Memory.h, Memory.cpp without IMemory (#207)
author김수진/동작제어Lab(SR)/Engineer/삼성전자 <sjsujin.kim@samsung.com>
Mon, 26 Mar 2018 11:02:27 +0000 (20:02 +0900)
committer최형규/동작제어Lab(SR)/Senior Engineer/삼성전자 <hk0110.choi@samsung.com>
Mon, 26 Mar 2018 11:02:27 +0000 (20:02 +0900)
* Add Memory.h, Memory.cpp without IMemory

This commit adds Memory.h and Memory.cpp without IMemory.

Signed-off-by: sjsujinkim <sjsujin.kim@samsung.com>
* Add getPointer of MemoryFd

src/runtime/ref/nn/common/Utils.cpp
src/runtime/ref/nn/common/include/Utils.h
src/runtime/ref/nn/runtime/CMakeLists.txt
src/runtime/ref/nn/runtime/Memory.cpp [new file with mode: 0644]
src/runtime/ref/nn/runtime/Memory.h [new file with mode: 0644]

index 5b4679a..08fc067 100644 (file)
@@ -214,12 +214,13 @@ uint32_t sizeOfData(OperandType type, const std::vector<uint32_t>& 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<IAllocator> 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) {
index a673b72..e8afd34 100644 (file)
@@ -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
index 038a160..a71f305 100644 (file)
@@ -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 (file)
index 0000000..add4010
--- /dev/null
@@ -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 <unistd.h> // 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<uint8_t*>(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<uint32_t>(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 (file)
index 0000000..c4e379f
--- /dev/null
@@ -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 <cutils/native_handle.h>
+#include <sys/mman.h>
+#include <unordered_map>
+
+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<uint8_t*>(static_cast<void*>(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<IMemory> 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<uint32_t>(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<const Memory*> mMemories;
+    // A faster way to see if we already have a memory than doing find().
+    std::unordered_map<const Memory*, uint32_t> mKnown;
+};
+
+}  // namespace nn
+}  // namespace android
+
+#endif  // ANDROID_ML_NN_RUNTIME_MEMORY_H