cpufreq概述【轉】 linux cpufreq

轉自:https://www.cnblogs.com/lvzh/p/13169941.html

 

linux cpufreq

cpufreq概述

cpufreq的核心功能,是通過調整CPU的電壓和頻率,兼顧系統的性能和功耗。在不需要高性能時,降低電壓和頻率,以降低功耗;在需要高性能時,提高電壓和頻率,以提高性能。

cpufreq軟件框架

對下,cpufreq基於clock、regulator、pmu等模塊實現頻率和電壓的控制。
對上,cpufreq通過cpufreq core、cpufreq governor、cpufreq stats等模塊以sysfs的形式向用戶空間提供頻率的查詢、控制等接口。
內部,cpufreq內部分爲core、governor、drivers等模塊。

 cpufreq調頻策略

  • Performance

性能優先,CPU固定工作在其支持的最高頻率。

  • Powersave

功耗優先,CPU固定工作在其支持的最低頻率。

  • Userspace

系統將變頻策略的決策權交給用戶態應用程序,並提供了相應的接口供用戶態程序設置CPU 頻率。

  • Ondemand

按需動態調整CPU頻率, 只要CPU負載超過閾值up_threshold就會立即設置爲最大頻率,其他時候根據負載計算出合適的頻率。

  • Conservative

與ondemand不同,Conservative不是一味追求最高頻率,而是平滑地調整CPU頻率,頻率的升降是漸變式的。

cpufreq調測命令

  • 查詢

以下文件節點均可通過cat命令顯示

# ls /sys/devices/system/cpu/cpu0/cpufreq/
affected_cpus                        //當前策略作用於哪些online core
cpuinfo_cur_freq                   //當前CPU硬件頻率
cpuinfo_max_freq                 //CPU硬件支持的最低頻率
cpuinfo_min_freq                  //CPU硬件支持的最高頻率
cpuinfo_transition_latency    //硬件支持的切換頻率最小間隔
related_cpus                        //online和offline core
scaling_available_frequencies    //軟件支持的頻率列表
scaling_available_governors      //支持的策略列表
scaling_cur_freq                  //軟件設置的當前頻率,通常與cpuinfo_cpus相同,如果出現硬件問題可能導致不一致
scaling_driver                      //當前使用的driver
scaling_governor                 //當前使用的governor
scaling_max_freq                //軟件governor設置的最高頻率
scaling_min_freq                 //軟件governor設置的最低頻率
scaling_setspeed                //需將governor類型切換爲userspace,纔會出現,通過echo修改數值,會切換主頻

  • 設置

可以通過 echo配置scaling_governor,scaling_max_freq,scaling_min_freq
例如:echo 1400 > /sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq

cpufreq編譯配置

#CPU Frequency scaling
CONFIG_CPU_FREQ=y #主開關
#CONFIG_CPU_FREQ_DEFAULT_GOV_SCHEDUTIL=y #default gov任選某個宏打開即可,決定了cpufreq初始化使用的governor,後續可在init.rc修改文件結點
#CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
#CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
CONFIG_CPU_FREQ_STAT=y #維測開關,查看cpufreq統計信息:/sys/devices/system/cpu/cpu0/cpufreq/stats

performance/powersave策略

performance/powersave策略都是靜態頻率,performance設置爲最高頻,powersave設置爲最低頻。在切換governor的時候配置好頻率:

cpufreq_set_policy->cpufreq_governor_limits

 

 

Userspace策略

用戶寫文件節點/sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed時,調用store_scaling_setspeed函數修改頻率。

Interactive策略

重要概念

hispeed_freq:當CPU頻率較低且負載突然超過go_hispeed_load時,CPU跳到此頻率,如果在

go_hispeed_load:hispeed_freq對應的負載

min_sample_time:在降頻前需要在當前頻率運行保持的時間

sampling_rate:interative管理器的採樣間隔

target_loads:爲每個CPU頻率設置理想的CPU負載,以負載+頻率的數組形式存儲,如75:800:80:900:85:1300: 90:1500:95,含義是負載75以下時頻率爲800MHz,75~80時,頻率爲900MHz。

above_hispeed_delay:頻率升高時的需要保持的時間,以頻率+時間的數組形式存儲

調頻基本流程

設置sched的回調函數,每次發生調度變化時設置一個irq_work任務,在irq_work中重新計算目標頻率

gov_set_update_util->cpufreq_add_update_util_hook->cpufreq_update_util->update_util_handler->irq_work_queue->eval_target_freq->update_load==choose_freq

update_load:以CPU idle運行時間,計算移動平均頻率
choose_freq:使用平均負載頻率,預估合適的目標頻率

