}
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) {
memory = mem;
}
});
-
+#endif
return memory;
}
-#endif // REF-ANN
+
uint32_t alignBytesNeeded(uint32_t index, size_t length) {
uint32_t pattern;
if (length < 2) {
// 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,
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
# Library `runtime`
SET (RUNTIME_SRCS NeuralNetworks.cpp
ModelBuilder.cpp
- CompilationBuilder.cpp)
+ CompilationBuilder.cpp
+ Memory.cpp)
SET (DEPEND_SRCS ${SRCS})
SET (DEPEND_INCS ${INC_DIRS})
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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