Hi,
limp wrote:Brendan mentioned to use the "thermal sensor" IRQ (in the local APIC) to determine when the speed of the RDTSC changes but I don’t really understand how this could be done in practice.
The idea is to use the (variable frequency) TSC to obtain a (fixed rate) counter, by adjusting for frequency changes.
Imagine if you've got a function like this:
Code: Select all
uint64_t virtual_ticks = 0;
uint64_t last_TSC_count = 0;
double scaling_factor = 1.0;
uint64_t get_virtual_ticks(void) {
uint64_t current_TSC_count;
current_TSC_count = RDTSC;
virtual_ticks += (current_TSC_count - last_TSC_count) * scaling_factor;
last_TSC_count = current_TSC_count;
return virtual_ticks;
}
Now imagine a "thermal status" IRQ hander, sort of like this:
Code: Select all
double scaling_factor_when_throttled = 0.5;
void thermal_status_IRQ(void) {
// Update the virtual ticks counter first to account for time passed before the speed change
get_virtual_ticks();
// Set new scaling factor (for new speed)
if( (getMSR(IA32_THERM_STATUS_MSR) & 1) == 0) {
// Speed changed from "slow" to "normal"
scaling_factor = 1.0;
} else {
// Speed changed from "normal" to "slow"
scaling_factor = scaling_factor_when_throttled;
}
}
In this case, "get_virtual_ticks()" would/could return a fixed rate counter value that isn't effected by automatic thermal throttling; and you could use it to (for e.g.) measure how much time has passed. For example:
Code: Select all
uint64_t start_time;
uint64_t time_taken;
start_time = get_virtual_ticks();
do_something();
time_taken = get_virtual_ticks() - start_time;
However, it's not that simple, and the code above is just a rough outline to describe the idea better.
The global variables would have to be "per CPU" variables (and be "volatile"), and you'd need some re-entrancy protection (although disabling IRQs should work, because if it's all "per CPU" you don't need to worry about other CPUs). It also won't handle software controlled throttling (you'd have to keep track of "scaling_factor_for_last_speed_requested_by_software" instead of assuming that "normal speed" means 100%).
You'd also have to find a way to determine the right value for "scaling_factor_when_throttled" (which depends on which CPU and how the firmware set it up). At a minimum you'd want some way of auto-detecting (e.g. the first time the CPU is throttled, use the PIT or some other timer to measure the frequency of the TSC during thermal throttling) to use as a fallback. For some CPUs there's MSRs that you might be able to use to determine the frequency the TSC during thermal throttling, so (depending on CPU, available information, etc) in some cases you might be able to avoid the "fallback" option.
limp wrote:The problem I’ve got is that Intel manuals say that the aforementioned MSR has been introduced as an MSR in the 0x0F family, version 0x0 (i.e. Intel Xeon Processors).
Does that mean that my Intel Atom processor (family=0x6, model=0x1C) doesn’t support it? If not, how can I determine if a thermal event occurred in my case?
Some CPUs with "family = 6" are newer and do support it, and some CPUs with "family = 6" are older and don't support it. You have to look at the model number to determine which, um, "sub-family"(?) the CPU is.
Chronological order (for Intel) is "..., Pentium III (family 6), Pentium 4 (family F), Pentium M (family 6), ..., Sandy Bridge (family 6)".
Cheers,
Brendan