ARM WFI和WFE指令

1. 前言

蝸蝸很早以前就知道有WFI和WFE這兩個指令存在,但一直似懂非懂。最近準備研究CPU idle framework,由於WFI是讓CPU進入idle狀態的一種方法,就下決心把它們弄清楚。

WFI(Wait for interrupt)和WFE(Wait for event)是兩個讓ARM核進入low-power standby模式的指令,由ARM architecture定義,由ARM core實現。聽着挺簡單,但怎麼會有兩個指令?它們的區別是什麼?使用場景是什麼?深究起來,還挺有意思,例如:能想象WFE和spinlock的關係嗎?

2. WFI和WFE

1)共同點

WFI和WFE的功能非常類似,以ARMv8-A爲例(參考DDI0487A_d_armv8_arm.pdf的描述),主要是“將ARMv8-A PE(Processing Element, 處理單元)設置爲low-power standby state”。

需要說明的是,ARM architecture並沒有規定“low-power standby state”的具體形式,因而可以由ARM core自行發揮,根據ARM的建議,一般可以實現爲standby(關閉clock、保持供電)、dormant、shutdown等等。但有個原則,不能造成內存一致性的問題。以Cortex-A57 ARM core爲例,它把WFI和WFE實現爲“put the core in a low-power state by disabling the clocks in the core while keeping the core powered up”,即我們通常所說的standby模式,保持供電,關閉clock。

2)不同點

那它們的區別體現在哪呢?主要體現進入和退出的方式上。

對WFI來說,執行WFI指令後,ARM core會立即進入low-power standby state,直到有WFI Wakeup events發生。

而WFE則稍微不同,執行WFE指令後,根據Event Register(一個單bit的寄存器,每個PE一個)的狀態,有兩種情況:如果Event Register爲1,該指令會把它清零,然後執行完成(不會standby);如果Event Register爲0,和WFI類似,進入low-power standby state,直到有WFE Wakeup events發生。

WFI wakeup event和WFE wakeup event可以分別讓Core從WFI和WFE狀態喚醒,這兩類Event大部分相同,如任何的IRQ中斷、FIQ中斷等等,一些細微的差別,可以參考“DDI0487A_d_armv8_arm.pdf“的描述。而最大的不同是,WFE可以被任何PE上執行的SEV指令喚醒。

所謂的SEV指令,就是一個用來改變Event Register的指令,有兩個:SEV會修改所有PE上的寄存器;SEVL,只修改本PE的寄存器值。下面讓我們看看WFE這種特殊設計的使用場景。

3. 使用場景

1)WFI

WFI一般用於cpuidle。

2)WFE

WFE的一個典型使用場景,是用在spinlock中(可參考arch_spin_lock,對arm64來說,位於arm64/include/asm/spinlock.h中)。spinlock的功能,是在不同CPU core之間,保護共享資源。使用WFE的流程是:

a)資源空閒

b)Core1訪問資源,acquire lock,獲得資源

c)Core2訪問資源,此時資源不空閒,執行WFE指令,讓core進入low-power state

d)Core1釋放資源,release lock,釋放資源,同時執行SEV指令,喚醒Core2

e)Core2獲得資源

以往的spinlock,在獲得不到資源時,讓Core進入busy loop,而通過插入WFE指令,可以節省功耗,也算是因禍(損失了性能)得福(降低了功耗)吧。

 

轉自。蝸窩科技,www.wowotech.net


評論:

lamaboy
2016-08-17 23:01
你好,,
請問 spin_lock  只是用來在不同CPU core之間,保護共享資源嗎??

對於那些單cpu 的spin_lock   有什麼不同之處呢??
wowo
2016-08-18 14:54
@lamaboy:spin的意思,就是讓某個CPU在原地打轉,這樣就可以避免它去訪問共享資源。
對於單個CPU來說,它只能順序執行(除非被中斷、異常打斷),因此沒有spin的必要,也就沒有spin_lock的概念。
單CPU需要做同步的話,就把自己的中斷關掉就行了。
randy
2016-09-01 19:15
@wowo:單核下spin lock也是有意義的:用於線程之間的同步時禁止內核搶佔,保證被中斷後仍然回到原先的線程中;用於線程上下文和中斷上下文之間的同步時根據上半部和下半部分別關中斷和關下半部
linuxer
2016-09-01 19:45
@randy:我想wowo同學的本意是:在單核情況下,spin lock退化成了禁止搶佔,其實已經脫離了spin lock的本意,因此,他才說“對於單個CPU來說,它只能順序執行(除非被中斷、異常打斷),因此沒有spin的必要”

