blob: fc86559f8f667bffb28c2ef5c8df2d9bf74c9393 [file]
/*
* 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_FRAMEWORKS_ML_NN_RUNTIME_MEMORY_H
#define ANDROID_FRAMEWORKS_ML_NN_RUNTIME_MEMORY_H
#include "HalInterfaces.h"
#include "NeuralNetworks.h"
#include "Utils.h"
#include <android-base/macros.h>
#include <cutils/native_handle.h>
#include <sys/mman.h>
#include <vndk/hardware_buffer.h>
#include <memory>
#include <mutex>
#include <unordered_map>
#include <utility>
#include <vector>
namespace android {
namespace nn {
class ExecutionBurstController;
class ModelBuilder;
// Represents a memory region.
class Memory {
// Disallow copy and assign to prevent slicing
DISALLOW_COPY_AND_ASSIGN(Memory);
public:
// Custom destructor to notify any ExecutionBurstControllers currently using
// this memory that it is being freed.
virtual ~Memory();
const hal::hidl_memory& getHidlMemory() const { return kHidlMemory; }
virtual bool validateSize(uint32_t offset, uint32_t length) const;
// Unique key representing this memory object.
intptr_t getKey() const;
// Marks a burst object as currently using this memory. When this
// memory object is destroyed, it will automatically free this memory from
// the bursts' memory cache.
void usedBy(const std::shared_ptr<ExecutionBurstController>& burst) const;
protected:
Memory(hal::hidl_memory memory);
// The hidl_memory handle for this shared memory. We will pass this value when
// communicating with the drivers.
const hal::hidl_memory kHidlMemory;
private:
mutable std::mutex mMutex;
// mUsedBy is essentially a set of burst objects which use this Memory
// object. However, std::weak_ptr does not have comparison operations nor a
// std::hash implementation. This is because it is either a valid pointer
// (non-null) if the shared object is still alive, or it is null if the
// object has been freed. To circumvent this, mUsedBy is a map with the raw
// pointer as the key and the weak_ptr as the value.
mutable std::unordered_map<const ExecutionBurstController*,
std::weak_ptr<ExecutionBurstController>>
mUsedBy;
};
class MemoryAshmem : public Memory {
public:
// Creates a memory object containing a new android shared memory ("ashmem")
// object of the size specified in bytes. Because this ashmem region can be
// shared with and accessed by one or more driver processes, MemoryAshmem
// has shared ownership over the ashmem region.
//
// On success, returns ANEURALNETWORKS_NO_ERROR and a memory object.
// On error, returns the appropriate NNAPI error code and nullptr.
static std::pair<int, std::unique_ptr<MemoryAshmem>> create(uint32_t size);
// Get a pointer to the ashmem region of memory. The returned pointer is
// valid for the lifetime of the MemoryAshmem object. This call always
// returns non-null because it was validated during MemoryAshmem::create.
uint8_t* getPointer() const;
// prefer using MemoryAshmem::create
MemoryAshmem(sp<hal::IMemory> mapped, hal::hidl_memory memory);
private:
const sp<hal::IMemory> kMappedMemory;
};
class MemoryFd : public Memory {
public:
// Create a memory object based on input size, prot, and fd that can be sent
// across HIDL. This function duplicates the provided fd, and owns the
// duplicate.
//
// On success, returns ANEURALNETWORKS_NO_ERROR and a memory object.
// On error, returns the appropriate NNAPI error code and nullptr.
static std::pair<int, std::unique_ptr<MemoryFd>> create(size_t size, int prot, int fd,
size_t offset);
// prefer using MemoryFd::create
MemoryFd(hal::hidl_memory memory);
};
class MemoryAHWB : public Memory {
public:
// Create a memory object to keep track of (but not take ownership of) the
// provided AHardwareBuffer handle.
//
// On success, returns ANEURALNETWORKS_NO_ERROR and a memory object.
// On error, returns the appropriate NNAPI error code and nullptr.
static std::pair<int, std::unique_ptr<MemoryAHWB>> create(const AHardwareBuffer& ahwb);
// validateSize should only be called for blob mode AHardwareBuffer.
// Calling it on non-blob mode AHardwareBuffer will result in an error.
// TODO(miaowang): consider separate blob and non-blob into different classes.
bool validateSize(uint32_t offset, uint32_t length) const override;
// prefer using MemoryAHWB::create
MemoryAHWB(const AHardwareBuffer_Desc& desc, hal::hidl_memory memory);
private:
const bool kBlobMode;
};
// 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 {
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;
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]; }
// Iteration
auto begin() { return mMemories.begin(); }
auto end() { return mMemories.end(); }
auto begin() const { return mMemories.begin(); }
auto end() const { return mMemories.end(); }
};
} // namespace nn
} // namespace android
#endif // ANDROID_FRAMEWORKS_ML_NN_RUNTIME_MEMORY_H