From a008b0a9726dc1400e85a3714af7bfc8583c444a Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Wed, 14 Sep 2016 14:12:24 -0700 Subject: [PATCH] SCP: Fix throttling to provide reasonable operation of calibrated clocks - Generate reasonable messages when presented with erroneous throttle input. - Add throttling recalibration logic if only if target rate drift exceeds 5% --- sim_timer.c | 86 +++++++++++++++++++++++++++++++++++++---------------- sim_timer.h | 21 ++++++------- 2 files changed, 71 insertions(+), 36 deletions(-) diff --git a/sim_timer.c b/sim_timer.c index 2636c4c1..85116347 100644 --- a/sim_timer.c +++ b/sim_timer.c @@ -100,6 +100,8 @@ static uint32 sim_throt_ms_stop = 0; static uint32 sim_throt_type = 0; static uint32 sim_throt_val = 0; static uint32 sim_throt_state = 0; +static double sim_throt_cps; +static double sim_throt_inst_start; static uint32 sim_throt_sleep_time = 0; static int32 sim_throt_wait = 0; static UNIT *sim_clock_unit[SIM_NTIMERS] = {NULL}; @@ -706,6 +708,13 @@ if (rtc_ticks[tmr] < ticksper) { /* 1 sec yet? */ } rtc_ticks[tmr] = 0; /* reset ticks */ rtc_elapsed[tmr] = rtc_elapsed[tmr] + 1; /* count sec */ +if (sim_throt_type != SIM_THROT_NONE) { + rtc_gtime[tmr] = sim_gtime(); /* save instruction time */ + rtc_currd[tmr] = (int32)(sim_throt_cps / ticksper); /* use throttle calibration */ + ++rtc_calibrations[tmr]; /* count calibrations */ + sim_debug (DBG_CAL, &sim_timer_dev, "using throttle calibrated value - result: %d\n", rtc_currd[tmr]); + return rtc_currd[tmr]; + } if (!rtc_avail) { /* no timer? */ return rtc_currd[tmr]; } @@ -874,7 +883,7 @@ for (tmr=clocks=0; tmr 0) && (val < 100)) sim_throt_type = SIM_THROT_PCT; - else if ((c == '/') && (val2 != 0)) { + else if ((c == '/') && (val2 != 0)) sim_throt_type = SIM_THROT_SPC; - } - else return SCPE_ARG; + else return sim_messagef (SCPE_ARG, "Invalid throttle specification: %s\n", cptr); if (sim_idle_enab) { sim_printf ("Idling disabled\n"); sim_clr_idle (NULL, 0, NULL, NULL); @@ -1180,8 +1190,14 @@ else { if (val2 >= sim_idle_rate_ms) sim_throt_sleep_time = (uint32) val2; else { - sim_throt_sleep_time = (uint32) (val2 * sim_idle_rate_ms); - sim_throt_val = (uint32) (val * sim_idle_rate_ms); + if ((sim_idle_rate_ms % val2) == 0) { + sim_throt_sleep_time = sim_idle_rate_ms; + sim_throt_val = (uint32) (val * (sim_idle_rate_ms / val2)); + } + else { + sim_throt_sleep_time = sim_idle_rate_ms; + sim_throt_val = (uint32) (val * (1 + (sim_idle_rate_ms / val2))); + } } } } @@ -1197,14 +1213,20 @@ else { case SIM_THROT_MCYC: fprintf (st, "Throttle = %d megacycles\n", sim_throt_val); + if (sim_throt_wait) + fprintf (st, "Throttling achieved by sleeping for %d ms every %d cycles\n", sim_throt_sleep_time, sim_throt_wait); break; case SIM_THROT_KCYC: fprintf (st, "Throttle = %d kilocycles\n", sim_throt_val); + if (sim_throt_wait) + fprintf (st, "Throttling achieved by sleeping for %d ms every %d cycles\n", sim_throt_sleep_time, sim_throt_wait); break; case SIM_THROT_PCT: fprintf (st, "Throttle = %d%%\n", sim_throt_val); + if (sim_throt_wait) + fprintf (st, "Throttling achieved by sleeping for %d ms every %d cycles\n", sim_throt_sleep_time, sim_throt_wait); break; case SIM_THROT_SPC: @@ -1215,14 +1237,7 @@ else { fprintf (st, "Throttling disabled\n"); break; } - - if (sim_switches & SWMASK ('D')) { - if (sim_throt_type != 0) - fprintf (st, "Throttle interval = %d cycles\n", sim_throt_wait); - } } -if (sim_switches & SWMASK ('D')) - fprintf (st, "minimum sleep resolution = %d ms\n", sim_os_sleep_min_ms); return SCPE_OK; } @@ -1260,6 +1275,7 @@ switch (sim_throt_state) { case 0: /* take initial reading */ sim_throt_ms_start = sim_os_msec (); + sim_throt_inst_start = sim_gtime(); sim_throt_wait = SIM_THROT_WST; sim_throt_state = 1; /* next state */ break; /* reschedule */ @@ -1274,6 +1290,7 @@ switch (sim_throt_state) { } sim_throt_wait = sim_throt_wait * SIM_THROT_WMUL; sim_throt_ms_start = sim_throt_ms_stop; + sim_throt_inst_start = sim_gtime(); } else { /* long enough */ a_cps = ((double) sim_throt_wait) * 1000.0 / (double) delta_ms; @@ -1294,21 +1311,38 @@ switch (sim_throt_state) { return SCPE_OK; } sim_throt_ms_start = sim_throt_ms_stop; + sim_throt_inst_start = sim_gtime(); sim_throt_state = 2; sim_debug (DBG_THR, &sim_timer_dev, "sim_throt_svc() Throttle values a_cps = %f, d_cps = %f, wait = %d\n", a_cps, d_cps, sim_throt_wait); + sim_throt_cps = (int32)d_cps; /* save the desired rate */ } break; case 2: /* throttling */ SIM_IDLE_MS_SLEEP (sim_throt_sleep_time); delta_ms = sim_os_msec () - sim_throt_ms_start; - if ((sim_throt_type != SIM_THROT_SPC) && /* when dynamic throttling */ - (delta_ms >= 10000)) { /* recompute every 10 sec */ - sim_throt_ms_start = sim_os_msec (); - sim_throt_wait = SIM_THROT_WST; - sim_throt_state = 1; /* next state */ + if (sim_throt_type != SIM_THROT_SPC) { /* when not dynamic throttling */ + if (delta_ms >= 10000) { /* recompute every 10 sec */ + double delta_insts = sim_gtime() - sim_throt_inst_start; + a_cps = (delta_insts * 1000.0) / (double) delta_ms; + if (sim_throt_type == SIM_THROT_MCYC) /* calc desired cps */ + d_cps = (double) sim_throt_val * 1000000.0; + else if (sim_throt_type == SIM_THROT_KCYC) + d_cps = (double) sim_throt_val * 1000.0; + else d_cps = (a_cps * ((double) sim_throt_val)) / 100.0; + if (fabs(100.0 * (d_cps - a_cps) / a_cps) > (double)SIM_THROT_DRIFT_PCT) { + sim_throt_wait = sim_throt_val; + sim_throt_state = 1; /* next state to recalibrate */ + sim_debug (DBG_THR, &sim_timer_dev, "sim_throt_svc() Recalibrating throttle based on values a_cps = %f, d_cps = %f\n", + a_cps, d_cps); + } + sim_throt_ms_start = sim_os_msec (); + sim_throt_inst_start = sim_gtime(); + } } + else /* record instruction rate */ + sim_throt_cps = (int32)((1000.0 * sim_throt_val) / (double)delta_ms); break; } diff --git a/sim_timer.h b/sim_timer.h index 9b4548de..8b154b29 100644 --- a/sim_timer.h +++ b/sim_timer.h @@ -85,16 +85,17 @@ int clock_gettime(int clock_id, struct timespec *tp); #define SIM_IDLE_STDFLT 20 /* dft sec for stability */ #define SIM_IDLE_STMAX 600 /* max sec for stability */ -#define SIM_THROT_WINIT 1000 /* cycles to skip */ -#define SIM_THROT_WST 10000 /* initial wait */ -#define SIM_THROT_WMUL 4 /* multiplier */ -#define SIM_THROT_WMIN 100 /* min wait */ -#define SIM_THROT_MSMIN 10 /* min for measurement */ -#define SIM_THROT_NONE 0 /* throttle parameters */ -#define SIM_THROT_MCYC 1 /* MegaCycles Per Sec */ -#define SIM_THROT_KCYC 2 /* KiloCycles Per Sec */ -#define SIM_THROT_PCT 3 /* Max Percent of host CPU */ -#define SIM_THROT_SPC 4 /* Specific periodic Delay */ +#define SIM_THROT_WINIT 1000 /* cycles to skip */ +#define SIM_THROT_WST 10000 /* initial wait */ +#define SIM_THROT_WMUL 4 /* multiplier */ +#define SIM_THROT_WMIN 100 /* min wait */ +#define SIM_THROT_DRIFT_PCT 5 /* drift percentage for recalibrate */ +#define SIM_THROT_MSMIN 10 /* min for measurement */ +#define SIM_THROT_NONE 0 /* throttle parameters */ +#define SIM_THROT_MCYC 1 /* MegaCycles Per Sec */ +#define SIM_THROT_KCYC 2 /* KiloCycles Per Sec */ +#define SIM_THROT_PCT 3 /* Max Percent of host CPU */ +#define SIM_THROT_SPC 4 /* Specific periodic Delay */ #define TIMER_DBG_IDLE 0x001 /* Debug Flag for Idle Debugging */ #define TIMER_DBG_QUEUE 0x002 /* Debug Flag for Asynch Queue Debugging */