Update neuralnetworks HAL to allow collecting execution duration.

Test: VtsHalNeuralnetworksV1_0TargetTest --hal_service_instance=android.hardware.neuralnetworks@1.0::IDevice/sample-all
Test: VtsHalNeuralnetworksV1_1TargetTest --hal_service_instance=android.hardware.neuralnetworks@1.1::IDevice/sample-all
Test: VtsHalNeuralnetworksV1_2TargetTest --hal_service_instance=android.hardware.neuralnetworks@1.2::IDevice/sample-all

Bug: 115390094

Change-Id: If67a5ffe39cfdd78498e01f26251734fdc8e66c7
diff --git a/neuralnetworks/1.2/IExecutionCallback.hal b/neuralnetworks/1.2/IExecutionCallback.hal
index 47de1b6..7f6c9ee 100644
--- a/neuralnetworks/1.2/IExecutionCallback.hal
+++ b/neuralnetworks/1.2/IExecutionCallback.hal
@@ -18,7 +18,6 @@
 
 import @1.0::ErrorStatus;
 import @1.0::IExecutionCallback;
-import OutputShape;
 
 /**
  * IExecutionCallback must be used to return the error status result from an
@@ -50,6 +49,11 @@
      *                     of the output operand in the Request outputs vector.
      *                     outputShapes must be empty unless the status is either
      *                     NONE or OUTPUT_INSUFFICIENT_SIZE.
+     * @return Timing Duration of execution. Unless MeasureTiming::YES was passed when
+     *                launching the execution and status is NONE, all times must
+     *                be reported as UINT64_MAX. A driver may choose to report
+     *                any time as UINT64_MAX, indicating that particular measurement is
+     *                not available.
      */
-    oneway notify_1_2(ErrorStatus status, vec<OutputShape> outputShapes);
+  oneway notify_1_2(ErrorStatus status, vec<OutputShape> outputShapes, Timing timing);
 };
diff --git a/neuralnetworks/1.2/IPreparedModel.hal b/neuralnetworks/1.2/IPreparedModel.hal
index 2d4e572..5d2d80f 100644
--- a/neuralnetworks/1.2/IPreparedModel.hal
+++ b/neuralnetworks/1.2/IPreparedModel.hal
@@ -59,6 +59,10 @@
      *
      * @param request The input and output information on which the prepared
      *                model is to be executed.
+     * @param measure Specifies whether or not to measure duration of the execution.
+     *                The duration runs from the time the driver sees the call
+     *                to the execute_1_2 function to the time the driver invokes
+     *                the callback.
      * @param callback A callback object used to return the error status of
      *                 the execution. The callback object's notify function must
      *                 be called exactly once, even if the execution was
@@ -72,7 +76,7 @@
      *                - INVALID_ARGUMENT if one of the input arguments is
      *                  invalid
      */
-    execute_1_2(Request request, IExecutionCallback callback)
+    execute_1_2(Request request, MeasureTiming measure, IExecutionCallback callback)
         generates (ErrorStatus status);
 
     /**
@@ -98,6 +102,10 @@
      *
      * @param request The input and output information on which the prepared
      *                model is to be executed.
+     * @param measure Specifies whether or not to measure duration of the execution.
+     *                The duration runs from the time the driver sees the call
+     *                to the executeSynchronously function to the time the driver
+     *                returns from the function.
      * @return status Error status of the execution, must be:
      *                - NONE if execution is performed successfully
      *                - DEVICE_UNAVAILABLE if driver is offline or busy
@@ -112,9 +120,13 @@
      *                      of the output operand in the Request outputs vector.
      *                      outputShapes must be empty unless the status is either
      *                      NONE or OUTPUT_INSUFFICIENT_SIZE.
+     * @return Timing Duration of execution. Unless measure is YES and status is
+     *                NONE, all times must be reported as UINT64_MAX. A driver may
+     *                choose to report any time as UINT64_MAX, indicating that
+     *                measurement is not available.
      */
