委託除錯¶
委託後端 是裝置端模型的重要組成部分,因為它們在定義行為方面具有靈活性。這種靈活性的一個副作用是它作為一種不透明的轉換操作。這會模糊在後處理中很有價值的豐富關聯和變異。
例如,如果在委託中發生兩種不同的運算元融合,後處理將無法區分這兩種轉換。
具體來說,這使得透過委託圖關聯執行時資訊(如效能分析結果)變得困難。委託除錯識別符號提供了一個框架,委託作者可以透過它傳播此資訊並將其用於執行後分析。
準備工作分為三個階段
提前 (AOT):委託作者生成一個 **除錯控制代碼對映**。
執行時:委託作者使用在 **除錯控制代碼對映** 中提前註冊的 **委託除錯識別符號** 進行日誌記錄。
反序列化:委託作者為委託事件中的自定義元資料提供解析器。
提前整合¶
委託作者透過從後端實現返回 **除錯控制代碼對映** 來傳播在 Lowered 後端中發生的轉換。
生成除錯控制代碼對映¶
**除錯控制代碼對映** 透過將 **委託除錯識別符號** 對映到除錯控制代碼來傳達後端中發生的轉換。
**委託除錯識別符號** 是生成或使用者提供的識別符號,用於表示執行時感興趣的點。回想一下,除錯控制代碼是模型圖中運算元例項的唯一識別符號。
例如
{ 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
PreprocessResult 在 此處 定義。
DelegateMappingBuilder¶
DelegateMappingBuilder 是一個用於管理和構建除錯控制代碼對映的輔助類。構建器的結果應在構建 PreprocessResult 時傳入。
DelegateMappingBuilder 在 此處 定義。
一個 DelegateMappingBuilder 例項可以按以下兩種模式之一構建:手動識別符號或生成識別符號。
# Manual Identifiers, Default
builder = DelegateMappingBuilder(generated_identifiers=False)
# Generated Identifiers
builder = DelegateMappingBuilder(generated_identifiers=True)
對於**手動識別符號**,使用者在建立條目時傳入一個**委託除錯識別符號**。對於**生成識別符號**,構建器將自動分配一個**委託除錯識別符號**。
要將條目新增到**除錯控制代碼對映**,請使用 insert_delegate_mapping_entry。它將一個或多個 fx.Node(s) 或除錯控制代碼(源自 node.meta["debug_handle"])關聯到一個可選的**委託除錯識別符號**(用於手動識別符號)。呼叫會返回記錄的識別符號。
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 允許您進行即時日誌記錄。**即時日誌記錄**在執行過程中 timestamp 可用時非常有用。它開銷最小,且作者呼叫起來很直觀。
要即時記錄事件(例如,明確表示效能分析的開始和停止),使用 event_tracer_start_profiling_delegate 建立一個 EventEntry,並使用 event_tracer_end_profiling_delegate 結束為提供的 EventTracer 建立的 EventEntry。
要使用 event_tracer_start_profiling_delegate 啟動一個 EventTracerEntry,根據**委託除錯識別符號**的型別(分別為 str 和 int),將**委託除錯識別符號**(提前提供給 debug_handle_map)作為 name 或 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 也允許您進行事後日誌記錄。有些執行時設定在執行時無法訪問 timestamp。**事後日誌記錄**使作者仍然能夠記錄這些事件。
要事後記錄事件(例如,同時記錄開始時間和結束時間),呼叫 event_tracer_log_profiling_delegate,並結合即時日誌記錄 API 中使用的引數和 timestamp。
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 例項時可以傳遞一個元資料解析器。解析器是一個可呼叫物件,用於反序列化資料並返回字串列表或包含鍵值對的字典。反序列化後的資料隨後會新增到事件塊中的相應事件中,供使用者使用。以下是如何編寫此解析器的示例:
注意:反序列化器的輸入是一個列表,其中每個條目是一個位元組序列(本質上每個條目都是一個不可變的位元組陣列)。使用者應遍歷此列表,反序列化每個條目,然後以預期的格式(字串列表或字典)返回。
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