-
Notifications
You must be signed in to change notification settings - Fork 18
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
platform(x86): our timer implementation is basically the worst thing ever #349
Comments
once again i am saved by @iximeow's near-encyclopedic knowledge of x86 arcana: apparently there's CPUID leaves that "just tell you what the TSC frequency is".1 quoth ixi:
so i guess we can just do that. we can always fall back to the stupid thing we do now, if the CPU is not from this decade and those CPUID leaves aren't present. Footnotes
|
peeking at CPUID seems a lot less life-ruining than trying to figure out why my TSC calibration code is kinda wrong, so this could be a fun weekend project to just go do. |
pub enum TscInitError {
ComputerAncient,
ComputerJustBroken,
} |
HELLO I BRING TIDINGS OF TIMER NEWS if you're just measuring times
Intelon Intel, other part of sidestepping "TSC calibration" can be backed up by two CPUID leaves:
for Intel there are some notes in the SDM that are relevant here too:
which suggests the TSC is, well, constant frequency with an easily determinable number. this should be AMDAMD doesn't enumerate CPUID leaves 15h or 16h. the TSC frequency on AMD is less easily found from the APM, but is somewhat simpler.. kinda. for family 17h model 31h, for example:
there isn't a CPUID bit to say that this is exactly what the TSC ticks at, but back in the APM there are more general statements that substantiate the TSC ticking at P0 generally.. on
and on "Time-Stamp Counter" there's:
which suggests the TSC in an X-GHz processor ticks at or close to finally, the Performance Timestamp Counter mentions OK. P0 frequency. AMD reports P-states in MSRs
|
thanks @iximeow, this is really lovely! really appreciate all the research. unfortunately i don't have a collection of "every x86 CPU made since 2007" to test against, but i'm gonna see how much i can get working... |
poking around a little, it appears that Linux does attempt to use CPUID to determine the TSC frequency, but will just immediately give up on AMD CPUs: if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL)
return 0; i suspect that this probably either means that finding the appropriate AMD documentation was more annoying, or whoever contributed this to linux just didn't care. or both. Also interesting is that on Denverton (Atom C3xxxx) SoCs, the CPUID leaves are missing and linux just hardcodes something, which we could borrow i guess. |
Some interesting learnings about QEMU behaviors:
these behaviors seem to be the case regardless of whether QEMU is KVM-accelerated or fully emulating the guest. it's possible there's flags i should be passing to make it give me something useful |
for those of you following along at home (or, for Future Elizas, when i forget this), the way you get QEMU to pass through the host CPU's $ qemu-system-x86_64 -machine accel=kvm -cpu host,migratable=no,+invtsc as per https://wiki.qemu.org/ChangeLog/2.1:
|
see also #343 (comment)
the x86 kernel's current clocksource for the kernel timer wheel is an ungodly abomination which i fittingly named
CLOCK_IDIOTIC
. essentially, it works like this:set the 8253 PIT to fire every 10 ms.
the PIT is x86's Worst clock source, essentially a NTSC colorburst oscillator from the 1970s with some extra bullshit nobody uses jammed onto it and bundled into one IC, which is now just a tiny bit of silicon stuck on modern PC chipsets. this thing sucks So Bad. the highest frequency it oscillates at is approximately 18.2 Hz, which is for TV Reasons that only made sense in 1970.
it's basically impossible to get any kind of reasonable accuracy or precision out of this thing, and pretty much no operating system from this millenium actually uses it for any purpose besides calibrating other, better timers. but, it's really easy to configure and you can use it without doing annoying calibration stuff, since it has a fixed frequency that's unrelated to the CPU's bus frequency. which is why we use it currently.1
when the PIT interval timer interrupt fires, increment an
AtomicU64
when you want a timestamp, read that
AtomicU64
. you now have a timestamp with the granularity of garbage.we should really use
RDTSC
instead of "the worst thing ever". unfortunately, before you can use this timer, you have to calibrate the timestamps it gives you against a known-frequency clock like the PIT.2 i previously started trying to bring up the TSC as clock source in Mycelium ages ago and gave up on finishing the TSC calibration routine because it was annoying and i couldn't get good timestamps out of it. this might actually be because i was doing all my development in a QEMU VM, and it turns out that when your VM's host threads get preempted, the guest sees the clock jump around weirdly.alternatives could include implementing a paravirtualized clock and using that when we're in QEMU, but that's a bunch of work we would do that's only valuable for VMs and not when running on a real computer. and we would still not have an easy way of testing the clock source used on real hardware because i don't really want to just install mnemOS on my laptop and turn it into a $2000 paperweight.
another option is the High-Performance Event Timer, or HPET. this is some microsoft bullshit that i think is mainly only used by windows? i don't know very much about it. it has a
MAIN_COUNTER_VAL
which can be used as a timestamp, i think. i'm not sure whether calibration is required for this thing, but if it's not, this could be a nice option that works the same in a VM as it does in Real Life, but isn't also "just whang an atomic every time an interrupt fires lol lmao". i'd need to look into that some more.Footnotes
what i'm saying here is that i'm lazy and stupid. ↩
or the ACPI PMTimer, which is also a fixed-frequency clock like the PIT. pros of this thing include that it has a much higher fixed frequency (3.579545 MHz). cons of it include "you can only talk to it using ACPI", which means it's basically never used by anyone. ↩
The text was updated successfully, but these errors were encountered: