# NMC Software Implementation ## Host-side ![](https://i.imgur.com/3RN62I4.png) ### Vendor Specified I/O Command ![](https://i.imgur.com/WmVQNcF.png) ```plain! NMC X X Data Model \ | | | / Wr Rd bit: 7 | 6 5 4 3 2 | 1 0 | hex | description 1 | 1 0 0 0 0 | 0 1 | C1h | create mapping table for new file 1 | 1 0 0 0 0 | 1 0 | C2h | close mapping table 1 | 1 0 0 0 0 | 1 1 | C3h | inference the specified file 1 | 1 0 0 1 0 | 0 1 | C9h | write tiff chunk 1 | 1 0 0 1 1 | 0 1 | CDh | write model ``` #### Command Flows ![](https://hackmd.io/_uploads/Hy1IUfIE2.png) #### Write-tiff (C1+C2+C9) #### Write-model (C1+C2+CD) #### Inference (C3) 流程概述: 1. Host 發出 Inference Request 2. :::spoiler Vendor Command Tests > 指定檔案作為 input data > > ![](https://i.imgur.com/2tFWrV8.png) 自定義的 command 除了 opcode 與額外資訊之外,其他行為應與 write 相同,因此用 read 檢查是否有正確寫入資料: > 原始檔案 > > ![](https://i.imgur.com/e7SO9gE.png) > > 寫入的內容 > > ![](https://i.imgur.com/hcJeR8l.png) 測試更大的檔案: > 4K > > ![](https://i.imgur.com/3CJXPRd.png) > > > 16K x 8 > > ![](https://i.imgur.com/cTJAvuo.png) ::: ### Test on OpenSSD - [x] 整合 nvme-cli 與 preprocessing 1. 透過 `nvme write-tiff` 啟動程式 2. 在 `nvme write-tiff` 過程中會先對圖片進行前處理 3. 接著再透過 `io-passthru` 將資料片段寫入 SSD - [x] 在 OpenSSD 上實測 - [x] 檢查 OpenSSD 讀取出的資料與存入的資料是否相同 :::danger - OpenSSD 的 sector size (4096) 與 QEMU (512) 不同 - [ ] 設定 QEMU 的 sector size - 可靠性測試 - [ ] 測試更大的圖片 - [ ] big-tiff ::: ## Data Placement :::info - 原圖片 = 87424 x 205952 x 3 bytes - 50.3058 GiB - 31.4411 秒 (沒有重複讀取資料) - 共有 30171 個 patch - 88.3916 GiB - 55.24475 秒 (patch 間有重疊,會有資料被重複讀取) ::: ### Mapping Table > 需要用 Mapping Table 讓 Unet 知道檔案存在哪些 block Assume: - 分配單位為 block (4M) - 每個 Channel 分開存 Table Size: - (87424 * 205952 * 3) / (4M) / 8 = 1610 blocks used per channel - 16384 blocks per channel → $2^{14}$ → 14 bits or 16 bits - 14 bits: - 1610 * 14 bits = 2817.5 bytes per channel - 16 bits: - 1610 * 16 bits = 3220 bytes per channel :::warning - Page-level (256 MiB) - #Entries = 64 x 2048 x 256 (pages) - Entry Size = 32b (PPN) + 32b (LPN) = 8 Bytes - Block-level (1 MiB) - #Entries = 64 x 2048 (blocks) - Entry Size = 32b (PPN) + 32b (LPN) = 8 Bytes - Demand-based page-level - Page-level (256M) + metadata (32K) ::: ### Result Data Buffer width: 200000 / 256 = 781.25 (先不考慮 patch 間有重疊) height: 80000 / 256 = 312.5 (先不考慮 patch 間有重疊) 312 * 781 * (2 * 256 * 256) = 29.7451171875 GiB (RAM 放不下) :::warning 定期回傳給 host -> DRAM 需要保留多少空間給 FPGA 存放 inference 結果? ::: <!-- --- --> ## Device-side ### Flush Data Buffer ```bash! # user issue write command $ sudo nvme write /dev/nvme0n1 -s 0 -z 4096 ``` :::success 寫入操作都會先被暫存在 buffer 中、不會被寫入 SSD,所以在 user 發出寫入請求後,data buffer 中會有 dirty entry,而在 user 發出 flush 請求後,這些 dirty entry 都應要被寫入 SSD 並變成 clean entry。 ::: ```plain! # before flush op INFO Dump dirty data buffer entries INFO buffer entry [1023] INFO .logicalSliceAddr = 0 INFO .dirty = 1 INFO .prevEntry = 65535 INFO .nextEntry = 1021 INFO .hashPrevEntry = 65535 INFO .hashNextEntry = 65535 INFO .blockingReqTail = 65535 IO Flush Command # after flush op INFO Dump dirty data buffer entries INFO LSA[0] -> VSA[0] INFO VSA[0] = Ch 0 Way 0 Blk 0 Page 0 ``` :::warning 因為 Flush Buffer 不會把原本的 buffer entry 踢掉,所以 user 直接讀原本的 LBA 也只會讀到暫存在 buffer 中的值,無法確認是否有真的寫入 SSD。 ::: ```bash! # user issue read command $ sudo nvme read /dev/nvme0n1 -s 0 -z 4096 flush test ``` :::info 若要檢查資料是否有被寫入 SSD,有幾種可行方案: 1. 把一個 free logical page $LPA_{Y}$ 指向應有資料的 physical page $PPA_{X}$,再讀取 $LPA_{Y}$ 2. 把 $LPA_{X}$ 的 Buffer Entry 清掉(drop cache)後再讀 $LPA_{X}$ ::: #### Method 1 :::success 找一個不在 data buffer 中的 $LPA_{Y}$,然後將 $LPA_{Y}$ 指到應有資料的 $PPA_{X}$ ::: ```plain! # LPA 33 not in data buffer (not used) INFO Dump the data buffer entry of LSA 33 # map LPA 33 to PPA 0 INFO Update L2V Mapping : LSA[33] -> VSA[0] ``` :::success 接著由 user 嘗試讀取,讓 fw 去 SSD 中讀取 $PPA_{X}$ ::: ```bash! # user issue read command $ sudo nvme read /dev/nvme0n1 -s 33 -z 4096 ``` :::danger 讀取 $LPA_{Y}$ 時,fw 卡在 scheduler 中出不來。 ::: :::spoiler DFTL - Translation Pages - Flash Page (16 KiB) - 一個 Page 可以存 4096 個 PPN (Physical Page Number) - 一個 Block 可以存 256 x 4096 個 PPN - SSD 共有 64 x 2048 x 256 個 Page - 需要 32 個 Block (128 MiB) - 紀錄**連續 Logical Pages** 對應的 Physical Pages - 以 **Entry 為單位暫存**在 DRAM 中 - Global Translation Directory (GTD) - SRAM - 紀錄 Translation Page 對應的 Physical Page - 共有 8192 個 Translation Pages - 需要 2 個 flash pages 儲存 (32K) - 需要頻繁更新 ![](https://i.imgur.com/lb2PwrW.png) :::