mirror of
https://github.com/Evolution-X/hardware_interfaces
synced 2026-02-01 22:04:26 +00:00
Cleanup NN callback error handling am: 7fd03c265e
Original change: https://android-review.googlesource.com/c/platform/hardware/interfaces/+/1534940 MUST ONLY BE SUBMITTED BY AUTOMERGER Change-Id: I43a46c563a91851777bc0ef55949eb5c25eb5f9c
This commit is contained in:
@@ -32,6 +32,26 @@
|
||||
|
||||
namespace android::hardware::neuralnetworks::V1_0::utils {
|
||||
|
||||
// Converts the results of IDevice::getSupportedOperations* to the NN canonical format. On success,
|
||||
// this function returns with the supported operations as indicated by a driver. On failure, this
|
||||
// function returns with the appropriate nn::GeneralError.
|
||||
nn::GeneralResult<std::vector<bool>> supportedOperationsCallback(
|
||||
ErrorStatus status, const hidl_vec<bool>& supportedOperations);
|
||||
|
||||
// Converts the results of IDevice::prepareModel* to the NN canonical format. On success, this
|
||||
// function returns with a non-null nn::SharedPreparedModel with a feature level of
|
||||
// nn::Version::ANDROID_OC_MR1. On failure, this function returns with the appropriate
|
||||
// nn::GeneralError.
|
||||
nn::GeneralResult<nn::SharedPreparedModel> prepareModelCallback(
|
||||
ErrorStatus status, const sp<IPreparedModel>& preparedModel);
|
||||
|
||||
// Converts the results of IDevice::execute* to the NN canonical format. On success, this function
|
||||
// returns with an empty output shape vector and no timing information. On failure, this function
|
||||
// returns with the appropriate nn::ExecutionError.
|
||||
nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> executionCallback(
|
||||
ErrorStatus status);
|
||||
|
||||
// A HIDL callback class to receive the results of IDevice::prepareModel asynchronously.
|
||||
class PreparedModelCallback final : public IPreparedModelCallback,
|
||||
public hal::utils::IProtectedCallback {
|
||||
public:
|
||||
@@ -44,11 +64,10 @@ class PreparedModelCallback final : public IPreparedModelCallback,
|
||||
Data get();
|
||||
|
||||
private:
|
||||
void notifyInternal(Data result);
|
||||
|
||||
hal::utils::TransferValue<Data> mData;
|
||||
};
|
||||
|
||||
// A HIDL callback class to receive the results of IDevice::execute asynchronously.
|
||||
class ExecutionCallback final : public IExecutionCallback, public hal::utils::IProtectedCallback {
|
||||
public:
|
||||
using Data = nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>;
|
||||
@@ -60,8 +79,6 @@ class ExecutionCallback final : public IExecutionCallback, public hal::utils::IP
|
||||
Data get();
|
||||
|
||||
private:
|
||||
void notifyInternal(Data result);
|
||||
|
||||
hal::utils::TransferValue<Data> mData;
|
||||
};
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <nnapi/Result.h>
|
||||
#include <nnapi/Types.h>
|
||||
#include <nnapi/hal/CommonUtils.h>
|
||||
#include <nnapi/hal/HandleError.h>
|
||||
#include <nnapi/hal/ProtectCallback.h>
|
||||
#include <nnapi/hal/TransferValue.h>
|
||||
|
||||
@@ -36,63 +37,52 @@
|
||||
// lifetimes across processes and for protecting asynchronous calls across HIDL.
|
||||
|
||||
namespace android::hardware::neuralnetworks::V1_0::utils {
|
||||
namespace {
|
||||
|
||||
nn::GeneralResult<nn::SharedPreparedModel> convertPreparedModel(
|
||||
const sp<IPreparedModel>& preparedModel) {
|
||||
return NN_TRY(utils::PreparedModel::create(preparedModel));
|
||||
nn::GeneralResult<std::vector<bool>> supportedOperationsCallback(
|
||||
ErrorStatus status, const hidl_vec<bool>& supportedOperations) {
|
||||
HANDLE_HAL_STATUS(status) << "get supported operations failed with " << toString(status);
|
||||
return supportedOperations;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
nn::GeneralResult<nn::SharedPreparedModel> prepareModelCallback(
|
||||
ErrorStatus status, const sp<IPreparedModel>& preparedModel) {
|
||||
HANDLE_HAL_STATUS(status) << "model preparation failed with " << toString(status);
|
||||
return NN_TRY(PreparedModel::create(preparedModel));
|
||||
}
|
||||
|
||||
nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> executionCallback(
|
||||
ErrorStatus status) {
|
||||
HANDLE_HAL_STATUS(status) << "execution failed with " << toString(status);
|
||||
return {};
|
||||
}
|
||||
|
||||
Return<void> PreparedModelCallback::notify(ErrorStatus status,
|
||||
const sp<IPreparedModel>& preparedModel) {
|
||||
if (status != ErrorStatus::NONE) {
|
||||
const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
|
||||
notifyInternal(NN_ERROR(canonical) << "preparedModel failed with " << toString(status));
|
||||
} else if (preparedModel == nullptr) {
|
||||
notifyInternal(NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
|
||||
<< "Returned preparedModel is nullptr");
|
||||
} else {
|
||||
notifyInternal(convertPreparedModel(preparedModel));
|
||||
}
|
||||
mData.put(prepareModelCallback(status, preparedModel));
|
||||
return Void();
|
||||
}
|
||||
|
||||
void PreparedModelCallback::notifyAsDeadObject() {
|
||||
notifyInternal(NN_ERROR(nn::ErrorStatus::DEAD_OBJECT) << "Dead object");
|
||||
mData.put(NN_ERROR(nn::ErrorStatus::DEAD_OBJECT) << "Dead object");
|
||||
}
|
||||
|
||||
PreparedModelCallback::Data PreparedModelCallback::get() {
|
||||
return mData.take();
|
||||
}
|
||||
|
||||
void PreparedModelCallback::notifyInternal(PreparedModelCallback::Data result) {
|
||||
mData.put(std::move(result));
|
||||
}
|
||||
|
||||
// ExecutionCallback methods begin here
|
||||
|
||||
Return<void> ExecutionCallback::notify(ErrorStatus status) {
|
||||
if (status != ErrorStatus::NONE) {
|
||||
const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
|
||||
notifyInternal(NN_ERROR(canonical) << "execute failed with " << toString(status));
|
||||
} else {
|
||||
notifyInternal({});
|
||||
}
|
||||
mData.put(executionCallback(status));
|
||||
return Void();
|
||||
}
|
||||
|
||||
void ExecutionCallback::notifyAsDeadObject() {
|
||||
notifyInternal(NN_ERROR(nn::ErrorStatus::DEAD_OBJECT) << "Dead object");
|
||||
mData.put(NN_ERROR(nn::ErrorStatus::DEAD_OBJECT) << "Dead object");
|
||||
}
|
||||
|
||||
ExecutionCallback::Data ExecutionCallback::get() {
|
||||
return mData.take();
|
||||
}
|
||||
|
||||
void ExecutionCallback::notifyInternal(ExecutionCallback::Data result) {
|
||||
mData.put(std::move(result));
|
||||
}
|
||||
|
||||
} // namespace android::hardware::neuralnetworks::V1_0::utils
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <nnapi/hal/CommonUtils.h>
|
||||
#include <nnapi/hal/HandleError.h>
|
||||
#include <nnapi/hal/ProtectCallback.h>
|
||||
#include <nnapi/hal/TransferValue.h>
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
@@ -44,24 +45,21 @@
|
||||
namespace android::hardware::neuralnetworks::V1_0::utils {
|
||||
namespace {
|
||||
|
||||
nn::GeneralResult<nn::Capabilities> initCapabilities(V1_0::IDevice* device) {
|
||||
nn::GeneralResult<nn::Capabilities> capabilitiesCallback(ErrorStatus status,
|
||||
const Capabilities& capabilities) {
|
||||
HANDLE_HAL_STATUS(status) << "getting capabilities failed with " << toString(status);
|
||||
return nn::convert(capabilities);
|
||||
}
|
||||
|
||||
nn::GeneralResult<nn::Capabilities> getCapabilitiesFrom(V1_0::IDevice* device) {
|
||||
CHECK(device != nullptr);
|
||||
|
||||
nn::GeneralResult<nn::Capabilities> result = NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
|
||||
<< "uninitialized";
|
||||
const auto cb = [&result](ErrorStatus status, const Capabilities& capabilities) {
|
||||
if (status != ErrorStatus::NONE) {
|
||||
const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
|
||||
result = NN_ERROR(canonical) << "getCapabilities failed with " << toString(status);
|
||||
} else {
|
||||
result = nn::convert(capabilities);
|
||||
}
|
||||
};
|
||||
auto cb = hal::utils::CallbackValue(capabilitiesCallback);
|
||||
|
||||
const auto ret = device->getCapabilities(cb);
|
||||
HANDLE_TRANSPORT_FAILURE(ret);
|
||||
|
||||
return result;
|
||||
return cb.take();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@@ -77,7 +75,7 @@ nn::GeneralResult<std::shared_ptr<const Device>> Device::create(std::string name
|
||||
<< "V1_0::utils::Device::create must have non-null device";
|
||||
}
|
||||
|
||||
auto capabilities = NN_TRY(initCapabilities(device.get()));
|
||||
auto capabilities = NN_TRY(getCapabilitiesFrom(device.get()));
|
||||
|
||||
auto deathHandler = NN_TRY(hal::utils::DeathHandler::create(device));
|
||||
return std::make_shared<const Device>(PrivateConstructorTag{}, std::move(name),
|
||||
@@ -134,27 +132,12 @@ nn::GeneralResult<std::vector<bool>> Device::getSupportedOperations(const nn::Mo
|
||||
|
||||
const auto hidlModel = NN_TRY(convert(modelInShared));
|
||||
|
||||
nn::GeneralResult<std::vector<bool>> result = NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
|
||||
<< "uninitialized";
|
||||
auto cb = [&result, &model](ErrorStatus status, const hidl_vec<bool>& supportedOperations) {
|
||||
if (status != ErrorStatus::NONE) {
|
||||
const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
|
||||
result = NN_ERROR(canonical)
|
||||
<< "getSupportedOperations failed with " << toString(status);
|
||||
} else if (supportedOperations.size() != model.main.operations.size()) {
|
||||
result = NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
|
||||
<< "getSupportedOperations returned vector of size "
|
||||
<< supportedOperations.size() << " but expected "
|
||||
<< model.main.operations.size();
|
||||
} else {
|
||||
result = supportedOperations;
|
||||
}
|
||||
};
|
||||
auto cb = hal::utils::CallbackValue(supportedOperationsCallback);
|
||||
|
||||
const auto ret = kDevice->getSupportedOperations(hidlModel, cb);
|
||||
HANDLE_TRANSPORT_FAILURE(ret);
|
||||
|
||||
return result;
|
||||
return cb.take();
|
||||
}
|
||||
|
||||
nn::GeneralResult<nn::SharedPreparedModel> Device::prepareModel(
|
||||
@@ -173,10 +156,7 @@ nn::GeneralResult<nn::SharedPreparedModel> Device::prepareModel(
|
||||
|
||||
const auto ret = kDevice->prepareModel(hidlModel, cb);
|
||||
const auto status = HANDLE_TRANSPORT_FAILURE(ret);
|
||||
if (status != ErrorStatus::NONE) {
|
||||
const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
|
||||
return NN_ERROR(canonical) << "prepareModel failed with " << toString(status);
|
||||
}
|
||||
HANDLE_HAL_STATUS(status) << "model preparation failed with " << toString(status);
|
||||
|
||||
return cb->get();
|
||||
}
|
||||
|
||||
@@ -42,8 +42,7 @@ namespace android::hardware::neuralnetworks::V1_0::utils {
|
||||
nn::GeneralResult<std::shared_ptr<const PreparedModel>> PreparedModel::create(
|
||||
sp<V1_0::IPreparedModel> preparedModel) {
|
||||
if (preparedModel == nullptr) {
|
||||
return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
|
||||
<< "V1_0::utils::PreparedModel::create must have non-null preparedModel";
|
||||
return NN_ERROR() << "V1_0::utils::PreparedModel::create must have non-null preparedModel";
|
||||
}
|
||||
|
||||
auto deathHandler = NN_TRY(hal::utils::DeathHandler::create(preparedModel));
|
||||
@@ -71,10 +70,7 @@ nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> Prepare
|
||||
|
||||
const auto ret = kPreparedModel->execute(hidlRequest, cb);
|
||||
const auto status = HANDLE_TRANSPORT_FAILURE(ret);
|
||||
if (status != ErrorStatus::NONE) {
|
||||
const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
|
||||
return NN_ERROR(canonical) << "execute failed with " << toString(status);
|
||||
}
|
||||
HANDLE_HAL_STATUS(status) << "execution failed with " << toString(status);
|
||||
|
||||
auto result = NN_TRY(cb->get());
|
||||
NN_TRY(hal::utils::makeExecutionFailure(
|
||||
|
||||
@@ -51,6 +51,10 @@ nn::GeneralResult<Capabilities> convert(const nn::Capabilities& capabilities);
|
||||
nn::GeneralResult<Model> convert(const nn::Model& model);
|
||||
nn::GeneralResult<ExecutionPreference> convert(const nn::ExecutionPreference& executionPreference);
|
||||
|
||||
nn::GeneralResult<V1_0::DeviceStatus> convert(const nn::DeviceStatus& deviceStatus);
|
||||
nn::GeneralResult<V1_0::Request> convert(const nn::Request& request);
|
||||
nn::GeneralResult<V1_0::ErrorStatus> convert(const nn::ErrorStatus& status);
|
||||
|
||||
} // namespace android::hardware::neuralnetworks::V1_1::utils
|
||||
|
||||
#endif // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_1_CONVERSIONS_H
|
||||
|
||||
@@ -275,4 +275,16 @@ nn::GeneralResult<ExecutionPreference> convert(const nn::ExecutionPreference& ex
|
||||
return validatedConvert(executionPreference);
|
||||
}
|
||||
|
||||
nn::GeneralResult<V1_0::DeviceStatus> convert(const nn::DeviceStatus& deviceStatus) {
|
||||
return V1_0::utils::convert(deviceStatus);
|
||||
}
|
||||
|
||||
nn::GeneralResult<V1_0::Request> convert(const nn::Request& request) {
|
||||
return V1_0::utils::convert(request);
|
||||
}
|
||||
|
||||
nn::GeneralResult<V1_0::ErrorStatus> convert(const nn::ErrorStatus& status) {
|
||||
return V1_0::utils::convert(status);
|
||||
}
|
||||
|
||||
} // namespace android::hardware::neuralnetworks::V1_1::utils
|
||||
|
||||
@@ -45,24 +45,21 @@
|
||||
namespace android::hardware::neuralnetworks::V1_1::utils {
|
||||
namespace {
|
||||
|
||||
nn::GeneralResult<nn::Capabilities> initCapabilities(V1_1::IDevice* device) {
|
||||
nn::GeneralResult<nn::Capabilities> capabilitiesCallback(V1_0::ErrorStatus status,
|
||||
const Capabilities& capabilities) {
|
||||
HANDLE_HAL_STATUS(status) << "getting capabilities failed with " << toString(status);
|
||||
return nn::convert(capabilities);
|
||||
}
|
||||
|
||||
nn::GeneralResult<nn::Capabilities> getCapabilitiesFrom(V1_1::IDevice* device) {
|
||||
CHECK(device != nullptr);
|
||||
|
||||
nn::GeneralResult<nn::Capabilities> result = NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
|
||||
<< "uninitialized";
|
||||
const auto cb = [&result](V1_0::ErrorStatus status, const Capabilities& capabilities) {
|
||||
if (status != V1_0::ErrorStatus::NONE) {
|
||||
const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
|
||||
result = NN_ERROR(canonical) << "getCapabilities_1_1 failed with " << toString(status);
|
||||
} else {
|
||||
result = nn::convert(capabilities);
|
||||
}
|
||||
};
|
||||
auto cb = hal::utils::CallbackValue(capabilitiesCallback);
|
||||
|
||||
const auto ret = device->getCapabilities_1_1(cb);
|
||||
HANDLE_TRANSPORT_FAILURE(ret);
|
||||
|
||||
return result;
|
||||
return cb.take();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@@ -78,7 +75,7 @@ nn::GeneralResult<std::shared_ptr<const Device>> Device::create(std::string name
|
||||
<< "V1_1::utils::Device::create must have non-null device";
|
||||
}
|
||||
|
||||
auto capabilities = NN_TRY(initCapabilities(device.get()));
|
||||
auto capabilities = NN_TRY(getCapabilitiesFrom(device.get()));
|
||||
|
||||
auto deathHandler = NN_TRY(hal::utils::DeathHandler::create(device));
|
||||
return std::make_shared<const Device>(PrivateConstructorTag{}, std::move(name),
|
||||
@@ -135,28 +132,12 @@ nn::GeneralResult<std::vector<bool>> Device::getSupportedOperations(const nn::Mo
|
||||
|
||||
const auto hidlModel = NN_TRY(convert(modelInShared));
|
||||
|
||||
nn::GeneralResult<std::vector<bool>> result = NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
|
||||
<< "uninitialized";
|
||||
auto cb = [&result, &model](V1_0::ErrorStatus status,
|
||||
const hidl_vec<bool>& supportedOperations) {
|
||||
if (status != V1_0::ErrorStatus::NONE) {
|
||||
const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
|
||||
result = NN_ERROR(canonical)
|
||||
<< "getSupportedOperations_1_1 failed with " << toString(status);
|
||||
} else if (supportedOperations.size() != model.main.operations.size()) {
|
||||
result = NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
|
||||
<< "getSupportedOperations_1_1 returned vector of size "
|
||||
<< supportedOperations.size() << " but expected "
|
||||
<< model.main.operations.size();
|
||||
} else {
|
||||
result = supportedOperations;
|
||||
}
|
||||
};
|
||||
auto cb = hal::utils::CallbackValue(V1_0::utils::supportedOperationsCallback);
|
||||
|
||||
const auto ret = kDevice->getSupportedOperations_1_1(hidlModel, cb);
|
||||
HANDLE_TRANSPORT_FAILURE(ret);
|
||||
|
||||
return result;
|
||||
return cb.take();
|
||||
}
|
||||
|
||||
nn::GeneralResult<nn::SharedPreparedModel> Device::prepareModel(
|
||||
@@ -176,10 +157,7 @@ nn::GeneralResult<nn::SharedPreparedModel> Device::prepareModel(
|
||||
|
||||
const auto ret = kDevice->prepareModel_1_1(hidlModel, hidlPreference, cb);
|
||||
const auto status = HANDLE_TRANSPORT_FAILURE(ret);
|
||||
if (status != V1_0::ErrorStatus::NONE) {
|
||||
const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
|
||||
return NN_ERROR(canonical) << "prepareModel failed with " << toString(status);
|
||||
}
|
||||
HANDLE_HAL_STATUS(status) << "model preparation failed with " << toString(status);
|
||||
|
||||
return cb->get();
|
||||
}
|
||||
|
||||
@@ -36,6 +36,19 @@
|
||||
|
||||
namespace android::hardware::neuralnetworks::V1_2::utils {
|
||||
|
||||
// Converts the results of IDevice::prepareModel* to the NN canonical format. On success, this
|
||||
// function returns with a non-null nn::SharedPreparedModel with a feature level of
|
||||
// nn::Version::ANDROID_Q. On failure, this function returns with the appropriate nn::GeneralError.
|
||||
nn::GeneralResult<nn::SharedPreparedModel> prepareModelCallback(
|
||||
V1_0::ErrorStatus status, const sp<IPreparedModel>& preparedModel);
|
||||
|
||||
// Converts the results of IDevice::execute* to the NN canonical format. On success, this function
|
||||
// returns with the output shapes and the timing information. On failure, this function returns with
|
||||
// the appropriate nn::ExecutionError.
|
||||
nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> executionCallback(
|
||||
V1_0::ErrorStatus status, const hidl_vec<OutputShape>& outputShapes, const Timing& timing);
|
||||
|
||||
// A HIDL callback class to receive the results of IDevice::prepareModel* asynchronously.
|
||||
class PreparedModelCallback final : public IPreparedModelCallback,
|
||||
public hal::utils::IProtectedCallback {
|
||||
public:
|
||||
@@ -51,11 +64,10 @@ class PreparedModelCallback final : public IPreparedModelCallback,
|
||||
Data get();
|
||||
|
||||
private:
|
||||
void notifyInternal(Data result);
|
||||
|
||||
hal::utils::TransferValue<Data> mData;
|
||||
};
|
||||
|
||||
// A HIDL callback class to receive the results of IDevice::execute_1_2 asynchronously.
|
||||
class ExecutionCallback final : public IExecutionCallback, public hal::utils::IProtectedCallback {
|
||||
public:
|
||||
using Data = nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>;
|
||||
@@ -69,8 +81,6 @@ class ExecutionCallback final : public IExecutionCallback, public hal::utils::IP
|
||||
Data get();
|
||||
|
||||
private:
|
||||
void notifyInternal(Data result);
|
||||
|
||||
hal::utils::TransferValue<Data> mData;
|
||||
};
|
||||
|
||||
|
||||
@@ -97,6 +97,12 @@ nn::GeneralResult<hidl_vec<Extension>> convert(const std::vector<nn::Extension>&
|
||||
nn::GeneralResult<hidl_vec<hidl_handle>> convert(const std::vector<nn::SharedHandle>& handles);
|
||||
nn::GeneralResult<hidl_vec<OutputShape>> convert(const std::vector<nn::OutputShape>& outputShapes);
|
||||
|
||||
nn::GeneralResult<V1_0::DeviceStatus> convert(const nn::DeviceStatus& deviceStatus);
|
||||
nn::GeneralResult<V1_0::Request> convert(const nn::Request& request);
|
||||
nn::GeneralResult<V1_0::ErrorStatus> convert(const nn::ErrorStatus& status);
|
||||
nn::GeneralResult<V1_1::ExecutionPreference> convert(
|
||||
const nn::ExecutionPreference& executionPreference);
|
||||
|
||||
} // namespace android::hardware::neuralnetworks::V1_2::utils
|
||||
|
||||
#endif // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_2_CONVERSIONS_H
|
||||
|
||||
@@ -37,10 +37,21 @@
|
||||
|
||||
namespace android::hardware::neuralnetworks::V1_2::utils {
|
||||
|
||||
nn::GeneralResult<std::string> initVersionString(V1_2::IDevice* device);
|
||||
nn::GeneralResult<nn::DeviceType> initDeviceType(V1_2::IDevice* device);
|
||||
nn::GeneralResult<std::vector<nn::Extension>> initExtensions(V1_2::IDevice* device);
|
||||
nn::GeneralResult<std::pair<uint32_t, uint32_t>> initNumberOfCacheFilesNeeded(
|
||||
// Retrieves the version string from the provided device object. On failure, this function returns
|
||||
// with the appropriate nn::GeneralError.
|
||||
nn::GeneralResult<std::string> getVersionStringFrom(V1_2::IDevice* device);
|
||||
|
||||
// Retrieves the device type from the provided device object. On failure, this function returns with
|
||||
// the appropriate nn::GeneralError.
|
||||
nn::GeneralResult<nn::DeviceType> getDeviceTypeFrom(V1_2::IDevice* device);
|
||||
|
||||
// Retrieves the extensions supported by the provided device object. On failure, this function
|
||||
// returns with the appropriate nn::GeneralError.
|
||||
nn::GeneralResult<std::vector<nn::Extension>> getSupportedExtensionsFrom(V1_2::IDevice* device);
|
||||
|
||||
// Retrieves the number of model cache files and data cache files needed by the provided device
|
||||
// object. On failure, this function returns with the appropriate nn::GeneralError.
|
||||
nn::GeneralResult<std::pair<uint32_t, uint32_t>> getNumberOfCacheFilesNeededFrom(
|
||||
V1_2::IDevice* device);
|
||||
|
||||
// Class that adapts V1_2::IDevice to nn::IDevice.
|
||||
|
||||
@@ -41,10 +41,10 @@ class PreparedModel final : public nn::IPreparedModel {
|
||||
|
||||
public:
|
||||
static nn::GeneralResult<std::shared_ptr<const PreparedModel>> create(
|
||||
sp<V1_2::IPreparedModel> preparedModel);
|
||||
sp<V1_2::IPreparedModel> preparedModel, bool executeSynchronously);
|
||||
|
||||
PreparedModel(PrivateConstructorTag tag, sp<V1_2::IPreparedModel> preparedModel,
|
||||
hal::utils::DeathHandler deathHandler);
|
||||
PreparedModel(PrivateConstructorTag tag, bool executeSynchronously,
|
||||
sp<V1_2::IPreparedModel> preparedModel, hal::utils::DeathHandler deathHandler);
|
||||
|
||||
nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> execute(
|
||||
const nn::Request& request, nn::MeasureTiming measure,
|
||||
@@ -65,6 +65,7 @@ class PreparedModel final : public nn::IPreparedModel {
|
||||
nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> executeAsynchronously(
|
||||
const V1_0::Request& request, MeasureTiming measure) const;
|
||||
|
||||
const bool kExecuteSynchronously;
|
||||
const sp<V1_2::IPreparedModel> kPreparedModel;
|
||||
const hal::utils::DeathHandler kDeathHandler;
|
||||
};
|
||||
|
||||
@@ -30,6 +30,8 @@
|
||||
|
||||
namespace android::hardware::neuralnetworks::V1_2::utils {
|
||||
|
||||
using CacheToken = hidl_array<uint8_t, static_cast<size_t>(Constant::BYTE_SIZE_OF_CACHE_TOKEN)>;
|
||||
|
||||
constexpr auto kDefaultMesaureTiming = MeasureTiming::NO;
|
||||
constexpr auto kNoTiming = Timing{.timeOnDevice = std::numeric_limits<uint64_t>::max(),
|
||||
.timeInDriver = std::numeric_limits<uint64_t>::max()};
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <nnapi/IPreparedModel.h>
|
||||
#include <nnapi/Result.h>
|
||||
#include <nnapi/Types.h>
|
||||
#include <nnapi/hal/1.0/Callbacks.h>
|
||||
#include <nnapi/hal/1.0/Conversions.h>
|
||||
#include <nnapi/hal/1.0/PreparedModel.h>
|
||||
#include <nnapi/hal/CommonUtils.h>
|
||||
@@ -42,104 +43,73 @@
|
||||
namespace android::hardware::neuralnetworks::V1_2::utils {
|
||||
namespace {
|
||||
|
||||
nn::GeneralResult<nn::SharedPreparedModel> convertPreparedModel(
|
||||
const sp<V1_0::IPreparedModel>& preparedModel) {
|
||||
return NN_TRY(V1_0::utils::PreparedModel::create(preparedModel));
|
||||
}
|
||||
|
||||
nn::GeneralResult<nn::SharedPreparedModel> convertPreparedModel(
|
||||
const sp<IPreparedModel>& preparedModel) {
|
||||
return NN_TRY(utils::PreparedModel::create(preparedModel));
|
||||
}
|
||||
|
||||
nn::GeneralResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>
|
||||
convertExecutionGeneralResultsHelper(const hidl_vec<OutputShape>& outputShapes,
|
||||
const Timing& timing) {
|
||||
return std::make_pair(NN_TRY(nn::convert(outputShapes)), NN_TRY(nn::convert(timing)));
|
||||
}
|
||||
|
||||
nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>
|
||||
convertExecutionGeneralResults(const hidl_vec<OutputShape>& outputShapes, const Timing& timing) {
|
||||
} // namespace
|
||||
|
||||
nn::GeneralResult<nn::SharedPreparedModel> prepareModelCallback(
|
||||
V1_0::ErrorStatus status, const sp<IPreparedModel>& preparedModel) {
|
||||
HANDLE_HAL_STATUS(status) << "model preparation failed with " << toString(status);
|
||||
return NN_TRY(PreparedModel::create(preparedModel, /*executeSynchronously=*/true));
|
||||
}
|
||||
|
||||
nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> executionCallback(
|
||||
V1_0::ErrorStatus status, const hidl_vec<OutputShape>& outputShapes, const Timing& timing) {
|
||||
if (status == V1_0::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE) {
|
||||
auto canonicalOutputShapes =
|
||||
nn::convert(outputShapes).value_or(std::vector<nn::OutputShape>{});
|
||||
return NN_ERROR(nn::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE, std::move(canonicalOutputShapes))
|
||||
<< "execution failed with " << toString(status);
|
||||
}
|
||||
HANDLE_HAL_STATUS(status) << "execution failed with " << toString(status);
|
||||
return hal::utils::makeExecutionFailure(
|
||||
convertExecutionGeneralResultsHelper(outputShapes, timing));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Return<void> PreparedModelCallback::notify(V1_0::ErrorStatus status,
|
||||
const sp<V1_0::IPreparedModel>& preparedModel) {
|
||||
if (status != V1_0::ErrorStatus::NONE) {
|
||||
const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
|
||||
notifyInternal(NN_ERROR(canonical) << "preparedModel failed with " << toString(status));
|
||||
} else if (preparedModel == nullptr) {
|
||||
notifyInternal(NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
|
||||
<< "Returned preparedModel is nullptr");
|
||||
} else {
|
||||
notifyInternal(convertPreparedModel(preparedModel));
|
||||
}
|
||||
mData.put(V1_0::utils::prepareModelCallback(status, preparedModel));
|
||||
return Void();
|
||||
}
|
||||
|
||||
Return<void> PreparedModelCallback::notify_1_2(V1_0::ErrorStatus status,
|
||||
const sp<IPreparedModel>& preparedModel) {
|
||||
if (status != V1_0::ErrorStatus::NONE) {
|
||||
const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
|
||||
notifyInternal(NN_ERROR(canonical) << "preparedModel failed with " << toString(status));
|
||||
} else if (preparedModel == nullptr) {
|
||||
notifyInternal(NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
|
||||
<< "Returned preparedModel is nullptr");
|
||||
} else {
|
||||
notifyInternal(convertPreparedModel(preparedModel));
|
||||
}
|
||||
mData.put(prepareModelCallback(status, preparedModel));
|
||||
return Void();
|
||||
}
|
||||
|
||||
void PreparedModelCallback::notifyAsDeadObject() {
|
||||
notifyInternal(NN_ERROR(nn::ErrorStatus::DEAD_OBJECT) << "Dead object");
|
||||
mData.put(NN_ERROR(nn::ErrorStatus::DEAD_OBJECT) << "Dead object");
|
||||
}
|
||||
|
||||
PreparedModelCallback::Data PreparedModelCallback::get() {
|
||||
return mData.take();
|
||||
}
|
||||
|
||||
void PreparedModelCallback::notifyInternal(PreparedModelCallback::Data result) {
|
||||
mData.put(std::move(result));
|
||||
}
|
||||
|
||||
// ExecutionCallback methods begin here
|
||||
|
||||
Return<void> ExecutionCallback::notify(V1_0::ErrorStatus status) {
|
||||
if (status != V1_0::ErrorStatus::NONE) {
|
||||
const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
|
||||
notifyInternal(NN_ERROR(canonical) << "execute failed with " << toString(status));
|
||||
} else {
|
||||
notifyInternal({});
|
||||
}
|
||||
mData.put(V1_0::utils::executionCallback(status));
|
||||
return Void();
|
||||
}
|
||||
|
||||
Return<void> ExecutionCallback::notify_1_2(V1_0::ErrorStatus status,
|
||||
const hidl_vec<OutputShape>& outputShapes,
|
||||
const Timing& timing) {
|
||||
if (status != V1_0::ErrorStatus::NONE) {
|
||||
const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
|
||||
notifyInternal(NN_ERROR(canonical) << "execute failed with " << toString(status));
|
||||
} else {
|
||||
notifyInternal(convertExecutionGeneralResults(outputShapes, timing));
|
||||
}
|
||||
mData.put(executionCallback(status, outputShapes, timing));
|
||||
return Void();
|
||||
}
|
||||
|
||||
void ExecutionCallback::notifyAsDeadObject() {
|
||||
notifyInternal(NN_ERROR(nn::ErrorStatus::DEAD_OBJECT) << "Dead object");
|
||||
mData.put(NN_ERROR(nn::ErrorStatus::DEAD_OBJECT) << "Dead object");
|
||||
}
|
||||
|
||||
ExecutionCallback::Data ExecutionCallback::get() {
|
||||
return mData.take();
|
||||
}
|
||||
|
||||
void ExecutionCallback::notifyInternal(ExecutionCallback::Data result) {
|
||||
mData.put(std::move(result));
|
||||
}
|
||||
|
||||
} // namespace android::hardware::neuralnetworks::V1_2::utils
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <nnapi/Types.h>
|
||||
#include <nnapi/Validation.h>
|
||||
#include <nnapi/hal/1.0/Conversions.h>
|
||||
#include <nnapi/hal/1.1/Conversions.h>
|
||||
#include <nnapi/hal/CommonUtils.h>
|
||||
#include <nnapi/hal/HandleError.h>
|
||||
|
||||
@@ -622,4 +623,21 @@ nn::GeneralResult<hidl_vec<OutputShape>> convert(const std::vector<nn::OutputSha
|
||||
return validatedConvert(outputShapes);
|
||||
}
|
||||
|
||||
nn::GeneralResult<V1_0::DeviceStatus> convert(const nn::DeviceStatus& deviceStatus) {
|
||||
return V1_1::utils::convert(deviceStatus);
|
||||
}
|
||||
|
||||
nn::GeneralResult<V1_0::Request> convert(const nn::Request& request) {
|
||||
return V1_1::utils::convert(request);
|
||||
}
|
||||
|
||||
nn::GeneralResult<V1_0::ErrorStatus> convert(const nn::ErrorStatus& status) {
|
||||
return V1_1::utils::convert(status);
|
||||
}
|
||||
|
||||
nn::GeneralResult<V1_1::ExecutionPreference> convert(
|
||||
const nn::ExecutionPreference& executionPreference) {
|
||||
return V1_1::utils::convert(executionPreference);
|
||||
}
|
||||
|
||||
} // namespace android::hardware::neuralnetworks::V1_2::utils
|
||||
|
||||
@@ -47,109 +47,102 @@
|
||||
namespace android::hardware::neuralnetworks::V1_2::utils {
|
||||
namespace {
|
||||
|
||||
nn::GeneralResult<nn::Capabilities> initCapabilities(V1_2::IDevice* device) {
|
||||
nn::GeneralResult<nn::Capabilities> capabilitiesCallback(V1_0::ErrorStatus status,
|
||||
const Capabilities& capabilities) {
|
||||
HANDLE_HAL_STATUS(status) << "getting capabilities failed with " << toString(status);
|
||||
return nn::convert(capabilities);
|
||||
}
|
||||
|
||||
nn::GeneralResult<std::string> versionStringCallback(V1_0::ErrorStatus status,
|
||||
const hidl_string& versionString) {
|
||||
HANDLE_HAL_STATUS(status) << "getVersionString failed with " << toString(status);
|
||||
return versionString;
|
||||
}
|
||||
|
||||
nn::GeneralResult<nn::DeviceType> deviceTypeCallback(V1_0::ErrorStatus status,
|
||||
DeviceType deviceType) {
|
||||
HANDLE_HAL_STATUS(status) << "getDeviceType failed with " << toString(status);
|
||||
return nn::convert(deviceType);
|
||||
}
|
||||
|
||||
nn::GeneralResult<std::vector<nn::Extension>> supportedExtensionsCallback(
|
||||
V1_0::ErrorStatus status, const hidl_vec<Extension>& extensions) {
|
||||
HANDLE_HAL_STATUS(status) << "getExtensions failed with " << toString(status);
|
||||
return nn::convert(extensions);
|
||||
}
|
||||
|
||||
nn::GeneralResult<std::pair<uint32_t, uint32_t>> numberOfCacheFilesNeededCallback(
|
||||
V1_0::ErrorStatus status, uint32_t numModelCache, uint32_t numDataCache) {
|
||||
HANDLE_HAL_STATUS(status) << "getNumberOfCacheFilesNeeded failed with " << toString(status);
|
||||
if (numModelCache > nn::kMaxNumberOfCacheFiles) {
|
||||
return NN_ERROR() << "getNumberOfCacheFilesNeeded returned numModelCache files greater "
|
||||
"than allowed max ("
|
||||
<< numModelCache << " vs " << nn::kMaxNumberOfCacheFiles << ")";
|
||||
}
|
||||
if (numDataCache > nn::kMaxNumberOfCacheFiles) {
|
||||
return NN_ERROR() << "getNumberOfCacheFilesNeeded returned numDataCache files greater "
|
||||
"than allowed max ("
|
||||
<< numDataCache << " vs " << nn::kMaxNumberOfCacheFiles << ")";
|
||||
}
|
||||
return std::make_pair(numModelCache, numDataCache);
|
||||
}
|
||||
|
||||
nn::GeneralResult<nn::Capabilities> getCapabilitiesFrom(V1_2::IDevice* device) {
|
||||
CHECK(device != nullptr);
|
||||
|
||||
nn::GeneralResult<nn::Capabilities> result = NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
|
||||
<< "uninitialized";
|
||||
const auto cb = [&result](V1_0::ErrorStatus status, const Capabilities& capabilities) {
|
||||
if (status != V1_0::ErrorStatus::NONE) {
|
||||
const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
|
||||
result = NN_ERROR(canonical) << "getCapabilities_1_2 failed with " << toString(status);
|
||||
} else {
|
||||
result = nn::convert(capabilities);
|
||||
}
|
||||
};
|
||||
auto cb = hal::utils::CallbackValue(capabilitiesCallback);
|
||||
|
||||
const auto ret = device->getCapabilities_1_2(cb);
|
||||
HANDLE_TRANSPORT_FAILURE(ret);
|
||||
|
||||
return result;
|
||||
return cb.take();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
nn::GeneralResult<std::string> initVersionString(V1_2::IDevice* device) {
|
||||
nn::GeneralResult<std::string> getVersionStringFrom(V1_2::IDevice* device) {
|
||||
CHECK(device != nullptr);
|
||||
|
||||
nn::GeneralResult<std::string> result = NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
|
||||
<< "uninitialized";
|
||||
const auto cb = [&result](V1_0::ErrorStatus status, const hidl_string& versionString) {
|
||||
if (status != V1_0::ErrorStatus::NONE) {
|
||||
const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
|
||||
result = NN_ERROR(canonical) << "getVersionString failed with " << toString(status);
|
||||
} else {
|
||||
result = versionString;
|
||||
}
|
||||
};
|
||||
auto cb = hal::utils::CallbackValue(versionStringCallback);
|
||||
|
||||
const auto ret = device->getVersionString(cb);
|
||||
HANDLE_TRANSPORT_FAILURE(ret);
|
||||
|
||||
return result;
|
||||
return cb.take();
|
||||
}
|
||||
|
||||
nn::GeneralResult<nn::DeviceType> initDeviceType(V1_2::IDevice* device) {
|
||||
nn::GeneralResult<nn::DeviceType> getDeviceTypeFrom(V1_2::IDevice* device) {
|
||||
CHECK(device != nullptr);
|
||||
|
||||
nn::GeneralResult<nn::DeviceType> result = NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
|
||||
<< "uninitialized";
|
||||
const auto cb = [&result](V1_0::ErrorStatus status, DeviceType deviceType) {
|
||||
if (status != V1_0::ErrorStatus::NONE) {
|
||||
const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
|
||||
result = NN_ERROR(canonical) << "getDeviceType failed with " << toString(status);
|
||||
} else {
|
||||
result = nn::convert(deviceType);
|
||||
}
|
||||
};
|
||||
auto cb = hal::utils::CallbackValue(deviceTypeCallback);
|
||||
|
||||
const auto ret = device->getType(cb);
|
||||
HANDLE_TRANSPORT_FAILURE(ret);
|
||||
|
||||
return result;
|
||||
return cb.take();
|
||||
}
|
||||
|
||||
nn::GeneralResult<std::vector<nn::Extension>> initExtensions(V1_2::IDevice* device) {
|
||||
nn::GeneralResult<std::vector<nn::Extension>> getSupportedExtensionsFrom(V1_2::IDevice* device) {
|
||||
CHECK(device != nullptr);
|
||||
|
||||
nn::GeneralResult<std::vector<nn::Extension>> result =
|
||||
NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "uninitialized";
|
||||
const auto cb = [&result](V1_0::ErrorStatus status, const hidl_vec<Extension>& extensions) {
|
||||
if (status != V1_0::ErrorStatus::NONE) {
|
||||
const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
|
||||
result = NN_ERROR(canonical) << "getExtensions failed with " << toString(status);
|
||||
} else {
|
||||
result = nn::convert(extensions);
|
||||
}
|
||||
};
|
||||
auto cb = hal::utils::CallbackValue(supportedExtensionsCallback);
|
||||
|
||||
const auto ret = device->getSupportedExtensions(cb);
|
||||
HANDLE_TRANSPORT_FAILURE(ret);
|
||||
|
||||
return result;
|
||||
return cb.take();
|
||||
}
|
||||
|
||||
nn::GeneralResult<std::pair<uint32_t, uint32_t>> initNumberOfCacheFilesNeeded(
|
||||
nn::GeneralResult<std::pair<uint32_t, uint32_t>> getNumberOfCacheFilesNeededFrom(
|
||||
V1_2::IDevice* device) {
|
||||
CHECK(device != nullptr);
|
||||
|
||||
nn::GeneralResult<std::pair<uint32_t, uint32_t>> result =
|
||||
NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "uninitialized";
|
||||
const auto cb = [&result](V1_0::ErrorStatus status, uint32_t numModelCache,
|
||||
uint32_t numDataCache) {
|
||||
if (status != V1_0::ErrorStatus::NONE) {
|
||||
const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
|
||||
result = NN_ERROR(canonical)
|
||||
<< "getNumberOfCacheFilesNeeded failed with " << toString(status);
|
||||
} else {
|
||||
result = std::make_pair(numModelCache, numDataCache);
|
||||
}
|
||||
};
|
||||
auto cb = hal::utils::CallbackValue(numberOfCacheFilesNeededCallback);
|
||||
|
||||
const auto ret = device->getNumberOfCacheFilesNeeded(cb);
|
||||
HANDLE_TRANSPORT_FAILURE(ret);
|
||||
|
||||
return result;
|
||||
return cb.take();
|
||||
}
|
||||
|
||||
nn::GeneralResult<std::shared_ptr<const Device>> Device::create(std::string name,
|
||||
@@ -163,11 +156,11 @@ nn::GeneralResult<std::shared_ptr<const Device>> Device::create(std::string name
|
||||
<< "V1_2::utils::Device::create must have non-null device";
|
||||
}
|
||||
|
||||
auto versionString = NN_TRY(initVersionString(device.get()));
|
||||
const auto deviceType = NN_TRY(initDeviceType(device.get()));
|
||||
auto extensions = NN_TRY(initExtensions(device.get()));
|
||||
auto capabilities = NN_TRY(initCapabilities(device.get()));
|
||||
const auto numberOfCacheFilesNeeded = NN_TRY(initNumberOfCacheFilesNeeded(device.get()));
|
||||
auto versionString = NN_TRY(getVersionStringFrom(device.get()));
|
||||
const auto deviceType = NN_TRY(getDeviceTypeFrom(device.get()));
|
||||
auto extensions = NN_TRY(getSupportedExtensionsFrom(device.get()));
|
||||
auto capabilities = NN_TRY(getCapabilitiesFrom(device.get()));
|
||||
const auto numberOfCacheFilesNeeded = NN_TRY(getNumberOfCacheFilesNeededFrom(device.get()));
|
||||
|
||||
auto deathHandler = NN_TRY(hal::utils::DeathHandler::create(device));
|
||||
return std::make_shared<const Device>(
|
||||
@@ -232,28 +225,12 @@ nn::GeneralResult<std::vector<bool>> Device::getSupportedOperations(const nn::Mo
|
||||
|
||||
const auto hidlModel = NN_TRY(convert(modelInShared));
|
||||
|
||||
nn::GeneralResult<std::vector<bool>> result = NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
|
||||
<< "uninitialized";
|
||||
auto cb = [&result, &model](V1_0::ErrorStatus status,
|
||||
const hidl_vec<bool>& supportedOperations) {
|
||||
if (status != V1_0::ErrorStatus::NONE) {
|
||||
const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
|
||||
result = NN_ERROR(canonical)
|
||||
<< "getSupportedOperations_1_2 failed with " << toString(status);
|
||||
} else if (supportedOperations.size() != model.main.operations.size()) {
|
||||
result = NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
|
||||
<< "getSupportedOperations_1_2 returned vector of size "
|
||||
<< supportedOperations.size() << " but expected "
|
||||
<< model.main.operations.size();
|
||||
} else {
|
||||
result = supportedOperations;
|
||||
}
|
||||
};
|
||||
auto cb = hal::utils::CallbackValue(V1_0::utils::supportedOperationsCallback);
|
||||
|
||||
const auto ret = kDevice->getSupportedOperations_1_2(hidlModel, cb);
|
||||
HANDLE_TRANSPORT_FAILURE(ret);
|
||||
|
||||
return result;
|
||||
return cb.take();
|
||||
}
|
||||
|
||||
nn::GeneralResult<nn::SharedPreparedModel> Device::prepareModel(
|
||||
@@ -266,10 +243,10 @@ nn::GeneralResult<nn::SharedPreparedModel> Device::prepareModel(
|
||||
NN_TRY(hal::utils::flushDataFromPointerToShared(&model, &maybeModelInShared));
|
||||
|
||||
const auto hidlModel = NN_TRY(convert(modelInShared));
|
||||
const auto hidlPreference = NN_TRY(V1_1::utils::convert(preference));
|
||||
const auto hidlPreference = NN_TRY(convert(preference));
|
||||
const auto hidlModelCache = NN_TRY(convert(modelCache));
|
||||
const auto hidlDataCache = NN_TRY(convert(dataCache));
|
||||
const auto hidlToken = token;
|
||||
const auto hidlToken = CacheToken{token};
|
||||
|
||||
const auto cb = sp<PreparedModelCallback>::make();
|
||||
const auto scoped = kDeathHandler.protectCallback(cb.get());
|
||||
@@ -277,10 +254,7 @@ nn::GeneralResult<nn::SharedPreparedModel> Device::prepareModel(
|
||||
const auto ret = kDevice->prepareModel_1_2(hidlModel, hidlPreference, hidlModelCache,
|
||||
hidlDataCache, hidlToken, cb);
|
||||
const auto status = HANDLE_TRANSPORT_FAILURE(ret);
|
||||
if (status != V1_0::ErrorStatus::NONE) {
|
||||
const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
|
||||
return NN_ERROR(canonical) << "prepareModel_1_2 failed with " << toString(status);
|
||||
}
|
||||
HANDLE_HAL_STATUS(status) << "model preparation failed with " << toString(status);
|
||||
|
||||
return cb->get();
|
||||
}
|
||||
@@ -290,17 +264,14 @@ nn::GeneralResult<nn::SharedPreparedModel> Device::prepareModelFromCache(
|
||||
const std::vector<nn::SharedHandle>& dataCache, const nn::CacheToken& token) const {
|
||||
const auto hidlModelCache = NN_TRY(convert(modelCache));
|
||||
const auto hidlDataCache = NN_TRY(convert(dataCache));
|
||||
const auto hidlToken = token;
|
||||
const auto hidlToken = CacheToken{token};
|
||||
|
||||
const auto cb = sp<PreparedModelCallback>::make();
|
||||
const auto scoped = kDeathHandler.protectCallback(cb.get());
|
||||
|
||||
const auto ret = kDevice->prepareModelFromCache(hidlModelCache, hidlDataCache, hidlToken, cb);
|
||||
const auto status = HANDLE_TRANSPORT_FAILURE(ret);
|
||||
if (status != V1_0::ErrorStatus::NONE) {
|
||||
const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
|
||||
return NN_ERROR(canonical) << "prepareModelFromCache failed with " << toString(status);
|
||||
}
|
||||
HANDLE_HAL_STATUS(status) << "model preparation from cache failed with " << toString(status);
|
||||
|
||||
return cb->get();
|
||||
}
|
||||
|
||||
@@ -41,54 +41,33 @@
|
||||
// lifetimes across processes and for protecting asynchronous calls across HIDL.
|
||||
|
||||
namespace android::hardware::neuralnetworks::V1_2::utils {
|
||||
namespace {
|
||||
|
||||
nn::GeneralResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>
|
||||
convertExecutionResultsHelper(const hidl_vec<OutputShape>& outputShapes, const Timing& timing) {
|
||||
return std::make_pair(NN_TRY(nn::convert(outputShapes)), NN_TRY(nn::convert(timing)));
|
||||
}
|
||||
|
||||
nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> convertExecutionResults(
|
||||
const hidl_vec<OutputShape>& outputShapes, const Timing& timing) {
|
||||
return hal::utils::makeExecutionFailure(convertExecutionResultsHelper(outputShapes, timing));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
nn::GeneralResult<std::shared_ptr<const PreparedModel>> PreparedModel::create(
|
||||
sp<V1_2::IPreparedModel> preparedModel) {
|
||||
sp<V1_2::IPreparedModel> preparedModel, bool executeSynchronously) {
|
||||
if (preparedModel == nullptr) {
|
||||
return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
|
||||
<< "V1_2::utils::PreparedModel::create must have non-null preparedModel";
|
||||
return NN_ERROR() << "V1_2::utils::PreparedModel::create must have non-null preparedModel";
|
||||
}
|
||||
|
||||
auto deathHandler = NN_TRY(hal::utils::DeathHandler::create(preparedModel));
|
||||
return std::make_shared<const PreparedModel>(PrivateConstructorTag{}, std::move(preparedModel),
|
||||
std::move(deathHandler));
|
||||
return std::make_shared<const PreparedModel>(PrivateConstructorTag{}, executeSynchronously,
|
||||
std::move(preparedModel), std::move(deathHandler));
|
||||
}
|
||||
|
||||
PreparedModel::PreparedModel(PrivateConstructorTag /*tag*/, sp<V1_2::IPreparedModel> preparedModel,
|
||||
PreparedModel::PreparedModel(PrivateConstructorTag /*tag*/, bool executeSynchronously,
|
||||
sp<V1_2::IPreparedModel> preparedModel,
|
||||
hal::utils::DeathHandler deathHandler)
|
||||
: kPreparedModel(std::move(preparedModel)), kDeathHandler(std::move(deathHandler)) {}
|
||||
: kExecuteSynchronously(executeSynchronously),
|
||||
kPreparedModel(std::move(preparedModel)),
|
||||
kDeathHandler(std::move(deathHandler)) {}
|
||||
|
||||
nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>
|
||||
PreparedModel::executeSynchronously(const V1_0::Request& request, MeasureTiming measure) const {
|
||||
nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> result =
|
||||
NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "uninitialized";
|
||||
const auto cb = [&result](V1_0::ErrorStatus status, const hidl_vec<OutputShape>& outputShapes,
|
||||
const Timing& timing) {
|
||||
if (status != V1_0::ErrorStatus::NONE) {
|
||||
const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
|
||||
result = NN_ERROR(canonical) << "executeSynchronously failed with " << toString(status);
|
||||
} else {
|
||||
result = convertExecutionResults(outputShapes, timing);
|
||||
}
|
||||
};
|
||||
auto cb = hal::utils::CallbackValue(executionCallback);
|
||||
|
||||
const auto ret = kPreparedModel->executeSynchronously(request, measure, cb);
|
||||
HANDLE_TRANSPORT_FAILURE(ret);
|
||||
|
||||
return result;
|
||||
return cb.take();
|
||||
}
|
||||
|
||||
nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>
|
||||
@@ -98,9 +77,8 @@ PreparedModel::executeAsynchronously(const V1_0::Request& request, MeasureTiming
|
||||
|
||||
const auto ret = kPreparedModel->execute_1_2(request, measure, cb);
|
||||
const auto status = HANDLE_TRANSPORT_FAILURE(ret);
|
||||
if (status != V1_0::ErrorStatus::NONE) {
|
||||
const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
|
||||
return NN_ERROR(canonical) << "execute failed with " << toString(status);
|
||||
if (status != V1_0::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE) {
|
||||
HANDLE_HAL_STATUS(status) << "execution failed with " << toString(status);
|
||||
}
|
||||
|
||||
return cb->get();
|
||||
@@ -115,31 +93,17 @@ nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> Prepare
|
||||
const nn::Request& requestInShared = NN_TRY(hal::utils::makeExecutionFailure(
|
||||
hal::utils::flushDataFromPointerToShared(&request, &maybeRequestInShared)));
|
||||
|
||||
const auto hidlRequest =
|
||||
NN_TRY(hal::utils::makeExecutionFailure(V1_0::utils::convert(requestInShared)));
|
||||
const auto hidlRequest = NN_TRY(hal::utils::makeExecutionFailure(convert(requestInShared)));
|
||||
const auto hidlMeasure = NN_TRY(hal::utils::makeExecutionFailure(convert(measure)));
|
||||
|
||||
nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> result =
|
||||
NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "uninitialized";
|
||||
const bool preferSynchronous = true;
|
||||
auto result = kExecuteSynchronously ? executeSynchronously(hidlRequest, hidlMeasure)
|
||||
: executeAsynchronously(hidlRequest, hidlMeasure);
|
||||
auto [outputShapes, timing] = NN_TRY(std::move(result));
|
||||
|
||||
// Execute synchronously if allowed.
|
||||
if (preferSynchronous) {
|
||||
result = executeSynchronously(hidlRequest, hidlMeasure);
|
||||
}
|
||||
NN_TRY(hal::utils::makeExecutionFailure(
|
||||
hal::utils::unflushDataFromSharedToPointer(request, maybeRequestInShared)));
|
||||
|
||||
// Run asymchronous execution if execution has not already completed.
|
||||
if (!result.has_value()) {
|
||||
result = executeAsynchronously(hidlRequest, hidlMeasure);
|
||||
}
|
||||
|
||||
// Flush output buffers if suxcessful execution.
|
||||
if (result.has_value()) {
|
||||
NN_TRY(hal::utils::makeExecutionFailure(
|
||||
hal::utils::unflushDataFromSharedToPointer(request, maybeRequestInShared)));
|
||||
}
|
||||
|
||||
return result;
|
||||
return std::make_pair(std::move(outputShapes), timing);
|
||||
}
|
||||
|
||||
nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>>
|
||||
@@ -154,7 +118,7 @@ PreparedModel::executeFenced(const nn::Request& /*request*/,
|
||||
}
|
||||
|
||||
std::any PreparedModel::getUnderlyingResource() const {
|
||||
sp<V1_0::IPreparedModel> resource = kPreparedModel;
|
||||
sp<V1_2::IPreparedModel> resource = kPreparedModel;
|
||||
return resource;
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,26 @@
|
||||
|
||||
namespace android::hardware::neuralnetworks::V1_3::utils {
|
||||
|
||||
// Converts the results of IDevice::getSupportedOperations* to the NN canonical format. On success,
|
||||
// this function returns with the supported operations as indicated by a driver. On failure, this
|
||||
// function returns with the appropriate nn::GeneralError.
|
||||
nn::GeneralResult<std::vector<bool>> supportedOperationsCallback(
|
||||
ErrorStatus status, const hidl_vec<bool>& supportedOperations);
|
||||
|
||||
// Converts the results of IDevice::prepareModel* to the NN canonical format. On success, this
|
||||
// function returns with a non-null nn::SharedPreparedModel with a feature level of
|
||||
// nn::Version::ANDROID_R. On failure, this function returns with the appropriate nn::GeneralError.
|
||||
nn::GeneralResult<nn::SharedPreparedModel> prepareModelCallback(
|
||||
ErrorStatus status, const sp<IPreparedModel>& preparedModel);
|
||||
|
||||
// Converts the results of IDevice::execute* to the NN canonical format. On success, this function
|
||||
// returns with the output shapes and the timing information. On failure, this function returns with
|
||||
// the appropriate nn::ExecutionError.
|
||||
nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> executionCallback(
|
||||
ErrorStatus status, const hidl_vec<V1_2::OutputShape>& outputShapes,
|
||||
const V1_2::Timing& timing);
|
||||
|
||||
// A HIDL callback class to receive the results of IDevice::prepareModel* asynchronously.
|
||||
class PreparedModelCallback final : public IPreparedModelCallback,
|
||||
public hal::utils::IProtectedCallback {
|
||||
public:
|
||||
@@ -55,11 +75,10 @@ class PreparedModelCallback final : public IPreparedModelCallback,
|
||||
Data get();
|
||||
|
||||
private:
|
||||
void notifyInternal(Data result);
|
||||
|
||||
hal::utils::TransferValue<Data> mData;
|
||||
};
|
||||
|
||||
// A HIDL callback class to receive the results of IDevice::execute_1_3 asynchronously.
|
||||
class ExecutionCallback final : public IExecutionCallback, public hal::utils::IProtectedCallback {
|
||||
public:
|
||||
using Data = nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>;
|
||||
@@ -76,8 +95,6 @@ class ExecutionCallback final : public IExecutionCallback, public hal::utils::IP
|
||||
Data get();
|
||||
|
||||
private:
|
||||
void notifyInternal(Data result);
|
||||
|
||||
hal::utils::TransferValue<Data> mData;
|
||||
};
|
||||
|
||||
|
||||
@@ -103,6 +103,17 @@ nn::GeneralResult<hidl_handle> convert(const nn::SharedHandle& handle);
|
||||
nn::GeneralResult<hidl_memory> convert(const nn::Memory& memory);
|
||||
nn::GeneralResult<hidl_vec<BufferRole>> convert(const std::vector<nn::BufferRole>& bufferRoles);
|
||||
|
||||
nn::GeneralResult<V1_0::DeviceStatus> convert(const nn::DeviceStatus& deviceStatus);
|
||||
nn::GeneralResult<V1_1::ExecutionPreference> convert(
|
||||
const nn::ExecutionPreference& executionPreference);
|
||||
nn::GeneralResult<hidl_vec<V1_2::Extension>> convert(const std::vector<nn::Extension>& extensions);
|
||||
nn::GeneralResult<hidl_vec<hidl_handle>> convert(const std::vector<nn::SharedHandle>& handles);
|
||||
nn::GeneralResult<hidl_vec<V1_2::OutputShape>> convert(
|
||||
const std::vector<nn::OutputShape>& outputShapes);
|
||||
nn::GeneralResult<V1_2::DeviceType> convert(const nn::DeviceType& deviceType);
|
||||
nn::GeneralResult<V1_2::MeasureTiming> convert(const nn::MeasureTiming& measureTiming);
|
||||
nn::GeneralResult<V1_2::Timing> convert(const nn::Timing& timing);
|
||||
|
||||
} // namespace android::hardware::neuralnetworks::V1_3::utils
|
||||
|
||||
#endif // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_CONVERSIONS_H
|
||||
|
||||
@@ -40,10 +40,10 @@ class PreparedModel final : public nn::IPreparedModel {
|
||||
|
||||
public:
|
||||
static nn::GeneralResult<std::shared_ptr<const PreparedModel>> create(
|
||||
sp<V1_3::IPreparedModel> preparedModel);
|
||||
sp<V1_3::IPreparedModel> preparedModel, bool executeSynchronously);
|
||||
|
||||
PreparedModel(PrivateConstructorTag tag, sp<V1_3::IPreparedModel> preparedModel,
|
||||
hal::utils::DeathHandler deathHandler);
|
||||
PreparedModel(PrivateConstructorTag tag, bool executeSynchronously,
|
||||
sp<V1_3::IPreparedModel> preparedModel, hal::utils::DeathHandler deathHandler);
|
||||
|
||||
nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> execute(
|
||||
const nn::Request& request, nn::MeasureTiming measure,
|
||||
@@ -66,6 +66,7 @@ class PreparedModel final : public nn::IPreparedModel {
|
||||
const Request& request, V1_2::MeasureTiming measure, const OptionalTimePoint& deadline,
|
||||
const OptionalTimeoutDuration& loopTimeoutDuration) const;
|
||||
|
||||
const bool kExecuteSynchronously;
|
||||
const sp<V1_3::IPreparedModel> kPreparedModel;
|
||||
const hal::utils::DeathHandler kDeathHandler;
|
||||
};
|
||||
|
||||
@@ -41,12 +41,10 @@ namespace android::hardware::neuralnetworks::V1_3::utils {
|
||||
nn::GeneralResult<std::shared_ptr<const Buffer>> Buffer::create(
|
||||
sp<V1_3::IBuffer> buffer, nn::Request::MemoryDomainToken token) {
|
||||
if (buffer == nullptr) {
|
||||
return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
|
||||
<< "V1_3::utils::Buffer::create must have non-null buffer";
|
||||
return NN_ERROR() << "V1_3::utils::Buffer::create must have non-null buffer";
|
||||
}
|
||||
if (token == static_cast<nn::Request::MemoryDomainToken>(0)) {
|
||||
return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
|
||||
<< "V1_3::utils::Buffer::create must have non-zero token";
|
||||
return NN_ERROR() << "V1_3::utils::Buffer::create must have non-zero token";
|
||||
}
|
||||
|
||||
return std::make_shared<const Buffer>(PrivateConstructorTag{}, std::move(buffer), token);
|
||||
@@ -68,10 +66,7 @@ nn::GeneralResult<void> Buffer::copyTo(const nn::Memory& dst) const {
|
||||
|
||||
const auto ret = kBuffer->copyTo(hidlDst);
|
||||
const auto status = HANDLE_TRANSPORT_FAILURE(ret);
|
||||
if (status != ErrorStatus::NONE) {
|
||||
const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
|
||||
return NN_ERROR(canonical) << "IBuffer::copyTo failed with " << toString(status);
|
||||
}
|
||||
HANDLE_HAL_STATUS(status) << "IBuffer::copyTo failed with " << toString(status);
|
||||
|
||||
return {};
|
||||
}
|
||||
@@ -83,10 +78,7 @@ nn::GeneralResult<void> Buffer::copyFrom(const nn::Memory& src,
|
||||
|
||||
const auto ret = kBuffer->copyFrom(hidlSrc, hidlDimensions);
|
||||
const auto status = HANDLE_TRANSPORT_FAILURE(ret);
|
||||
if (status != ErrorStatus::NONE) {
|
||||
const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
|
||||
return NN_ERROR(canonical) << "IBuffer::copyFrom failed with " << toString(status);
|
||||
}
|
||||
HANDLE_HAL_STATUS(status) << "IBuffer::copyFrom failed with " << toString(status);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include <nnapi/Types.h>
|
||||
#include <nnapi/hal/1.0/Conversions.h>
|
||||
#include <nnapi/hal/1.0/PreparedModel.h>
|
||||
#include <nnapi/hal/1.2/Callbacks.h>
|
||||
#include <nnapi/hal/1.2/Conversions.h>
|
||||
#include <nnapi/hal/1.2/PreparedModel.h>
|
||||
#include <nnapi/hal/CommonUtils.h>
|
||||
@@ -45,136 +46,93 @@
|
||||
namespace android::hardware::neuralnetworks::V1_3::utils {
|
||||
namespace {
|
||||
|
||||
nn::GeneralResult<nn::SharedPreparedModel> convertPreparedModel(
|
||||
const sp<V1_0::IPreparedModel>& preparedModel) {
|
||||
return NN_TRY(V1_0::utils::PreparedModel::create(preparedModel));
|
||||
}
|
||||
|
||||
nn::GeneralResult<nn::SharedPreparedModel> convertPreparedModel(
|
||||
const sp<V1_2::IPreparedModel>& preparedModel) {
|
||||
return NN_TRY(V1_2::utils::PreparedModel::create(preparedModel));
|
||||
}
|
||||
|
||||
nn::GeneralResult<nn::SharedPreparedModel> convertPreparedModel(
|
||||
const sp<IPreparedModel>& preparedModel) {
|
||||
return NN_TRY(utils::PreparedModel::create(preparedModel));
|
||||
}
|
||||
|
||||
nn::GeneralResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>
|
||||
convertExecutionGeneralResultsHelper(const hidl_vec<V1_2::OutputShape>& outputShapes,
|
||||
const V1_2::Timing& timing) {
|
||||
return std::make_pair(NN_TRY(nn::convert(outputShapes)), NN_TRY(nn::convert(timing)));
|
||||
}
|
||||
|
||||
nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>
|
||||
convertExecutionGeneralResults(const hidl_vec<V1_2::OutputShape>& outputShapes,
|
||||
const V1_2::Timing& timing) {
|
||||
} // namespace
|
||||
|
||||
nn::GeneralResult<std::vector<bool>> supportedOperationsCallback(
|
||||
ErrorStatus status, const hidl_vec<bool>& supportedOperations) {
|
||||
HANDLE_HAL_STATUS(status) << "get supported operations failed with " << toString(status);
|
||||
return supportedOperations;
|
||||
}
|
||||
|
||||
nn::GeneralResult<nn::SharedPreparedModel> prepareModelCallback(
|
||||
ErrorStatus status, const sp<IPreparedModel>& preparedModel) {
|
||||
HANDLE_HAL_STATUS(status) << "model preparation failed with " << toString(status);
|
||||
return NN_TRY(PreparedModel::create(preparedModel, /*executeSynchronously=*/true));
|
||||
}
|
||||
|
||||
nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> executionCallback(
|
||||
ErrorStatus status, const hidl_vec<V1_2::OutputShape>& outputShapes,
|
||||
const V1_2::Timing& timing) {
|
||||
if (status == ErrorStatus::OUTPUT_INSUFFICIENT_SIZE) {
|
||||
auto canonicalOutputShapes =
|
||||
nn::convert(outputShapes).value_or(std::vector<nn::OutputShape>{});
|
||||
return NN_ERROR(nn::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE, std::move(canonicalOutputShapes))
|
||||
<< "execution failed with " << toString(status);
|
||||
}
|
||||
HANDLE_HAL_STATUS(status) << "execution failed with " << toString(status);
|
||||
return hal::utils::makeExecutionFailure(
|
||||
convertExecutionGeneralResultsHelper(outputShapes, timing));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Return<void> PreparedModelCallback::notify(V1_0::ErrorStatus status,
|
||||
const sp<V1_0::IPreparedModel>& preparedModel) {
|
||||
if (status != V1_0::ErrorStatus::NONE) {
|
||||
const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
|
||||
notifyInternal(NN_ERROR(canonical) << "preparedModel failed with " << toString(status));
|
||||
} else if (preparedModel == nullptr) {
|
||||
notifyInternal(NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
|
||||
<< "Returned preparedModel is nullptr");
|
||||
} else {
|
||||
notifyInternal(convertPreparedModel(preparedModel));
|
||||
}
|
||||
mData.put(V1_0::utils::prepareModelCallback(status, preparedModel));
|
||||
return Void();
|
||||
}
|
||||
|
||||
Return<void> PreparedModelCallback::notify_1_2(V1_0::ErrorStatus status,
|
||||
const sp<V1_2::IPreparedModel>& preparedModel) {
|
||||
if (status != V1_0::ErrorStatus::NONE) {
|
||||
const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
|
||||
notifyInternal(NN_ERROR(canonical) << "preparedModel failed with " << toString(status));
|
||||
} else if (preparedModel == nullptr) {
|
||||
notifyInternal(NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
|
||||
<< "Returned preparedModel is nullptr");
|
||||
} else {
|
||||
notifyInternal(convertPreparedModel(preparedModel));
|
||||
}
|
||||
mData.put(V1_2::utils::prepareModelCallback(status, preparedModel));
|
||||
return Void();
|
||||
}
|
||||
|
||||
Return<void> PreparedModelCallback::notify_1_3(ErrorStatus status,
|
||||
const sp<IPreparedModel>& preparedModel) {
|
||||
if (status != ErrorStatus::NONE) {
|
||||
const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
|
||||
notifyInternal(NN_ERROR(canonical) << "preparedModel failed with " << toString(status));
|
||||
} else if (preparedModel == nullptr) {
|
||||
notifyInternal(NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
|
||||
<< "Returned preparedModel is nullptr");
|
||||
} else {
|
||||
notifyInternal(convertPreparedModel(preparedModel));
|
||||
}
|
||||
mData.put(prepareModelCallback(status, preparedModel));
|
||||
return Void();
|
||||
}
|
||||
|
||||
void PreparedModelCallback::notifyAsDeadObject() {
|
||||
notifyInternal(NN_ERROR(nn::ErrorStatus::DEAD_OBJECT) << "Dead object");
|
||||
mData.put(NN_ERROR(nn::ErrorStatus::DEAD_OBJECT) << "Dead object");
|
||||
}
|
||||
|
||||
PreparedModelCallback::Data PreparedModelCallback::get() {
|
||||
return mData.take();
|
||||
}
|
||||
|
||||
void PreparedModelCallback::notifyInternal(PreparedModelCallback::Data result) {
|
||||
mData.put(std::move(result));
|
||||
}
|
||||
|
||||
// ExecutionCallback methods begin here
|
||||
|
||||
Return<void> ExecutionCallback::notify(V1_0::ErrorStatus status) {
|
||||
if (status != V1_0::ErrorStatus::NONE) {
|
||||
const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
|
||||
notifyInternal(NN_ERROR(canonical) << "execute failed with " << toString(status));
|
||||
} else {
|
||||
notifyInternal({});
|
||||
}
|
||||
mData.put(V1_0::utils::executionCallback(status));
|
||||
return Void();
|
||||
}
|
||||
|
||||
Return<void> ExecutionCallback::notify_1_2(V1_0::ErrorStatus status,
|
||||
const hidl_vec<V1_2::OutputShape>& outputShapes,
|
||||
const V1_2::Timing& timing) {
|
||||
if (status != V1_0::ErrorStatus::NONE) {
|
||||
const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
|
||||
notifyInternal(NN_ERROR(canonical) << "execute failed with " << toString(status));
|
||||
} else {
|
||||
notifyInternal(convertExecutionGeneralResults(outputShapes, timing));
|
||||
}
|
||||
mData.put(V1_2::utils::executionCallback(status, outputShapes, timing));
|
||||
return Void();
|
||||
}
|
||||
|
||||
Return<void> ExecutionCallback::notify_1_3(ErrorStatus status,
|
||||
const hidl_vec<V1_2::OutputShape>& outputShapes,
|
||||
const V1_2::Timing& timing) {
|
||||
if (status != ErrorStatus::NONE) {
|
||||
const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
|
||||
notifyInternal(NN_ERROR(canonical) << "execute failed with " << toString(status));
|
||||
} else {
|
||||
notifyInternal(convertExecutionGeneralResults(outputShapes, timing));
|
||||
}
|
||||
mData.put(executionCallback(status, outputShapes, timing));
|
||||
return Void();
|
||||
}
|
||||
|
||||
void ExecutionCallback::notifyAsDeadObject() {
|
||||
notifyInternal(NN_ERROR(nn::ErrorStatus::DEAD_OBJECT) << "Dead object");
|
||||
mData.put(NN_ERROR(nn::ErrorStatus::DEAD_OBJECT) << "Dead object");
|
||||
}
|
||||
|
||||
ExecutionCallback::Data ExecutionCallback::get() {
|
||||
return mData.take();
|
||||
}
|
||||
|
||||
void ExecutionCallback::notifyInternal(ExecutionCallback::Data result) {
|
||||
mData.put(std::move(result));
|
||||
}
|
||||
|
||||
} // namespace android::hardware::neuralnetworks::V1_3::utils
|
||||
|
||||
@@ -685,4 +685,38 @@ nn::GeneralResult<hidl_vec<BufferRole>> convert(const std::vector<nn::BufferRole
|
||||
return validatedConvert(bufferRoles);
|
||||
}
|
||||
|
||||
nn::GeneralResult<V1_0::DeviceStatus> convert(const nn::DeviceStatus& deviceStatus) {
|
||||
return V1_2::utils::convert(deviceStatus);
|
||||
}
|
||||
|
||||
nn::GeneralResult<V1_1::ExecutionPreference> convert(
|
||||
const nn::ExecutionPreference& executionPreference) {
|
||||
return V1_2::utils::convert(executionPreference);
|
||||
}
|
||||
|
||||
nn::GeneralResult<hidl_vec<V1_2::Extension>> convert(const std::vector<nn::Extension>& extensions) {
|
||||
return V1_2::utils::convert(extensions);
|
||||
}
|
||||
|
||||
nn::GeneralResult<hidl_vec<hidl_handle>> convert(const std::vector<nn::SharedHandle>& handles) {
|
||||
return V1_2::utils::convert(handles);
|
||||
}
|
||||
|
||||
nn::GeneralResult<hidl_vec<V1_2::OutputShape>> convert(
|
||||
const std::vector<nn::OutputShape>& outputShapes) {
|
||||
return V1_2::utils::convert(outputShapes);
|
||||
}
|
||||
|
||||
nn::GeneralResult<V1_2::DeviceType> convert(const nn::DeviceType& deviceType) {
|
||||
return V1_2::utils::convert(deviceType);
|
||||
}
|
||||
|
||||
nn::GeneralResult<V1_2::MeasureTiming> convert(const nn::MeasureTiming& measureTiming) {
|
||||
return V1_2::utils::convert(measureTiming);
|
||||
}
|
||||
|
||||
nn::GeneralResult<V1_2::Timing> convert(const nn::Timing& timing) {
|
||||
return V1_2::utils::convert(timing);
|
||||
}
|
||||
|
||||
} // namespace android::hardware::neuralnetworks::V1_3::utils
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include <nnapi/hal/1.1/Conversions.h>
|
||||
#include <nnapi/hal/1.2/Conversions.h>
|
||||
#include <nnapi/hal/1.2/Device.h>
|
||||
#include <nnapi/hal/1.2/Utils.h>
|
||||
#include <nnapi/hal/CommonUtils.h>
|
||||
#include <nnapi/hal/HandleError.h>
|
||||
#include <nnapi/hal/ProtectCallback.h>
|
||||
@@ -69,29 +70,27 @@ nn::GeneralResult<hidl_vec<sp<IPreparedModel>>> convert(
|
||||
return hidlPreparedModels;
|
||||
}
|
||||
|
||||
nn::GeneralResult<nn::SharedBuffer> convert(
|
||||
nn::GeneralResult<std::shared_ptr<const Buffer>> result) {
|
||||
return NN_TRY(std::move(result));
|
||||
nn::GeneralResult<nn::Capabilities> capabilitiesCallback(ErrorStatus status,
|
||||
const Capabilities& capabilities) {
|
||||
HANDLE_HAL_STATUS(status) << "getting capabilities failed with " << toString(status);
|
||||
return nn::convert(capabilities);
|
||||
}
|
||||
|
||||
nn::GeneralResult<nn::Capabilities> initCapabilities(V1_3::IDevice* device) {
|
||||
nn::GeneralResult<nn::Capabilities> getCapabilitiesFrom(V1_3::IDevice* device) {
|
||||
CHECK(device != nullptr);
|
||||
|
||||
nn::GeneralResult<nn::Capabilities> result = NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
|
||||
<< "uninitialized";
|
||||
const auto cb = [&result](ErrorStatus status, const Capabilities& capabilities) {
|
||||
if (status != ErrorStatus::NONE) {
|
||||
const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
|
||||
result = NN_ERROR(canonical) << "getCapabilities_1_3 failed with " << toString(status);
|
||||
} else {
|
||||
result = nn::convert(capabilities);
|
||||
}
|
||||
};
|
||||
auto cb = hal::utils::CallbackValue(capabilitiesCallback);
|
||||
|
||||
const auto ret = device->getCapabilities_1_3(cb);
|
||||
HANDLE_TRANSPORT_FAILURE(ret);
|
||||
|
||||
return result;
|
||||
return cb.take();
|
||||
}
|
||||
|
||||
nn::GeneralResult<nn::SharedBuffer> allocationCallback(ErrorStatus status,
|
||||
const sp<IBuffer>& buffer, uint32_t token) {
|
||||
HANDLE_HAL_STATUS(status) << "IDevice::allocate failed with " << toString(status);
|
||||
return Buffer::create(buffer, static_cast<nn::Request::MemoryDomainToken>(token));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@@ -107,12 +106,12 @@ nn::GeneralResult<std::shared_ptr<const Device>> Device::create(std::string name
|
||||
<< "V1_3::utils::Device::create must have non-null device";
|
||||
}
|
||||
|
||||
auto versionString = NN_TRY(V1_2::utils::initVersionString(device.get()));
|
||||
const auto deviceType = NN_TRY(V1_2::utils::initDeviceType(device.get()));
|
||||
auto extensions = NN_TRY(V1_2::utils::initExtensions(device.get()));
|
||||
auto capabilities = NN_TRY(initCapabilities(device.get()));
|
||||
auto versionString = NN_TRY(V1_2::utils::getVersionStringFrom(device.get()));
|
||||
const auto deviceType = NN_TRY(V1_2::utils::getDeviceTypeFrom(device.get()));
|
||||
auto extensions = NN_TRY(V1_2::utils::getSupportedExtensionsFrom(device.get()));
|
||||
auto capabilities = NN_TRY(getCapabilitiesFrom(device.get()));
|
||||
const auto numberOfCacheFilesNeeded =
|
||||
NN_TRY(V1_2::utils::initNumberOfCacheFilesNeeded(device.get()));
|
||||
NN_TRY(V1_2::utils::getNumberOfCacheFilesNeededFrom(device.get()));
|
||||
|
||||
auto deathHandler = NN_TRY(hal::utils::DeathHandler::create(device));
|
||||
return std::make_shared<const Device>(
|
||||
@@ -177,27 +176,12 @@ nn::GeneralResult<std::vector<bool>> Device::getSupportedOperations(const nn::Mo
|
||||
|
||||
const auto hidlModel = NN_TRY(convert(modelInShared));
|
||||
|
||||
nn::GeneralResult<std::vector<bool>> result = NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
|
||||
<< "uninitialized";
|
||||
auto cb = [&result, &model](ErrorStatus status, const hidl_vec<bool>& supportedOperations) {
|
||||
if (status != ErrorStatus::NONE) {
|
||||
const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
|
||||
result = NN_ERROR(canonical)
|
||||
<< "IDevice::getSupportedOperations_1_3 failed with " << toString(status);
|
||||
} else if (supportedOperations.size() != model.main.operations.size()) {
|
||||
result = NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
|
||||
<< "IDevice::getSupportedOperations_1_3 returned vector of size "
|
||||
<< supportedOperations.size() << " but expected "
|
||||
<< model.main.operations.size();
|
||||
} else {
|
||||
result = supportedOperations;
|
||||
}
|
||||
};
|
||||
auto cb = hal::utils::CallbackValue(supportedOperationsCallback);
|
||||
|
||||
const auto ret = kDevice->getSupportedOperations_1_3(hidlModel, cb);
|
||||
HANDLE_TRANSPORT_FAILURE(ret);
|
||||
|
||||
return result;
|
||||
return cb.take();
|
||||
}
|
||||
|
||||
nn::GeneralResult<nn::SharedPreparedModel> Device::prepareModel(
|
||||
@@ -210,12 +194,12 @@ nn::GeneralResult<nn::SharedPreparedModel> Device::prepareModel(
|
||||
NN_TRY(hal::utils::flushDataFromPointerToShared(&model, &maybeModelInShared));
|
||||
|
||||
const auto hidlModel = NN_TRY(convert(modelInShared));
|
||||
const auto hidlPreference = NN_TRY(V1_1::utils::convert(preference));
|
||||
const auto hidlPreference = NN_TRY(convert(preference));
|
||||
const auto hidlPriority = NN_TRY(convert(priority));
|
||||
const auto hidlDeadline = NN_TRY(convert(deadline));
|
||||
const auto hidlModelCache = NN_TRY(V1_2::utils::convert(modelCache));
|
||||
const auto hidlDataCache = NN_TRY(V1_2::utils::convert(dataCache));
|
||||
const auto hidlToken = token;
|
||||
const auto hidlModelCache = NN_TRY(convert(modelCache));
|
||||
const auto hidlDataCache = NN_TRY(convert(dataCache));
|
||||
const auto hidlToken = V1_2::utils::CacheToken{token};
|
||||
|
||||
const auto cb = sp<PreparedModelCallback>::make();
|
||||
const auto scoped = kDeathHandler.protectCallback(cb.get());
|
||||
@@ -224,10 +208,7 @@ nn::GeneralResult<nn::SharedPreparedModel> Device::prepareModel(
|
||||
kDevice->prepareModel_1_3(hidlModel, hidlPreference, hidlPriority, hidlDeadline,
|
||||
hidlModelCache, hidlDataCache, hidlToken, cb);
|
||||
const auto status = HANDLE_TRANSPORT_FAILURE(ret);
|
||||
if (status != ErrorStatus::NONE) {
|
||||
const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
|
||||
return NN_ERROR(canonical) << "prepareModel_1_3 failed with " << toString(status);
|
||||
}
|
||||
HANDLE_HAL_STATUS(status) << "model preparation failed with " << toString(status);
|
||||
|
||||
return cb->get();
|
||||
}
|
||||
@@ -236,9 +217,9 @@ nn::GeneralResult<nn::SharedPreparedModel> Device::prepareModelFromCache(
|
||||
nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
|
||||
const std::vector<nn::SharedHandle>& dataCache, const nn::CacheToken& token) const {
|
||||
const auto hidlDeadline = NN_TRY(convert(deadline));
|
||||
const auto hidlModelCache = NN_TRY(V1_2::utils::convert(modelCache));
|
||||
const auto hidlDataCache = NN_TRY(V1_2::utils::convert(dataCache));
|
||||
const auto hidlToken = token;
|
||||
const auto hidlModelCache = NN_TRY(convert(modelCache));
|
||||
const auto hidlDataCache = NN_TRY(convert(dataCache));
|
||||
const auto hidlToken = V1_2::utils::CacheToken{token};
|
||||
|
||||
const auto cb = sp<PreparedModelCallback>::make();
|
||||
const auto scoped = kDeathHandler.protectCallback(cb.get());
|
||||
@@ -246,10 +227,7 @@ nn::GeneralResult<nn::SharedPreparedModel> Device::prepareModelFromCache(
|
||||
const auto ret = kDevice->prepareModelFromCache_1_3(hidlDeadline, hidlModelCache, hidlDataCache,
|
||||
hidlToken, cb);
|
||||
const auto status = HANDLE_TRANSPORT_FAILURE(ret);
|
||||
if (status != ErrorStatus::NONE) {
|
||||
const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
|
||||
return NN_ERROR(canonical) << "prepareModelFromCache_1_3 failed with " << toString(status);
|
||||
}
|
||||
HANDLE_HAL_STATUS(status) << "model preparation from cache failed with " << toString(status);
|
||||
|
||||
return cb->get();
|
||||
}
|
||||
@@ -263,27 +241,13 @@ nn::GeneralResult<nn::SharedBuffer> Device::allocate(
|
||||
const auto hidlInputRoles = NN_TRY(convert(inputRoles));
|
||||
const auto hidlOutputRoles = NN_TRY(convert(outputRoles));
|
||||
|
||||
nn::GeneralResult<nn::SharedBuffer> result = NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
|
||||
<< "uninitialized";
|
||||
auto cb = [&result](ErrorStatus status, const sp<IBuffer>& buffer, uint32_t token) {
|
||||
if (status != ErrorStatus::NONE) {
|
||||
const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
|
||||
result = NN_ERROR(canonical) << "IDevice::allocate failed with " << toString(status);
|
||||
} else if (buffer == nullptr) {
|
||||
result = NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "Returned buffer is nullptr";
|
||||
} else if (token == 0) {
|
||||
result = NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "Returned token is invalid (0)";
|
||||
} else {
|
||||
result = convert(
|
||||
Buffer::create(buffer, static_cast<nn::Request::MemoryDomainToken>(token)));
|
||||
}
|
||||
};
|
||||
auto cb = hal::utils::CallbackValue(allocationCallback);
|
||||
|
||||
const auto ret =
|
||||
kDevice->allocate(hidlDesc, hidlPreparedModels, hidlInputRoles, hidlOutputRoles, cb);
|
||||
HANDLE_TRANSPORT_FAILURE(ret);
|
||||
|
||||
return result;
|
||||
return cb.take();
|
||||
}
|
||||
|
||||
} // namespace android::hardware::neuralnetworks::V1_3::utils
|
||||
|
||||
@@ -45,25 +45,17 @@
|
||||
namespace android::hardware::neuralnetworks::V1_3::utils {
|
||||
namespace {
|
||||
|
||||
nn::GeneralResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>
|
||||
convertExecutionResultsHelper(const hidl_vec<V1_2::OutputShape>& outputShapes,
|
||||
const V1_2::Timing& timing) {
|
||||
return std::make_pair(NN_TRY(nn::convert(outputShapes)), NN_TRY(nn::convert(timing)));
|
||||
}
|
||||
|
||||
nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> convertExecutionResults(
|
||||
const hidl_vec<V1_2::OutputShape>& outputShapes, const V1_2::Timing& timing) {
|
||||
return hal::utils::makeExecutionFailure(convertExecutionResultsHelper(outputShapes, timing));
|
||||
}
|
||||
|
||||
nn::GeneralResult<std::pair<nn::Timing, nn::Timing>> convertFencedExecutionCallbackResults(
|
||||
const V1_2::Timing& timingLaunched, const V1_2::Timing& timingFenced) {
|
||||
ErrorStatus status, const V1_2::Timing& timingLaunched, const V1_2::Timing& timingFenced) {
|
||||
HANDLE_HAL_STATUS(status) << "fenced execution callback info failed with " << toString(status);
|
||||
return std::make_pair(NN_TRY(nn::convert(timingLaunched)), NN_TRY(nn::convert(timingFenced)));
|
||||
}
|
||||
|
||||
nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>>
|
||||
convertExecuteFencedResults(const hidl_handle& syncFence,
|
||||
const sp<IFencedExecutionCallback>& callback) {
|
||||
nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>> fencedExecutionCallback(
|
||||
ErrorStatus status, const hidl_handle& syncFence,
|
||||
const sp<IFencedExecutionCallback>& callback) {
|
||||
HANDLE_HAL_STATUS(status) << "fenced execution failed with " << toString(status);
|
||||
|
||||
auto resultSyncFence = nn::SyncFence::createAsSignaled();
|
||||
if (syncFence.getNativeHandle() != nullptr) {
|
||||
auto sharedHandle = NN_TRY(nn::convert(syncFence));
|
||||
@@ -78,23 +70,12 @@ convertExecuteFencedResults(const hidl_handle& syncFence,
|
||||
// Create callback which can be used to retrieve the execution error status and timings.
|
||||
nn::ExecuteFencedInfoCallback resultCallback =
|
||||
[callback]() -> nn::GeneralResult<std::pair<nn::Timing, nn::Timing>> {
|
||||
nn::GeneralResult<std::pair<nn::Timing, nn::Timing>> result =
|
||||
NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "uninitialized";
|
||||
auto cb = [&result](ErrorStatus status, const V1_2::Timing& timingLaunched,
|
||||
const V1_2::Timing& timingFenced) {
|
||||
if (status != ErrorStatus::NONE) {
|
||||
const auto canonical =
|
||||
nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
|
||||
result = NN_ERROR(canonical) << "getExecutionInfo failed with " << toString(status);
|
||||
} else {
|
||||
result = convertFencedExecutionCallbackResults(timingLaunched, timingFenced);
|
||||
}
|
||||
};
|
||||
auto cb = hal::utils::CallbackValue(convertFencedExecutionCallbackResults);
|
||||
|
||||
const auto ret = callback->getExecutionInfo(cb);
|
||||
HANDLE_TRANSPORT_FAILURE(ret);
|
||||
|
||||
return result;
|
||||
return cb.take();
|
||||
};
|
||||
|
||||
return std::make_pair(std::move(resultSyncFence), std::move(resultCallback));
|
||||
@@ -103,42 +84,34 @@ convertExecuteFencedResults(const hidl_handle& syncFence,
|
||||
} // namespace
|
||||
|
||||
nn::GeneralResult<std::shared_ptr<const PreparedModel>> PreparedModel::create(
|
||||
sp<V1_3::IPreparedModel> preparedModel) {
|
||||
sp<V1_3::IPreparedModel> preparedModel, bool executeSynchronously) {
|
||||
if (preparedModel == nullptr) {
|
||||
return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
|
||||
<< "V1_3::utils::PreparedModel::create must have non-null preparedModel";
|
||||
return NN_ERROR() << "V1_3::utils::PreparedModel::create must have non-null preparedModel";
|
||||
}
|
||||
|
||||
auto deathHandler = NN_TRY(hal::utils::DeathHandler::create(preparedModel));
|
||||
return std::make_shared<const PreparedModel>(PrivateConstructorTag{}, std::move(preparedModel),
|
||||
std::move(deathHandler));
|
||||
return std::make_shared<const PreparedModel>(PrivateConstructorTag{}, executeSynchronously,
|
||||
std::move(preparedModel), std::move(deathHandler));
|
||||
}
|
||||
|
||||
PreparedModel::PreparedModel(PrivateConstructorTag /*tag*/, sp<V1_3::IPreparedModel> preparedModel,
|
||||
PreparedModel::PreparedModel(PrivateConstructorTag /*tag*/, bool executeSynchronously,
|
||||
sp<V1_3::IPreparedModel> preparedModel,
|
||||
hal::utils::DeathHandler deathHandler)
|
||||
: kPreparedModel(std::move(preparedModel)), kDeathHandler(std::move(deathHandler)) {}
|
||||
: kExecuteSynchronously(executeSynchronously),
|
||||
kPreparedModel(std::move(preparedModel)),
|
||||
kDeathHandler(std::move(deathHandler)) {}
|
||||
|
||||
nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>
|
||||
PreparedModel::executeSynchronously(const Request& request, V1_2::MeasureTiming measure,
|
||||
const OptionalTimePoint& deadline,
|
||||
const OptionalTimeoutDuration& loopTimeoutDuration) const {
|
||||
nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> result =
|
||||
NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "uninitialized";
|
||||
const auto cb = [&result](ErrorStatus status, const hidl_vec<V1_2::OutputShape>& outputShapes,
|
||||
const V1_2::Timing& timing) {
|
||||
if (status != ErrorStatus::NONE) {
|
||||
const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
|
||||
result = NN_ERROR(canonical) << "executeSynchronously failed with " << toString(status);
|
||||
} else {
|
||||
result = convertExecutionResults(outputShapes, timing);
|
||||
}
|
||||
};
|
||||
auto cb = hal::utils::CallbackValue(executionCallback);
|
||||
|
||||
const auto ret = kPreparedModel->executeSynchronously_1_3(request, measure, deadline,
|
||||
loopTimeoutDuration, cb);
|
||||
HANDLE_TRANSPORT_FAILURE(ret);
|
||||
|
||||
return result;
|
||||
return cb.take();
|
||||
}
|
||||
|
||||
nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>
|
||||
@@ -151,9 +124,8 @@ PreparedModel::executeAsynchronously(const Request& request, V1_2::MeasureTiming
|
||||
const auto ret =
|
||||
kPreparedModel->execute_1_3(request, measure, deadline, loopTimeoutDuration, cb);
|
||||
const auto status = HANDLE_TRANSPORT_FAILURE(ret);
|
||||
if (status != ErrorStatus::NONE) {
|
||||
const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
|
||||
return NN_ERROR(canonical) << "executeAsynchronously failed with " << toString(status);
|
||||
if (status != ErrorStatus::OUTPUT_INSUFFICIENT_SIZE) {
|
||||
HANDLE_HAL_STATUS(status) << "execution failed with " << toString(status);
|
||||
}
|
||||
|
||||
return cb->get();
|
||||
@@ -169,35 +141,22 @@ nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> Prepare
|
||||
hal::utils::flushDataFromPointerToShared(&request, &maybeRequestInShared)));
|
||||
|
||||
const auto hidlRequest = NN_TRY(hal::utils::makeExecutionFailure(convert(requestInShared)));
|
||||
const auto hidlMeasure =
|
||||
NN_TRY(hal::utils::makeExecutionFailure(V1_2::utils::convert(measure)));
|
||||
const auto hidlMeasure = NN_TRY(hal::utils::makeExecutionFailure(convert(measure)));
|
||||
const auto hidlDeadline = NN_TRY(hal::utils::makeExecutionFailure(convert(deadline)));
|
||||
const auto hidlLoopTimeoutDuration =
|
||||
NN_TRY(hal::utils::makeExecutionFailure(convert(loopTimeoutDuration)));
|
||||
|
||||
nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> result =
|
||||
NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "uninitialized";
|
||||
const bool preferSynchronous = true;
|
||||
auto result = kExecuteSynchronously
|
||||
? executeSynchronously(hidlRequest, hidlMeasure, hidlDeadline,
|
||||
hidlLoopTimeoutDuration)
|
||||
: executeAsynchronously(hidlRequest, hidlMeasure, hidlDeadline,
|
||||
hidlLoopTimeoutDuration);
|
||||
auto [outputShapes, timing] = NN_TRY(std::move(result));
|
||||
|
||||
// Execute synchronously if allowed.
|
||||
if (preferSynchronous) {
|
||||
result = executeSynchronously(hidlRequest, hidlMeasure, hidlDeadline,
|
||||
hidlLoopTimeoutDuration);
|
||||
}
|
||||
NN_TRY(hal::utils::makeExecutionFailure(
|
||||
hal::utils::unflushDataFromSharedToPointer(request, maybeRequestInShared)));
|
||||
|
||||
// Run asymchronous execution if execution has not already completed.
|
||||
if (!result.has_value()) {
|
||||
result = executeAsynchronously(hidlRequest, hidlMeasure, hidlDeadline,
|
||||
hidlLoopTimeoutDuration);
|
||||
}
|
||||
|
||||
// Flush output buffers if suxcessful execution.
|
||||
if (result.has_value()) {
|
||||
NN_TRY(hal::utils::makeExecutionFailure(
|
||||
hal::utils::unflushDataFromSharedToPointer(request, maybeRequestInShared)));
|
||||
}
|
||||
|
||||
return result;
|
||||
return std::make_pair(std::move(outputShapes), timing);
|
||||
}
|
||||
|
||||
nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>>
|
||||
@@ -212,28 +171,18 @@ PreparedModel::executeFenced(const nn::Request& request, const std::vector<nn::S
|
||||
|
||||
const auto hidlRequest = NN_TRY(convert(requestInShared));
|
||||
const auto hidlWaitFor = NN_TRY(hal::utils::convertSyncFences(waitFor));
|
||||
const auto hidlMeasure = NN_TRY(V1_2::utils::convert(measure));
|
||||
const auto hidlMeasure = NN_TRY(convert(measure));
|
||||
const auto hidlDeadline = NN_TRY(convert(deadline));
|
||||
const auto hidlLoopTimeoutDuration = NN_TRY(convert(loopTimeoutDuration));
|
||||
const auto hidlTimeoutDurationAfterFence = NN_TRY(convert(timeoutDurationAfterFence));
|
||||
|
||||
nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>> result =
|
||||
NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "uninitialized";
|
||||
auto cb = [&result](ErrorStatus status, const hidl_handle& syncFence,
|
||||
const sp<IFencedExecutionCallback>& callback) {
|
||||
if (status != ErrorStatus::NONE) {
|
||||
const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
|
||||
result = NN_ERROR(canonical) << "executeFenced failed with " << toString(status);
|
||||
} else {
|
||||
result = convertExecuteFencedResults(syncFence, callback);
|
||||
}
|
||||
};
|
||||
auto cb = hal::utils::CallbackValue(fencedExecutionCallback);
|
||||
|
||||
const auto ret = kPreparedModel->executeFenced(hidlRequest, hidlWaitFor, hidlMeasure,
|
||||
hidlDeadline, hidlLoopTimeoutDuration,
|
||||
hidlTimeoutDurationAfterFence, cb);
|
||||
HANDLE_TRANSPORT_FAILURE(ret);
|
||||
auto [syncFence, callback] = NN_TRY(std::move(result));
|
||||
auto [syncFence, callback] = NN_TRY(cb.take());
|
||||
|
||||
// If executeFenced required the request memory to be moved into shared memory, block here until
|
||||
// the fenced execution has completed and flush the memory back.
|
||||
|
||||
@@ -44,9 +44,18 @@ nn::Capabilities::OperandPerformanceTable makeQuantized8PerformanceConsistentWit
|
||||
bool hasNoPointerData(const nn::Model& model);
|
||||
bool hasNoPointerData(const nn::Request& request);
|
||||
|
||||
// Relocate pointer-based data to shared memory.
|
||||
// Relocate pointer-based data to shared memory. If `model` has no Operand::LifeTime::POINTER data,
|
||||
// the function returns with a reference to `model`. If `model` has Operand::LifeTime::POINTER data,
|
||||
// the model is copied to `maybeModelInSharedOut` with the POINTER data relocated to a memory pool,
|
||||
// and the function returns with a reference to `*maybeModelInSharedOut`.
|
||||
nn::GeneralResult<std::reference_wrapper<const nn::Model>> flushDataFromPointerToShared(
|
||||
const nn::Model* model, std::optional<nn::Model>* maybeModelInSharedOut);
|
||||
|
||||
// Relocate pointer-based data to shared memory. If `request` has no
|
||||
// Request::Argument::LifeTime::POINTER data, the function returns with a reference to `request`. If
|
||||
// `request` has Request::Argument::LifeTime::POINTER data, the request is copied to
|
||||
// `maybeRequestInSharedOut` with the POINTER data relocated to a memory pool, and the function
|
||||
// returns with a reference to `*maybeRequestInSharedOut`.
|
||||
nn::GeneralResult<std::reference_wrapper<const nn::Request>> flushDataFromPointerToShared(
|
||||
const nn::Request* request, std::optional<nn::Request>* maybeRequestInSharedOut);
|
||||
|
||||
|
||||
@@ -79,4 +79,11 @@ nn::ExecutionResult<Type> makeExecutionFailure(nn::Result<Type> result, nn::Erro
|
||||
return makeExecutionFailure(makeGeneralFailure(result, status));
|
||||
}
|
||||
|
||||
#define HANDLE_HAL_STATUS(status) \
|
||||
if (const auto canonical = ::android::nn::convert(status).value_or( \
|
||||
::android::nn::ErrorStatus::GENERAL_FAILURE); \
|
||||
canonical == ::android::nn::ErrorStatus::NONE) { \
|
||||
} else \
|
||||
return NN_ERROR(canonical)
|
||||
|
||||
} // namespace android::hardware::neuralnetworks::utils
|
||||
@@ -17,19 +17,60 @@
|
||||
#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_TRANSFER_VALUE_H
|
||||
#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_TRANSFER_VALUE_H
|
||||
|
||||
#include <android-base/logging.h>
|
||||
#include <android-base/thread_annotations.h>
|
||||
|
||||
#include <condition_variable>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <type_traits>
|
||||
|
||||
namespace android::hardware::neuralnetworks::utils {
|
||||
|
||||
// This class is thread safe.
|
||||
// This class adapts a function pointer and offers two affordances:
|
||||
// 1) This class object can be used to generate a callback (via the implicit conversion operator)
|
||||
// that can be used to send the result to `CallbackValue` when called.
|
||||
// 2) This class object can be used to retrieve the result of the callback with `take`.
|
||||
//
|
||||
// This class is thread compatible.
|
||||
template <typename ReturnType, typename... ArgTypes>
|
||||
class CallbackValue final {
|
||||
public:
|
||||
using FunctionType = std::add_pointer_t<ReturnType(ArgTypes...)>;
|
||||
using CallbackType = std::function<void(ArgTypes...)>;
|
||||
|
||||
explicit CallbackValue(FunctionType fn);
|
||||
|
||||
// Creates a callback that forwards its arguments to `mFunction` and stores the result in
|
||||
// `mReturnValue`.
|
||||
/*implicit*/ operator CallbackType(); // NOLINT(google-explicit-constructor)
|
||||
|
||||
// Take the result of calling `mFunction`.
|
||||
// Precondition: mReturnValue.has_value()
|
||||
// Postcondition: !mReturnValue.has_value()
|
||||
[[nodiscard]] ReturnType take();
|
||||
|
||||
private:
|
||||
std::optional<ReturnType> mReturnValue;
|
||||
FunctionType mFunction;
|
||||
};
|
||||
|
||||
// Deduction guidelines for CallbackValue when constructed with a function pointer.
|
||||
template <typename ReturnType, typename... ArgTypes>
|
||||
CallbackValue(ReturnType (*)(ArgTypes...))->CallbackValue<ReturnType, ArgTypes...>;
|
||||
|
||||
// Thread-safe container to pass a value between threads.
|
||||
template <typename Type>
|
||||
class TransferValue final {
|
||||
public:
|
||||
// Put the value in `TransferValue`. If `TransferValue` already has a value, this function is a
|
||||
// no-op.
|
||||
void put(Type object) const;
|
||||
|
||||
// Take the value stored in `TransferValue`. If no value is available, this function will block
|
||||
// until the value becomes available.
|
||||
// Postcondition: !mObject.has_value()
|
||||
[[nodiscard]] Type take() const;
|
||||
|
||||
private:
|
||||
@@ -38,7 +79,23 @@ class TransferValue final {
|
||||
mutable std::optional<Type> mObject GUARDED_BY(mMutex);
|
||||
};
|
||||
|
||||
// template implementation
|
||||
// template implementations
|
||||
|
||||
template <typename ReturnType, typename... ArgTypes>
|
||||
CallbackValue<ReturnType, ArgTypes...>::CallbackValue(FunctionType fn) : mFunction(fn) {}
|
||||
|
||||
template <typename ReturnType, typename... ArgTypes>
|
||||
CallbackValue<ReturnType, ArgTypes...>::operator CallbackType() {
|
||||
return [this](ArgTypes... args) { mReturnValue = mFunction(args...); };
|
||||
}
|
||||
|
||||
template <typename ReturnType, typename... ArgTypes>
|
||||
ReturnType CallbackValue<ReturnType, ArgTypes...>::take() {
|
||||
CHECK(mReturnValue.has_value());
|
||||
std::optional<ReturnType> object;
|
||||
std::swap(object, mReturnValue);
|
||||
return std::move(object).value();
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
void TransferValue<Type>::put(Type object) const {
|
||||
@@ -56,6 +113,7 @@ Type TransferValue<Type>::take() const {
|
||||
std::unique_lock lock(mMutex);
|
||||
base::ScopedLockAssertion lockAssertion(mMutex);
|
||||
mCondition.wait(lock, [this]() REQUIRES(mMutex) { return mObject.has_value(); });
|
||||
CHECK(mObject.has_value());
|
||||
std::optional<Type> object;
|
||||
std::swap(object, mObject);
|
||||
return std::move(object).value();
|
||||
|
||||
Reference in New Issue
Block a user