Изменения времени часов на разных компьютерах

Я работаю над реализацией DMG-01 (также известного как gameboy 1989) на моем github. Я уже реализовал и APU, и PPU с (почти) идеальной синхронизацией на моем компьютере (и компьютере моих друзей). Однако, когда я запускаю эмулятор на компьютере одного из моих друзей, он работает вдвое быстрее, чем мой или остальных моих друзей.

Код для синхронизации часов (между геймбоем и компьютером, на котором он работает) выглядит следующим образом:

Заголовочный файл Clock.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();
        }
    }
    // ...
}

Есть ли причина, по которой хроно в этом случае будет по-другому влиять на другие компьютеры? Время абсолютно, я бы понял, почему на одном компьютере запуск эмулятора будет медленнее, но почему быстрее? Я проверил тип своих часов (high_resolution_clock), но не понимаю, почему это так. Спасибо!


person Noam Rodrik    schedule 14.10.2020    source источник
comment
Если вы проверите тип period std::high_resolution_clock, различается ли он между двумя системами ?   -  person Some programmer dude    schedule 14.10.2020
comment
@Someprogrammerdude Мой друг не большой программист, поэтому мне придется установить визуальную студию на его компьютер (если он крут с но), но в любом случае я не вижу причины, по которой std::ratio будет меняться между двумя системы (стандарт также не определяет такую ​​разницу)   -  person Noam Rodrik    schedule 14.10.2020
comment
Один из вас использует гиперпоточность, а другой нет?   -  person Surt    schedule 14.10.2020
comment
Вам не нужно устанавливать Visual Studio, просто добавьте журналирование std::ratio num и den членов вашей программы.   -  person Some programmer dude    schedule 14.10.2020
comment
@Someprogrammerdude Хорошая идея, я попробую и обновлю ее здесь.   -  person Noam Rodrik    schedule 14.10.2020
comment
@Surt Как гиперпоточность влияет на std::this_thread::sleep_until?   -  person Noam Rodrik    schedule 14.10.2020
comment
@NoamRodrik, этого не должно быть, но расписание может быть другим.   -  person Surt    schedule 14.10.2020


Ответы (1)


Я думаю, что вы можете столкнуться с переполнением под капотом <chrono>.

Выражение:

clock::now() + one_clock_period

проблематично. clock – это high_resolution_clock, и обычно это разрешение nanoseconds. one_clock_period имеет единицы 1/4'194'304. Результирующее выражение будет time_point с period из 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})};
person Howard Hinnant    schedule 14.10.2020