drivers/cpuidle/governors/menu.c

Source file repositories/reference/linux-study-clean/drivers/cpuidle/governors/menu.c

File Facts

System
Linux kernel
Corpus path
drivers/cpuidle/governors/menu.c
Extension
.c
Size
16854 bytes
Lines
545
Domain
Driver Families
Bucket
drivers/cpuidle
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

struct menu_device {
	int             needs_update;
	int             tick_wakeup;

	u64		next_timer_ns;
	unsigned int	bucket;
	unsigned int	correction_factor[BUCKETS];
	unsigned int	intervals[INTERVALS];
	int		interval_ptr;
};

static inline int which_bucket(u64 duration_ns)
{
	int bucket = 0;

	if (duration_ns < 10ULL * NSEC_PER_USEC)
		return bucket;
	if (duration_ns < 100ULL * NSEC_PER_USEC)
		return bucket + 1;
	if (duration_ns < 1000ULL * NSEC_PER_USEC)
		return bucket + 2;
	if (duration_ns < 10000ULL * NSEC_PER_USEC)
		return bucket + 3;
	if (duration_ns < 100000ULL * NSEC_PER_USEC)
		return bucket + 4;
	return bucket + 5;
}

static DEFINE_PER_CPU(struct menu_device, menu_devices);

static void menu_update_intervals(struct menu_device *data, unsigned int interval_us)
{
	/* Update the repeating-pattern data. */
	data->intervals[data->interval_ptr++] = interval_us;
	if (data->interval_ptr >= INTERVALS)
		data->interval_ptr = 0;
}

static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev);

/*
 * Try detecting repeating patterns by keeping track of the last 8
 * intervals, and checking if the standard deviation of that set
 * of points is below a threshold. If it is... then use the
 * average of these 8 points as the estimated value.
 */
static unsigned int get_typical_interval(struct menu_device *data)
{
	s64 value, min_thresh = -1, max_thresh = UINT_MAX;
	unsigned int max, min, divisor;
	u64 avg, variance, avg_sq;
	int i;

again:
	/* Compute the average and variance of past intervals. */
	max = 0;
	min = UINT_MAX;
	avg = 0;
	variance = 0;
	divisor = 0;
	for (i = 0; i < INTERVALS; i++) {
		value = data->intervals[i];
		/*
		 * Discard the samples outside the interval between the min and
		 * max thresholds.
		 */
		if (value <= min_thresh || value >= max_thresh)
			continue;

		divisor++;

		avg += value;
		variance += value * value;

		if (value > max)
			max = value;

		if (value < min)
			min = value;
	}

	if (!max)
		return UINT_MAX;

	if (divisor == INTERVALS) {
		avg >>= INTERVAL_SHIFT;
		variance >>= INTERVAL_SHIFT;
	} else {
		do_div(avg, divisor);
		do_div(variance, divisor);

Annotation

Implementation Notes