DVFS--動態電壓頻率調整

linux低功耗研究也有一段時間了,基本把低功耗的實現方式想清楚了(主要分成機制和策略),這段時間的工作主要在機制上。暫時想實現的主要的機制有:cpu級,設備驅動級,系統平臺級。管理顆粒度不斷遞增,形成三駕馬車齊驅的形勢。

 

cpu:主要實現比較容易的在系統處於目標在於頻繁發生、更高粒度的電源狀態改變,主要的實現方式爲idle,包括今天的主要想講的動態主頻。

設備驅動級:主要實現對單個設備驅動的管理(suspendresume等),通過系統監測將閒置的設備,通過從用戶態對sys文件目錄動態進行單個驅動設備的管理

,置於省電模式。

系統平臺級:目標在於管理較大的、非常見的重大電源狀態改變,用於減少產品設備在長時間的空閒之後,減少電源消耗 。主要實現方式是依託linux內核所支持的apm技術,實現整個系統的睡眠/恢復(sleep

 

這幾個層次其實並不是相互獨立的,都是相互交叉的,比如系統平臺級的睡眠不可避免會涉及到cpusleep模式和設備驅動的掛起,而動態主頻的實現除了cpu本身的支持也需要外圍驅動隨着主頻變化做出相應的適應活動。因此這裏的分級只是一種粗範圍的,邏輯上的分層。

 

前段時間還調研了一下IBMMonta Vista搞得那套DPMDynamic Power Management)機制,看了不少論文和觀點,總的感覺就是太過複雜而且也不是很實用,感覺噱頭大過實際功效,(因此這套機制始終還不能進入內核的mainline),言歸正傳,還是重點講述下cpufreq技術。

 

1.爲什麼要cpufreq

 

關於要不要實現cpufreq技術,我也糾結過,一個原因是:當時對內核如何提供這麼一套動態變頻的機制還不瞭解,只覺得應該非常麻煩,因爲涉及到外圍驅動的參數更新,另外一個原因是:在SEP4020這種體量的處理器上跑linux,即使運行在最高頻率時的處理能力可能也不是很富餘,我再給它降頻還有沒有意義?掙扎之後還是覺得要實現它,我也給自己列了這麼幾條原因:

n      雖然cpu在板級中已不是主要的耗電源,但是仍然佔着舉足輕重的位置,功耗機制到最後就是幾毫安幾毫安的扣了,降頻肯定能在一定程序上節約功耗那我爲什麼不採用?

n      細化功耗管理的顆粒度,爲應用程序提供更多的功耗節省機制

n      對普通的應用,系統可以運行在維持平臺運作的最低頻率,在有處理任務時,變頻機制會自動切換到合適的高主頻,並且在任務結束時重回省電的低主頻,這樣就解決了我之前的第二個疑惑。

Ø        SEP4020在運行在88M時板級功耗爲:222mA

Ø        SEP4020在運行在56M時板級功耗爲:190mA,降低14%

Ø        SEP4020在運行在32M時板級功耗爲:160mA,降低28%

n      實現的一些工作是我們一直需要去做但是一直沒有動力做的

Ø        變頻會涉及到大量模塊的參數的重新配置,作爲cpu原廠,我們需要把這些參數徹底掌握

Ø        對這些參數的充分理解,能對現有系統進行優化,提升整體系統的效率,比如使用發現一些參數還是太過保守(sdram,nand),我們的通用配置在系統降爲32M時仍能正常工作。

n      可行性論證沒有問題:偶然看到armkiller同志提供的nand驅動代碼中有變頻的實現(這裏非常感謝armkiller),網上這方面的文章很少,於是翻閱了linux內核源碼中自帶的/documentation/cpufreq後,對這種機制大概有一定的瞭解(linux中的documentation是個好東東),也看到了一些處理器廠商爲自己的cpu已經實現了的代碼,如sa1100pxa系列。

 

2. 內核所提供的這種cpufreq技術的機制

n      目的:

變頻技術是指CPU硬件本身支持在不同的頻率下運行,系統在運行過程中可以根據隨時可能發生變化的系統負載情況動態在這些不同的運行頻率之間進行切換,從而達到對性能和功耗做到二者兼顧的目的。

n      來源:

雖然多個處理器生產廠家都提供了對變頻技術的支持,但是其硬件實現和使用方法必然存在着細微甚至巨大的差別。這就使得每個處理器生產廠家都需要按照其特殊的硬件實現和使用方法向內核中添加代碼,從而讓自己產品中的變頻技術在Linux 中得到支持和使用。然而,這種內核開發模式所導致的後果是各個廠家的實現代碼散落在 Linux 內核代碼樹的各個角落裏,各種不同的實現之間沒有任何代碼是共享的,這給內核的維護以及將來添加對新的產品的支持都帶來了巨大的開銷,並直接導致了 cpufreq 內核子系統的誕生。

n      管理策略:

Linux內部共有五種對頻率的管理策略userspaceconservativeondemandpowersave  performance

Ø         1.performance CPU會固定工作在其支持的最高運行頻率上;

