My Intel CPU changes clock speed depending on the usage, but how does it decide what clock speed to run at? Is the clock speed determined by the OS software using an algorithm, or is it hardware based? Is it dependent on the # of interrupts? The cache turnover? Does the CPU itself set its own clock? Or does a separate controller set it? Or software?
The core clock of the CPU isn't received directly from the motherboard. That clock is usually much slower (often by a factor of 10 or more) than the internal frequency of the CPU. Instead, the clock signal from the motherboard is used as the reference frequency for a higher frequency phase locked loop controlled oscillator inside the CPU. The generated clock runs at some multiple of the reference clock, and that multiple can be changed by setting certain registers in the CPU. The actual generation of the clock is done purely in hardware.
To reduce power even further, the CPU also signals to the voltage regulator supplying its core voltage to run at a lower set point. At lower frequencies the CPU can run at a lower voltage without malfunctioning, and because power consumption is proportional to the square of the voltage, even a small reduction in voltage can save a large amount of power.
The voltage and frequency scaling is done by hardware, but the decision to run in a low power mode is made by software (the OS). How the OS determines the optimal mode to run in is a separate, messier, problem, but it likely comes down to mostly what %time has the system been idle lately. Mostly idle, lower the frequency. Mostly busy, raise the frequency. Once the OS decides the frequency to run at, it's just a matter of setting a register.
Well, on modern operating systems there is something called "task scheduler". It runs periodically (very fast) and selects (from a list) wich next task to execute. Tasks can be at many states, like select, blocked, sleeping etc.
If all tasks are in select mode (waiting for something from the operating system) and cannot be served, or some are sleeping etc, so there is no heavy usage of the processor being done, the task scheduler will invoke a special task called "idle".
If the CPU driver checks the task scheduler table and verify that the idle task is running most of the CPU time, it will simply send a command to the clock generation PLL circuit of the CPU to reduce its clock. On the contrary, if the idle task takes less and less CPU time (meaning that the CPU is getting used heavily) the CPU driver will increase the CPU Speed.
Its not very hard, but there is a lower limit where the CPU cannot be throttled lower because not all CPUs are fully static (so they need refreshing cycles). Fully static cpus can go as low as 0 (zero) MHz because there is no state to be lost if the clock is stopped.