This commit prevents to deallocate acl's constant tensor used in several nodes.
Signed-off-by: jiseob.jang <jiseob.jang@samsung.com>
#define __NEURUN_BACKEND_ACL_CL_TENSOR_REGISTER_H__
#include <AclTensorRegister.h>
+#include <misc/polymorphic_downcast.h>
+#include "TensorBuilder.h"
namespace neurun
{
namespace acl_cl
{
-using TensorRegister = acl_common::AclTensorRegister;
+class TensorRegister : public acl_common::AclTensorRegister
+{
+public:
+ TensorRegister(const model::Operands &operands,
+ const std::shared_ptr<TensorBuilder> &tensor_builder)
+ : acl_common::AclTensorRegister{operands, tensor_builder}
+ {
+ // DO NOTHING
+ }
+
+ void setUsesCount(const model::OperandIndex &ind, size_t num_uses) const override
+ {
+ nnfw::misc::polymorphic_downcast<TensorBuilder *>(tensor_builder().get())
+ ->setUsesCount(ind, num_uses);
+ }
+};
} // namespace acl_cl
} // namespace backend
namespace operand
{
-CLTensor::CLTensor(const arm_compute::TensorInfo &info, size_t rank)
- : _cl_tensor(std::make_shared<arm_compute::CLTensor>()), _rank{rank}
+CLTensor::CLTensor(const arm_compute::TensorInfo &info, size_t rank, size_t num_uses)
+ : _cl_tensor(std::make_shared<arm_compute::CLTensor>()), _rank{rank}, _num_uses{num_uses}
{
allocator()->init(info);
}
CLTensor() = delete;
public:
- CLTensor(const arm_compute::TensorInfo &info, size_t rank);
+ CLTensor(const arm_compute::TensorInfo &info, size_t rank, size_t num_uses);
public:
size_t num_dimensions() const final { return _rank; }
public:
const arm_compute::CLTensor *handle() const override;
arm_compute::CLTensor *handle() override;
+ size_t num_uses() const { return _num_uses; }
public:
arm_compute::CLTensorAllocator *allocator();
private:
std::shared_ptr<arm_compute::CLTensor> _cl_tensor;
size_t _rank;
+ size_t _num_uses;
};
} // namespace operand
virtual void finishLifetime(const model::OperandIndex &) { /* DO NOTHING */}
void buildTensor(const model::OperandIndex &ind, const ::arm_compute::TensorInfo &info,
- size_t rank)
+ size_t rank, size_t num_uses)
{
- auto tensor = std::make_shared<T_Tensor>(info, rank);
+ auto tensor = std::make_shared<T_Tensor>(info, rank, num_uses);
_tensors[ind] = tensor;
}
void deallocateInternalBufferManager(void);
void buildTensor(const model::OperandIndex &ind, const ::arm_compute::TensorInfo &info,
- size_t rank, bool as_const);
+ size_t rank, bool as_const, size_t num_uses);
void buildSubtensor(const model::OperandIndex &parent, const model::OperandIndex &child,
const ::arm_compute::TensorShape &shape,
const ::arm_compute::Coordinates &coordinates, size_t rank,
template <typename T_ITensor, typename T_Tensor, typename T_SubTensor, typename T_Object>
void AclTensorManager<T_ITensor, T_Tensor, T_SubTensor, T_Object>::buildTensor(
const model::OperandIndex &ind, const ::arm_compute::TensorInfo &info, size_t rank,
- bool as_const)
+ bool as_const, size_t num_uses)
{
assert(_ind_to_mgr.find(ind) == _ind_to_mgr.end());
if (as_const)
{
- _const_mgr->buildTensor(ind, info, rank);
+ _const_mgr->buildTensor(ind, info, rank, num_uses);
_ind_to_mgr.insert({ind, *_const_mgr});
}
else
{
- _nonconst_mgr->buildTensor(ind, info, rank);
+ _nonconst_mgr->buildTensor(ind, info, rank, num_uses);
_ind_to_mgr.insert({ind, *_nonconst_mgr});
}
}
{
const auto &ind = it->first;
auto tensor = it->second;
- if (tensor->handle() && !tensor->handle()->is_used())
+ // NOTE The condition "tensor->num_uses() < 2" is used to prevent deallocating a constant tensor
+ // used in several nodes.
+ if (tensor->handle() && !tensor->handle()->is_used() && tensor->num_uses() < 2)
{
VERBOSE(AclTensorManager) << "Tensor #" << ind.value()
<< " will be deallocated as an unused constant tensor" << std::endl;
assert(tensor_builder != nullptr);
}
+void AclTensorRegister::visit(const model::Subgraph &subgraph)
+{
+ for (const auto &e : subgraph.operations())
+ {
+ const auto &node = *(e.node);
+ node.accept(*this);
+ // Set count of nodes to use operand
+ for (const auto &input : node.getInputs())
+ {
+ setUsesCount(input, _operands.at(input).getUses().size());
+ }
+ }
+}
+
} // namespace acl_common
} // namespace backend
} // namespace neurun
class AclTensorRegister : public ITensorRegister
{
-public:
+protected:
AclTensorRegister(const model::Operands &operands,
const std::shared_ptr<ITensorBuilder> &tensor_builder);
-private:
+public:
+ virtual ~AclTensorRegister() = default;
+
+protected:
+ void visit(const model::Subgraph &subgraph);
+ virtual void setUsesCount(const model::OperandIndex &ind, size_t num_uses) const = 0;
+
+protected:
const model::Operands &operands() const override { return _operands; }
std::shared_ptr<ITensorBuilder> tensor_builder() const override { return _tensor_builder; }
bool supportSubTensor() const final { return true; }
T_AclTensorManager *acl_tensor_manager(void) { return _tensor_mgr.get(); }
+ void setUsesCount(const model::OperandIndex &index, size_t num_uses)
+ {
+ assert(_uses_count_map.find(index) != _uses_count_map.end() ? _uses_count_map[index] == num_uses
+ : true);
+ _uses_count_map[index] = num_uses;
+ }
+
private:
void buildTensors(void);
void buildSubtensors(void);
model::OperandIndexMap<compiler::SubTensorInfo> _subtensor_info_map;
model::OperandIndexMap<bool> _apply_dim_correction_map;
model::OperandIndexMap<model::Layout> _tensor_layout_map;
+ model::OperandIndexMap<size_t> _uses_count_map;
std::unique_ptr<T_AclTensorManager> _tensor_mgr;
model::OperandIndexSequence _constants;
const auto &backend_layout = _tensor_layout_map[root_parent];
auto tensor_info = asTensorInfo(info.shape(), info.typeInfo(), model::Layout::UNKNOWN,
backend_layout, _apply_dim_correction_map[ind]);
- _tensor_mgr->buildTensor(ind, tensor_info, info.shape().rank(), _constants.contains(ind));
+ _tensor_mgr->buildTensor(ind, tensor_info, info.shape().rank(), _constants.contains(ind),
+ _uses_count_map[ind]);
}
}
#define __NEURUN_BACKEND_ACL_NEON_TENSOR_REGISTER_H__
#include <AclTensorRegister.h>
+#include <misc/polymorphic_downcast.h>
+#include "TensorBuilder.h"
namespace neurun
{
namespace acl_neon
{
-using TensorRegister = acl_common::AclTensorRegister;
+class TensorRegister : public acl_common::AclTensorRegister
+{
+public:
+ TensorRegister(const model::Operands &operands,
+ const std::shared_ptr<TensorBuilder> &tensor_builder)
+ : acl_common::AclTensorRegister{operands, tensor_builder}
+ {
+ // DO NOTHING
+ }
+
+ void setUsesCount(const model::OperandIndex &ind, size_t num_uses) const override
+ {
+ nnfw::misc::polymorphic_downcast<TensorBuilder *>(tensor_builder().get())
+ ->setUsesCount(ind, num_uses);
+ }
+};
} // namespace acl_neon
} // namespace backend
namespace operand
{
-NETensor::NETensor(const arm_compute::TensorInfo &info, size_t rank)
- : _ne_tensor(std::make_shared<arm_compute::Tensor>()), _rank{rank}
+NETensor::NETensor(const arm_compute::TensorInfo &info, size_t rank, size_t num_uses)
+ : _ne_tensor(std::make_shared<arm_compute::Tensor>()), _rank{rank}, _num_uses{num_uses}
{
allocator()->init(info);
}
NETensor() = delete;
public:
- NETensor(const arm_compute::TensorInfo &info, size_t rank);
+ NETensor(const arm_compute::TensorInfo &info, size_t rank, size_t num_uses);
public:
size_t num_dimensions() const final { return _rank; }
public:
const arm_compute::Tensor *handle() const override;
arm_compute::Tensor *handle() override;
+ size_t num_uses() const { return _num_uses; }
public:
arm_compute::TensorAllocator *allocator();
private:
std::shared_ptr<arm_compute::Tensor> _ne_tensor;
size_t _rank;
+ size_t _num_uses;
};
} // namespace operand