@@ -627,6 +627,169 @@ TEST_P(BackendIntegrationTest, GetMethodNameDuringExecuteSuccess) {
627627 ASSERT_EQ (err, Error::Ok);
628628}
629629
630+ TEST_P (BackendIntegrationTest, RuntimeSpecsPassedToBackendInitContext) {
631+ using executorch::runtime::BackendOptions;
632+ using executorch::runtime::LoadBackendOptionsMap;
633+
634+ Result<FileDataLoader> loader = FileDataLoader::from (program_path ());
635+ ASSERT_EQ (loader.error (), Error::Ok);
636+
637+ // Track whether init was called and what runtime_specs it received
638+ bool init_called = false ;
639+ size_t received_specs_size = 0 ;
640+ int received_num_threads = 0 ;
641+ bool received_enable_profiling = false ;
642+ const char * received_compute_unit = nullptr ;
643+
644+ StubBackend::singleton ().install_init (
645+ [&](FreeableBuffer* processed,
646+ ET_UNUSED ArrayRef<CompileSpec> compile_specs,
647+ BackendInitContext& backend_init_context) -> Result<DelegateHandle*> {
648+ init_called = true ;
649+
650+ // Get runtime_specs from context
651+ received_specs_size = backend_init_context.runtime_specs ().size ();
652+
653+ // Use convenience methods to extract values
654+ auto num_threads_result =
655+ backend_init_context.get_runtime_spec <int >(" num_threads" );
656+ if (num_threads_result.ok ()) {
657+ received_num_threads = num_threads_result.get ();
658+ }
659+
660+ auto enable_profiling_result =
661+ backend_init_context.get_runtime_spec <bool >(" enable_profiling" );
662+ if (enable_profiling_result.ok ()) {
663+ received_enable_profiling = enable_profiling_result.get ();
664+ }
665+
666+ auto compute_unit_result =
667+ backend_init_context.get_runtime_spec <const char *>(" compute_unit" );
668+ if (compute_unit_result.ok ()) {
669+ received_compute_unit = compute_unit_result.get ();
670+ }
671+
672+ processed->Free ();
673+ return nullptr ;
674+ });
675+
676+ Result<Program> program = Program::load (&loader.get ());
677+ ASSERT_EQ (program.error (), Error::Ok);
678+
679+ // Create backend options for StubBackend
680+ BackendOptions<4 > stub_opts;
681+ stub_opts.set_option (" num_threads" , 8 );
682+ stub_opts.set_option (" enable_profiling" , true );
683+ stub_opts.set_option (" compute_unit" , " cpu_and_gpu" );
684+
685+ // Create the map and set options for StubBackend
686+ LoadBackendOptionsMap backend_options;
687+ ASSERT_EQ (
688+ backend_options.set_options (StubBackend::kName , stub_opts.view ()),
689+ Error::Ok);
690+
691+ ManagedMemoryManager mmm (kDefaultNonConstMemBytes , kDefaultRuntimeMemBytes );
692+
693+ // Load method with backend_options
694+ Result<Method> method = program->load_method (
695+ " forward" ,
696+ &mmm.get (),
697+ /* event_tracer=*/ nullptr ,
698+ /* named_data_map=*/ nullptr ,
699+ &backend_options);
700+ EXPECT_TRUE (method.ok ());
701+
702+ // Verify that init was called and received the correct runtime_specs
703+ EXPECT_TRUE (init_called);
704+ EXPECT_EQ (received_specs_size, 3 );
705+ EXPECT_EQ (received_num_threads, 8 );
706+ EXPECT_TRUE (received_enable_profiling);
707+ ASSERT_NE (received_compute_unit, nullptr );
708+ EXPECT_STREQ (received_compute_unit, " cpu_and_gpu" );
709+ }
710+
711+ TEST_P (BackendIntegrationTest, NoRuntimeSpecsWhenBackendOptionsNull) {
712+ Result<FileDataLoader> loader = FileDataLoader::from (program_path ());
713+ ASSERT_EQ (loader.error (), Error::Ok);
714+
715+ // Track whether init was called and what runtime_specs it received
716+ bool init_called = false ;
717+ size_t received_specs_size = 0 ;
718+
719+ StubBackend::singleton ().install_init (
720+ [&](FreeableBuffer* processed,
721+ ET_UNUSED ArrayRef<CompileSpec> compile_specs,
722+ BackendInitContext& backend_init_context) -> Result<DelegateHandle*> {
723+ init_called = true ;
724+ received_specs_size = backend_init_context.runtime_specs ().size ();
725+ processed->Free ();
726+ return nullptr ;
727+ });
728+
729+ Result<Program> program = Program::load (&loader.get ());
730+ ASSERT_EQ (program.error (), Error::Ok);
731+
732+ ManagedMemoryManager mmm (kDefaultNonConstMemBytes , kDefaultRuntimeMemBytes );
733+
734+ // Load method WITHOUT backend_options (nullptr)
735+ Result<Method> method = program->load_method (" forward" , &mmm.get ());
736+ EXPECT_TRUE (method.ok ());
737+
738+ // Verify that init was called but received empty runtime_specs
739+ EXPECT_TRUE (init_called);
740+ EXPECT_EQ (received_specs_size, 0 );
741+ }
742+
743+ TEST_P (BackendIntegrationTest, NoRuntimeSpecsWhenBackendNotInMap) {
744+ using executorch::runtime::BackendOptions;
745+ using executorch::runtime::LoadBackendOptionsMap;
746+
747+ Result<FileDataLoader> loader = FileDataLoader::from (program_path ());
748+ ASSERT_EQ (loader.error (), Error::Ok);
749+
750+ // Track whether init was called and what runtime_specs it received
751+ bool init_called = false ;
752+ size_t received_specs_size = 0 ;
753+
754+ StubBackend::singleton ().install_init (
755+ [&](FreeableBuffer* processed,
756+ ET_UNUSED ArrayRef<CompileSpec> compile_specs,
757+ BackendInitContext& backend_init_context) -> Result<DelegateHandle*> {
758+ init_called = true ;
759+ received_specs_size = backend_init_context.runtime_specs ().size ();
760+ processed->Free ();
761+ return nullptr ;
762+ });
763+
764+ Result<Program> program = Program::load (&loader.get ());
765+ ASSERT_EQ (program.error (), Error::Ok);
766+
767+ // Create backend options for a DIFFERENT backend (not StubBackend)
768+ BackendOptions<2 > other_opts;
769+ other_opts.set_option (" key" , " value" );
770+
771+ LoadBackendOptionsMap backend_options;
772+ ASSERT_EQ (
773+ backend_options.set_options (" OtherBackend" , other_opts.view ()),
774+ Error::Ok);
775+
776+ ManagedMemoryManager mmm (kDefaultNonConstMemBytes , kDefaultRuntimeMemBytes );
777+
778+ // Load method with backend_options that don't include StubBackend
779+ Result<Method> method = program->load_method (
780+ " forward" ,
781+ &mmm.get (),
782+ /* event_tracer=*/ nullptr ,
783+ /* named_data_map=*/ nullptr ,
784+ &backend_options);
785+ EXPECT_TRUE (method.ok ());
786+
787+ // Verify that init was called but received empty runtime_specs
788+ // (because StubBackend wasn't in the map)
789+ EXPECT_TRUE (init_called);
790+ EXPECT_EQ (received_specs_size, 0 );
791+ }
792+
630793// TODO: Add more tests for the runtime-to-backend interface. E.g.:
631794// - Errors during init() or execute() result in runtime init/execution failures
632795// - Correct values are passed to init()/execute()
0 commit comments