|
15 | 15 |
|
16 | 16 | #include <executorch/extension/data_loader/file_data_loader.h> |
17 | 17 | #include <executorch/extension/tensor/tensor.h> |
| 18 | +#include <executorch/runtime/backend/backend_options_map.h> |
| 19 | +#include <executorch/runtime/backend/options.h> |
18 | 20 | #include <executorch/runtime/core/exec_aten/testing_util/tensor_util.h> |
19 | 21 |
|
20 | 22 | using namespace ::executorch::extension; |
@@ -554,3 +556,165 @@ TEST_F(ModuleTest, TestPTD_Multiple) { |
554 | 556 | auto tensor2 = make_tensor_ptr({3}, {2.f, 3.f, 4.f}); |
555 | 557 | ASSERT_EQ(module_linear.forward(tensor2).error(), Error::Ok); |
556 | 558 | } |
| 559 | + |
| 560 | +// ============================================================================= |
| 561 | +// LoadBackendOptionsMap / RuntimeSpec Tests |
| 562 | +// ============================================================================= |
| 563 | + |
| 564 | +TEST_F(ModuleTest, TestLoadWithLoadBackendOptionsMap) { |
| 565 | + Module module(model_path_); |
| 566 | + |
| 567 | + // Create a LoadBackendOptionsMap with some options for a hypothetical backend |
| 568 | + LoadBackendOptionsMap backend_options; |
| 569 | + BackendOptions<4> options; |
| 570 | + options.set_option("compute_unit", "cpu_only"); |
| 571 | + options.set_option("debug_mode", true); |
| 572 | + ASSERT_EQ( |
| 573 | + backend_options.set_options("TestBackend", options.view()), Error::Ok); |
| 574 | + |
| 575 | + // Load with backend options - should succeed even though the model |
| 576 | + // doesn't use this backend (options are simply passed through) |
| 577 | + EXPECT_FALSE(module.is_loaded()); |
| 578 | + const auto error = module.load(backend_options); |
| 579 | + EXPECT_EQ(error, Error::Ok); |
| 580 | + EXPECT_TRUE(module.is_loaded()); |
| 581 | +} |
| 582 | + |
| 583 | +TEST_F(ModuleTest, TestLoadWithLoadBackendOptionsMapThenExecute) { |
| 584 | + Module module(model_path_); |
| 585 | + |
| 586 | + LoadBackendOptionsMap backend_options; |
| 587 | + BackendOptions<2> options; |
| 588 | + options.set_option("key1", "value1"); |
| 589 | + ASSERT_EQ( |
| 590 | + backend_options.set_options("SomeBackend", options.view()), Error::Ok); |
| 591 | + |
| 592 | + const auto load_error = module.load(backend_options); |
| 593 | + EXPECT_EQ(load_error, Error::Ok); |
| 594 | + |
| 595 | + // Execute should work normally |
| 596 | + auto tensor = make_tensor_ptr({2, 2}, {1.f, 2.f, 3.f, 4.f}); |
| 597 | + const auto result = module.execute("forward", {tensor, tensor, 1.0}); |
| 598 | + EXPECT_EQ(result.error(), Error::Ok); |
| 599 | + |
| 600 | + const auto expected = make_tensor_ptr({2, 2}, {2.f, 4.f, 6.f, 8.f}); |
| 601 | + EXPECT_TENSOR_CLOSE(result->at(0).toTensor(), *expected.get()); |
| 602 | +} |
| 603 | + |
| 604 | +TEST_F(ModuleTest, TestLoadMethodWithLoadBackendOptionsMap) { |
| 605 | + Module module(model_path_); |
| 606 | + |
| 607 | + LoadBackendOptionsMap backend_options; |
| 608 | + BackendOptions<2> options; |
| 609 | + options.set_option("option1", 42); |
| 610 | + ASSERT_EQ( |
| 611 | + backend_options.set_options("AnotherBackend", options.view()), Error::Ok); |
| 612 | + |
| 613 | + EXPECT_FALSE(module.is_method_loaded("forward")); |
| 614 | + const auto error = |
| 615 | + module.load_method("forward", nullptr, nullptr, &backend_options); |
| 616 | + EXPECT_EQ(error, Error::Ok); |
| 617 | + EXPECT_TRUE(module.is_method_loaded("forward")); |
| 618 | + EXPECT_TRUE(module.is_loaded()); |
| 619 | +} |
| 620 | + |
| 621 | +TEST_F(ModuleTest, TestLoadForwardWithLoadBackendOptionsMap) { |
| 622 | + Module module(model_path_); |
| 623 | + |
| 624 | + LoadBackendOptionsMap backend_options; |
| 625 | + BackendOptions<2> options; |
| 626 | + options.set_option("setting", "enabled"); |
| 627 | + ASSERT_EQ( |
| 628 | + backend_options.set_options("ForwardBackend", options.view()), Error::Ok); |
| 629 | + |
| 630 | + EXPECT_FALSE(module.is_method_loaded("forward")); |
| 631 | + const auto error = module.load_forward(nullptr, nullptr, &backend_options); |
| 632 | + EXPECT_EQ(error, Error::Ok); |
| 633 | + EXPECT_TRUE(module.is_method_loaded("forward")); |
| 634 | +} |
| 635 | + |
| 636 | +TEST_F(ModuleTest, TestLoadWithEmptyLoadBackendOptionsMap) { |
| 637 | + Module module(model_path_); |
| 638 | + |
| 639 | + // Empty LoadBackendOptionsMap should work fine |
| 640 | + LoadBackendOptionsMap backend_options; |
| 641 | + |
| 642 | + const auto error = module.load(backend_options); |
| 643 | + EXPECT_EQ(error, Error::Ok); |
| 644 | + EXPECT_TRUE(module.is_loaded()); |
| 645 | +} |
| 646 | + |
| 647 | +TEST_F(ModuleTest, TestLoadBackendOptionsMapPersistedAcrossLoadMethod) { |
| 648 | + Module module(model_path_); |
| 649 | + |
| 650 | + // Set backend options via load() |
| 651 | + LoadBackendOptionsMap backend_options; |
| 652 | + BackendOptions<2> options; |
| 653 | + options.set_option("persist_test", true); |
| 654 | + ASSERT_EQ( |
| 655 | + backend_options.set_options("PersistBackend", options.view()), Error::Ok); |
| 656 | + |
| 657 | + const auto load_error = module.load(backend_options); |
| 658 | + EXPECT_EQ(load_error, Error::Ok); |
| 659 | + |
| 660 | + // load_method without explicit backend_options should use the stored ones |
| 661 | + const auto method_error = module.load_method("forward"); |
| 662 | + EXPECT_EQ(method_error, Error::Ok); |
| 663 | + EXPECT_TRUE(module.is_method_loaded("forward")); |
| 664 | +} |
| 665 | + |
| 666 | +TEST_F(ModuleTest, TestLoadMethodOverridesStoredBackendOptions) { |
| 667 | + Module module(model_path_); |
| 668 | + |
| 669 | + // Set initial backend options via load() |
| 670 | + LoadBackendOptionsMap initial_options; |
| 671 | + BackendOptions<2> opts1; |
| 672 | + opts1.set_option("source", "load"); |
| 673 | + ASSERT_EQ( |
| 674 | + initial_options.set_options("TestBackend", opts1.view()), Error::Ok); |
| 675 | + |
| 676 | + const auto load_error = module.load(initial_options); |
| 677 | + EXPECT_EQ(load_error, Error::Ok); |
| 678 | + |
| 679 | + // Unload and reload with different options passed to load_method |
| 680 | + module.unload_method("forward"); |
| 681 | + |
| 682 | + LoadBackendOptionsMap override_options; |
| 683 | + BackendOptions<2> opts2; |
| 684 | + opts2.set_option("source", "load_method"); |
| 685 | + ASSERT_EQ( |
| 686 | + override_options.set_options("TestBackend", opts2.view()), Error::Ok); |
| 687 | + |
| 688 | + // The override_options should take precedence |
| 689 | + const auto method_error = |
| 690 | + module.load_method("forward", nullptr, nullptr, &override_options); |
| 691 | + EXPECT_EQ(method_error, Error::Ok); |
| 692 | + EXPECT_TRUE(module.is_method_loaded("forward")); |
| 693 | +} |
| 694 | + |
| 695 | +TEST_F(ModuleTest, TestMultipleBackendsInOptionsMap) { |
| 696 | + Module module(model_path_); |
| 697 | + |
| 698 | + LoadBackendOptionsMap backend_options; |
| 699 | + |
| 700 | + // Add options for multiple backends |
| 701 | + BackendOptions<2> backend1_opts; |
| 702 | + backend1_opts.set_option("compute_unit", "gpu"); |
| 703 | + ASSERT_EQ( |
| 704 | + backend_options.set_options("Backend1", backend1_opts.view()), Error::Ok); |
| 705 | + |
| 706 | + BackendOptions<3> backend2_opts; |
| 707 | + backend2_opts.set_option("optimization_level", 3); |
| 708 | + backend2_opts.set_option("debug", false); |
| 709 | + ASSERT_EQ( |
| 710 | + backend_options.set_options("Backend2", backend2_opts.view()), Error::Ok); |
| 711 | + |
| 712 | + const auto error = module.load(backend_options); |
| 713 | + EXPECT_EQ(error, Error::Ok); |
| 714 | + EXPECT_TRUE(module.is_loaded()); |
| 715 | + |
| 716 | + // Should still execute normally |
| 717 | + auto tensor = make_tensor_ptr({2, 2}, {1.f, 2.f, 3.f, 4.f}); |
| 718 | + const auto result = module.forward({tensor, tensor, 1.0}); |
| 719 | + EXPECT_EQ(result.error(), Error::Ok); |
| 720 | +} |
0 commit comments