cpufreq 调频 --- linux kernel 实现赏析

98 篇文章 11 订阅
22 篇文章 0 订阅
  1. 注册cpufreq_driver 时设置 cpufreq_policy .
    在这里插入图片描述
    在这里插入图片描述
/*
 *    问渠哪得清如许, 唯有源头活水来. 那么我们就从
 *    这一个源头来看下 struct cpufreq_polcy 是怎么从上游源头流经到下游的.
 *    在流动途中接纳了什么 ? 最终形成了什么 ?
 *    
 *    if (cpu_online(cpu)) 
 *         ret = cpufreq_online()
 * 
 *    很显然顾名思义. cpufreq作用的对象是处于online状态的cpu. 之所以加上
 *    这个 if 判断 是考虑到 cpuhotplug 机制的影响.  当然如果cpuhp状态跃迁
 *    到online上来了,那么cpufreq_online 是会被再次调用的. 这是cpufreq_driver_register()
 *    的职责. 看下面.
 *    cpufreq_register_driver(...)
 *    {
 *          .......
 *       	ret = cpuhp_setup_state_nocalls_cpuslocked(CPUHP_AP_ONLINE_DYN,
 *						   "cpufreq:online",
 *						   cpuhp_cpufreq_online,   // 在这里.
 *						   cpuhp_cpufreq_offline);
 *    }
 *    ok, 现在我们知道 处于online状态的cpu会执行下面的操作. 且如果小于online状态的cpu再次处于
 *    online状态时,该函数会再次被调用. 这是cpuhp所包含的一个动作. 你体会到了cpuhp 设计的精妙了吗 ? 😄
 */
static int cpufreq_online(unsigned int cpu)
{
   /*
    *  下面给这个policy赋值有两个地方. 这涉及到了BPAP.
    *  要弄懂这个policy 你需要先明白 cpufreq_policy 与 cpus的关系.
    *  一般来说. 同一个簇下的cpu是由同一个clock提供时钟输入、同一路regulator电源供电.
    *  所以 只需要一个cpu管理policy 就可以了. 哈哈😄,不允许藩镇割据各自为政 . 画了一个图. 看下面
    * 
    *      for_each_cpu(j, policy->related_cpus) {
	* 		    per_cpu(cpufreq_cpu_data, j) = policy;  // 在这里.
    *   
    *   真正的策略是policy持有的 governor,还没有走到那里, 到了再说. 
	*/
    struct cpufreq_policy *policy;

   /*
    *  获取该cpu上的per-cpu变量cpufreq_cpu_data. 它指向该cpu对应的 struct cpufreq_policy
    *  作者意图很明显, 就是想看看该cpu 是否有一个policy来管理它.
    *  因为
    *  每个处于online状态的cpu都会被遍历,对于每一个cpu都执行cpufreq_online. 
    *  cpu 为 0, 该policy 显然为 NULL. new_policy =true
    *  继续下面的逻辑:
    *      if (new_policy) {
	*	      for_each_cpu(j, policy->related_cpus) {
	*		      per_cpu(cpufreq_cpu_data, j) = policy;	// 在这里
	*	so. cpu0新创建的cpufreq_policy来管理cluster中的所有cpu. AP们感觉岁月静好, 只不过都是BP在负重前行了.
    */
    policy = per_cpu(cpufreq_cpu_data, cpu);
    if (policy) {
        
    } else {
       /* 
        *  用bool来区分是cpu0还是cpux的执行逻辑.
        */
    	new_policy = true;  
       /*
        * ok, 创建policy吧. 底层调用kzalloc(), 然后赋值初始化. 玩套路吗大哥 !
    	*/
		policy = cpufreq_policy_alloc(cpu);
		if (!policy)
			return -ENOMEM;
    }
}

在这里插入图片描述
二 : mechanism for registering utilization update callbacks

/*
 *  核心来了. DLRTCFS 都会执行到该函数.
 *  注意, 它是per-cpu类型的. 它也肯定要被设置为per-cpu的. cpufreq 把per-cpu机制发挥的淋漓尽致 !
 *  它就是调度器与schedutil governor 之间的桥梁 ! 直接看下面, 体会一下原汁原味的意思 : 
 *    This function is called by the scheduler on the CPU whose utilization is being updated.
 *  懂了吧 ! 😄 知道了它的意思, 我看看它的参数. 
 * 
 *  1. struct rq *rq : 不用多说,通用的运行队列.
 *  2. flags : 为啥要update. 通常传入 0.
 * 
 *  为什么要传入一个通用的queue, 😄 想一下如果你传入一个cfs_rq, 它只能代表cfs啊. 传入的目的显而易见
 *   static inline int cpu_of(struct rq *rq)
 *	 {
 *	 #ifdef CONFIG_SMP
 *		 return rq->cpu;  // 在这里.
 *	 #else
 *		 return 0;
 *	 #endif
 *	}
 */
static inline void cpufreq_update_util(struct rq *rq, unsigned int flags)
{
   /*
    *13的设计. 里面只包含一个func. 即cpu使用率发生变化的时候的回调函数.
    *   ok, 现在问题来了, 该callback 是在什么时候被设置进去的.
    *   别慌 哈哈😄, 它是在启动schedutil governor 的时候设置的. 这也是合理的时机. 
	*/
    struct update_util_data *data;
   /*
    *    ok, 根据cpuid 取出per_cpu变量了.自然的就执行data持有的func了.
    *    那我们今天就聊聊 Kernel中第二大特性 RCU. 
	*/
	data = rcu_dereference_sched(*per_cpu_ptr(&cpufreq_update_util_data,
						 	 cpu_of(rq)));
   /*
    *   通路不复杂, 终于再这里落地了. 通知schedutil governor了.
    *   governor 是否下发调频给cpufreq_driver, 还是需要做判断的, 总不能DL task 入队一次就实际调频一次吧.
    *   具体再func(), 一会我们就看.
	*/						 	 
    if (data)
		data->func(data, rq_clock(rq), flags);						 	 
}
/*
 *    启动 schedutil governor !
 *    ok, 看启动的时机.
 */
static int sugov_init(struct cpufreq_policy *policy)
{
    
}
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值