-    executeSynchronously(Request request)
-        generates (ErrorStatus status, vec<OutputShape> outputShapes);
+    executeSynchronously(Request request, MeasureTiming measure)
+            generates (ErrorStatus status, vec<OutputShape> outputShapes, Timing timing);
 
     /**
      * Configure a Burst object used to execute multiple inferences on a
diff --git a/neuralnetworks/1.2/types.hal b/neuralnetworks/1.2/types.hal
index ce993d7..8bc28b4 100644
--- a/neuralnetworks/1.2/types.hal
+++ b/neuralnetworks/1.2/types.hal
@@ -447,8 +447,34 @@
 };
 
 /**
- * FmqRequestDatum is a single element of a serialized representation of a
- * {@link @1.0::Request} object which is sent across FastMessageQueue.
+ * Specifies whether or not to measure timing information during execution.
+ */
+enum MeasureTiming : int32_t {
+    NO  = 0,
+    YES = 1,
+};
+
+/**
+
+ * Timing information measured during execution. Each time is a duration from
+ * the beginning of some task to the end of that task, including time when that
+ * task is not active (for example, preempted by some other task, or
+ * waiting for some resource to become available).
+ *
+ * Times are measured in microseconds.
+ * When a time is not available, it must be reported as UINT64_MAX.
+ */
+struct Timing {
+    /** Execution time on device (not driver, which runs on host processor). */
+    uint64_t timeOnDevice;
+    /** Execution time in driver (including time on device). */
+    uint64_t timeInDriver;
+};
+
+/**
+ * FmqRequestDatum is a single element of a serialized representation of an
+ * execution request (a {@link @1.0::Request} object and a {@link MeasureTiming}
+ * value) which is sent across FastMessageQueue.
  *
  * The serialized representation for a particular execution is referred to later
  * in these descriptions as a 'packet'.
@@ -456,7 +482,7 @@
  * FastMessageQueue can only pass HIDL-defined types that do not involve nested
  * buffers, handles, or interfaces.
  *
- * The {@link @1.0::Request} is serialized as follows:
+ * The request is serialized as follows:
  * 1) 'packetInformation'
  * 2) For each input operand:
  *    2.1) 'inputOperandInformation'
@@ -468,6 +494,7 @@
  *         3.2.1) 'outputOperandDimensionValue'
  * 4) For each pool:
  *    4.1) 'poolIdentifier'
+ * 5) 'measureTiming'
  */
 safe_union FmqRequestDatum {
     /**
@@ -561,12 +588,21 @@
      * identifier.
      */
     int32_t poolIdentifier;
+
+    /**
+     * Specifies whether or not to measure duration of the execution. The
+     * duration runs from the time the driver dequeues the request from a
+     * FastMessageQueue to the time the driver enqueues results to a
+     * FastMessageQueue.
+     */
+    MeasureTiming measureTiming;
 };
 
 /**
  * FmqResultDatum is a single element of a serialized representation of the
- * values returned from an execution ({@link @1.0::ErrorStatus} and
- * vec<{@link OutputShape}>) which is returned via FastMessageQueue.
+ * values returned from an execution ({@link @1.0::ErrorStatus},
+ * vec<{@link OutputShape}>, and {@link Timing}) which is returned via
+ * FastMessageQueue.
  *
  * The serialized representation for a particular execution is referred to later
  * in these descriptions as a 'packet'.
@@ -581,6 +617,7 @@
  *    2.1) 'operandInformation'
  *    2.2) For each dimension element of the operand:
  *         2.2.1) 'operandDimensionValue'
+ * 3) 'executionTiming'
  */
 safe_union FmqResultDatum {
     /**
@@ -636,4 +673,12 @@
      * Element of the dimensions vector.
      */
     uint32_t operandDimensionValue;
+
+    /**
+     * Duration of execution. Unless measurement was requested and execution
+     * succeeds, all times must be reported as UINT64_MAX. A driver may choose
+     * to report any time as UINT64_MAX, indicating that measurement is not
+     * available.
+     */
+    Timing executionTiming;
 };
diff --git a/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp
index 1eaea4b..00a7c3e 100644
--- a/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp
+++ b/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp
@@ -42,6 +42,10 @@
 
 ///////////////////////// UTILITY FUNCTIONS /////////////////////////
 
+static bool badTiming(Timing timing) {
+    return timing.timeOnDevice == UINT64_MAX && timing.timeInDriver == UINT64_MAX;
+}
+
 static void createPreparedModel(const sp<IDevice>& device, const Model& model,
                                 sp<IPreparedModel>* preparedModel) {
     ASSERT_NE(nullptr, preparedModel);
@@ -98,31 +102,46 @@
                      Request request, const std::function<void(Request*)>& mutation) {
     mutation(&request);
 
+    // We'd like to test both with timing requested and without timing
+    // requested. Rather than running each test both ways, we'll decide whether
+    // to request timing by hashing the message. We do not use std::hash because
+    // it is not guaranteed stable across executions.
+    char hash = 0;
+    for (auto c : message) {
+        hash ^= c;
+    };
+    MeasureTiming measure = (hash & 1) ? MeasureTiming::YES : MeasureTiming::NO;
+
     {
         SCOPED_TRACE(message + " [execute_1_2]");
 
         sp<ExecutionCallback> executionCallback = new ExecutionCallback();
         ASSERT_NE(nullptr, executionCallback.get());
         Return<ErrorStatus> executeLaunchStatus =
-            preparedModel->execute_1_2(request, executionCallback);
+                preparedModel->execute_1_2(request, measure, executionCallback);
         ASSERT_TRUE(executeLaunchStatus.isOk());
         ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast<ErrorStatus>(executeLaunchStatus));
 
         executionCallback->wait();
         ErrorStatus executionReturnStatus = executionCallback->getStatus();
         const auto& outputShapes = executionCallback->getOutputShapes();
+        Timing timing = executionCallback->getTiming();
         ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, executionReturnStatus);
         ASSERT_EQ(outputShapes.size(), 0);
+        ASSERT_TRUE(badTiming(timing));
     }
 
     {
         SCOPED_TRACE(message + " [executeSynchronously]");
 
         Return<void> executeStatus = preparedModel->executeSynchronously(
-            request, [](ErrorStatus error, const hidl_vec<OutputShape>& outputShapes) {
-                ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, error);
-                EXPECT_EQ(outputShapes.size(), 0);
-            });
+                request, measure,
+                [](ErrorStatus error, const hidl_vec<OutputShape>& outputShapes,
+                   const Timing& timing) {
+                    ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, error);
+                    EXPECT_EQ(outputShapes.size(), 0);
+                    EXPECT_TRUE(badTiming(timing));
+                });
         ASSERT_TRUE(executeStatus.isOk());
     }
 }