日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

interactive governor study for android

發(fā)布時間:2023/12/16 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 interactive governor study for android 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

interactive governor全部思考思路:

1、Interactive governor 初始化,一些定時器綁定的函數(shù),創(chuàng)建內(nèi)核線程進(jìn)行調(diào)頻并注冊interative governor(對應(yīng)cpufreq_interactive_initfunction)。

?

2、注冊governor執(zhí)行函數(shù):cpufreq_governor_interactive這個函數(shù)通過三個不同的event來處理不同的情況,分別如下:

  • CPUFREQ_GOV_START:用來對每個CPU對應(yīng)的Governor info進(jìn)行初始化操作并創(chuàng)建相應(yīng)的governorsysfs interface,并注冊idle和頻率改變通知鏈。由于interactive governor是通過定時器來實時的統(tǒng)計cpuload,所以這個governor一啟動的時候就必須設(shè)定相關(guān)的定時器。通過函數(shù)cpufreq_interactive_timer_start實現(xiàn)的

  • CPUFREQ_GOV_STOP:用來暫停此governor的工作,那么就必須將啟動這個governor設(shè)定的一些信息就必須清除了,比如創(chuàng)建的通知鏈、定時器、sysfsinterface等等。

  • CPUFREQ_GOV_LIMITS:這里是當(dāng)用戶修改CPU的最小最大頻率的時候會調(diào)用此處,目的是用戶修改之后,governor要知道這些并將其寫入到相應(yīng)的CPU相關(guān)的結(jié)構(gòu)體中。即對結(jié)構(gòu)體cpufreq_policy中的最大最小頻率進(jìn)行修改,其實在linux系統(tǒng)中或者android手機中通過console執(zhí)行”echox >/sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq“,就可以修改最小頻率。

  • 通過kernel給出的文檔我們可以更加容易的理解這三個event的用意:

    CPUFREQ_GOV_START: This governor shall start its duty for the CPU policy->cpu

    CPUFREQ_GOV_STOP: This governor shall end its duty for the CPU policy->cpu

    CPUFREQ_GOV_LIMITS: The limits for CPU policy->cpu have changed to policy->minand policy->max.

  • 3、既然啟動了interactive governor,那么它是如何工作的呢?

    首先啟動code:cpufreq_interactive_timer_start,在初始化的時候,每一個CPU core的timer都是獨立工作的。Code is as follow:

    staticvoid cpufreq_interactive_timer_start(int cpu)

    {

    structcpufreq_interactive_cpuinfo *pcpu = &per_cpu(cpuinfo, cpu);

    unsignedlong expires = jiffies + usecs_to_jiffies(timer_rate);

    unsignedlong flags;

    ?

    pcpu->cpu_timer.expires= expires;//CPU core 統(tǒng)計load的定時器

    add_timer_on(&pcpu->cpu_timer,cpu);//加入到定時器鏈表中去

    if(timer_slack_val >= 0 && pcpu->target_freq >pcpu->policy->min) {

    expires+= usecs_to_jiffies(timer_slack_val);

    pcpu->cpu_slack_timer.expires= expires;

    add_timer_on(&pcpu->cpu_slack_timer,cpu);//not consider

    }

    ?

    spin_lock_irqsave(&pcpu->load_lock,flags);

    //計算CPU啟動到現(xiàn)在的idle時間

    pcpu->time_in_idle=

    get_cpu_idle_time(cpu,&pcpu->time_in_idle_timestamp);

    pcpu->cputime_speedadj= 0;

    //計算啟動啟動到現(xiàn)在的時間

    pcpu->cputime_speedadj_timestamp= pcpu->time_in_idle_timestamp;

    //上面的兩個參數(shù)是用來計算cpuload使用的,即cpuidle時間是多少,忙的時間是多少。

    spin_unlock_irqrestore(&pcpu->load_lock,flags);

    }

    ?

    定時器設(shè)置之后,一旦定時器到期的話就會調(diào)用定時器綁定的函數(shù),并執(zhí)行這個函數(shù),這個函數(shù)是:

    staticvoid cpufreq_interactive_timer(unsigned long data)。這個函數(shù)是interactivegovernor的關(guān)鍵,只要把這個函數(shù)弄懂了基本上就搞明白了這個governor是怎么工作的了。下面就來分析此函數(shù)。看它是怎樣jisuacpuload的,通過如下代碼實現(xiàn):

    ?

    now= update_load(data);//計算CPU運行到現(xiàn)在的總時間

    //現(xiàn)在的總時間減去上次的總時間就是在一個統(tǒng)計周期里CPU運行的時間。

    delta_time= (unsigned int)(now – pcpu->cputime_speedadj_timestamp);

    /*下面的這個值,我們可以通過update_load這個函數(shù)來看它是怎么計算的。是 active_time乘以當(dāng)前頻率的value,pcpu->cputime_speedadj+= active_time * pcpu->policy->cur;*/

    cputime_speedadj= pcpu->cputime_speedadj;

    spin_unlock_irqrestore(&pcpu->load_lock,flags);

    ?

    if(WARN_ON_ONCE(!delta_time))//detect whether delta_time is zero?

    gotorearm;

    /*活動時間除以總的運行時間在乘以當(dāng)前頻率,值存儲在cputime_speedadj中*/

    do_div(cputime_speedadj,delta_time);

    /*上面計算的結(jié)果存儲在cputime_speedadj中,是一個百分比*當(dāng)前頻率,下面乘以 100的目的就是計算cpu_load的時候是一個大于1的整數(shù)。*/

    ?

    loadadjfreq= (unsigned int)cputime_speedadj * 100;

    /*得到cpu_load的值,至于為什么這樣做,是值得思考的。我的理解就是既考慮了時間又考慮了當(dāng)前頻率,因為在調(diào)整頻率的時候不能只看單純的load信息,即cpu的忙閑的比例。*/

    cpu_load= loadadjfreq / pcpu->target_freq;

    上面的分析我們已經(jīng)知道了CPUload的值是怎樣計算的。接下來如何使用CPUload的值來調(diào)節(jié)CPU的頻率呢?

    看如下的code:

    boosted= boost_val || now < boostpulse_endtime;//用在突發(fā)任務(wù)的時候

    if(cpu_load >= go_hispeed_load || boosted) {

    if(pcpu->target_freq < hispeed_freq) {

    new_freq= hispeed_freq;

    }else {

    new_freq= choose_freq(pcpu, loadadjfreq);

    ?

    if(new_freq < hispeed_freq)

    new_freq= hispeed_freq;

    }

    }else {

    new_freq= choose_freq(pcpu, loadadjfreq);

    }

    go_hispeed_loaddefault value is 99.我們可以很清楚的看到這些語句是如何實現(xiàn)計算new_freq的值的。這些語句比較好理解,如果CPUload>=99的話,那么無論如何都要將CPU的頻率提高到最高頻率。否則按照普通方式進(jìn)行處理。

    ?

    這個函數(shù)choose_freq是用來計算new_freq的,那么它又是如何實現(xiàn)的呢?簡單的說下就是系統(tǒng)設(shè)置了一個target_load,目的是當(dāng)前設(shè)置當(dāng)前的頻率是CPUcore的load值降低到此target_load值之下,如果這個值越小,系統(tǒng)就會越頻繁的升高CPU的頻率使loadvalue<target_load。它的整個代碼就是這個意思,對于target_load的含義我們看kerneldocument有如下解釋:

    target_loads:CPU load values used to adjust speed to influence thecurrentCPU load toward that value. In general, the lower the targetload,the more often the governor will raise CPU speeds to bring loadbelowthe target. The format is a single target load, optionallyfollowedby pairs of CPU speeds and CPU loads to target at or abovethosespeeds. Colons can be used between the speeds and associated

    targetloads for readability. For example:

    851000000:90 1700000:99

    targetsCPU load 85% below speed 1GHz, 90% at or above 1GHz, until1.7GHzand above, at which load 99% is targeted. If speeds arespecifiedthese must appear in ascending order. Higher target load

    valuesare typically specified for higher speeds, that is, target loadvaluesalso usually appear in an ascending order. The default istargetload 90% for all speeds.好好思考這些東西對理解一些參數(shù)還是很有幫助的。

    找到了new_freq的值,還沒有完,code繼續(xù)告訴我們,究竟在什么時候才可以進(jìn)行調(diào)節(jié)頻率而不影響系統(tǒng)的實時性能,尤其對interactivegovernor是一個升頻快速的governor,能夠及時的響應(yīng)系統(tǒng)的負(fù)載信息,及時的調(diào)節(jié)CPU頻率來滿足用戶體驗,當(dāng)然這是以耗電為代價的。

    不說廢話,接著分析,知道我們看到調(diào)節(jié)頻率的code為止:

    if(pcpu->target_freq >= hispeed_freq &&

    new_freq > pcpu->target_freq &&

    now - pcpu->hispeed_validate_time <

    freq_to_above_hispeed_delay(pcpu->target_freq)) {

    trace_cpufreq_interactive_notyet(data,cpu_load, pcpu->target_freq,pcpu->policy->cur,new_freq);

    goto rearm;

    }

    ?

    pcpu->hispeed_validate_time= now;

    ?

    if(cpufreq_frequency_table_target(pcpu->policy, pcpu->freq_table,new_freq, CPUFREQ_RELATION_L,

    &index))

    goto rearm;

    ?

    new_freq= pcpu->freq_table[index].frequency;

    我們來分析第一個if語句。如果滿足了第一個條件就是當(dāng)前的目標(biāo)頻率是最高頻率了,新計算出來的new_freq比最高頻率還高的話,繼續(xù)看now- pcpu->hispeed_validate_time <freq_to_above_hispeed_delay(pcpu->target_freq)這條語句,比較難以費解。我的理解是這樣的:CPU到現(xiàn)在的運行時間減去CPU上次呆在hispeed的時間點上,如果這個value小于設(shè)定的值,即函數(shù)freq_to_above_hispeed_delay(pcpu->target_freq)。即如果系統(tǒng)的頻率處在較高的頻率點上的時間小于這個值的話,那么就沒有必要調(diào)節(jié)頻率了,因為此時的CPU的頻率值就符合要求的。所以直接”gotorearm“了。

    如果這條語句不符合,則更新pcpu->hispeed_validate_time,設(shè)置為CPU到現(xiàn)在的運行時間。

    接下來分析第二條if語句。在freq_table中查找>=new_freq的頻率點。有的話,直接設(shè)置new_freq為freq_table中的值。這樣我們的new_freq就找出來了,至于是否就是本次CPU的調(diào)節(jié)的頻率接著往下看。

    下面這些code還是比較費解的。

    /*

    * Do not scale below floor_freq unless we have been at or above the

    * floor frequency for the minimum sample time since last validated.

    */

    if(new_freq < pcpu->floor_freq) {

    if(now - pcpu->floor_validate_time < min_sample_time) {

    trace_cpufreq_interactive_notyet(

    data,cpu_load, pcpu->target_freq,

    pcpu->policy->cur,new_freq);

    goto rearm;

    }

    }

    我的理解就是當(dāng)new_freq小于pcpu->floor_freq(基準(zhǔn)頻率,暫且這樣說吧)的時候,那么就沒有必要急于頻率的調(diào)整了,如果此時的CPU運行時間減去pcpu->floor_validate_time還小于最小抽樣間隔,那么就真的不需要調(diào)整頻率了,為和選用最小抽樣時間間隔來做比較呢,而這整體現(xiàn)了google工程師的高明之處,在最小抽樣間隔期間內(nèi),CPU的頻率是不會改變的,這就說明了這點。

    接著看下面的code:

    它的注釋很好的解釋了一切。不再多講。

    /*

    * Update the timestamp for checking whether speed has been held at

    * or above the selected frequency for a minimum of min_sample_time,

    * if not boosted to hispeed_freq. If boosted to hispeed_freqthen we

    * allow the speed to drop as soon as the boostpulse duration expires

    * (or the indefinite boost is turned off).

    */

    ?

    if(!boosted || new_freq > hispeed_freq) {

    pcpu->floor_freq= new_freq;

    pcpu->floor_validate_time= now;

    }

    接著下面的code:

    if(pcpu->target_freq == new_freq) {

    trace_cpufreq_interactive_already(

    data,cpu_load, pcpu->target_freq,

    pcpu->policy->cur,new_freq);

    goto? rearm_if_notmax;

    }

    如果計算的new_freq與目標(biāo)頻率是一樣的,跳轉(zhuǎn)到”rearm_if_notmax“處,在那里判斷是否是最高頻率,如果是最高頻率的話,就結(jié)束本次頻率的調(diào)整,并關(guān)閉cputime定時器,CPU頻率會一直呆在最高頻率上(不管其他CPUcore的load是輕還重),等待下次此CPUcore idle的時候重新設(shè)置定時器。idle的進(jìn)出我們一開始就分析了,使用了idle通知鏈機制:

    idle_notifier_register(&cpufreq_interactive_idle_nb);//注冊

    //通知鏈處理函數(shù)

    staticint cpufreq_interactive_idle_notifier(struct notifier_block *nb,

    unsigned long val,

    void *data)

    {

    switch(val) {

    case IDLE_START:

    cpufreq_interactive_idle_start();

    break;

    case IDLE_END:

    cpufreq_interactive_idle_end();

    break;

    }

    ?

    return0;

    }

    ?

    staticstruct notifier_block cpufreq_interactive_idle_nb = {

    .notifier_call= cpufreq_interactive_idle_notifier,//對應(yīng)的通知鏈處理函數(shù)

    };

    接下來,一切都比較順利的情況,interactivegovernor是怎樣實現(xiàn)頻率調(diào)節(jié)的:

    相關(guān)代碼如下:

    pcpu->target_freq= new_freq;//設(shè)置新的目標(biāo)頻率

    spin_lock_irqsave(&speedchange_cpumask_lock,flags);

    /*設(shè)置需要調(diào)節(jié)頻率的CPUcore的cpumask*/

    cpumask_set_cpu(data,&speedchange_cpumask);

    spin_unlock_irqrestore(&speedchange_cpumask_lock,flags);

    /*喚醒內(nèi)核線程來執(zhí)行頻率的改變*/

    wake_up_process(speedchange_task);

    ?

    rearm_if_notmax:

    /*

    * Already set max speed and don't see a need to change that,

    * wait until next idle to re-evaluate, don't need timer.非常重要

    */

    if(pcpu->target_freq == pcpu->policy->max) {

    goto exit;

    }

    rearm:

    /*

    *判斷cpu_timer是否為空,為空的話就重新設(shè)置相關(guān)的timer并

    *將其加入到定時器鏈表中。

    */

    if(!timer_pending(&pcpu->cpu_timer))

    cpufreq_interactive_timer_resched(pcpu);

    ?

    exit:

    /*放棄使能信號量*/

    up_read(&pcpu->enable_sem);

    return;

    到此為止,cpufreq_interactive_timer函數(shù)就這樣結(jié)束了,比較復(fù)雜,這些搞懂了,其他之類的函數(shù)就是為它服務(wù)的。

    ?

    下面進(jìn)入調(diào)節(jié)頻率的函數(shù)了,也就是創(chuàng)建的內(nèi)核線程綁定的函數(shù)cpufreq_interactive_speedchange_task,分析如下:

    staticint cpufreq_interactive_speedchange_task(void *data)

    {

    unsignedint cpu;

    cpumask_ttmp_mask;

    unsignedlong flags;

    structcpufreq_interactive_cpuinfo *pcpu;

    ?

    /*這個循環(huán)不斷的在執(zhí)行*/

    while(1) {

    set_current_state(TASK_INTERRUPTIBLE);

    spin_lock_irqsave(&speedchange_cpumask_lock,flags);

    ?

    if(cpumask_empty(&speedchange_cpumask)) {

    spin_unlock_irqrestore(&speedchange_cpumask_lock,flags);

    schedule();//如果沒有哪個CPUcore的頻率需要調(diào)整,就去執(zhí)行其他事情

    ?

    if(kthread_should_stop())

    break;

    ?

    spin_lock_irqsave(&speedchange_cpumask_lock,flags);

    }

    /*將線程設(shè)置為可運行狀態(tài)*/

    set_current_state(TASK_RUNNING);

    tmp_mask= speedchange_cpumask;//臨時保存

    /*記得每次都要清除,因為這個值可能時刻在改變著*/

    cpumask_clear(&speedchange_cpumask);

    spin_unlock_irqrestore(&speedchange_cpumask_lock,flags);

    /*這里開始真正的頻率調(diào)節(jié)了*/

    for_each_cpu(cpu,&tmp_mask) {

    unsignedint j;

    unsignedint max_freq = 0;

    ?

    pcpu= &per_cpu(cpuinfo, cpu);

    if(!down_read_trylock(&pcpu->enable_sem))

    continue;

    if(!pcpu->governor_enabled) {

    up_read(&pcpu->enable_sem);

    continue;

    }

    ?

    for_each_cpu(j,pcpu->policy->cpus) {

    structcpufreq_interactive_cpuinfo *pjcpu =&per_cpu(cpuinfo,j);

    /*找出所有CPUcore的最大頻率*/

    if(pjcpu->target_freq > max_freq)

    max_freq= pjcpu->target_freq;

    }

    /*調(diào)節(jié)頻率,執(zhí)行的函數(shù)是一個回調(diào)函數(shù)(callbackfunction),應(yīng)該是DVFSdriver執(zhí)行具體動作的*/

    if(max_freq != pcpu->policy->cur)

    __cpufreq_driver_target(pcpu->policy,max_freq,CPUFREQ_RELATION_H);

    trace_cpufreq_interactive_setspeed(cpu,pcpu->target_freq,pcpu->policy->cur);

    ?

    up_read(&pcpu->enable_sem);

    }

    }

    ?

    return 0;

    }

    到此調(diào)節(jié)頻率完成了。就這樣周而復(fù)始的執(zhí)行上述code。

    我們必須知道一種情況就是,如果某個CPUcore不處在idlestatus,并且此時的CPUcore的frequency==max_freq的話,統(tǒng)計CPUcore load的函數(shù)(staticvoid cpufreq_interactive_timer(unsigned long data))不會執(zhí)行,直到下次idle的到來。

    如果對于有些參數(shù)不是很理解的話,可以查看kernel目錄下:document/cpufreq/governor.txt,里面對多種governor的參數(shù)進(jìn)行了詳細(xì)的說明。

    ?

    還有一些細(xì)節(jié)自己還是沒有弄明白,希望有疑問的朋友,或者說的有錯誤的地方,望各位看官不吝賜教,謝謝!

    總結(jié)

    以上是生活随笔為你收集整理的interactive governor study for android的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 中国黄色一级大片 | 久久久123| 国产日韩欧美一区 | 国产一区=区| 悟空影视大全免费高清观看在线 | 人人爱人人射 | 无码日韩精品视频 | www精品一区二区三区 | 内射后入在线观看一区 | 日本成人一区二区三区 | 日本一区二区欧美 | 久热欧美 | 在线免费观看国产视频 | 亚洲一区 | 性少妇videosexfreexxx片 | 亚洲av无码一区二区二三区软件 | 欧美一级黄色网 | 深夜福利视频在线观看 | 亚洲男人天堂2017 | 女儿的朋友5中汉字晋通话 欧美成人免费高清视频 | 国产综合一区二区 | 91在线超碰| 国产另类av| 国内9l自拍 | 日本女优一区 | 国产18禁黄网站免费观看 | 草比网站 | 欧美男人又粗又长又大 | 善良的女朋友在线观看 | 亚洲综合免费观看高清完整版 | 黄色大片免费在线观看 | 久久嗨 | 青青青视频在线 | 欧美s码亚洲码精品m码 | 韩国主播青草55部完整 | 久草手机在线视频 | 精品国产午夜福利在线观看 | 99久久精品国产一区二区成人 | 日本三级黄色录像 | 不卡的av在线免费观看 | 欧美日韩亚洲高清 | 麻豆视频网站入口 | 成人免费公开视频 | 成人av网站免费 | 草莓巧克力香氛动漫的观看方法 | 精品一区三区 | 超碰97在线免费观看 | 三级做爰在线观看视频 | 久久精品波多野结衣 | 精品日韩欧美 | 2019天天操 | 人人爽久久涩噜噜噜网站 | 精品国产视频一区二区三区 | 国产女18毛片多18精品 | 成人超碰在线 | 毛片在线免费观看网址 | 亚洲免费网址 | 国产成人av电影 | 青青草视频免费看 | 免费中文字幕日韩欧美 | 国产精品-区区久久久狼 | 欧美日韩国产综合网 | 夜夜躁狠狠躁 | 日韩欧美成人免费视频 | 一区二区三区丝袜 | 欧美天堂网站 | 神马午夜我不卡 | 姐姐你真棒插曲快来救救我电影 | 福利综合网 | 日韩视频在线观看一区 | 成年女人毛片 | 91毛片观看| 日本在线二区 | 成人亚洲在线 | 国产成人久久777777 | 先锋av资源网 | 五月天婷婷色 | 涩涩国产| 欧美一级色图 | 婷婷丁香一区二区三区 | 日韩欧美自拍偷拍 | 欧美一二区视频 | 日本福利一区二区三区 | 国产精品日韩av | 无限资源日本好片 | 黑人一级女人全片 | 免费网站在线观看黄色 | 亚洲在线a| www亚洲精品 | 黄色在线播放视频 | 成人在线网站 | 国产高清免费观看 | 男人天堂黄色 | 国产女大学生av | 精品国产黄 | 大陆明星乱淫(高h)小说 | 日韩av不卡电影 | 齐天大性床战铁扇公主 | av一区二区在线观看 |