Ø         2.powersave CPU會固定工作在其支持的最低運行頻率上。因此這兩種 governors 都屬於靜態 governor ,即在使用它們時 CPU 的運行頻率不會根據系統運行時負載的變化動態作出調整。這兩種 governors 對應的是兩種極端的應用場景,使用 performance governor 體現的是對系統高性能的最大追求,而使用 powersave governor 則是對系統低功耗的最大追求。

Ø        3.Userspace:最早的 cpufreq 子系統通過 userspace governor 爲用戶提供了這種靈活性。系統將變頻策略的決策權交給了用戶態應用程序,並提供了相應的接口供用戶態應用程序調節 CPU 運行頻率使用。 (可以使用Dominik 等人開發了cpufrequtils 工具包 

Ø        4.ondemand userspace是內核態的檢測,效率低。而ondemand正是人們長期以來希望看到的一個完全在內核態下工作並且能夠以更加細粒度的時間間隔對系統負載情況進行採樣分析的 governor

Ø        5.conservative  ondemand governor 的最初實現是在可選的頻率範圍內調低至下一個可用頻率。這種降頻策略的主導思想是儘量減小對系統性能的負面影響,從而不會使得系統性能在短時間內迅速降低以影響用戶體驗。但是在 ondemand governor 的這種最初實現版本在社區發佈後,大量用戶的使用結果表明這種擔心實際上是多餘的, ondemand governor在降頻時對於目標頻率的選擇完全可以更加激進。因此最新的 ondemand governor 在降頻時會在所有可選頻率中一次性選擇出可以保證 CPU 工作在 80% 以上負荷的頻率,當然如果沒有任何一個可選頻率滿足要求的話則會選擇 CPU 支持的最低運行頻率。大量用戶的測試結果表明這種新的算法可以在不影響系統性能的前提下做到更高效的節能。在算法改進後, ondemand governor 的名字並沒有改變,而 ondemand governor 最初的實現也保存了下來,並且由於其算法的保守性而得名 conservative 

Ondemand降頻更加激進,conservative降頻比較緩慢保守,事實使用ondemand的效果也是比較好的。

 

n      Cpufreq在用戶態所呈現的接口:

Ø        cpuinfo_max_freq  cpuinfo_min_freq 分別給出了 CPU 硬件所支持的最高運行頻率及最低運行頻率,

Ø        cpuinfo_cur_freq 則會從 CPU 硬件寄存器中讀取 CPU 當前所處的運行頻率。

Ø        Governor在選擇合適的運行頻率時只會在 scaling_max_freq  scaling_min_freq 所確定的頻率範圍內進行選擇

Ø        scaling_cur_freq 返回的是 cpufreq 模塊緩存的 CPU 當前運行頻率,而不會對 CPU 硬件寄存器進行檢查。

Ø        scaling_available_governors 會告訴用戶當前有哪些 governors 可供用戶使用

Ø         scaling_driver 則會顯示該 CPU 所使用的變頻驅動程序

Ø        Scaling_governor 則會顯示當前的管理策略,往這個上echo其他類型會有相應的轉變。

Ø        scaling_setspeed:需將governor類型切換爲userspace,纔會出現,往這個文件echo數值,會切換主頻

 

以下是將governor切換爲ondemand後生成的ondemand文件夾下出現的配置文件。(conservative就不說了,不準備使用)

Ø        sampling_rate:當前使用的採樣間隔 ,單位:微秒

Ø        sampling_rate_min:允許使用的最短採樣間隔

Ø        sampling_rate_max:允許使用的最長採樣間隔

Ø        up_threshold :表明了系統負載超過什麼百分比時 ondemand governor 會自動提高 CPU 的運行頻率

Ø        ignore_nice_loadignore_nice_load 文件可以設置爲 0  1是默認設置)。當這個參數設置爲 1 時,任何具有 “nice”值的處理器不計入總處理器利用率。在設置爲 0 時,所有處理器都計入利用率。

Ø        sampling_down_factor

 

n      使用方法:

Ø        cd sys/devices/system/cpu/cpu0/cpufreq/目錄

echo 32000 > scaling_min_freq 設置最小工作頻率(khz,32000~88000)

//若想使用userspace策略

# echo userspace > scaling_governor切換工作方式爲userspace

echo 64000 > scaling_setspeed  設置成想要的工作頻率khz

//若想使用ondemand策略

# echo ondemand > scaling_governor切換工作方式爲ondemand

 

3.如何實現?

       首先需要幹一些雜活,修改kconfig makefile把系統屏蔽的cpufreq打開,對於我們來說主要的核心有兩部分:

系統相關:主要有cputimer(變了頻率一定要更新系統timer,否則系統時間就不準了),sdram等。

主要就是實現下面這個結構體:

static struct cpufreq_driver sep4020_driver =

{

       .flags      = CPUFREQ_STICKY,

       .verify     = sep4020_verify_speed,

       .target     = sep4020_target,

       .get         = sep4020_getspeed,

       .init         = sep4020_cpu_init,

       .name            = "SEP4020 Freq",

};

代碼還是很簡陋,很多細節都沒考慮,所以具體的暫時先不講了,大家可以先參考pxasa1100的實現。

 

