1. buffer pointer of Halide::Runtime::Buffer
宣告一個 Buffer object 並不困難像是:Halide::Runtime::Buffer
buf(x, y) = val
使用由 data() 取得的 pointer 就必須注意 layout, 預設的是 Planarunsigned char* buf_ptr = (unsigned char*)(buf.data());
若需要使用 interleaving data 則要透過 set_stride 來設定 (見 Lesson 16)
2. Buffer allocation
儘管一般開發 Halide 程式使用的裝置離不開 CPU/GPU但是 Halide 俱備介面, 只要實作 code generation 與 runtime interface 就可以接上
以 Qualcomm HVX 來說, DSP backend 的 Buffer 使用與 CPU 有相當不同
透過的是 Buffer::device_malloc() 來配置特定計算裝置的記憶體
並以此避免 memcpy 的呼叫, 來達到 zero-copy 的目的
而 device_malloc 需要帶入 Device API 的 interface
像是在 Qualcomm 官方 Halide 文件中提到 Qualcomm Hexagon DSP buffer 配置的呼叫為:
buf.device_malloc(halide_hexagon_device_interface());如此即可配置針對 Hexagon DSP 所使用的記憶體空間, 並且無需 data copy
3. Prefetch schedule directive
計算單元與記憶體間資料的傳輸方式一直是改善效能的重點個人經驗是撰寫 SIMD code 透過 prefetch 能改善不少效能
其他像是 GPU 俱備 local/shared memory,
有些 DSP 也有著自己的 scratchpad memory
透過重疊(overlapping) 執行時間與傳輸時間
這部分都牽涉到 2D 的 Prefetch 或 DMA 的呼叫使用
在 2015 年剛接觸 Halide 時, 與當時熟悉 Halide 同事討論
當時給的答覆是並無法對應 prefetch 這樣的行為
而日前第一時間在 Qualcomm Halide SDK 中的範例看到 prefetch 排程指令時:
(像是 Halide SDK 中 HALIDE_Tools/2.0/Halide/hexagon_benchmarks/gaussian5x5_generator.cpp )
output.hexagon().prefetch(input, y, 2) ... ;個人一度以為這只是 Qualcomm 為了 Hexagon DSP 而客製的 API
然而近日發現 Halide 中的 Prefetch.h 的說明文件
又挖了 History 後才發現在 2016 年中 Halide 已加入了對於 prefetch 行為的支援
這也讓 Halide 能夠更彈性的支援不同處理器的運作特性
而類似於 data 在 Boundary 的處理 Prefetch 也有 PrefetchBoundStrategy
4. AOT target
在 Lesson 15 並沒有提及 Generator Enhancements在後續 Halide 對於 Generator 分為 generate() 與 schedule()
顧名思義, generate() 是用來定義 pipeline 的, 而 schedule() 是處理排程的
若希望有效地支援不同平台, 就需要知道 code generation target 的特性
這裡主要透過二個 API 與二個 public member
* Halide::GeneratorContext::get_target() - 這可以得到 Halide::Target 的物件, 透過這物件可以獲得相關資訊, 最直接的就是 Target::to_string() 可以得到指令傳入的 target 字串
* Halide::Target::has_feature() - 可以確認是否支援某些特性像是 SSE/AVX, ARMv7s or HVX
* Halide::Target.arch - X86, ARM, Hexagon ...
* Halide::Target.os - Linux, Windows ...
如此可以透過條件判別來針對平台特性呼叫在 schedule() 中呼叫對應的排程指令
簡短列出這些日子看到的有趣東西, 一方面也做個紀錄
沒有留言:
張貼留言