@ -28,100 +28,103 @@ void CallbackTemplate(u64 userdata, s64 cycles_late) {
REQUIRE ( lateness = = cycles_late ) ;
REQUIRE ( lateness = = cycles_late ) ;
}
}
class ScopeInit final {
struct ScopeInit final {
public :
ScopeInit ( ) {
ScopeInit ( ) {
Core: : Timing : : Init ( ) ;
core_timing. Initialize ( ) ;
}
}
~ ScopeInit ( ) {
~ ScopeInit ( ) {
Core: : Timing : : Shutdown ( ) ;
core_timing. Shutdown ( ) ;
}
}
Core : : Timing : : CoreTiming core_timing ;
} ;
} ;
static void AdvanceAndCheck ( u32 idx , int downcount , int expected_lateness = 0 ,
static void AdvanceAndCheck ( Core: : Timing : : CoreTiming & core_timing , u32 idx , int downcount ,
int cpu_downcount = 0 ) {
int expected_lateness = 0 , int cpu_downcount = 0 ) {
callbacks_ran_flags = 0 ;
callbacks_ran_flags = 0 ;
expected_callback = CB_IDS [ idx ] ;
expected_callback = CB_IDS [ idx ] ;
lateness = expected_lateness ;
lateness = expected_lateness ;
// Pretend we executed X cycles of instructions.
// Pretend we executed X cycles of instructions.
Core: : Timing : : AddTicks ( Core : : Timing : : GetDowncount ( ) - cpu_downcount ) ;
core_timing. AddTicks ( core_timing . GetDowncount ( ) - cpu_downcount ) ;
Core: : Timing : : Advance ( ) ;
core_timing. Advance ( ) ;
REQUIRE ( decltype ( callbacks_ran_flags ) ( ) . set ( idx ) = = callbacks_ran_flags ) ;
REQUIRE ( decltype ( callbacks_ran_flags ) ( ) . set ( idx ) = = callbacks_ran_flags ) ;
REQUIRE ( downcount = = Core: : Timing : : GetDowncount ( ) ) ;
REQUIRE ( downcount = = core_timing. GetDowncount ( ) ) ;
}
}
TEST_CASE ( " CoreTiming[BasicOrder] " , " [core] " ) {
TEST_CASE ( " CoreTiming[BasicOrder] " , " [core] " ) {
ScopeInit guard ;
ScopeInit guard ;
auto & core_timing = guard . core_timing ;
Core : : Timing : : EventType * cb_a = Core: : Timing : : RegisterEvent ( " callbackA " , CallbackTemplate < 0 > ) ;
Core : : Timing : : EventType * cb_a = core_timing. RegisterEvent ( " callbackA " , CallbackTemplate < 0 > ) ;
Core : : Timing : : EventType * cb_b = Core: : Timing : : RegisterEvent ( " callbackB " , CallbackTemplate < 1 > ) ;
Core : : Timing : : EventType * cb_b = core_timing. RegisterEvent ( " callbackB " , CallbackTemplate < 1 > ) ;
Core : : Timing : : EventType * cb_c = Core: : Timing : : RegisterEvent ( " callbackC " , CallbackTemplate < 2 > ) ;
Core : : Timing : : EventType * cb_c = core_timing. RegisterEvent ( " callbackC " , CallbackTemplate < 2 > ) ;
Core : : Timing : : EventType * cb_d = Core: : Timing : : RegisterEvent ( " callbackD " , CallbackTemplate < 3 > ) ;
Core : : Timing : : EventType * cb_d = core_timing. RegisterEvent ( " callbackD " , CallbackTemplate < 3 > ) ;
Core : : Timing : : EventType * cb_e = Core: : Timing : : RegisterEvent ( " callbackE " , CallbackTemplate < 4 > ) ;
Core : : Timing : : EventType * cb_e = core_timing. RegisterEvent ( " callbackE " , CallbackTemplate < 4 > ) ;
// Enter slice 0
// Enter slice 0
Core: : Timing : : Advance ( ) ;
core_timing. Advance ( ) ;
// D -> B -> C -> A -> E
// D -> B -> C -> A -> E
Core: : Timing : : ScheduleEvent ( 1000 , cb_a , CB_IDS [ 0 ] ) ;
core_timing. ScheduleEvent ( 1000 , cb_a , CB_IDS [ 0 ] ) ;
REQUIRE ( 1000 = = Core: : Timing : : GetDowncount ( ) ) ;
REQUIRE ( 1000 = = core_timing. GetDowncount ( ) ) ;
Core: : Timing : : ScheduleEvent ( 500 , cb_b , CB_IDS [ 1 ] ) ;
core_timing. ScheduleEvent ( 500 , cb_b , CB_IDS [ 1 ] ) ;
REQUIRE ( 500 = = Core: : Timing : : GetDowncount ( ) ) ;
REQUIRE ( 500 = = core_timing. GetDowncount ( ) ) ;
Core: : Timing : : ScheduleEvent ( 800 , cb_c , CB_IDS [ 2 ] ) ;
core_timing. ScheduleEvent ( 800 , cb_c , CB_IDS [ 2 ] ) ;
REQUIRE ( 500 = = Core: : Timing : : GetDowncount ( ) ) ;
REQUIRE ( 500 = = core_timing. GetDowncount ( ) ) ;
Core: : Timing : : ScheduleEvent ( 100 , cb_d , CB_IDS [ 3 ] ) ;
core_timing. ScheduleEvent ( 100 , cb_d , CB_IDS [ 3 ] ) ;
REQUIRE ( 100 = = Core: : Timing : : GetDowncount ( ) ) ;
REQUIRE ( 100 = = core_timing. GetDowncount ( ) ) ;
Core: : Timing : : ScheduleEvent ( 1200 , cb_e , CB_IDS [ 4 ] ) ;
core_timing. ScheduleEvent ( 1200 , cb_e , CB_IDS [ 4 ] ) ;
REQUIRE ( 100 = = Core: : Timing : : GetDowncount ( ) ) ;
REQUIRE ( 100 = = core_timing. GetDowncount ( ) ) ;
AdvanceAndCheck ( 3 , 400 ) ;
AdvanceAndCheck ( core_timing , 3 , 400 ) ;
AdvanceAndCheck ( 1 , 300 ) ;
AdvanceAndCheck ( core_timing , 1 , 300 ) ;
AdvanceAndCheck ( 2 , 200 ) ;
AdvanceAndCheck ( core_timing , 2 , 200 ) ;
AdvanceAndCheck ( 0 , 200 ) ;
AdvanceAndCheck ( core_timing , 0 , 200 ) ;
AdvanceAndCheck ( 4 , MAX_SLICE_LENGTH ) ;
AdvanceAndCheck ( core_timing , 4 , MAX_SLICE_LENGTH ) ;
}
}
TEST_CASE ( " CoreTiming[Threadsave] " , " [core] " ) {
TEST_CASE ( " CoreTiming[Threadsave] " , " [core] " ) {
ScopeInit guard ;
ScopeInit guard ;
auto & core_timing = guard . core_timing ;
Core : : Timing : : EventType * cb_a = Core: : Timing : : RegisterEvent ( " callbackA " , CallbackTemplate < 0 > ) ;
Core : : Timing : : EventType * cb_a = core_timing. RegisterEvent ( " callbackA " , CallbackTemplate < 0 > ) ;
Core : : Timing : : EventType * cb_b = Core: : Timing : : RegisterEvent ( " callbackB " , CallbackTemplate < 1 > ) ;
Core : : Timing : : EventType * cb_b = core_timing. RegisterEvent ( " callbackB " , CallbackTemplate < 1 > ) ;
Core : : Timing : : EventType * cb_c = Core: : Timing : : RegisterEvent ( " callbackC " , CallbackTemplate < 2 > ) ;
Core : : Timing : : EventType * cb_c = core_timing. RegisterEvent ( " callbackC " , CallbackTemplate < 2 > ) ;
Core : : Timing : : EventType * cb_d = Core: : Timing : : RegisterEvent ( " callbackD " , CallbackTemplate < 3 > ) ;
Core : : Timing : : EventType * cb_d = core_timing. RegisterEvent ( " callbackD " , CallbackTemplate < 3 > ) ;
Core : : Timing : : EventType * cb_e = Core: : Timing : : RegisterEvent ( " callbackE " , CallbackTemplate < 4 > ) ;
Core : : Timing : : EventType * cb_e = core_timing. RegisterEvent ( " callbackE " , CallbackTemplate < 4 > ) ;
// Enter slice 0
// Enter slice 0
Core: : Timing : : Advance ( ) ;
core_timing. Advance ( ) ;
// D -> B -> C -> A -> E
// D -> B -> C -> A -> E
Core: : Timing : : ScheduleEventThreadsafe ( 1000 , cb_a , CB_IDS [ 0 ] ) ;
core_timing. ScheduleEventThreadsafe ( 1000 , cb_a , CB_IDS [ 0 ] ) ;
// Manually force since ScheduleEventThreadsafe doesn't call it
// Manually force since ScheduleEventThreadsafe doesn't call it
Core: : Timing : : ForceExceptionCheck ( 1000 ) ;
core_timing. ForceExceptionCheck ( 1000 ) ;
REQUIRE ( 1000 = = Core: : Timing : : GetDowncount ( ) ) ;
REQUIRE ( 1000 = = core_timing. GetDowncount ( ) ) ;
Core: : Timing : : ScheduleEventThreadsafe ( 500 , cb_b , CB_IDS [ 1 ] ) ;
core_timing. ScheduleEventThreadsafe ( 500 , cb_b , CB_IDS [ 1 ] ) ;
// Manually force since ScheduleEventThreadsafe doesn't call it
// Manually force since ScheduleEventThreadsafe doesn't call it
Core: : Timing : : ForceExceptionCheck ( 500 ) ;
core_timing. ForceExceptionCheck ( 500 ) ;
REQUIRE ( 500 = = Core: : Timing : : GetDowncount ( ) ) ;
REQUIRE ( 500 = = core_timing. GetDowncount ( ) ) ;
Core: : Timing : : ScheduleEventThreadsafe ( 800 , cb_c , CB_IDS [ 2 ] ) ;
core_timing. ScheduleEventThreadsafe ( 800 , cb_c , CB_IDS [ 2 ] ) ;
// Manually force since ScheduleEventThreadsafe doesn't call it
// Manually force since ScheduleEventThreadsafe doesn't call it
Core: : Timing : : ForceExceptionCheck ( 800 ) ;
core_timing. ForceExceptionCheck ( 800 ) ;
REQUIRE ( 500 = = Core: : Timing : : GetDowncount ( ) ) ;
REQUIRE ( 500 = = core_timing. GetDowncount ( ) ) ;
Core: : Timing : : ScheduleEventThreadsafe ( 100 , cb_d , CB_IDS [ 3 ] ) ;
core_timing. ScheduleEventThreadsafe ( 100 , cb_d , CB_IDS [ 3 ] ) ;
// Manually force since ScheduleEventThreadsafe doesn't call it
// Manually force since ScheduleEventThreadsafe doesn't call it
Core: : Timing : : ForceExceptionCheck ( 100 ) ;
core_timing. ForceExceptionCheck ( 100 ) ;
REQUIRE ( 100 = = Core: : Timing : : GetDowncount ( ) ) ;
REQUIRE ( 100 = = core_timing. GetDowncount ( ) ) ;
Core: : Timing : : ScheduleEventThreadsafe ( 1200 , cb_e , CB_IDS [ 4 ] ) ;
core_timing. ScheduleEventThreadsafe ( 1200 , cb_e , CB_IDS [ 4 ] ) ;
// Manually force since ScheduleEventThreadsafe doesn't call it
// Manually force since ScheduleEventThreadsafe doesn't call it
Core: : Timing : : ForceExceptionCheck ( 1200 ) ;
core_timing. ForceExceptionCheck ( 1200 ) ;
REQUIRE ( 100 = = Core: : Timing : : GetDowncount ( ) ) ;
REQUIRE ( 100 = = core_timing. GetDowncount ( ) ) ;
AdvanceAndCheck ( 3 , 400 ) ;
AdvanceAndCheck ( core_timing , 3 , 400 ) ;
AdvanceAndCheck ( 1 , 300 ) ;
AdvanceAndCheck ( core_timing , 1 , 300 ) ;
AdvanceAndCheck ( 2 , 200 ) ;
AdvanceAndCheck ( core_timing , 2 , 200 ) ;
AdvanceAndCheck ( 0 , 200 ) ;
AdvanceAndCheck ( core_timing , 0 , 200 ) ;
AdvanceAndCheck ( 4 , MAX_SLICE_LENGTH ) ;
AdvanceAndCheck ( core_timing , 4 , MAX_SLICE_LENGTH ) ;
}
}
namespace SharedSlotTest {
namespace SharedSlotTest {
@ -142,59 +145,62 @@ TEST_CASE("CoreTiming[SharedSlot]", "[core]") {
using namespace SharedSlotTest ;
using namespace SharedSlotTest ;
ScopeInit guard ;
ScopeInit guard ;
auto & core_timing = guard . core_timing ;
Core : : Timing : : EventType * cb_a = Core: : Timing : : RegisterEvent ( " callbackA " , FifoCallback < 0 > ) ;
Core : : Timing : : EventType * cb_a = core_timing. RegisterEvent ( " callbackA " , FifoCallback < 0 > ) ;
Core : : Timing : : EventType * cb_b = Core: : Timing : : RegisterEvent ( " callbackB " , FifoCallback < 1 > ) ;
Core : : Timing : : EventType * cb_b = core_timing. RegisterEvent ( " callbackB " , FifoCallback < 1 > ) ;
Core : : Timing : : EventType * cb_c = Core: : Timing : : RegisterEvent ( " callbackC " , FifoCallback < 2 > ) ;
Core : : Timing : : EventType * cb_c = core_timing. RegisterEvent ( " callbackC " , FifoCallback < 2 > ) ;
Core : : Timing : : EventType * cb_d = Core: : Timing : : RegisterEvent ( " callbackD " , FifoCallback < 3 > ) ;
Core : : Timing : : EventType * cb_d = core_timing. RegisterEvent ( " callbackD " , FifoCallback < 3 > ) ;
Core : : Timing : : EventType * cb_e = Core: : Timing : : RegisterEvent ( " callbackE " , FifoCallback < 4 > ) ;
Core : : Timing : : EventType * cb_e = core_timing. RegisterEvent ( " callbackE " , FifoCallback < 4 > ) ;
Core: : Timing : : ScheduleEvent ( 1000 , cb_a , CB_IDS [ 0 ] ) ;
core_timing. ScheduleEvent ( 1000 , cb_a , CB_IDS [ 0 ] ) ;
Core: : Timing : : ScheduleEvent ( 1000 , cb_b , CB_IDS [ 1 ] ) ;
core_timing. ScheduleEvent ( 1000 , cb_b , CB_IDS [ 1 ] ) ;
Core: : Timing : : ScheduleEvent ( 1000 , cb_c , CB_IDS [ 2 ] ) ;
core_timing. ScheduleEvent ( 1000 , cb_c , CB_IDS [ 2 ] ) ;
Core: : Timing : : ScheduleEvent ( 1000 , cb_d , CB_IDS [ 3 ] ) ;
core_timing. ScheduleEvent ( 1000 , cb_d , CB_IDS [ 3 ] ) ;
Core: : Timing : : ScheduleEvent ( 1000 , cb_e , CB_IDS [ 4 ] ) ;
core_timing. ScheduleEvent ( 1000 , cb_e , CB_IDS [ 4 ] ) ;
// Enter slice 0
// Enter slice 0
Core: : Timing : : Advance ( ) ;
core_timing. Advance ( ) ;
REQUIRE ( 1000 = = Core: : Timing : : GetDowncount ( ) ) ;
REQUIRE ( 1000 = = core_timing. GetDowncount ( ) ) ;
callbacks_ran_flags = 0 ;
callbacks_ran_flags = 0 ;
counter = 0 ;
counter = 0 ;
lateness = 0 ;
lateness = 0 ;
Core: : Timing : : AddTicks ( Core : : Timing : : GetDowncount ( ) ) ;
core_timing. AddTicks ( core_timing . GetDowncount ( ) ) ;
Core: : Timing : : Advance ( ) ;
core_timing. Advance ( ) ;
REQUIRE ( MAX_SLICE_LENGTH = = Core: : Timing : : GetDowncount ( ) ) ;
REQUIRE ( MAX_SLICE_LENGTH = = core_timing. GetDowncount ( ) ) ;
REQUIRE ( 0x1FULL = = callbacks_ran_flags . to_ullong ( ) ) ;
REQUIRE ( 0x1FULL = = callbacks_ran_flags . to_ullong ( ) ) ;
}
}
TEST_CASE ( " Core::Timing[PredictableLateness] " , " [core] " ) {
TEST_CASE ( " Core::Timing[PredictableLateness] " , " [core] " ) {
ScopeInit guard ;
ScopeInit guard ;
auto & core_timing = guard . core_timing ;
Core : : Timing : : EventType * cb_a = Core: : Timing : : RegisterEvent ( " callbackA " , CallbackTemplate < 0 > ) ;
Core : : Timing : : EventType * cb_a = core_timing. RegisterEvent ( " callbackA " , CallbackTemplate < 0 > ) ;
Core : : Timing : : EventType * cb_b = Core: : Timing : : RegisterEvent ( " callbackB " , CallbackTemplate < 1 > ) ;
Core : : Timing : : EventType * cb_b = core_timing. RegisterEvent ( " callbackB " , CallbackTemplate < 1 > ) ;
// Enter slice 0
// Enter slice 0
Core: : Timing : : Advance ( ) ;
core_timing. Advance ( ) ;
Core: : Timing : : ScheduleEvent ( 100 , cb_a , CB_IDS [ 0 ] ) ;
core_timing. ScheduleEvent ( 100 , cb_a , CB_IDS [ 0 ] ) ;
Core: : Timing : : ScheduleEvent ( 200 , cb_b , CB_IDS [ 1 ] ) ;
core_timing. ScheduleEvent ( 200 , cb_b , CB_IDS [ 1 ] ) ;
AdvanceAndCheck ( 0 , 90 , 10 , - 10 ) ; // (100 - 10)
AdvanceAndCheck ( core_timing , 0 , 90 , 10 , - 10 ) ; // (100 - 10)
AdvanceAndCheck ( 1 , MAX_SLICE_LENGTH , 50 , - 50 ) ;
AdvanceAndCheck ( core_timing , 1 , MAX_SLICE_LENGTH , 50 , - 50 ) ;
}
}
namespace ChainSchedulingTest {
namespace ChainSchedulingTest {
static int reschedules = 0 ;
static int reschedules = 0 ;
static void RescheduleCallback ( u64 userdata , s64 cycles_late ) {
static void RescheduleCallback ( Core : : Timing : : CoreTiming & core_timing , u64 userdata ,
s64 cycles_late ) {
- - reschedules ;
- - reschedules ;
REQUIRE ( reschedules > = 0 ) ;
REQUIRE ( reschedules > = 0 ) ;
REQUIRE ( lateness = = cycles_late ) ;
REQUIRE ( lateness = = cycles_late ) ;
if ( reschedules > 0 ) {
if ( reschedules > 0 ) {
Core: : Timing : : ScheduleEvent ( 1000 , reinterpret_cast < Core : : Timing : : EventType * > ( userdata ) ,
core_timing. ScheduleEvent ( 1000 , reinterpret_cast < Core : : Timing : : EventType * > ( userdata ) ,
userdata ) ;
userdata ) ;
}
}
}
}
} // namespace ChainSchedulingTest
} // namespace ChainSchedulingTest
@ -203,36 +209,39 @@ TEST_CASE("CoreTiming[ChainScheduling]", "[core]") {
using namespace ChainSchedulingTest ;
using namespace ChainSchedulingTest ;
ScopeInit guard ;
ScopeInit guard ;
auto & core_timing = guard . core_timing ;
Core : : Timing : : EventType * cb_a = Core : : Timing : : RegisterEvent ( " callbackA " , CallbackTemplate < 0 > ) ;
Core : : Timing : : EventType * cb_a = core_timing . RegisterEvent ( " callbackA " , CallbackTemplate < 0 > ) ;
Core : : Timing : : EventType * cb_b = Core : : Timing : : RegisterEvent ( " callbackB " , CallbackTemplate < 1 > ) ;
Core : : Timing : : EventType * cb_b = core_timing . RegisterEvent ( " callbackB " , CallbackTemplate < 1 > ) ;
Core : : Timing : : EventType * cb_c = Core : : Timing : : RegisterEvent ( " callbackC " , CallbackTemplate < 2 > ) ;
Core : : Timing : : EventType * cb_c = core_timing . RegisterEvent ( " callbackC " , CallbackTemplate < 2 > ) ;
Core : : Timing : : EventType * cb_rs =
Core : : Timing : : EventType * cb_rs = core_timing . RegisterEvent (
Core : : Timing : : RegisterEvent ( " callbackReschedule " , RescheduleCallback ) ;
" callbackReschedule " , [ & core_timing ] ( u64 userdata , s64 cycles_late ) {
RescheduleCallback ( core_timing , userdata , cycles_late ) ;
} ) ;
// Enter slice 0
// Enter slice 0
Core: : Timing : : Advance ( ) ;
core_timing. Advance ( ) ;
Core: : Timing : : ScheduleEvent ( 800 , cb_a , CB_IDS [ 0 ] ) ;
core_timing. ScheduleEvent ( 800 , cb_a , CB_IDS [ 0 ] ) ;
Core: : Timing : : ScheduleEvent ( 1000 , cb_b , CB_IDS [ 1 ] ) ;
core_timing. ScheduleEvent ( 1000 , cb_b , CB_IDS [ 1 ] ) ;
Core: : Timing : : ScheduleEvent ( 2200 , cb_c , CB_IDS [ 2 ] ) ;
core_timing. ScheduleEvent ( 2200 , cb_c , CB_IDS [ 2 ] ) ;
Core: : Timing : : ScheduleEvent ( 1000 , cb_rs , reinterpret_cast < u64 > ( cb_rs ) ) ;
core_timing. ScheduleEvent ( 1000 , cb_rs , reinterpret_cast < u64 > ( cb_rs ) ) ;
REQUIRE ( 800 = = Core: : Timing : : GetDowncount ( ) ) ;
REQUIRE ( 800 = = core_timing. GetDowncount ( ) ) ;
reschedules = 3 ;
reschedules = 3 ;
AdvanceAndCheck ( 0 , 200 ) ; // cb_a
AdvanceAndCheck ( core_timing , 0 , 200 ) ; // cb_a
AdvanceAndCheck ( 1 , 1000 ) ; // cb_b, cb_rs
AdvanceAndCheck ( core_timing , 1 , 1000 ) ; // cb_b, cb_rs
REQUIRE ( 2 = = reschedules ) ;
REQUIRE ( 2 = = reschedules ) ;
Core: : Timing : : AddTicks ( Core : : Timing : : GetDowncount ( ) ) ;
core_timing. AddTicks ( core_timing . GetDowncount ( ) ) ;
Core: : Timing : : Advance ( ) ; // cb_rs
core_timing. Advance ( ) ; // cb_rs
REQUIRE ( 1 = = reschedules ) ;
REQUIRE ( 1 = = reschedules ) ;
REQUIRE ( 200 = = Core: : Timing : : GetDowncount ( ) ) ;
REQUIRE ( 200 = = core_timing. GetDowncount ( ) ) ;
AdvanceAndCheck ( 2 , 800 ) ; // cb_c
AdvanceAndCheck ( core_timing , 2 , 800 ) ; // cb_c
Core: : Timing : : AddTicks ( Core : : Timing : : GetDowncount ( ) ) ;
core_timing. AddTicks ( core_timing . GetDowncount ( ) ) ;
Core: : Timing : : Advance ( ) ; // cb_rs
core_timing. Advance ( ) ; // cb_rs
REQUIRE ( 0 = = reschedules ) ;
REQUIRE ( 0 = = reschedules ) ;
REQUIRE ( MAX_SLICE_LENGTH = = Core: : Timing : : GetDowncount ( ) ) ;
REQUIRE ( MAX_SLICE_LENGTH = = core_timing. GetDowncount ( ) ) ;
}
}