9797#include < unistd.h>
9898#include < memory>
9999#include < type_traits>
100+ #include < utility>
100101#include < vector>
101102
102103#include " arm_memory_allocator.h"
@@ -340,6 +341,8 @@ void et_pal_free(ET_UNUSED void* ptr) {}
340341namespace {
341342
342343// / Lightweight heapless container that constructs and stores a T in-place.
344+ // / Useful when you want to avoid heap allocations but need to delay
345+ // / construction.
343346template <typename T>
344347class Box {
345348 public:
@@ -543,8 +546,13 @@ struct RunnerContext {
543546 size_t input_memsize = 0 ;
544547 size_t pte_size = 0 ;
545548 bool bundle_io = false ;
549+ Box<BufferDataLoader> loader;
550+ Box<Program> program;
546551 Box<ArmMemoryAllocator> method_allocator;
547552 Box<ArmMemoryAllocator> temp_allocator;
553+ std::vector<Span<uint8_t >> planned_spans;
554+ Box<HierarchicalAllocator> planned_memory;
555+ Box<MemoryManager> memory_manager;
548556 Box<Result<Method>> method;
549557#if defined(ET_EVENT_TRACER_ENABLED)
550558 Box<ETDumpGen> etdump_gen;
@@ -584,30 +592,31 @@ void runner_init(
584592 (unsigned int )status);
585593 }
586594#endif
587- auto loader = BufferDataLoader (program_data, ctx.program_data_len );
595+ ctx.loader .reset (program_data, ctx.program_data_len );
596+ auto & loader = ctx.loader .value ();
588597 ET_LOG (Info, " PTE Model data loaded. Size: %zu bytes." , ctx.program_data_len );
589598
590599 // Parse the program file. This is immutable, and can also be reused
591600 // between multiple execution invocations across multiple threads.
592- Result<Program> program = Program::load (&loader);
593- if (!program. ok ()) {
594- ET_LOG (
595- Info ,
596- " Program loading failed @ 0x%p: 0x% " PRIx32 ,
597- program_data,
598- program.error ( ));
599- }
601+ Result<Program> program_result = Program::load (&loader);
602+ ET_CHECK_MSG (
603+ program_result. ok (),
604+ " Program loading failed @ %p: 0x% " PRIx32 ,
605+ program_data ,
606+ program_result. error ());
607+ ctx. program .reset ( std::move (program_result. get () ));
608+ Program& program = ctx. program . value ();
600609
601- ET_LOG (Info, " Model buffer loaded, has %zu methods" , program-> num_methods ());
610+ ET_LOG (Info, " Model buffer loaded, has %zu methods" , program. num_methods ());
602611
603612 {
604- const auto method_name_result = program-> get_method_name (0 );
613+ const auto method_name_result = program. get_method_name (0 );
605614 ET_CHECK_MSG (method_name_result.ok (), " Program has no methods" );
606615 ctx.method_name = *method_name_result;
607616 }
608617 ET_LOG (Info, " Running method %s" , ctx.method_name );
609618
610- Result<MethodMeta> method_meta = program-> method_meta (ctx.method_name );
619+ Result<MethodMeta> method_meta = program. method_meta (ctx.method_name );
611620 if (!method_meta.ok ()) {
612621 ET_LOG (
613622 Info,
@@ -624,10 +633,9 @@ void runner_init(
624633 ctx.method_allocator .reset (
625634 method_allocation_pool_size, method_allocation_pool);
626635
627- std::vector<uint8_t *> planned_buffers; // Owns the memory
628- std::vector<Span<uint8_t >> planned_spans; // Passed to the allocator
636+ ctx.planned_spans .clear ();
629637 size_t num_memory_planned_buffers = method_meta->num_memory_planned_buffers ();
630-
638+ ctx. planned_spans . reserve (num_memory_planned_buffers);
631639 size_t planned_buffer_membase = ctx.method_allocator ->used_size ();
632640
633641 for (size_t id = 0 ; id < num_memory_planned_buffers; ++id) {
@@ -643,21 +651,24 @@ void runner_init(
643651 buffer != nullptr ,
644652 " Could not allocate memory for memory planned buffer size %zu" ,
645653 buffer_size);
646- planned_buffers.push_back (buffer);
647- planned_spans.push_back ({planned_buffers.back (), buffer_size});
654+ ctx.planned_spans .push_back ({buffer, buffer_size});
648655 }
649656
650657 ctx.planned_buffer_memsize =
651658 ctx.method_allocator ->used_size () - planned_buffer_membase;
652659
653- HierarchicalAllocator planned_memory (
654- {planned_spans.data (), planned_spans.size ()});
660+ Span<Span<uint8_t >> planned_memory_span;
661+ if (!ctx.planned_spans .empty ()) {
662+ planned_memory_span =
663+ Span<Span<uint8_t >>(ctx.planned_spans .data (), ctx.planned_spans .size ());
664+ }
665+ ctx.planned_memory .reset (planned_memory_span);
655666
656667 ctx.temp_allocator .reset (temp_allocation_pool_size, temp_allocation_pool);
657668
658- MemoryManager memory_manager (
669+ ctx. memory_manager . reset (
659670 &ctx.method_allocator .value (),
660- &planned_memory,
671+ &ctx. planned_memory . value () ,
661672 &ctx.temp_allocator .value ());
662673
663674 size_t method_loaded_membase = ctx.method_allocator ->used_size ();
@@ -723,8 +734,8 @@ void runner_init(
723734#endif // defined(ET_DUMP_INTERMEDIATE_OUTPUTS) || defined(ET_DUMP_OUTPUTS)
724735#endif // defined(ET_EVENT_TRACER_ENABLED)
725736
726- ctx.method .reset (
727- program-> load_method ( ctx.method_name , &memory_manager, event_tracer_ptr));
737+ ctx.method .reset (program. load_method (
738+ ctx.method_name , &ctx. memory_manager . value () , event_tracer_ptr));
728739
729740 if (!ctx.method ->ok ()) {
730741 ET_LOG (
0 commit comments