AMPERE ALTRA和AMPERE ALTRA MAX 的鎖機制
讓我們先來了解一些基本的問題。Arm 在 Arm?v8.2-A 架構中引入了大型系統擴展(Large System Extensions, LSE),它用單個原子指令取代了鎖操作的指令序列。這里 (https://dev.to/aws-builders/large-system-extensions-for-aws-graviton-processors-3eci)是一個非常不錯的總結。雖然舊的 Arm 版本在功能上可以很好地工作,但隨著核心數量的增加和鎖的爭用更加頻繁,預計性能會受到影響。Ampere Altra 和 Ampere Altra Max 支持 LSE,并配備了可擴展的鎖性能。
為了說明使用的指令之間的差異,讓我們看看 gcc 的處理方式
__atomic_fetch_add()。在本例中,將鎖值減 1:
__atomic_fetch_add(&lockptr->lockval, -1, __ATOMIC_ACQ_REL);
使用* -march =armv8.2-a*選項編譯,編譯器生成帶有原子指令的代碼:
998: f8f60280 ldaddal x22, x0, [x20]
另一方面,設置* -march =armv8-a*(不支持LSE),生成一個不同的序列:
9a4: c85ffe60 ldaxr x0, [x19] 9a8: d1000400 sub x0, x0, #0x1 9ac: c801fe60 stlxr w1, x0, [x19] 9b0: 35ffffa1 cbnz w1, 9a4
為了使序列具有原子性,需要一個單獨的監視器。ldaxr 獲得一個地址標記,在本例中為 [x19]。然后執行減法,然后存儲回內存位置。但是,只有當存儲(store)時的標記與加載(Load)中的標記匹配時,存儲才會成功。stlxr 之后的條件分支 cbnz 檢查存儲是否成功,這意味著 load 和 store 中的標記匹配。如果不是,則跳回序列的開頭,在本例中是地址 0x9a4。
這里值得注意的是,如果沒有 LSE 指令,這個指令序列可能要執行幾次才能被認為成功。使用 LSE, ldaddal 指令可以保證以一條指令完成,不需要循環。
圖 1 顯示了當線程數從 1 增加到 80 時,使用 LSE 和不使用 LSE 時每秒獲得排他鎖的性能差異。
圖 1
通常,Compare 和 Exchange 硬件指令用于在軟件中實現鎖。需要注意的是,這些指令必須是原子指令。
原子在這里是什么意思呢?這些指令首先獲得包含鎖的緩存行(Cache Line)的所有權,并將其加載到 CPU 的本地緩存中。然后將當前值與隨指令提交的比較值進行比較。如果相等,作為指令一部分提交的新值將替換當前值。如果不相等,則保持當前值。這方面的原子性意味著整個序列由一個線程執行,而沒有其他線程訪問緩存行,由硬件保證。
鎖的種類
在軟件中可以實現不同類型的鎖,如互斥鎖(mutexes)、票據鎖(ticket)和自旋鎖(spinlocks)。如前所述,不同的鎖類型在軟件中實現,硬件提供類似 cmpxchg 或 fetchadd 的指令。相同的鎖類型在不同的硬件上運行,只有使用的指令不同。
如何實現鎖機制
這是一個非常重要的問題。讓我們把它分解成兩個選項:1) 使用可用的庫和 2) 使用原子指令來實現專有的鎖定算法。
選項1有幾個優點。庫已經存在,不需要自定義實現,而且經過了充分測試,通常將會在未來的庫版本中進行維護。例如pthread_mutex_lock和pthread_rwlock。聽起來不錯,那么有什么缺點呢? 缺乏統計數據可能是一個問題。沒有向應用程序返回任何信息,報告旋轉(spins)或線程被調度出多少次。此外,庫實現可能不太適合某些應用程序,因為庫更通用。
pthread_mutex_lock
https://pubs.opengroup.org/onlinepubs/007908799/xsh/pthread_mutex_lock.html
選項 2 更復雜。它需要實現鎖定函數并維護它們。但是,它可以獲得一些好處,因為它是專門為應用程序設計的。鎖定原語和原子指令可以通過內聯匯編(inline assembly)或利用編譯器的支持來實現。同樣,使用內聯程序集編寫代碼需要應用程序維護該段代碼。
對于編譯器,gcc提供了atomic built-in function,它允許應用程序使用低級函數,這些函數將被編譯成 Arm 原子指令。這些內置函數為應用程序提供了原子指令和內存序指令的不同方法。代碼也更易于移植。但是,使用*-mcpu或-march*的正確設置來編譯應用程序來生成 Arm LSE 指令是很重要的。Ampere Altra 和 Ampere Altra Max 使用 Neoverse-n1 架構,其中就包括LSE。
atomic built-in function
https://gcc.gnu.org/onlinedocs/gcc/_005f_005fatomic-Builtins.html
然而,使用原子指令實現鎖需要設計決策。如果鎖被持有,旋轉(spinning)是否合理?轉幾圈?線程在旋轉一定次數后如果不成功,是否應該放棄?在旋轉環中需要后退,還是直線旋轉? 這些只是需要解決的問題中的一部分。
其他的設計決策
1鎖的數據類型和大小
通常,應用程序使用 int 或long 作為鎖。用于原子操作的內置函數(Built-in functions)從內存中讀取鎖值。如果應用程序也直接讀取鎖值,鎖類型應該有“volatile”前綴,例如 volatile long。使用 volatile,編譯器生成從內存中讀取數據的指令。否則,該值可能在寄存器中而沒有更新,從而錯過對鎖位置的更新。
2鎖的粒度
由于競爭,粗粒度鎖有可能成為性能瓶頸。另一方面,如果每個資源都有自己的鎖來保護,那么將需要大量內存來存儲鎖。必須是一種折衷設計,以避免任何不利因素。
3鎖對齊
編譯器對結構進行正確對齊。如果應用程序管理自己的內存,那么鎖的位置可能與鎖的大小不一致。在最壞的情況下,鎖可能跨越兩條緩存行。在 AArch64 上,對未對齊鎖的原子操作會導致 SIGBUS (硬件向操作系統發出信號,表明 CPU 不能尋址內存地址的總線錯誤,在這種情況下是由于未對齊訪問)。從積極的方面來看,獲得 SIGBUS 需要固定對齊,而不是隱藏很少被發現的性能問題。
4假共享
虛假分享是什么意思?即同一高速緩存行上的獨立數據對性能有不良影響,鎖數組就屬于這一類。這些鎖保護不同的關鍵區域。但是,對同一緩存行上鎖的原子操作會影響該緩存行上的所有鎖。重要的是,原子性不是針對鎖本身,而是針對包含鎖的整個緩存行。
5在 cmpxchg 之前做測試
在執行 cmpxchg 指令之前讀取自旋循環(spinloop)中的鎖值可能對爭用鎖有利。Cmpxchg 需要緩存行的所有權,而test將以共享模式獲取緩存行,從而避免失效。然而,這可能會增加執行的 spin 數量。
6如果可能的話,在無鎖時
使用fetchadd 而不是 cmpxchg
釋放鎖需要返回線程為獲取鎖而執行的操作。Cmpxchg,特別是對于共享鎖或讀寫鎖,需要一個循環,并且由于鎖值的變化而可能會重試操作。然而,fetchadd 不需要循環,沒有比較,因此它會成功。
7鎖定持有時間
通常指臨界區域內的指令數或在臨界區域內花費的時間。時間是一個更好的度量標準,因為臨界區域可能只有很少的指令。然而,所有的指令都可以從內存中讀取。嵌套鎖屬于同一類別。無法獲得內部鎖以及 spinning 或 sleeping 會影響外部鎖的保持時間。減少關鍵區域的保持時間總是好的,如果數據在本地緩存而不是內存中就更好了。
8搶占
不幸的是,線程在持有鎖時可能會被重新調度。如果鎖處于獨占模式,這意味著沒有其他線程能夠獲得鎖。在考慮性能問題時,要記住這一點。較短的保持時間將降低搶占的可能性。
內存序
如前所述,正確的內存排序指令對于正確性很重要。AArch64 遵循一種寬松的內存模型。使用 LSE, AArch64 指令強制執行特定的內存順序。例如,cmpxchg 指令集有獲取(CASA 指令)、釋放(CASL 指令)以及獲取和釋放(CASAL 指令)的版本。硬件保證這些指令遵循其特定指令的內存模型。這取決于軟件使用適當的指令。通常,acquire 用于鎖獲取,Release 用于鎖釋放。但是,如果應用程序在無鎖之后讀取數據(例如,如果該鎖有任何等待程序),那么空閑程序的 release 語義可能會導致問題,因為對等待程序結構的讀取可能會提升到空閑程序之上,因此在空閑程序之后,寄存器中就會出現陳舊的數據。在這些情況下,最好使用 acquire 和 release 語義。同樣,這取決于應用程序實現。gcc 編譯器直接在內置函數中使用這些指令,如下列網址所示。
https://gcc.gnu.org/onlinedocs/gcc/_005f_005fatomic-Builtins.html
總結
Ampere 系列處理器正以其持續增加的核心數量不斷挑戰性能極限,并具備使用鎖的多線程應用程序可擴展性的所有要素。使用 LSE,在硬件中提供原子指令以獲得更好的鎖性能。正如我們在本文所看到的,應用程序開發人員可以通過鎖庫或正確實現鎖定算法來充分利用這些指令。
關于 Ampere Computing
Ampere Computing 是一家現代化半導體企業,致力于塑造云計算的未來,并推出了世界上首款云原生處理器。為可持續云而生,Ampere 云原生處理器兼具最高性能和最佳每瓦性能,助力加速多種云計算應用的交付,為云提供行業領先的性能、能效和可擴展性。
審核編輯:湯梓紅
-
處理器
+關注
關注
68文章
19160瀏覽量
229115 -
ARM
+關注
關注
134文章
9045瀏覽量
366809 -
內存
+關注
關注
8文章
2999瀏覽量
73882 -
指令
+關注
關注
1文章
606瀏覽量
35650 -
Ampere
+關注
關注
1文章
64瀏覽量
4533
發布評論請先 登錄
相關推薦
評論