eas k5.4 (九):v4.15 - Frequency Invariant Engine (FIE)

https://lkml.org/lkml/2017/7/6/268

431ead0 arm64: wire cpu-invariant accounting support up to the task scheduler
4e63ebe arm64: wire frequency-invariant accounting support up to the task scheduler
552c465 arm: wire cpu-invariant accounting support up to the task scheduler
3a1ed9c arm: wire frequency-invariant accounting support up to the task scheduler
8216f58 drivers base/arch_topology: allow inlining cpu-invariant accounting support
0e27c56 drivers base/arch_topology: provide frequency-invariant accounting support
400ec74 cpufreq: dt: invoke frequency-invariance setter function
518accf cpufreq: arm_big_little: invoke frequency-invariance setter function
e7d5459 cpufreq: provide default frequency-invariance setter function
5408211 drivers base/arch_topology: free cpumask cpus_to_visit
 

一. cpufreq notifier

cpufreq notifier有兩種,一種是變頻時的notifier;一種是cpufreq policy發生變化時的notifier。

drivers/cpufreq/cpufreq.c /*cpufreq暴露出註冊nb的接口函數*/
1913 /*********************************************************************
1914  *                     NOTIFIER LISTS INTERFACE                      *
1915  *********************************************************************/
1916 
1917 /**
1918  *  cpufreq_register_notifier - register a driver with cpufreq
1919  *  @nb: notifier function to register
1920  *      @list: CPUFREQ_TRANSITION_NOTIFIER or CPUFREQ_POLICY_NOTIFIER
1921  *
1922  *  Add a driver to one of two lists: either a list of drivers that
1923  *      are notified about clock rate changes (once before and once after
1924  *      the transition), or a list of drivers that are notified about
1925  *      changes in cpufreq policy.
1926  *
1927  *  This function may sleep, and has the same return conditions as
1928  *  blocking_notifier_chain_register.
1929  */
1930 int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list)
1931 {
1932     int ret;
1933    
1934     if (cpufreq_disabled())
1935         return -EINVAL;
1936 
1937     switch (list) {
1938     case CPUFREQ_TRANSITION_NOTIFIER:
1939         mutex_lock(&cpufreq_fast_switch_lock);
1940 
1941         if (cpufreq_fast_switch_count > 0) {
1942             mutex_unlock(&cpufreq_fast_switch_lock);
1943             return -EBUSY;   
1944         }
1945         ret = srcu_notifier_chain_register(
1946                 &cpufreq_transition_notifier_list, nb);
1947         if (!ret)
1948             cpufreq_fast_switch_count--;
1949 
1950         mutex_unlock(&cpufreq_fast_switch_lock);
1951         break; 
1952     case CPUFREQ_POLICY_NOTIFIER:
1953         ret = blocking_notifier_chain_register(
1954                 &cpufreq_policy_notifier_list, nb);
1955         break;
1956     default:
1957         ret = -EINVAL;
1958     }
1959 
1960     return ret;
1961 }
1962 EXPORT_SYMBOL(cpufreq_register_notifier);
  1. arch topology註冊nb到cpufreq的cpufreq_policy_notifier_list,在cpufreq policy發生變化時,通過調用註冊的nb中的callback函數init_cpu_capacity_notifier..init_cpu_capacity_callback,使用CIE(Capacity Invariant Engine)重新設置:
    a. capacity_scale(最大cpu raw capacity值,單位=mips);
    b. cpu的capacity(cpu_scale,scale到capacity_scale並歸一化到1024的值)。
     

    註冊notifier:
    core_initcall(register_cpufreq_notifier)->cpufreq_register_notifier(&init_cpu_capacity_notifierCPUFREQ_POLICY_NOTIFIER)->blocking_notifier_chain_register(&cpufreq_policy_notifier_list, nb)

    調用notifier:
    1. cpufreq_policy_free(struct cpufreq_policy *policy)->blocking_notifier_call_chain(&cpufreq_policy_notifier_list,CPUFREQ_REMOVE_POLICY, policy);
    2. cpufreq_online(unsigned int cpu)--new_policy?->blocking_notifier_call_chain(&cpufreq_policy_notifier_list,CPUFREQ_CREATE_POLICY, policy)

    drivers/base/arch_topology.c (CIE)
    231 static struct notifier_block init_cpu_capacity_notifier = {
    232     .notifier_call = init_cpu_capacity_callback,
    233 }; 
    
    194 static int
    195 init_cpu_capacity_callback(struct notifier_block *nb,
    196                unsigned long val,             
    197                void *data)
    198 {
    199     struct cpufreq_policy *policy = data; 
    200     int cpu;
    201 
    202     if (!raw_capacity)
    203         return 0;
    204 
    205     if (val != CPUFREQ_CREATE_POLICY) 
    206         return 0;
    207 
    208     pr_debug("cpu_capacity: init cpu capacity for CPUs [%*pbl] (to_visit=%*pbl)\n",
    209          cpumask_pr_args(policy->related_cpus),
    210          cpumask_pr_args(cpus_to_visit));
    211 
    212     cpumask_andnot(cpus_to_visit, cpus_to_visit, policy->related_cpus);
    /*related_cpus是online+offline cpus*/
    213 
    214     for_each_cpu(cpu, policy->related_cpus) {
    215         raw_capacity[cpu] = topology_get_cpu_scale(cpu) *
    216                     policy->cpuinfo.max_freq / 1000UL;
    /*raw_capacity[cpu0~2]=544(capacity-dmips-mhz)*1820000/1000=990080(mips)*/
    /*raw_capacity[cpu3]=1024(capacity-dmips-mhz)*2028000/1000=2076672(mips)*/
    217         capacity_scale = max(raw_capacity[cpu], capacity_scale);
    /*capacity_scale =2076672*/
    218     }
    219 
    220     if (cpumask_empty(cpus_to_visit)) {
    221         topology_normalize_cpu_scale();
    222         schedule_work(&update_topology_flags_work);
    223         free_raw_capacity();
    224         pr_debug("cpu_capacity: parsing done\n");
    225         schedule_work(&parsing_done_work);
    226     }
    227 
    228     return 0;
    229 }
    drivers/base/arch_topology.c (CIE)
    131 void topology_normalize_cpu_scale(void)
    132 {  
    133     u64 capacity;
    134     int cpu;
    135    
    136     if (!raw_capacity)    
    137         return;
    138                           
    139     pr_debug("cpu_capacity: capacity_scale=%u\n", capacity_scale);
    140     for_each_possible_cpu(cpu) {   
    141         pr_debug("cpu_capacity: cpu=%d raw_capacity=%u\n",
    142              cpu, raw_capacity[cpu]);       
    143         capacity = (raw_capacity[cpu] << SCHED_CAPACITY_SHIFT)
    144             / capacity_scale;
    /*把cpu_scale capacity歸一化到1024*/
    145         topology_set_cpu_scale(cpu, capacity);
    /*cpu_scale[0~2]=488; cpu_scale[3]=1024*/
    146         pr_debug("cpu_capacity: CPU%d cpu_capacity=%lu\n",
    147             cpu, topology_get_cpu_scale(cpu));
    148     }
    149 }
    150 
  2. cpufreq_transition_notifier註冊到cpufreq_transition_notifier_list鏈表,在cpufreq 調頻時,通過調用註冊在cpufreq_transition_notifier_list上的callback函數,使用FIE(Frequency Invariant Engine)。

    註冊notifier:__init register_cpufreq_notifier(void)->cpufreq_register_notifier(&cpufreq_notifier, CPUFREQ_TRANSITION_NOTIFIER)

 

 

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