NNAPI: Add execution preference to prepareModel (HAL)
A model can be prepared in different ways to optimize for different
use-cases. This CL propagates the execution preference across the HAL so
that the NN service can better fit the users needs.
Bug: 77864669
Test: mma
Test: NeuralNetworksTest_static
Test: VtsHalNeuralnetworksV1_1TargetTest
Change-Id: Ib928d510d462f36b6a87d5e81010513db7829fa8
diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp
index 4f9d528..ed1fb94 100644
--- a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp
@@ -242,8 +242,8 @@
// launch prepare model
sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
ASSERT_NE(nullptr, preparedModelCallback.get());
- Return<ErrorStatus> prepareLaunchStatus =
- device->prepareModel_1_1(model, preparedModelCallback);
+ Return<ErrorStatus> prepareLaunchStatus = device->prepareModel_1_1(
+ model, ExecutionPreference::FAST_SINGLE_ANSWER, preparedModelCallback);
ASSERT_TRUE(prepareLaunchStatus.isOk());
ASSERT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(prepareLaunchStatus));
diff --git a/neuralnetworks/1.1/IDevice.hal b/neuralnetworks/1.1/IDevice.hal
index d2c4843..1335bde 100644
--- a/neuralnetworks/1.1/IDevice.hal
+++ b/neuralnetworks/1.1/IDevice.hal
@@ -102,6 +102,8 @@
* Multiple threads can call prepareModel on the same model concurrently.
*
* @param model The model to be prepared for execution.
+ * @param preference Indicates the intended execution behavior of a prepared
+ * model.
* @param callback A callback object used to return the error status of
* preparing the model for execution and the prepared model
* if successful, nullptr otherwise. The callback object's
@@ -115,6 +117,7 @@
* - INVALID_ARGUMENT if one of the input arguments is
* invalid
*/
- prepareModel_1_1(Model model, IPreparedModelCallback callback)
+ prepareModel_1_1(Model model, ExecutionPreference preference,
+ IPreparedModelCallback callback)
generates (ErrorStatus status);
};
diff --git a/neuralnetworks/1.1/types.hal b/neuralnetworks/1.1/types.hal
index b4fccae..8290fbb 100644
--- a/neuralnetworks/1.1/types.hal
+++ b/neuralnetworks/1.1/types.hal
@@ -382,3 +382,24 @@
*/
bool relaxComputationFloat32toFloat16;
};
+
+/**
+ * Execution preferences.
+ */
+enum ExecutionPreference : int32_t {
+ /**
+ * Prefer executing in a way that minimizes battery drain.
+ * This is desirable for compilations that will be executed often.
+ */
+ LOW_POWER = 0,
+ /**
+ * Prefer returning a single answer as fast as possible, even if this causes
+ * more power consumption.
+ */
+ FAST_SINGLE_ANSWER = 1,
+ /**
+ * Prefer maximizing the throughput of successive frames, for example when
+ * processing successive frames coming from the camera.
+ */
+ SUSTAINED_SPEED = 2,
+};
diff --git a/neuralnetworks/1.1/vts/functional/ValidateModel.cpp b/neuralnetworks/1.1/vts/functional/ValidateModel.cpp
index 7a20e26..3aa55f8 100644
--- a/neuralnetworks/1.1/vts/functional/ValidateModel.cpp
+++ b/neuralnetworks/1.1/vts/functional/ValidateModel.cpp
@@ -50,13 +50,13 @@
}
static void validatePrepareModel(const sp<IDevice>& device, const std::string& message,
- const V1_1::Model& model) {
+ const V1_1::Model& model, ExecutionPreference preference) {
SCOPED_TRACE(message + " [prepareModel_1_1]");
sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
ASSERT_NE(nullptr, preparedModelCallback.get());
Return<ErrorStatus> prepareLaunchStatus =
- device->prepareModel_1_1(model, preparedModelCallback);
+ device->prepareModel_1_1(model, preference, preparedModelCallback);
ASSERT_TRUE(prepareLaunchStatus.isOk());
ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast<ErrorStatus>(prepareLaunchStatus));
@@ -67,15 +67,24 @@
ASSERT_EQ(nullptr, preparedModel.get());
}
+static bool validExecutionPreference(ExecutionPreference preference) {
+ return preference == ExecutionPreference::LOW_POWER ||
+ preference == ExecutionPreference::FAST_SINGLE_ANSWER ||
+ preference == ExecutionPreference::SUSTAINED_SPEED;
+}
+
// Primary validation function. This function will take a valid model, apply a
// mutation to it to invalidate the model, then pass it to interface calls that
// use the model. Note that the model here is passed by value, and any mutation
// to the model does not leave this function.
static void validate(const sp<IDevice>& device, const std::string& message, V1_1::Model model,
- const std::function<void(Model*)>& mutation) {
+ const std::function<void(Model*)>& mutation,
+ ExecutionPreference preference = ExecutionPreference::FAST_SINGLE_ANSWER) {
mutation(&model);
- validateGetSupportedOperations(device, message, model);
- validatePrepareModel(device, message, model);
+ if (validExecutionPreference(preference)) {
+ validateGetSupportedOperations(device, message, model);
+ }
+ validatePrepareModel(device, message, model, preference);
}
// Delete element from hidl_vec. hidl_vec doesn't support a "remove" operation,
@@ -486,6 +495,22 @@
}
}
+///////////////////////// VALIDATE EXECUTION PREFERENCE /////////////////////////
+
+static const int32_t invalidExecutionPreferences[] = {
+ static_cast<int32_t>(ExecutionPreference::LOW_POWER) - 1, // lower bound
+ static_cast<int32_t>(ExecutionPreference::SUSTAINED_SPEED) + 1, // upper bound
+};
+
+static void mutateExecutionPreferenceTest(const sp<IDevice>& device, const V1_1::Model& model) {
+ for (int32_t preference : invalidExecutionPreferences) {
+ const std::string message =
+ "mutateExecutionPreferenceTest: preference " + std::to_string(preference);
+ validate(device, message, model, [](Model*) {},
+ static_cast<ExecutionPreference>(preference));
+ }
+}
+
////////////////////////// ENTRY POINT //////////////////////////////
void ValidationTest::validateModel(const V1_1::Model& model) {
@@ -503,6 +528,7 @@
removeOperationOutputTest(device, model);
addOperationInputTest(device, model);
addOperationOutputTest(device, model);
+ mutateExecutionPreferenceTest(device, model);
}
} // namespace functional
diff --git a/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp
index bd96614..b42f561 100644
--- a/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp
+++ b/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp
@@ -60,8 +60,8 @@
// launch prepare model
sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
ASSERT_NE(nullptr, preparedModelCallback.get());
- Return<ErrorStatus> prepareLaunchStatus =
- device->prepareModel_1_1(model, preparedModelCallback);
+ Return<ErrorStatus> prepareLaunchStatus = device->prepareModel_1_1(
+ model, ExecutionPreference::FAST_SINGLE_ANSWER, preparedModelCallback);
ASSERT_TRUE(prepareLaunchStatus.isOk());
ASSERT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(prepareLaunchStatus));