aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Eilers <jan.eilers@arm.com>2021-10-26 16:57:34 +0100
committerJan Eilers <jan.eilers@arm.com>2021-11-02 11:49:32 +0000
commitf39f8d8597c59057118f67cacf70d246f95fea9b (patch)
tree35c6f5b1b641a143d29e1ce478877f9e2b251569
parent32c7527df494a99a97283fe09580671e10f8d398 (diff)
downloadarmnn-f39f8d8597c59057118f67cacf70d246f95fea9b.tar.gz
Move command line parsing in external delegate to DelegateOptions
* Moves the creation of a DelegateOption object from armnn_external_delegate to DelegateOptions. * This allows this code to be reused elsewhere * Allow boolean values of DelegateOptions to be passed as strings e.g. 'true' or 'false' * Add unit tests Signed-off-by: Jan Eilers <jan.eilers@arm.com> Change-Id: I0ada17f511027dd3f47a85142cae346464682f5a
-rw-r--r--delegate/include/DelegateOptions.hpp135
-rw-r--r--delegate/src/DelegateOptions.cpp187
-rw-r--r--delegate/src/armnn_external_delegate.cpp318
-rw-r--r--delegate/src/test/DelegateOptionsTest.cpp84
-rw-r--r--include/armnn/utility/StringUtils.hpp44
-rw-r--r--src/armnn/test/UtilityTests.cpp29
6 files changed, 484 insertions, 313 deletions
diff --git a/delegate/include/DelegateOptions.hpp b/delegate/include/DelegateOptions.hpp
index 24a2e5c597..5bc2e59070 100644
--- a/delegate/include/DelegateOptions.hpp
+++ b/delegate/include/DelegateOptions.hpp
@@ -37,6 +37,141 @@ public:
const armnn::Optional<armnn::LogSeverity>& logSeverityLevel = armnn::EmptyOptional(),
const armnn::Optional<armnn::DebugCallbackFunction>& func = armnn::EmptyOptional());
+
+ /**
+ * This constructor processes delegate options in form of command line arguments.
+ * It works in conjunction with the TfLite external delegate plugin.
+ *
+ * Available options:
+ *
+ * Option key: "backends" \n
+ * Possible values: ["EthosNPU"/"GpuAcc"/"CpuAcc"/"CpuRef"] \n
+ * Descriptions: A comma separated list without whitespaces of
+ * backends which should be used for execution. Falls
+ * back to next backend in list if previous doesn't
+ * provide support for operation. e.g. "GpuAcc,CpuAcc"
+ *
+ * Option key: "dynamic-backends-path" \n
+ * Possible values: [filenameString] \n
+ * Descriptions: This is the directory that will be searched for any dynamic backends.
+ *
+ * Option key: "logging-severity" \n
+ * Possible values: ["trace"/"debug"/"info"/"warning"/"error"/"fatal"] \n
+ * Description: Sets the logging severity level for ArmNN. Logging
+ * is turned off if this option is not provided.
+ *
+ * Option key: "gpu-tuning-level" \n
+ * Possible values: ["0"/"1"/"2"/"3"] \n
+ * Description: 0=UseOnly(default), 1=RapidTuning, 2=NormalTuning,
+ * 3=ExhaustiveTuning. Requires option gpu-tuning-file.
+ * 1,2 and 3 will create a tuning-file, 0 will apply the
+ * tunings from an existing file
+ *
+ * Option key: "gpu-mlgo-tuning-file" \n
+ * Possible values: [filenameString] \n
+ * Description: File name for the MLGO tuning file
+ *
+ * Option key: "gpu-tuning-file" \n
+ * Possible values: [filenameString] \n
+ * Description: File name for the tuning file.
+ *
+ * Option key: "gpu-enable-profiling" \n
+ * Possible values: ["true"/"false"] \n
+ * Description: Enables GPU profiling
+ *
+ * Option key: "gpu-kernel-profiling-enabled" \n
+ * Possible values: ["true"/"false"] \n
+ * Description: Enables GPU kernel profiling
+ *
+ * Option key: "save-cached-network" \n
+ * Possible values: ["true"/"false"] \n
+ * Description: Enables saving of the cached network to a file,
+ * specified with the cached-network-filepath option
+ *
+ * Option key: "cached-network-filepath" \n
+ * Possible values: [filenameString] \n
+ * Description: If non-empty, the given file will be used to load/save the cached network.
+ * If save-cached-network is given then the cached network will be saved to the given file.
+ * To save the cached network a file must already exist.
+ * If save-cached-network is not given then the cached network will be loaded from the given file.
+ * This will remove initial compilation time of kernels and speed up the first execution.
+ *
+ * Option key: "enable-fast-math" \n
+ * Possible values: ["true"/"false"] \n
+ * Description: Enables fast_math options in backends that support it
+ *
+ * Option key: "number-of-threads" \n
+ * Possible values: ["1"-"64"] \n
+ * Description: Assign the number of threads used by the CpuAcc backend.
+ * Default is set to 0 (Backend will decide number of threads to use).
+ *
+ * Option key: "reduce-fp32-to-fp16" \n
+ * Possible values: ["true"/"false"] \n
+ * Description: Reduce Fp32 data to Fp16 for faster processing
+ *
+ * Option key: "reduce-fp32-to-bf16" \n
+ * Possible values: ["true"/"false"] \n
+ * Description: Reduce Fp32 data to Bf16 for faster processing
+ *
+ * Option key: "debug-data" \n
+ * Possible values: ["true"/"false"] \n
+ * Description: Add debug data for easier troubleshooting
+ *
+ * Option key: "memory-import" \n
+ * Possible values: ["true"/"false"] \n
+ * Description: Enable memory import
+ *
+ * Option key: "enable-internal-profiling" \n
+ * Possible values: ["true"/"false"] \n
+ * Description: Enable the internal profiling feature.
+ *
+ * Option key: "internal-profiling-detail" \n
+ * Possible values: [1/2] \n
+ * Description: Set the detail on the internal profiling. 1 = DetailsWithEvents, 2 = DetailsOnly.
+ *
+ * Option key: "enable-external-profiling" \n
+ * Possible values: ["true"/"false"] \n
+ * Description: Enable the external profiling feature.
+ *
+ * Option key: "timeline-profiling" \n
+ * Possible values: ["true"/"false"] \n
+ * Description: Indicates whether external timeline profiling is enabled or not.
+ *
+ * Option key: "outgoing-capture-file" \n
+ * Possible values: [filenameString] \n
+ * Description: Path to a file in which outgoing timeline profiling messages will be stored.
+ *
+ * Option key: "incoming-capture-file" \n
+ * Possible values: [filenameString] \n
+ * Description: Path to a file in which incoming timeline profiling messages will be stored.
+ *
+ * Option key: "file-only-external-profiling" \n
+ * Possible values: ["true"/"false"] \n
+ * Description: Enable profiling output to file only.
+ *
+ * Option key: "counter-capture-period" \n
+ * Possible values: Integer, Default is 10000u
+ * Description: Value in microseconds of the profiling capture period. \n
+ *
+ * Option key: "profiling-file-format" \n
+ * Possible values: String of ["binary"] \n
+ * Description: The format of the file used for outputting profiling data. Currently on "binary" is supported.
+ *
+ * Option key: "serialize-to-dot" \n
+ * Possible values: [filenameString] \n
+ * Description: Serialize the optimized network to the file specified in "dot" format.
+ *
+ * @param[in] option_keys Delegate option names
+ * @param[in] options_values Delegate option values
+ * @param[in] num_options Number of delegate options
+ * @param[in,out] report_error Error callback function
+ *
+ */
+ DelegateOptions(char const* const* options_keys,
+ char const* const* options_values,
+ size_t num_options,
+ void (*report_error)(const char*));
+
const std::vector<armnn::BackendId>& GetBackends() const { return m_Backends; }
void SetBackends(const std::vector<armnn::BackendId>& backends) { m_Backends = backends; }
diff --git a/delegate/src/DelegateOptions.cpp b/delegate/src/DelegateOptions.cpp
index c19697d6c6..d477d9839d 100644
--- a/delegate/src/DelegateOptions.cpp
+++ b/delegate/src/DelegateOptions.cpp
@@ -4,6 +4,8 @@
//
#include <DelegateOptions.hpp>
+#include <armnn/utility/NumericCast.hpp>
+#include <armnn/utility/StringUtils.hpp>
namespace armnnDelegate
{
@@ -48,4 +50,189 @@ DelegateOptions::DelegateOptions(const std::vector<armnn::BackendId>& backends,
{
}
+DelegateOptions::DelegateOptions(char const* const* options_keys,
+ char const* const* options_values,
+ size_t num_options,
+ void (*report_error)(const char*))
+{
+ armnn::IRuntime::CreationOptions runtimeOptions;
+ armnn::OptimizerOptions optimizerOptions;
+ bool internalProfilingState = false;
+ armnn::ProfilingDetailsMethod internalProfilingDetail = armnn::ProfilingDetailsMethod::DetailsWithEvents;
+ armnn::IRuntime::CreationOptions::ExternalProfilingOptions extProfilingParams;
+ for (size_t i = 0; i < num_options; ++i)
+ {
+ // Process backends
+ if (std::string(options_keys[i]) == std::string("backends"))
+ {
+ // The backend option is a comma separated string of backendIDs that needs to be split
+ std::vector<armnn::BackendId> backends;
+ char* dup = strdup(options_values[i]);
+ char* pch = std::strtok(dup, ",");
+ while (pch != NULL)
+ {
+ backends.push_back(pch);
+ pch = strtok (NULL, ",");
+ }
+ this->SetBackends(backends);
+ }
+ // Process dynamic-backends-path
+ else if (std::string(options_keys[i]) == std::string("dynamic-backends-path"))
+ {
+ runtimeOptions.m_DynamicBackendsPath = std::string(options_values[i]);
+ }
+ // Process logging level
+ else if (std::string(options_keys[i]) == std::string("logging-severity"))
+ {
+ this->SetLoggingSeverity(options_values[i]);
+ }
+ // Process GPU backend options
+ else if (std::string(options_keys[i]) == std::string("gpu-tuning-level"))
+ {
+ armnn::BackendOptions option("GpuAcc", {{"TuningLevel", atoi(options_values[i])}});
+ runtimeOptions.m_BackendOptions.push_back(option);
+ }
+ else if (std::string(options_keys[i]) == std::string("gpu-mlgo-tuning-file"))
+ {
+ armnn::BackendOptions option("GpuAcc", {{"MLGOTuningFilePath", std::string(options_values[i])}});
+ optimizerOptions.m_ModelOptions.push_back(option);
+ }
+ else if (std::string(options_keys[i]) == std::string("gpu-tuning-file"))
+ {
+ armnn::BackendOptions option("GpuAcc", {{"TuningFile", std::string(options_values[i])}});
+ runtimeOptions.m_BackendOptions.push_back(option);
+ }
+ else if (std::string(options_keys[i]) == std::string("gpu-enable-profiling"))
+ {
+ runtimeOptions.m_EnableGpuProfiling = (*options_values[i] != '0');
+ }
+ else if (std::string(options_keys[i]) == std::string("gpu-kernel-profiling-enabled"))
+ {
+ armnn::BackendOptions option("GpuAcc", {{"KernelProfilingEnabled",
+ armnn::stringUtils::StringToBool(options_values[i])}});
+ runtimeOptions.m_BackendOptions.push_back(option);
+ }
+ else if (std::string(options_keys[i]) == std::string("save-cached-network"))
+ {
+ armnn::BackendOptions option("GpuAcc", {{"SaveCachedNetwork",
+ armnn::stringUtils::StringToBool(options_values[i])}});
+ optimizerOptions.m_ModelOptions.push_back(option);
+ }
+ else if (std::string(options_keys[i]) == std::string("cached-network-filepath"))
+ {
+ armnn::BackendOptions option("GpuAcc", {{"CachedNetworkFilePath", std::string(options_values[i])}});
+ optimizerOptions.m_ModelOptions.push_back(option);
+ }
+ // Process GPU & CPU backend options
+ else if (std::string(options_keys[i]) == std::string("enable-fast-math"))
+ {
+ armnn::BackendOptions modelOptionGpu("GpuAcc", {{"FastMathEnabled",
+ armnn::stringUtils::StringToBool(options_values[i])}});
+ optimizerOptions.m_ModelOptions.push_back(modelOptionGpu);
+
+ armnn::BackendOptions modelOptionCpu("CpuAcc", {{"FastMathEnabled",
+ armnn::stringUtils::StringToBool(options_values[i])}});
+ optimizerOptions.m_ModelOptions.push_back(modelOptionCpu);
+ }
+ // Process CPU backend options
+ else if (std::string(options_keys[i]) == std::string("number-of-threads"))
+ {
+ unsigned int numberOfThreads = armnn::numeric_cast<unsigned int>(atoi(options_values[i]));
+ armnn::BackendOptions modelOption("CpuAcc", {{"NumberOfThreads", numberOfThreads}});
+ optimizerOptions.m_ModelOptions.push_back(modelOption);
+ }
+ // Process reduce-fp32-to-fp16 option
+ else if (std::string(options_keys[i]) == std::string("reduce-fp32-to-fp16"))
+ {
+ optimizerOptions.m_ReduceFp32ToFp16 = armnn::stringUtils::StringToBool(options_values[i]);
+ }
+ // Process reduce-fp32-to-bf16 option
+ else if (std::string(options_keys[i]) == std::string("reduce-fp32-to-bf16"))
+ {
+ optimizerOptions.m_ReduceFp32ToBf16 = armnn::stringUtils::StringToBool(options_values[i]);
+ }
+ // Process debug-data
+ else if (std::string(options_keys[i]) == std::string("debug-data"))
+ {
+ optimizerOptions.m_Debug = armnn::stringUtils::StringToBool(options_values[i]);
+ }
+ // Process memory-import
+ else if (std::string(options_keys[i]) == std::string("memory-import"))
+ {
+ optimizerOptions.m_ImportEnabled = armnn::stringUtils::StringToBool(options_values[i]);
+ }
+ // Process enable-internal-profiling
+ else if (std::string(options_keys[i]) == std::string("enable-internal-profiling"))
+ {
+ internalProfilingState = *options_values[i] != '0';
+ optimizerOptions.m_ProfilingEnabled = internalProfilingState;
+ }
+ // Process internal-profiling-detail
+ else if (std::string(options_keys[i]) == std::string("internal-profiling-detail"))
+ {
+ uint32_t detailLevel = static_cast<uint32_t>(std::stoul(options_values[i]));
+ switch (detailLevel)
+ {
+ case 1:
+ internalProfilingDetail = armnn::ProfilingDetailsMethod::DetailsWithEvents;
+ break;
+ case 2:
+ internalProfilingDetail = armnn::ProfilingDetailsMethod::DetailsOnly;
+ break;
+ default:
+ internalProfilingDetail = armnn::ProfilingDetailsMethod::Undefined;
+ break;
+ }
+ }
+ // Process enable-external-profiling
+ else if (std::string(options_keys[i]) == std::string("enable-external-profiling"))
+ {
+ extProfilingParams.m_EnableProfiling = armnn::stringUtils::StringToBool(options_values[i]);
+ }
+ // Process timeline-profiling
+ else if (std::string(options_keys[i]) == std::string("timeline-profiling"))
+ {
+ extProfilingParams.m_TimelineEnabled = armnn::stringUtils::StringToBool(options_values[i]);
+ }
+ // Process outgoing-capture-file
+ else if (std::string(options_keys[i]) == std::string("outgoing-capture-file"))
+ {
+ extProfilingParams.m_OutgoingCaptureFile = options_values[i];
+ }
+ // Process incoming-capture-file
+ else if (std::string(options_keys[i]) == std::string("incoming-capture-file"))
+ {
+ extProfilingParams.m_IncomingCaptureFile = options_values[i];
+ }
+ // Process file-only-external-profiling
+ else if (std::string(options_keys[i]) == std::string("file-only-external-profiling"))
+ {
+ extProfilingParams.m_FileOnly = armnn::stringUtils::StringToBool(options_values[i]);
+ }
+ // Process counter-capture-period
+ else if (std::string(options_keys[i]) == std::string("counter-capture-period"))
+ {
+ extProfilingParams.m_CapturePeriod = static_cast<uint32_t>(std::stoul(options_values[i]));
+ }
+ // Process profiling-file-format
+ else if (std::string(options_keys[i]) == std::string("profiling-file-format"))
+ {
+ extProfilingParams.m_FileFormat = options_values[i];
+ }
+ // Process serialize-to-dot
+ else if (std::string(options_keys[i]) == std::string("serialize-to-dot"))
+ {
+ this->SetSerializeToDot(options_values[i]);
+ }
+ else
+ {
+ throw armnn::Exception("Unknown option for the ArmNN Delegate given: " + std::string(options_keys[i]));
+ }
+ }
+
+ this->SetRuntimeOptions(runtimeOptions);
+ this->SetOptimizerOptions(optimizerOptions);
+ this->SetInternalProfilingParams(internalProfilingState, internalProfilingDetail);
+ this->SetExternalProfilingParams(extProfilingParams);
+}
} // namespace armnnDelegate
diff --git a/delegate/src/armnn_external_delegate.cpp b/delegate/src/armnn_external_delegate.cpp
index 5919a6c5ab..c3875740e1 100644
--- a/delegate/src/armnn_external_delegate.cpp
+++ b/delegate/src/armnn_external_delegate.cpp
@@ -26,327 +26,23 @@ namespace tflite
extern "C"
{
-std::vector<std::string> gpu_options {"gpu-tuning-level",
- "gpu-tuning-file",
- "gpu-kernel-profiling-enabled"};
-
/**
- * Create an ArmNN delegate plugin
- *
- * Available options:
- *
- * Option key: "backends" \n
- * Possible values: ["EthosNPU"/"GpuAcc"/"CpuAcc"/"CpuRef"] \n
- * Descriptions: A comma separated list without whitespaces of
- * backends which should be used for execution. Falls
- * back to next backend in list if previous doesn't
- * provide support for operation. e.g. "GpuAcc,CpuAcc"
- *
- * Option key: "dynamic-backends-path" \n
- * Possible values: [filenameString] \n
- * Descriptions: This is the directory that will be searched for any dynamic backends.
- *
- * Option key: "logging-severity" \n
- * Possible values: ["trace"/"debug"/"info"/"warning"/"error"/"fatal"] \n
- * Description: Sets the logging severity level for ArmNN. Logging
- * is turned off if this option is not provided.
- *
- * Option key: "gpu-tuning-level" \n
- * Possible values: ["0"/"1"/"2"/"3"] \n
- * Description: 0=UseOnly(default), 1=RapidTuning, 2=NormalTuning,
- * 3=ExhaustiveTuning. Requires option gpu-tuning-file.
- * 1,2 and 3 will create a tuning-file, 0 will apply the
- * tunings from an existing file
- *
- * Option key: "gpu-mlgo-tuning-file" \n
- * Possible values: [filenameString] \n
- * Description: File name for the MLGO tuning file
- *
- * Option key: "gpu-tuning-file" \n
- * Possible values: [filenameString] \n
- * Description: File name for the tuning file.
- *
- * Option key: "gpu-enable-profiling" \n
- * Possible values: ["true"/"false"] \n
- * Description: Enables GPU profiling
- *
- * Option key: "gpu-kernel-profiling-enabled" \n
- * Possible values: ["true"/"false"] \n
- * Description: Enables GPU kernel profiling
- *
- * Option key: "save-cached-network" \n
- * Possible values: ["true"/"false"] \n
- * Description: Enables saving of the cached network to a file,
- * specified with the cached-network-filepath option
- *
- * Option key: "cached-network-filepath" \n
- * Possible values: [filenameString] \n
- * Description: If non-empty, the given file will be used to load/save the cached network.
- * If save-cached-network is given then the cached network will be saved to the given file.
- * To save the cached network a file must already exist.
- * If save-cached-network is not given then the cached network will be loaded from the given file.
- * This will remove initial compilation time of kernels and speed up the first execution.
- *
- * Option key: "enable-fast-math" \n
- * Possible values: ["true"/"false"] \n
- * Description: Enables fast_math options in backends that support it
- *
- * Option key: "number-of-threads" \n
- * Possible values: ["1"-"64"] \n
- * Description: Assign the number of threads used by the CpuAcc backend.
- * Default is set to 0 (Backend will decide number of threads to use).
- *
- * Option key: "reduce-fp32-to-fp16" \n
- * Possible values: ["true"/"false"] \n
- * Description: Reduce Fp32 data to Fp16 for faster processing
- *
- * Option key: "reduce-fp32-to-bf16" \n
- * Possible values: ["true"/"false"] \n
- * Description: Reduce Fp32 data to Bf16 for faster processing
- *
- * Option key: "debug-data" \n
- * Possible values: ["true"/"false"] \n
- * Description: Add debug data for easier troubleshooting
- *
- * Option key: "memory-import" \n
- * Possible values: ["true"/"false"] \n
- * Description: Enable memory import
- *
- * Option key: "enable-internal-profiling" \n
- * Possible values: ["true"/"false"] \n
- * Description: Enable the internal profiling feature.
- *
- * Option key: "internal-profiling-detail" \n
- * Possible values: [1/2] \n
- * Description: Set the detail on the internal profiling. 1 = DetailsWithEvents, 2 = DetailsOnly.
- *
- * Option key: "enable-external-profiling" \n
- * Possible values: ["true"/"false"] \n
- * Description: Enable the external profiling feature.
- *
- * Option key: "timeline-profiling" \n
- * Possible values: ["true"/"false"] \n
- * Description: Indicates whether external timeline profiling is enabled or not.
- *
- * Option key: "outgoing-capture-file" \n
- * Possible values: [filenameString] \n
- * Description: Path to a file in which outgoing timeline profiling messages will be stored.
- *
- * Option key: "incoming-capture-file" \n
- * Possible values: [filenameString] \n
- * Description: Path to a file in which incoming timeline profiling messages will be stored.
- *
- * Option key: "file-only-external-profiling" \n
- * Possible values: ["true"/"false"] \n
- * Description: Enable profiling output to file only.
- *
- * Option key: "counter-capture-period" \n
- * Possible values: Integer, Default is 10000u
- * Description: Value in microseconds of the profiling capture period. \n
- *
- * Option key: "profiling-file-format" \n
- * Possible values: String of ["binary"] \n
- * Description: The format of the file used for outputting profiling data. Currently on "binary" is supported.
- *
- * Option key: "serialize-to-dot" \n
- * Possible values: [filenameString] \n
- * Description: Serialize the optimized network to the file specified in "dot" format.
- *
- * @param[in] option_keys Delegate option names
- * @param[in] options_values Delegate option values
- * @param[in] num_options Number of delegate options
- * @param[in,out] report_error Error callback function
- *
- * @return An ArmNN delegate if it succeeds else NULL
- */
+ * Implementation of the TfLite external delegate plugin
+ *
+ * For details about what options_keys and option_values are supported please see:
+ * armnnDelegate::DelegateOptions::DelegateOptions(char const* const*, char const* const*,size_t,void (*)(const char*))
+ */
TfLiteDelegate* tflite_plugin_create_delegate(char** options_keys,
char** options_values,
size_t num_options,
void (*report_error)(const char*))
{
- // Returning null indicates an error during delegate creation so we initialize with that
+ // Returning null indicates an error during delegate creation, we initialize with that
TfLiteDelegate* delegate = nullptr;
try
{
- // (Initializes with CpuRef backend)
- armnnDelegate::DelegateOptions options = armnnDelegate::TfLiteArmnnDelegateOptionsDefault();
-
- armnn::IRuntime::CreationOptions runtimeOptions;
- armnn::OptimizerOptions optimizerOptions;
- bool internalProfilingState = false;
- armnn::ProfilingDetailsMethod internalProfilingDetail = armnn::ProfilingDetailsMethod::DetailsWithEvents;
- armnn::IRuntime::CreationOptions::ExternalProfilingOptions extProfilingParams;
- for (size_t i = 0; i < num_options; ++i)
- {
- // Process backends
- if (std::string(options_keys[i]) == std::string("backends"))
- {
- // The backend option is a comma separated string of backendIDs that needs to be split
- std::vector<armnn::BackendId> backends;
- char* pch;
- pch = strtok(options_values[i],",");
- while (pch != NULL)
- {
- backends.push_back(pch);
- pch = strtok (NULL, ",");
- }
- options.SetBackends(backends);
- }
- // Process dynamic-backends-path
- else if (std::string(options_keys[i]) == std::string("dynamic-backends-path"))
- {
- runtimeOptions.m_DynamicBackendsPath = std::string(options_values[i]);
- }
- // Process logging level
- else if (std::string(options_keys[i]) == std::string("logging-severity"))
- {
- options.SetLoggingSeverity(options_values[i]);
- }
- // Process GPU backend options
- else if (std::string(options_keys[i]) == std::string("gpu-tuning-level"))
- {
- armnn::BackendOptions option("GpuAcc", {{"TuningLevel", atoi(options_values[i])}});
- runtimeOptions.m_BackendOptions.push_back(option);
- }
- else if (std::string(options_keys[i]) == std::string("gpu-mlgo-tuning-file"))
- {
- armnn::BackendOptions option("GpuAcc", {{"MLGOTuningFilePath", std::string(options_values[i])}});
- optimizerOptions.m_ModelOptions.push_back(option);
- }
- else if (std::string(options_keys[i]) == std::string("gpu-tuning-file"))
- {
- armnn::BackendOptions option("GpuAcc", {{"TuningFile", std::string(options_values[i])}});
- runtimeOptions.m_BackendOptions.push_back(option);
- }
- else if (std::string(options_keys[i]) == std::string("gpu-enable-profiling"))
- {
- runtimeOptions.m_EnableGpuProfiling = (*options_values[i] != '0');
- }
- else if (std::string(options_keys[i]) == std::string("gpu-kernel-profiling-enabled"))
- {
- armnn::BackendOptions option("GpuAcc", {{"KernelProfilingEnabled", (*options_values[i] != '0')}});
- runtimeOptions.m_BackendOptions.push_back(option);
- }
- else if (std::string(options_keys[i]) == std::string("save-cached-network"))
- {
- armnn::BackendOptions option("GpuAcc", {{"SaveCachedNetwork", (*options_values[i] != '0')}});
- optimizerOptions.m_ModelOptions.push_back(option);
- }
- else if (std::string(options_keys[i]) == std::string("cached-network-filepath"))
- {
- armnn::BackendOptions option("GpuAcc", {{"CachedNetworkFilePath", std::string(options_values[i])}});
- optimizerOptions.m_ModelOptions.push_back(option);
- }
- // Process GPU & CPU backend options
- else if (std::string(options_keys[i]) == std::string("enable-fast-math"))
- {
- armnn::BackendOptions modelOptionGpu("GpuAcc", {{"FastMathEnabled", (*options_values[i] != '0')}});
- optimizerOptions.m_ModelOptions.push_back(modelOptionGpu);
-
- armnn::BackendOptions modelOptionCpu("CpuAcc", {{"FastMathEnabled", (*options_values[i] != '0')}});
- optimizerOptions.m_ModelOptions.push_back(modelOptionCpu);
- }
- // Process CPU backend options
- else if (std::string(options_keys[i]) == std::string("number-of-threads"))
- {
- unsigned int numberOfThreads = armnn::numeric_cast<unsigned int>(atoi(options_values[i]));
- armnn::BackendOptions modelOption("CpuAcc", {{"NumberOfThreads", numberOfThreads}});
- optimizerOptions.m_ModelOptions.push_back(modelOption);
- }
- // Process reduce-fp32-to-fp16 option
- else if (std::string(options_keys[i]) == std::string("reduce-fp32-to-fp16"))
- {
- optimizerOptions.m_ReduceFp32ToFp16 = *options_values[i] != '0';
- }
- // Process reduce-fp32-to-bf16 option
- else if (std::string(options_keys[i]) == std::string("reduce-fp32-to-bf16"))
- {
- optimizerOptions.m_ReduceFp32ToBf16 = *options_values[i] != '0';
- }
- // Process debug-data
- else if (std::string(options_keys[i]) == std::string("debug-data"))
- {
- optimizerOptions.m_Debug = *options_values[i] != '0';
- }
- // Process memory-import
- else if (std::string(options_keys[i]) == std::string("memory-import"))
- {
- optimizerOptions.m_ImportEnabled = *options_values[i] != '0';
- }
- // Process enable-internal-profiling
- else if (std::string(options_keys[i]) == std::string("enable-internal-profiling"))
- {
- internalProfilingState = *options_values[i] != '0';
- optimizerOptions.m_ProfilingEnabled = internalProfilingState;
- }
- // Process internal-profiling-detail
- else if (std::string(options_keys[i]) == std::string("internal-profiling-detail"))
- {
- uint32_t detailLevel = static_cast<uint32_t>(std::stoul(options_values[i]));
- switch (detailLevel)
- {
- case 1:
- internalProfilingDetail = armnn::ProfilingDetailsMethod::DetailsWithEvents;
- break;
- case 2:
- internalProfilingDetail = armnn::ProfilingDetailsMethod::DetailsOnly;
- break;
- default:
- internalProfilingDetail = armnn::ProfilingDetailsMethod::Undefined;
- break;
- }
- }
- // Process enable-external-profiling
- else if (std::string(options_keys[i]) == std::string("enable-external-profiling"))
- {
- extProfilingParams.m_EnableProfiling = *options_values[i] != '0';
- }
- // Process timeline-profiling
- else if (std::string(options_keys[i]) == std::string("timeline-profiling"))
- {
- extProfilingParams.m_TimelineEnabled = *options_values[i] != '0';
- }
- // Process outgoing-capture-file
- else if (std::string(options_keys[i]) == std::string("outgoing-capture-file"))
- {
- extProfilingParams.m_OutgoingCaptureFile = options_values[i];
- }
- // Process incoming-capture-file
- else if (std::string(options_keys[i]) == std::string("incoming-capture-file"))
- {
- extProfilingParams.m_IncomingCaptureFile = options_values[i];
- }
- // Process file-only-external-profiling
- else if (std::string(options_keys[i]) == std::string("file-only-external-profiling"))
- {
- extProfilingParams.m_FileOnly = *options_values[i] != '0';
- }
- // Process counter-capture-period
- else if (std::string(options_keys[i]) == std::string("counter-capture-period"))
- {
- extProfilingParams.m_CapturePeriod = static_cast<uint32_t>(std::stoul(options_values[i]));
- }
- // Process profiling-file-format
- else if (std::string(options_keys[i]) == std::string("profiling-file-format"))
- {
- extProfilingParams.m_FileFormat = options_values[i];
- }
- // Process serialize-to-dot
- else if (std::string(options_keys[i]) == std::string("serialize-to-dot"))
- {
- options.SetSerializeToDot(options_values[i]);
- }
- else
- {
- throw armnn::Exception("Unknown option for the ArmNN Delegate given: " + std::string(options_keys[i]));
- }
- }
-
- options.SetRuntimeOptions(runtimeOptions);
- options.SetOptimizerOptions(optimizerOptions);
- options.SetInternalProfilingParams(internalProfilingState, internalProfilingDetail);
- options.SetExternalProfilingParams(extProfilingParams);
+ armnnDelegate::DelegateOptions options (options_keys, options_values, num_options, (*report_error));
delegate = TfLiteArmnnDelegateCreate(options);
}
catch (const std::exception& ex)
diff --git a/delegate/src/test/DelegateOptionsTest.cpp b/delegate/src/test/DelegateOptionsTest.cpp
index 338772596b..54f9c8f0e3 100644
--- a/delegate/src/test/DelegateOptionsTest.cpp
+++ b/delegate/src/test/DelegateOptionsTest.cpp
@@ -223,6 +223,90 @@ TEST_CASE ("ArmnnDelegateSerializeToDot")
fs::remove(filename);
}
+void CreateFp16StringParsingTestRun(std::vector<std::string>& keys,
+ std::vector<std::string>& values,
+ std::stringstream& ss)
+{
+ StreamRedirector redirect(std::cout, ss.rdbuf());
+
+ std::vector<armnn::BackendId> backends = { armnn::Compute::CpuRef };
+ std::vector<int32_t> tensorShape { 1, 2, 2, 1 };
+ std::vector<float> inputData = { 1, 2, 3, 4 };
+ std::vector<float> divData = { 2, 2, 3, 4 };
+ std::vector<float> expectedResult = { 1, 2, 2, 2 };
+
+ // Create options_keys and options_values char array
+ size_t num_options = keys.size();
+ std::unique_ptr<const char*> options_keys =
+ std::unique_ptr<const char*>(new const char*[num_options + 1]);
+ std::unique_ptr<const char*> options_values =
+ std::unique_ptr<const char*>(new const char*[num_options + 1]);
+ for (size_t i=0; i<num_options; ++i)
+ {
+ options_keys.get()[i] = keys[i].c_str();
+ options_values.get()[i] = values[i].c_str();
+ }
+
+ armnnDelegate::DelegateOptions delegateOptions(options_keys.get(), options_values.get(), num_options, nullptr);
+ DelegateOptionTest<float>(::tflite::TensorType_FLOAT32,
+ backends,
+ tensorShape,
+ inputData,
+ inputData,
+ divData,
+ expectedResult,
+ delegateOptions);
+}
+
+TEST_CASE ("ArmnnDelegateStringParsingOptionReduceFp32ToFp16")
+{
+ SUBCASE("Fp16=1")
+ {
+ std::stringstream ss;
+ std::vector<std::string> keys { "backends", "debug-data", "reduce-fp32-to-fp16", "logging-severity"};
+ std::vector<std::string> values { "CpuRef", "1", "1", "info"};
+ CreateFp16StringParsingTestRun(keys, values, ss);
+ CHECK(ss.str().find("convert_fp32_to_fp16") != std::string::npos);
+ CHECK(ss.str().find("convert_fp16_to_fp32") != std::string::npos);
+ }
+ SUBCASE("Fp16=true")
+ {
+ std::stringstream ss;
+ std::vector<std::string> keys { "backends", "debug-data", "reduce-fp32-to-fp16"};
+ std::vector<std::string> values { "CpuRef", "TRUE", "true"};
+ CreateFp16StringParsingTestRun(keys, values, ss);
+ CHECK(ss.str().find("convert_fp32_to_fp16") != std::string::npos);
+ CHECK(ss.str().find("convert_fp16_to_fp32") != std::string::npos);
+ }
+ SUBCASE("Fp16=True")
+ {
+ std::stringstream ss;
+ std::vector<std::string> keys { "backends", "debug-data", "reduce-fp32-to-fp16"};
+ std::vector<std::string> values { "CpuRef", "true", "True"};
+ CreateFp16StringParsingTestRun(keys, values, ss);
+ CHECK(ss.str().find("convert_fp32_to_fp16") != std::string::npos);
+ CHECK(ss.str().find("convert_fp16_to_fp32") != std::string::npos);
+ }
+ SUBCASE("Fp16=0")
+ {
+ std::stringstream ss;
+ std::vector<std::string> keys { "backends", "debug-data", "reduce-fp32-to-fp16"};
+ std::vector<std::string> values { "CpuRef", "true", "0"};
+ CreateFp16StringParsingTestRun(keys, values, ss);
+ CHECK(ss.str().find("convert_fp32_to_fp16") == std::string::npos);
+ CHECK(ss.str().find("convert_fp16_to_fp32") == std::string::npos);
+ }
+ SUBCASE("Fp16=false")
+ {
+ std::stringstream ss;
+ std::vector<std::string> keys { "backends", "debug-data", "reduce-fp32-to-fp16"};
+ std::vector<std::string> values { "CpuRef", "1", "false"};
+ CreateFp16StringParsingTestRun(keys, values, ss);
+ CHECK(ss.str().find("convert_fp32_to_fp16") == std::string::npos);
+ CHECK(ss.str().find("convert_fp16_to_fp32") == std::string::npos);
+ }
+}
+
}
diff --git a/include/armnn/utility/StringUtils.hpp b/include/armnn/utility/StringUtils.hpp
index cc5e8e7349..172b1798c5 100644
--- a/include/armnn/utility/StringUtils.hpp
+++ b/include/armnn/utility/StringUtils.hpp
@@ -7,6 +7,9 @@
#include <iostream>
#include <sstream>
+#include <algorithm>
+#include <vector>
+#include <armnn/Exceptions.hpp>
namespace armnn
{
@@ -115,6 +118,47 @@ inline void StringReplaceAll(std::string& str,
}
}
+///
+/// Converts a string to bool.
+/// Accepts "true", "false" (case-insensitive) and numbers, 1 (true) or 0 (false).
+///
+/// \param s String to convert to bool
+/// \param throw_on_error Bool variable to suppress error if conversion failed (Will return false in that case)
+/// \return bool value
+///
+inline bool StringToBool(const std::string& s, bool throw_on_error = true)
+{
+ // in case of failure to convert returns false
+ auto result = false;
+
+ // isstringstream fails if parsing didn't work
+ std::istringstream is(s);
+
+ // try integer conversion first. For the case s is a number
+ is >> result;
+
+ if (is.fail())
+ {
+ // transform to lower case to make case-insensitive
+ std::string s_lower = s;
+ std::transform(s_lower.begin(),
+ s_lower.end(),
+ s_lower.begin(),
+ [](unsigned char c){ return std::tolower(c); });
+ is.str(s_lower);
+ // try boolean -> s="false" or "true"
+ is.clear();
+ is >> std::boolalpha >> result;
+ }
+
+ if (is.fail() && throw_on_error)
+ {
+ throw armnn::InvalidArgumentException(s + " is not convertable to bool");
+ }
+
+ return result;
+}
+
} // namespace stringUtils
} // namespace armnn \ No newline at end of file
diff --git a/src/armnn/test/UtilityTests.cpp b/src/armnn/test/UtilityTests.cpp
index 7911fd2608..fba0dd9d52 100644
--- a/src/armnn/test/UtilityTests.cpp
+++ b/src/armnn/test/UtilityTests.cpp
@@ -3,16 +3,17 @@
// SPDX-License-Identifier: MIT
//
-#include <doctest/doctest.h>
#define ARMNN_POLYMORPHIC_CAST_TESTABLE
#define ARMNN_NUMERIC_CAST_TESTABLE
+#include <armnn/Exceptions.hpp>
#include <armnn/utility/IgnoreUnused.hpp>
#include <armnn/utility/PolymorphicDowncast.hpp>
#include <armnn/utility/NumericCast.hpp>
+#include <armnn/utility/StringUtils.hpp>
-#include <armnn/Exceptions.hpp>
+#include <doctest/doctest.h>
#include <limits>
@@ -250,4 +251,28 @@ TEST_CASE("NumericCast")
}
+TEST_CASE("StringToBool")
+ {
+ CHECK(true == armnn::stringUtils::StringToBool("1"));
+ CHECK(false == armnn::stringUtils::StringToBool("0"));
+ // Any number larger than 1 will be a failure.
+ CHECK_THROWS_AS(armnn::stringUtils::StringToBool("2"), armnn::InvalidArgumentException);
+ CHECK_THROWS_AS(armnn::stringUtils::StringToBool("23456567"), armnn::InvalidArgumentException);
+ CHECK_THROWS_AS(armnn::stringUtils::StringToBool("-23456567"), armnn::InvalidArgumentException);
+ CHECK_THROWS_AS(armnn::stringUtils::StringToBool("Not a number"), armnn::InvalidArgumentException);
+ // Empty string should be a failure.
+ CHECK_THROWS_AS(armnn::stringUtils::StringToBool(""), armnn::InvalidArgumentException);
+ CHECK(true == armnn::stringUtils::StringToBool("true"));
+ CHECK(false == armnn::stringUtils::StringToBool("false"));
+ // Should be case agnostic.
+ CHECK(true == armnn::stringUtils::StringToBool("TrUe"));
+ CHECK(false == armnn::stringUtils::StringToBool("fAlSe"));
+
+ // Same negative test cases with throw_on_error set to false.
+ CHECK(false == armnn::stringUtils::StringToBool("2", false));
+ CHECK(false == armnn::stringUtils::StringToBool("23456567", false));
+ CHECK(false == armnn::stringUtils::StringToBool("-23456567", false));
+ CHECK(false == armnn::stringUtils::StringToBool("Not a number", false));
+ CHECK(false == armnn::stringUtils::StringToBool("", false));
+ }
}