Linux内核Thermal框架详解十五、Thermal Governor(5)
本文部分内容参考
Linux Thermal机制源码分析之框架概述_不捡风筝的玖伍贰柒的博客-CSDN博客,
Linux内核中最牛逼的温控方案——IPA(二)_啪一个右边腿的博客-CSDN博客,
Linux thermal governor之IPA分析_内核工匠的博客-CSDN博客
特此致谢!
接前一篇文章Linux内核Thermal框架详解十四、Thermal Governor(4)
二、具体温控策略
上一篇文章介绍并详细分析了step_wise governor的源码。本文介绍第4种温控策略:power_allocator。
4. power_allocator
IPA(Intelligent PowerAllocation)是由ARM开发的符合linux内核Thermal框架的governor,代码中的名字为power_allocator,旨在满足温控效果的条件下最大化性能。IPA模型的核心是利用 PID 控制器,ThermalZone 的温度作为输入,可分配功耗值作为输出,调节 Allocator 的频率和电压值。
power_allocator governor的代码在drivers/thermal/drivers/thermal/gov_power_allocator.c.c中,总共有753行代码(Linux内核版本:5.15.8)。从代码行数上就能看出来,IPA远比其它温控策略复杂得多,完全不是一个数量级的。因此,本文会分几篇文章来对IPA即power_allocator governor代码进行解析。
(1)THERMAL_GOVERNOR_DECLARE相关代码
先来看THERMAL_GOVERNOR_DECLARE。它是一个宏定义,在drivers/thermal/thermal_core.h中,代码如下:
/* Init section thermal table */
extern struct thermal_governor *__governor_thermal_table[];
extern struct thermal_governor *__governor_thermal_table_end[];
#define THERMAL_TABLE_ENTRY(table, name) \
static typeof(name) *__thermal_table_entry_##name \
__used __section("__" #table "_thermal_table") = &name
#define THERMAL_GOVERNOR_DECLARE(name) THERMAL_TABLE_ENTRY(governor, name)
实际上这段代码在前文Linux内核Thermal框架详解四、Thermal Core(3)中已经进行了详细分析,这里就不再赘述了。不过为了便于理解和加深印象,将power_allocator governor展开后的代码再次列出:
static struct thermal_governor thermal_gov_power_allocator = {
.name = "power_allocator",
.bind_to_tz = power_allocator_bind,
.unbind_from_tz = power_allocator_unbind,
.throttle = power_allocator_throttle,
};
static struct thermal_governor *__thermal_table_entry_thermal_gov_power_allocator \
__used __section("__governor_thermal_table") = &thermal_gov_power_allocator
Thermal Governor都是通过THERMAL_GOVERNOR_DECLARE定义到了__governor_thermal_table这段空间内。然后在thermal core初始化时通过调用thermal_register_governors来注册到thermal_governor_list链表中。再之后通过经由“thermal_init->thermal_register_governors-> thermal_set_governor”路径和thermal zone device关联上。
(2)handle_non_critical_trips
struct thermal_governor中有一个成员throttle,其是一个函数指针:
int (*throttle)(struct thermal_zone_device *tz, int trip);
对于对象thermal_gov_power_allocator来说,指向了power_allocator_throttle函数。在解析power_allocator_throttle函数之前,有一个问题必须弄清楚:这个函数是何时被调用的?
是在drivers/thermal/thermal_core.c的handle_non_critical_trips函数中,代码如下:
static void handle_non_critical_trips(struct thermal_zone_device *tz, int trip)
{
tz->governor ? tz->governor->throttle(tz, trip) :
def_governor->throttle(tz, trip);
}
那么又是哪里调用的handle_non_critical_trips?是在drivers/thermal/thermal_core.c的handle_thermal_trip函数中,代码如下:
static void handle_thermal_trip(struct thermal_zone_device *tz, int trip)
{
enum thermal_trip_type type;
int trip_temp, hyst = 0;
/* Ignore disabled trip points */
if (test_bit(trip, &tz->trips_disabled))
return;
tz->ops->get_trip_temp(tz, trip, &trip_temp);
tz->ops->get_trip_type(tz, trip, &type);
if (tz->ops->get_trip_hyst)
tz->ops->get_trip_hyst(tz, trip, &hyst);
if (tz->last_temperature != THERMAL_TEMP_INVALID) {
if (tz->last_temperature < trip_temp &&
tz->temperature >= trip_temp)
thermal_notify_tz_trip_up(tz->id, trip,
tz->temperature);
if (tz->last_temperature >= trip_temp &&
tz->temperature < (trip_temp - hyst))
thermal_notify_tz_trip_down(tz->id, trip,
tz->temperature);
}
if (type == THERMAL_TRIP_CRITICAL || type == THERMAL_TRIP_HOT)
handle_critical_trips(tz, trip, type);
else
handle_non_critical_trips(tz, trip);
/*
* Alright, we handled this trip successfully.
* So, start monitoring again.
*/
monitor_thermal_zone(tz);
}
对于handle_thermal_trip函数的详细分析有专门的文章章节,由于本篇文章专注于bang_bang governor,故在此不深入展开。
(3)power_allocator_throttle
power_allocator_throttle函数无疑是power_allocator governor的核心。代码如下:
static int power_allocator_throttle(struct thermal_zone_device *tz, int trip)
{
int ret;
int switch_on_temp, control_temp;
struct power_allocator_params *params = tz->governor_data;
bool update;
/*
* We get called for every trip point but we only need to do
* our calculations once
*/
if (trip != params->trip_max_desired_temperature)
return 0;
ret = tz->ops->get_trip_temp(tz, params->trip_switch_on,
&switch_on_temp);
if (!ret && (tz->temperature < switch_on_temp)) {
update = (tz->last_temperature >= switch_on_temp);
tz->passive = 0;
reset_pid_controller(params);
allow_maximum_power(tz, update);
return 0;
}
tz->passive = 1;
ret = tz->ops->get_trip_temp(tz, params->trip_max_desired_temperature,
&control_temp);
if (ret) {
dev_warn(&tz->device,
"Failed to get the maximum desired temperature: %d\n",
ret);
return ret;
}
return allocate_power(tz, control_temp);
}
不同于其它几个策略中的相应函数,这个函数没有注释。不过还比较好理解。
第一个tz->ops->get_trip_temp函数即tz->ops->get_trip_temp(tz, params->trip_switch_on, &switch_on_temp)的意思是获取trip温度,作为switch_on触发温度。
第二个tz->ops->get_trip_temp函数即tz->ops->get_trip_temp(tz, params->trip_max_desired_temperature, &control_temp)的意思是获取trip温度,作为目标温度。
最后就进入到了IPA注算法逻辑allocate_power函数。我们放在下一篇文章中进行详解。
相关文章
- Linux中的read函数:简介与概述(read函数linux)
- Linux发行版本:开源内核上的创新之旅(linux发行版本内核)
- Linux内核:涵盖了多少行源代码?(linux内核多少行代码)
- 籍Linux书籍:掌握Linux基础知识的必备之选(linux书)
- 提升Linux内核安全性:策略分析(linux内核策略)
- 设置Linux下鼠标设置的简易指南(linux鼠标)
- Linux访问内核空间:突破极限的方式(linux访问内核空间)
- 深入浅出:Linux虚拟机编译内核实战(linux虚拟机编译内核)
- linux内核面试题及解析(linux内核面试题)
- Linux下的.o文件:研究此文件的来源与用处。(.o文件linux)
- 掌握Linux内核修改技巧——让你从容掌控内核(如何修改linux内核)
- 推荐五款适合Linux的高效图片查看器(linux图片查看器)
- 深入探究Linux操作系统的系统框架(linux系统框架)
- 轻松安装,畅享音乐——QQ音乐Linux版上线!(qq音乐linux版)
- Linux 内核可兼容性的优势(linux内核兼容)
- Linux系统下实现音频解码的最佳方案(linux音频解码库)
- 改变Linux:切换语言环境(linux改语言)
- 学习Linux:安装Linux内核源码教程(安装linux内核源码)
- 深入剖析:探索Linux内核下的C语言编程技巧(linux内核的c语言)
- Linux 内核: 最新版本来袭!(linux内核最新版本)
- Linux内核之路:快速启动(linux 内核 启动)
- Linux 下快速安装多个软件的方法(linux 批量安装软件)
- Linux下循环命令使用技巧(linux循环命令)
- 版本如何查看Linux内核版本?(怎么查看linux内核)