1 /*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "CompilationBuilder.h"
18 #include "ExecutionBurstServer.h"
19 #include "HalInterfaces.h"
20 #include "Manager.h"
21 #include "NeuralNetworks.h"
22 #include "NeuralNetworksOEM.h"
23 #include "SampleDriver.h"
24 #include "TestNeuralNetworksWrapper.h"
25 #include "Utils.h"
26 #include "ValidateHal.h"
27
28 #include <gtest/gtest.h>
29
30 #include <iterator>
31 #include <map>
32 #include <queue>
33 #include <set>
34
35 namespace {
36
37 using namespace ::android;
38
39 using CompilationBuilder = nn::CompilationBuilder;
40 using Device = nn::Device;
41 using DeviceManager = nn::DeviceManager;
42 using ExecutePreference = nn::test_wrapper::ExecutePreference;
43 using ExecutionBurstServer = nn::ExecutionBurstServer;
44 using HidlModel = hardware::neuralnetworks::V1_2::Model;
45 using HidlToken = hardware::hidl_array<uint8_t, ANEURALNETWORKS_BYTE_SIZE_OF_CACHE_TOKEN>;
46 using PreparedModelCallback = hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback;
47 using Result = nn::test_wrapper::Result;
48 using SampleDriver = nn::sample_driver::SampleDriver;
49 using SamplePreparedModel = nn::sample_driver::SamplePreparedModel;
50 using WrapperModel = nn::test_wrapper::Model;
51 using WrapperOperandType = nn::test_wrapper::OperandType;
52 using WrapperType = nn::test_wrapper::Type;
53
54 template <typename T>
55 using MQDescriptorSync = hardware::MQDescriptorSync<T>;
56
57 const Timing kBadTiming = {.timeOnDevice = UINT64_MAX, .timeInDriver = UINT64_MAX};
58
59 // This is an IDevice for testing purposes. The test driver has customized
60 // getCapabilities_1_1 and getSupportedOperations_1_2.
61 class TestDriver : public SampleDriver {
62 public:
TestDriver(const char * name,Capabilities capabilities,const std::vector<bool> & supportedOps)63 TestDriver(const char* name, Capabilities capabilities, const std::vector<bool>& supportedOps)
64 : SampleDriver(name), mCapabilities(capabilities), mSupportedOps(supportedOps) {}
~TestDriver()65 ~TestDriver() override {}
66
getCapabilities_1_2(getCapabilities_1_2_cb cb)67 Return<void> getCapabilities_1_2(getCapabilities_1_2_cb cb) override {
68 cb(ErrorStatus::NONE, mCapabilities);
69 return Void();
70 }
71
getSupportedOperations_1_2(const Model & model,getSupportedOperations_cb cb)72 Return<void> getSupportedOperations_1_2(const Model& model,
73 getSupportedOperations_cb cb) override {
74 if (!android::nn::validateModel(model)) {
75 cb(ErrorStatus::INVALID_ARGUMENT, std::vector<bool>());
76 return Void();
77 }
78 const size_t count = model.operations.size();
79 std::vector<bool> supported(count);
80 std::transform(
81 model.operations.begin(), model.operations.end(), supported.begin(),
82 [this](Operation op) { return mSupportedOps[static_cast<int32_t>(op.type)]; });
83 cb(ErrorStatus::NONE, supported);
84 return Void();
85 }
86
87 private:
88 Capabilities mCapabilities;
89 std::vector<bool> mSupportedOps;
90 };
91
92 class IntrospectionControlTest : public ::testing::Test {
93 protected:
SetUp()94 virtual void SetUp() {}
TearDown()95 virtual void TearDown() {
96 if (mEvent) {
97 ANeuralNetworksEvent_free(mEvent);
98 }
99 if (mExecution) {
100 ANeuralNetworksExecution_free(mExecution);
101 }
102 if (mCompilation) {
103 ANeuralNetworksCompilation_free(mCompilation);
104 }
105 DeviceManager::get()->forTest_reInitializeDeviceList();
106 }
107
108 struct DeviceSpecification {
DeviceSpecification__anon062581700111::IntrospectionControlTest::DeviceSpecification109 DeviceSpecification(const std::string& name, float perf, std::vector<bool>& supportedOps)
110 : mName(name), mSupportedOps(supportedOps) {
111 PerformanceInfo perfInfo = {.execTime = perf, .powerUsage = perf};
112 mCapabilities = {.relaxedFloat32toFloat16PerformanceScalar = perfInfo,
113 .relaxedFloat32toFloat16PerformanceTensor = perfInfo,
114 .operandPerformance = nn::nonExtensionOperandPerformance(perfInfo)};
115 }
116 std::string mName;
117 Capabilities mCapabilities;
118 std::vector<bool> mSupportedOps;
119 };
120
121 // From a vector of DeviceSpecification, register new Devices.
registerDevices(std::vector<DeviceSpecification> specifications)122 void registerDevices(std::vector<DeviceSpecification> specifications) {
123 for (const auto& specification : specifications) {
124 DeviceManager::get()->forTest_registerDevice(
125 specification.mName.c_str(),
126 new TestDriver(specification.mName.c_str(), specification.mCapabilities,
127 specification.mSupportedOps));
128 }
129 }
130
selectDeviceByName(const std::string & name)131 bool selectDeviceByName(const std::string& name) {
132 uint32_t numDevices = 0;
133 EXPECT_EQ(ANeuralNetworks_getDeviceCount(&numDevices), ANEURALNETWORKS_NO_ERROR);
134 EXPECT_GE(numDevices, (uint32_t)1);
135
136 for (uint32_t i = 0; i < numDevices; i++) {
137 ANeuralNetworksDevice* device = nullptr;
138 EXPECT_EQ(ANeuralNetworks_getDevice(i, &device), ANEURALNETWORKS_NO_ERROR);
139 const char* buffer = nullptr;
140 int result = ANeuralNetworksDevice_getName(device, &buffer);
141 if (result == ANEURALNETWORKS_NO_ERROR && name.compare(buffer) == 0) {
142 mDevices.push_back(device);
143 return true;
144 }
145 }
146 return false;
147 }
148
isSupportedOpListExpected(const std::vector<bool> & expected)149 bool isSupportedOpListExpected(const std::vector<bool>& expected) {
150 const uint32_t kMaxNumberOperations = 256;
151 EXPECT_LE(expected.size(), kMaxNumberOperations);
152 ANeuralNetworksModel* modelHandle = mModel.getHandle();
153 bool supported[kMaxNumberOperations] = {false};
154 EXPECT_EQ(ANeuralNetworksModel_getSupportedOperationsForDevices(
155 modelHandle, mDevices.data(), mDevices.size(), supported),
156 ANEURALNETWORKS_NO_ERROR);
157 return std::equal(expected.begin(), expected.end(), supported);
158 }
159
prepareForExecution(bool measureTiming=false)160 int prepareForExecution(bool measureTiming = false) {
161 ANeuralNetworksModel* modelHandle = mModel.getHandle();
162 int result = ANeuralNetworksCompilation_createForDevices(modelHandle, mDevices.data(),
163 mDevices.size(), &mCompilation);
164 if (result != ANEURALNETWORKS_NO_ERROR) {
165 return result;
166 }
167 EXPECT_EQ(ANeuralNetworksCompilation_finish(mCompilation), ANEURALNETWORKS_NO_ERROR);
168 EXPECT_EQ(ANeuralNetworksExecution_create(mCompilation, &mExecution),
169 ANEURALNETWORKS_NO_ERROR);
170 if (measureTiming) {
171 // Don't call setMeasureTiming unless we need to -- cannot call this
172 // API unless there is exactly one device.
173 EXPECT_EQ(ANeuralNetworksExecution_setMeasureTiming(mExecution, true),
174 ANEURALNETWORKS_NO_ERROR);
175 }
176 return ANEURALNETWORKS_NO_ERROR;
177 }
178
179 std::vector<ANeuralNetworksDevice*> mDevices;
180 ANeuralNetworksEvent* mEvent = nullptr;
181 ANeuralNetworksExecution* mExecution = nullptr;
182 ANeuralNetworksCompilation* mCompilation = nullptr;
183 WrapperModel mModel;
184 };
185
createSimpleAddModel(WrapperModel * model)186 void createSimpleAddModel(WrapperModel* model) {
187 WrapperOperandType type0(WrapperType::TENSOR_FLOAT32, {2});
188 WrapperOperandType type1(WrapperType::INT32, {});
189 // Phase 1, operands
190 auto op1 = model->addOperand(&type0);
191 auto op2 = model->addOperand(&type0);
192 auto act = model->addOperand(&type1);
193 auto op3 = model->addOperand(&type0);
194 // Phase 2, operations
195 static int32_t act_init[] = {0};
196 model->setOperandValue(act, act_init, sizeof(act_init));
197 model->addOperation(ANEURALNETWORKS_ADD, {op1, op2, act}, {op3});
198 // Phase 3, inputs and outputs
199 model->identifyInputsAndOutputs({op1, op2}, {op3});
200 model->finish();
201 ASSERT_TRUE(model->isValid());
202 }
203
204 // This test verifies that a simple ADD model is able to run on a single device that claims being
205 // able to handle all operations.
TEST_F(IntrospectionControlTest,SimpleAddModel)206 TEST_F(IntrospectionControlTest, SimpleAddModel) {
207 // This is needed before we have the CPU fallback path being treated as a Device.
208 // TODO(miaowang): remove once b/72506261 is fixed.
209 if (DeviceManager::get()->getUseCpuOnly()) {
210 GTEST_SKIP();
211 }
212
213 createSimpleAddModel(&mModel);
214
215 std::string driverName = "test-all";
216 std::vector<bool> ops(android::nn::kNumberOfOperationTypes, true);
217 registerDevices({{driverName, 0.9, ops}});
218
219 EXPECT_TRUE(selectDeviceByName(driverName));
220 EXPECT_TRUE(isSupportedOpListExpected({true}));
221 EXPECT_EQ(prepareForExecution(), ANEURALNETWORKS_NO_ERROR);
222
223 // Verify that the mCompilation is actually using the "test-all" device.
224 CompilationBuilder* c = reinterpret_cast<CompilationBuilder*>(mCompilation);
225 const char* deviceNameBuffer =
226 c->forTest_getExecutionPlan().forTest_simpleGetDevice()->getName();
227 EXPECT_TRUE(driverName.compare(deviceNameBuffer) == 0);
228
229 float input1[2] = {1.0f, 2.0f};
230 float input2[2] = {3.0f, 4.0f};
231 float output[2];
232 EXPECT_EQ(ANeuralNetworksExecution_setInput(mExecution, 0, nullptr, input1, sizeof(input1)),
233 ANEURALNETWORKS_NO_ERROR);
234 EXPECT_EQ(ANeuralNetworksExecution_setInput(mExecution, 1, nullptr, input2, sizeof(input2)),
235 ANEURALNETWORKS_NO_ERROR);
236 EXPECT_EQ(ANeuralNetworksExecution_setOutput(mExecution, 0, nullptr, output, sizeof(output)),
237 ANEURALNETWORKS_NO_ERROR);
238 EXPECT_EQ(ANeuralNetworksExecution_setMeasureTiming(mExecution, true),
239 ANEURALNETWORKS_NO_ERROR);
240
241 EXPECT_EQ(ANeuralNetworksExecution_startCompute(mExecution, &mEvent), ANEURALNETWORKS_NO_ERROR);
242 EXPECT_EQ(ANeuralNetworksEvent_wait(mEvent), ANEURALNETWORKS_NO_ERROR);
243 EXPECT_EQ(output[0], input1[0] + input2[0]);
244 EXPECT_EQ(output[1], input1[1] + input2[1]);
245
246 uint64_t timeOnHardware, timeInDriver;
247 EXPECT_EQ(ANeuralNetworksExecution_getDuration(mExecution, ANEURALNETWORKS_DURATION_ON_HARDWARE,
248 &timeOnHardware),
249 ANEURALNETWORKS_NO_ERROR);
250 EXPECT_EQ(ANeuralNetworksExecution_getDuration(mExecution, ANEURALNETWORKS_DURATION_IN_DRIVER,
251 &timeInDriver),
252 ANEURALNETWORKS_NO_ERROR);
253 if (timeOnHardware != UINT64_MAX && timeInDriver != UINT64_MAX) {
254 EXPECT_LE(timeOnHardware, timeInDriver);
255 }
256 }
257
258 /*-- Begin timing tests -------------------------------------------------------------------------*/
259
260 namespace timing_tests {
261
262 constexpr Timing kGoodTiming = {.timeOnDevice = 123, .timeInDriver = 456};
263
264 enum class DriverKind {
265 CPU,
266 OLD, // too old to support timing (1.1 or earlier)
267 NEW // new enough to support timing (1.2 or later)
268 };
269
operator <<(std::ostream & os,DriverKind kind)270 std::ostream& operator<<(std::ostream& os, DriverKind kind) {
271 const char* names[] = {"CPU", "OLD", "NEW"};
272 const uint32_t index = static_cast<uint32_t>(kind);
273 CHECK(index < std::size(names));
274 return os << names[index];
275 }
276
277 enum class Success {
278 // ASYNC: Return ErrorStatus::NONE; notify ErrorStatus::NONE and timing
279 // SYNC, BURST: Return ErrorStatus::NONE and timing
280 PASS_NEITHER, // timing = kBadTiming
281 PASS_DEVICE, // timing = kGoodTiming.timeOnDevice, kBadTiming.timeInDriver
282 PASS_DRIVER, // timing = kBadTiming.timeOnDevice, kGoodTiming.timeInDriver
283 PASS_BOTH, // timing = kGoodTiming
284 PASS_CPU, // timing = { kBadTiming.timeOnDevice or 0, kBadTiming.timeInDriver or 0 }
285
286 // ASYNC: Return ErrorStatus::GENERAL_FAILURE; notify ErrorStatus::GENERAL_FAILURE and
287 // kBadTiming
288 // SYNC, BURST: Return ErrorStatus::GENERAL_FAILURE and kBadTiming
289 FAIL_LAUNCH,
290
291 // ASYNC: Return ErrorStatus::NONE; notify ErrorStatus::GENERAL_FAILURE and kBadTiming
292 FAIL_WAIT
293 };
294
operator <<(std::ostream & os,Success success)295 std::ostream& operator<<(std::ostream& os, Success success) {
296 const char* names[] = {"PASS_NEITHER", "PASS_DEVICE", "PASS_DRIVER", "PASS_BOTH",
297 "PASS_CPU", "FAIL_LAUNCH", "FAIL_WAIT"};
298 const uint32_t index = static_cast<uint32_t>(success);
299 CHECK(index < std::size(names));
300 return os << names[index];
301 }
302
303 std::map<Success, Timing> expectedTimingMap = {
304 {Success::PASS_NEITHER, kBadTiming},
305 {Success::PASS_DEVICE,
306 {.timeOnDevice = kGoodTiming.timeOnDevice, .timeInDriver = kBadTiming.timeInDriver}},
307 {Success::PASS_DRIVER,
308 {.timeOnDevice = kBadTiming.timeOnDevice, .timeInDriver = kGoodTiming.timeInDriver}},
309 {Success::PASS_BOTH, kGoodTiming},
310 {Success::FAIL_LAUNCH, kBadTiming},
311 {Success::FAIL_WAIT, kBadTiming}};
312
313 std::set<Success> expectedPassSet = {Success::PASS_NEITHER, Success::PASS_DEVICE,
314 Success::PASS_DRIVER, Success::PASS_BOTH, Success::PASS_CPU};
315
316 enum class Compute { ASYNC, SYNC, BURST };
317
operator <<(std::ostream & os,Compute compute)318 std::ostream& operator<<(std::ostream& os, Compute compute) {
319 const char* names[] = {"ASYNC", "SYNC", "BURST"};
320 const uint32_t index = static_cast<uint32_t>(compute);
321 CHECK(index < std::size(names));
322 return os << names[index];
323 }
324
325 // For these tests we don't care about actually running an inference -- we
326 // just want to dummy up execution status and timing results.
327 class TestPreparedModel12 : public SamplePreparedModel {
328 public:
TestPreparedModel12(const HidlModel & model,const SampleDriver * driver,Success success)329 TestPreparedModel12(const HidlModel& model, const SampleDriver* driver, Success success)
330 : SamplePreparedModel(model, driver), mSuccess(success) {}
331
execute(const Request &,const sp<V1_0::IExecutionCallback> & callback)332 Return<ErrorStatus> execute(const Request&,
333 const sp<V1_0::IExecutionCallback>& callback) override {
334 switch (mSuccess) {
335 case Success::PASS_NEITHER:
336 callback->notify(ErrorStatus::NONE);
337 return ErrorStatus::NONE;
338 case Success::FAIL_LAUNCH:
339 callback->notify(ErrorStatus::GENERAL_FAILURE);
340 return ErrorStatus::GENERAL_FAILURE;
341 case Success::FAIL_WAIT:
342 callback->notify(ErrorStatus::GENERAL_FAILURE);
343 return ErrorStatus::NONE;
344 default:
345 ADD_FAILURE() << "Unexpected Success kind";
346 return ErrorStatus::GENERAL_FAILURE;
347 }
348 }
349
execute_1_2(const Request &,MeasureTiming measure,const sp<V1_2::IExecutionCallback> & callback)350 Return<ErrorStatus> execute_1_2(const Request&, MeasureTiming measure,
351 const sp<V1_2::IExecutionCallback>& callback) override {
352 EXPECT_EQ(measure, MeasureTiming::YES);
353 switch (mSuccess) {
354 case Success::PASS_NEITHER:
355 case Success::PASS_DEVICE:
356 case Success::PASS_DRIVER:
357 case Success::PASS_BOTH:
358 callback->notify_1_2(ErrorStatus::NONE, {}, expectedTimingMap.at(mSuccess));
359 return ErrorStatus::NONE;
360 case Success::FAIL_LAUNCH:
361 callback->notify(ErrorStatus::GENERAL_FAILURE);
362 return ErrorStatus::GENERAL_FAILURE;
363 case Success::FAIL_WAIT:
364 callback->notify(ErrorStatus::GENERAL_FAILURE);
365 return ErrorStatus::NONE;
366 default:
367 ADD_FAILURE() << "Unexpected Success kind";
368 return ErrorStatus::GENERAL_FAILURE;
369 }
370 }
371
executeSynchronously(const Request &,MeasureTiming measure,executeSynchronously_cb cb)372 Return<void> executeSynchronously(const Request&, MeasureTiming measure,
373 executeSynchronously_cb cb) override {
374 EXPECT_EQ(measure, MeasureTiming::YES);
375 switch (mSuccess) {
376 case Success::PASS_NEITHER:
377 case Success::PASS_DEVICE:
378 case Success::PASS_DRIVER:
379 case Success::PASS_BOTH:
380 cb(ErrorStatus::NONE, {}, expectedTimingMap.at(mSuccess));
381 return Void();
382 case Success::FAIL_LAUNCH:
383 case Success::FAIL_WAIT:
384 // While this is a synchronous execution method, the NNAPI
385 // runtime may call it even for asynchronous execution, so we
386 // need to tolerate Success::FAIL_WAIT here, not just
387 // Success::FAIL_LAUNCH.
388 cb(ErrorStatus::GENERAL_FAILURE, {}, kBadTiming);
389 return Void();
390 default:
391 ADD_FAILURE() << "Unexpected Success kind";
392 cb(ErrorStatus::GENERAL_FAILURE, {}, kBadTiming);
393 return Void();
394 }
395 }
396
397 // ExecutionBurstServer::create has an overload that will use
398 // IPreparedModel::executeSynchronously(), so we can rely on that, rather
399 // than having to implement ExecutionBurstServer::IExecutorWithCache.
configureExecutionBurst(const sp<V1_2::IBurstCallback> & callback,const MQDescriptorSync<V1_2::FmqRequestDatum> & requestChannel,const MQDescriptorSync<V1_2::FmqResultDatum> & resultChannel,configureExecutionBurst_cb cb)400 Return<void> configureExecutionBurst(
401 const sp<V1_2::IBurstCallback>& callback,
402 const MQDescriptorSync<V1_2::FmqRequestDatum>& requestChannel,
403 const MQDescriptorSync<V1_2::FmqResultDatum>& resultChannel,
404 configureExecutionBurst_cb cb) override {
405 const sp<V1_2::IBurstContext> burst =
406 ExecutionBurstServer::create(callback, requestChannel, resultChannel, this);
407
408 cb(burst == nullptr ? ErrorStatus::GENERAL_FAILURE : ErrorStatus::NONE, burst);
409 return Void();
410 }
411
412 private:
413 Success mSuccess;
414 };
415
416 // Like TestPreparedModel12, but implementing 1.0
417 class TestPreparedModel10 : public V1_0::IPreparedModel {
418 public:
TestPreparedModel10(const HidlModel & model,const SampleDriver * driver,Success success)419 TestPreparedModel10(const HidlModel& model, const SampleDriver* driver, Success success)
420 : m12PreparedModel(new TestPreparedModel12(model, driver, success)) {}
421
execute(const Request & request,const sp<V1_0::IExecutionCallback> & callback)422 Return<ErrorStatus> execute(const Request& request,
423 const sp<V1_0::IExecutionCallback>& callback) override {
424 return m12PreparedModel->execute(request, callback);
425 }
426
427 private:
428 const sp<V1_2::IPreparedModel> m12PreparedModel;
429 };
430
431 // Behaves like SampleDriver, except that it produces customized IPrepareModel.
432 class TestDriver12 : public SampleDriver {
433 public:
TestDriver12(const std::string & name,Success success)434 TestDriver12(const std::string& name, Success success)
435 : SampleDriver(name.c_str()), mSuccess(success) {}
436
getCapabilities_1_2(getCapabilities_1_2_cb _hidl_cb)437 Return<void> getCapabilities_1_2(getCapabilities_1_2_cb _hidl_cb) override {
438 android::nn::initVLogMask();
439 const PerformanceInfo kPerf = {.execTime = 0.75f, .powerUsage = 0.75f};
440 Capabilities capabilities = {
441 .relaxedFloat32toFloat16PerformanceScalar = kPerf,
442 .relaxedFloat32toFloat16PerformanceTensor = kPerf,
443 .operandPerformance = nn::nonExtensionOperandPerformance(kPerf)};
444 _hidl_cb(ErrorStatus::NONE, capabilities);
445 return Void();
446 }
447
getSupportedOperations_1_2(const HidlModel & model,getSupportedOperations_1_2_cb cb)448 Return<void> getSupportedOperations_1_2(const HidlModel& model,
449 getSupportedOperations_1_2_cb cb) override {
450 if (nn::validateModel(model)) {
451 std::vector<bool> supported(model.operations.size(), true);
452 cb(ErrorStatus::NONE, supported);
453 } else {
454 std::vector<bool> supported;
455 cb(ErrorStatus::INVALID_ARGUMENT, supported);
456 }
457 return Void();
458 }
459
prepareModel_1_2(const HidlModel & model,ExecutionPreference,const hidl_vec<hidl_handle> &,const hidl_vec<hidl_handle> &,const HidlToken &,const sp<IPreparedModelCallback> & callback)460 Return<ErrorStatus> prepareModel_1_2(const HidlModel& model, ExecutionPreference,
461 const hidl_vec<hidl_handle>&, const hidl_vec<hidl_handle>&,
462 const HidlToken&,
463 const sp<IPreparedModelCallback>& callback) override {
464 callback->notify_1_2(ErrorStatus::NONE, new TestPreparedModel12(model, this, mSuccess));
465 return ErrorStatus::NONE;
466 }
467
prepareModel_1_1(const V1_1::Model & model,ExecutionPreference,const sp<V1_0::IPreparedModelCallback> & callback)468 Return<ErrorStatus> prepareModel_1_1(
469 const V1_1::Model& model, ExecutionPreference,
470 const sp<V1_0::IPreparedModelCallback>& callback) override {
471 callback->notify(ErrorStatus::NONE,
472 new TestPreparedModel10(nn::convertToV1_2(model), this, mSuccess));
473 return ErrorStatus::NONE;
474 }
475
prepareModel(const V1_0::Model & model,const sp<V1_0::IPreparedModelCallback> & callback)476 Return<ErrorStatus> prepareModel(const V1_0::Model& model,
477 const sp<V1_0::IPreparedModelCallback>& callback) override {
478 return prepareModel_1_1(nn::convertToV1_1(model), ExecutionPreference::FAST_SINGLE_ANSWER,
479 callback);
480 }
481
482 private:
483 Success mSuccess;
484 };
485
486 // Like TestDriver, but implementing 1.1
487 class TestDriver11 : public V1_1::IDevice {
488 public:
TestDriver11(const std::string & name,Success success)489 TestDriver11(const std::string& name, Success success)
490 : m12Driver(new TestDriver12(name, success)) {}
getCapabilities_1_1(getCapabilities_1_1_cb _hidl_cb)491 Return<void> getCapabilities_1_1(getCapabilities_1_1_cb _hidl_cb) override {
492 return m12Driver->getCapabilities_1_1(_hidl_cb);
493 }
getSupportedOperations_1_1(const V1_1::Model & model,getSupportedOperations_1_1_cb _hidl_cb)494 Return<void> getSupportedOperations_1_1(const V1_1::Model& model,
495 getSupportedOperations_1_1_cb _hidl_cb) override {
496 return m12Driver->getSupportedOperations_1_1(model, _hidl_cb);
497 }
prepareModel_1_1(const V1_1::Model & model,ExecutionPreference preference,const sp<V1_0::IPreparedModelCallback> & actualCallback)498 Return<ErrorStatus> prepareModel_1_1(
499 const V1_1::Model& model, ExecutionPreference preference,
500 const sp<V1_0::IPreparedModelCallback>& actualCallback) override {
501 return m12Driver->prepareModel_1_1(model, preference, actualCallback);
502 }
getStatus()503 Return<DeviceStatus> getStatus() override { return m12Driver->getStatus(); }
getCapabilities(getCapabilities_cb _hidl_cb)504 Return<void> getCapabilities(getCapabilities_cb _hidl_cb) override {
505 return m12Driver->getCapabilities(_hidl_cb);
506 }
getSupportedOperations(const V1_0::Model & model,getSupportedOperations_cb _hidl_cb)507 Return<void> getSupportedOperations(const V1_0::Model& model,
508 getSupportedOperations_cb _hidl_cb) override {
509 return m12Driver->getSupportedOperations(model, _hidl_cb);
510 }
prepareModel(const V1_0::Model & model,const sp<V1_0::IPreparedModelCallback> & actualCallback)511 Return<ErrorStatus> prepareModel(
512 const V1_0::Model& model,
513 const sp<V1_0::IPreparedModelCallback>& actualCallback) override {
514 return m12Driver->prepareModel(model, actualCallback);
515 }
516
517 private:
518 const sp<V1_2::IDevice> m12Driver;
519 };
520
521 class TimingTest : public IntrospectionControlTest,
522 public ::testing::WithParamInterface<std::tuple<DriverKind, Success, Compute>> {
523 public:
TimingTest()524 TimingTest()
525 : kDriverKind(std::get<0>(GetParam())),
526 kSuccess(std::get<1>(GetParam())),
527 kCompute(std::get<2>(GetParam())) {}
528
529 protected:
530 const DriverKind kDriverKind;
531 const Success kSuccess;
532 const Compute kCompute;
533 };
534
TEST_P(TimingTest,Test)535 TEST_P(TimingTest, Test) {
536 // There's no straightforward way to force CPU execution to fail.
537 ASSERT_EQ(kDriverKind == DriverKind::CPU, kSuccess == Success::PASS_CPU);
538
539 // FAIL_WAIT only makes sense for ASYNC.
540 ASSERT_TRUE(kCompute == Compute::ASYNC || kSuccess != Success::FAIL_WAIT);
541
542 if (DeviceManager::get()->getUseCpuOnly() != (kDriverKind == DriverKind::CPU)) {
543 // We don't have an elegant way to request the CPU driver. Therefore,
544 // we rely on our test framework to make the choice between CPU and
545 // non-CPU.
546 GTEST_SKIP();
547 }
548
549 createSimpleAddModel(&mModel);
550
551 switch (kDriverKind) {
552 case DriverKind::CPU: {
553 // There should be only one driver -- the CPU
554 const char* name = DeviceManager::get()->getDrivers()[0]->getName();
555 ASSERT_TRUE(selectDeviceByName(name));
556 break;
557 }
558 case DriverKind::OLD: {
559 static const char name[] = "old";
560 DeviceManager::get()->forTest_registerDevice(name, new TestDriver11(name, kSuccess));
561 ASSERT_TRUE(selectDeviceByName(name));
562 break;
563 }
564 case DriverKind::NEW: {
565 static const char name[] = "new";
566 DeviceManager::get()->forTest_registerDevice(name, new TestDriver12(name, kSuccess));
567 ASSERT_TRUE(selectDeviceByName(name));
568 break;
569 }
570 default:
571 FAIL() << "Unexpected DriverKind";
572 }
573
574 EXPECT_EQ(prepareForExecution(true /*measureTiming*/), ANEURALNETWORKS_NO_ERROR);
575
576 float input1[2] = {1.0f, 2.0f};
577 float input2[2] = {3.0f, 4.0f};
578 float output[2];
579 EXPECT_EQ(ANeuralNetworksExecution_setInput(mExecution, 0, nullptr, input1, sizeof(input1)),
580 ANEURALNETWORKS_NO_ERROR);
581 EXPECT_EQ(ANeuralNetworksExecution_setInput(mExecution, 1, nullptr, input2, sizeof(input2)),
582 ANEURALNETWORKS_NO_ERROR);
583 EXPECT_EQ(ANeuralNetworksExecution_setOutput(mExecution, 0, nullptr, output, sizeof(output)),
584 ANEURALNETWORKS_NO_ERROR);
585 EXPECT_EQ(ANeuralNetworksExecution_setMeasureTiming(mExecution, true),
586 ANEURALNETWORKS_NO_ERROR);
587
588 auto Check = [](bool expectPass, int result) {
589 if (expectPass) {
590 ASSERT_EQ(result, ANEURALNETWORKS_NO_ERROR);
591 } else {
592 ASSERT_NE(result, ANEURALNETWORKS_NO_ERROR);
593 }
594 };
595
596 const bool isPass = expectedPassSet.count(kSuccess) != 0;
597
598 switch (kCompute) {
599 case Compute::ASYNC: {
600 // Ideally what we'd like to do here is
601 //
602 // Check(kSuccess != Success::FAIL_LAUNCH,
603 // ANeuralNetworksExecution_startCompute(mExecution, &mEvent));
604 // Check(isPass, ANeuralNetworksEvent_wait(mEvent));
605 //
606 // However, in the current implementation of the runtime, a launch
607 // failure at the HAL level does not show up as a launch failure at
608 // the NDK level ("startCompute"): The NNAPI runtime does not call a
609 // driver until it (the runtime) begins execution, so a launch
610 // failure at the HAL level looks like an execution failure at the
611 // NDK level ("wait").
612 SCOPED_TRACE("ASYNC startCompute");
613 Check(true, // rather than kSuccess != Success::FAIL_LAUNCH
614 ANeuralNetworksExecution_startCompute(mExecution, &mEvent));
615 SCOPED_TRACE("ASYNC wait");
616 Check(isPass, ANeuralNetworksEvent_wait(mEvent));
617 break;
618 }
619 case Compute::SYNC: {
620 SCOPED_TRACE("SYNC");
621 Check(isPass, ANeuralNetworksExecution_compute(mExecution));
622 break;
623 }
624 case Compute::BURST: {
625 SCOPED_TRACE("BURST");
626 ANeuralNetworksBurst* burst;
627 ASSERT_EQ(ANeuralNetworksBurst_create(mCompilation, &burst), ANEURALNETWORKS_NO_ERROR);
628 Check(isPass, ANeuralNetworksExecution_burstCompute(mExecution, burst));
629 ANeuralNetworksBurst_free(burst);
630 break;
631 }
632 default:
633 FAIL() << "unreachable";
634 }
635
636 uint64_t timeOnHardware, timeInDriver;
637 EXPECT_EQ(ANeuralNetworksExecution_getDuration(mExecution, ANEURALNETWORKS_DURATION_ON_HARDWARE,
638 &timeOnHardware),
639 ANEURALNETWORKS_NO_ERROR);
640 EXPECT_EQ(ANeuralNetworksExecution_getDuration(mExecution, ANEURALNETWORKS_DURATION_IN_DRIVER,
641 &timeInDriver),
642 ANEURALNETWORKS_NO_ERROR);
643 switch (kDriverKind) {
644 case DriverKind::CPU: {
645 // TODO: Should we require timing to be reported as 0?
646 EXPECT_TRUE(timeOnHardware == 0 || timeOnHardware == UINT64_MAX)
647 << "timeOnHardware = " << timeOnHardware;
648 EXPECT_TRUE(timeInDriver == 0 || timeInDriver == UINT64_MAX)
649 << "timeInDriver = " << timeOnHardware;
650 break;
651 }
652 case DriverKind::OLD: {
653 EXPECT_EQ(timeOnHardware, UINT64_MAX);
654 EXPECT_EQ(timeInDriver, UINT64_MAX);
655 break;
656 }
657 case DriverKind::NEW: {
658 auto microsToNanos = [](uint64_t micros) {
659 constexpr uint64_t kNanosPerMicro = 1000;
660 return micros == UINT64_MAX ? UINT64_MAX : kNanosPerMicro * micros;
661 };
662 const Timing expectedTiming = expectedTimingMap.at(kSuccess);
663 EXPECT_EQ(timeOnHardware, microsToNanos(expectedTiming.timeOnDevice));
664 EXPECT_EQ(timeInDriver, microsToNanos(expectedTiming.timeInDriver));
665 break;
666 }
667 default:
668 FAIL() << "unreachable";
669 }
670 if (timeOnHardware != UINT64_MAX && timeInDriver != UINT64_MAX) {
671 EXPECT_LE(timeOnHardware, timeInDriver);
672 }
673 }
674
675 auto kTimingTestValues = ::testing::Values(
676 // NOTE: We cannot force CPU execution to fail
677 std::make_tuple(DriverKind::CPU, Success::PASS_CPU, Compute::ASYNC),
678 std::make_tuple(DriverKind::CPU, Success::PASS_CPU, Compute::SYNC),
679 std::make_tuple(DriverKind::CPU, Success::PASS_CPU, Compute::BURST),
680
681 // NOTE: OLD driver does not provide timing
682 std::make_tuple(DriverKind::OLD, Success::PASS_NEITHER, Compute::ASYNC),
683 std::make_tuple(DriverKind::OLD, Success::PASS_NEITHER, Compute::SYNC),
684 std::make_tuple(DriverKind::OLD, Success::PASS_NEITHER, Compute::BURST),
685
686 std::make_tuple(DriverKind::OLD, Success::FAIL_LAUNCH, Compute::ASYNC),
687 std::make_tuple(DriverKind::OLD, Success::FAIL_LAUNCH, Compute::SYNC),
688 std::make_tuple(DriverKind::OLD, Success::FAIL_LAUNCH, Compute::BURST),
689
690 // NOTE: Only ASYNC is paired with a wait
691 std::make_tuple(DriverKind::OLD, Success::FAIL_WAIT, Compute::ASYNC),
692
693 std::make_tuple(DriverKind::NEW, Success::PASS_NEITHER, Compute::ASYNC),
694 std::make_tuple(DriverKind::NEW, Success::PASS_NEITHER, Compute::SYNC),
695 std::make_tuple(DriverKind::NEW, Success::PASS_NEITHER, Compute::BURST),
696
697 std::make_tuple(DriverKind::NEW, Success::PASS_DEVICE, Compute::ASYNC),
698 std::make_tuple(DriverKind::NEW, Success::PASS_DEVICE, Compute::SYNC),
699 std::make_tuple(DriverKind::NEW, Success::PASS_DEVICE, Compute::BURST),
700
701 std::make_tuple(DriverKind::NEW, Success::PASS_DRIVER, Compute::ASYNC),
702 std::make_tuple(DriverKind::NEW, Success::PASS_DRIVER, Compute::SYNC),
703 std::make_tuple(DriverKind::NEW, Success::PASS_DRIVER, Compute::BURST),
704
705 std::make_tuple(DriverKind::NEW, Success::PASS_BOTH, Compute::ASYNC),
706 std::make_tuple(DriverKind::NEW, Success::PASS_BOTH, Compute::SYNC),
707 std::make_tuple(DriverKind::NEW, Success::PASS_BOTH, Compute::BURST),
708
709 std::make_tuple(DriverKind::NEW, Success::FAIL_LAUNCH, Compute::ASYNC),
710 std::make_tuple(DriverKind::NEW, Success::FAIL_LAUNCH, Compute::SYNC),
711 std::make_tuple(DriverKind::NEW, Success::FAIL_LAUNCH, Compute::BURST),
712
713 // NOTE: Only ASYNC is paired with a wait
714 std::make_tuple(DriverKind::NEW, Success::FAIL_WAIT, Compute::ASYNC));
715
716 INSTANTIATE_TEST_CASE_P(Flavor, TimingTest, kTimingTestValues);
717
718 } // namespace timing_tests
719
720 /*-- End timing tests -------------------------------------------------------------------------*/
721
722 const float kSimpleMultiplier = 2.0f;
723
createAddMulModel(WrapperModel * model,bool reverseOrder)724 void createAddMulModel(WrapperModel* model, bool reverseOrder) {
725 WrapperOperandType type0(WrapperType::TENSOR_FLOAT32, {2});
726 WrapperOperandType type1(WrapperType::INT32, {});
727 // Phase 1, operands
728 auto op1 = model->addOperand(&type0);
729 auto op2 = model->addOperand(&type0);
730 auto act = model->addOperand(&type1);
731 auto op3 = model->addOperand(&type0);
732 auto op4 = model->addOperand(&type0);
733 auto op5 = model->addOperand(&type0);
734 // Phase 2, operations
735 static int32_t act_init[] = {0};
736 model->setOperandValue(act, act_init, sizeof(act_init));
737 static float multiplier[] = {kSimpleMultiplier, kSimpleMultiplier};
738 model->setOperandValue(op4, multiplier, sizeof(multiplier));
739 if (reverseOrder) {
740 // In this case, add MUL first, but the execution order is still ADD -> MUL.
741 model->addOperation(ANEURALNETWORKS_MUL, {op3, op4, act}, {op5});
742 model->addOperation(ANEURALNETWORKS_ADD, {op1, op2, act}, {op3});
743 } else {
744 model->addOperation(ANEURALNETWORKS_ADD, {op1, op2, act}, {op3});
745 model->addOperation(ANEURALNETWORKS_MUL, {op3, op4, act}, {op5});
746 }
747 // Phase 3, inputs and outputs
748 model->identifyInputsAndOutputs({op1, op2}, {op5});
749 model->finish();
750 ASSERT_TRUE(model->isValid());
751 }
752
753 // TODO(miaowang): add a test to make sure ANNCompilation_create() has CPU
754 // fallback.
755 // This test verifies that a device that could only handle ADD would correctly report that an
756 // ADD->MUL model could not be fully supported.
TEST_F(IntrospectionControlTest,PartialModelNotSupported)757 TEST_F(IntrospectionControlTest, PartialModelNotSupported) {
758 // This is needed before we have the CPU fallback path being treated as a Device.
759 // TODO(miaowang): remove once b/72506261 is fixed.
760 if (DeviceManager::get()->getUseCpuOnly()) {
761 GTEST_SKIP();
762 }
763
764 createAddMulModel(&mModel, false);
765
766 std::string addOnlyDriver = "test-onlyAdd";
767 std::vector<bool> addOnlyOp(android::nn::kNumberOfOperationTypes, false);
768 addOnlyOp[ANEURALNETWORKS_ADD] = true;
769
770 registerDevices({{addOnlyDriver, 0.9, addOnlyOp}});
771
772 EXPECT_TRUE(selectDeviceByName(addOnlyDriver));
773 EXPECT_TRUE(isSupportedOpListExpected({true, false}));
774
775 ANeuralNetworksModel* modelHandle = mModel.getHandle();
776 EXPECT_EQ(ANeuralNetworksCompilation_createForDevices(modelHandle, mDevices.data(),
777 mDevices.size(), &mCompilation),
778 ANEURALNETWORKS_NO_ERROR);
779 // The compilation must fail as there is no fallback when using
780 // Introspection API.
781 EXPECT_NE(ANeuralNetworksCompilation_finish(mCompilation), ANEURALNETWORKS_NO_ERROR);
782 }
783
784 // This test verifies that a device that could only handle ADD would correctly report that an
785 // ADD->MUL model could not be fully supported. Also verifies that the indices of returned
786 // supported op list correctly map to the order of operations being added by the user.
TEST_F(IntrospectionControlTest,PartialModelNotSupportedOrder)787 TEST_F(IntrospectionControlTest, PartialModelNotSupportedOrder) {
788 // This is needed before we have the CPU fallback path being treated as a Device.
789 // TODO(miaowang): remove once b/72506261 is fixed.
790 if (DeviceManager::get()->getUseCpuOnly()) {
791 GTEST_SKIP();
792 }
793
794 createAddMulModel(&mModel, true);
795
796 std::string addOnlyDriver = "test-onlyAdd";
797 std::vector<bool> addOnlyOp(android::nn::kNumberOfOperationTypes, false);
798 addOnlyOp[ANEURALNETWORKS_ADD] = true;
799
800 registerDevices({{addOnlyDriver, 0.9, addOnlyOp}});
801
802 EXPECT_TRUE(selectDeviceByName(addOnlyDriver));
803 EXPECT_TRUE(isSupportedOpListExpected({false, true}));
804 }
805
806 // TODO(miaowang): update the test to make sure the model is actually running on the test devices.
807 // This test verifies that an ADD->MUL model is able to run on two selected devices that together
808 // can handle all operations.
TEST_F(IntrospectionControlTest,ModelNeedTwoDevices)809 TEST_F(IntrospectionControlTest, ModelNeedTwoDevices) {
810 // This is needed before we have the CPU fallback path being treated as a Device.
811 // TODO(miaowang): remove once b/72506261 is fixed.
812 if (DeviceManager::get()->getUseCpuOnly()) {
813 GTEST_SKIP();
814 }
815
816 createAddMulModel(&mModel, false);
817
818 std::string addOnlyDriver = "test-onlyAdd";
819 std::vector<bool> addOnlyOp(android::nn::kNumberOfOperationTypes, false);
820 addOnlyOp[ANEURALNETWORKS_ADD] = true;
821
822 std::string mulOnlyDriver = "test-onlyMul";
823 std::vector<bool> mulOnlyOp(android::nn::kNumberOfOperationTypes, false);
824 mulOnlyOp[ANEURALNETWORKS_MUL] = true;
825
826 registerDevices({
827 {addOnlyDriver, 0.9, addOnlyOp},
828 {mulOnlyDriver, 0.9, mulOnlyOp},
829 });
830
831 EXPECT_TRUE(selectDeviceByName(addOnlyDriver));
832 EXPECT_TRUE(selectDeviceByName(mulOnlyDriver));
833 EXPECT_TRUE(isSupportedOpListExpected({true, true}));
834 EXPECT_EQ(prepareForExecution(), ANEURALNETWORKS_NO_ERROR);
835
836 float input1[2] = {1.0f, 2.0f};
837 float input2[2] = {3.0f, 4.0f};
838 float output[2];
839 EXPECT_EQ(ANeuralNetworksExecution_setInput(mExecution, 0, nullptr, input1, sizeof(input1)),
840 ANEURALNETWORKS_NO_ERROR);
841 EXPECT_EQ(ANeuralNetworksExecution_setInput(mExecution, 1, nullptr, input2, sizeof(input2)),
842 ANEURALNETWORKS_NO_ERROR);
843 EXPECT_EQ(ANeuralNetworksExecution_setOutput(mExecution, 0, nullptr, output, sizeof(output)),
844 ANEURALNETWORKS_NO_ERROR);
845
846 EXPECT_EQ(ANeuralNetworksExecution_startCompute(mExecution, &mEvent), ANEURALNETWORKS_NO_ERROR);
847 EXPECT_EQ(ANeuralNetworksEvent_wait(mEvent), ANEURALNETWORKS_NO_ERROR);
848 EXPECT_EQ(output[0], kSimpleMultiplier * (input1[0] + input2[0]));
849 EXPECT_EQ(output[1], kSimpleMultiplier * (input1[1] + input2[1]));
850 }
851 } // namespace
852