2023年11月12日 星期日

Chisel 學習筆記 - Scala 與 Chisel 基礎語法

標題為筆記, 但這篇比較屬於心得

延續上一篇的環境建立, 這次計劃藉由 Jserv 最新的課程安排來學習 Chisel, 當然個人目標是能夠按照 Jserv 的課程規劃在期限之內完成 Lab 3, 由於個人並非 digital designer (現在這年紀也算老貓學新把戲...), 因此對於 chisel 的一切也是從基本開始, 目前計劃於一週內按照 Chisel Bootcamp 的章節完成 Chap 0 ~ 3 的所有內容. (Chap 4 部份在後續會依照進階需求選擇回來看)

週末花了點時間把 Chap 0 ~ 2 的說明研讀完, code block 的操作也跑過一次流程, 另外是在 try and error 下完成當中的所有 exercise & test. 個人覺得 Chisel Bootcamp 多少是面向俱備 Verilog / HDL 有些許基礎的人. 儘管無基礎並不會造成學習的困難, 但多少難以體會 Chisel 相較之下的優點與強項.

基本上Chap 0 ~ 2 的重點其實並不多

  • Chisel 的特性
  • Scala 的基本語法
  • 建構於 Scala 之上的 Chisel DSL
  • 電路的基本: module, combinational, control & sequential logic
  • 除錯與測試方式

由於並非第一次學習建構在另一語言的 Domain Specific Language. 過往學習 Halide 的過程就是這樣的一個經驗. 然而與先前 Halide 不一樣的地方是 Halide 所依附的 C++ 個人有所基礎, 但是對於 Scala / Chisel 這樣的組合卻是完全從頭學起. 而這大概有幾個面向是需要反覆思考與刻意練習的.

第一個主要的點在於 Value 與 Typing System, 類似於 C++ 與 Halide 有著各自的 value & typing system, C++ 主要用在撰寫與控成 Halide code 的流程, Halide 體系著重在產生 target code 上. Scala 與 Chisel 也有各自的 value & typing system. Scala 也是用在撰寫 Chisel 主體與流程上, Chisel 是用以定義 hardware 使用到的 module 與產生 instance. Chap 1 ~ 2.1 強調分清楚 Scala 與 Chisel 的 value & typing system 確實是很重要的一件事.

第二個是 Chisel 的實作撰寫必需了解的 3 個階段 - circuit generation, circuit simulation 與 testing. (Halide 也有著類似的階段, 甚至都使用 Generator 這樣的名稱) Scala 與 Chisel 在使用上容易搞混的是 generation, Scala 是讓 code generation 能透過參數化來產生對應不同的 circuit (按照教學說法, 這是 Chisel 強大的地方). 因此這些都是在 compile time 決定的, 而 Chisel 的撰寫則是決定了 circuit generation 的結果. 對於一些 if / else 的思考必須區隔希望影響的是 compile time 的行為抑或者是 runtime 時的所需. (習題上來說, 觀察前後輸入的 data type 就可以快速反應)

儘管這些並不是什麼艱深難懂的心得, 然而困難的點是在熟悉與快速應用 Scala / Chisel. 重要的還是需要刻意練習來讓思維方式有著正確的對應. 若儘只是研讀一番並不足以深刻體會, 或是習得實務上的撰寫能力. Chisel Bootcamp 的作業與測試非常值得一一花時間下去練習. 藉由這些能夠一次次找到認知錯誤的地方或是盲點. 個人認為能嘗試完成 2.2 Arbiter, 2.3 Finite State Machine 與 2.5 FIR Filter Generator 這三個 exercise 應符合了基本要求. ( 2.2 中提供的 Cheatsheet 第一頁對於閱讀內容與作業相當有幫助)


2023年11月10日 星期五

Chisel 學習筆記 - 環境建立

近日 Jserv 在期 2023 年度課程中仿效 UC Berkeley 的課程, 計劃透過課程 Lab 引導學生學習 Chisel 來實作 RISC-V 核心

為此他高度簡化了原本 UC Berkeley 的教程, 建立一個新的 Lab, 目標是帶領學生實作 5-stage pipeline RISC-V processor

Lab 3 的 Hackmd 頁面上可以看到幾個章節:

  • Install sbt
  • Chisel Tutorial
  • Chisel Bootcamp & Chisel 介紹
  • Single-cycle RISC-V CPU

