Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4895b4df authored by Michael Butler's avatar Michael Butler
Browse files

Change NNAPI time from steady_clock to boot_clock -- hal

Previously, the NNAPI used std::chrono::steady_clock to represent and
measure timings. However, steady_clock does not count while the system
is suspended. Instead, boot_clock is monotonic like steady_clock but
does include the time when the system is suspended.

This change also indicates that services may convert from
std::chrono::steady_clock::time_point to
android::base::boot_clock::time_point in the HIDL 1.3 NN HAL.

Bug: 183118340
Test: mma
Test: VtsHalNeuralnetworksV1_3TargetTest
Test: VtsHalNeuralnetworksTargetTest
Test: presubmit
Change-Id: I5a7d039a31d9ce98602a301387ec99635f279f42
Merged-In: I5a7d039a31d9ce98602a301387ec99635f279f42
parent 42d9f3f3
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -782,6 +782,8 @@ cd84ab19c590e0e73dd2307b591a3093ee18147ef95e6d5418644463a6620076 android.hardwar
f729ee6a5f136b25d79ea6895d24700fce413df555baaecf2c39e4440d15d043 android.hardware.neuralnetworks@1.0::types
a84f8dac7a9b75de1cc2936a9b429b9b62b32a31ea88ca52c29f98f5ddc0fa95 android.hardware.neuralnetworks@1.2::types
cd331b92312d16ab89f475c39296abbf539efc4114a8c5c2b136ad99b904ef33 android.hardware.neuralnetworks@1.3::types
c3fec5bd470984402997f78a74b6511efc4063b270f2bd9ee7b78f48b683a1bb android.hardware.neuralnetworks@1.3::IDevice
0fdfad62c2ec33b52e6687004e5a1971c02d10b93ee4d26df5ccff7ce032494a android.hardware.neuralnetworks@1.3::IPreparedModel
e8c86c69c438da8d1549856c1bb3e2d1b8da52722f8235ff49a30f2cce91742c android.hardware.soundtrigger@2.1::ISoundTriggerHwCallback
b9fbb6e2e061ed0960939d48b785e9700210add1f13ed32ecd688d0f1ca20ef7 android.hardware.renderscript@1.0::types
0f53d70e1eadf8d987766db4bf6ae2048004682168f4cab118da576787def3fa android.hardware.radio@1.0::types
+17 −1
Original line number Diff line number Diff line
@@ -131,6 +131,14 @@ interface IDevice extends @1.2::IDevice {
     * ErrorStatus::MISSED_DEADLINE_TRANSIENT} or {@link
     * ErrorStatus::MISSED_DEADLINE_PERSISTENT} may be returned. The error due
     * to an abort must be sent the same way as other errors, described above.
     * The deadline is represented as nanoseconds since the epoch of the steady
     * clock (as if from std::chrono::steady_clock::time_point), but the service
     * may convert it to the nanoseconds since boot time (as if from
     * clock_gettime(CLOCK_BOOTTIME, &ts) or
     * android::base::boot_clock::time_point) to account for time when the
     * system is suspended. This conversion can by done by finding the timeout
     * duration remaining compared to the steady_clock and adding it to the
     * current boot_clock time.
     *
     * Optionally, the driver may save the prepared model to cache during the
     * asynchronous preparation. Any error that occurs when saving to cache must
@@ -249,7 +257,15 @@ interface IDevice extends @1.2::IDevice {
     * ErrorStatus::MISSED_DEADLINE_TRANSIENT}
     * or {@link ErrorStatus::MISSED_DEADLINE_PERSISTENT} may be returned. The
     * error due to an abort must be sent the same way as other errors,
     * described above.
     * described above. The deadline is represented as nanoseconds since the
     * epoch of the steady clock (as if from
     * std::chrono::steady_clock::time_point), but the service may convert it to
     * the nanoseconds since boot time (as if from
     * clock_gettime(CLOCK_BOOTTIME, &ts) or
     * android::base::boot_clock::time_point) to account for time when the
     * system is suspended. This conversion can by done by finding the timeout
     * duration remaining compared to the steady_clock and adding it to the
     * current boot_clock time.
     *
     * The only information that may be unknown to the model at this stage is
     * the shape of the tensors, which may only be known at execution time. As
