cpufreq: update_limits 实现和引用

本文探讨了cpufreq的update_limits实现,重点在于调用流程,通过cpufreq_set_policy更新调频策略,涉及cpufreq_driver的verify和setpolicy方法。refresh_frequency_limits函数主要负责重新验证频点并设定新的策略状态。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


void acpi_processor_ppc_has_changed(struct acpi_processor *pr, int event_flag)
{
	int ret;

	if (ignore_ppc || !pr->performance) {
		/*
		 * Only when it is notification event, the _OST object
		 * will be evaluated. Otherwise it is skipped.
		 */
		if (event_flag)
			acpi_processor_ppc_ost(pr->handle, 1);
		return;
	}

	ret = acpi_processor_get_platform_limit(pr);
	/*
	 * Only when it is notification event, the _OST object
	 * will be evaluated. Otherwise it is skipped.
	 */
	if (event_flag) {
		if (ret < 0)
			acpi_processor_ppc_ost(pr->handle, 1);
		else
			acpi_processor_ppc_ost(pr->handle, 0);
	}
	if (ret >= 0)
		cpufreq_update_limits(pr->id);//调用下面的update_limits入口,
}
/**
 * cpufreq_update_limits - Update policy limits for a given CPU.
 * @cpu: CPU to update the policy limits for.
 *
 * Invoke the driver's ->update_limits callback if present or call
 * cpufreq_update_policy() for @cpu.
 */
void cpufreq_update_limits(unsigned int cpu)
{
	if (cpufreq_driver->update_limits)
		cpufreq_driver->update_limits(cpu);
	else
		cpufreq_update_policy(cpu);
}
EXPORT_SYMBOL_GPL(cpufreq_update_limits);
static struct cpufreq_driver intel_pstate = {
	.flags		= CPUFREQ_CONST_LOOPS,
	.verify		= intel_pstate_verify_policy,
	.setpolicy	= intel_pstate_set_policy,
	.suspend	= intel_pstate_suspend,
	.resume		= intel_pstate_resume,
	.init		= intel_pstate_cpu_init,
	.exit		= intel_pstate_cpu_exit,
	.offline	= intel_pstate_cpu_offline,
	.online		= intel_pstate_cpu_online,
	.update_limits	= intel_pstate_update_limits,//频率更新的入口函数
	.name		= "intel_pstate",
};

来看下具体的调用流程, 说明比较少. 看函数call的过程

static void intel_pstate_update_limits(unsigned int cpu)
{
	mutex_lock(&intel_pstate_driver_lock);

	update_turbo_state();
	/*
	 * If turbo has been turned on or off globally, policy limits for
	 * all CPUs need to be updated to reflect that.
	 */
	if (global.turbo_disabled_mf != global.turbo_disabled) {
		global.turbo_disabled_mf = global.turbo_disabled;
		arch_set_max_freq_ratio(global.turbo_disabled);
		for_each_possible_cpu(cpu)
			intel_pstate_update_max_freq(cpu);
	} else {
		cpufreq_update_policy(cpu);
	}

	mutex_unlock(&intel_pstate_driver_lock);
}
static void intel_pstate_update_max_freq(unsigned int cpu)
{
	struct cpufreq_policy *policy = cpufreq_cpu_acquire(cpu);
	struct cpudata *cpudata;

	if (!policy)
		return;

	cpudata = all_cpu_data[cpu];
	policy->cpuinfo.max_freq = global.turbo_disabled_mf ?
			cpudata->pstate.max_freq : cpudata->pstate.turbo_freq;

	refresh_frequency_limits(policy);//会调用set policy 来更新策略

	cpufreq_cpu_release(policy);
}
void refresh_frequency_limits(struct cpufreq_policy *policy)
{
	if (!policy_is_inactive(policy)) {
		pr_debug("updating policy for CPU %u\n", policy->cpu);

		cpufreq_set_policy(policy, policy->governor, policy->policy);
	}
}
EXPORT_SYMBOL(refresh_frequency_limits);

会调用到cpufreq_set_policy() 来更新调频策略

-> ret = cpufreq_driver->verify(&new_data);
-> return cpufreq_driver->setpolicy(policy);

所以来看 refresh_frequency_limits 这个函数的主要内容就是重新来verify 频点和设置新的policy 状态.

