//
// Copyright © 2021 Arm Ltd and Contributors. All rights reserved.
// SPDX-License-Identifier: MIT
//

#include <armnn/backends/ICustomAllocator.hpp>
#include <armnn/Descriptors.hpp>
#include <armnn/Exceptions.hpp>
#include <armnn/IRuntime.hpp>
#include <armnn/backends/TensorHandle.hpp>
// Requires the OpenCl backend to be included (GpuAcc)
#include <cl/ClBackend.hpp>
#include <doctest/doctest.h>
#include <backendsCommon/DefaultAllocator.hpp>
#include <backendsCommon/test/MockBackend.hpp>
#include <cl/ClBackendDefaultAllocator.hpp>

using namespace armnn;


namespace
{

TEST_SUITE("DefaultAllocatorTests")
{

TEST_CASE("DefaultAllocatorTest")
{
    float number = 3;

    TensorInfo inputTensorInfo(TensorShape({1, 1}), DataType::Float32);

    // Create ArmNN runtime
    IRuntime::CreationOptions options; // default options
    auto customAllocator = std::make_shared<DefaultAllocator>();
    options.m_CustomAllocatorMap = {{"GpuAcc", std::move(customAllocator)}};
    IRuntimePtr run = IRuntime::Create(options);

    // Creates structures for input & output
    unsigned int numElements = inputTensorInfo.GetNumElements();
    size_t totalBytes = numElements * sizeof(float);

    void* alignedInputPtr = options.m_CustomAllocatorMap["GpuAcc"]->allocate(totalBytes, 0);

    auto* inputPtr = reinterpret_cast<float*>(alignedInputPtr);
    std::fill_n(inputPtr, numElements, number);
    CHECK(inputPtr[0] == 3);

    auto& backendRegistry = armnn::BackendRegistryInstance();
    backendRegistry.DeregisterAllocator(ClBackend::GetIdStatic());
}

TEST_CASE("DefaultAllocatorTestMulti")
{
    float number = 3;

    TensorInfo inputTensorInfo(TensorShape({2, 1}), DataType::Float32);

    // Create ArmNN runtime
    IRuntime::CreationOptions options; // default options
    auto customAllocator = std::make_shared<DefaultAllocator>();
    options.m_CustomAllocatorMap = {{"GpuAcc", std::move(customAllocator)}};
    IRuntimePtr run = IRuntime::Create(options);

    // Creates structures for input & output
    unsigned int numElements = inputTensorInfo.GetNumElements();
    size_t totalBytes = numElements * sizeof(float);

    void* alignedInputPtr = options.m_CustomAllocatorMap["GpuAcc"]->allocate(totalBytes, 0);
    void* alignedInputPtr2 = options.m_CustomAllocatorMap["GpuAcc"]->allocate(totalBytes, 0);

    auto* inputPtr = reinterpret_cast<float*>(alignedInputPtr);
    std::fill_n(inputPtr, numElements, number);
    CHECK(inputPtr[0] == 3);
    CHECK(inputPtr[1] == 3);

    auto* inputPtr2 = reinterpret_cast<float*>(alignedInputPtr2);
    std::fill_n(inputPtr2, numElements, number);
    CHECK(inputPtr2[0] == 3);
    CHECK(inputPtr2[1] == 3);

    // No overlap
    CHECK(inputPtr[0] == 3);
    CHECK(inputPtr[1] == 3);

    auto& backendRegistry = armnn::BackendRegistryInstance();
    backendRegistry.DeregisterAllocator(ClBackend::GetIdStatic());
}

TEST_CASE("DefaultAllocatorTestMock")
{
    // Create ArmNN runtime
    IRuntime::CreationOptions options; // default options
    IRuntimePtr run = IRuntime::Create(options);

    // Initialize Mock Backend
    MockBackendInitialiser initialiser;
    auto factoryFun = BackendRegistryInstance().GetFactory(MockBackend().GetIdStatic());
    ARMNN_ASSERT(factoryFun != nullptr);
    auto backend = factoryFun();
    auto defaultAllocator = backend->GetDefaultAllocator();

    // GetMemorySourceType
    CHECK(defaultAllocator->GetMemorySourceType() == MemorySource::Malloc);

    size_t totalBytes = 1 * sizeof(float);
    // Allocate
    void* ptr = defaultAllocator->allocate(totalBytes, 0);

    // GetMemoryRegionAtOffset
    CHECK(defaultAllocator->GetMemoryRegionAtOffset(ptr, 0, 0));

    // Free
    defaultAllocator->free(ptr);

    // Clean up
    auto& backendRegistry = armnn::BackendRegistryInstance();
    backendRegistry.Deregister(MockBackend().GetIdStatic());
    backendRegistry.DeregisterAllocator(ClBackend::GetIdStatic());
}

}


TEST_SUITE("ClDefaultAllocatorTests")
{

TEST_CASE("ClDefaultAllocatorTest")
{
    float number = 3;

    TensorInfo inputTensorInfo(TensorShape({1, 1}), DataType::Float32);

    // Create ArmNN runtime
    IRuntime::CreationOptions options; // default options
    auto customAllocator = std::make_shared<ClBackendDefaultAllocator>();
    options.m_CustomAllocatorMap = {{"GpuAcc", std::move(customAllocator)}};
    IRuntimePtr run = IRuntime::Create(options);

    // Creates structures for input & output
    unsigned int numElements = inputTensorInfo.GetNumElements();
    size_t totalBytes = numElements * sizeof(float);

    void* alignedInputPtr = options.m_CustomAllocatorMap["GpuAcc"]->allocate(totalBytes, 0);

    auto* inputPtr = reinterpret_cast<float*>(alignedInputPtr);
    std::fill_n(inputPtr, numElements, number);
    CHECK(inputPtr[0] == 3);

    auto& backendRegistry = armnn::BackendRegistryInstance();
    backendRegistry.DeregisterAllocator(ClBackend::GetIdStatic());
}

TEST_CASE("ClDefaultAllocatorTestMulti")
{
    float number = 3;

    TensorInfo inputTensorInfo(TensorShape({2, 1}), DataType::Float32);

    // Create ArmNN runtime
    IRuntime::CreationOptions options; // default options
    auto customAllocator = std::make_shared<ClBackendDefaultAllocator>();
    options.m_CustomAllocatorMap = {{"GpuAcc", std::move(customAllocator)}};
    IRuntimePtr run = IRuntime::Create(options);

    // Creates structures for input & output
    unsigned int numElements = inputTensorInfo.GetNumElements();
    size_t totalBytes = numElements * sizeof(float);

    void* alignedInputPtr = options.m_CustomAllocatorMap["GpuAcc"]->allocate(totalBytes, 0);
    void* alignedInputPtr2 = options.m_CustomAllocatorMap["GpuAcc"]->allocate(totalBytes, 0);

    auto* inputPtr = reinterpret_cast<float*>(alignedInputPtr);
    std::fill_n(inputPtr, numElements, number);
    CHECK(inputPtr[0] == 3);
    CHECK(inputPtr[1] == 3);

    auto* inputPtr2 = reinterpret_cast<float*>(alignedInputPtr2);
    std::fill_n(inputPtr2, numElements, number);
    CHECK(inputPtr2[0] == 3);
    CHECK(inputPtr2[1] == 3);

    // No overlap
    CHECK(inputPtr[0] == 3);
    CHECK(inputPtr[1] == 3);

    auto& backendRegistry = armnn::BackendRegistryInstance();
    backendRegistry.DeregisterAllocator(ClBackend::GetIdStatic());
}

}

} // namespace armnn