bochs clock and APIC Timer frequency
Posted: Fri Dec 13, 2024 12:13 am
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:
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.
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:
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?
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
}
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);
}
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
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?