+24 −0
Original line number Diff line number Diff line
@@ -74,6 +74,14 @@ interface IPreparedModel extends @1.2::IPreparedModel {
     * ErrorStatus::MISSED_DEADLINE_TRANSIENT} or {@link
     * ErrorStatus::MISSED_DEADLINE_PERSISTENT} may be returned. The error due
     * to an abort must be sent the same way as other errors, described above.
     * The deadline is represented as nanoseconds since the epoch of the steady
     * clock (as if from std::chrono::steady_clock::time_point), but the service
     * may convert it to the nanoseconds since boot time (as if from
     * clock_gettime(CLOCK_BOOTTIME, &ts) or
     * android::base::boot_clock::time_point) to account for time when the
     * system is suspended. This conversion can by done by finding the timeout
     * duration remaining compared to the steady_clock and adding it to the
     * current boot_clock time.
     *
     * Any number of calls to the execute* and executeSynchronously* functions,
     * in any combination, may be made concurrently, even on the same
@@ -150,6 +158,14 @@ interface IPreparedModel extends @1.2::IPreparedModel {
     * ErrorStatus::MISSED_DEADLINE_TRANSIENT} or {@link
     * ErrorStatus::MISSED_DEADLINE_PERSISTENT} may be returned. The error due
     * to an abort must be sent the same way as other errors, described above.
     * The deadline is represented as nanoseconds since the epoch of the steady
     * clock (as if from std::chrono::steady_clock::time_point), but the service
     * may convert it to the nanoseconds since boot time (as if from
     * clock_gettime(CLOCK_BOOTTIME, &ts) or
     * android::base::boot_clock::time_point) to account for time when the
     * system is suspended. This conversion can by done by finding the timeout
     * duration remaining compared to the steady_clock and adding it to the
     * current boot_clock time.
     *
     * Any number of calls to the execute* and executeSynchronously* functions,
     * in any combination, may be made concurrently, even on the same
