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
This commit is contained in:
parent
0a27ac19f2
commit
b8cf54cf5a
8 changed files with 133 additions and 25 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -40,6 +40,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);
|
||||
|
@ -276,8 +293,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 "
|
||||
|
@ -601,9 +642,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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -73,8 +73,8 @@ interface IPreparedModel {
|
|||
* runs from the time the driver sees the call to the executeSynchronously
|
||||
* function to the time the driver returns from the function.
|
||||
* @param deadline The time by which the execution is expected to complete. The time is measured
|
||||
* in nanoseconds since epoch of the steady clock (as from
|
||||
* std::chrono::steady_clock). If the execution cannot be finished by the
|
||||
* in nanoseconds since boot (as from clock_gettime(CLOCK_BOOTTIME, &ts) or
|
||||
* ::android::base::boot_clock). If the execution cannot be finished by the
|
||||
* deadline, the execution may be aborted. Passing -1 means the deadline is
|
||||
* omitted. Other negative values are invalid.
|
||||
* @param loopTimeoutDuration The maximum amount of time in nanoseconds that should be spent
|
||||
|
@ -138,8 +138,8 @@ interface IPreparedModel {
|
|||
* sync fences have been signaled.
|
||||
* @param measure Specifies whether or not to measure duration of the execution.
|
||||
* @param deadline The time by which the execution is expected to complete. The time is measured
|
||||
* in nanoseconds since epoch of the steady clock (as from
|
||||
* std::chrono::steady_clock).If the execution cannot be finished by the
|
||||
* in nanoseconds since boot (as from clock_gettime(CLOCK_BOOTTIME, &ts) or
|
||||
* ::android::base::boot_clock). If the execution cannot be finished by the
|
||||
* deadline, the execution may be aborted. Passing -1 means the deadline is
|
||||
* omitted. Other negative values are invalid.
|
||||
* @param loopTimeoutDuration The maximum amount of time in nanoseconds that should be spent
|
||||
|
|
|
@ -964,11 +964,12 @@ nn::GeneralResult<Timing> unvalidatedConvert(const nn::Timing& timing) {
|
|||
}
|
||||
|
||||
nn::GeneralResult<int64_t> unvalidatedConvert(const nn::Duration& duration) {
|
||||
const uint64_t nanoseconds = duration.count();
|
||||
if (nanoseconds > std::numeric_limits<int64_t>::max()) {
|
||||
return std::numeric_limits<int64_t>::max();
|
||||
if (duration < nn::Duration::zero()) {
|
||||
return NN_ERROR() << "Unable to convert invalid (negative) duration";
|
||||
}
|
||||
return static_cast<int64_t>(nanoseconds);
|
||||
constexpr std::chrono::nanoseconds::rep kIntMax = std::numeric_limits<int64_t>::max();
|
||||
const auto count = duration.count();
|
||||
return static_cast<int64_t>(std::min(count, kIntMax));
|
||||
}
|
||||
|
||||
nn::GeneralResult<int64_t> unvalidatedConvert(const nn::OptionalDuration& optionalDuration) {
|
||||
|
|
|
@ -14,10 +14,10 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <android-base/chrono_utils.h>
|
||||
#include <android/binder_enums.h>
|
||||
#include <android/binder_interface_utils.h>
|
||||
#include <android/binder_status.h>
|
||||
|
||||
#include <nnapi/hal/aidl/Conversions.h>
|
||||
|
||||
#include "Callbacks.h"
|
||||
|
@ -61,16 +61,16 @@ static int64_t makeDeadline(DeadlineBoundType deadlineBoundType) {
|
|||
return std::chrono::duration_cast<std::chrono::nanoseconds>(timeSinceEpoch).count();
|
||||
};
|
||||
|
||||
std::chrono::steady_clock::time_point timePoint;
|
||||
::android::base::boot_clock::time_point timePoint;
|
||||
switch (deadlineBoundType) {
|
||||
case DeadlineBoundType::NOW:
|
||||
timePoint = std::chrono::steady_clock::now();
|
||||
timePoint = ::android::base::boot_clock::now();
|
||||
break;
|
||||
case DeadlineBoundType::UNLIMITED:
|
||||
timePoint = std::chrono::steady_clock::time_point::max();
|
||||
timePoint = ::android::base::boot_clock::time_point::max();
|
||||
break;
|
||||
case DeadlineBoundType::SHORT:
|
||||
timePoint = std::chrono::steady_clock::now() + kShortDuration;
|
||||
timePoint = ::android::base::boot_clock::now() + kShortDuration;
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue