事務記憶體支援¶
POWER 核心對該特性的支援目前僅限於支援使用者程式使用它。核心本身目前不使用它。
此檔案旨在總結 Linux 如何支援它以及您可以從使用者程式中期望的行為。
基本概述¶
硬體事務記憶體在 POWER8 處理器上受支援,它是一種支援不同形式的原子記憶體訪問的特性。提供幾個新指令來分隔事務;事務保證要麼以原子方式完成,要麼回滾並撤消任何部分更改。
一個簡單的事務如下所示
begin_move_money:
tbegin
beq abort_handler
ld r4, SAVINGS_ACCT(r3)
ld r5, CURRENT_ACCT(r3)
subi r5, r5, 1
addi r4, r4, 1
std r4, SAVINGS_ACCT(r3)
std r5, CURRENT_ACCT(r3)
tend
b continue
abort_handler:
... test for odd failures ...
/* Retry the transaction if it failed because it conflicted with
* someone else: */
b begin_move_money
“tbegin”指令表示起始點,“tend”表示結束點。在這些點之間,處理器處於“事務”狀態;如果系統內沒有與其他事務或非事務訪問發生衝突,則任何記憶體引用都將一次性完成。在此示例中,如果其他處理器沒有觸及 SAVINGS_ACCT(r3) 或 CURRENT_ACCT(r3),則事務完成,就像它是正常的直線程式碼一樣;已執行從當前帳戶到儲蓄帳戶的原子轉賬。即使使用了普通的 ld/std 指令(注意沒有 lwarx/stwcx),要麼 *SAVINGS_ACCT(r3) 和 CURRENT_ACCT(r3)* 都將被更新,要麼都不會被更新。
如果與此同時,與事務訪問的位置發生衝突,CPU 將中止事務。暫存器和記憶體狀態將回滾到“tbegin”時的狀態,控制將從“tbegin+4”繼續。第二次將執行跳轉到 abort_handler 的分支;中止處理程式可以檢查失敗的原因並重試。
檢查點暫存器包括所有 GPR、FPR、VR/VSR、LR、CCR/CR、CTR、FPCSR 和一些其他狀態/標誌暫存器;有關詳細資訊,請參見 ISA。
事務中止的原因¶
與其他處理器使用的快取行衝突
訊號
上下文切換
有關將中止事務的所有內容的完整文件,請參見 ISA。
系統呼叫¶
從活動事務中發出的系統呼叫將不會被執行,並且該事務將被核心以失敗程式碼 TM_CAUSE_SYSCALL | TM_CAUSE_PERSISTENT 判定失敗。
從暫停事務中發出的系統呼叫將像往常一樣執行,並且事務不會被核心顯式判定失敗。但是,核心執行系統呼叫的方式可能會導致硬體判定事務失敗。系統呼叫以暫停模式執行,因此任何副作用都將是持久的,獨立於事務成功或失敗。核心不提供關於哪些系統呼叫將影響事務成功的保證。
如果呼叫是透過庫進行的,則在依賴於在活動事務期間中止的系統呼叫時必須小心。庫可能會快取值(這可能會給出成功的假象)或執行在進入核心之前導致事務失敗的操作(這可能會產生不同的失敗程式碼)。例如 glibc 的 getpid() 和惰性符號解析。
訊號¶
在事務期間傳遞訊號(同步和非同步)提供了第二個執行緒狀態 (ucontext/mcontext) 來表示第二個事務暫存器狀態。訊號傳遞 “treclaim” 來捕獲兩種暫存器狀態,因此訊號會中止事務。傳遞給訊號處理程式的常規 ucontext_t 表示檢查點/原始暫存器狀態;訊號似乎出現在 “tbegin+4”。
如果 sighandler ucontext 設定了 uc_link,則已傳遞第二個 ucontext。為了將來的相容性,應檢查 MSR.TS 欄位以確定事務狀態 -- 如果是,則 uc->uc_link 中的第二個 ucontext 表示訊號點的活動事務暫存器。
對於 64 位程序,uc->uc_mcontext.regs->msr 是完整的 64 位 MSR,其 TS 欄位顯示事務模式。
對於 32 位程序,mcontext 的 MSR 暫存器只有 32 位;高 32 位儲存在第二個 ucontext 的 MSR 中,即 uc->uc_link->uc_mcontext.regs->msr 中。頂部字包含事務狀態 TS。
但是,基本訊號處理程式不需要知道事務,只需從處理程式返回即可正確處理事情
事務感知訊號處理程式可以從第二個 ucontext 讀取事務暫存器狀態。例如,崩潰處理程式需要這樣做才能確定導致 SIGSEGV 的指令地址。
示例訊號處理程式
void crash_handler(int sig, siginfo_t *si, void *uc)
{
ucontext_t *ucp = uc;
ucontext_t *transactional_ucp = ucp->uc_link;
if (ucp_link) {
u64 msr = ucp->uc_mcontext.regs->msr;
/* May have transactional ucontext! */
#ifndef __powerpc64__
msr |= ((u64)transactional_ucp->uc_mcontext.regs->msr) << 32;
#endif
if (MSR_TM_ACTIVE(msr)) {
/* Yes, we crashed during a transaction. Oops. */
fprintf(stderr, "Transaction to be restarted at 0x%llx, but "
"crashy instruction was at 0x%llx\n",
ucp->uc_mcontext.regs->nip,
transactional_ucp->uc_mcontext.regs->nip);
}
}
fix_the_problem(ucp->dar);
}
當處於活動事務中接收到訊號時,我們需要小心堆疊。堆疊有可能在 tbegin 之後向上移動。這裡明顯的例子是 tbegin 在 tend 之前返回的函式內部被呼叫。在這種情況下,堆疊是檢查點事務記憶體狀態的一部分。如果我們以非事務方式或暫停方式覆蓋此內容,我們將遇到麻煩,因為如果我們獲得 tm 中止,程式計數器和堆疊指標將返回到 tbegin,但我們的記憶體堆疊將不再有效。
為了避免這種情況,當在活動事務中接收到訊號時,我們需要使用來自檢查點狀態的堆疊指標,而不是推測狀態。這確保了訊號上下文(寫入 tm 暫停)將被寫入回滾所需的堆疊下方。由於 treclaim,事務被中止,因此在 tbegin 和訊號之間寫入的任何記憶體都將被回滾。
對於在非 TM 或暫停模式下接收的訊號,我們使用常規/非檢查點堆疊指標。
在 sighandler 內部啟動並在從 sighandler 返回到核心時暫停的任何事務都將被回收和丟棄。
核心使用的失敗原因程式碼¶
這些在 <asm/reg.h> 中定義,並區分核心中止事務的不同原因
TM_CAUSE_RESCHED
執行緒已重新排程。
TM_CAUSE_TLBI
軟體 TLB 無效。
TM_CAUSE_FAC_UNAV
FP/VEC/VSX 不可用陷阱。
TM_CAUSE_SYSCALL
來自活動事務的系統呼叫。
TM_CAUSE_SIGNAL
訊號已傳遞。
TM_CAUSE_MISC
當前未使用。
TM_CAUSE_ALIGNMENT
對齊錯誤。
TM_CAUSE_EMULATE
觸控記憶體的模擬。
使用者程式的中止處理程式可以檢查這些程式碼作為 TEXASR[0:7]。如果設定了位 7,則表示該錯誤被認為是永續性的。例如,TM_CAUSE_ALIGNMENT 將是永續性的,而 TM_CAUSE_RESCHED 將不會。
GDB¶
GDB 和 ptrace 目前不感知 TM。如果在事務期間停止,它看起來就像事務剛剛開始(呈現檢查點狀態)。然後無法繼續該事務,並將採用失敗處理程式路徑。此外,事務的第二個暫存器狀態將無法訪問。目前可以在使用 TM 的程式中使用 GDB,但在事務中的部分中不能明智地使用。
POWER9¶
POWER9 上的 TM 在儲存完整的暫存器狀態時存在問題。這在此提交中描述
commit 4bb3c7a0208fc13ca70598efd109901a7cd45ae7
Author: Paul Mackerras <paulus@ozlabs.org>
Date: Wed Mar 21 21:32:01 2018 +1100
KVM: PPC: Book3S HV: Work around transactional memory bugs in POWER9
為了解決這個問題,不同的 POWER9 晶片以不同的方式啟用了 TM。
在 POWER9N DD2.01 及以下版本中,TM 已停用。即未設定 HWCAP2[PPC_FEATURE2_HTM]。
在 POWER9N DD2.1 上,TM 由韌體配置為在發生 tm 暫停時始終中止事務。因此,tsuspend 將導致事務中止並回滾。核心異常也會導致事務中止並回滾,並且不會發生異常。如果使用者空間構造了一個啟用 TM 暫停的 sigcontext,則核心將拒絕該 sigcontext。此模式透過設定 HWCAP2[PPC_FEATURE2_HTM_NO_SUSPEND] 來向用戶通告。在此模式下未設定 HWCAP2[PPC_FEATURE2_HTM]。
在 POWER9N DD2.2 及以上版本中,KVM 和 POWERVM 模擬來賓的 TM(如提交 4bb3c7a0208f 中所述),因此為來賓啟用了 TM,即為來賓使用者空間設定了 HWCAP2[PPC_FEATURE2_HTM]。大量使用 TM 暫停的來賓(tsuspend 或核心暫停)將導致陷入 hypervisor,因此會導致效能下降。主機使用者空間已停用 TM,即未設定 HWCAP2[PPC_FEATURE2_HTM]。(儘管如果我們將來將模擬帶入主機使用者空間上下文切換,我們可能會在某些時候啟用它)。
POWER9C DD1.2 及以上版本僅適用於 POWERVM,因此 Linux 僅作為來賓執行。在這些系統上,TM 的模擬方式與 POWER9N DD2.2 上相同。
從 POWER8 到 POWER9 的來賓遷移將適用於 POWER9N DD2.2 和 POWER9C DD1.2。由於較早的 POWER9 處理器不支援 TM 模擬,因此不支援從 POWER8 到 POWER9 的遷移。
核心實現¶
h/rfid mtmsrd 怪癖¶
如 ISA 中定義的,rfid 有一個怪癖,它在早期異常處理中很有用。當在使用者空間事務中並且我們透過一些異常進入核心時,MSR 將最終變為 TM=0 和 TS=01(即 TM 關閉但 TM 暫停)。通常,核心想要更改 MSR 中的位,並將執行 rfid 來執行此操作。在這種情況下,rfid 可以具有 SRR0 TM = 0 和 TS = 00(即 TM 關閉和非事務),並且生成的 MSR 將保留之前的 TM = 0 和 TS=01(即保持暫停狀態)。這是架構中的一個怪癖,因為這通常是從 TS=01 到 TS=00(即暫停 -> 非事務)的轉換,這是一種非法轉換。
此怪癖在 rfid 的定義中的架構中描述,包含以下幾行
- if (MSR 29:31 ¬ = 0b010 | SRR1 29:31 ¬ = 0b000) then
MSR 29:31 <- SRR1 29:31
hrfid 和 mtmsrd 具有相同的怪癖。
Linux 核心在其早期異常處理中使用此怪癖。