[RK3288][Android6.0] 调试笔记 --- 读取GPU当前频率方法

Platform: Rockchip 
OS: Android 6.0 
Kernel: 3.10.92

mali_device_driver 分为两个部分 : platform_dependent_part 和 common_parts, 参见 mali_kbase_config_rk.c 开头部分的注释.

gpu dvfs核心控制在mali_kbase_dvfs.c中.

s_mali_dvfs_level_table 定义gpu所有可变的freq level以及对应的min utilisation和max utilisation.

static struct mali_dvfs_level_t s_mali_dvfs_level_table[] = {
    {100000, 0, 70},
    {160000, 50, 65},
    {266000, 60, 78},
    {350000, 65, 75},
    {400000, 70, 75},
    {500000, 90, 100},
};

不过它会被dts中的operating-points所覆盖

clk_gpu_dvfs_table: clk_gpu {
    operating-points = <
        /* KHz uV */
        200000 1200000
        300000 1200000
        400000 1200000
        >;
};

gpu dvfs运行时, common parts (metrics system)会周期地(20ms)通知回调 platform_dependent_part 中的函数 kbase_platform_dvfs_event(), 并传入当前的 gpu utilization.

dvfs_callback -> kbase_pm_get_dvfs_action -> kbase_platform_dvfs_event

int kbase_platform_dvfs_event(struct kbase_device *kbdev,
                  u32 utilisation, /* calculated_utilisation. */
                  u32 util_gl_share_no_use,
                  u32 util_cl_share_no_use[2])
{
    struct rk_dvfs_t *dvfs = get_rk_dvfs(kbdev);

    dvfs->utilisation = utilisation;

    if (dvfs->is_enabled) {
        /* run 'mali_dvfs_work' in 'mali_dvfs_wq', on cpu0. */
        queue_work_on(0, dvfs->mali_dvfs_wq, &(dvfs->mali_dvfs_work));
    }

    return 1;
}

该 event 被转发到 mali_dvfs_event_proc() 中处理.

static void mali_dvfs_event_proc(struct work_struct *w)
{
    int ret = 0;
    struct rk_dvfs_t *dvfs = work_to_dvfs(w);
    int temp = rockchip_tsadc_get_temp(1, 0);

    if (INVALID_TEMP == temp) {
        D("got invalid temp, reset to 0.");
        temp = 0;
    }
    dvfs->sum_of_temps += temp;
    dvfs->times_of_temp_measures++;

    if (dvfs->times_of_temp_measures >= NUM_OF_TEMP_MEASURES_IN_A_SESSION) {
        dvfs->temp = dvfs->sum_of_temps
            / NUM_OF_TEMP_MEASURES_IN_A_SESSION;

        dvfs->times_of_temp_measures = 0;
        dvfs->sum_of_temps = 0;
    }

    /*-------------------------------------------------------*/

    mutex_lock(&(dvfs->dvfs_mutex));

    if (is_overheated(dvfs)) {
        if (could_jump_down(dvfs)) {
            I("to jump down for overheated, temp:%d.",
              dvfs->temp);
            ret = jump_down_actually(dvfs);
            if (ret)
                E("fail to jump down, ret:%d.", ret);
        } else {
            W("overheated! temp:%d, but can't jump down anymore.",
              dvfs->temp);
        }

        dvfs->temp = 0;
        goto EXIT;
    }

    /* If calculated_utilisation asks current_level to jump up,
     * and current_level could jump up,
     * then ....  */
    if (dvfs->utilisation > get_util_max_threshold_of_curr_level(dvfs) &&
        could_jump_up(dvfs)) {
        inc_requests_to_jump_up(dvfs);

        if (are_enough_jump_up_requests(dvfs)) {
            V("to jump up to highest, util:%d, curr_level:%d.",
              dvfs->utilisation,
              get_current_level(dvfs));
            ret = jump_up_to_highest_actually(dvfs);
            if (ret) {
                E("fail to jump up, ret:%d.", ret);
                goto EXIT;
            }

            reset_requests_to_jump_up(dvfs);
        }

        reset_requests_to_jump_down(dvfs);
        goto EXIT;
    } else if (dvfs->utilisation
            < get_util_min_threshold_of_curr_level(dvfs) &&
           could_jump_down(dvfs)) {
        inc_requests_to_jump_down(dvfs);

        if (are_enough_jump_down_requests(dvfs)) {
            V("to jump down actually, util:%d, curr_level:%d",
              dvfs->utilisation,
              get_current_level(dvfs));
            jump_down_actually(dvfs);

            reset_requests_to_jump_down(dvfs);
        }

        reset_requests_to_jump_up(dvfs);
        goto EXIT;
    } else {
        reset_requests_to_jump_down(dvfs);
        reset_requests_to_jump_up(dvfs);

        V("stay in current_level, util:%d, curr_level:%d.",
                dvfs->utilisation,
                get_current_level(dvfs));
    }

EXIT:
    mutex_unlock(&(dvfs->dvfs_mutex));
}

a. 如果当前温度过高,那么执行jump_down_actually()下调频率. 
b. 如果当前utilization 大于 max_utilization_of_current_dvfs_level, 则直接上跳到最高频率(jump_up_to_highest_actually() ).不过要满足NUM_OF_REQUESTS_TO_PERFORM_ACTUAL_JUMP_UP的次数才上跳. 
c. 如果当前utilization 小于max_utilization_of_current_dvfs_level,则一级级下跳(jump_down_actually()).不过要满足NUM_OF_REQUESTS_TO_PERFORM_ACTUAL_JUMP_DOWN的次数才下跳.

如果觉得目前上跳策略太激进, 则可以在 mali_dvfs_event_proc() 进一步修改, 比如每次只上跳一级, 而不是直接到 highest.

原文地址 https://blog.csdn.net/kris_fei/article/details/78059392


参考: 
基于Android系统的GPU动态调频方案

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值