我其實比較挑戰的是他的另外一句話“單CPU需要做同步的話,就把自己的中斷關掉就行了”,一言不合就使用關中斷這種大殺器我是反對的,可以選擇使用最適合的同步方法。
wowo
2016-09-02 08:55
@randy:是的,randy和linuxer的說法比我說的“精細”多了,多謝~~
我的風格是比較直接,不太希望把話題延伸的太寬,大家多包涵哈~~~
堅持到底
2015-11-17 11:32
arm64 smp 中,並沒有直接在 arch_spin_unlock() 裏使用 sev 來喚醒執行 wfe 的 CPU,請問樓主有沒研究過執行 wfe 的 CPU 怎麼被喚醒的?
wowo
2015-11-17 13:45
@堅持到底:當前ARM Kernel的spin_lock是不是沒有利用WFE節省功耗?
請教linuxer,ldaxrh讓CPU進入低功耗嗎?如果不會,現在僅僅用了busy loop的方式。
堅持到底
2015-11-17 14:11
@wowo:static inline void arch_spin_lock(arch_spinlock_t *lock)
{
    unsigned int tmp;

    asm volatile(
    "    sevl\n"
    "1:    wfe\n"
    "2:    ldaxr    %w0, %1\n"
    "    cbnz    %w0, 1b\n"
    "    stxr    %w0, %w2, %1\n"
    "    cbnz    %w0, 2b\n"
    : "=&r" (tmp), "+Q" (lock->lock)
    : "r" (1)
    : "cc", "memory");
}

static inline void arch_spin_unlock(arch_spinlock_t *lock)
{
    asm volatile(
    "    stlr    %w1, %0\n"
    : "=Q" (lock->lock) : "r" (0) : "memory");
}

我的 linux kernel  3.10.61,是有用到 wfe 的。
wowo
2015-11-17 14:33
@堅持到底:這兩個配合:
"    sevl\n"
    "1:    wfe\n"
wfe不會進入低功耗模式的。
堅持到底
2015-11-17 14:58
@wowo:會的。

假設 cpu0 執行下面僞代碼:

"    sevl\n"  //set event register 1
    "1:    wfe\n"  //clear event register 爲 0,執行 wfe 完畢,不睡眠。
    "2:    ldaxr    %w0, %1\n" //tmp = lock->lock, 測試 lock->lock是否有 CPU 佔用,1 爲有 CPU 佔用,0 爲沒 CPU 佔用。假設此時已經有 CPU 佔用被設置爲 1, 則非零,跳轉到 1b, wfe.
    "    cbnz    %w0, 1b\n"
linuxer
2015-11-17 15:05
@堅持到底:當沒有獲取spinlock的時候,cpu core當然會調用wfe,等待其他cpu使用sev來喚醒自己。linux kernel的ARM64代碼當然不會busy loop了,那太業餘了。具體可以參考:
http://www.wowotech.net/kernel_synchronization/spinlock.html

在ARM64中,arch_spin_unlock並沒有顯示的調用sev來喚醒其他cpu,而是通過stlr指令完成的。在ARM ARM文檔中有說:在執行store操作的時候,如果要操作的地址被標記爲exclusive的,那麼global monitor的狀態會從exclusive access變成open access,同時會觸發一個事件,喚醒wfe中的cpu。
wowo
2015-11-17 15:42
@linuxer:嗯嗯,這就對了,我也一直懷疑stlr,去memory barrier文檔中找了很久沒找到信息,原來在spin lock中。

@堅持到底:抱歉誤導您了啊,好在有大神在,哈哈。
linuxer
2015-11-17 18:27
@wowo:大神不敢當啊,我還是喜歡華南區(深圳,珠海除外)首席xxx這樣的稱號,^_^
堅持到底
2015-11-17 15:54
@linuxer:是的,感謝啊。在 6000 頁的 pdf 中找到:

The ARMv8 architecture adds the acquire and release semantics to Load-Exclusive and Store-Exclusive instructions, which allows them to gain ordering acquire and/or release semantics.