static int cpufreq_set_policy(struct cpufreq_policy *policy,
			      struct cpufreq_governor *new_gov,
			      unsigned int new_pol)
{
	struct cpufreq_policy_data new_data;
	struct cpufreq_governor *old_gov;
	int ret;
pr_err("+++++++ cpufreq_set_policy 1 ++++++++\n");
	memcpy(&new_data.cpuinfo, &policy->cpuinfo, sizeof(policy->cpuinfo));
	new_data.freq_table = policy->freq_table;
	new_data.cpu = policy->cpu;
	/*
	 * PM QoS framework collects all the requests from users and provide us
	 * the final aggregated value here.
	 */
	new_data.min = freq_qos_read_value(&policy->constraints, FREQ_QOS_MIN);
	new_data.max = freq_qos_read_value(&policy->constraints, FREQ_QOS_MAX);

	pr_err("setting new policy for CPU %u: %u - %u kHz\n",
		 new_data.cpu, new_data.min, new_data.max);

	/*
	 * Verify that the CPU speed can be set within these limits and make sure
	 * that min <= max.
	 */
	pr_err("+++++++ cpufreq_set_policy 2 ++++++++\n");
	ret = cpufreq_driver->verify(&new_data);
	if (ret)
		return ret;
pr_err("+++++++ cpufreq_set_policy 3 ++++++++\n");
	/*
	 * Resolve policy min/max to available frequencies. It ensures
	 * no frequency resolution will neither overshoot the requested maximum
	 * nor undershoot the requested minimum.
	 */
	policy->min = new_data.min;
	policy->max = new_data.max;
	policy->min = __resolve_freq(policy, policy->min, CPUFREQ_RELATION_L);
	policy->max = __resolve_freq(policy, policy->max, CPUFREQ_RELATION_H);
	trace_cpu_frequency_limits(policy);
pr_err("+++++++ cpufreq_set_policy 4 ++++++++\n");
	policy->cached_target_freq = UINT_MAX;

	pr_debug("new min and max freqs are %u - %u kHz\n",
		 policy->min, policy->max);

	if (cpufreq_driver->setpolicy) {
		policy->policy = new_pol;
		pr_debug("setting range\n");
		pr_err("+++++++ cpufreq_set_policy 4.1 ++++++++\n");
		return cpufreq_driver->setpolicy(policy);
	}
pr_err("+++++++ cpufreq_set_policy 5 ++++++++\n");
	if (new_gov == policy->governor) {
		pr_debug("governor limits update\n");
		cpufreq_governor_limits(policy);
		return 0;
	}
pr_err("+++++++ cpufreq_set_policy 6 ++++++++\n");
	pr_err("governor switch\n");

	/* save old, working values */
	old_gov = policy->governor;
	/* end old governor */
	if (old_gov) {
		cpufreq_stop_governor(policy);
		cpufreq_exit_governor(policy);
	}

	/* start new governor */
	policy->governor = new_gov;
	ret = cpufreq_init_governor(policy);
	if (!ret) {
		ret = cpufreq_start_governor(policy);
		if (!ret) {
			pr_debug("governor change\n");
			sched_cpufreq_governor_change(policy, old_gov);
			return 0;
		}
		cpufreq_exit_governor(policy);
	}

	/* new governor failed, so re-start old one */
	pr_debug("starting governor %s failed\n", policy->governor->name);
	if (old_gov) {
		policy->governor = old_gov;
		if (cpufreq_init_governor(policy))
			policy->governor = NULL;
		else
			cpufreq_start_governor(policy);
	}

	return ret;
}
"sgmediation.zip" 是一个包含 UCLA(加利福尼亚大学洛杉矶分校)开发的 sgmediation 插件的压缩包。该插件专为统计分析软件 Stata 设计,用于进行中介效应分析。在社会科学、心理学、市场营销等领域,中介效应分析是一种关键的统计方法,它帮助研究人员探究变量之间的因果关系,尤其是中间变量如何影响因变量与自变量之间的关系。Stata 是一款广泛使用的统计分析软件,具备众多命令用户编写的程序来拓展其功能,sgmediation 插件便是其中之一。它能让用户在 Stata 中轻松开展中介效应分析,无需编写复杂代码。 下载并解压 "sgmediation.zip" 后,需将解压得到的 "sgmediation" 文件移至 Stata 的 ado 目录结构中。ado(ado 目录并非“adolescent data organization”缩写,而是 Stata 的自定义命令存放目录)目录是 Stata 存放自定义命令的地方,应将文件放置于 "ado\base\s" 子目录下。这样,Stata 启动时会自动加载该目录下的所有 ado 文件,使 "sgmediation" 命令在 Stata 命令行中可用。 使用 sgmediation 插件的步骤如下:1. 安装插件:将解压后的 "sgmediation" 文件放入 Stata 的 ado 目录。如果 Stata 安装路径是 C:\Program Files\Stata\ado\base,则需将文件复制到 C:\Program Files\Stata\ado\base\s。2. 启动 Stata:打开 Stata,确保软件已更新至最新版本,以便识别新添加的 ado 文件。3. 加载插件:启动 Stata 后,在命令行输入 ado update sgmediation,以确保插件已加载并更新至最新版本。4
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值