研究員
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note No publishing access yet

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.

      Your account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

      Your team account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

      Explore these features while you wait
      Complete general settings
      Bookmark and like published notes
      Write a few more notes
      Complete general settings
      Write a few more notes
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Engagement control
    • Make a copy
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Make a copy Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note No publishing access yet

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.

    Your account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

    Your team account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

    Explore these features while you wait
    Complete general settings
    Bookmark and like published notes
    Write a few more notes
    Complete general settings
    Write a few more notes
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    # 平行處理 有分為兩種層面: - 工作層面 Task-level (process-level) parallelism - 讓單一個工作(independent jobs)的 throughput 增加 - 例如工作的某個程序由某個核心來做 - 程序層面 Parallel processing program - 單一個程序(program)用多個核心執行 ## Amdahl’s Law 一樣,想要平行化?要先看看平行化帶來的效率提升夠不夠。 舉例來說,我們動用了 100 個核心平行化處理,來看看新的所耗時間跟舊的相比差多少: $$ T_{\text{new}}=\frac{T_{\text{parallelizable}}}{100}+T_{\text{sequential}} $$ 或者我們換個方法表示,$T_{\text{parallelizable}}$ 跟 $T_{\text{sequential}}$ 加起來等於 1,$T_{\text{parallelizable}}$ 跟 $T_{\text{sequential}}$ 的比例分別為 $F_{\text{parallelizable}}$ 跟 $F_{\text{sequential}}$,那麼,改成用比率表示的話為: $$ \frac{1}{\frac{F_{\text{parallelizable}}}{100}+F_{\text{sequential}}}=\frac{1}{\frac{F_{\text{parallelizable}}}{100}+(1-F_{\text{parallelizable}})} $$ 我們用了 100 顆核心,想要有 90 倍的提升應該不為過吧?,那麼我們來算算看 $F_{\text{parallelizable}}$ 要佔多少的比例: $$ \frac{1}{\frac{F_{\text{parallelizable}}}{100}+(1-F_{\text{parallelizable}})}=90 $$ 可以解得 $F_{\text{parallelizable}}=0.999$,代表我們要有非常大的部分屬於可平行化,才可以達到 90 倍的提升。 # Strong vs Weak Scaling 從上面的例子可以看到,不是狂堆核心,效能就會上去,而是跟工作的類型有關。 為此聰明的人們分出兩種類型: - Strong Scaling - 工作的大小固定,核心堆越高效能越好 - 這就是上面我們理想的工作 - Weak Scaling - 工作量跟核心的需求量成正比 - 也就是說工作量要多,高核心才可以提高效能 舉個例子。 - 工作 A,他是將 10 個純量加起來,並且再做兩個 10X10 的矩陣元素相加。 - 工作 B,一樣是將 10 個純量加起來,但是再做兩個 100X100 的矩陣元素相加。 可以看到將 10 個純量加起來就是 Seq 的部分。然後我們分別用單核心跟多核心的情況模擬,並且計算 「Potential」: - 工作 A - 單核心:$(10+100)\times t_{\text{add}}=110\times t_{\text{add}}$ - 10 顆核心:$(10+\frac{100}{10})\times t_{\text{add}}=20\times t_{\text{add}}$ - 跟單核心相比:$\frac{110}{20}=5.5$ 倍的提升 - 但是理論上 10 顆核心應該要有 10 倍提升,所以 Potential 為 $\frac{5.5}{10}=55\%$ - 100 顆核心:$(10+\frac{100}{100})\times t_{\text{add}}=11\times t_{\text{add}}$ - 跟單核心相比:$\frac{110}{11}=10$ 倍的提升 - 但是理論上 100 顆核心應該要有 100 倍提升,所以 Potential 為 $\frac{10}{100}=10\%$ 可以看出如果工作量固定的話,狂疊核心的 Potential 反而會變低。 - 工作 B - 單核心:$(10+10000)\times t_{\text{add}}=10010\times t_{\text{add}}$ - 10 顆核心:$(10+\frac{10000}{10})\times t_{\text{add}}=1010\times t_{\text{add}}$ - 跟單核心相比:$\frac{10010}{1010}=9.9$ 倍的提升 - 但是理論上 10 顆核心應該要有 10 倍提升,所以 Potential 為 $\frac{9.9}{10}=99\%$ - 100 顆核心:$(10+\frac{10000}{100})\times t_{\text{add}}=110\times t_{\text{add}}$ - 跟單核心相比:$\frac{10010}{110}=91$ 倍的提升 - 但是理論上 100 顆核心應該要有 100 倍提升,所以 Potential 為 $\frac{91}{100}=91\%$ 可以看到工作量如果變多了,100 顆核心的 Potential 會變高。 :::warning 所以我們其實可以列出一個方程式來計算這個問題: - 單核心:$(10+x^2)\times t_{\text{add}}$ - 10 顆核心:$(10+\frac{x^2}{10})\times t_{\text{add}}$ - 跟單核心相比:$\frac{10+x^2}{10+\frac{x^2}{10}}=\frac{100+10x^2}{100+x^2}$ 倍的提升 - 但是理論上 10 顆核心應該要有 10 倍提升,所以 Potential 為 $\frac{\frac{100+10x^2}{100+x^2}}{10}=\frac{10+x^2}{100+x^2}$ - 100 顆核心:$(10+\frac{x^2}{100})\times t_{\text{add}}$ - 跟單核心相比:$\frac{10+x^2}{10+\frac{x^2}{100}}=\frac{1000+100x^2}{1000+x^2}$ 倍的提升 - 但是理論上 100 顆核心應該要有 100 倍提升,所以 Potential 為 $\frac{\frac{1000+100x^2}{1000+x^2}}{100}=\frac{10+x^2}{1000+x^2}$ 所以我們可以知道,要到何種程度 100 顆才會比 10 顆好,就是: $$ \displaylines{ \frac{10+x^2}{100+x^2}<\frac{10+x^2}{1000+x^2}\\ 1000+x^2<100+x^2\\ } $$ 永遠不會比較好。 ::: Data Decomposition Task Decomposition Pipelining --- # Shared Memory Multiprocessor / SMP 顧名思義,就是每個核心都共用一塊記憶體。 聰明的人們用 Memory access time 來劃分出兩個種類: - UMA:uniform memory access - 各個核心存取的延遲是一樣的,如那張圖,因為就只有一塊記憶體,所以大家延遲都一樣 - NUMA:nonuniform memory access 下面主要著重 UMA 的部分。 # UMA - Cache Coherency 因為每個核心都共用一塊記憶體,但是 Cache 是各自擁有的,例如下圖: <iframe src="https://drive.google.com/file/d/1f5x-pOkedTKQLmWLwwk7iKc5RJDVqXFT/preview" height="480"></iframe> 所以必須要維持 Cache 內容的一致性。 我們的手段是透過一個叫 Snooping 的方式來處理。 # Snooping 講白話一點他就是 broadcast。上面的圖可以看到有個 Interconnection Network,這個東西又叫做 Bus,他是 broadcast 可以運作的主要結構。 大致維護的方法一個核心就是將「requests for data」的訊號給其他的核心,然後做一些操作。 在 Bus 上 Snooping 的手段,被廣泛用於小型的機器 small scale machines,也就是家用主機這樣的類別。 至於詳細的 Snooping,分為兩種: - Write Invalidate Protocol - Multiple readers, single writer - 發出 request 的人叫其他人把他們的資料變為不合法 - 這個動作又叫 Write to shared data - Read Miss 的部分,如果某個核心他沒有找到要讀的資料怎麼辦? - Write-through:memory is always up-to-date,所以不用擔心 - Write-back:snoop in caches to find most recent copy,也就是去看其他人的 cache,把有最新 cache 的核心的資料複製過來 - 這個待會會細講,會透過資料的 validate 狀態來判斷 - Write Update Protocol - 在 Bus 上廣播給大家,叫大家以及記憶體一起更新 - Read Miss?永遠不會發生,因為隨時大家資料都是最新的 ## 優缺 Invalidate 的每次寫入操作,只需要一次的 bus 傳輸訊號,因為第一次的廣播就會讓其他人的 cache 資料都變 invalidate,自己的保持 validate,所以如果第二次寫入同個 block 並保持是 validate,就不用再次做廣播,因為其他人已經是確保是 invalidate。 除非有其他人也做寫入,就會換你的資料變成 invalidate。 Update 則可以讓 read 跟 write 之間有較低的延遲,因為每次都是一次性叫全部人一起更改,資料隨時都是最新的,所以發生 read miss 時就不用花時間去查誰的 cahce 是最新的。 下面是個流程的範例: <iframe src="https://drive.google.com/file/d/1OgkVTkVzU-hL6MObEhbOKZ4qLsv_ffN9/preview" height="580"></iframe> 可以看到 Invalidate 中的 B,在 A 發出寫入訊號後,他的 cache 資料就變成了 invalidate,所以就不見了,並且這裡的例子是 write back,所以記憶體中的資料並沒有一起更新,這也是為何其他核心如果要拿資料的話,必須要從有最新資料的核心拿的原因。 在 Update 中則是 A 發出寫入訊號後,大家都一起更新了。 :::warning 所以如果某個處理器的規模較小, bus 能力有限,就會採用 Invalidate 這種對 bus 負擔較小的 Protocol ::: # Invalidate Snoopy with write-back cache 下面以「狀態圖」的方式完整介紹 Invalidate Snoopy 的內容,搭配 write-back cache。 在那之前,要先說明: - 對於每個 cache block(也就是一個 set)來說,他只會在下面的三種狀態其中一種: - Shared:分享狀態,這個 block 是可以被其所擁有的 CPU 讀取的 - Exclusive:獨特狀態,這個 block 擁有最新的資料,其他人的都是舊的 - 此時這份資料除了可以被其所擁有的 CPU 讀取,也可以被寫入 - 但是因為是 write back 所以要設置 dirty bit。 - Invalid:cache 沒有 block 的資料,或是不是最新的,所以不能用了 下面介紹兩種角度的狀態圖。 ## Request 發起人 我們一個一個的來看各個狀態: <iframe src="https://drive.google.com/file/d/1vTRyV-JBmQKomy-QnocWJhKqNOgHQY3F/preview" height="580"></iframe> - 當前 block 狀態是 **Invalid**: - 如果此時發起 CPU **read**,會向 Bus 吐出「**Read Miss**」 - 代表這個 block 之後會被放入從其他人來的「**最新的資料**」 - 也因此進入了 **Shared state**,代表其他人如果想拿最新資料... - **不可以跟他要,只能從記憶體拿** - Shared 的意思只代表該資料目前是處於「分享的狀態」,所以記憶體的資料是合法的 - 如果此時發起 CPU **write**,會向 Bus 吐出「**Write Miss**」 - 代表這個 block 之後會被放入從其他人來的「**最新的資料**」 - 並且會對他進行寫入,成為比**目前為止最新的資料** - 也因此進入了 **Eclusive state**,代表目前的 block 擁有最尖端的資料 - 當前 block 狀態是 **Shared**: - 如果此時發起 CPU read,不過好家在,block 在 cache 內,所以就一樣指回自己 - 如果此時發起 CPU **read** 但是**沒有資料**,會向 Bus 吐出「**Read Miss**」 - 代表這個 block 之後會被放入從其他人來的「最新的資料」 - 所以跟剛剛 Invalid state 一樣,都是進到 Shared state - 如果此時發起 CPU write - **無論資料有沒有在 cache 內,都會向 Bus 吐出「Write Miss」** - 代表目前的核心即將會擁有這個 block 最尖端的資料,也因此進入了 **Exclusive state** - 同時也在告知其他核心,**你們的資料都過期啦** - 當前 block 狀態是 **Exclusive state**: - 如果此時發起 CPU read 或 write,但是好家在,block 在 cache 內 - 所以就一樣指回自己,資料一樣是維持最新穎的資料 - 如果是 read,但是沒有資料,會向 Bus 吐出「**Read Miss**」 - 並且還會將自己最頂尖的資料先寫回記憶體 - 然後就會進到 **Shared state**,代表該資料目前是處於「分享的狀態」 - 要拿資料就從記憶體去拿 - 如果是 write,但是沒有資料,會向 Bus 吐出「**Write Miss**」 - 跟 read miss 一樣,會先將自己最尖銳的資料寫回記憶體 - 然後因為是寫入的操作,所以之後擁有的 block 一樣還是最尖端的科技 - 因此停留在 **Eclusive state** :::warning - 沒有資料的意思是,該 block 的資料不是要 read 或 write 的資料,是一個 miss - 簡單來說,發起 write 的時候會進到 **Exclusive**;發起 read 的時候,進到 **Shared** - 關於「Shared state 的意思」跟「從記憶體拿」,請看下面。 ::: ## Request 接收者 我們一個一個的來看各個狀態: <iframe src="https://drive.google.com/file/d/1HKdF_gzxBPito4PWh3k6biKGmB-6kr8o/preview" height="580"></iframe> - 當前 block 狀態是 **Invalid**: - 可以看到並沒有任何指向外面的箭頭,關鍵在於這是「**以某個核心的角度來說**」 - 因為以某個核心來講,他雖然收到了 write 或 read miss,但是它本身該 block 的資料就是 invalid,也就不能給別人 - 所以對於最初始的狀態,如果某個 miss 的發起人沒有收到其他人的回覆,就得要從記憶體拿資料 - 當前 block 狀態是 **Shared**: - 如果收到的請求是 write miss,並且本身的該 block 的狀態是 Shared - 代表**該 block 的資料就要失效了**,所以會進入 Invalid state - 這就是上面提到的,request 發起人會叫其他人把資料設成 Invalid - 那為甚麼收到的請求是 read miss,並且本身的該 block 的狀態是 Shared,卻沒有箭頭呢? - 其實可以看到在 Exclusive state 的時候,如果收到 read miss,會**將資料寫回記憶體** - 也就是代表,當前最尖端的資料已經放在記憶體了,所以資料是 **Shared** 的狀態 - 也因此 Shared state 的核心如果又收到 read miss,並不會做任何動作 - 告訴你要拿請跟記憶體拿,**記憶體有最新的資料** - 當前 block 狀態是 Eclusive state: - 如果收到的是 read miss - 會將最新穎的資料先寫回記憶體,然後進入 Shared state - 代表當前該 block 的資料是最新的,最純的 - 並因此可以看到有個 abort memory access 的字樣,代表不需從記憶體讀取 - 相對的,Shared state 沒有寫的就是要從記憶體讀取 - 如果收到的是 write miss - 一樣會將最新穎的資料先寫回記憶體 - 但是發起 write 的核心待會就會有最新的資料了,所以自己的資料即將過期 - 因此進入了 Invalid state - 也一樣可以看到 abort memory access ## 下面是模擬 <iframe src="https://drive.google.com/file/d/17bvbRjVpe8zvHyKeasB5f8bV1cjP5nCy/preview" height="300"></iframe>) --- # 四個 C 從上次的三個 Miss 多加了這次的第四個 Miss:Coherency Misses,代表是跟維持一致性有關而造成的 miss。 當兩個 CPU 要存取相同的 block 時,Coherency Misses 有分成兩種: - True sharing misses - 是真的因為該 block 的資料要維持一致性而造成的 miss - 像上面提到的,如果某個 block 處於 Shared state,那麼要發起寫入時一定會送出 write miss - False sharing misses - 但是我們知道一個 block 內可能會放有很多資料,但是因為他們都在同個 block 內,所以可以會發生 A 資料的更新導致了 B 資料的 invalidate,例如下圖 <iframe src="https://drive.google.com/file/d/1PBAddUCgcCR7_34rDsH8KTzPK5UaRxti/preview" height="480"></iframe> 這圖的假設是一開始 P1 跟 P2 兩個核心內的某一個 block 內,有著 x1 跟 x2 兩個資料,並且當前是 Shared state: - 第一時刻,P1 想要 write x1,根據上面第一個狀態圖,可知 P1 會向 Bus 發送「write miss」 - 這個 miss 是因為想要 write x1 而引起的,所以是 **True (sharing) miss** - 但是此時 P1 該 block 就會進入 Exclusive,P2 的就會進入 Invalid - **而倒楣的 x2 因為跟 x1 同個 block,所以害他也跟著變 Invalid** - 第二時刻,P2 想要 read x2,因為 P2 該 block 目前是 invalid,可知 P2 會向 Bus 發送「read miss」 - **這個 miss 是因為剛剛的 write x1 所導致的 invalid,所以是 False miss** - 而此根據上面的狀態圖,P1 跟 P2 的該 block 都會進入 shared state - **倒楣的 x1 也就因為這樣進到了 shared state** - 第三時刻,P1 想要 write x1,因為 P1 該 block 目前是 shared,可知 P1 會向 Bus 發送「write miss」 - **這個 miss 是因為剛剛 read x2 而引起的,所以是 False (sharing) miss** - 但是此時 P1 該 block 就會進入 Exclusive,P2 的就會進入 Invalid - 而倒楣的 x2 因為跟 x1 同個 block,所以害他也跟著變 Invalid - 這件事跟剛剛第一時刻一模一樣,歷史總是驚人的相似 - 第四時刻,P2 想要 write x2,因為 P2 該 block 目前是 invalid,可知 P2 會向 Bus 發送「write miss」 - **這個 miss 是因為剛剛的 write x1 所導致的 invalid,所以是 False miss** - 而此根據上面的狀態圖,P1 的該 block 會進入 invalid state - 而 P2 因為是寫入操作,所以有最新的資料,目前在 Exclusive state - **倒楣的 x1 也就因為這樣進到了 invalid state** - 第五時刻,P1 想要 read x2,因為 P1 該 block 目前是 invalid,可知 P1 會向 Bus 發送「read miss」 - 這時有趣了,**這個 miss 是因為剛剛 write x2 而引起的**,加上現在要 read x2 - **所以現在是屬於True (sharing) miss** - 然後 P1 跟 P2 的該 block 就都進入了 shared state,倒楣的 x1 又.... --- # Roofline model ## 1. 多處理器效能基準測試 (Benchmarks) 在介紹模型之前,投影片列出了幾種常見的平行處理效能測試標準: * **Linpack:** 矩陣線性代數運算(常用於 Top500 超級電腦排名)。 * **SPECrate:** 平行執行 SPEC CPU 程式,測試任務級 (Job-level) 平行度。 * **SPLASH / PARSEC:** 針對共享記憶體 (Shared Memory) 的應用程式基準測試,包含多種核心運算與應用場景。 --- ## 2. Roofline Model (屋頂模型) 核心概念 這個模型將硬體極限與軟體特性結合在一張圖表上,幫助開發者判斷瓶頸所在。 ![image](https://hackmd.io/_uploads/By0Tu4XfZx.png) ## **A. 兩個關鍵參數** 模型主要由以下兩個參數構成座標軸: 1. **X 軸 - 運算強度 (Arithmetic Intensity):** * 定義:每存取一個 Byte 的記憶體,進行了多少次浮點運算 (FLOPs)。 * 公式:$\frac{\text{Floating-Point Ops}}{\text{Bytes Accessed}}$ * 意義:反映演算法對資料的重複利用率。強度越高,代表對記憶體頻寬的需求相對越低。 2. **Y 軸 - 可達到的效能 (Attainable GFLOPs/sec):** * 系統實際能跑出的運算速度。 ## **B. 「屋頂」的組成 (The Roof)** 圖表中的「屋頂」形狀由兩條線組成,代表硬體的物理極限: 1. **斜線部分 (Memory Bandwidth Limited):** * 受限於 **Peak Memory Bandwidth (記憶體頻寬峰值)**。 * 當運算強度較低時,效能卡在==記憶體傳輸速度==,CPU 運算單元在等待資料。 2. **水平線部分 (Computation Limited):** * 受限於 **Peak Floating-Point Performance (浮點運算峰值)**。 * 當運算強度夠高(資料讀進來後被重複運算很多次),效能瓶頸就會轉移到 ==CPU 的運算速度==上。 ## **C. 效能公式** 系統能達到的效能是兩者的最小值: $$ \displaylines{ Attainable\ GFLOPs/sec = \\ \min(\text{Peak Memory BW} \times \text{Arithmetic Intensity},\ \text{Peak FP Performance}) } $$ - 對照上圖的話,$\text{Peak FP Performance}$ 就是 16 GFlops/sec - 意思就是 ==CPU 的運算速度上限==是 16 GFlops/sec - $\text{Peak Memory BW} \times \text{Arithmetic Intensity}$ 得到的就是斜線上的 y 值 - 從 x = 1 的位置我們可以知道 $\text{Peak Memory BW}$ 就是 16 bytes / sec - 意思就是 ==記憶體傳輸速度上限是== 16 bytes / sec - 所以 x = $\frac{1}{4}$ 的位置,剛好乘上 16 就會得到 4 GFlops/sec :::warning 根據公式我們可以知道: - 斜直線區域的公式就是 **運算效能=記憶體最大帶寬×運算強度** - 在這區域內,**對於某個運算強度 $x$,你的上限受記憶體最大帶寬影響** - 最大帶寬越高,**$x$ 強度下**的運算效能越高 - 因此才說是受記憶體帶寬影響 - 水平線區域就是 **最大運算效能** - 在這區域內,**對於某個運算強度 $y$,你的上限受最大運算效能影響** - 最大運算效能越高,**$y$ 強度下**的運算效能越高 - 因此才說是受最大運算效能影響 ::: ## 3. 演算法的運算強度光譜 ![image](https://hackmd.io/_uploads/r1199N7GZx.png) 不同類型演算法的運算強度,決定了它們落在 Roofline Model 的哪個位置: * **低強度 (容易受限於記憶體):** 稀疏矩陣 (Sparse Matrix)、結構化網格 (Structured Grids)。 * **中強度:** 頻譜方法 (FFTs)。 * **高強度 (容易受限於運算能力):** 稠密矩陣 (Dense Matrix, 如 BLAS3)、N-body 粒子模擬。 --- ### 4. 系統比較範例 (Opteron X2 vs. X4) 投影片最後用 AMD Opteron X2 (雙核) 與 X4 (四核) 的比較來說明模型價值: ![image](https://hackmd.io/_uploads/Byvo_4mGZe.png) * **情境:** X4 的核心數是 X2 的兩倍(理論運算峰值倍增),但兩者共用相同的記憶體系統(頻寬相同)。 * **圖表分析:** * **左側 (低運算強度):** 兩條線重疊。因為瓶頸是記憶體頻寬,增加核心數(X4)無法提升效能。 * **右側 (高運算強度):** X4 的「屋頂」比較高。只有當程式的運算強度夠高,或者工作集 (Working Set) 能塞進 Cache (避免存取主記憶體) 時,X4 才能發揮出比 X2 更高的效能。 ### 總結 這個模型告訴我們:**單純增加 CPU 核心數或時脈不一定能變快**。如果你的程式落在 Roofline 的左側斜坡(記憶體受限),你應該優化記憶體存取(提升運算強度);如果落在右側平頂(運算受限),你才需要考慮向量化指令或更多核心。 # Bisection Bandwidth --- CMP chip multi processor = multicore 透過 router 來做資料溝通(packet switch),每個核心就好像一個節點 又叫做 network on chip L1 屬於 private 的 cache, L2 雖然物理上是分布的,但是實際上是屬於 shared 的 cache 老師說現在核心很多的多半是用這種 大小核 for energy efficiency,因為有時候大核能力太強了,比較耗電 --- # Hardware Multithreading 這是加速具有超純量技術的 CPU 的一個技巧,讓 CPU 可以在多個 thread 之間切換,甚至並行。 ![image](https://hackmd.io/_uploads/rkoOaNQz-e.png) 上圖是 4 stage 的 pipeline,一個 row 代表一個 cycle - 可以看到 Superscalar 有些時候是空白的,代表該時候資源是沒有被利用的,會造成浪費;這些空白可能是因為 branch 導致的 NoOP 或是某些 hazard 的 stall。 - 所以我們希望不要有空白,也就是空白的時候就換別的 thread 去執行。 - Fine-Grained 就是大家輪流執行一個 stage,這樣就很難會有空白了 - 又叫做 Round robin - Coarse-Grained 是直到 CPU 發現有空白的時候才換 thread 執行 但是要注意,超純量是指令級的並行,你可以發現一個 cycle 內就只有一個 thread 的指令。 最右邊是多核心處理器,一個處理器內有多個核心,自然就可以同時執行不同的 thread。 此外還有一個更著名的,Intel 稱作超執行緒,在有超純量的指令級並行的情況下,同時達成執行緒級並行: ![image](https://hackmd.io/_uploads/S19N8F0zbl.png) 就是最右邊的 SMT (Simultaneous-Multithreading),讓一個 cycle 可以運行不同 thread 的指令 >很像 OFDMA --- SIMD 像是矩陣相乘,一次需要很多資料 並且由於一次只需要一次 fetch ,所以比較節能,因為 fetching 其實很耗電的,所以 SIMD 效能會比 MIMD 會比較好 而且也可以讓寫 code 的人不需要用平行化的方式去思考演算法(比較好想),物理層面都做好了 SIMD 隨著趨勢演進,就是讓一個暫存器內可以一次攜帶更多 Data 進來,前提是要保持這些資料是連續的且 aligned 的,才可以進行辨識。 Vector Architectures 好像是專門用來矩陣運算的架構? 總之就是我們設計一種很酷的暫存器,他可以存放 n 個 m bit 的值,每個 m bit 之間是獨立的。 這種暫存器需要配套的指令支援,像是 RISCV 的 V 擴展。 其用法就是可以一次性的將 2 個 n 個 m bit 的值,每個 row 各自相加等等的操作;也算是簡化了平行演算法,並且因為省去了 loop,還可以避免 control hazard 但相對的,硬體也要做出調整, ALU 必須要修改成很多個 ALU 協同運作,例如某個 ALU 負責計算第 0, 4, 8... 個 row 的值 interleaved 是之前提到過的 memory bank,也就是記憶體中的資料會分成不同的 bank 來存放,可能第一個 bank 放第餘數是 0 byte 的資料等等 MLPerf 是個專門用來比較 ML 的 Benchmark --- 這幾個章節(第 51 頁至 58 頁)主要在介紹如何利用 **Data-Level Parallelism(資料級平行化)** 來提升效能,也就是「一個指令同時處理多筆資料」。 這裡將技術分成了兩大類來探討:**SIMD 多媒體擴充指令集** 與 **向量架構 (Vector Architectures)**。 以下是詳細的章節重點說明: ### 1. 運算分類與 SIMD 概念 (Page 51-52) * **分類 (Flynn's Taxonomy):** * [cite_start]投影片首先釐清了電腦架構的分類。傳統單核心是 **SISD** (單一指令單一資料),而這裡要講的是 **SIMD** (單一指令多重資料) [cite: 739]。 * **SIMD 的核心精神:** * [cite_start]**效率:** 只需要讀取一次指令 (Fetch),就能對一整排資料進行運算,這比 MIMD (多指令多資料) 更省電 [cite: 755-756]。 * [cite_start]**應用場景:** 非常適合處理矩陣運算、影像處理或聲音訊號,因為這些資料通常都是一整塊且需要進行相同的運算 [cite: 744-746]。 ### 2. SIMD 多媒體擴充指令集 (Multimedia Extensions) (Page 53) 這是現代 CPU(如 Intel/AMD x86)常見的實作方式。 * **背景:** 許多媒體資料(如像素的 R、G、B)只需要 8-bit 或 16-bit,但 CPU 暫存器通常是 64-bit。 * [cite_start]**作法:** 將長暫存器切分,例如一個 64-bit 暫存器可以同時裝 8 個 8-bit 的數字,一次加法就能算完 8 個像素的亮度調整 [cite: 765-767]。 * **演進歷史:** * **Intel MMX (1996):** 64-bit 運算。 * **SSE (1999):** 128-bit 運算,支援浮點數。 * [cite_start]**AVX (2010):** 256-bit 運算 [cite: 768-774]。 * [cite_start]**限制:** 資料在記憶體中必須是**連續且對齊 (Aligned)** 的,否則無法有效率讀取 [cite: 775]。 ### 3. 向量架構 (Vector Architectures) (Page 54-57) 這是一種比上述 SIMD 擴充指令更進階、更靈活的架構(投影片以 RISC-V Vector 為例)。 * **運作方式:** * [cite_start]使用專門的「向量暫存器」(Vector Registers),可以一次讀入大量的資料元素 [cite: 779]。 * [cite_start]**Gather / Scatter:** 這是向量架構的一大特點。它支援從記憶體中「收集 (Gather)」分散的資料到暫存器,運算完再「分散 (Scatter)」寫回,不像傳統 SIMD 被限制在連續記憶體 [cite: 780-783]。 * **程式碼比較 (DAXPY 範例):** * 投影片比較了 $Y = a \times X + Y$ 的程式碼。 * [cite_start]**傳統 RISC-V:** 需要寫迴圈 (Loop),每次只算一個數,還要處理索引增加與跳轉指令,指令數多 [cite: 819-846]。 * [cite_start]**向量 RISC-V:** 幾乎沒有迴圈,幾個指令 (`fld.v`, `fmul.d.vs`, `fadd.d.v`) 就能算完一整排資料,大幅減少了指令讀取的頻寬需求 [cite: 847-862]。 * [cite_start]**優勢:** 編譯器更容易優化,因為它明確告訴硬體「這裡沒有迴圈相依性 (Loop-carried dependences)」,且比 MMX/SSE 這種特定擴充指令更通用 [cite: 867-872]。 ### 4. 硬體實作:多通道 (Multiple Lanes) (Page 58) * **概念:** 為了讓向量運算更快,硬體內部會將運算單元切分成多個 **Lanes (通道)**。 * **運作:** * 假設有 4 個通道 (Lane 0 ~ Lane 3)。 * Lane 0 負責計算第 0, 4, 8... 個元素。 * Lane 1 負責計算第 1, 5, 9... 個元素。 * [cite_start]這樣可以讓硬體資源利用率最大化,同時並行處理多個資料點 [cite: 875-910]。 ### 總結 這幾頁是從**軟體概念**到**硬體實作**的推進: 1. **SIMD 概念:** 一個指令算多筆資料。 2. **Multimedia Extensions (如 AVX):** x86 CPU 上的實作,要求資料連續。 3. **Vector Architectures:** 更高階的架構,支援 Gather/Scatter,程式碼更精簡。 4. **Lanes:** 硬體如何透過多通道並行來實現上述架構。

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password
    or
    Sign in via Facebook Sign in via X(Twitter) Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    By signing in, you agree to our terms of service.

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully