Tuesday, November 29, 2011

Power Management (2):CPU省電功能(一)

前一篇介紹了電源管理的基礎概念。那麼,現今的PC有哪些的電源管理,以及他們跟BIOS的關聯性又是什麼?

提到PC的Power Management,不能不提到兩份標準:ACPI跟PCIE。

ACPI(Advanced Configuration and Power Management)跟PCIE(PCI Express)可以說是今日PC最重要的兩份軟硬體工業規範,而各自為包含許多功能以及細節。這篇文章將只會包含小部份功能的介紹,以後有機會另有專文討論ACPI跟PCIE,也請讀者對應這兩份的規格書以獲得完整的資訊。

不管是Processor或是Device甚至對整個系統來說,ACPI定義完整相對應的電源模式。以下附圖是從ACPI 4.0a Figure 3.1中擷出:




這一篇文章會討論最常見CPU的三種省電功能:P-State、T-State以及C-State,如上圖右下角所示。

中央處理器(CPU)的省電模式

當系統在G0之下(註1),根據系統的負載,作業系統(Operating System)可以將CPU切換到不同的模式之下來達到省電。每種作業系統甚至同一種作業系統但是不同的情境之下,都能夠只用不同的演算法來達成最適合當下的省電模式。

舉例來說,伺服器(Server)跟筆記電腦(Laptop PC)最大的差異在於伺服器永遠接著電源但是筆記電腦卻需要在電池模式下盡量的省電。就算單比較伺服器本身,白天的服務需求(快速的反應)高,但夜晚可以盡量省電。

不過作業系統怎麼知道底層的硬體是如何運作的?以今天的電腦硬體更換的速度比作業系統來的快速,在新的硬體上安裝舊的作業系統(在大多數的情況)也可以正常工作而且也能更享受到最新的功能,這是如何辦到的?

這都是BIOS的功勞。

BIOS最大的功能,除了初始化硬體(就是開機)之外,就是告訴作業系統也硬體支援哪些功能以及如何使用這些功能(註2)。在開機的過程中,BIOS需要針對不同的CPU做硬體的初始化,同時間根據不同的CPU特性建立ACPI table,放在記憶體讓作業系統讀取(這也是為什麼更新BIOS可以支援新的CPU)。

ACPI為CPU定義了C-State,包含了C0(CPU的Working State)以及Cx(x >= 1,CPU的睡眠模式)。而在C0中,又定義了兩種將CPU頻率降低的方法,分別為Performance State和Throllting,如下圖:




註1:G0為ACPI定義系統的Working State,即一般所謂的「runt-time」。詳細內容請參考ACPI Specification。

註2:因為歷史因素(舊仇新恨?),Linux除了讀ACPI table之外,也可以特別使用內建的驅動程式(Driver)來達成C-State切換。何者優劣不在本文討論範圍,但是筆者認為如果BIOS有錯誤,不應該用驅動程式修正,而是BIOS工程師能夠提供更新。

C-State(CPU State):

在C0之中,CPU(或是CPU的核心)是正常運轉,並且執行指令(instruction)。但是在C1、C2、C3等C-State之下,CPU是處在睡眠模式,並沒有在執行指令,一直到被中斷(interrupt)喚醒為止。

BIOS是如何告知作業有哪些C-State?

ACPI定義了兩種方法:

1. FADT:

ACPI規範中特別把C2/C3定義在Fixed Hardware中(註3)。在x86平台中,作業系統可以透過讀I/O Port來切換CPU到C2/C3(註4)。

作業系統怎麼知道要透過哪些I/O Port來觸發C2/C3?

答案是FADT中的三個值:
  1. P_BLK (Processor Control Block)
  2. P_LVL2_LAT (C2 Latency)
  3. P_LVL3_LAT (C3 Latency)

而作業系統需要觸發C2/C3的I/O位置為:
C2:P_LVL2 = P_BLK + 4
C3:P_LVL3 = P_BLK + 5

(以下範例是從一台HP筆記電腦擷取出來,所有的值皆為16進制
===================================
  FACS Address : 9B75E000
  DSDT Address : 9B7ED000
  Model : 01
  PM Profile : 02 (Mobile)
  SCI Interrupt : 0009
  SMI Command Port : 000000B2
  ACPI Enable Value : A0
  ACPI Disable Value : A1
  S4BIOS Command : 00
  P-State Control : 80
  PM1A Event Block Address : 00000400
  PM1B Event Block Address : 00000000
  PM1A Control Block Address : 00000404
  PM1B Control Block Address : 00000000
  PM2 Control Block Address : 00000450
  PM Timer Block Address : 00000408
  GPE0 Block Address : 00000420
  GPE1 Block Address : 00000000
  PM1 Event Block Length : 04
  PM1 Control Block Length : 02
  PM2 Control Block Length : 01
  PM Timer Block Length : 04
  GPE0 Block Length : 10
  GPE1 Block Length : 00
  GPE1 Base Offset : 00
  _CST Support : 85
  C2 Latency : 0065
  C3 Latency : 0039
  CPU Cache Size : 0400
  Cache Flush Stride : 0010
  Duty Cycle Offset : 01
  Duty Cycle Width : 00
  ... (下略)
===================================

在這台系統上,作業系統要觸發C2就讀取I/O Port 0x408,要觸發C3就讀取I/O Port 0x409。

當硬體不支援C2/C3的時候,BIOS也要透過FADT來宣告,作法為:

  P_LVL2_LAT > 100  (10進制)
  P_LVL3_LAT > 1000(10進制)

建議讀者去ACPI Specification查詢P_LVL2_LAT跟P_LVL3_LAT的作用。

根據筆者所知,這些參數現在都是由晶片廠商如INTEL跟AMD提供,ODM/OEM鮮少微調,畢竟晶片廠商才是最了解他們產品的人(註5)。

註3:其實C1也有,就是CPU的HLT指令。

註4:實際硬體的行為複雜的多,可以透過Chipset(實際I/O的接受者)通知CPU,也可以由CPU在偵測到I/O指令集到對應Port的時候自動產生,BIOS在開機的過程中必須正確的設定如何觸發C2/C3,否則C2/C3不會產生作用。但是對作業系統來說,C2/C3只是個簡單的「IN port#」。

註5:其實筆者覺得OEM/ODM也應該要能根據他們的產品微調,但可能受限於開發時間壓力和微調效果不大,加上晶片廠商不會替OEM/ODM的微調背書,所以還沒見過有人去修改晶片廠商提供的參數。但筆者樂見有讀者舉出反證並告知哪些廠商還願意花苦工做技術研究。

2. _CST Object in DSDT/SSDT:

原本定義的C2跟C3已經不能滿足最新CPU的功能,所以ACPI加入了更新的支援C-State的宣告:_CST(註6)。

根據ACPI的規範,當_CST存在的情況,作業系統必須忽略FADT中相關的宣告只使用_CST的資訊。以下_CST擷取至某HP i7的平台的第一顆CPU核心,其他的7核心都是回覆相同的資訊。如對內容需要更新的了解,請參閱ACPI Specification。

============================
\_PR_.CPU0._CST:
  CState 0
    Register (FFixedHW, 1, 2, 0)
    Type            C1
    Lantency        3ms
    Power           1000mv

  CState 1
    Register (FFixedHW, 1, 2, 10)
    Type            C2
    Lantency        205ms
    Power           500mv

  CState 2
    Register (FFixedHW, 1, 2, 20)
    Type            C3
    Lantency        245ms
    Power           350mv
============================

透過_CST object,作業系統能夠知道有支援哪些C-State(如上示C1、C2、C3)以及透過哪些Register來觸發C-State。

也因為今日主流的機器已經改用_CST宣告C-State,這也代表BIOS能夠在不同的情境之下通知作業系統來更換現在所支援的C-State,作法為:
  Notify(\_PR_.CPU0, 0x81)
  Notify(\_PR_.CPU1, 0x81)
  Notify(\_PR_.CPU2, 0x81)
  ...
  Notify(\_PR_.CPUx, 0x81)

之後作業系統會重新執行
  \_PR_.CPU0._CST
  \_PR_.CPU1._CST
  \_PR_.CPU2._CST
  ...
  \_PR_.CPUx._CST

而BIOS可以根據這同的情境回報不同的C-State支援。

應用題之一:筆者曾經被問過「如果(筆記電腦上)在AC模式把C3的宣告移除是否會造成系統不穩定?」

答案:
「不會」。因為C-State的進入與否是作業系統主動產生,當_CST宣告不支援C3,作業系統就只會將CPU放入本來就有的C0~C2。除非C0~C2有問題,系統除了比較耗電,但是絕對不會有穩定性的問題。

應用題之二:當_CST回報系統支援C1~C3如上,代表這個CPU只支援這幾種C-State嗎?

答案:
「否」。_CST只代表BIOS回報的只有當下情況支援的C-State,而BIOS可以動態改變_CST回報的值。舉例來說,筆記電腦的BIOS可以在有接電源的情況下允許到C3,而在只有電池的情況下支援到C6。

有一個更特異的例子:在近期的Intel平台上,Intel建議跳過C2,讓系統直接支援C3。而Intel的作法是把C3宣告成C2,而當作業系統認為它在執行C2的時候,CPU實際上是在C3模式。


註6:ACPI還定義了其他與C-State相關的object如_CSD(C State Dependencies),詳細內容請參閱ACPI Specification。

(續:Power Management (2):省電功能 - CPU系列之二)

No comments:

Post a Comment