Skip to content

Commit 8f3eb3e

Browse files
authored
Refactor Memory Allocator from Arm Executor Runner (#12353)
### Summary Some applications desire using more minimal memory allocators when leveraging the existing the exist arm_executor_runner.cpp, e.g. [here](https://github.com/BujSet/zephyr/blob/executorch-module-integration/samples/modules/executorch/arm/hello_world/src/et_memory_allocator.hpp). This change decouples a custom memory allocator wrapper from the executor runner so that apps can choose different implementations as needed. ### Test plan Ran the steps of the [Arm EthosU tutorial](https://docs.pytorch.org/executorch/main/tutorial-arm-ethos-u.html) to ensure that existing flow still works. I.e. running: ``` ./examples/arm/setup.sh --i-agree-to-the-contained-eula source ... ./examples/arm/run.sh --model_name=add --no_quantize --target=ethos-u55-128 ``` still produces the following output: ``` I [executorch:arm_executor_runner.cpp:762 main()] Model executed successfully. I [executorch:arm_executor_runner.cpp:768 main()] model_pte_program_size: 2064 bytes. I [executorch:arm_executor_runner.cpp:769 main()] model_pte_loaded_size: 2064 bytes. I [executorch:arm_executor_runner.cpp:783 main()] method_allocator_used: 320 / 62914560 free: 62914240 ( used: 0 % ) I [executorch:arm_executor_runner.cpp:790 main()] method_allocator_planned: 64 bytes I [executorch:arm_executor_runner.cpp:794 main()] method_allocator_loaded: 232 bytes I [executorch:arm_executor_runner.cpp:798 main()] method_allocator_input: 24 bytes I [executorch:arm_executor_runner.cpp:799 main()] method_allocator_executor: 0 bytes I [executorch:arm_executor_runner.cpp:802 main()] peak_temp_allocator: 64 / 2097152 free: 2097152 ( used: 0 % ) I [executorch:arm_executor_runner.cpp:812 main()] 1 outputs: Output[0][0]: (int) 2 Output[0][1]: (int) 2 Output[0][2]: (int) 2 Output[0][3]: (int) 2 Output[0][4]: (int) 2 I [executorch:arm_executor_runner.cpp:952 main()] Program complete, exiting. I [executorch:arm_executor_runner.cpp:956 main()] ♦ Info: /OSCI/SystemC: Simulation stopped by user. [warning ][main@0][3440 ns] Simulation stopped by user [backends/arm/scripts/run_fvp.sh] Simulation complete, 0 Checking for problems in log: No problems found! + set +x ```
1 parent c41c433 commit 8f3eb3e

File tree

4 files changed

+83
-53
lines changed

4 files changed

+83
-53
lines changed

examples/arm/executor_runner/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -566,7 +566,7 @@ endif()
566566
add_executable(arm_executor_runner)
567567

568568
target_sources(
569-
arm_executor_runner PRIVATE arm_executor_runner.cpp arm_perf_monitor.cpp
569+
arm_executor_runner PRIVATE arm_executor_runner.cpp arm_perf_monitor.cpp arm_memory_allocator.cpp
570570
)
571571

572572
# Include the target's bare-metal linker script

examples/arm/executor_runner/arm_executor_runner.cpp

Lines changed: 1 addition & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <memory>
2020
#include <vector>
2121

22+
#include "arm_memory_allocator.h"
2223
#include "arm_perf_monitor.h"
2324

2425
#if defined(ET_BUNDLE_IO)
@@ -288,58 +289,6 @@ class Box {
288289
}
289290
};
290291

