@ -6,6 +6,10 @@
# include <string>
# include <tuple>
# ifdef _WIN32
# include "common/windows/timer_resolution.h"
# endif
# include "common/microprofile.h"
# include "core/core_timing.h"
# include "core/core_timing_util.h"
@ -38,7 +42,8 @@ struct CoreTiming::Event {
} ;
CoreTiming : : CoreTiming ( )
: clock { Common : : CreateBestMatchingClock ( Hardware : : BASE_CLOCK_RATE , Hardware : : CNTFREQ ) } { }
: cpu_clock { Common : : CreateBestMatchingClock ( Hardware : : BASE_CLOCK_RATE , Hardware : : CNTFREQ ) } ,
event_clock { Common : : CreateStandardWallClock ( Hardware : : BASE_CLOCK_RATE , Hardware : : CNTFREQ ) } { }
CoreTiming : : ~ CoreTiming ( ) {
Reset ( ) ;
@ -185,15 +190,15 @@ void CoreTiming::ResetTicks() {
}
u64 CoreTiming : : GetCPUTicks ( ) const {
if ( is_multicore ) {
return c lock- > GetCPUCycles ( ) ;
if ( is_multicore ) [[likely]] {
return c pu_c lock- > GetCPUCycles ( ) ;
}
return ticks ;
}
u64 CoreTiming : : GetClockTicks ( ) const {
if ( is_multicore ) {
return c lock- > GetClockCycles ( ) ;
if ( is_multicore ) [[likely]] {
return c pu_c lock- > GetClockCycles ( ) ;
}
return CpuCyclesToClockCycles ( ticks ) ;
}
@ -252,22 +257,21 @@ void CoreTiming::ThreadLoop() {
const auto next_time = Advance ( ) ;
if ( next_time ) {
// There are more events left in the queue, wait until the next event.
const auto wait_time = * next_time - GetGlobalTimeNs ( ) . count ( ) ;
auto wait_time = * next_time - GetGlobalTimeNs ( ) . count ( ) ;
if ( wait_time > 0 ) {
# ifdef _WIN32
// Assume a timer resolution of 1ms.
static constexpr s64 TimerResolutionNS = 1000000 ;
const auto timer_resolution_ns =
Common : : Windows : : GetCurrentTimerResolution ( ) . count ( ) ;
// Sleep in discrete intervals of the timer resolution, and spin the rest.
const auto sleep_time = wait_time - ( wait_time % TimerResolutionNS ) ;
if ( sleep_time > 0 ) {
event . WaitFor ( std : : chrono : : nanoseconds ( sleep_time ) ) ;
}
while ( ! paused & & ! event . IsSet ( ) & & wait_time > 0 ) {
wait_time = * next_time - GetGlobalTimeNs ( ) . count ( ) ;
while ( ! paused & & ! event . IsSet ( ) & & GetGlobalTimeNs ( ) . count ( ) < * next_time ) {
// Yield to reduce thread starvation.
if ( wait_time > = timer_resolution_ns ) {
Common : : Windows : : SleepForOneTick ( ) ;
} else {
std : : this_thread : : yield ( ) ;
}
}
if ( event . IsSet ( ) ) {
event . Reset ( ) ;
@ -285,9 +289,9 @@ void CoreTiming::ThreadLoop() {
}
paused_set = true ;
clock- > Pause ( true ) ;
event_ clock- > Pause ( true ) ;
pause_event . Wait ( ) ;
clock- > Pause ( false ) ;
event_ clock- > Pause ( false ) ;
}
}
@ -303,16 +307,23 @@ void CoreTiming::Reset() {
has_started = false ;
}
std : : chrono : : nanoseconds CoreTiming : : GetCPUTimeNs ( ) const {
if ( is_multicore ) [[likely]] {
return cpu_clock - > GetTimeNS ( ) ;
}
return CyclesToNs ( ticks ) ;
}
std : : chrono : : nanoseconds CoreTiming : : GetGlobalTimeNs ( ) const {
if ( is_multicore ) {
return clock - > GetTimeNS ( ) ;
if ( is_multicore ) [[likely]] {
return event_ clock- > GetTimeNS ( ) ;
}
return CyclesToNs ( ticks ) ;
}
std : : chrono : : microseconds CoreTiming : : GetGlobalTimeUs ( ) const {
if ( is_multicore ) {
return clock- > GetTimeUS ( ) ;
if ( is_multicore ) [[likely]] {
return event_ clock- > GetTimeUS ( ) ;
}
return CyclesToUs ( ticks ) ;
}