33#include " util/helpers/fspinlock.h"
44#include " util/highresolutiontimer/HighResolutionTimer.h"
55#include " Common/cpu_features.h"
6+
67#include " Common/Intrinsics.h"
78
9+ #include < chrono>
10+ #include < thread>
11+
812uint64 _rdtscLastMeasure = 0 ;
913uint64 _rdtscFrequency = 0 ;
10- uint64 _tickSummary = 0 ;
11-
12- struct uint128_t
13- {
14- uint64 low;
15- uint64 high;
16- };
17-
18- static_assert (sizeof (uint128_t ) == 16 );
1914
2015uint128_t _rdtscAcc{};
2116
@@ -30,32 +25,42 @@ uint64 muldiv64(uint64 a, uint64 b, uint64 d)
3025
3126uint64 PPCTimer_estimateRDTSCFrequency ()
3227{
33- #if defined(ARCH_X86_64)
28+ #if defined(ARCH_X86_64) || defined(__x86_64__) || defined(_M_X64 )
3429 if (!g_CPUFeatures.x86 .invariant_tsc )
3530 cemuLog_log (LogType::Force, " Invariant TSC not supported" );
36- #endif
31+ #endif
3732
3833 BARRIER_FENCE ();
3934 uint64 tscStart = READ_TSC ();
40- unsigned int startTime = GetTickCount ();
35+ auto startTime = std::chrono::steady_clock::now ();
4136 HRTick startTick = HighResolutionTimer::now ().getTick ();
42-
37+ // wait roughly 3 seconds
4338 while (true )
4439 {
45- if ((GetTickCount () - startTime) >= 3000 )
40+ auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
41+ std::chrono::steady_clock::now () - startTime).count ();
42+ if (elapsed >= 3000 )
4643 break ;
4744 std::this_thread::sleep_for (std::chrono::milliseconds (10 ));
4845 }
4946
5047 BARRIER_FENCE ();
5148 HRTick stopTick = HighResolutionTimer::now ().getTick ();
5249 uint64 tscEnd = READ_TSC ();
53-
50+ // derive frequency approximation from measured time difference
5451 uint64 tsc_diff = tscEnd - tscStart;
5552 uint64 hrtFreq = 0 ;
5653 uint64 hrtDiff = HighResolutionTimer::getTimeDiffEx (startTick, stopTick, hrtFreq);
5754 uint64 tsc_freq = muldiv64 (tsc_diff, hrtFreq, hrtDiff);
5855
56+ // uint64 freqMultiplier = tsc_freq / hrtFreq;
57+ // cemuLog_log(LogType::Force, "RDTSC measurement test:");
58+ // cemuLog_log(LogType::Force, "TSC-diff: 0x{:016x}", tsc_diff);
59+ // cemuLog_log(LogType::Force, "TSC-freq: 0x{:016x}", tsc_freq);
60+ // cemuLog_log(LogType::Force, "HPC-diff: 0x{:016x}", qpc_diff);
61+ // cemuLog_log(LogType::Force, "HPC-freq: 0x{:016x}", (uint64)qpc_freq.QuadPart);
62+ // cemuLog_log(LogType::Force, "Multiplier: 0x{:016x}", freqMultiplier);
63+
5964 return tsc_freq;
6065}
6166
@@ -72,6 +77,8 @@ void PPCTimer_init()
7277 _rdtscLastMeasure = READ_TSC ();
7378}
7479
80+ uint64 _tickSummary = 0 ;
81+
7582void PPCTimer_start ()
7683{
7784 _rdtscLastMeasure = READ_TSC ();
@@ -91,12 +98,10 @@ uint64 PPCTimer_microsecondsToTsc(uint64 us)
9198uint64 PPCTimer_tscToMicroseconds (uint64 us)
9299{
93100 uint128_t r{};
94- // Changed: Using Multiply64to128 wrapper
95- r.low = Multiply64to128 (us, 1000000ULL , &r.high );
101+ r.low = portable_umul128 (us, 1000000ULL , &r.high );
96102
97103 uint64 remainder;
98- // Changed: Using Divide128by64 wrapper
99- const uint64 microseconds = Divide128by64 (r.high , r.low , _rdtscFrequency, &remainder);
104+ const uint64 microseconds = portable_udiv128 (r.high , r.low , _rdtscFrequency, &remainder);
100105
101106 return microseconds;
102107}
@@ -113,37 +118,35 @@ void PPCTimer_waitForInit()
113118
114119FSpinlock sTimerSpinlock ;
115120
121+ // thread safe
116122uint64 PPCTimer_getFromRDTSC ()
117123{
118124 sTimerSpinlock .lock ();
119125 BARRIER_FENCE ();
120126 uint64 rdtscCurrentMeasure = READ_TSC ();
121127 uint64 rdtscDif = rdtscCurrentMeasure - _rdtscLastMeasure;
122-
128+ // optimized max(rdtscDif, 0) without conditionals
123129 rdtscDif = rdtscDif & ~(uint64)((sint64)rdtscDif >> 63 );
124130
125131 uint128_t diff{};
126- diff.low = Multiply64to128 (rdtscDif, Espresso::CORE_CLOCK , &diff.high );
132+ diff.low = portable_umul128 (rdtscDif, Espresso::CORE_CLOCK , &diff.high );
127133
128134 if (rdtscCurrentMeasure > _rdtscLastMeasure)
129- _rdtscLastMeasure = rdtscCurrentMeasure;
135+ _rdtscLastMeasure = rdtscCurrentMeasure; // only travel forward in time
130136
131- uint8 c = 0 ;
132- #if defined(_MSC_VER)
133- c = _addcarry_u64 (c, _rdtscAcc.low , diff.low , &_rdtscAcc.low );
134- _addcarry_u64 (c, _rdtscAcc.high , diff.high , &_rdtscAcc.high );
135- #else
136- c = _addcarry_u64 (c, _rdtscAcc.low , diff.low , (unsigned long long *)&_rdtscAcc.low );
137- _addcarry_u64 (c, _rdtscAcc.high , diff.high , (unsigned long long *)&_rdtscAcc.high );
138- #endif
137+ uint64 old_low = _rdtscAcc.low ;
138+ _rdtscAcc.low += diff.low ;
139+ uint64 carry = (_rdtscAcc.low < old_low) ? 1 : 0 ;
140+ _rdtscAcc.high += diff.high + carry;
139141
140142 uint64 remainder;
141- uint64 elapsedTick = Divide128by64 (_rdtscAcc.high , _rdtscAcc.low , _rdtscFrequency, &remainder);
143+ uint64 elapsedTick = portable_udiv128 (_rdtscAcc.high , _rdtscAcc.low , _rdtscFrequency, &remainder);
142144
143145 _rdtscAcc.low = remainder;
144146 _rdtscAcc.high = 0 ;
145147
146- elapsedTick <<= 3ull ;
148+ // timer scaling
149+ elapsedTick <<= 3ull ; // *8
147150 uint8 timerShiftFactor = ActiveSettings::GetTimerShiftFactor ();
148151 elapsedTick >>= timerShiftFactor;
149152
0 commit comments