The Load-Exclusive instruction can be specified to have acquire semantics, and the Store-Exclusive instruction can be specified to have release semantics. These can be arbitrarily combined to allow the atomic update created by a successful Load-Exclusive and Store-Exclusive pair to have any of:

?
No Ordering semantics (using LDREX and STREX).
?
Acquire only semantics (using LDAEX and STREX).
?
Release only semantics (using LDREX and STLEX).
?
Sequentially consistent semantics (using LDAEX and STLEX).

In addition, the ARMv8 specification requires that the clearing of a global monitor will generate an event for the PE associated with the global monitor, which can simplify the use of WFE, by removing the need for a DSB barrier and SEV instruction.
linuxer
2015-11-17 18:29
@堅持到底:關於這個問題可以參考ARM ARM文檔中的Figure B2-5,這個圖是PE(n)的global monitor的狀態遷移圖。當PE(n)對x地址發起了exclusive操作的時候,PE(n)的global monitor從open access遷移到exclusive access狀態,來自其他PE上針對x(該地址已經被mark for PE(n))的store操作會導致PE(n)的global monitor從exclusive access遷移到open access狀態,這時候,PE(n)的Event register會被寫入event,就好象生成一個event,將該PE喚醒,從而可以省略一個SEV的指令。
堅持到底
2015-11-19 01:01
@linuxer:這裏我有個疑問。

假設 spinlock 場景:

1. cpu0 exclusive load, and exclusive store 操作 lock->lock.此時 global monitor 對於 lock->lock 的 status 依然是 exclusive.

2. cpu1 exclusive load, and wfe.

3. cpu2 exclusive load, and wfe.

4. cpu3 exclusive load, and wfe.

5. 此時只有 cpu0 能去 arch_spin_unlock(), exclusive store 操作 lock->lock, 本應該 excl -> open,會觸發 global monitor generate an event for the PE.

但是從你上一段描述和 Figure B2-5 的意思又不一致。 上面 spinlock 的場景根本不會有其他 PE 上針對 x( mark for exclusive ) 的操作了。Figure B2-5 圖中也表示 StoreExcl(Marked_address,n) 進行 excl access 操作,global monitor status 是不變的。
linuxer
2015-11-19 10:34
@堅持到底:好吧,看來我表述的不是那麼的清楚,針對你說的場景,我重新組織一下:
在cpu0調用unlock之前,各個狀態機的狀態如下:
1、cpu0上針對spink lockmemory的狀態機是open access狀態。當然,這個狀態和具體實現相關,不過,在這個場景中,沒有人關注它的狀態。
2、cpu1上針對spink lockmemory的狀態機是exclusive access狀態,這時候cpu1處於wfe
3、cpu2狀態機和cpu1相同
4、cpu3狀態機和cpu1相同


cpu0執行了spin_unlock操作,各個狀態機的遷移情況如下:
1、cpu0上針對spink lockmemory的狀態機是怎樣的呢?有人在乎嗎?需要知道它的狀態嗎?當然不需要。
2、cpu1的狀態遷移:這時候實際上產生的事件是有其他cpu(指cpu0)執行了針對marked address(指共享的spin lock memory地址)的store操作,在狀態圖上對應Store(Marked_address,!n)事件,因此,該狀態機遷移到open access狀態,這時候cpu1的Event register會被寫入event,就好象生成一個event,將cpu1喚醒
3、cpu2類似cpu1
4、cpu3類似cpu1