這篇文章的重點是放在建立可攜式的 Scala Build Tool 環境, 由於並非每個人都想在日常使用環境與這類開發環境混在一起, 希望儘可能保持系統的單純與乾淨程度. 所以還是選擇透過 Apptainer 這個 rootless 的 container 技術來建立環境. Apptainer 的安裝相當簡單, 在官網的 Installation 頁面可以找到個別 Linux Distro 的安裝方式. 至於 Apptainer 的使用方式則可以參考個人先前的介紹文.

對於 SBT 於 Linux  上的安裝, 在官網提供了兩個方式, 分別是透過 SDKMAN 與 debian-based repository 的方裝方式, 由於使用 apptainer, 所以我們可以選擇透過 debian-based repository 的方式.

經嘗試後, 下列為建立 apptainer sandbox 的 script

#!/bin/sh export SANDBOX=chisel_env
rm -rf $SANDBOX
rm -rf $SANDBOX-overlay
apptainer build --fakeroot --sandbox $SANDBOX docker://ubuntu:latest
apptainer exec --fakeroot --writable $SANDBOX apt update
apptainer exec --fakeroot --writable $SANDBOX apt dist-upgrade -yqq
apptainer exec --fakeroot --writable $SANDBOX apt install openssh-client openjdk-11-jre-headless openjdk-11-jdk-headless ca-certificates-java apt-transport-https curl gnupg -yqq
apptainer exec --fakeroot --writable $SANDBOX sh -c "echo 'deb https://repo.scala-sbt.org/scalasbt/debian all main' | tee /etc/apt/sources.list.d/sbt.list"
apptainer exec --fakeroot --writable $SANDBOX sh -c "echo 'deb https://repo.scala-sbt.org/scalasbt/debian /' | tee /etc/apt/sources.list.d/sbt_old.list"
apptainer exec --fakeroot --writable $SANDBOX sh -c "curl -sL 'https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x2EE0EA64E40A89B84B2DF73499E82A75642AC823' | gpg --no-default-keyring --keyring gnupg-ring:/etc/apt/trusted.gpg.d/scalasbt-release.gpg --import"
apptainer exec --fakeroot --writable $SANDBOX chmod 644 /etc/apt/trusted.gpg.d/scalasbt-release.gpg apptainer exec --fakeroot --writable $SANDBOX apt update
apptainer exec --fakeroot --writable $SANDBOX apt install sbt graphviz -yqq mkdir $SANDBOX-overlay
# testing sbt
apptainer exec --overlay $SANDBOX-overlay $SANDBOX sbt --version

完成後可以看到如下的字串

sbt version in this project: 1.9.7
sbt script version: 1.9.7

後續使用方式並不難, 只要提供 overlay 與 sandbox 的路徑即可, 所以可以宣告絕對路徑來使用, 假設 sandbox 與 overlay 的目錄為 ~/workspace/ca2023/ 下, 那麼可以如下先建立環境變數:

$ export SANDBOX_PATH=~/workspace/ca2023/chisel_env
$ export SANDBOX_OVERLAY=~/workspace/ca2023/chisel_env-overlay

如此可以透過下列指令在 chisel-tutorial 來執行 sbt run

$ apptainer exec --overlay $SANDBOX_OVERLAY $SANDBOX_PATH sbt run

當然也可以先執行下列指令, 得到建立環境的 shell 後切到 chisel-tutorial 目錄執行 sbt run

$ apptainer shell --overlay $SANDBOX_OVERLAY $SANDBOX_PATH
Apptainer> cd chisel-tutorial/
Apptainer> sbt run

[info] Loading project definition from /home/champ/workspace/ca2023/chisel-tutorial/project
[info] Loading settings for project chisel-tutorial from build.sbt ...
[info] Set current project to chisel-tutorial (in build file:/home/champ/workspace/ca2023/chisel-tutorial/)
[info] running hello.Hello
[info] [0.001] Elaborating design...
[info] [0.054] Done elaborating.
Computed transform order in: 208.3 ms
Total FIRRTL Compile Time: 261.5 ms
End of dependency graph
Circuit state created
[info] [0.000] SEED 1699679987261
test Hello Success: 1 tests passed in 6 cycles taking 0.008084 seconds
[info] [0.002] RAN 1 CYCLES PASSED
[success] Total time: 2 s, completed Nov 11, 2023, 5:19:48 AM
Apptainer>

