委托调试¶
委托后端是设备端模型的一个重要组成部分,因为它们在定义行为方面具有灵活性。这种灵活性的副作用是它作为不透明的转换运行。这会混淆在后处理中有价值的丰富关联和突变。
例如,如果一个委托中发生两个不同的运算符融合,则后处理将无法分离这两个转换。
具体来说,它使得通过委托图关联运行时信息(例如性能分析结果)变得困难。委托调试标识符提供了一个框架,委托作者可以通过该框架传播此信息并将其用于运行后分析。
准备工作分为三个阶段:
提前 (AOT):委托作者生成调试句柄映射。
运行时:委托作者使用在 Debug Handle Map 中注册的 Delegate Debug Identifiers 注册的 AOT 进行记录。
反序列化:委托作者为委托事件中的自定义元数据提供解析器。
提前集成¶
委托作者通过从后端实现返回 Debug Handle Map 来传播在降低的后端中发生的转换。
生成调试句柄映射¶
调试句柄映射通过将 Delegate Debug Identifiers 映射到调试句柄来传达后端中发生的转换。
委托调试标识符是生成的或用户提供的标识符,用于在运行时表示目标点。回想一下,调试句柄是模型图中运算符实例的唯一标识符。
例如:
{ 0: (10, 11), 1: (11, 12) }:运行时中的标识符 0 和 1 分别对应于具有调试句柄 (10, 11) 和 (11, 12) 的运算符。
{ “fused_op_1_2_3”: (11, 12, 15) }: 运行时标识符 “fused_op_1_2_3” 对应带有调试句柄 (11, 12, 15) 的算子,11, 12, 15 对应操作 1、操作 2 和操作 3。
注意
标识符是将运行时结果连接到模型图的一种方式;标识符的解释由委托作者定义。
调试句柄映射是使用 DelegateMappingBuilder 构建的,并作为 的一部分返回。PreprocessResult
class PreprocessResult:
processed_bytes: bytes = bytes()
debug_handle_map: Optional[
Union[Dict[int, Tuple[int]], Dict[str, Tuple[int]]]
] = None
DelegateMappingBuilder (代理映射生成器)¶
DelegateMappingBuilder
是用于管理和构造调试句柄映射的帮助程序类。在构造 PreprocessResult 时,应传入构建器的结果。
DelegateMappingBuilder
定义如下
实例可以采用以下两种模式之一构建:手动标识符或生成的标识符。DelegateMappingBuilder
# Manual Identifiers, Default
builder = DelegateMappingBuilder(generated_identifiers=False)
# Generated Identifiers
builder = DelegateMappingBuilder(generated_identifiers=True)
使用手动标识符时,用户可以在创建条目时传入 Delegate Debug Identifier。 使用生成的标识符,构建器将自动分配一个 Delegate Debug Identifier。
要向 Debug Handle Map 添加条目,请使用 .它将其中一个或调试句柄(源自 node.meta[“debug_handle”])与可选的委托调试标识符(用于手动标识符)相关联。记录的标识符是从调用中返回的。insert_delegate_mapping_entry
fx.Node(s)
def insert_delegate_mapping_entry(
self,
nodes: Optional[Union[Node, List[Node]]] = None,
handles: Optional[Union[int, List[int]]] = None,
identifier: Optional[Union[int, str]] = None,
) -> Union[int, str]:
要检索调试句柄映射,请使用 .get_delegate_mapping
def get_delegate_mapping(
self,
) -> Union[Dict[int, Tuple[int]], Dict[str, Tuple[int]]]
可在此处找到 AOT 映射的演示
运行时日志记录¶
然后,运行时与 AOT 映射相对应,定义记录这些事件的功能。
实时日志记录¶
ExecuTorch 允许您实时登录。当执行时时间戳可用时,实时日志记录非常有用。它提供的开销最小,并且作者可以直观地调用。
实时记录事件(例如,显式表示性能分析的开始和停止),用于创建 ,并用于结束所提供的 .event_tracer_start_profiling_delegate
EventEntry
event_tracer_end_profiling_delegate
EventEntry
EventTracer
要开始使用 ,委托调试标识符(提供给 的 AOT )将作为名称或参数传递,具体取决于委托调试标识符类型(分别为 str 和 int)EventTracerEntry
event_tracer_start_profiling_delegate
debug_handle_map
delegate_debug_id
EventTracerEntry event_tracer_start_profiling_delegate(
EventTracer* event_tracer,
const char* name,
DebugHandle delegate_debug_id)
要得出结论,只需提供原始 .EventTracerEntry
event_tracer_end_profiling_delegate
EventTracerEntry
(可选)此时还可以记录其他运行时。metadata
void event_tracer_end_profiling_delegate(
EventTracer* event_tracer,
EventTracerEntry event_tracer_entry,
const void* metadata = nullptr,
size_t metadata_len = 0)
后时间记录¶
ExecuTorch 还允许您登录 post time。某些运行时设置在执行时无法访问时间戳。Post-Time Logging 使作者仍能够记录这些事件。
要在 post 中记录事件(例如,同时记录开始和结束时间),请使用实时日志记录 API 和时间戳中使用的参数的组合来调用。event_tracer_log_profiling_delegate
void event_tracer_log_profiling_delegate(
EventTracer* event_tracer,
const char* name,
DebugHandle delegate_debug_id,
et_timestamp_t start_time,
et_timestamp_t end_time,
const void* metadata = nullptr,
size_t metadata_len = 0)
可在此处找到运行时代码的演示。
显示委托事件中的自定义元数据¶
如上面的运行时日志记录 API 所示,用户可以记录字节数组及其委托分析事件。我们通过 Inspector API 在后处理中向用户提供这些数据。
用户可以在创建 Inspector 实例时传递元数据解析器。解析器是一个可调用对象,它反序列化数据并返回字符串列表或包含键值对的字典。然后,将反序列化的数据添加回事件块中的相应事件,供用户使用。下面是如何编写此解析器的示例:
注意: 反序列化器的 input 是一个列表,其中每个条目都是一系列字节(本质上每个条目都是一个不可变的 bytearray)。用户需要迭代此列表,反序列化每个条目,然后以预期的格式返回它,即字符串列表或字典。
Inspector(
etdump_path=etdump_path,
# Optional
etrecord=etrecord_path,
# Optional, only needed if debugging was enabled.
buffer_path=buffer_path,
delegate_metadata_parser=parse_delegate_metadata
)
def parse_delegate_metadata(delegate_metadatas: List[bytes]) -> Union[List[str], Dict[str, Any]]:
metadata_str = []
for metadata_bytes in delegate_metadatas:
metadata_str += str(metadata_bytes)
return metadata_str