bochs clock and APIC Timer frequency

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
User avatar
mrjbom
Member
Member
Posts: 317
Joined: Sun Jul 21, 2019 7:34 am

bochs clock and APIC Timer frequency

Post by mrjbom »

Hi.
I am trying to measure the frequency of the APIC Timer using PIT, but I'm dealing with the fickleness.
I do it like this:

Code: Select all

fn determine_timer_true_frequency(current_frequency_divider: u8) -> u64 {
    // 10 measures
    let mut ticks_measures = [0u64; 10];
    for v in ticks_measures.iter_mut() {
        // Sleep betwen measures
        pit::sleep(5);

        let initial_count = u32::MAX;

        // Start APIC Timer
        set_initial_count_register(initial_count);

        // Sleep 10 ms
        pit::sleep(10);

        // Read current count register
        let current_count = get_current_count_register_value();

        // Ticks in 10 ms
        *v = (initial_count - current_count) as u64;
    }

    // Disable APIC Timer
    set_initial_count_register(0);

    // Ticks in 10 ms
    let average_ticks: u64 = ticks_measures.iter().sum::<u64>() / ticks_measures.len() as u64;

    // Ticks in 1000 ms without divisor = true HZ
    average_ticks * current_frequency_divider as u64 * 100
}
10 times I measure how much the current counter has decreased and calculate the average value. I figured this would add precision since my PIT generates 1 interrupt per 1 ms and probably in sleep it could take 9 ms instead of 10.

In my test code, I call this function 10 times with a 1 second break.

Code: Select all

for i in 0..10 {
    let timer_true_frequency = determine_timer_true_frequency(16);
    log::debug!("Determined APIC Timer true frequency {i}: {timer_true_frequency}");
    pit::sleep(1000);
}
If I set “clock: sync=realtime, time0=local” for bochs, I get different results for each call in the output.
And they can be very different sometimes:

Code: Select all

DEBUG: Determined APIC Timer true frequency 0: 28628800
DEBUG: Determined APIC Timer true frequency 1: 28193600
DEBUG: Determined APIC Timer true frequency 2: 30819200
DEBUG: Determined APIC Timer true frequency 3: 68516800
DEBUG: Determined APIC Timer true frequency 4: 69318400
DEBUG: Determined APIC Timer true frequency 5: 70348800
DEBUG: Determined APIC Timer true frequency 6: 70488000
DEBUG: Determined APIC Timer true frequency 7: 70726400
DEBUG: Determined APIC Timer true frequency 8: 70521600
DEBUG: Determined APIC Timer true frequency 9: 70537600
If I set clock: sync=none, time0=local” for bochs, all values match exactly, but bochs flies forward and 10 seconds pass instantly, so I don't like this and want to use sync=realtime.
sync=slowdown is incredibly slow, many times slower than realtime, so it doesn't seem to fit either.

It seems to me that sync=realtime is the most suitable, because in it time flows the same way as in reality.

However, I am intimidated by this difference in measurements, is this a problem? As far as I understand, this is normal and will not cause problems as bochs just changes the IPS (These drops coincide with the drops and IPS values).
Can I safely use sync=realtime and not worry about what I see in the measurements?
User avatar
mrjbom
Member
Member
Posts: 317
Joined: Sun Jul 21, 2019 7:34 am

Re: bochs clock and APIC Timer frequency

Post by mrjbom »

UPD:
My assumption that changing the IPS was not a problem turned out to be wrong.

When my code tries to determine the frequency, the IPS is about 70_000_000, and it calculates the same value. Right after that, when I try to test sleep(), the IPS jumps to 100_000_000 and the timer ends up rushing.

Much less often the same happens with PIT, sometimes it runs faster than real time or longer.

In qemu everything looks better, but still everything lags somehow.

In Virtual Box I have after enabling APIC stop generating interrupts from vector 32 (IRQ0) and only go LINT0, I don't know if this behaviour is correct.
In qemu and bochs after enabling APIC I still have IRQ0 interrupts working and I use them for PIT and APIC Timer initialization, in Virtual Box it doesn't work. It looks like I have to configure IO APIC before configuring APIC Timer with PIT.

Can the invariant TSC help me somehow to initialise the APIC Timer?

Seems like emulators(qemu and especially bochs) are absolutely failing at keeping real time, right?
rdos
Member
Member
Posts: 3297
Joined: Wed Oct 01, 2008 1:55 pm

Re: bochs clock and APIC Timer frequency

Post by rdos »

I think how it works on real hardware is the most important not if it works correctly on emulators.
User avatar
eekee
Member
Member
Posts: 891
Joined: Mon May 22, 2017 5:56 am
Location: Kerbin
Discord: eekee
Contact:

Re: bochs clock and APIC Timer frequency

Post by eekee »

mrjbom wrote: Fri Dec 13, 2024 10:13 am Seems like emulators(qemu and especially bochs) are absolutely failing at keeping real time, right?
It's difficult for emulators to get timing just right, especially if they're designed to run fast, but I don't know why PC emulators skip ahead so much. My experience with DOS programs in QEMU is awful; briefly press an arrow key and the cursor moves a minimum of 2 characters, sometimes as many as 5. Your best option might be to enable sync=slowdown to debug your code, then remove the option once it works correctly. I don't know how other OS devs deal with it though.
Kaph — a modular OS intended to be easy and fun to administer and code for.
"May wisdom, fun, and the greater good shine forth in all your work." — Leo Brodie
Post Reply