#c #c 17 #timing #chrono #gameboy
#c #c 17 #синхронизация #c -хроно #gameboy
Вопрос:
Я работаю над реализацией DMG-01 (A.K.A gameboy 1989) на моем github. Я уже внедрил как APU, так и PPU, с (почти) идеальной синхронизацией на моем ПК (и ПК моих друзей). Однако, когда я запускаю эмулятор на одном из компьютеров моего друга, он работает в два раза быстрее, чем у меня или у остальных моих друзей.
Код для синхронизации часов (между gameboy и ПК, на котором он запущен) выглядит следующим образом:
Часы.Файл заголовка h:
class Clock
{
// ...
public:
void SyncClock();
private:
/* API::LR35902_HZ_CLOCK is 4'194'304 */
using lr35902_clock_period = std::chrono::duration<int64_t, std::ratio<1, API::LR35902_HZ_CLOCK>>;
static constexpr lr35902_clock_period one_clock_period{1};
using clock = std::chrono::high_resolution_clock;
private:
decltype(clock::now()) _last_tick{std::chrono::time_point_cast<clock::duration>(clock::now() one_clock_period)};
};
Clock.cpp файл
void Clock::SyncClock()
{
// Sleep until one tick has passed.
std::this_thread::sleep_until(this->_last_tick);
// Use time_point_cast to convert (via truncation towards zero) back to
// the "native" duration of high_resolution_clock
this->_last_tick = std::chrono::time_point_cast<clock::duration>(this->_last_tick one_clock_period);
}
Который вызывается в main.cpp вот так:
int main()
{
// ...
while (true)
{
// processor.Clock() returns the number of clocks it took for the processor to run the
// current instruction. We need to sleep this thread for each clock passed.
for (std::size_t current_clock = processor.Clock(); current_clock > 0; --current_clock)
{
clock.SyncClock();
}
}
// ...
}
Есть ли причина, по которой chrono в этом случае будет по-другому влиять на другие компьютеры? Время является абсолютным, я бы понял, почему на одном ПК запуск эмулятора будет медленнее, но почему быстрее?
Я проверил тип моих часов (high_resolution_clock), но я не понимаю, почему это так.
Спасибо!
Комментарии:
1. Если вы проверите
period
типstd::high_resolution_clock
, отличается ли он между двумя системами?2. @Someprogrammerdude Мой друг не очень программист, поэтому мне придется установить visual studio на его ПК (если он согласен, но), но в любом случае я не вижу причины, по которой std ::ratio изменится между двумя системами (стандарт также не определяет такую разницу)
3. Один из вас запускает гиперпоточность, а другой нет?
4.Вам не нужно устанавливать Visual Studio, просто добавьте ведение
std::ratio
num
den
журнала элементов и в вашу программу.5. @Someprogrammerdude Хорошая идея, я попробую и обновлю ее здесь.
Ответ №1:
Я думаю, вы можете столкнуться с переполнением под капотом <chrono>
.
Выражение:
clock::now() one_clock_period
является проблематичным. clock
есть high_resolution_clock
, и обычно это имеет nanoseconds
разрешение. one_clock_period
имеет единицы измерения 1/4'194'304
. Результирующим выражением будет a time_point
с a period
of 1/8'192'000'000'000
.
При использовании 64-разрядных интегральных типов max()
со знаком такая точность составляет чуть более 13 дней. Поэтому, если clock::now()
возвращает .time_since_epoch()
значение, превышающее 13 дней, _last_tick
оно будет переполняться и может иногда быть отрицательным (в зависимости от того, сколько clock::now()
превышает 13 дней).
Чтобы исправить, попробуйте выполнить приведение one_clock_period
к точности clock
немедленно:
static constexpr clock::duration one_clock_period{
std::chrono::duration_cast<clock::duration>(lr35902_clock_period{1})};