複製代碼
static u64 update_load(struct interactive_cpu *icpu, int cpu)
{
    struct interactive_tunables *tunables = icpu->ipolicy->tunables;
    u64 now_idle, now, active_time, delta_idle, delta_time;

    now_idle = get_cpu_idle_time(cpu, &now, tunables->io_is_busy); /* 系統啓動之後CPU處於idle的總時間 */
    delta_idle = (now_idle - icpu->time_in_idle); /* 本次與上次進入update_load之間,CPU處於idle的總時間 */
    delta_time = (now - icpu->time_in_idle_timestamp); /* 本次與上次進入update_load時間只差 */

    if (delta_time <= delta_idle)
        active_time = 0;
    else
        active_time = delta_time - delta_idle;

    icpu->cputime_speedadj += active_time * icpu->ipolicy->policy->cur; /* 移動平均值,代表CPU實際需要的頻率值 */

    icpu->time_in_idle = now_idle;
    icpu->time_in_idle_timestamp = now;

    return now;
}
複製代碼
複製代碼
/* Re-evaluate load to see if a frequency change is required or not */
static void eval_target_freq(struct interactive_cpu *icpu)
{
    ...

    spin_lock_irqsave(&icpu->load_lock, flags);
    now = update_load(icpu, smp_processor_id());
    delta_time = (unsigned int)(now - icpu->cputime_speedadj_timestamp);
    cputime_speedadj = icpu->cputime_speedadj;
    spin_unlock_irqrestore(&icpu->load_lock, flags);

    spin_lock_irqsave(&icpu->target_freq_lock, flags);
    do_div(cputime_speedadj, delta_time);
    /* loadadjfreq = (cputime_speedadj + active_time * policy->cur) / delta_time *100 ≈ cur_load * cur_freq;表示在週期內CPU需要的平均負載頻率 */
    loadadjfreq = (unsigned int)cputime_speedadj * 100;

    /* cpu_load = (cputime_speedadj / policy->cur + active_time ) / * delta_time) *100 ≈ active_time/delta_time*100≈cur_load;表示CPU平均負載*/
    cpu_load = loadadjfreq / policy->cur;
    
    ....
    /* choose_freq中使用loadadjfreq、target_loads的負載和頻率,計算預期的頻率 */
    choose_freq(icpu, loadadjfreq);
    ...
}
複製代碼
複製代碼
/*
 * If increasing frequencies never map to a lower target load then
 * choose_freq() will find the minimum frequency that does not exceed its
 * target load given the current load.
 */
static unsigned int choose_freq(struct interactive_cpu *icpu, unsigned int loadadjfreq)
{
    struct cpufreq_policy *policy = icpu->ipolicy->policy;
    struct cpufreq_frequency_table *freq_table = policy->freq_table;
    unsigned int prevfreq, freqmin = 0, freqmax = UINT_MAX, tl;
    unsigned int freq = policy->cur;
    int index;

    do {
        prevfreq = freq;
        tl = freq_to_targetload(icpu->ipolicy->tunables, freq); /* 根據目標freq返回目標負載 */
        /*
         * Find the lowest frequency where the computed load is less
         * than or equal to the target load.
         * target_frqe = loadadjfreq / tl = cur_freq * cur_load / tl; /* 根據這個公式逐漸收縮,多次調整找到最佳tl和目標freq */
         */
        index = cpufreq_frequency_table_target(policy, loadadjfreq / tl, CPUFREQ_RELATION_L);
        freq = freq_table[index].frequency;
        if (freq > prevfreq) {
            /* The previous frequency is too low */
      ...
        } else if (freq < prevfreq) {
            /* The previous frequency is high enough. */
      ...
        }
        /* If same frequency chosen as previous then done. */
    } while (freq != prevfreq);

    return freq;
}
複製代碼

Schedutil策略

基本思想

cpufreq_add_update_util_hook註冊回調函數,當負載變化時通知調頻

負載變化時調用這個函數

 

 

 

 

 

 

 

以下都會調用update_load_avg。

enqueue_entity

dequeue_entity

 set_next_entity

put_prev_entity

entity_tick

enqueue_task_fair

dequeue_task_fair

update_blocked_averages

propagate_entity_cfs_rq

detach_entity_cfs_rq

attach_entity_cfs_rq

init_tg_cfs_entry

sched_group_set_shares

 

schedutil介紹

https://blog.csdn.net/wukongmingjing/article/details/81784727

根據下面文檔做一下cpufreq的總結

Documentation/admin-guide/pm/cpufreq.rst

load和util的區別

 

 
標籤: 電源管理Linux
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章