@@ -231,6 +247,14 @@ interface IPreparedModel extends @1.2::IPreparedModel {
     * {@link ErrorStatus::MISSED_DEADLINE_TRANSIENT} or {@link
     * ErrorStatus::MISSED_DEADLINE_PERSISTENT} may be returned. The error due
     * to an abort must be sent the same way as other errors, described above.
     * The deadline is represented as nanoseconds since the epoch of the steady
     * clock (as if from std::chrono::steady_clock::time_point), but the service
     * may convert it to the nanoseconds since boot time (as if from
     * clock_gettime(CLOCK_BOOTTIME, &ts) or
     * android::base::boot_clock::time_point) to account for time when the
     * system is suspended. This conversion can by done by finding the timeout
     * duration remaining compared to the steady_clock and adding it to the
     * current boot_clock time.
     *
     * If any of the sync fences in waitFor changes to error status after the executeFenced
     * call succeeds, or the execution is aborted because it cannot finish before the deadline
+68 −3
Original line number Diff line number Diff line
@@ -42,6 +42,23 @@

namespace {

std::chrono::nanoseconds makeNanosFromUint64(uint64_t nanoseconds) {
    constexpr auto kMaxCount = std::chrono::nanoseconds::max().count();
    using CommonType = std::common_type_t<std::chrono::nanoseconds::rep, uint64_t>;
    const auto count = std::min<CommonType>(kMaxCount, nanoseconds);
    return std::chrono::nanoseconds{static_cast<std::chrono::nanoseconds::rep>(count)};
}

uint64_t makeUint64FromNanos(std::chrono::nanoseconds nanoseconds) {
    if (nanoseconds < std::chrono::nanoseconds::zero()) {
        return 0;
    }
    constexpr auto kMaxCount = std::numeric_limits<uint64_t>::max();
    using CommonType = std::common_type_t<std::chrono::nanoseconds::rep, uint64_t>;
    const auto count = std::min<CommonType>(kMaxCount, nanoseconds.count());
    return static_cast<uint64_t>(count);
}

template <typename Type>
constexpr std::underlying_type_t<Type> underlyingType(Type value) {
    return static_cast<std::underlying_type_t<Type>>(value);
@@ -237,8 +254,32 @@ GeneralResult<OptionalTimePoint> unvalidatedConvert(
    switch (optionalTimePoint.getDiscriminator()) {
        case Discriminator::none:
            return {};
        case Discriminator::nanosecondsSinceEpoch:
            return TimePoint{Duration{optionalTimePoint.nanosecondsSinceEpoch()}};
        case Discriminator::nanosecondsSinceEpoch: {
            const auto currentSteadyTime = std::chrono::steady_clock::now();
            const auto currentBootTime = Clock::now();

            const auto timeSinceEpoch =
                    makeNanosFromUint64(optionalTimePoint.nanosecondsSinceEpoch());
            const auto steadyTimePoint = std::chrono::steady_clock::time_point{timeSinceEpoch};

            // Both steadyTimePoint and currentSteadyTime are guaranteed to be non-negative, so this
            // subtraction will never overflow or underflow.
            const auto timeRemaining = steadyTimePoint - currentSteadyTime;

            // currentBootTime is guaranteed to be non-negative, so this code only protects against
            // an overflow.
            nn::TimePoint bootTimePoint;
            constexpr auto kZeroNano = std::chrono::nanoseconds::zero();
            constexpr auto kMaxTime = nn::TimePoint::max();
            if (timeRemaining > kZeroNano && currentBootTime > kMaxTime - timeRemaining) {
                bootTimePoint = kMaxTime;
            } else {
                bootTimePoint = currentBootTime + timeRemaining;
            }

            constexpr auto kZeroTime = nn::TimePoint{};
            return std::max(bootTimePoint, kZeroTime);
        }
    }
    return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
           << "Invalid OptionalTimePoint discriminator "
@@ -549,9 +590,33 @@ nn::GeneralResult<Request::MemoryPool> unvalidatedConvert(

nn::GeneralResult<OptionalTimePoint> unvalidatedConvert(
        const nn::OptionalTimePoint& optionalTimePoint) {
    const auto currentSteadyTime = std::chrono::steady_clock::now();
    const auto currentBootTime = nn::Clock::now();

    OptionalTimePoint ret;
    if (optionalTimePoint.has_value()) {
        const auto count = optionalTimePoint.value().time_since_epoch().count();
        const auto bootTimePoint = optionalTimePoint.value();

        if (bootTimePoint < nn::TimePoint{}) {
            return NN_ERROR() << "Trying to cast invalid time point";
        }

        // Both bootTimePoint and currentBootTime are guaranteed to be non-negative, so this
        // subtraction will never overflow or underflow.
        const auto timeRemaining = bootTimePoint - currentBootTime;

        // currentSteadyTime is guaranteed to be non-negative, so this code only protects against an
        // overflow.
        std::chrono::steady_clock::time_point steadyTimePoint;
        constexpr auto kZeroNano = std::chrono::nanoseconds::zero();
        constexpr auto kMaxTime = std::chrono::steady_clock::time_point::max();
        if (timeRemaining > kZeroNano && currentSteadyTime > kMaxTime - timeRemaining) {
            steadyTimePoint = kMaxTime;
        } else {
            steadyTimePoint = currentSteadyTime + timeRemaining;
        }

        const uint64_t count = makeUint64FromNanos(steadyTimePoint.time_since_epoch());
        ret.nanosecondsSinceEpoch(count);
    }
    return ret;
+8 −8
Original line number Diff line number Diff line
@@ -307,10 +307,10 @@ interface IDevice {
     * @param priority The priority of the prepared model relative to other prepared models owned by
     *                 the client.
     * @param deadline The time by which the model is expected to be prepared. The time is measured
     *                 in nanoseconds since epoch of the steady clock (as from
     *                 std::chrono::steady_clock). If the model cannot be prepared by the deadline,
     *                 the preparation may be aborted. Passing -1 means the deadline is omitted.
     *                 Other negative values are invalid.
     *                 in nanoseconds since boot (as from clock_gettime(CLOCK_BOOTTIME, &ts)
     *                 or ::android::base::boot_clock). If the model cannot be prepared by the
     *                 deadline, the preparation may be aborted. Passing -1 means the deadline is
     *                 omitted. Other negative values are invalid.
     * @param modelCache A vector of file descriptors for the security-sensitive cache. The length
     *                   of the vector must either be 0 indicating that caching information is not
     *                   provided, or match the numModelCache returned from
@@ -396,10 +396,10 @@ interface IDevice {
     * different shapes of inputs on different (possibly concurrent) executions.
     *
     * @param deadline The time by which the model is expected to be prepared. The time is measured
     *                 in nanoseconds since epoch of the steady clock (as from
     *                 std::chrono::steady_clock). If the model cannot be prepared by the deadline,
     *                 the preparation may be aborted. Passing -1 means the deadline is omitted.
     *                 Other negative values are invalid.
     *                 in nanoseconds since boot (as from clock_gettime(CLOCK_BOOTTIME, &ts) or
     *                 ::android::base::boot_clock). If the model cannot be prepared by the
     *                 deadline, the preparation may be aborted. Passing -1 means the deadline is
     *                 omitted. Other negative values are invalid.
     * @param modelCache A vector of file descriptors for the security-sensitive cache. The length
     *                   of the vector must match the numModelCache returned from
     *                   getNumberOfCacheFilesNeeded. The cache file descriptors will be provided in
Loading