diff --git a/inference-engine/include/gna/gna_config.hpp b/inference-engine/include/gna/gna_config.hpp index 7273f5a0332..193427734cf 100644 --- a/inference-engine/include/gna/gna_config.hpp +++ b/inference-engine/include/gna/gna_config.hpp @@ -77,6 +77,27 @@ DECLARE_GNA_CONFIG_VALUE(AVX1_EXACT); DECLARE_GNA_CONFIG_VALUE(AVX2); DECLARE_GNA_CONFIG_VALUE(AVX2_EXACT); +/** +* @brief The option to override the GNA HW execution target. May be one of GNA_TARGET_2_0, GNA_TARGET_3_0. +* By default (in case of no value set) the behavior depends on GNA HW availability: +* If GNA HW is present, use the option corresponding to this HW. +* If HW is not present, use the option corresponding to the latest fully supported GNA HW generation. +* A fully supported GNA HW generation means it must be supported by booth the OV GNA Plugin and the core GNA Library. +* For the GNA Library 2.0.X.Y, the latest supported GNA HW generation corresponds to GNA_TARGET_2_0. +* For the GNA Library 2.1.X.Y, the latest supported GNA HW generation corresponds to GNA_TARGET_3_0. +* For the OV GNA Plugin 2021.4, the latest supported GNA HW generation corresponds to GNA_TARGET_3_0. +*/ +DECLARE_GNA_CONFIG_KEY(EXEC_TARGET); + +DECLARE_GNA_CONFIG_VALUE(TARGET_2_0); +DECLARE_GNA_CONFIG_VALUE(TARGET_3_0); + +/** +* @brief The option to override the GNA HW compile target. May be one of GNA_TARGET_2_0, GNA_TARGET_3_0. +* By default the same as GNA_EXEC_TARGET. +*/ +DECLARE_GNA_CONFIG_KEY(COMPILE_TARGET); + /** * @brief if enabled produced minimum memory footprint for loaded network in GNA memory, default value is YES */ diff --git a/inference-engine/samples/speech_sample/main.cpp b/inference-engine/samples/speech_sample/main.cpp index d6b79c76f91..3c883e3bf64 100644 --- a/inference-engine/samples/speech_sample/main.cpp +++ b/inference-engine/samples/speech_sample/main.cpp @@ -760,6 +760,8 @@ int main(int argc, char* argv[]) { gnaPluginConfig[GNAConfigParams::KEY_GNA_PRECISION] = "I16"; } + gnaPluginConfig[GNAConfigParams::KEY_GNA_EXEC_TARGET] = FLAGS_exec_target; + gnaPluginConfig[GNAConfigParams::KEY_GNA_COMPILE_TARGET] = FLAGS_compile_target; gnaPluginConfig[GNAConfigParams::KEY_GNA_LIB_N_THREADS] = std::to_string((FLAGS_cw_r > 0 || FLAGS_cw_l > 0) ? 1 : FLAGS_nthreads); gnaPluginConfig[GNA_CONFIG_KEY(COMPACT_MODE)] = CONFIG_VALUE(NO); gnaPluginConfig[GNA_CONFIG_KEY(PWL_MAX_ERROR_PERCENT)] = std::to_string(FLAGS_pwl_me); diff --git a/inference-engine/samples/speech_sample/speech_sample.hpp b/inference-engine/samples/speech_sample/speech_sample.hpp index a2c7f3aee6c..9ae11ecb47c 100644 --- a/inference-engine/samples/speech_sample/speech_sample.hpp +++ b/inference-engine/samples/speech_sample/speech_sample.hpp @@ -27,6 +27,20 @@ static const char target_device_message[] = "Optional. Specify a target device t "below. " "The sample will look for a suitable plugin for device specified."; +/// @brief message for execution target +static const char execution_target_message[] = "Optional. Specify GNA execution target generation. " + "May be one of GNA_TARGET_2_0, GNA_TARGET_3_0. " + "By default, generation corresponds to the GNA HW available in the system " + "or the latest fully supported generation by the software. " + "See the GNA Plugin's GNA_EXEC_TARGET config option description."; + +/// @brief message for execution target +static const char compile_target_message[] = "Optional. Specify GNA compile target generation. " + "May be one of GNA_TARGET_2_0, GNA_TARGET_3_0. " + "By default, generation corresponds to the GNA HW available in the system " + "or the latest fully supported generation by the software. " + "See the GNA Plugin's GNA_COMPILE_TARGET config option description."; + /// @brief message for performance counters static const char performance_counter_message[] = "Optional. Enables per-layer performance report."; @@ -109,6 +123,12 @@ DEFINE_string(m, "", model_message); /// \brief device the target device to infer on (default CPU)
DEFINE_string(d, "CPU", target_device_message); +/// \brief GNA execution target
+DEFINE_string(exec_target, "", execution_target_message); + +/// \brief GNA compile target
+DEFINE_string(compile_target, "", compile_target_message); + /// \brief Enable per-layer performance report DEFINE_bool(pc, false, performance_counter_message); diff --git a/inference-engine/src/gna_plugin/gna_device.cpp b/inference-engine/src/gna_plugin/gna_device.cpp index 95899982ca3..01e0d7e80be 100644 --- a/inference-engine/src/gna_plugin/gna_device.cpp +++ b/inference-engine/src/gna_plugin/gna_device.cpp @@ -24,6 +24,7 @@ #include "gna-api.h" #endif +#include "gna/gna_config.hpp" #include "gna_plugin_log.hpp" //#define MODEL_DUMP @@ -130,7 +131,7 @@ void GNADeviceHelper::enforceLegacyCnns(Gna2Model& gnaModel) { uint32_t GNADeviceHelper::createModel(Gna2Model& gnaModel) const { std::unique_lock lockGnaCalls{ acrossPluginsSync }; uint32_t modelId; - if (isUpTo20GnaHwDevice() && isGnaLibVersion2_1) { + if (enforceLegacyCnnNeeded()) { enforceLegacyCnns(gnaModel); } #if GNA_LIB_VER == 2 && defined MODEL_DUMP @@ -154,15 +155,40 @@ void GNADeviceHelper::releaseModel(const uint32_t model_id) { checkGna2Status(status, "Gna2ModelRelease"); } +bool GNADeviceHelper::enforceLegacyCnnNeeded() const { + auto devVersion = getExecutionTargetDevice(); + return isGnaLibVersion2_1 && isUpTo20HwGnaDevice(devVersion); +} + +Gna2DeviceVersion GNADeviceHelper::getExecutionTargetDevice() const { + const volatile auto Gna2DeviceVersion3_0 = static_cast(0x30); + if (executionTarget.empty()) { + if (detectedGnaDevVersion == Gna2DeviceVersionSoftwareEmulation) + return isGnaLibVersion2_1 ? Gna2DeviceVersion3_0 : Gna2DeviceVersion2_0; + return detectedGnaDevVersion; + } else if (executionTarget == InferenceEngine::GNAConfigParams::GNA_TARGET_3_0) { + if (!isGnaLibVersion2_1) + THROW_GNA_EXCEPTION << "Unsupported GNA execution target " << executionTarget << " when GNA Library version is 2.0.X.Y"; + return Gna2DeviceVersion3_0; + } else if (executionTarget == InferenceEngine::GNAConfigParams::GNA_TARGET_2_0) { + return Gna2DeviceVersion2_0; + } + THROW_GNA_EXCEPTION << "Unknown execution target: \"" << executionTarget << "\""; +} + uint32_t GNADeviceHelper::createRequestConfig(const uint32_t model_id) { std::unique_lock lockGnaCalls{ acrossPluginsSync }; uint32_t reqConfId; auto status = Gna2RequestConfigCreate(model_id, &reqConfId); checkGna2Status(status, "Gna2RequestConfigCreate"); - if (gna2HwConsistency != Gna2DeviceVersionSoftwareEmulation && !isGnaLibVersion2_1) { - status = Gna2RequestConfigEnableHardwareConsistency(reqConfId, - isUpTo20GnaDevice() ? gna2HwConsistency : detectedGnaDevVersion); - checkGna2Status(status, "Gna2RequestConfigEnableHardwareConsistency"); + + // When the GNA_SW_EXACT mode is chosen inference results should be computed exactly the same way + // (bit exactly) as on the selected GNA execution target generation. + // See the GNA Plugin's GNA_EXEC_TARGET config option description. + if (swExactMode) { + const auto consistentDevice = getExecutionTargetDevice(); + status = Gna2RequestConfigEnableHardwareConsistency(reqConfId, consistentDevice); + checkGna2Status(status, "Gna2RequestConfigEnableHardwareConsistency(" + std::to_string(static_cast(consistentDevice)) + ")"); } status = Gna2InstrumentationConfigAssignToRequestConfig(instrumentationConfigId, reqConfId); checkGna2Status(status, "Gna2InstrumentationConfigAssignToRequestConfig"); diff --git a/inference-engine/src/gna_plugin/gna_device.hpp b/inference-engine/src/gna_plugin/gna_device.hpp index ad639291e3d..831b9fde517 100644 --- a/inference-engine/src/gna_plugin/gna_device.hpp +++ b/inference-engine/src/gna_plugin/gna_device.hpp @@ -51,8 +51,10 @@ class GNADeviceHelper { intel_gna_perf_t nGNAPerfResultsTotal; #else uint32_t nGnaDeviceIndex = 0; - Gna2DeviceVersion gna2HwConsistency = Gna2DeviceVersionSoftwareEmulation; + bool swExactMode = false; Gna2DeviceVersion detectedGnaDevVersion = Gna2DeviceVersionSoftwareEmulation; + std::string executionTarget; + std::string compileTarget; bool isGnaLibVersion2_1 = false; static const uint32_t TotalGna2InstrumentationPoints = 2; @@ -75,11 +77,15 @@ public: bool isPerformanceMeasuring = false) : isPerformanceMeasuring(isPerformanceMeasuring) { #else - explicit GNADeviceHelper(Gna2DeviceVersion gna2HwConsistency = Gna2DeviceVersionSoftwareEmulation, + explicit GNADeviceHelper(std::string executionTargetIn = "", + std::string compileTargetIn = "", + bool swExactModeIn = false, uint8_t lib_async_n_threads = 1, bool use_openmp = false, bool isPerformanceMeasuring = false) : - gna2HwConsistency(gna2HwConsistency), + swExactMode(swExactModeIn), + executionTarget(executionTargetIn), + compileTarget(compileTargetIn), isPerformanceMeasuring(isPerformanceMeasuring), nGnaDeviceIndex{selectGnaDevice()} { #endif @@ -129,15 +135,17 @@ public: uint32_t createRequestConfig(const uint32_t model_id); static uint32_t getNumberOfGnaDevices(); static uint32_t selectGnaDevice(); + static bool isGnaHw(const Gna2DeviceVersion dev) { + return Gna2DeviceVersionSoftwareEmulation != dev; + } bool hasGnaHw() const { - return Gna2DeviceVersionSoftwareEmulation != detectedGnaDevVersion; + return isGnaHw(detectedGnaDevVersion); } - bool isUpTo20GnaDevice() const { - return detectedGnaDevVersion <= Gna2DeviceVersion2_0; - } - bool isUpTo20GnaHwDevice() const { - return isUpTo20GnaDevice() && detectedGnaDevVersion != Gna2DeviceVersionSoftwareEmulation; + static bool isUpTo20HwGnaDevice(const Gna2DeviceVersion dev) { + return dev <= Gna2DeviceVersion2_0 && isGnaHw(dev); } + bool enforceLegacyCnnNeeded() const; + Gna2DeviceVersion getExecutionTargetDevice() const; static void checkGna2Status(Gna2Status status, const std::string& from); static void checkGna2Status(Gna2Status status, const Gna2Model& gnaModel); #endif diff --git a/inference-engine/src/gna_plugin/gna_plugin.cpp b/inference-engine/src/gna_plugin/gna_plugin.cpp index e997e49cf91..9832d59d527 100644 --- a/inference-engine/src/gna_plugin/gna_plugin.cpp +++ b/inference-engine/src/gna_plugin/gna_plugin.cpp @@ -397,7 +397,9 @@ void GNAPlugin::InitGNADevice() { gnaFlags->gna_openmp_multithreading, gnaFlags->performance_counting); #else - gnadevice = std::make_shared(config.pluginGna2DeviceConsistent, + gnadevice = std::make_shared(config.gnaExecTarget, + config.gnaCompileTarget, + config.swExactMode, gnaFlags->gna_lib_async_threads_num, gnaFlags->gna_openmp_multithreading, gnaFlags->performance_counting); diff --git a/inference-engine/src/gna_plugin/gna_plugin_config.cpp b/inference-engine/src/gna_plugin/gna_plugin_config.cpp index b006e235323..2dcb05d6ab8 100644 --- a/inference-engine/src/gna_plugin/gna_plugin_config.cpp +++ b/inference-engine/src/gna_plugin/gna_plugin_config.cpp @@ -33,22 +33,28 @@ static const std::vector supported_values_on_gna2 = { GNAConfigParams::GNA_AVX2_EXACT }; #else -static const caseless_unordered_map > supported_values = { - {GNAConfigParams::GNA_AUTO, {Gna2AccelerationModeAuto, Gna2DeviceVersionSoftwareEmulation}}, - {GNAConfigParams::GNA_HW, {Gna2AccelerationModeHardware, Gna2DeviceVersionSoftwareEmulation}}, - {GNAConfigParams::GNA_SW, {Gna2AccelerationModeSoftware, Gna2DeviceVersionSoftwareEmulation}}, - {GNAConfigParams::GNA_SW_EXACT, {Gna2AccelerationModeSoftware, Gna2DeviceVersion1_0}}, - {GNAConfigParams::GNA_GEN, {Gna2AccelerationModeGeneric, Gna2DeviceVersionSoftwareEmulation}}, - {GNAConfigParams::GNA_GEN_EXACT, {Gna2AccelerationModeGeneric, Gna2DeviceVersion1_0}}, - {GNAConfigParams::GNA_SSE, {Gna2AccelerationModeSse4x2, Gna2DeviceVersionSoftwareEmulation}}, - {GNAConfigParams::GNA_SSE_EXACT, {Gna2AccelerationModeSse4x2, Gna2DeviceVersion1_0}}, - {GNAConfigParams::GNA_AVX1, {Gna2AccelerationModeAvx1, Gna2DeviceVersionSoftwareEmulation}}, - {GNAConfigParams::GNA_AVX1_EXACT, {Gna2AccelerationModeAvx1, Gna2DeviceVersion1_0}}, - {GNAConfigParams::GNA_AVX2, {Gna2AccelerationModeAvx2, Gna2DeviceVersionSoftwareEmulation}}, - {GNAConfigParams::GNA_AVX2_EXACT, {Gna2AccelerationModeAvx2, Gna2DeviceVersion1_0}}, +static const caseless_unordered_map > supported_values = { + {GNAConfigParams::GNA_AUTO, {Gna2AccelerationModeAuto, false}}, + {GNAConfigParams::GNA_HW, {Gna2AccelerationModeHardware, false}}, + {GNAConfigParams::GNA_SW, {Gna2AccelerationModeSoftware, false}}, + {GNAConfigParams::GNA_SW_EXACT, {Gna2AccelerationModeSoftware, true}}, + {GNAConfigParams::GNA_GEN, {Gna2AccelerationModeGeneric, false}}, + {GNAConfigParams::GNA_GEN_EXACT, {Gna2AccelerationModeGeneric, true}}, + {GNAConfigParams::GNA_SSE, {Gna2AccelerationModeSse4x2, false}}, + {GNAConfigParams::GNA_SSE_EXACT, {Gna2AccelerationModeSse4x2, true}}, + {GNAConfigParams::GNA_AVX1, {Gna2AccelerationModeAvx1, false}}, + {GNAConfigParams::GNA_AVX1_EXACT, {Gna2AccelerationModeAvx1, true}}, + {GNAConfigParams::GNA_AVX2, {Gna2AccelerationModeAvx2, false}}, + {GNAConfigParams::GNA_AVX2_EXACT, {Gna2AccelerationModeAvx2, true}}, }; #endif +static const std::set supportedTargets = { + GNAConfigParams::GNA_TARGET_2_0, + GNAConfigParams::GNA_TARGET_3_0, + "" +}; + void Config::UpdateFromMap(const std::map& config) { for (auto&& item : config) { auto key = item.first; @@ -116,9 +122,14 @@ void Config::UpdateFromMap(const std::map& config) { gna_proc_type = static_cast(procType->second); #else pluginGna2AccMode = procType->second.first; - pluginGna2DeviceConsistent = procType->second.second; + swExactMode = procType->second.second; #endif } + } else if (key == GNA_CONFIG_KEY(EXEC_TARGET) || key == GNA_CONFIG_KEY(COMPILE_TARGET)) { + if (supportedTargets.count(value) == 0) { + THROW_GNA_EXCEPTION << "Unsupported GNA config value (key, value): (" << key << ", " << value << ")"; + } + (key == GNA_CONFIG_KEY(EXEC_TARGET) ? gnaExecTarget : gnaCompileTarget) = value; } else if (key == GNA_CONFIG_KEY(COMPACT_MODE)) { if (value == PluginConfigParams::YES) { gnaFlags.compact_mode = true; @@ -255,15 +266,17 @@ void Config::AdjustKeyMapValues() { } #else if (value.second.first == pluginGna2AccMode && - value.second.second == pluginGna2DeviceConsistent) { + value.second.second == swExactMode) { device_mode = value.first; - break; - } + break; + } #endif } } IE_ASSERT(!device_mode.empty()); keyConfigMap[GNA_CONFIG_KEY(DEVICE_MODE)] = device_mode; + keyConfigMap[GNA_CONFIG_KEY(EXEC_TARGET)] = gnaExecTarget; + keyConfigMap[GNA_CONFIG_KEY(COMPILE_TARGET)] = gnaCompileTarget; keyConfigMap[GNA_CONFIG_KEY(COMPACT_MODE)] = gnaFlags.compact_mode ? PluginConfigParams::YES: PluginConfigParams::NO; keyConfigMap[CONFIG_KEY(EXCLUSIVE_ASYNC_REQUESTS)] = diff --git a/inference-engine/src/gna_plugin/gna_plugin_config.hpp b/inference-engine/src/gna_plugin/gna_plugin_config.hpp index 502c2cbe1b8..850c61c5a6e 100644 --- a/inference-engine/src/gna_plugin/gna_plugin_config.hpp +++ b/inference-engine/src/gna_plugin/gna_plugin_config.hpp @@ -37,7 +37,7 @@ struct Config { gna_proc_type = r.gna_proc_type; #else pluginGna2AccMode = r.pluginGna2AccMode; - pluginGna2DeviceConsistent = r.pluginGna2DeviceConsistent; + swExactMode = r.swExactMode; #endif inputScaleFactors = r.inputScaleFactors; gnaFlags = r.gnaFlags; @@ -55,11 +55,14 @@ struct Config { std::string dumpXNNPath; std::string dumpXNNGeneration; + std::string gnaExecTarget; + std::string gnaCompileTarget; + #if GNA_LIB_VER == 1 intel_gna_proc_t gna_proc_type = static_cast(GNA_SOFTWARE & GNA_HARDWARE); #else Gna2AccelerationMode pluginGna2AccMode = Gna2AccelerationModeSoftware; - Gna2DeviceVersion pluginGna2DeviceConsistent = Gna2DeviceVersion1_0; + bool swExactMode = true; #endif std::vector inputScaleFactors; diff --git a/inference-engine/tests/unit/gna/gna_plugin_config_test.cpp b/inference-engine/tests/unit/gna/gna_plugin_config_test.cpp index 83290777425..bdfd50ba037 100644 --- a/inference-engine/tests/unit/gna/gna_plugin_config_test.cpp +++ b/inference-engine/tests/unit/gna/gna_plugin_config_test.cpp @@ -16,6 +16,8 @@ const std::map supportedConfigKeysWithDefaults = { {GNA_CONFIG_KEY(SCALE_FACTOR) + std::string("_0"), "1.000000"}, {GNA_CONFIG_KEY(FIRMWARE_MODEL_IMAGE), ""}, {GNA_CONFIG_KEY(FIRMWARE_MODEL_IMAGE_GENERATION), ""}, + {GNA_CONFIG_KEY(EXEC_TARGET), ""}, + {GNA_CONFIG_KEY(COMPILE_TARGET), ""}, {GNA_CONFIG_KEY(DEVICE_MODE), GNAConfigParams::GNA_SW_EXACT}, {GNA_CONFIG_KEY(COMPACT_MODE), CONFIG_VALUE(NO)}, {CONFIG_KEY(EXCLUSIVE_ASYNC_REQUESTS), CONFIG_VALUE(NO)}, @@ -104,28 +106,28 @@ TEST_F(GNAPluginConfigTest, GnaConfigDeviceModeTest) { EXPECT_EQ(config.gna_proc_type, static_cast(GNA_HARDWARE)); #else EXPECT_EQ(config.pluginGna2AccMode, Gna2AccelerationModeHardware); - EXPECT_EQ(config.pluginGna2DeviceConsistent, Gna2DeviceVersionSoftwareEmulation); + EXPECT_EQ(config.swExactMode, false); #endif SetAndCompare(GNA_CONFIG_KEY(DEVICE_MODE), GNAConfigParams::GNA_SW); #if GNA_LIB_VER == 1 EXPECT_EQ(config.gna_proc_type, static_cast(GNA_SOFTWARE)); #else EXPECT_EQ(config.pluginGna2AccMode, Gna2AccelerationModeSoftware); - EXPECT_EQ(config.pluginGna2DeviceConsistent, Gna2DeviceVersionSoftwareEmulation); + EXPECT_EQ(config.swExactMode, false); #endif SetAndCompare(GNA_CONFIG_KEY(DEVICE_MODE), GNAConfigParams::GNA_SW_EXACT); #if GNA_LIB_VER == 1 EXPECT_EQ(config.gna_proc_type, static_cast(GNA_SOFTWARE & GNA_HARDWARE)); #else EXPECT_EQ(config.pluginGna2AccMode, Gna2AccelerationModeSoftware); - EXPECT_EQ(config.pluginGna2DeviceConsistent, Gna2DeviceVersion1_0); + EXPECT_EQ(config.swExactMode, true); #endif SetAndCompare(GNA_CONFIG_KEY(DEVICE_MODE), GNAConfigParams::GNA_AUTO); #if GNA_LIB_VER == 1 EXPECT_EQ(config.gna_proc_type, static_cast(GNA_AUTO)); #else EXPECT_EQ(config.pluginGna2AccMode, Gna2AccelerationModeAuto); - EXPECT_EQ(config.pluginGna2DeviceConsistent, Gna2DeviceVersionSoftwareEmulation); + EXPECT_EQ(config.swExactMode, false); #endif ExpectThrow(GNA_CONFIG_KEY(DEVICE_MODE), ""); ExpectThrow(GNA_CONFIG_KEY(DEVICE_MODE), "abc"); @@ -187,3 +189,25 @@ TEST_F(GNAPluginConfigTest, GnaConfigSingleThreadTest) { config.gnaFlags.gna_openmp_multithreading, true); } + +TEST_F(GNAPluginConfigTest, GnaConfigGnaExecTargetTest) { + SetAndCompare(GNA_CONFIG_KEY(EXEC_TARGET), "GNA_TARGET_2_0"); + EXPECT_EQ(config.gnaExecTarget, "GNA_TARGET_2_0"); + SetAndCompare(GNA_CONFIG_KEY(EXEC_TARGET), "GNA_TARGET_3_0"); + EXPECT_EQ(config.gnaExecTarget, "GNA_TARGET_3_0"); + ExpectThrow(GNA_CONFIG_KEY(EXEC_TARGET), "GNA_TARGET_3_5"); + ExpectThrow(GNA_CONFIG_KEY(EXEC_TARGET), "0"); + ExpectThrow(GNA_CONFIG_KEY(EXEC_TARGET), "GNA_TARGET_1_5"); + ExpectThrow(GNA_CONFIG_KEY(EXEC_TARGET), "GNA_TARGET"); +} + +TEST_F(GNAPluginConfigTest, GnaConfigGnaCompileTargetTest) { + SetAndCompare(GNA_CONFIG_KEY(COMPILE_TARGET), "GNA_TARGET_2_0"); + EXPECT_EQ(config.gnaCompileTarget, "GNA_TARGET_2_0"); + SetAndCompare(GNA_CONFIG_KEY(COMPILE_TARGET), "GNA_TARGET_3_0"); + EXPECT_EQ(config.gnaCompileTarget, "GNA_TARGET_3_0"); + ExpectThrow(GNA_CONFIG_KEY(COMPILE_TARGET), "GNA_TARGET_3_5"); + ExpectThrow(GNA_CONFIG_KEY(COMPILE_TARGET), "0"); + ExpectThrow(GNA_CONFIG_KEY(COMPILE_TARGET), "GNA_TARGET_1_5"); + ExpectThrow(GNA_CONFIG_KEY(COMPILE_TARGET), "GNA_TARGET"); +}