Skip to content

Commit 282c137

Browse files
authored
Add event tracing and ETDumps to executor_runner (#5027)
* Add event tracing and ETDumps to executor_runner - Enabled via EXECUTORCH_ENABLE_EVENT_TRACER - Add flag 'etdump_path' to specify the file path for the ETDump file - Add flag 'num_executions' for number of iterations to run - Create and pass event tracer 'ETDumpGen' - Save ETDump to disk - Update docs to reflect the changes Signed-off-by: Benjamin Klimczak <[email protected]> Change-Id: I7e8e8b7f21453bb8d88fa2b9c2ef66c532f3ea46 * Fix comments during code review - Raise a CMake error if event tracing is enabled without the devtools - Re-factoring of the changes in the portable executor_runner - Minor fix in docs Change-Id: Ia50fef8172f678f9cbe2b33e2178780ff983f335 Signed-off-by: Benjamin Klimczak <[email protected]> * Small fix for use of flag `FLAGS_etdump` Change-Id: I0ebb22636cdd64aea24bcee51cba05496ed78b1f * Another fix for case ET_EVENT_TRACER_ENABLED=OFF Change-Id: I7d72e4d8f46ec727a60c9553851d5b71da8e91d4 Signed-off-by: Benjamin Klimczak <[email protected]> * Revert use of FLATCCRT_LIB to flatccrt Signed-off-by: Benjamin Klimczak <[email protected]> Change-Id: I5e7d8ef5d66bc3d5de36ea451b31fb3bdcd42d09 * Fix linker issue when building executor_runner - Remove explicit addition of `-DET_EVENT_TRACER_ENABLED` from backends/qualcomm/CMakeLists.txt as setting the definition without enabling cmake flag `EXECUTORCH_ENABLE_EVENT_TRACER` caused issues when building the executor_runner. - Replace deprecated namespace `torch::executor` with `executorch::etdump` in the executor_runner.cpp. Signed-off-by: Benjamin Klimczak <[email protected]> Change-Id: Iadff38374e661f42e394dc69903548922ca08aea --------- Signed-off-by: Benjamin Klimczak <[email protected]>
1 parent c857cc3 commit 282c137

File tree

6 files changed

+108
-17
lines changed

6 files changed

+108
-17
lines changed

CMakeLists.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# Copyright (c) Meta Platforms, Inc. and affiliates.
2+
# Copyright 2024-2025 Arm Limited and/or its affiliates.
23
# All rights reserved.
34
#
45
# This source code is licensed under the BSD-style license found in the
@@ -819,6 +820,14 @@ if(EXECUTORCH_BUILD_EXECUTOR_RUNNER)
819820
list(APPEND _executor_runner_libs quantized_ops_lib)
820821
endif()
821822

823+
if(EXECUTORCH_ENABLE_EVENT_TRACER)
824+
if(EXECUTORCH_BUILD_DEVTOOLS)
825+
list(APPEND _executor_runner_libs etdump flatccrt)
826+
else()
827+
message(SEND_ERROR "Use of 'EXECUTORCH_ENABLE_EVENT_TRACER' requires 'EXECUTORCH_BUILD_DEVTOOLS' to be enabled.")
828+
endif()
829+
endif()
830+
822831
add_executable(executor_runner ${_executor_runner__srcs})
823832
if(CMAKE_BUILD_TYPE STREQUAL "Release")
824833
if(APPLE)

backends/qualcomm/CMakeLists.txt

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# Copyright (c) Qualcomm Innovation Center, Inc.
2+
# Copyright 2025 Arm Limited and/or its affiliates.
23
# All rights reserved
34
#
45
# This source code is licensed under the BSD-style license found in the
@@ -199,11 +200,6 @@ target_link_libraries(
199200
#
200201
target_link_options_shared_lib(qnn_executorch_backend)
201202

202-
#
203-
# add compile option
204-
#
205-
target_compile_options(executorch PUBLIC -DET_EVENT_TRACER_ENABLED)
206-
207203
#
208204
# add sources
209205
#

backends/xnnpack/CMakeLists.txt

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# Copyright (c) Meta Platforms, Inc. and affiliates.
2+
# Copyright 2024-2025 Arm Limited and/or its affiliates.
23
# All rights reserved.
34
#
45
# This source code is licensed under the BSD-style license found in the
@@ -128,8 +129,17 @@ if(NOT CMAKE_TOOLCHAIN_FILE MATCHES ".*(iOS|ios\.toolchain)\.cmake$")
128129
#
129130
list(TRANSFORM _xnn_executor_runner__srcs PREPEND "${EXECUTORCH_ROOT}/")
130131
add_executable(xnn_executor_runner ${_xnn_executor_runner__srcs})
132+
133+
if(EXECUTORCH_ENABLE_EVENT_TRACER)
134+
if(EXECUTORCH_BUILD_DEVTOOLS)
135+
list(APPEND xnn_executor_runner_libs etdump)
136+
else()
137+
message(SEND_ERROR "Use of 'EXECUTORCH_ENABLE_EVENT_TRACER' requires 'EXECUTORCH_BUILD_DEVTOOLS' to be enabled.")
138+
endif()
139+
endif()
140+
131141
target_link_libraries(
132-
xnn_executor_runner xnnpack_backend gflags portable_ops_lib
142+
xnn_executor_runner gflags portable_ops_lib ${xnn_executor_runner_libs}
133143
)
134144
target_compile_options(xnn_executor_runner PUBLIC ${_common_compile_options})
135145
endif()

docs/source/native-delegates-executorch-xnnpack-delegate.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ Since weight packing creates an extra copy of the weights inside XNNPACK, We fre
7070
When executing the XNNPACK subgraphs, we prepare the tensor inputs and outputs and feed them to the XNNPACK runtime graph. After executing the runtime graph, the output pointers are filled with the computed tensors.
7171

7272
#### **Profiling**
73-
We have enabled basic profiling for XNNPACK delegate that can be enabled with the following compiler flag `-DENABLE_XNNPACK_PROFILING`. With ExecuTorch's Developer Tools integration, you can also now use the Developer Tools to profile the model. You can follow the steps in [Using the ExecuTorch Developer Tools to Profile a Model](./tutorials/devtools-integration-tutorial) on how to profile ExecuTorch models and use Developer Tools' Inspector API to view XNNPACK's internal profiling information.
73+
We have enabled basic profiling for the XNNPACK delegate that can be enabled with the compiler flag `-DEXECUTORCH_ENABLE_EVENT_TRACER` (add `-DENABLE_XNNPACK_PROFILING` for additional details). With ExecuTorch's Developer Tools integration, you can also now use the Developer Tools to profile the model. You can follow the steps in [Using the ExecuTorch Developer Tools to Profile a Model](./tutorials/devtools-integration-tutorial) on how to profile ExecuTorch models and use Developer Tools' Inspector API to view XNNPACK's internal profiling information. An example implementation is available in the `xnn_executor_runner` (see [tutorial here](tutorial-xnnpack-delegate-lowering.md#profiling)).
7474

7575

7676
[comment]: <> (TODO: Refactor quantizer to a more official quantization doc)

docs/source/tutorial-xnnpack-delegate-lowering.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,3 +177,6 @@ Now you should be able to find the executable built at `./cmake-out/backends/xnn
177177

178178
## Building and Linking with the XNNPACK Backend
179179
You can build the XNNPACK backend [CMake target](https://github.com/pytorch/executorch/blob/main/backends/xnnpack/CMakeLists.txt#L83), and link it with your application binary such as an Android or iOS application. For more information on this you may take a look at this [resource](demo-apps-android.md) next.
180+
181+
## Profiling
182+
To enable profiling in the `xnn_executor_runner` pass the flags `-DEXECUTORCH_ENABLE_EVENT_TRACER=ON` and `-DEXECUTORCH_BUILD_DEVTOOLS=ON` to the build command (add `-DENABLE_XNNPACK_PROFILING=ON` for additional details). This will enable ETDump generation when running the inference and enables command line flags for profiling (see `xnn_executor_runner --help` for details).

examples/portable/executor_runner/executor_runner.cpp

Lines changed: 83 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/*
22
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
* Copyright 2024-2025 Arm Limited and/or its affiliates.
34
* All rights reserved.
45
*
56
* This source code is licensed under the BSD-style license found in the
@@ -25,10 +26,14 @@
2526
#include <executorch/extension/data_loader/file_data_loader.h>
2627
#include <executorch/extension/evalue_util/print_evalue.h>
2728
#include <executorch/extension/runner_util/inputs.h>
29+
#include <executorch/runtime/core/event_tracer.h>
2830
#include <executorch/runtime/executor/method.h>
2931
#include <executorch/runtime/executor/program.h>
3032
#include <executorch/runtime/platform/log.h>
3133
#include <executorch/runtime/platform/runtime.h>
34+
#ifdef ET_EVENT_TRACER_ENABLED
35+
#include <executorch/devtools/etdump/etdump_flatcc.h>
36+
#endif // ET_EVENT_TRACER_ENABLED
3237

3338
static uint8_t method_allocator_pool[4 * 1024U * 1024U]; // 4 MB
3439

@@ -38,10 +43,15 @@ DEFINE_string(
3843
model_path,
3944
"model.pte",
4045
"Model serialized in flatbuffer format.");
46+
DEFINE_uint32(num_executions, 1, "Number of times to run the model.");
47+
#ifdef ET_EVENT_TRACER_ENABLED
48+
DEFINE_string(etdump_path, "model.etdump", "Write ETDump data to this path.");
49+
#endif // ET_EVENT_TRACER_ENABLED
4150

4251
using executorch::extension::FileDataLoader;
4352
using executorch::runtime::Error;
4453
using executorch::runtime::EValue;
54+
using executorch::runtime::EventTracer;
4555
using executorch::runtime::HierarchicalAllocator;
4656
using executorch::runtime::MemoryAllocator;
4757
using executorch::runtime::MemoryManager;
@@ -51,6 +61,56 @@ using executorch::runtime::Program;
5161
using executorch::runtime::Result;
5262
using executorch::runtime::Span;
5363

64+
/// Helper to manage resources for ETDump generation
65+
class EventTraceManager {
66+
public:
67+
EventTraceManager() : event_tracer_ptr_(nullptr) {
68+
#ifdef ET_EVENT_TRACER_ENABLED
69+
event_tracer_ptr_ = std::make_shared<executorch::etdump::ETDumpGen>();
70+
#endif // ET_EVENT_TRACER_ENABLED
71+
}
72+
73+
EventTracer* get_event_tracer() const {
74+
return event_tracer_ptr_.get();
75+
};
76+
77+
Error write_etdump_to_file() const {
78+
EventTracer* const event_tracer_ptr = get_event_tracer();
79+
if (!event_tracer_ptr) {
80+
return Error::NotSupported;
81+
}
82+
83+
#ifdef ET_EVENT_TRACER_ENABLED
84+
executorch::etdump::ETDumpGen* const etdump_ptr =
85+
static_cast<executorch::etdump::ETDumpGen*>(event_tracer_ptr);
86+
87+
const char* filename = FLAGS_etdump_path.c_str();
88+
89+
std::unique_ptr<FILE, decltype(&fclose)> etdump_file(
90+
fopen(filename, "w+"), fclose);
91+
if (!etdump_file) {
92+
ET_LOG(Error, "Failed to open ETDump file at %s.", filename);
93+
return Error::AccessFailed;
94+
}
95+
96+
executorch::etdump::ETDumpResult result = etdump_ptr->get_etdump_data();
97+
if (result.buf != nullptr && result.size > 0) {
98+
fwrite((uint8_t*)result.buf, 1, result.size, etdump_file.get());
99+
free(result.buf);
100+
ET_LOG(Info, "ETDump written to file '%s'.", filename);
101+
} else {
102+
ET_LOG(Error, "No ETDump data available!");
103+
return Error::NotFound;
104+
}
105+
#endif // ET_EVENT_TRACER_ENABLED
106+
107+
return Error::Ok;
108+
}
109+
110+
private:
111+
std::shared_ptr<EventTracer> event_tracer_ptr_;
112+
};
113+
54114
int main(int argc, char** argv) {
55115
executorch::runtime::runtime_init();
56116

@@ -158,8 +218,9 @@ int main(int argc, char** argv) {
158218
// the method can mutate the memory-planned buffers, so the method should only
159219
// be used by a single thread at at time, but it can be reused.
160220
//
161-
162-
Result<Method> method = program->load_method(method_name, &memory_manager);
221+
EventTraceManager tracer;
222+
Result<Method> method = program->load_method(
223+
method_name, &memory_manager, tracer.get_event_tracer());
163224
ET_CHECK_MSG(
164225
method.ok(),
165226
"Loading of method %s failed with status 0x%" PRIx32,
@@ -178,24 +239,36 @@ int main(int argc, char** argv) {
178239
ET_LOG(Info, "Inputs prepared.");
179240

180241
// Run the model.
181-
Error status = method->execute();
182-
ET_CHECK_MSG(
183-
status == Error::Ok,
184-
"Execution of method %s failed with status 0x%" PRIx32,
185-
method_name,
186-
(uint32_t)status);
187-
ET_LOG(Info, "Model executed successfully.");
242+
for (uint32_t i = 0; i < FLAGS_num_executions; i++) {
243+
Error status = method->execute();
244+
ET_CHECK_MSG(
245+
status == Error::Ok,
246+
"Execution of method %s failed with status 0x%" PRIx32,
247+
method_name,
248+
(uint32_t)status);
249+
}
250+
ET_LOG(
251+
Info,
252+
"Model executed successfully %" PRIu32 " time(s).",
253+
FLAGS_num_executions);
188254

189255
// Print the outputs.
190256
std::vector<EValue> outputs(method->outputs_size());
191257
ET_LOG(Info, "%zu outputs: ", outputs.size());
192-
status = method->get_outputs(outputs.data(), outputs.size());
258+
Error status = method->get_outputs(outputs.data(), outputs.size());
193259
ET_CHECK(status == Error::Ok);
194260
// Print the first and last 100 elements of long lists of scalars.
195261
std::cout << executorch::extension::evalue_edge_items(100);
196262
for (int i = 0; i < outputs.size(); ++i) {
197263
std::cout << "Output " << i << ": " << outputs[i] << std::endl;
198264
}
199265

266+
if (tracer.get_event_tracer()) {
267+
// Dump ETDump data containing profiling/debugging data to file specified in
268+
// command line flag.
269+
Error status = tracer.write_etdump_to_file();
270+
ET_CHECK_MSG(status == Error::Ok, "Failed to save ETDump file.");
271+
}
272+
200273
return 0;
201274
}

0 commit comments

Comments
 (0)