diff options
| author | bunnei <bunneidev@gmail.com> | 2021-02-19 19:11:05 -0800 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-02-19 19:11:05 -0800 | 
| commit | def03d4075421d38f5cda255f2b6fb5495f57c32 (patch) | |
| tree | a694010851607ea3aa341a7879db121236867bc7 | |
| parent | 728ee181ebdabf61ef7d4d9bd688cdfde4a9eaff (diff) | |
| parent | 3acb265c9ee8ac26ab43361997a5db0e4b9fa47c (diff) | |
Merge pull request #5964 from bunnei/timing-fix
common: wall_clock: Fix integer overflow with StandardWallClock.
| -rw-r--r-- | src/common/uint128.h | 20 | ||||
| -rw-r--r-- | src/common/wall_clock.cpp | 15 | 
2 files changed, 28 insertions, 7 deletions
| diff --git a/src/common/uint128.h b/src/common/uint128.h index 83560a9ce..4780b2f9d 100644 --- a/src/common/uint128.h +++ b/src/common/uint128.h @@ -98,4 +98,24 @@ namespace Common {  #endif  } +// This function divides a u128 by a u32 value and produces two u64 values: +// the result of division and the remainder +[[nodiscard]] static inline std::pair<u64, u64> Divide128On32(u128 dividend, u32 divisor) { +    u64 remainder = dividend[0] % divisor; +    u64 accum = dividend[0] / divisor; +    if (dividend[1] == 0) +        return {accum, remainder}; +    // We ignore dividend[1] / divisor as that overflows +    const u64 first_segment = (dividend[1] % divisor) << 32; +    accum += (first_segment / divisor) << 32; +    const u64 second_segment = (first_segment % divisor) << 32; +    accum += (second_segment / divisor); +    remainder += second_segment % divisor; +    if (remainder >= divisor) { +        accum++; +        remainder -= divisor; +    } +    return {accum, remainder}; +} +  } // namespace Common diff --git a/src/common/wall_clock.cpp b/src/common/wall_clock.cpp index 1545993bd..49830b8ab 100644 --- a/src/common/wall_clock.cpp +++ b/src/common/wall_clock.cpp @@ -20,9 +20,7 @@ using base_time_point = std::chrono::time_point<base_timer>;  class StandardWallClock final : public WallClock {  public:      explicit StandardWallClock(u64 emulated_cpu_frequency_, u64 emulated_clock_frequency_) -        : WallClock(emulated_cpu_frequency_, emulated_clock_frequency_, false), -          emulated_clock_factor{GetFixedPoint64Factor(emulated_clock_frequency, 1000000000)}, -          emulated_cpu_factor{GetFixedPoint64Factor(emulated_cpu_frequency, 1000000000)} { +        : WallClock(emulated_cpu_frequency_, emulated_clock_frequency_, false) {          start_time = base_timer::now();      } @@ -45,11 +43,16 @@ public:      }      u64 GetClockCycles() override { -        return MultiplyHigh(GetTimeNS().count(), emulated_clock_factor); +        std::chrono::nanoseconds time_now = GetTimeNS(); +        const u128 temporary = +            Common::Multiply64Into128(time_now.count(), emulated_clock_frequency); +        return Common::Divide128On32(temporary, 1000000000).first;      }      u64 GetCPUCycles() override { -        return MultiplyHigh(GetTimeNS().count(), emulated_cpu_factor); +        std::chrono::nanoseconds time_now = GetTimeNS(); +        const u128 temporary = Common::Multiply64Into128(time_now.count(), emulated_cpu_frequency); +        return Common::Divide128On32(temporary, 1000000000).first;      }      void Pause([[maybe_unused]] bool is_paused) override { @@ -58,8 +61,6 @@ public:  private:      base_time_point start_time; -    const u64 emulated_clock_factor; -    const u64 emulated_cpu_factor;  };  #ifdef ARCHITECTURE_x86_64 | 