如此就建立好可以使用的 container, 需要清除也很簡單, 刪除 chisel_env 與 chisel_env-overlay 即可


最後對於 Chisel 語言的學習提供的材料是 Chisel Bootcamp, Lab 3 中提供的是 GitHub 上面的兩個方式 - Docker 與 Local Install. 

然而 Chisel Bootcamp 的安裝設定, 並不是 Lab 的主要重點, 個人最建議的方式是直接使用在其 GitHub 主頁面上的 Get Started 一段中提供的 "Try it out HERE! No local installation required!", 如此可以省下安裝設置 Docker 或是 local 安裝 jupyter 碰到各種問題的時間.

2023年11月5日 星期日

OpenCL 1.2 之後(個人觀點中)重要的 feature 與 extension

最近因工作緣故, 而看到了使用 subgroup 特性的實作, 在第一時間個人難以解讀程式碼的目的與原意,  後來看了原始實作與擴充功能的說明文件才得知 subgroup 的功能特性為何. 主要因為個人對於 OpenCL 2.x 印象僅停留在 Shared Virtual Memory. 然而事實上 OpenCL 2.0 到 OpenCL 3.0 這段期間依然有數個實用的功能特性與擴充 對於 OpenCL 3.0 而言, 這些 2.0 以後加入的新 features 與 extensions 都屬於 extension. 因此可以到 The OpenCL™ Extension Specification 頁面一一查看. 以下列出個人覺得實用的 extensions:

Creating a 2D Image From A Buffer

許多時候人們很希望能透過 vload / vstore 來存取 buffer, 又希望能夠使用 GPU 的 texturing unit. 在 OpenCL 1.x 的時代, 通常是透過 ION buffer 來重複 mapping 到 Buffer 與 Image, 並且傳入對應的 kernel 中使用. 基本上這需要 GPU vendor 確認 cache coherency 的問題, 甚至提供對應的 driver 支援. 在 OpenCL 2.0 中將類似功能成為 core feature, 也就是 OpenCL 2.0 中是必要的存在. 透過 cl_khr_image2d_from_buffer 這個 extension, 可以先配置 Buffer 後再以此 Buffer 來建立 Image. 一開始提到相同目的.

Subgroups

儘管 OpenCL 中提供了 Global 與 Local work size 來對整體工作做切割, 而 Local work size 另一個重要的意義是對應的 workgroup size 是能作同步的最小單位. 在 OpenCL 2.1 中新增了這個 core feature. 在 Workgroup 中能夠再切分一個 1D 的 subgroup, 除了 subgroup 層及的 barrier 做同步外, 也提供了 3 個種類的 kernel function: reduce_op, scan_exclusive_op 與 scan_inclusive_op. 這些 operation 對於 reduction 與 integral 這兩類原本 OpenCL 不適合應付的計算提供了有效的介面, 讓 device 能夠使用硬體支援來處理這類的計算.

Mipmaps

在 OpenGL 中支援以硬體產生 Mipmaps 來做 texturing. 可以避免 aliasing. 這裡應該是同等的結構. 但除了做原本 antialiasing 用途外, 不知是否有機會利用這個 pyramid 結構來做 CV 應用.

Integer Dot Product

OpenCL 中原本只支援 float / double 型別的內積 (dot product), 然而現今 NN 應用中 8-bit integer dot product 的需求相當大. 這個 extension 有效的提供了對於 8-bit dot product 硬體加速的介面. 理論上透過 multiplication 搭配 subgroup 就可以得到相同結果, 但若支援此 extension 且俱備硬體加速, 可以得到更高的 computation throughput.


當然 OpenCL 2.x 系列還是有其他像是 SVM, device-side enqueue 與 Pipe 的功能, 有時間再來寫程式並撰文說明這些功能的實際的應用.


在 ARM 平台上使用 Function Multi-Versioning (FMV) - 以使用 Android NDK 為例

Function Multi-Versioning (FMV) 過往的 CPU 發展歷程中, x86 平台由於因應各種應用需求的提出, 而陸陸續續加入了不同的指令集, 此外也可能因為針對市場做等級區隔, 支援的數量與種類也不等. 在 Linux 平台上這些 CPU 資訊可以透過...