委派偵錯¶
委派後端由於其定義行為的靈活性,是裝置端模型的重要組件。這種靈活性的副作用是它作為不透明的轉換運作。這模糊了豐富的關聯和突變,這些關聯和突變在後處理中非常重要。
例如,如果兩個不同的運算子融合發生在委派中,後處理將無法分離這兩個轉換。
具體來說,它使得透過委派圖關聯運行時資訊(例如效能分析結果)變得困難。委派偵錯識別碼提供了一個框架,委派作者可以透過該框架傳播此資訊並將其用於運行後分析。
準備工作分為三個階段
預先 (AOT):委派作者產生偵錯控制代碼對應。
執行階段 (Runtime):委派作者使用註冊於 Debug Handle Map (偵錯控制碼映射表) 中且 AOT (Ahead-of-Time,預先) 註冊的 Delegate Debug Identifiers (委派偵錯識別符) 進行記錄。
反序列化 (Deserialization):委派作者為委派事件中的自訂元資料 (metadata) 提供剖析器 (parser)。
預先 (Ahead-of-Time) 整合¶
委派作者透過從後端實作傳回一個 Debug Handle Map (偵錯控制碼映射表),來傳播在降級的後端中發生的轉換。
產生偵錯控制碼映射表 (Debug Handle Map)¶
Debug Handle Maps (偵錯控制碼映射表) 透過將 Delegate Debug Identifiers (委派偵錯識別符) 映射到偵錯控制碼 (debug handles),來傳達在後端中發生的轉換。
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。
注意
識別符是用於將執行階段結果連接到模型圖的手段;識別符的解釋由委派作者定義。
Debug Handle Maps (偵錯控制碼映射表) 是透過使用 DelegateMappingBuilder 建構的,並作為 PreprocessResult
的一部分傳回。
class PreprocessResult:
processed_bytes: bytes = bytes()
debug_handle_map: Optional[
Union[Dict[int, Tuple[int]], Dict[str, Tuple[int]]]
] = None
PreprocessResult 的定義 在此。
DelegateMappingBuilder¶
DelegateMappingBuilder
是一個用於管理和建構 Debug Handle Maps 的輔助類別。建構 PreprocessResult 時,應傳入建構器的結果。
DelegateMappingBuilder
的定義 在此。
可以透過 2 種模式之一建構 DelegateMappingBuilder
實例:手動識別符或產生的識別符。
# Manual Identifiers, Default
builder = DelegateMappingBuilder(generated_identifiers=False)
# Generated Identifiers
builder = DelegateMappingBuilder(generated_identifiers=True)
使用手動識別符 (manual identifiers) 時,使用者在建立條目時傳入一個 Delegate Debug Identifier (委派偵錯識別符)。使用產生的識別符 (generated identifiers) 時,建構器將自動指派一個 Delegate Debug Identifier (委派偵錯識別符)。
要將條目新增到 Debug Handle Map (偵錯控制碼映射表),請使用 insert_delegate_mapping_entry
。 它將 fx.Node(s)
或偵錯控制碼 (debug handles) (來源於 node.meta[“debug_handle”]) 之一,與可選的 Delegate Debug Identifier (委派偵錯識別符) (用於手動識別符) 相關聯。 記錄的識別符會從呼叫中傳回。
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]:
要檢索 Debug Handle Map (偵錯控制碼映射表),請使用 get_delegate_mapping
。
def get_delegate_mapping(
self,
) -> Union[Dict[int, Tuple[int]], Dict[str, Tuple[int]]]
可以在 此處 找到 AOT 映射的演示。
執行階段記錄 (Runtime Logging)¶
與 AOT 映射對應,執行階段接著定義透過其記錄這些事件的功能。
即時記錄 (Real-Time Logging)¶
ExecuTorch 允許您即時記錄。 當時間戳記在執行發生時可用時,即時記錄 (Real time Logging) 非常有用。 它提供的額外負擔 (overhead) 最小,並且對作者來說調用起來很直觀。
要即時記錄事件 (例如,明確表示分析開始和停止),使用 event_tracer_start_profiling_delegate
來建立 EventEntry
,並使用 event_tracer_end_profiling_delegate
來結束提供的 EventTracer
的 EventEntry
。
要使用 event_tracer_start_profiling_delegate
啟動 EventTracerEntry
,Delegate Debug Identifier (委派偵錯識別符) (AOT 提供給 debug_handle_map
) 會作為名稱或 delegate_debug_id
引數傳遞,具體取決於 Delegate Debug Identifier (委派偵錯識別符) 的類型 (分別為字串和整數)。
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)
事後記錄 (Post-Time Logging)¶
ExecuTorch 也允許您事後記錄。 一些執行階段設定在執行時無法存取時間戳記。 事後記錄 (Post-Time Logging) 使作者仍然能夠記錄這些事件。
要在事後記錄事件 (例如,同時記錄開始和結束時間),請使用即時記錄 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)
可以在 此處 找到執行階段程式碼的演示。
從委派事件中浮現自訂元資料 (metadata)¶
如上述執行階段記錄 API 中所見,使用者可以記錄一個位元組陣列以及他們的委派分析事件。 我們透過 Inspector API (檢測器 API) 在後處理中為使用者提供此資料。
使用者可以在建立 Inspector 實例時傳遞元資料剖析器。 剖析器是一個可呼叫物件,它會反序列化資料並傳回字串清單或包含鍵值對的字典。 然後,反序列化的資料會新增回事件區塊中的相應事件,以供使用者使用。 以下是如何編寫此剖析器的範例
注意:反序列化器的輸入是一個清單,其中每個條目都是一系列位元組 (本質上每個條目都是一個不可變的位元組陣列)。 使用者應迭代此清單,反序列化每個條目,然後以預期的格式 (字串清單或字典) 傳回它。
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