tflite: mtk_neuron: Add AbortedWhenWaiting test

According to MTK's document, the abort time consider both model
inference time and waiting time.
This CL check if this is true by sending a large model to block the NPU
and send a small model with a slightly larger abort time.
The expected behavior is the small model will be aborted in the given
time frame, without needing to wait the large model complete its work.

BUG=b:374245241
TEST=neuron_delegate_test on navi

Change-Id: Ifc3503765e5337e16417deb61f9346d486747f02
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/tflite/+/6437797
Reviewed-by: Shik Chen <shik@chromium.org>
Commit-Queue: Tommy Chiang <ototot@google.com>
Tested-by: Tommy Chiang <ototot@google.com>
diff --git a/delegate/mtk_neuron/neuron_delegate_test.cc b/delegate/mtk_neuron/neuron_delegate_test.cc
index 90cdb34..03d1004 100644
--- a/delegate/mtk_neuron/neuron_delegate_test.cc
+++ b/delegate/mtk_neuron/neuron_delegate_test.cc
@@ -245,6 +245,18 @@
           kBatch * kSize * kSize * kChannels};
 }
 
+std::pair<std::unique_ptr<FlatBufferModel>, int> GetSmallModelAndBufferSize() {
+  // The model with these parameters runs <5ms on Navi.
+  constexpr int kBatch = 1;
+  constexpr int kSize = 2;
+  constexpr int kChannels = 1;
+  constexpr int kKernel = 1;
+  constexpr int kLayers = 1;
+  constexpr int kWidth = 1;
+  return {GetModel<kBatch, kSize, kChannels, kKernel, kLayers, kWidth>(),
+          kBatch * kSize * kSize * kChannels};
+}
+
 std::vector<float> GetRandomizedFloatData(int size) {
   absl::BitGen gen;
   std::vector<float> buffer(size);
@@ -413,6 +425,56 @@
   EXPECT_NEAR(FDivDuration(time_used1, time_used2), 2, 0.15);
 }
 
+TEST(NeuronDelegateTest, AbortedWhenWaiting) {
+  // Set optimization hints to OPTIMIZATION_LOW_LATENCY to ensure the model
+  // utilizing every NPU cores.
+  using MtkNeuronSettings_::OptimizationHint;
+  TFLiteSettingsT settings = GetDefaultSettings();
+  settings.mtk_neuron_settings->optimization_hints =
+      std::vector<OptimizationHint>{
+          OptimizationHint::OptimizationHint_OPTIMIZATION_LOW_LATENCY};
+
+  // Create the driver for a time consuming model without inferencing.
+  auto [big_model, big_model_buffer_size] =
+      GetTimeConsumingModelAndBufferSize();
+  auto big_model_driver =
+      PrepareSyncDriver(big_model, GetDelegateFromSettings(&settings),
+                        GetRandomizedFloatData(big_model_buffer_size));
+  ASSERT_NE(big_model_driver, nullptr);
+
+  // Since the small model usually finish in <5ms and the large model finish in
+  // >500ms, pick 50ms should be safe.
+  settings.mtk_neuron_settings->inference_abort_time_ms = 50;
+
+  // Create the driver for a small model without inferencing.
+  auto [small_model, small_model_buffer_size] = GetSmallModelAndBufferSize();
+  auto small_model_driver =
+      PrepareSyncDriver(small_model, GetDelegateFromSettings(&settings),
+                        GetRandomizedFloatData(small_model_buffer_size));
+  ASSERT_NE(small_model_driver, nullptr);
+
+  // Create a child thread to inference the time consuming model.
+  TfLiteStatus big_model_inference_status;
+  std::thread child_thread(
+      [&] { big_model_inference_status = big_model_driver->Invoke(); });
+
+  // Sleep 100ms to ensure the time consuming model is running first.
+  absl::SleepFor(absl::Milliseconds(100));
+  absl::Time before_invoke = absl::Now();
+  EXPECT_NE(small_model_driver->Invoke(), kTfLiteOk);
+  absl::Duration small_model_latency = absl::Now() - before_invoke;
+
+  child_thread.join();
+
+  // Time consuming model should be normally inferenced.
+  EXPECT_EQ(big_model_inference_status, kTfLiteOk);
+  // The time spent for small model should similar to abort_time_ms.
+  // Setting 100ms here to allow some overheads. This should not affect
+  // the effectiveness of the check since the time consuming model
+  // normally spent more than 500ms.
+  EXPECT_LT(small_model_latency, absl::Milliseconds(100));
+}
+
 }  // namespace tflite::cros::tests
 
 int main(int argc, char** argv) {