Files
hardware_interfaces/neuralnetworks/1.2/vts/functional/Callbacks.cpp
Slava Shklyaev 73ee79dafa Refactor NNAPI VTS to remove unreasonable dependence between versions
To make it easier to create the next version of NNAPI, this change
removes the following nonsensical dependence:
- NNAPI 1.0 VTS depends on NNAPI 1.1 and 1.2
- NNAPI 1.1 VTS depends on NNAPI 1.2

In particular, I made the following changes:
- split GeneratedTestHarness.cpp into three separate implementations,
- created a restricted version of Callbacks.h for 1.0 and 1.1,
- removed the dependency on frameworks/ml/nn/HalInterfaces.h,
- refactored Android.bp files for more autonomy between 1.0, 1.1, and 1.2,
- consolidated some common code into Utils.h,
- created structure for sharing code between VTS versions (VtsHalNeuralNetworksV1_0_utils).

Bug: 74827824
Bug: 124462414
Test: VtsHalNeuralnetworksV1_0TargetTest
Test: VtsHalNeuralnetworksV1_1TargetTest
Test: VtsHalNeuralnetworksV1_1CompatV1_0TargetTest
Test: VtsHalNeuralnetworksV1_2TargetTest
Test: VtsHalNeuralnetworksV1_2CompatV1_0TargetTest
Test: VtsHalNeuralnetworksV1_2CompatV1_1TargetTest
Change-Id: I4243d0b5e574255cef1070850f4d0a284f65f54e
Merged-In: I4243d0b5e574255cef1070850f4d0a284f65f54e
(cherry picked from commit 1d6b465997)
2019-07-19 14:00:29 +01:00

174 lines
5.1 KiB
C++

/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "1.2/Callbacks.h"
#include <android-base/logging.h>
namespace android {
namespace hardware {
namespace neuralnetworks {
namespace V1_2 {
namespace implementation {
CallbackBase::CallbackBase() : mNotified(false) {}
CallbackBase::~CallbackBase() {
// Note that we cannot call CallbackBase::join_thread from here:
// CallbackBase is intended to be reference counted, and it is possible that
// the reference count drops to zero in the bound thread, causing the
// bound thread to call this destructor. If a thread tries to join
// itself, it throws an exception, producing a message like the
// following:
//
// terminating with uncaught exception of type std::__1::system_error:
// thread::join failed: Resource deadlock would occur
}
void CallbackBase::wait() {
std::unique_lock<std::mutex> lock(mMutex);
mCondition.wait(lock, [this] { return mNotified; });
join_thread_locked();
}
bool CallbackBase::on_finish(std::function<bool(void)> post_work) {
std::lock_guard<std::mutex> lock(mMutex);
if (mPostWork != nullptr) {
LOG(ERROR) << "CallbackBase::on_finish -- a post-work function has already been bound to "
"this callback object";
return false;
}
if (post_work == nullptr) {
LOG(ERROR) << "CallbackBase::on_finish -- the new post-work function is invalid";
return false;
}
mPostWork = std::move(post_work);
return true;
}
bool CallbackBase::bind_thread(std::thread&& asyncThread) {
std::lock_guard<std::mutex> lock(mMutex);
if (mThread.joinable()) {
LOG(ERROR) << "CallbackBase::bind_thread -- a thread has already been bound to this "
"callback object";
return false;
}
if (!asyncThread.joinable()) {
LOG(ERROR) << "CallbackBase::bind_thread -- the new thread is not joinable";
return false;
}
mThread = std::move(asyncThread);
return true;
}
void CallbackBase::join_thread() {
std::lock_guard<std::mutex> lock(mMutex);
join_thread_locked();
}
void CallbackBase::notify() {
{
std::lock_guard<std::mutex> lock(mMutex);
mNotified = true;
if (mPostWork != nullptr) {
bool success = mPostWork();
if (!success) {
LOG(ERROR) << "CallbackBase::notify -- post work failed";
}
}
}
mCondition.notify_all();
}
void CallbackBase::join_thread_locked() {
if (mThread.joinable()) {
mThread.join();
}
}
PreparedModelCallback::PreparedModelCallback()
: mErrorStatus(ErrorStatus::GENERAL_FAILURE), mPreparedModel(nullptr) {}
PreparedModelCallback::~PreparedModelCallback() {}
Return<void> PreparedModelCallback::notify(ErrorStatus errorStatus,
const sp<V1_0::IPreparedModel>& preparedModel) {
mErrorStatus = errorStatus;
mPreparedModel = preparedModel;
CallbackBase::notify();
return Void();
}
Return<void> PreparedModelCallback::notify_1_2(ErrorStatus errorStatus,
const sp<V1_2::IPreparedModel>& preparedModel) {
mErrorStatus = errorStatus;
mPreparedModel = preparedModel;
CallbackBase::notify();
return Void();
}
ErrorStatus PreparedModelCallback::getStatus() {
wait();
return mErrorStatus;
}
sp<V1_0::IPreparedModel> PreparedModelCallback::getPreparedModel() {
wait();
return mPreparedModel;
}
ExecutionCallback::ExecutionCallback() : mErrorStatus(ErrorStatus::GENERAL_FAILURE) {}
ExecutionCallback::~ExecutionCallback() {}
Return<void> ExecutionCallback::notify(ErrorStatus errorStatus) {
mErrorStatus = errorStatus;
mOutputShapes = {};
mTiming = {.timeOnDevice = UINT64_MAX, .timeInDriver = UINT64_MAX};
CallbackBase::notify();
return Void();
}
Return<void> ExecutionCallback::notify_1_2(ErrorStatus errorStatus,
const hidl_vec<OutputShape>& outputShapes,
const Timing& timing) {
mErrorStatus = errorStatus;
mOutputShapes = outputShapes;
mTiming = timing;
CallbackBase::notify();
return Void();
}
ErrorStatus ExecutionCallback::getStatus() {
wait();
return mErrorStatus;
}
const std::vector<OutputShape>& ExecutionCallback::getOutputShapes() {
wait();
return mOutputShapes;
}
Timing ExecutionCallback::getTiming() {
wait();
return mTiming;
}
} // namespace implementation
} // namespace V1_2
} // namespace neuralnetworks
} // namespace hardware
} // namespace android