GPU版本的邏輯相對複雜一些,講講GPU的邏輯:
進行column計算,需要從硬碟讀取11層layer的資料,並整合成column排布。GPU版本,一批批的進行處理,將一部分column讀取排序後,透過channel送給GPU處理(Column Hash以及構造Merkle樹)。程式碼邏輯大體上就是兩個執行緒,一個讀取layer的資料,column排序,另外一個GPU處理。每次batch的節點個數預設是400000,也就是135M左右。在column計算完成後,GPU構造Merkle樹。
2. Replica計算
Replica是最後一層layer的資料和原始資料編碼之後的結果。每次Encoding一部分Replica,透過channel送給GPU(構造Merkle樹)。每次batch的節點個數預設是700000,也就是22M左右。注意,batch的是Encoding的結果。
Merkle樹的構造都是採用merkletree庫。這個庫實現通用的Merkle樹的結構和計算。通用的Merkle樹,指的是Merkle並不只是通常我們理解的二叉樹,而是分成3層:top,sub和base。
如上圖的示例,top是1叉,sub是3叉,base是4叉。在Precommit2計算中,tree_c和tree_r_last都是8叉樹:
type Tree = storage_proofs::merkle::OctMerkleTree<DefaultTreeHasher>;
pub type OctMerkleTree<H> = DiskTree<H, U8, U0, U0>;
4. GPU加速
在Precommit2計算中,Column Hash的計算以及Merkle樹的構造是採用GPU加速。相關的程式碼在neptune程式碼庫中。有意思的是,這部分的程式碼並不是用cuda或者opencl實現的,而是一種新的更高層的語言:Futhark。
5. 相關巨集定義
FIL_PROOFS_USE_GPU_COLUMN_BUILDER - 使用GPU,進行column hash的計算
FIL_PROOFS_MAX_GPU_COLUMN_BATCH_SIZE - 每次計算Column的batch大小,預設400000
FIL_PROOFS_COLUMN_WRITE_BATCH_SIZE - 每次刷Column資料的batch大小,預設262144
FIL_PROOFS_USE_GPU_TREE_BUILDER - 使用GPU,構造Merkle樹
FIL_PROOFS_MAX_GPU_TREE_BATCH_SIZE - 每次Encoding計算的batch大小,預設700000
總結:
Precommit2階段,主要是計算Column Hash以及生成Replica,並構造相應的Merkle樹。其中,Column Hash的計算以及Merkle樹的構造可以採用GPU加速。GPU的實現採用一種新的高層語言:Futhark。