blob: 1562c9f837a4645f766e6fe6f725f8dd0ed83149 [file] [log] [blame]
//
// Copyright © 2023 Arm Ltd and Contributors. All rights reserved.
// SPDX-License-Identifier: MIT
//
#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
#include <doctest/doctest.h>
#include <opaque/include/armnn_delegate.hpp>
#include <tensorflow/lite/kernels/builtin_op_kernels.h>
#include <tensorflow/lite/interpreter.h>
#include <tensorflow/lite/kernels/register.h>
#include "tensorflow/lite/core/c/builtin_op_data.h"
namespace armnnOpaqueDelegate
{
TEST_SUITE("ArmnnOpaqueDelegate")
{
TEST_CASE ("ArmnnOpaqueDelegate_Registered")
{
using namespace tflite;
auto tfLiteInterpreter = std::make_unique<Interpreter>();
tfLiteInterpreter->AddTensors(3);
tfLiteInterpreter->SetInputs({0, 1});
tfLiteInterpreter->SetOutputs({2});
tfLiteInterpreter->SetTensorParametersReadWrite(0, kTfLiteFloat32, "input1", {1,2,2,1}, TfLiteQuantization());
tfLiteInterpreter->SetTensorParametersReadWrite(1, kTfLiteFloat32, "input2", {1,2,2,1}, TfLiteQuantization());
tfLiteInterpreter->SetTensorParametersReadWrite(2, kTfLiteFloat32, "output", {1,2,2,1}, TfLiteQuantization());
TfLiteAddParams* addParams = reinterpret_cast<TfLiteAddParams*>(malloc(sizeof(TfLiteAddParams)));
addParams->activation = kTfLiteActNone;
addParams->pot_scale_int16 = false;
tflite::ops::builtin::BuiltinOpResolver opResolver;
const TfLiteRegistration* opRegister = opResolver.FindOp(BuiltinOperator_ADD, 1);
tfLiteInterpreter->AddNodeWithParameters({0, 1}, {2}, "", 0, addParams, opRegister);
// Create the Armnn Delegate
std::vector<armnn::BackendId> backends = { armnn::Compute::CpuRef };
std::vector<armnn::BackendOptions> backendOptions;
backendOptions.emplace_back(
armnn::BackendOptions{ "BackendName",
{
{ "Option1", 42 },
{ "Option2", true }
}}
);
armnnDelegate::DelegateOptions delegateOptions(backends, backendOptions);
std::unique_ptr<TfLiteDelegate, decltype(&armnnOpaqueDelegate::TfLiteArmnnOpaqueDelegateDelete)>
theArmnnDelegate(armnnOpaqueDelegate::TfLiteArmnnOpaqueDelegateCreate(delegateOptions),
armnnOpaqueDelegate::TfLiteArmnnOpaqueDelegateDelete);
auto status = tfLiteInterpreter->ModifyGraphWithDelegate(std::move(theArmnnDelegate));
CHECK(status == kTfLiteOk);
CHECK(tfLiteInterpreter != nullptr);
}
TEST_CASE ("ArmnnOpaqueDelegate_OptimizerOptionsRegistered")
{
using namespace tflite;
auto tfLiteInterpreter = std::make_unique<Interpreter>();
tfLiteInterpreter->AddTensors(3);
tfLiteInterpreter->SetInputs({0, 1});
tfLiteInterpreter->SetOutputs({2});
tfLiteInterpreter->SetTensorParametersReadWrite(0, kTfLiteFloat32, "input1", {1,2,2,1}, TfLiteQuantization());
tfLiteInterpreter->SetTensorParametersReadWrite(1, kTfLiteFloat32, "input2", {1,2,2,1}, TfLiteQuantization());
tfLiteInterpreter->SetTensorParametersReadWrite(2, kTfLiteFloat32, "output", {1,2,2,1}, TfLiteQuantization());
TfLiteAddParams* addParams = reinterpret_cast<TfLiteAddParams*>(malloc(sizeof(TfLiteAddParams)));
addParams->activation = kTfLiteActNone;
addParams->pot_scale_int16 = false;
tflite::ops::builtin::BuiltinOpResolver opResolver;
const TfLiteRegistration* opRegister = opResolver.FindOp(BuiltinOperator_ADD, 1);
tfLiteInterpreter->AddNodeWithParameters({0, 1}, {2}, "", 0, addParams, opRegister);
// Create the Armnn Delegate
std::vector<armnn::BackendId> backends = { armnn::Compute::CpuRef };
armnn::OptimizerOptionsOpaque optimizerOptions(true, true, false, true);
armnnDelegate::DelegateOptions delegateOptions(backends, optimizerOptions);
std::unique_ptr<TfLiteDelegate, decltype(&armnnOpaqueDelegate::TfLiteArmnnOpaqueDelegateDelete)>
theArmnnDelegate(armnnOpaqueDelegate::TfLiteArmnnOpaqueDelegateCreate(delegateOptions),
armnnOpaqueDelegate::TfLiteArmnnOpaqueDelegateDelete);
auto status = tfLiteInterpreter->ModifyGraphWithDelegate(std::move(theArmnnDelegate));
CHECK(status == kTfLiteOk);
CHECK(tfLiteInterpreter != nullptr);
}
TEST_CASE ("DelegateOptions_OpaqueDelegateDefault")
{
// Check default options can be created
auto options = armnnOpaqueDelegate::TfLiteArmnnDelegateOptionsDefault();
armnnOpaqueDelegate::ArmnnOpaqueDelegate delegate(options);
// Check version returns correctly
auto version = delegate.GetVersion();
CHECK_EQ(version, OPAQUE_DELEGATE_VERSION);
auto* builder = delegate.GetDelegateBuilder();
CHECK(builder);
// Check Opaque delegate created
auto opaqueDelegate = armnnOpaqueDelegate::TfLiteArmnnOpaqueDelegateCreate(options);
CHECK(opaqueDelegate);
// Check Opaque Delegate can be deleted
CHECK(opaqueDelegate->opaque_delegate_builder->data);
armnnOpaqueDelegate::TfLiteArmnnOpaqueDelegateDelete(opaqueDelegate);
}
TEST_CASE ("DelegatePluginTest")
{
const char* backends = "CpuRef";
bool fastmath = false;
const char* additional_parameters = "allow-expanded-dims=true";
flatbuffers::FlatBufferBuilder flatbuffer_builder;
flatbuffers::Offset<tflite::ArmNNSettings>
armnn_settings_offset = tflite::CreateArmNNSettingsDirect(flatbuffer_builder,
backends,
fastmath,
additional_parameters);
tflite::TFLiteSettingsBuilder tflite_settings_builder(flatbuffer_builder);
tflite_settings_builder.add_armnn_settings(armnn_settings_offset);
flatbuffers::Offset<tflite::TFLiteSettings> tflite_settings_offset = tflite_settings_builder.Finish();
flatbuffer_builder.Finish(tflite_settings_offset);
const tflite::TFLiteSettings* tflite_settings = flatbuffers::GetRoot<tflite::TFLiteSettings>(
flatbuffer_builder.GetBufferPointer());
std::unique_ptr<tflite::delegates::DelegatePluginInterface> delegatePlugin =
tflite::delegates::DelegatePluginRegistry::CreateByName("armnn_delegate", *tflite_settings);
// Plugin is created correctly using armnn_delegate name.
CHECK((delegatePlugin != nullptr));
tflite::delegates::TfLiteDelegatePtr armnnDelegate = delegatePlugin->Create();
// Armnn Opaque Delegate is created correctly.
CHECK((armnnDelegate != nullptr));
CHECK((armnnDelegate->opaque_delegate_builder != nullptr));
}
armnnDelegate::DelegateOptions BuildDelegateOptions(const char* backends,
bool fastmath,
const char* additional_parameters)
{
flatbuffers::FlatBufferBuilder flatbuffer_builder;
flatbuffers::Offset<tflite::ArmNNSettings>
armnn_settings_offset = tflite::CreateArmNNSettingsDirect(flatbuffer_builder,
backends,
fastmath,
additional_parameters);
tflite::TFLiteSettingsBuilder tflite_settings_builder(flatbuffer_builder);
tflite_settings_builder.add_armnn_settings(armnn_settings_offset);
flatbuffers::Offset<tflite::TFLiteSettings> tflite_settings_offset = tflite_settings_builder.Finish();
flatbuffer_builder.Finish(tflite_settings_offset);
const tflite::TFLiteSettings* tflite_settings = flatbuffers::GetRoot<tflite::TFLiteSettings>(
flatbuffer_builder.GetBufferPointer());
armnnDelegate::DelegateOptions delegateOptions = ParseArmNNSettings(tflite_settings);
return delegateOptions;
}
unsigned int CountBackendOptions(armnn::BackendId backendId,
armnnDelegate::DelegateOptions& delegateOptions,
bool runtime = false)
{
unsigned int count = 0;
std::vector<armnn::BackendOptions> modelOptions = runtime ? delegateOptions.GetRuntimeOptions().m_BackendOptions
: delegateOptions.GetOptimizerOptions().GetModelOptions();
for (const auto& backendOptions : modelOptions)
{
if (backendOptions.GetBackendId() == backendId)
{
count = backendOptions.GetOptionCount();
}
}
return count;
}
bool GetBackendOption(armnn::BackendId backendId,
armnnDelegate::DelegateOptions& delegateOptions,
std::string& optionName,
armnn::BackendOptions::BackendOption& backendOption,
bool runtime = false)
{
bool result = false;
std::vector<armnn::BackendOptions> modelOptions = runtime ? delegateOptions.GetRuntimeOptions().m_BackendOptions
: delegateOptions.GetOptimizerOptions().GetModelOptions();
for (const auto& backendOptions : modelOptions)
{
if (backendOptions.GetBackendId() == backendId)
{
for (size_t i = 0; i < backendOptions.GetOptionCount(); ++i)
{
const armnn::BackendOptions::BackendOption& option = backendOptions.GetOption(i);
if (option.GetName() == optionName)
{
backendOption = option;
result = true;
break;
}
}
}
}
return result;
}
TEST_CASE ("ParseArmNNSettings_backend")
{
{
armnnDelegate::DelegateOptions delegateOptions = BuildDelegateOptions("CpuRef,GpuAcc", false, nullptr);
std::vector<armnn::BackendId> expectedBackends = {"CpuRef", "GpuAcc"};
CHECK_EQ(expectedBackends, delegateOptions.GetBackends());
}
{
armnnDelegate::DelegateOptions delegateOptions = BuildDelegateOptions("GpuAcc", false, nullptr);
std::vector<armnn::BackendId> expectedBackends = {"GpuAcc"};
CHECK_EQ(expectedBackends, delegateOptions.GetBackends());
}
}
TEST_CASE ("ParseArmNNSettings_fastmath")
{
// Test fastmath true in both backends
{
armnnDelegate::DelegateOptions delegateOptions = BuildDelegateOptions("CpuAcc,GpuAcc", true, nullptr);
std::vector<armnn::BackendId> expectedBackends = {"CpuAcc", "GpuAcc"};
CHECK_EQ(expectedBackends, delegateOptions.GetBackends());
CHECK_EQ(CountBackendOptions(armnn::Compute::CpuAcc, delegateOptions), 1);
CHECK_EQ(CountBackendOptions(armnn::Compute::CpuAcc, delegateOptions), 1);
armnn::BackendOptions::BackendOption backendOption("", false);
std::string optionName = "FastMathEnabled";
CHECK_EQ(GetBackendOption(armnn::Compute::CpuAcc, delegateOptions, optionName, backendOption), true);
CHECK_EQ(backendOption.GetValue().AsBool(), true);
CHECK_EQ(backendOption.GetName(), optionName);
CHECK_EQ(GetBackendOption(armnn::Compute::GpuAcc, delegateOptions, optionName, backendOption), true);
CHECK_EQ(backendOption.GetValue().AsBool(), true);
CHECK_EQ(backendOption.GetName(), optionName);
}
// Test fastmath true in one backend
{
armnnDelegate::DelegateOptions delegateOptions = BuildDelegateOptions("CpuAcc,CpuRef", true, nullptr);
std::vector<armnn::BackendId> expectedBackends = {"CpuAcc", "CpuRef"};
CHECK_EQ(expectedBackends, delegateOptions.GetBackends());
CHECK_EQ(CountBackendOptions(armnn::Compute::CpuAcc, delegateOptions), 1);
CHECK_EQ(CountBackendOptions(armnn::Compute::CpuRef, delegateOptions), 0);
armnn::BackendOptions::BackendOption backendOption("", false);
std::string optionName = "FastMathEnabled";
CHECK_EQ(GetBackendOption(armnn::Compute::CpuAcc, delegateOptions, optionName, backendOption), true);
CHECK_EQ(backendOption.GetValue().AsBool(), true);
CHECK_EQ(backendOption.GetName(), optionName);
CHECK_EQ(GetBackendOption(armnn::Compute::CpuRef, delegateOptions, optionName, backendOption), false);
}
// Test fastmath false
{
armnnDelegate::DelegateOptions delegateOptions = BuildDelegateOptions("GpuAcc", false, nullptr);
std::vector<armnn::BackendId> expectedBackends = {"GpuAcc"};
CHECK_EQ(expectedBackends, delegateOptions.GetBackends());
CHECK_EQ(CountBackendOptions(armnn::Compute::GpuAcc, delegateOptions), 1);
armnn::BackendOptions::BackendOption backendOption("", false);
std::string optionName = "FastMathEnabled";
CHECK_EQ(GetBackendOption(armnn::Compute::GpuAcc, delegateOptions, optionName, backendOption), true);
CHECK_EQ(backendOption.GetValue().AsBool(), false);
CHECK_EQ(backendOption.GetName(), optionName);
}
}
TEST_CASE ("ParseArmNNSettings_additional_options_raw")
{
const char* backends = "GpuAcc";
bool fastmath = false;
const char* additional_parameters = "allow-expanded-dims=true";
flatbuffers::FlatBufferBuilder flatbuffer_builder;
flatbuffers::Offset<tflite::ArmNNSettings>
armnn_settings_offset = tflite::CreateArmNNSettingsDirect(flatbuffer_builder,
backends,
fastmath,
additional_parameters);
tflite::TFLiteSettingsBuilder tflite_settings_builder(flatbuffer_builder);
tflite_settings_builder.add_armnn_settings(armnn_settings_offset);
flatbuffers::Offset<tflite::TFLiteSettings> tflite_settings_offset = tflite_settings_builder.Finish();
flatbuffer_builder.Finish(tflite_settings_offset);
const tflite::TFLiteSettings* tflite_settings = flatbuffers::GetRoot<tflite::TFLiteSettings>(
flatbuffer_builder.GetBufferPointer());
CHECK((tflite_settings->armnn_settings()->additional_parameters() != nullptr));
CHECK_EQ(tflite_settings->armnn_settings()->additional_parameters()->str(), additional_parameters);
armnnDelegate::DelegateOptions delegateOptions = ParseArmNNSettings(tflite_settings);
CHECK_EQ(delegateOptions.GetOptimizerOptions().GetAllowExpandedDims(), true);
}
TEST_CASE ("ParseArmNNSettings_additional_options")
{
std::string options = "number-of-threads=29," // optimizer-backend option only Cpu
"gpu-kernel-profiling-enabled=true," // runtime-backend option only GPU
"allow-expanded-dims=true," // optimizer option
"logging-severity=debug," // option
"counter-capture-period=100u"; // runtime-profiling option
armnnDelegate::DelegateOptions delegateOptions = BuildDelegateOptions("CpuAcc,GpuAcc", false, options.c_str());
// Variables to be used in all checks
armnn::BackendOptions::BackendOption backendOption("", false);
std::string optionName;
// number-of-threads
CHECK_EQ(CountBackendOptions(armnn::Compute::CpuAcc, delegateOptions), 1);
optionName = "NumberOfThreads";
CHECK_EQ(GetBackendOption(armnn::Compute::CpuAcc, delegateOptions, optionName, backendOption), true);
CHECK_EQ(backendOption.GetValue().AsUnsignedInt(), 29);
CHECK_EQ(backendOption.GetName(), optionName);
// gpu-kernel-profiling-enabled
CHECK_EQ(CountBackendOptions(armnn::Compute::GpuAcc, delegateOptions, true), 1);
optionName = "KernelProfilingEnabled";
CHECK_EQ(GetBackendOption(armnn::Compute::GpuAcc, delegateOptions, optionName, backendOption, true), true);
CHECK_EQ(backendOption.GetValue().AsBool(), true);
CHECK_EQ(backendOption.GetName(), optionName);
// allow-expanded-dims
CHECK_EQ(delegateOptions.GetOptimizerOptions().GetAllowExpandedDims(), true);
// logging-severity
CHECK_EQ(delegateOptions.GetLoggingSeverity(), armnn::LogSeverity::Debug);
// counter-capture-period
CHECK_EQ(delegateOptions.GetRuntimeOptions().m_ProfilingOptions.m_CapturePeriod, 100);
}
TEST_CASE ("ParseArmNNSettings_additional_options_regex")
{
std::string options = "allow-expanded-dims= true, " // optimizer option
"number-of-threads =29 ," // optimizer-backend option only Cpu
"logging-severity = trace , " // option
"counter-capture-period = 100u"; // runtime-profiling option
armnnDelegate::DelegateOptions delegateOptions = BuildDelegateOptions("GpuAcc", false, options.c_str());
// Variables to be used in all checks
armnn::BackendOptions::BackendOption backendOption("", false);
std::string optionName;
std::vector<armnn::BackendId> expectedBackends = {"GpuAcc"};
CHECK_EQ(expectedBackends, delegateOptions.GetBackends());
// enable-fast-math
CHECK_EQ(CountBackendOptions(armnn::Compute::GpuAcc, delegateOptions), 1);
optionName = "FastMathEnabled";
CHECK_EQ(GetBackendOption(armnn::Compute::CpuRef, delegateOptions, optionName, backendOption), false);
CHECK_EQ(GetBackendOption(armnn::Compute::CpuAcc, delegateOptions, optionName, backendOption), false);
CHECK_EQ(GetBackendOption(armnn::Compute::GpuAcc, delegateOptions, optionName, backendOption), true);
CHECK_EQ(backendOption.GetValue().AsBool(), false);
CHECK_EQ(backendOption.GetName(), optionName);
// allow-expanded-dims
CHECK_EQ(delegateOptions.GetOptimizerOptions().GetAllowExpandedDims(), true);
// number-of-threads not saved anywhere, as it is a parameter only valid for CpuAcc
optionName="number-of-threads";
CHECK_EQ(GetBackendOption(armnn::Compute::CpuAcc, delegateOptions, optionName, backendOption), false);
CHECK_EQ(GetBackendOption(armnn::Compute::GpuAcc, delegateOptions, optionName, backendOption), false);
// logging-severity
CHECK_EQ(delegateOptions.GetLoggingSeverity(), armnn::LogSeverity::Trace);
// counter-capture-period
CHECK_EQ(delegateOptions.GetRuntimeOptions().m_ProfilingOptions.m_CapturePeriod, 100);
}
TEST_CASE ("ParseArmNNSettings_additional_options_incorrect")
{
std::string options = "number-of-thread=29"; // The correct one would be "number-of-threads" in plural
CHECK_THROWS(BuildDelegateOptions("CpuAcc,GpuAcc", false, options.c_str()));
}
}
} // namespace armnnDelegate