Common: improve native clock.
This commit is contained in:
		| @@ -30,6 +30,10 @@ namespace Common { | |||||||
| #else | #else | ||||||
|     return _udiv128(r[1], r[0], d, &remainder); |     return _udiv128(r[1], r[0], d, &remainder); | ||||||
| #endif | #endif | ||||||
|  | #else | ||||||
|  | #ifdef __SIZEOF_INT128__ | ||||||
|  |     const auto product = static_cast<unsigned __int128>(a) * static_cast<unsigned __int128>(b); | ||||||
|  |     return static_cast<u64>(product / d); | ||||||
| #else | #else | ||||||
|     const u64 diva = a / d; |     const u64 diva = a / d; | ||||||
|     const u64 moda = a % d; |     const u64 moda = a % d; | ||||||
| @@ -37,6 +41,7 @@ namespace Common { | |||||||
|     const u64 modb = b % d; |     const u64 modb = b % d; | ||||||
|     return diva * b + moda * divb + moda * modb / d; |     return diva * b + moda * divb + moda * modb / d; | ||||||
| #endif | #endif | ||||||
|  | #endif | ||||||
| } | } | ||||||
|  |  | ||||||
| // This function multiplies 2 u64 values and produces a u128 value; | // This function multiplies 2 u64 values and produces a u128 value; | ||||||
|   | |||||||
| @@ -5,7 +5,6 @@ | |||||||
| #include <chrono> | #include <chrono> | ||||||
| #include <thread> | #include <thread> | ||||||
|  |  | ||||||
| #include "common/atomic_ops.h" |  | ||||||
| #include "common/uint128.h" | #include "common/uint128.h" | ||||||
| #include "common/x64/native_clock.h" | #include "common/x64/native_clock.h" | ||||||
|  |  | ||||||
| @@ -65,8 +64,10 @@ NativeClock::NativeClock(u64 emulated_cpu_frequency_, u64 emulated_clock_frequen | |||||||
|                          u64 rtsc_frequency_) |                          u64 rtsc_frequency_) | ||||||
|     : WallClock(emulated_cpu_frequency_, emulated_clock_frequency_, true), rtsc_frequency{ |     : WallClock(emulated_cpu_frequency_, emulated_clock_frequency_, true), rtsc_frequency{ | ||||||
|                                                                                rtsc_frequency_} { |                                                                                rtsc_frequency_} { | ||||||
|     time_point.inner.last_measure = FencedRDTSC(); |     TimePoint new_time_point{}; | ||||||
|     time_point.inner.accumulated_ticks = 0U; |     new_time_point.last_measure = FencedRDTSC(); | ||||||
|  |     new_time_point.accumulated_ticks = 0U; | ||||||
|  |     time_point.store(new_time_point); | ||||||
|     ns_rtsc_factor = GetFixedPoint64Factor(NS_RATIO, rtsc_frequency); |     ns_rtsc_factor = GetFixedPoint64Factor(NS_RATIO, rtsc_frequency); | ||||||
|     us_rtsc_factor = GetFixedPoint64Factor(US_RATIO, rtsc_frequency); |     us_rtsc_factor = GetFixedPoint64Factor(US_RATIO, rtsc_frequency); | ||||||
|     ms_rtsc_factor = GetFixedPoint64Factor(MS_RATIO, rtsc_frequency); |     ms_rtsc_factor = GetFixedPoint64Factor(MS_RATIO, rtsc_frequency); | ||||||
| @@ -76,34 +77,31 @@ NativeClock::NativeClock(u64 emulated_cpu_frequency_, u64 emulated_clock_frequen | |||||||
|  |  | ||||||
| u64 NativeClock::GetRTSC() { | u64 NativeClock::GetRTSC() { | ||||||
|     TimePoint new_time_point{}; |     TimePoint new_time_point{}; | ||||||
|     TimePoint current_time_point{}; |     TimePoint current_time_point = time_point.load(std::memory_order_acquire); | ||||||
|  |  | ||||||
|     current_time_point.pack = Common::AtomicLoad128(time_point.pack.data()); |  | ||||||
|     do { |     do { | ||||||
|         const u64 current_measure = FencedRDTSC(); |         const u64 current_measure = FencedRDTSC(); | ||||||
|         u64 diff = current_measure - current_time_point.inner.last_measure; |         u64 diff = current_measure - current_time_point.last_measure; | ||||||
|         diff = diff & ~static_cast<u64>(static_cast<s64>(diff) >> 63); // max(diff, 0) |         diff = diff & ~static_cast<u64>(static_cast<s64>(diff) >> 63); // max(diff, 0) | ||||||
|         new_time_point.inner.last_measure = current_measure > current_time_point.inner.last_measure |         new_time_point.last_measure = current_measure > current_time_point.last_measure | ||||||
|                                           ? current_measure |                                           ? current_measure | ||||||
|                                                 : current_time_point.inner.last_measure; |                                           : current_time_point.last_measure; | ||||||
|         new_time_point.inner.accumulated_ticks = current_time_point.inner.accumulated_ticks + diff; |         new_time_point.accumulated_ticks = current_time_point.accumulated_ticks + diff; | ||||||
|     } while (!Common::AtomicCompareAndSwap(time_point.pack.data(), new_time_point.pack, |     } while (!time_point.compare_exchange_weak( | ||||||
|                                            current_time_point.pack, current_time_point.pack)); |         current_time_point, new_time_point, std::memory_order_release, std::memory_order_acquire)); | ||||||
|     /// The clock cannot be more precise than the guest timer, remove the lower bits |     /// The clock cannot be more precise than the guest timer, remove the lower bits | ||||||
|     return new_time_point.inner.accumulated_ticks & inaccuracy_mask; |     return new_time_point.accumulated_ticks & inaccuracy_mask; | ||||||
| } | } | ||||||
|  |  | ||||||
| void NativeClock::Pause(bool is_paused) { | void NativeClock::Pause(bool is_paused) { | ||||||
|     if (!is_paused) { |     if (!is_paused) { | ||||||
|         TimePoint current_time_point{}; |  | ||||||
|         TimePoint new_time_point{}; |         TimePoint new_time_point{}; | ||||||
|  |         TimePoint current_time_point = time_point.load(std::memory_order_acquire); | ||||||
|         current_time_point.pack = Common::AtomicLoad128(time_point.pack.data()); |  | ||||||
|         do { |         do { | ||||||
|             new_time_point.pack = current_time_point.pack; |             new_time_point = current_time_point; | ||||||
|             new_time_point.inner.last_measure = FencedRDTSC(); |             new_time_point.last_measure = FencedRDTSC(); | ||||||
|         } while (!Common::AtomicCompareAndSwap(time_point.pack.data(), new_time_point.pack, |         } while (!time_point.compare_exchange_weak(current_time_point, new_time_point, | ||||||
|                                                current_time_point.pack, current_time_point.pack)); |                                                    std::memory_order_release, | ||||||
|  |                                                    std::memory_order_acquire)); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -3,6 +3,7 @@ | |||||||
|  |  | ||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
|  | #include <atomic> | ||||||
| #include "common/wall_clock.h" | #include "common/wall_clock.h" | ||||||
|  |  | ||||||
| namespace Common { | namespace Common { | ||||||
| @@ -28,13 +29,9 @@ public: | |||||||
| private: | private: | ||||||
|     u64 GetRTSC(); |     u64 GetRTSC(); | ||||||
|  |  | ||||||
|     union alignas(16) TimePoint { |     struct alignas(16) TimePoint { | ||||||
|         TimePoint() : pack{} {} |  | ||||||
|         u128 pack{}; |  | ||||||
|         struct Inner { |  | ||||||
|         u64 last_measure{}; |         u64 last_measure{}; | ||||||
|         u64 accumulated_ticks{}; |         u64 accumulated_ticks{}; | ||||||
|         } inner; |  | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     /// value used to reduce the native clocks accuracy as some apss rely on |     /// value used to reduce the native clocks accuracy as some apss rely on | ||||||
| @@ -42,7 +39,7 @@ private: | |||||||
|     /// be higher. |     /// be higher. | ||||||
|     static constexpr u64 inaccuracy_mask = ~(UINT64_C(0x400) - 1); |     static constexpr u64 inaccuracy_mask = ~(UINT64_C(0x400) - 1); | ||||||
|  |  | ||||||
|     TimePoint time_point; |     std::atomic<TimePoint> time_point; | ||||||
|     // factors |     // factors | ||||||
|     u64 clock_rtsc_factor{}; |     u64 clock_rtsc_factor{}; | ||||||
|     u64 cpu_rtsc_factor{}; |     u64 cpu_rtsc_factor{}; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user