291-
// Setup our own allocator that can show some extra stuff like used and free
292-
// memory info
293-
class ArmMemoryAllocator : public executorch::runtime::MemoryAllocator {
294-
public:
295-
ArmMemoryAllocator(uint32_t size, uint8_t* base_address)
296-
: MemoryAllocator(size, base_address), used_(0), peak_used_(0) {}
297-
298-
void* allocate(size_t size, size_t alignment = kDefaultAlignment) override {
299-
void* ret = executorch::runtime::MemoryAllocator::allocate(size, alignment);
300-
if (ret != nullptr) {
301-
// Align with the same code as in MemoryAllocator::allocate() to keep
302-
// used_ "in sync" As alignment is expected to be power of 2 (checked by
303-
// MemoryAllocator::allocate()) we can check it the lower bits
304-
// (same as alignment - 1) is zero or not.
305-
if ((size & (alignment - 1)) == 0) {
306-
// Already aligned.
307-
used_ += size;
308-
} else {
309-
used_ = (used_ | (alignment - 1)) + 1 + size;
310-
}
311-
if (used_ > peak_used_)
312-
peak_used_ = used_;
313-
}
314-
return ret;
315-
}
316-
317-
// Returns the used size of the allocator's memory buffer.
318-
size_t used_size() const {
319-
return used_;
320-
}
321-
322-
// Returns the peak memory usage of the allocator's memory buffer
323-
// Peak usage is useful when doing multiple allocations & resets
324-
size_t peak_used() const {
325-
return peak_used_;
326-
}
327-
328-
// Returns the free size of the allocator's memory buffer.
329-
size_t free_size() const {
330-
return executorch::runtime::MemoryAllocator::size() - used_;
331-
}
332-
333-
void reset() {
334-
executorch::runtime::MemoryAllocator::reset();
335-
used_ = 0;
336-
}
337-
338-
private:
339-
size_t used_;
340-
size_t peak_used_;
341-
};
342-
343292
Result<BufferCleanup> prepare_input_tensors(
344293
Method& method,
345294
MemoryAllocator& allocator,
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/* Copyright 2025 Arm Limited and/or its affiliates.
2+
*
3+
* This source code is licensed under the BSD-style license found in the
4+
* LICENSE file in the root directory of this source tree.
5+
*/
6+
7+
#include "arm_memory_allocator.h"
8+
9+
ArmMemoryAllocator::ArmMemoryAllocator(uint32_t size, uint8_t* base_address)
10+
: MemoryAllocator(size, base_address), used_(0), peak_used_(0) {}
11+
12+
void* ArmMemoryAllocator::allocate(size_t size, size_t alignment) {
13+
void* ret = executorch::runtime::MemoryAllocator::allocate(size, alignment);
14+
if (ret != nullptr) {
15+
// Align with the same code as in MemoryAllocator::allocate() to keep
16+
// used_ "in sync" As alignment is expected to be power of 2 (checked by
17+
// MemoryAllocator::allocate()) we can check it the lower bits
18+
// (same as alignment - 1) is zero or not.
19+
if ((size & (alignment - 1)) == 0) {
20+
// Already aligned.
21+
used_ += size;
22+
} else {
23+
used_ = (used_ | (alignment - 1)) + 1 + size;
24+
}
25+
if (used_ > peak_used_)
26+
peak_used_ = used_;
27+
}
28+
return ret;
29+
}
30+
31+
size_t ArmMemoryAllocator::used_size() const {
32+
return used_;
33+
}
34+
35+
size_t ArmMemoryAllocator::peak_used() const {
36+
return peak_used_;
37+
}
38+
39+
size_t ArmMemoryAllocator::free_size() const {
40+
return executorch::runtime::MemoryAllocator::size() - used_;
41+
}
42+
43+
void ArmMemoryAllocator::reset() {
44+
executorch::runtime::MemoryAllocator::reset();
45+
used_ = 0;
46+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/* Copyright 2025 Arm Limited and/or its affiliates.
2+
*
3+
* This source code is licensed under the BSD-style license found in the
4+
* LICENSE file in the root directory of this source tree.
5+
*/
6+
7+
#include <executorch/runtime/core/memory_allocator.h>
8+
9+
using executorch::runtime::MemoryAllocator;
10+
11+
#pragma once
12+
13+
// Setup our own allocator that can show some extra stuff like used and free
14+
// memory info
15+
class ArmMemoryAllocator : public executorch::runtime::MemoryAllocator {
16+
public:
17+
ArmMemoryAllocator(uint32_t size, uint8_t* base_address);
18+
19+
void* allocate(size_t size, size_t alignment = kDefaultAlignment) override;
20+
21+
// Returns the used size of the allocator's memory buffer.
22+
size_t used_size() const;
23+
24+
// Returns the peak memory usage of the allocator's memory buffer
25+
// Peak usage is useful when doing multiple allocations & resets
26+
size_t peak_used() const;
27+
28+
// Returns the free size of the allocator's memory buffer.
29+
size_t free_size() const;
30+
void reset();
31+
32+
private:
33+
size_t used_;
34+
size_t peak_used_;
35+
};

0 commit comments

Comments
 (0)