上面是我的理解,請參考
堅持到底
2015-11-19 23:51
@linuxer:對的,謝謝解釋啊。^_^
omind
2015-05-28 11:48
都寫到armv8了,先進啊
shoujixiaodao
2015-04-29 22:41
我也一直疑惑這兩條指令,今日才明白。如撥雲見日。感謝!
wowo
2015-04-29 23:13
@shoujixiaodao:不必客氣,大家多交流~~
rockwu
2015-01-26 13:44
核心是WFI只能由cpu硬件來喚醒,WFE除了硬件喚醒之外還支持軟件喚醒。所以WFE的自由度更好,只要WFE和SEV成對使用。不知道理解是否正確。
wowo
2015-01-26 22:32
@rockwu:應該就是您說理解的那個樣子。
不過是不是必須“由CPU硬件喚醒”,這個不能太武斷,因爲到底什麼是硬件的範疇,不太好界定。
haichunzhao
2014-12-11 18:10
剛註冊了個賬號
不論cpuidle和平臺sleep最後走的都是WFI。WFE沒研究過,看到你寫的,在spinlock中使用的話,感覺和信號量差不多了。
wowo
2014-12-11 18:26
@haichunzhao:sleep應該是ARM core或者ARM cpu的低功耗狀態,估計會在WFI之後,再關閉一些其它的東西。不知道是不是所有CPU都一樣。
行爲確實和信號量類似,但信號量依賴軟件的調度,而使用WFE的spinlock是硬件行爲。
sea
2015-01-15 11:30
@wowo:wowo,“cpuidle和平臺sleep最後走的都是WFI”,那sleep會調用cpuidle framework來走WFI嗎?如果不是,那不就意味着sleep也就相當於使用的是《Linux cpuidle framework(1)_概述和軟件架構》中“曾經有過一段時間的cpuidle過程”。而且像android這種移動端os,能夠進入到idle進程的情況下,應該早就進行suspend操作了吧。這樣的話cpuidle framework不就沒什麼意義了。或者說suspend也是使用cpuidle framework來走WFI,又或者有其它的應用場景?
wowo
2015-01-15 13:18
@sea:1. sleep這個詞可能過於含糊,不同平臺的實現可能不同,因此是否會使用WFI,是不一定的。
2. WFI只是ARM體系結構的一個指令,誰會使用這個指令,spinlock?cpuidle?還是sleep?是沒有限制的,因此也不一定非要走cpuidle framework。
3. 你說的很對,Android選擇了autosleep作爲自身電源管理的主要手段,cpuidle framework就沒有太多用處了,甚至,大多數的Android設備,沒有啓用cpuidle framework功能。
4. 個人意見,cpuidle framework的主要使用場景,是在服務器系統中,這些系統的cpu core動輒就幾十個,對系統響應能力的要求又比較高,通過cpuidle,既可以保證性能,也可以節省很多power。
shoujixiaodao
2015-04-29 22:52
@sea:說說我的見解。只限於手機場景。不論cpuide和sleep雖都調用wfi,但流程不同。很多情況下是cpu idle狀態。比如你把手機亮屏不做任何操作有可能進入cpu idle,滅屏聽fm也可能會進入。
wowo
2015-04-29 23:12
@shoujixiaodao:我接觸的手機平臺不多,不知道它們是否使能了cpuidle功能。從道理上來說,確實是這樣的。
shoujixiaodao
2015-04-29 22:45
@wowo:我的理解是:信號量依賴軟件的調度,所以cpu還幹活。而使用WFE的spinlock。則cpu進入低功耗模式。不幹活了。
wowo
2015-04-29 23:11
@shoujixiaodao:是的,完全正確,所以從這個角度看,spinlock並不是那麼可怕了。
tigger
2014-12-11 10:35
hi wowo
但是這個arch_spin_lock 使用到的地方很少啊。
好像只有raw_spin_lock_irqsave 會用到這個地方。
wowo
2014-12-11 10:39
@tigger:應該不會,不過我沒有細看,你可以順着這個調用順序看一下:__lock_acquire-->mark_lock-->graph_lock-->arch_spin_lock(arch/arm64/include/asm/spinlock.h)。
PS:有沒有同學把spinlock分析一下啊?還挺有意思啊。
tigger
2014-12-11 10:40
@wowo:linuxer 之前分析過的啊
wowo
2014-12-11 11:11
@tigger:是嗎?我怎麼不記得了呢?
linuxer
2014-12-11 11:57
@wowo:內核同步的第四篇就是spin lock,不過我還沒有寫呢,最近又沉迷與時間子系統,唉,時間總是不夠用啊
tigger
2014-12-11 12:00
@linuxer:我也感覺時間不夠用,想學的東西太多了。總是東學一下,西學一下。
linuxer
2014-12-11 10:17
最近準備研究CPU idle framework
-----------------------------------------------
太好了,我在看tick broadcast framework,和cpuidle framework有關,我還在想蝸窩應該寫到這裏了吧

另外,你文章中的PE的full name是什麼?
wowo
2014-12-11 10:36
@linuxer:Processing Element, Cortex-A57有一個ARM core的架構圖,比較清晰。我不想寫太多,光這個詞,就可以寫一篇文章啊,涉及到ARM的架構。
發佈了297 篇原創文章 · 獲贊 36 · 訪問量 31萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章