1. 程式人生 > >高通GPU頻率動態調整機制

高通GPU頻率動態調整機制

我們來看一下他們的實現機制。

首先在初始化的過程中,msm-adreno-tz先呼叫devfreq_add_governor(),向devfreq框架中新增一個governor。

隨後,Adreno在初始化的過程中呼叫devfreq_add_device(“msm-adreno-tz”),並選定其使用的governor,它同時像devfreq框架提供了幾個回撥函式,這些函式在devfreq_dev_profile結構體中:

                    .target =kgsl_devfreq_target;//設定調整後的頻率

                    .get_dev_status= kgsl_devfreq_get_dev_status;//獲得GPU的負載

                    .get_cur_freq= kgsl_devfreq_get_cur_freq;//獲得GPU當前的頻率值

在匹配完成後,devfreq框架傳送DEVFREQ_GOV_START訊息到msm-adreno-tz,這樣msm-adreno-tz就會註冊notifier到Adreno,這樣 Adreno就可以使用msm-aderno-tz來動態調整頻率了。

在msm-adreno-tz初始化階段,會向Adreno註冊一個回撥函式tz_notify(),這樣Adreno就可以通過tz_notify來通知msm-adreno-tz動態調整頻率了,具體流程是:

adreno_dispatcher_work

    -->kgsl_pwrscale_idle

        -->queue_work(devfreq_notify_ws)

            -->do_devfreq_notify(ADRENO_DEVFREQ_NOTIFY_RETIRE)

                -->tz_notify()

                    -->update_devfreq(devfreq)

                        -->profile->get_dev_status()

                            -->profile.target()

adreno_dispatcher_work()相當於是一個分配任務的回撥介面,可以理解是個Loop,這樣流程就可以串起來了。

msm-adreno-tz動態調整頻率使用devfreq框架提供的update_devfreq()函式,該函式通過get_target_freq()回撥函式來獲得要調整的頻率值。在performance中,get_target_freq()返回的是max_freq,在powersave中返回的是min_freq,在我們的msm-adreno-tz中,則會呼叫profile->get_dev_status()回撥函式,從Adreno驅動中獲取GPU的負載,並通過一定演算法(__secure_tz_entry3??)來計算出頻率值,並通過profile->target()回撥函式,改變Adreno的頻率,至此一個Loop就完成了,接下來就是一直Loop直至系統待機。

高通給的可以手動調節GPU頻率的介面為:

echo1 > /sys/class/kgsl/kgsl-3d0/force_clk_on

echo 10000000 > /sys/class/kgsl/kgsl-3d0/idle_timer

echo performance > /sys/class/kgsl/kgsl-3d0/devfreq/governor

echo<max freq> > /sys/class/kgsl/kgsl-3d0/gpucl

具體理解為是:

1、echo 1 > force_clk_on是設定KGSL_PWRFLAGS_CLK_ON這個power_flags。使用echo freq > gpuclk時,是通過kgsl_pwrctrl_pwrlevel_change設定頻率,它會判斷KGSL_PWRFLAGS_CLK_ON這個power_flags,如果沒有這個flag,可能就不會真正的設定頻率,不過我測試了一下,即使不用這個命令,在大多數情況下也是可以工作的。也就是說,它會強制使得接下來第@4步的設定生效。

2、echo 10000000 > idle_timer,,設定interval_timeout,預設值是80ms。

當系統啟動的時候,會初始化一個idle_timer-->kgsl_timer,這個timer會執行kgsl_idle_check()用於檢測GPU是否處於idle狀態,如果是,則會呼叫:

kgsl_pwrctrl_sleep()

    -->devfreq_suspend_device()

        -->governor->event_handler(DEVFREQ_GOV_SUSPEND)

            -->msm-adreno-tz/performance,stop

接下來如果有系統呼叫至KGSL,則會喚醒Adreno:

kgsl_pwrscale_wake()

    --> devfreq_resume_device()

        -->governor->event_handler(DEVFREQ_GOV_RESUME)

            -->msm-adreno-tz/performance,start

而在governor restart的過程中,會重新初始化GPU所對應的頻率,這樣即使我們設定了我們想要的頻率,最後也很快就被沖掉了,所以要把該interval_timeout設定為很大。

3、echo performance > devfreq/governor, 這時devfreq會為Adreno重新選擇governor,也就是performance。這時它會使用GPU所支援的最大頻率,而不考慮系統的負載。

預設的msm-adreno-tz機制會不停的動態更新頻率,即使我們設定過頻率也會被覆蓋掉,這就是為什麼直接設定頻率無效的原因。

而如果改成performance機制,這樣它會使得Adreno動態的調整機制無效,我們的設定才會生效。

4、echo freq > gpuclk,簡單的設定GPU的頻率,一般是在200000 000, 320 000 000和450 000 000之間,如果不對,就會就近選擇這三者之一。

在前面設定做鋪墊的情況下,idle_interval被設定成了很大,這樣邊不會suspend、resume,我們設定的gpuclk才不會被重新設定,並且do_devfreq_notify()也不起了作用,所以可以用我們設定的頻率進行功耗及跑分測試了。