From c38eacd0c8bef5c89fc98f5a787e07da101268e1 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Tue, 25 Oct 2011 03:52:24 -0700 Subject: [PATCH] Fixed throttling in several ways: - Sleep for the observed clock tick size while throttling - Recompute the throttling wait once every 10 seconds to account for varying instruction mixes during different phases of a simulator execution or to accommodate the presence of other load on the host system. - Each of the pre-existing throttling modes (Kcps, Mcps, and %) all compute the appropriate throttling interval dynamically. These dynamic computations assume that 100% of the host CPU is dedicated to the current simulator during this computation. This assumption may not always be true and under certain conditions may never provide a way to correctly determine the appropriate throttling wait. An additional throttling mode has been added which allows the simulator operator to explicitly state the desired throttling wait parameters. These are specified by: SET THROT insts/delay where 'insts' is the number of instructions to execute before sleeping for 'delay' milliseconds. --- scp.c | 3 +- sim_timer.c | 86 +++++++++++++++++++++++++++++++++++++++++++---------- sim_timer.h | 7 +++-- 3 files changed, 77 insertions(+), 19 deletions(-) diff --git a/scp.c b/scp.c index ed2e4ab4..9651f41d 100644 --- a/scp.c +++ b/scp.c @@ -616,7 +616,8 @@ static CTAB cmd_table[] = { "set console NODEBUG disable console debugging\n" "set break set breakpoints\n" "set nobreak clear breakpoints\n" - "set throttle x{M|K|%%} set simulation rate\n" + "set throttle {x{M|K|%}}|{x/t}\n" + " set simulation rate\n" "set nothrottle set simulation rate to maximum\n" "set asynch enable asynchronous I/O\n" "set noasynch disable asynchronous I/O\n" diff --git a/sim_timer.c b/sim_timer.c index 8abdbb3a..5b05d00e 100644 --- a/sim_timer.c +++ b/sim_timer.c @@ -23,6 +23,28 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 21-Oct-11 MP Fixed throttling in several ways: + - Sleep for the observed clock tick size while throttling + - Recompute the throttling wait once every 10 seconds + to account for varying instruction mixes during + different phases of a simulator execution or to + accommodate the presence of other load on the host + system. + - Each of the pre-existing throttling modes (Kcps, + Mcps, and %) all compute the appropriate throttling + interval dynamically. These dynamic computations + assume that 100% of the host CPU is dedicated to + the current simulator during this computation. + This assumption may not always be true and under + certain conditions may never provide a way to + correctly determine the appropriate throttling + wait. An additional throttling mode has been added + which allows the simulator operator to explicitly + state the desired throttling wait parameters. + These are specified by: + SET THROT insts/delay + where 'insts' is the number of instructions to + execute before sleeping for 'delay' milliseconds. 22-Apr-11 MP Fixed Asynch I/O support to reasonably account cycles when an idle wait is terminated by an external event 05-Jan-11 MP Added Asynch I/O support @@ -67,6 +89,7 @@ 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 uint32 sim_throt_sleep_time = 0; static int32 sim_throt_wait = 0; extern int32 sim_interval, sim_switches; extern FILE *sim_log; @@ -641,8 +664,11 @@ return SCPE_OK; t_stat sim_show_idle (FILE *st, UNIT *uptr, int32 val, void *desc) { -if (sim_idle_enab) - fprintf (st, "idle enabled, stability wait = %ds, minimum sleep resolution = %dms", sim_idle_stable, sim_idle_rate_ms); +if (sim_idle_enab) { + fprintf (st, "idle enabled"); + if (sim_switches & SWMASK ('D')) + fprintf (st, ", stability wait = %ds, minimum sleep resolution = %dms", sim_idle_stable, sim_idle_rate_ms); + } else fputs ("idle disabled", st); return SCPE_OK; } @@ -652,7 +678,7 @@ return SCPE_OK; t_stat sim_set_throt (int32 arg, char *cptr) { char *tptr, c; -t_value val; +t_value val, val2; if (arg == 0) { if ((cptr != 0) && (*cptr != 0)) @@ -666,8 +692,11 @@ else { val = strtotv (cptr, &tptr, 10); if (cptr == tptr) return SCPE_ARG; + sim_throt_sleep_time = sim_idle_rate_ms; c = toupper (*tptr++); - if (*tptr != 0) + if (c == '/') + val2 = strtotv (tptr, &tptr, 10); + if ((*tptr != 0) || (val == 0)) return SCPE_ARG; if (c == 'M') sim_throt_type = SIM_THROT_MCYC; @@ -675,6 +704,9 @@ else { sim_throt_type = SIM_THROT_KCYC; else if ((c == '%') && (val > 0) && (val < 100)) sim_throt_type = SIM_THROT_PCT; + else if ((c == '/') && (val2 != 0)) { + sim_throt_type = SIM_THROT_SPC; + } else return SCPE_ARG; if (sim_idle_enab) { printf ("Idling disabled\n"); @@ -683,6 +715,14 @@ else { sim_clr_idle (NULL, 0, NULL, NULL); } sim_throt_val = (uint32) val; + if (sim_throt_type == SIM_THROT_SPC) { + 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); + } + } } return SCPE_OK; } @@ -706,13 +746,17 @@ else { fprintf (st, "Throttle = %d%%\n", sim_throt_val); break; + case SIM_THROT_SPC: + fprintf (st, "Throttle = %d ms every %d cycles\n", sim_throt_sleep_time, sim_throt_val); + break; + default: fprintf (st, "Throttling disabled\n"); break; } if (sim_switches & SWMASK ('D')) { - fprintf (st, "Wait rate = %d ms\n", sim_idle_rate_ms); + fprintf (st, "minimum sleep resolution = %d ms\n", sim_idle_rate_ms); if (sim_throt_type != 0) fprintf (st, "Throttle interval = %d cycles\n", sim_throt_wait); } @@ -725,7 +769,6 @@ void sim_throt_sched (void) sim_throt_state = 0; if (sim_throt_type) sim_activate (&sim_throt_unit, SIM_THROT_WINIT); -return; } void sim_throt_cancel (void) @@ -735,11 +778,12 @@ sim_cancel (&sim_throt_unit); /* Throttle service - Throttle service has three distinct states + Throttle service has three distinct states used while dynamically + determining a throttling interval: - 0 take initial measurement - 1 take final measurement, calculate wait values - 2 periodic waits to slow down the CPU + 0 take initial measurement + 1 take final measurement, calculate wait values + 2 periodic waits to slow down the CPU */ t_stat sim_throt_svc (UNIT *uptr) @@ -747,12 +791,16 @@ t_stat sim_throt_svc (UNIT *uptr) uint32 delta_ms; double a_cps, d_cps; +if (sim_throt_type == SIM_THROT_SPC) { /* Non dynamic? */ + sim_throt_state = 2; /* force state */ + sim_throt_wait = sim_throt_val; + } switch (sim_throt_state) { case 0: /* take initial reading */ sim_throt_ms_start = sim_os_msec (); sim_throt_wait = SIM_THROT_WST; - sim_throt_state++; /* next state */ + sim_throt_state = 1; /* next state */ break; /* reschedule */ case 1: /* take final reading */ @@ -774,24 +822,32 @@ switch (sim_throt_state) { d_cps = (double) sim_throt_val * 1000.0; else d_cps = (a_cps * ((double) sim_throt_val)) / 100.0; if (d_cps >= a_cps) { - sim_throt_state = 0; + sim_throt_sched (); /* start over */ return SCPE_OK; } sim_throt_wait = (int32) /* time between waits */ ((a_cps * d_cps * ((double) sim_idle_rate_ms)) / (1000.0 * (a_cps - d_cps))); if (sim_throt_wait < SIM_THROT_WMIN) { /* not long enough? */ - sim_throt_state = 0; + sim_throt_sched (); /* start over */ return SCPE_OK; } - sim_throt_state++; + sim_throt_ms_start = sim_throt_ms_stop; + sim_throt_state = 2; // fprintf (stderr, "Throttle values a_cps = %f, d_cps = %f, wait = %d\n", // a_cps, d_cps, sim_throt_wait); } break; case 2: /* throttling */ - sim_os_ms_sleep (1); + sim_os_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 */ + } break; } diff --git a/sim_timer.h b/sim_timer.h index 73174432..1bf8aa42 100644 --- a/sim_timer.h +++ b/sim_timer.h @@ -55,9 +55,10 @@ int clock_gettime(int clock_id, struct timespec *tp); #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 -#define SIM_THROT_KCYC 2 -#define SIM_THROT_PCT 3 +#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 */ t_bool sim_timer_init (void); void sim_timespec_diff (struct timespec *diff, struct timespec *min, struct timespec *sub);