• 文件 >
  • 可攜式 C++ 程式設計
快捷方式

可攜式 C++ 程式設計

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

ExecuTorch 執行階段程式碼旨在可攜,並且應該可以為各種系統建置,從伺服器到手機到 DSP,從 POSIX 到 Windows 到裸機環境。

這表示它不能假設存在

  • 檔案

  • 執行緒

  • 例外

  • stdout, stderr

  • printf(), fprintf()

  • 一般的 POSIX API 和概念

同時,它也不能假設

  • 64 位元指標

  • 給定整數類型的大小

  • char 的正負號

為了將二進位檔案大小保持在最小,並嚴格控制記憶體分配,程式碼可能無法使用

  • malloc()free()

  • newdelete

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

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

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

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

  • Core PyTorch (僅適用於 ATen 模式)

平台抽象層 (PAL)

為了避免假設目標系統的功能,ExecuTorch 執行期允許客戶端覆寫其平台抽象層 (PAL) 中的底層函數,PAL 在 //executorch/runtime/platform/platform.h 中定義,以執行以下操作:

  • 獲取目前時間戳記

  • 列印日誌訊息

  • 使系統 panic

記憶體分配

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

檔案載入

客戶端不應直接載入檔案,而應提供已載入資料的緩衝區,或包裝在類似 DataLoader 的類型中。

整數類型

ExecuTorch 執行期程式碼不應對原始類型(例如 intshortchar)的大小做任何假設。 例如,C++ 標準僅保證 int 至少為 16 位寬。 並且 ARM 工具鏈將 char 視為無符號,而其他工具鏈通常將其視為有符號。

相反,執行期 API 使用一組更可預測但仍是標準的整數類型

  • 類似於 uint64_tint32_t<cstdint> 類型; 這些類型保證位元寬度和正負號,與架構無關。 當您需要非常特定的整數寬度時,請使用這些類型。

  • size_t 用於事物計數或記憶體偏移量。 保證 size_t 足夠大,可以表示任何記憶體位元組偏移量; 也就是說,它將與目標系統的本機指標類型一樣寬。 優先使用它而不是 uint64_t 來進行計數/偏移量,以便 32 位元系統無需為 64 位元值的額外開銷付費。

  • ssize_t 用於某些 ATen 相容性情況,其中 Tensor 會傳回帶正負號的計數。 盡可能優先使用 size_t

浮點運算

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

核心執行期之外的 Kernel 允許執行浮點運算。 儘管有些 Kernel 可能選擇不執行,以便它們可以在沒有浮點支援的系統上執行。

日誌記錄

ExecuTorch 執行期不使用 printf()fprintf()coutcerr 或類似 folly::loggingglog 的程式庫,而是提供 ET_LOG 介面(在 //executorch/runtime/platform/log.h 中)和 ET_CHECK 介面(在 //executorch/runtime/platform/assert.h 中)。 這些訊息是使用 PAL 中的 hook 列印的,這表示客戶端可以將它們重新導向到任何底層日誌記錄系統,或者如果可用,只需將它們列印到 stderr 即可。

日誌記錄格式可移植性

固定寬度整數

當您有類似這樣的日誌語句時

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

您應該在 %??? 部分放置什麼來匹配 int64_t? 在不同的系統上,int64_t typdef 可能是 intlong intlong long int。 選擇像 %d%ld%lld 這樣的格式可能在一個目標上有效,但在另一個目標上會中斷。

為了具有可移植性,執行期程式碼使用 <cinttypes> 中的標準(但不得不承認很尷尬)輔助巨集。 每個可移植整數類型都有一個對應的 PRIn## 巨集,例如

  • int32_t -> PRId32

  • uint32_t -> PRIu32

  • int64_t -> PRId64

  • uint64_t -> PRIu64

  • 有關更多訊息,請參閱 https://en.cppreference.com/w/cpp/header/cinttypes

這些巨集是文字字串,可以與格式字串的其他部分串連,例如

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

請注意,這需要分割文字格式字串(額外的雙引號)。 它還需要在巨集之前加上 %

但是,透過使用這些巨集,您可以確保工具鏈會針對該類型使用適當的格式模式。

size_tssize_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 也能夠工作,但它會不必要地要求 32 位元系統在 lean 模式下處理 64 位元的值。

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

文件

存取 PyTorch 的全面開發人員文件

檢視文件

教學

取得針對初學者和進階開發人員的深入教學課程

檢視教學課程

資源

尋找開發資源並取得問題的解答

檢視資源