aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichalis Spyrou <michalis.spyrou@arm.com>2019-09-09 19:23:39 +0100
committerGeorgios Pinitas <georgios.pinitas@arm.com>2019-09-16 15:11:51 +0000
commitcaa7deedfe1b0d0020c6099d8f616ec92b1bd5e9 (patch)
treef33643941f0824d5fa79140070a7c9993acb2851
parentd87a7b297a5bfc2bad3ba78ea97754d7894e82ef (diff)
downloadComputeLibrary-caa7deedfe1b0d0020c6099d8f616ec92b1bd5e9.tar.gz
COMPMID-2641 [NEON] Create a test case for dynamic tensor support
Change-Id: I181e9acffd34ff1c807c65a822cfafb7327b8c8a Signed-off-by: Michalis Spyrou <michalis.spyrou@arm.com> Reviewed-on: https://review.mlplatform.org/c/1913 Comments-Addressed: Arm Jenkins <bsgcomp@arm.com> Tested-by: Arm Jenkins <bsgcomp@arm.com>
-rw-r--r--arm_compute/runtime/MemoryGroupBase.h10
-rw-r--r--arm_compute/runtime/OffsetLifetimeManager.h8
-rw-r--r--arm_compute/runtime/OffsetMemoryPool.h5
-rw-r--r--src/runtime/CL/CLTensorAllocator.cpp2
-rw-r--r--src/runtime/GLES_COMPUTE/GCTensorAllocator.cpp4
-rw-r--r--src/runtime/ISimpleLifetimeManager.cpp4
-rw-r--r--src/runtime/OffsetLifetimeManager.cpp5
-rw-r--r--src/runtime/OffsetMemoryPool.cpp12
-rw-r--r--src/runtime/TensorAllocator.cpp2
-rw-r--r--tests/validation/NEON/UNIT/DynamicTensor.cpp80
-rw-r--r--tests/validation/fixtures/UNIT/DynamicTensorFixture.h224
11 files changed, 340 insertions, 16 deletions
diff --git a/arm_compute/runtime/MemoryGroupBase.h b/arm_compute/runtime/MemoryGroupBase.h
index 7dc18c8b4f..e3f38f7cfe 100644
--- a/arm_compute/runtime/MemoryGroupBase.h
+++ b/arm_compute/runtime/MemoryGroupBase.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2018 ARM Limited.
+ * Copyright (c) 2017-2019 ARM Limited.
*
* SPDX-License-Identifier: MIT
*
@@ -101,7 +101,7 @@ inline MemoryGroupBase<TensorType>::MemoryGroupBase(std::shared_ptr<IMemoryManag
template <typename TensorType>
inline void MemoryGroupBase<TensorType>::manage(TensorType *obj)
{
- if(_memory_manager && _mappings.empty())
+ if(_memory_manager)
{
ARM_COMPUTE_ERROR_ON(!_memory_manager->lifetime_manager());
@@ -119,11 +119,7 @@ inline void MemoryGroupBase<TensorType>::manage(TensorType *obj)
template <typename TensorType>
inline void MemoryGroupBase<TensorType>::finalize_memory(TensorType *obj, IMemory &obj_memory, size_t size, size_t alignment)
{
- // TODO (geopin01) : Check size (track size in MemoryMappings)
- // Check if existing mapping is valid
- ARM_COMPUTE_ERROR_ON(!_mappings.empty() && (_mappings.find(&obj_memory) == std::end(_mappings)));
-
- if(_memory_manager && _mappings.empty())
+ if(_memory_manager)
{
ARM_COMPUTE_ERROR_ON(!_memory_manager->lifetime_manager());
_memory_manager->lifetime_manager()->end_lifetime(obj, obj_memory, size, alignment);
diff --git a/arm_compute/runtime/OffsetLifetimeManager.h b/arm_compute/runtime/OffsetLifetimeManager.h
index 26aeb1ef6a..748f3b6f81 100644
--- a/arm_compute/runtime/OffsetLifetimeManager.h
+++ b/arm_compute/runtime/OffsetLifetimeManager.h
@@ -41,6 +41,9 @@ class IMemoryPool;
class OffsetLifetimeManager : public ISimpleLifetimeManager
{
public:
+ using info_type = BlobInfo;
+
+public:
/** Constructor */
OffsetLifetimeManager();
/** Prevent instances of this class to be copy constructed */
@@ -51,6 +54,11 @@ public:
OffsetLifetimeManager(OffsetLifetimeManager &&) = default;
/** Allow instances of this class to be moved */
OffsetLifetimeManager &operator=(OffsetLifetimeManager &&) = default;
+ /** Accessor to the pool internal configuration meta-data
+ *
+ * @return Pool internal configuration meta-data
+ */
+ const info_type &info() const;
// Inherited methods overridden:
std::unique_ptr<IMemoryPool> create_pool(IAllocator *allocator) override;
diff --git a/arm_compute/runtime/OffsetMemoryPool.h b/arm_compute/runtime/OffsetMemoryPool.h
index bc09de6a14..26005706df 100644
--- a/arm_compute/runtime/OffsetMemoryPool.h
+++ b/arm_compute/runtime/OffsetMemoryPool.h
@@ -58,6 +58,11 @@ public:
OffsetMemoryPool(OffsetMemoryPool &&) = default;
/** Allow instances of this class to be move assigned */
OffsetMemoryPool &operator=(OffsetMemoryPool &&) = default;
+ /** Accessor to the pool internal configuration meta-data
+ *
+ * @return Pool internal configuration meta-data
+ */
+ const BlobInfo &info() const;
// Inherited methods overridden:
void acquire(MemoryMappings &handles) override;
diff --git a/src/runtime/CL/CLTensorAllocator.cpp b/src/runtime/CL/CLTensorAllocator.cpp
index 51caf69297..72b5854c5c 100644
--- a/src/runtime/CL/CLTensorAllocator.cpp
+++ b/src/runtime/CL/CLTensorAllocator.cpp
@@ -181,7 +181,7 @@ Status CLTensorAllocator::import_memory(cl::Buffer buffer)
void CLTensorAllocator::set_associated_memory_group(CLMemoryGroup *associated_memory_group)
{
ARM_COMPUTE_ERROR_ON(associated_memory_group == nullptr);
- ARM_COMPUTE_ERROR_ON(_associated_memory_group != nullptr);
+ ARM_COMPUTE_ERROR_ON(_associated_memory_group != nullptr && _associated_memory_group != associated_memory_group);
ARM_COMPUTE_ERROR_ON(_memory.region() != nullptr && _memory.cl_region()->cl_data().get() != nullptr);
_associated_memory_group = associated_memory_group;
diff --git a/src/runtime/GLES_COMPUTE/GCTensorAllocator.cpp b/src/runtime/GLES_COMPUTE/GCTensorAllocator.cpp
index a0dd540a7c..9a5d139517 100644
--- a/src/runtime/GLES_COMPUTE/GCTensorAllocator.cpp
+++ b/src/runtime/GLES_COMPUTE/GCTensorAllocator.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2018 ARM Limited.
+ * Copyright (c) 2017-2019 ARM Limited.
*
* SPDX-License-Identifier: MIT
*
@@ -65,7 +65,7 @@ void GCTensorAllocator::free()
void GCTensorAllocator::set_associated_memory_group(GCMemoryGroup *associated_memory_group)
{
ARM_COMPUTE_ERROR_ON(associated_memory_group == nullptr);
- ARM_COMPUTE_ERROR_ON(_associated_memory_group != nullptr);
+ ARM_COMPUTE_ERROR_ON(_associated_memory_group != nullptr && _associated_memory_group != associated_memory_group);
ARM_COMPUTE_ERROR_ON(_memory.region() != nullptr && _memory.gc_region()->gc_ssbo_name() != 0);
_associated_memory_group = associated_memory_group;
diff --git a/src/runtime/ISimpleLifetimeManager.cpp b/src/runtime/ISimpleLifetimeManager.cpp
index 97c20d1882..39a4096799 100644
--- a/src/runtime/ISimpleLifetimeManager.cpp
+++ b/src/runtime/ISimpleLifetimeManager.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2018 ARM Limited.
+ * Copyright (c) 2017-2019 ARM Limited.
*
* SPDX-License-Identifier: MIT
*
@@ -100,7 +100,7 @@ void ISimpleLifetimeManager::end_lifetime(void *obj, IMemory &obj_memory, size_t
occupied_blob_it->id = nullptr;
_free_blobs.splice(std::begin(_free_blobs), _occupied_blobs, occupied_blob_it);
- // Check if all object are finalized and reset active group
+ // Check if all objects are finalized and reset active group
if(are_all_finalized())
{
ARM_COMPUTE_ERROR_ON(!_occupied_blobs.empty());
diff --git a/src/runtime/OffsetLifetimeManager.cpp b/src/runtime/OffsetLifetimeManager.cpp
index ad23220c0e..e9aa1ff447 100644
--- a/src/runtime/OffsetLifetimeManager.cpp
+++ b/src/runtime/OffsetLifetimeManager.cpp
@@ -49,6 +49,11 @@ OffsetLifetimeManager::OffsetLifetimeManager()
{
}
+const OffsetLifetimeManager::info_type &OffsetLifetimeManager::info() const
+{
+ return _blob;
+}
+
std::unique_ptr<IMemoryPool> OffsetLifetimeManager::create_pool(IAllocator *allocator)
{
ARM_COMPUTE_ERROR_ON(allocator == nullptr);
diff --git a/src/runtime/OffsetMemoryPool.cpp b/src/runtime/OffsetMemoryPool.cpp
index 70cbe90bf0..a335f6087a 100644
--- a/src/runtime/OffsetMemoryPool.cpp
+++ b/src/runtime/OffsetMemoryPool.cpp
@@ -32,8 +32,8 @@
#include "arm_compute/runtime/Types.h"
#include "support/ToolchainSupport.h"
-using namespace arm_compute;
-
+namespace arm_compute
+{
OffsetMemoryPool::OffsetMemoryPool(IAllocator *allocator, BlobInfo blob_info)
: _allocator(allocator), _blob(), _blob_info(blob_info)
{
@@ -41,6 +41,11 @@ OffsetMemoryPool::OffsetMemoryPool(IAllocator *allocator, BlobInfo blob_info)
_blob = _allocator->make_region(blob_info.size, blob_info.alignment);
}
+const BlobInfo &OffsetMemoryPool::info() const
+{
+ return _blob_info;
+}
+
void OffsetMemoryPool::acquire(MemoryMappings &handles)
{
ARM_COMPUTE_ERROR_ON(_blob == nullptr);
@@ -71,4 +76,5 @@ std::unique_ptr<IMemoryPool> OffsetMemoryPool::duplicate()
{
ARM_COMPUTE_ERROR_ON(!_allocator);
return support::cpp14::make_unique<OffsetMemoryPool>(_allocator, _blob_info);
-} \ No newline at end of file
+}
+} // namespace arm_compute \ No newline at end of file
diff --git a/src/runtime/TensorAllocator.cpp b/src/runtime/TensorAllocator.cpp
index d9616ca09d..dfe239c586 100644
--- a/src/runtime/TensorAllocator.cpp
+++ b/src/runtime/TensorAllocator.cpp
@@ -164,7 +164,7 @@ Status TensorAllocator::import_memory(void *memory)
void TensorAllocator::set_associated_memory_group(MemoryGroup *associated_memory_group)
{
ARM_COMPUTE_ERROR_ON(associated_memory_group == nullptr);
- ARM_COMPUTE_ERROR_ON(_associated_memory_group != nullptr);
+ ARM_COMPUTE_ERROR_ON(_associated_memory_group != nullptr && _associated_memory_group != associated_memory_group);
ARM_COMPUTE_ERROR_ON(_memory.region() != nullptr && _memory.region()->buffer() != nullptr);
_associated_memory_group = associated_memory_group;
diff --git a/tests/validation/NEON/UNIT/DynamicTensor.cpp b/tests/validation/NEON/UNIT/DynamicTensor.cpp
new file mode 100644
index 0000000000..731c6d1650
--- /dev/null
+++ b/tests/validation/NEON/UNIT/DynamicTensor.cpp
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2019 ARM Limited.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include "arm_compute/runtime/Allocator.h"
+#include "arm_compute/runtime/MemoryGroup.h"
+#include "arm_compute/runtime/MemoryManagerOnDemand.h"
+#include "arm_compute/runtime/NEON/functions/NENormalizationLayer.h"
+#include "arm_compute/runtime/OffsetLifetimeManager.h"
+#include "arm_compute/runtime/PoolManager.h"
+#include "support/ToolchainSupport.h"
+#include "tests/AssetsLibrary.h"
+#include "tests/Globals.h"
+#include "tests/NEON/Accessor.h"
+#include "tests/Utils.h"
+#include "tests/framework/Asserts.h"
+#include "tests/framework/Macros.h"
+#include "tests/framework/datasets/Datasets.h"
+#include "tests/validation/fixtures/UNIT/DynamicTensorFixture.h"
+#include <arm_compute/runtime/OffsetMemoryPool.h>
+
+namespace arm_compute
+{
+namespace test
+{
+namespace validation
+{
+TEST_SUITE(NEON)
+TEST_SUITE(UNIT)
+TEST_SUITE(DynamicTensor)
+
+using NEDynamicTensorType3SingleFunction = DynamicTensorType3SingleFunction<Tensor, Accessor, Allocator, OffsetLifetimeManager, PoolManager, MemoryManagerOnDemand, NENormalizationLayer>;
+
+/** Tests the memory manager with dynamic input and output tensors.
+ *
+ * Create and manage the tensors needed to run a simple function. After the function is executed,
+ * change the input and output size requesting more memory and go through the manage/allocate process.
+ * The memory manager should be able to update the inner structures and allocate the requested memory
+ * */
+FIXTURE_DATA_TEST_CASE(DynamicTensorType3Single, NEDynamicTensorType3SingleFunction, framework::DatasetMode::ALL,
+ framework::dataset::zip(framework::dataset::make("Level0Shape", { TensorShape(12U, 11U, 3U), TensorShape(256U, 8U, 12U) }),
+ framework::dataset::make("Level1Shape", { TensorShape(67U, 31U, 15U), TensorShape(11U, 2U, 3U) })))
+{
+ if(input_l0.total_size() < input_l1.total_size())
+ {
+ ARM_COMPUTE_EXPECT(internal_l0.size < internal_l1.size, framework::LogLevel::ERRORS);
+ ARM_COMPUTE_EXPECT(cross_l0.size < cross_l1.size, framework::LogLevel::ERRORS);
+ }
+ else
+ {
+ ARM_COMPUTE_EXPECT(internal_l0.size == internal_l1.size, framework::LogLevel::ERRORS);
+ ARM_COMPUTE_EXPECT(cross_l0.size == cross_l1.size, framework::LogLevel::ERRORS);
+ }
+}
+
+TEST_SUITE_END() // DynamicTensor
+TEST_SUITE_END() // UNIT
+TEST_SUITE_END() // NEON
+} // namespace validation
+} // namespace test
+} // namespace arm_compute
diff --git a/tests/validation/fixtures/UNIT/DynamicTensorFixture.h b/tests/validation/fixtures/UNIT/DynamicTensorFixture.h
new file mode 100644
index 0000000000..df12a4aa30
--- /dev/null
+++ b/tests/validation/fixtures/UNIT/DynamicTensorFixture.h
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2019 ARM Limited.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef ARM_COMPUTE_TEST_UNIT_DYNAMIC_TENSOR
+#define ARM_COMPUTE_TEST_UNIT_DYNAMIC_TENSOR
+
+#include "arm_compute/core/TensorShape.h"
+#include "arm_compute/core/Types.h"
+#include "tests/AssetsLibrary.h"
+#include "tests/Globals.h"
+#include "tests/IAccessor.h"
+#include "tests/framework/Asserts.h"
+#include "tests/framework/Fixture.h"
+#include "tests/validation/Helpers.h"
+#include "tests/validation/reference/NormalizationLayer.h"
+
+namespace arm_compute
+{
+namespace test
+{
+namespace validation
+{
+namespace
+{
+template <typename AllocatorType,
+ typename LifetimeMgrType,
+ typename PoolMgrType,
+ typename MemoryMgrType>
+struct MemoryManagementService
+{
+public:
+ MemoryManagementService()
+ : allocator(), lifetime_mgr(nullptr), pool_mgr(nullptr), mm(nullptr), mg(), num_pools(0)
+ {
+ lifetime_mgr = std::make_shared<LifetimeMgrType>();
+ pool_mgr = std::make_shared<PoolMgrType>();
+ mm = std::make_shared<MemoryMgrType>(lifetime_mgr, pool_mgr);
+ mg = MemoryGroup(mm);
+ }
+
+ void populate(size_t pools)
+ {
+ mm->populate(allocator, pools);
+ num_pools = pools;
+ }
+
+ void clear()
+ {
+ mm->clear();
+ num_pools = 0;
+ }
+
+ void validate(bool validate_finalized) const
+ {
+ ARM_COMPUTE_EXPECT(mm->pool_manager() != nullptr, framework::LogLevel::ERRORS);
+ ARM_COMPUTE_EXPECT(mm->lifetime_manager() != nullptr, framework::LogLevel::ERRORS);
+
+ if(validate_finalized)
+ {
+ ARM_COMPUTE_EXPECT(mm->lifetime_manager()->are_all_finalized(), framework::LogLevel::ERRORS);
+ }
+ ARM_COMPUTE_EXPECT(mm->pool_manager()->num_pools() == num_pools, framework::LogLevel::ERRORS);
+ }
+
+ AllocatorType allocator;
+ std::shared_ptr<LifetimeMgrType> lifetime_mgr;
+ std::shared_ptr<PoolMgrType> pool_mgr;
+ std::shared_ptr<MemoryMgrType> mm;
+ MemoryGroup mg;
+ size_t num_pools;
+};
+} // namespace
+
+/** Simple test case to run a single function with different shapes twice.
+ *
+ * Runs a specified function twice, where the second time the size of the input/output is different
+ * Internal memory of the function and input/output are managed by different services
+ */
+template <typename TensorType,
+ typename AccessorType,
+ typename AllocatorType,
+ typename LifetimeMgrType,
+ typename PoolMgrType,
+ typename MemoryManagerType,
+ typename NormalizationFunctionType>
+class DynamicTensorType3SingleFunction : public framework::Fixture
+{
+ using T = float;
+ using MemoryManagementServiceType = MemoryManagementService<AllocatorType, LifetimeMgrType, PoolMgrType, MemoryManagerType>;
+
+public:
+ template <typename...>
+ void setup(TensorShape input_level0, TensorShape input_level1)
+ {
+ input_l0 = input_level0;
+ input_l1 = input_level1;
+ run();
+ }
+
+protected:
+ void run()
+ {
+ MemoryManagementServiceType serv_internal;
+ MemoryManagementServiceType serv_cross;
+ const size_t num_pools = 1;
+ const bool validate_finalized = true;
+
+ // Create Tensor shapes.
+ TensorShape level_0 = TensorShape(input_l0);
+ TensorShape level_1 = TensorShape(input_l1);
+
+ // Level 0
+ // Create tensors
+ TensorType src = create_tensor<Tensor>(level_0, DataType::F32, 1);
+ TensorType dst = create_tensor<Tensor>(level_0, DataType::F32, 1);
+
+ serv_cross.mg.manage(&src);
+ serv_cross.mg.manage(&dst);
+
+ // Create and configure function
+ NormalizationFunctionType norm_layer(serv_internal.mm);
+ norm_layer.configure(&src, &dst, NormalizationLayerInfo(NormType::CROSS_MAP, 3));
+
+ ARM_COMPUTE_EXPECT(src.info()->is_resizable(), framework::LogLevel::ERRORS);
+ ARM_COMPUTE_EXPECT(dst.info()->is_resizable(), framework::LogLevel::ERRORS);
+
+ // Allocate tensors
+ src.allocator()->allocate();
+ dst.allocator()->allocate();
+
+ ARM_COMPUTE_EXPECT(!src.info()->is_resizable(), framework::LogLevel::ERRORS);
+ ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
+
+ // Populate and validate memory manager
+ serv_cross.populate(num_pools);
+ serv_internal.populate(num_pools);
+ serv_cross.validate(validate_finalized);
+ serv_internal.validate(validate_finalized);
+
+ // Extract lifetime manager meta-data information
+ internal_l0 = serv_internal.lifetime_mgr->info();
+ cross_l0 = serv_cross.lifetime_mgr->info();
+
+ // Acquire memory manager, fill tensors and compute functions
+ serv_cross.mg.acquire();
+ arm_compute::test::library->fill_tensor_value(Accessor(src), 12.f);
+ norm_layer.run();
+ serv_cross.mg.release();
+
+ // Clear manager
+ serv_cross.clear();
+ serv_internal.clear();
+ serv_cross.validate(validate_finalized);
+ serv_internal.validate(validate_finalized);
+
+ // Level 1
+ // Update the tensor shapes
+ src.info()->set_tensor_shape(level_1);
+ dst.info()->set_tensor_shape(level_1);
+ src.info()->set_is_resizable(true);
+ dst.info()->set_is_resizable(true);
+
+ serv_cross.mg.manage(&src);
+ serv_cross.mg.manage(&dst);
+
+ // Re-configure the function
+ norm_layer.configure(&src, &dst, NormalizationLayerInfo(NormType::CROSS_MAP, 3));
+
+ // Allocate tensors
+ src.allocator()->allocate();
+ dst.allocator()->allocate();
+
+ // Populate and validate memory manager
+ serv_cross.populate(num_pools);
+ serv_internal.populate(num_pools);
+ serv_cross.validate(validate_finalized);
+ serv_internal.validate(validate_finalized);
+
+ // Extract lifetime manager meta-data information
+ internal_l1 = serv_internal.lifetime_mgr->info();
+ cross_l1 = serv_cross.lifetime_mgr->info();
+
+ // Compute functions
+ serv_cross.mg.acquire();
+ arm_compute::test::library->fill_tensor_value(AccessorType(src), 12.f);
+ norm_layer.run();
+ serv_cross.mg.release();
+
+ // Clear manager
+ serv_cross.clear();
+ serv_internal.clear();
+ serv_cross.validate(validate_finalized);
+ serv_internal.validate(validate_finalized);
+ }
+
+public:
+ TensorShape input_l0{}, input_l1{};
+ typename LifetimeMgrType::info_type internal_l0{}, internal_l1{};
+ typename LifetimeMgrType::info_type cross_l0{}, cross_l1{};
+};
+} // namespace validation
+} // namespace test
+} // namespace arm_compute
+#endif /* ARM_COMPUTE_TEST_UNIT_DYNAMIC_TENSOR */