然後就是收頻率影響的驅動:

簡單的來說就是:系統在變化cpu主頻的時候會調用cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);函數,響掛載在這個cpu上所有的驅動發出一個信號,驅動接收到這個信號則調用相應的處理函數。

這裏把串口部分的實現簡化,如下:

#ifdef CONFIG_CPU_FREQ

 

static int sep4020_serial_cpufreq_transition(struct notifier_block *nb, unsigned long val, void *data)

{

   //      printk("in the serial cpufreq_transition/n");

       int pmcr_pre;

       unsigned long cpu_clk,baud,baudh,baudl;

       pmcr_pre = *(volatile unsigned long*)PMU_PMCR_V;

              if(pmcr_pre > 0x4000)

              cpu_clk = (pmcr_pre-0x4000)*8000000;

       else

              cpu_clk = (pmcr_pre)*4000000;

 

       baud = cpu_clk/16/115200;      

       baudh = baud >>8;

       baudl = baud&0xff;    

 

       *(volatile unsigned char*)UART0_LCR_V |= (0x80);

       *(volatile unsigned char*)UART0_DLBL_V   = baudl;

       *(volatile unsigned char*)UART0_DLBH_V   = baudh;

       *(volatile unsigned char*)UART0_LCR_V &= ~(0x80);

       printk("in the serial cpufreq_transition/n");

    return 0;

}

 

static inline int sep4020_serial_cpufreq_register(void)

{

    sep4020_serial_freq_transition.notifier_call = sep4020_serial_cpufreq_transition;

 

    return cpufreq_register_notifier(&sep4020_serial_freq_transition,

                     CPUFREQ_TRANSITION_NOTIFIER);

}

 

static inline void sep4020_serial_cpufreq_deregister(void)

{

    cpufreq_unregister_notifier(&sep4020_serial_freq_transition,

                    CPUFREQ_TRANSITION_NOTIFIER);

}

 

#else

#endif

 

4.效果

sys下開啓ondeman模式,串上電流表:

1.      板級電流從220mA調至160mA(因爲此時內核檢測系統無負載,降頻)

2.      執行一個nandflash的拷貝命令,拷貝一個5M左右的文件到其他文件夾,

3.      在拷貝執行時間在3秒時(我給內核設的掃描週期爲2.5秒)系統發現有負載,升頻,電流從160mA變爲220mA(可見已是系統最高主頻)

4.      此後的拷貝的整個過程中電流保持爲220mA

5.      在拷貝結束後不久(2-3s內),系統電流又跳變至160mA

1.內核選項:

Linux 動態變頻管理 cpufreq 提供了操作系統級別的變頻功能,同時需要用戶層來制定和執行策略。cpufreq後臺進程cpufreqd 就是用來監測系統的運行狀況,並根據不同的狀況設定 CPU 的工作頻率的。 

 

要想在用戶層使用後臺進程cpufreqd,首先需要在配置linux內核編譯選項時選擇CPU Frequency scaling功能選項其內有一些子選項,包含governor的選擇和是否Enable CPUfreq debugging cpufreq有五種governor(將在10.1.3中介紹),要使cpufreqd正常運行,至少需要選擇performance governor;在測試階段往往希望看到系統變頻信息,那麼需要Enable CPUfreq debugging。在Enable CPUfreq debugging的前提下,在u-bootlinux啓動參數bootargs加上loglevel=8 cpufreq.debug=<value>,就可以看到cpufreq的相應級別的運行信息。 <value>的值可以是 124,也可以是它們的或(3567),具體意義如下:

1 to activate CPUfreq core debugging,

2 to activate CPUfreq drivers debugging(這是和SEP4020相關的調試), and  

4 to activate CPUfreq governor debugging

 

後臺進程 cpufreqd 需要用到三個庫,分別是cpufreqd-2.2.1cpufrequtils-002 sysfsutils-2.1.0,這三個庫都是 GNU 免費開源軟件,我們對 cpufreqd-2.2.1cpufrequtils-002 進行了一些修改,由於編譯這三個庫還是蠻麻煩的,因此我在君正發佈的cpufreqd的開發包上對arm平臺進行二次編譯,這樣減少了不少工作(做事要站在巨人的肩膀上,呵呵)首先你可以君正的官方ftp上下載這個包。

下面將介紹cpufreqd arm上的交叉編譯和安裝過程以及在目標板上安裝和運行方法。

附:

在開啓DVFS的時候做老化測試的時候出現死機的狀況,這可能在配置核心電壓的時候出現死機的狀況,所以在配置核心電壓的時候可以稍微高一點!一般電壓浮動是上下5%!如果不行還可以稍微高一點!

<script type=text/javascript charset=utf-8 src="http://static.bshare.cn/b/buttonLite.js#style=-1&uuid=&pophcol=3&lang=zh"></script> <script type=text/javascript charset=utf-8 src="http://static.bshare.cn/b/bshareC0.js"></script>
閱讀(948) | 評論(0) | 轉發(2) |
給主人留下些什麼吧!~~
評論熱議
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章