• 文件 >
  • 行動式 C++ 程式設計
快捷方式

行動式 C++ 程式設計

注意:本文件涵蓋了需要在目標硬體環境中構建和執行的程式碼。這適用於核心執行執行時以及此倉庫中的核心和後端實現。這些規則不一定適用於僅在開發主機上執行的程式碼,例如創作或構建工具。

ExecuTorch 執行時程式碼旨在實現可移植性,應能在各種系統上構建,從伺服器到行動電話再到 DSP,從 POSIX 到 Windows 再到裸機環境。

這意味著它不能假定存在以下內容:

  • 檔案

  • 執行緒

  • 異常

  • stdout, stderr

  • printf(), fprintf()

  • 一般的 POSIX API 和概念

它也不能假定

  • 64 位指標

  • 給定整數型別的大小

  • char 的有無符號性

為了使二進位制檔案大小最小化,並嚴格控制記憶體分配,程式碼不得使用

  • malloc(), free()

  • new, delete

  • 大多數 stdlibc++ 型別;特別是那些管理自身記憶體的容器型別,如 stringvector,或者記憶體管理包裝型別,如 unique_ptrshared_ptr

為了幫助降低複雜性,程式碼不得依賴於任何外部依賴項,除了

  • flatbuffers(用於 .pte 檔案反序列化)

  • flatcc(用於事件跟蹤序列化)

  • Core PyTorch(僅用於 ATen 模式)

平臺抽象層 (PAL)

為了避免假定目標系統的能力,ExecuTorch 執行時允許客戶端在其平臺抽象層 (PAL) 中覆蓋低階函式,PAL 定義在 //executorch/runtime/platform/platform.h 中,用於執行以下操作:

  • 獲取當前時間戳

  • 列印日誌訊息

  • 使系統崩潰

記憶體分配

執行時程式碼應使用客戶端提供的 MemoryManager//executorch/runtime/executor/memory_manager.h)來分配記憶體,而不是使用 malloc()new

檔案載入

客戶端不應直接載入檔案,而應提供已載入資料的緩衝區,或封裝在如 DataLoader 這樣的型別中。

整數型別

ExecuTorch 執行時程式碼不應假定基本型別(如 int, shortchar)的任何大小。例如,C++ 標準只保證 int 至少有 16 位寬。ARM 工具鏈將 char 視為無符號型別,而其他工具鏈通常將其視為有符號型別。

相反,執行時 API 使用一組更可預測但仍然標準的整數型別

  • <cstdint> 型別,如 uint64_t, int32_t`;這些型別保證了位寬和有無符號性,與架構無關。當你需要非常特定的整數寬度時使用這些型別。

  • size_t 用於計數或記憶體偏移量。size_t 保證足夠大,可以表示任何記憶體位元組偏移量;也就是說,它的寬度將與目標系統的原生指標型別相同。對於計數/偏移量,優先使用它而不是 uint64_t,這樣 32 位系統就不需要為 64 位值的額外開銷付費。

  • 在某些 ATen 相容場景下,Tensor 返回有符號計數時使用 ssize_t。儘可能優先使用 size_t

浮點算術

並非所有系統都支援浮點算術:有些甚至不在其工具鏈中啟用浮點模擬。因此,核心執行時程式碼在執行時不得執行任何浮點算術,儘管可以簡單地建立或管理 floatdouble 值(例如,在 EValue 中)。

核心,作為核心執行時之外的部分,允許執行浮點算術。儘管有些核心可能會選擇不這樣做,以便它們可以在不支援浮點運算的系統上執行。

日誌記錄

ExecuTorch 執行時提供了 //executorch/runtime/platform/log.h 中的 ET_LOG 介面和 //executorch/runtime/platform/assert.h 中的 ET_CHECK 介面,而不是使用 printf(), fprintf(), cout, cerr,或像 folly::loggingglog 這樣的庫。訊息使用 PAL 中的一個鉤子列印,這意味著客戶端可以將它們重定向到任何底層日誌系統,或者如果可用,直接列印到 stderr

日誌格式可移植性

定寬整數

當你有一個日誌語句,例如

int64_t value;
ET_LOG(Error, "Value %??? is bad", value);

對於 %??? 部分,應該填寫什麼來匹配 int64_t?在不同的系統上,int64_t 的 typedef 可能是 int`, `long intlong long int。選擇像 %d`, `%ld%lld 這樣的格式可能在一個目標系統上有效,但在其他系統上會出錯。

為了實現可移植性,執行時程式碼使用了標準(但確實有點彆扭)的 <cinttypes> 輔助宏。每種可移植整數型別都有一個對應的 PRIn## 宏,例如

  • int32_t -> PRId32

  • uint32_t -> PRIu32

  • int64_t -> PRId64

  • uint64_t -> PRIu64

  • 更多資訊請參閱 https://cppreference.tw/w/cpp/header/cinttypes

這些宏是字面量字串,可以與格式字串的其他部分連線,例如

int64_t value;
ET_LOG(Error, "Value %" PRId64 " is bad", value);

請注意,這需要將字面格式字串切分(額外的雙引號)。它還需要在宏前面加上前導的 %

但是,透過使用這些宏,可以保證工具鏈將為該型別使用適當的格式模式。

size_t, ssize_t

與定寬整數型別不同,格式字串已經有了一種可移植的方式來處理 size_tssize_t

  • size_t -> %zu

  • ssize_t -> %zd

型別轉換

有時,特別是在跨越 ATen 和 lean 模式的程式碼中,值本身的型別在不同構建模式下可能不同。在這種情況下,將值轉換為 lean 模式型別,例如

ET_CHECK_MSG(
    input.dim() == output.dim(),
    "input.dim() %zd not equal to output.dim() %zd",
    (ssize_t)input.dim(),
    (ssize_t)output.dim());

在這種情況下,Tensor::dim() 在 lean 模式下返回 ssize_t,而 at::Tensor::dim() 在 ATen 模式下返回 int64_t。由於它們在概念上都返回(有符號的)計數,ssize_t 是最合適的整數型別。int64_t 也能工作,但在 lean 模式下會不必要地要求 32 位系統處理 64 位值。

這是唯一需要進行型別轉換的情況,即當 lean 模式和 ATen 模式不一致時。否則,請使用與型別匹配的格式模式。

文件

訪問 PyTorch 的全面開發者文件

檢視文件

教程

獲取面向初學者和高階開發者的深度教程

檢視教程

資源

查詢開發資源並解答你的問題

檢視資源