ETRecord is intended to be the debug artifact that is generated by
users ahead of time (when they export their model to run on ExecuTorch).
To draw a rough equivalent to conventional software development,
ETRecord can be considered as the binary built with debug symbols
that is used for debugging in GNU Debugger (gdb). It is expected that
the user will supply this to the ExecuTorch Developer Tools in order for
them to debug and visualize their model.
ETRecord contains numerous components such as:
- Edge dialect graph with debug handles
- Delegate debug handle maps
The ETRecord object itself is intended to be opaque to users and they should not access any components inside it directly.
It should be provided to the Inspector API to link back performance and debug data sourced from the runtime back to the Python source code.
There are multiple ways to generate an ETRecord for debugging purposes:
The recommended approach is to enable ETRecord generation by passing generate_etrecord=True
to your export API calls. This can be used with:
executorch.export()- High-level export APIto_edge()- Edge dialect conversionto_edge_transform_and_lower()- Edge conversion with transformations and lowering
After export completes, retrieve the ETRecord using the get_etrecord() method, and save it using the save() method:
Example withexecutorch.export():
importexecutorchfromexecutorch.exportimportExportRecipe# Export with ETRecord generation enabledsession=executorch.export(
model=model,
example_inputs=[example_inputs],
export_recipe=recipe,
generate_etrecord=True# Enable ETRecord generation
)
# Get and save the ETRecordetrecord=session.get_etrecord()
etrecord.save("model_debug.etrecord")Example withto_edge():
fromexecutorch.exir.programimportto_edgefromtorch.exportimportexport# Export model firstexported_program=export(model, example_inputs)
# Convert to edge with ETRecord generationedge_manager=to_edge(
exported_program,
generate_etrecord=True# Enable ETRecord generation
)
# Apply transformationsedge_manager=edge_manager.to_backend()
et_manager=edge_manager.to_executorch()
# Get and save ETRecordetrecord=et_manager.get_etrecord()
etrecord.save("edge_debug.etrecord")Example withto_edge_transform_and_lower():
fromexecutorch.exir.programimportto_edge_transform_and_lowerfromtorch.exportimportexport# Export model firstexported_program=export(model, example_inputs)
# Transform and lower with ETRecord generationedge_manager=to_edge_transform_and_lower(
exported_program,
partitioner=[MyPartitioner()],
generate_etrecord=True# Enable ETRecord generation
)
et_manager=edge_manager.to_executorch()
# Get and save ETRecordetrecord=et_manager.get_etrecord()
etrecord.save("debug.etrecord")You can also use the standalone generate_etrecord() function to generate an ETRecord.
This method requires you to provide the Edge Dialect program (returned by to_edge()),
the ExecuTorch program (returned by to_executorch()), and optional models.
Warning
When using the standalone function, users should do a deepcopy of the output of to_edge() and pass in the deepcopy to the generate_etrecord API. This is needed because the subsequent call, to_executorch(), does an in-place mutation and will lose debug data in the process.
Example:
importcopyfromexecutorch.devtoolsimportgenerate_etrecordfromtorch.exportimportexport# Export and convert to edgeaten_dialect=export(model, example_inputs, strict=True)
edge_program=to_edge(aten_dialect)
# Create copy for ETRecord (needed because to_executorch modifies in-place)edge_program_copy=copy.deepcopy(edge_program)
# Convert to ExecutorchProgramManagerexecutorch_program=edge_program_copy.to_executorch()
# Generate ETRecord separatelygenerate_etrecord(
"debug.etrecord",
edge_program,
executorch_program,
).. currentmodule:: executorch.devtools.etrecord._etrecord
.. autofunction:: generate_etrecord
Pass the ETRecord as an optional argument into the Inspector API to access this data and do post-run analysis.