Skip to content

Commit b78ec1b

Browse files
zingofacebook-github-bot
authored andcommitted
Arm backend: Track target memory usage (pytorch#5788)
Summary: This adds memory stats API to a subclass of Memory Allocator and make it possible for the backend to track and report runtime memory usage. Pull Request resolved: pytorch#5788 Reviewed By: mergennachin Differential Revision: D63808756 Pulled By: digantdesai fbshipit-source-id: 0fbf15048957bae48fa35b40c7a82e554e6739d5
1 parent 8ac2608 commit b78ec1b

File tree

1 file changed

+91
-3
lines changed

1 file changed

+91
-3
lines changed

examples/arm/executor_runner/arm_executor_runner.cpp

Lines changed: 91 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,44 @@ void et_pal_emit_log_message(
135135

136136
namespace {
137137

138+
// Setup our own allocator that can show some extra stuff like used and free
139+
// memory info
140+
class ArmMemoryAllocator : public executorch::runtime::MemoryAllocator {
141+
public:
142+
ArmMemoryAllocator(uint32_t size, uint8_t* base_address)
143+
: MemoryAllocator(size, base_address), used_(0) {}
144+
145+
void* allocate(size_t size, size_t alignment = kDefaultAlignment) override {
146+
void* ret = executorch::runtime::MemoryAllocator::allocate(size, alignment);
147+
if (ret != nullptr) {
148+
// Align with the same code as in MemoryAllocator::allocate() to keep
149+
// used_ "in sync" As alignment is expected to be power of 2 (checked by
150+
// MemoryAllocator::allocate()) we can check it the lower bits
151+
// (same as alignment - 1) is zero or not.
152+
if ((size & (alignment - 1)) == 0) {
153+
// Already aligned.
154+
used_ += size;
155+
} else {
156+
used_ = (used_ | (alignment - 1)) + 1 + size;
157+
}
158+
}
159+
return ret;
160+
}
161+
162+
// Returns the used size of the allocator's memory buffer.
163+
size_t used_size() const {
164+
return used_;
165+
}
166+
167+
// Returns the free size of the allocator's memory buffer.
168+
size_t free_size() const {
169+
return executorch::runtime::MemoryAllocator::size() - used_;
170+
}
171+
172+
private:
173+
size_t used_;
174+
};
175+
138176
Result<BufferCleanup> prepare_input_tensors(
139177
Method& method,
140178
MemoryAllocator& allocator,
@@ -291,7 +329,7 @@ int main(int argc, const char* argv[]) {
291329

292330
#ifdef SEMIHOSTING
293331
const char* output_basename = nullptr;
294-
MemoryAllocator input_file_allocator(
332+
ArmMemoryAllocator input_file_allocator(
295333
input_file_allocation_pool_size, input_file_allocation_pool);
296334

297335
/* parse input parameters */
@@ -354,13 +392,15 @@ int main(int argc, const char* argv[]) {
354392
(unsigned int)method_meta.error());
355393
}
356394

357-
MemoryAllocator method_allocator(
395+
ArmMemoryAllocator method_allocator(
358396
method_allocation_pool_size, method_allocation_pool);
359397

360398
std::vector<uint8_t*> planned_buffers; // Owns the memory
361399
std::vector<Span<uint8_t>> planned_spans; // Passed to the allocator
362400
size_t num_memory_planned_buffers = method_meta->num_memory_planned_buffers();
363401

402+
size_t planned_buffer_membase = method_allocator.used_size();
403+
364404
for (size_t id = 0; id < num_memory_planned_buffers; ++id) {
365405
size_t buffer_size =
366406
static_cast<size_t>(method_meta->memory_planned_buffer_size(id).get());
@@ -373,15 +413,20 @@ int main(int argc, const char* argv[]) {
373413
planned_spans.push_back({planned_buffers.back(), buffer_size});
374414
}
375415

416+
size_t planned_buffer_memsize =
417+
method_allocator.used_size() - planned_buffer_membase;
418+
376419
HierarchicalAllocator planned_memory(
377420
{planned_spans.data(), planned_spans.size()});
378421

379-
MemoryAllocator temp_allocator(
422+
ArmMemoryAllocator temp_allocator(
380423
temp_allocation_pool_size, temp_allocation_pool);
381424

382425
MemoryManager memory_manager(
383426
&method_allocator, &planned_memory, &temp_allocator);
384427

428+
size_t method_loaded_membase = method_allocator.used_size();
429+
385430
Result<Method> method = program->load_method(method_name, &memory_manager);
386431
if (!method.ok()) {
387432
ET_LOG(
@@ -390,9 +435,12 @@ int main(int argc, const char* argv[]) {
390435
method_name,
391436
method.error());
392437
}
438+
size_t method_loaded_memsize =
439+
method_allocator.used_size() - method_loaded_membase;
393440
ET_LOG(Info, "Method loaded.");
394441

395442
ET_LOG(Info, "Preparing inputs...");
443+
size_t input_membase = method_allocator.used_size();
396444

397445
auto inputs =
398446
::prepare_input_tensors(*method, method_allocator, input_buffers);
@@ -404,12 +452,52 @@ int main(int argc, const char* argv[]) {
404452
method_name,
405453
inputs.error());
406454
}
455+
size_t input_memsize = method_allocator.used_size() - input_membase;
407456
ET_LOG(Info, "Input prepared.");
408457

409458
ET_LOG(Info, "Starting the model execution...");
459+
size_t executor_membase = method_allocator.used_size();
410460
StartMeasurements();
411461
Error status = method->execute();
412462
StopMeasurements();
463+
size_t executor_memsize = method_allocator.used_size() - executor_membase;
464+
465+
ET_LOG(Info, "model_pte_loaded_size: %lu bytes.", pte_size);
466+
#ifdef SEMIHOSTING
467+
if (input_file_allocator.size() > 0) {
468+
ET_LOG(
469+
Info,
470+
"input_file_allocator_used: %zu / %zu free: %zu ( used: %zu %% ) ",
471+
input_file_allocator.used_size(),
472+
input_file_allocator.size(),
473+
input_file_allocator.free_size(),
474+
100 * input_file_allocator.used_size() / input_file_allocator.size());
475+
}
476+
#endif
477+
if (method_allocator.size() != 0) {
478+
size_t method_allocator_used = method_allocator.used_size();
479+
ET_LOG(
480+
Info,
481+
"method_allocator_used: %zu / %zu free: %zu ( used: %zu %% ) ",
482+
method_allocator_used,
483+
method_allocator.size(),
484+
method_allocator.free_size(),
485+
100 * method_allocator_used / method_allocator.size());
486+
ET_LOG(
487+
Info, "method_allocator_planned: %zu bytes", planned_buffer_memsize);
488+
ET_LOG(Info, "method_allocator_loaded: %zu bytes", method_loaded_memsize);
489+
ET_LOG(Info, "method_allocator_input: %zu bytes", input_memsize);
490+
ET_LOG(Info, "method_allocator_executor: %zu bytes", executor_memsize);
491+
}
492+
if (temp_allocator.size() > 0) {
493+
ET_LOG(
494+
Info,
495+
"temp_allocator_used: %zu / %zu free: %zu ( used: %zu %% ) ",
496+
temp_allocator.used_size(),
497+
temp_allocator.size(),
498+
temp_allocator.free_size(),
499+
100 * temp_allocator.used_size() / temp_allocator.size());
500+
}
413501

414502
if (status != Error::Ok) {
415503
ET_LOG(

0 commit comments

Comments
 (0)