drivers/cpufreq/cpufreq_governor.c

Source file repositories/reference/linux-study-clean/drivers/cpufreq/cpufreq_governor.c

File Facts

System
Linux kernel
Corpus path
drivers/cpufreq/cpufreq_governor.c
Extension
.c
Size
17972 bytes
Lines
600
Domain
Driver Families
Bucket
drivers/cpufreq
Inferred role
Driver Families: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

for_each_cpu(j, policy_dbs->policy->cpus) {
			struct cpu_dbs_info *j_cdbs = &per_cpu(cpu_dbs, j);

			j_cdbs->prev_cpu_idle = get_cpu_idle_time(j, &j_cdbs->prev_update_time,
								  dbs_data->io_is_busy);
			j_cdbs->prev_cpu_nice = kcpustat_field(CPUTIME_NICE, j);
		}
		mutex_unlock(&policy_dbs->update_mutex);
	}
}
EXPORT_SYMBOL_GPL(gov_update_cpu_data);

unsigned int dbs_update(struct cpufreq_policy *policy)
{
	struct policy_dbs_info *policy_dbs = policy->governor_data;
	struct dbs_data *dbs_data = policy_dbs->dbs_data;
	unsigned int ignore_nice = dbs_data->ignore_nice_load;
	unsigned int max_load = 0, idle_periods = UINT_MAX;
	unsigned int sampling_rate, io_busy, j;
	u64 cur_nice;

	/*
	 * Sometimes governors may use an additional multiplier to increase
	 * sample delays temporarily.  Apply that multiplier to sampling_rate
	 * so as to keep the wake-up-from-idle detection logic a bit
	 * conservative.
	 */
	sampling_rate = dbs_data->sampling_rate * policy_dbs->rate_mult;
	/*
	 * For the purpose of ondemand, waiting for disk IO is an indication
	 * that you're performance critical, and not that the system is actually
	 * idle, so do not add the iowait time to the CPU idle time then.
	 */
	io_busy = dbs_data->io_is_busy;

	/* Get Absolute Load */
	for_each_cpu(j, policy->cpus) {
		struct cpu_dbs_info *j_cdbs = &per_cpu(cpu_dbs, j);
		u64 update_time, cur_idle_time;
		unsigned int idle_time, time_elapsed;
		unsigned int load;

		cur_idle_time = get_cpu_idle_time(j, &update_time, io_busy);

		time_elapsed = update_time - j_cdbs->prev_update_time;
		j_cdbs->prev_update_time = update_time;

		/*
		 * cur_idle_time could be smaller than j_cdbs->prev_cpu_idle if
		 * it's obtained from get_cpu_idle_time_jiffy() when NOHZ is
		 * off, where idle_time is calculated by the difference between
		 * time elapsed in jiffies and "busy time" obtained from CPU
		 * statistics.  If a CPU is 100% busy, the time elapsed and busy
		 * time should grow with the same amount in two consecutive
		 * samples, but in practice there could be a tiny difference,
		 * making the accumulated idle time decrease sometimes.  Hence,
		 * in this case, idle_time should be regarded as 0 in order to
		 * make the further process correct.
		 */
		if (cur_idle_time > j_cdbs->prev_cpu_idle)
			idle_time = cur_idle_time - j_cdbs->prev_cpu_idle;
		else
			idle_time = 0;

		j_cdbs->prev_cpu_idle = cur_idle_time;

		/*
		 * Always sample cur_nice and advance prev_cpu_nice, regardless
		 * of ignore_nice.  This keeps prev_cpu_nice current so that
		 * enabling ignore_nice_load via sysfs never produces a
		 * stale-baseline spike (the delta will be at most one sampling
		 * interval of accumulated nice time, not since boot).
		 */
		cur_nice = kcpustat_field(CPUTIME_NICE, j);
		if (ignore_nice)
			idle_time += div_u64(cur_nice - j_cdbs->prev_cpu_nice, NSEC_PER_USEC);

		j_cdbs->prev_cpu_nice = cur_nice;

		if (unlikely(!time_elapsed)) {
			/*
			 * That can only happen when this function is called
			 * twice in a row with a very short interval between the
			 * calls, so the previous load value can be used then.
			 */
			load = j_cdbs->prev_load;
		} else if (unlikely(idle_time > 2 * sampling_rate &&
				    j_cdbs->prev_load)) {
			/*
			 * If the CPU had gone completely idle and a task has

Annotation

Implementation Notes