From 34ffe986053368c81d193541186ed9e6e02db63e Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Tue, 17 Jan 2017 16:29:55 -0800 Subject: [PATCH] TIMER: Fixed generic coscheduling and extended details in debug information --- sim_timer.c | 118 ++++++++++++++++++++++++++++++++-------------------- sim_timer.h | 1 + sim_tmxr.c | 9 ++-- 3 files changed, 77 insertions(+), 51 deletions(-) diff --git a/sim_timer.c b/sim_timer.c index 13de12ee..df6f4dde 100644 --- a/sim_timer.c +++ b/sim_timer.c @@ -723,6 +723,7 @@ else static int32 rtc_ticks[SIM_NTIMERS+1] = { 0 }; /* ticks */ static uint32 rtc_hz[SIM_NTIMERS+1] = { 0 }; /* tick rate */ +static uint32 rtc_last_hz[SIM_NTIMERS+1] = { 0 }; /* prior tick rate */ static uint32 rtc_rtime[SIM_NTIMERS+1] = { 0 }; /* real time */ static uint32 rtc_vtime[SIM_NTIMERS+1] = { 0 }; /* virtual time */ static double rtc_gtime[SIM_NTIMERS+1] = { 0 }; /* instruction time */ @@ -834,6 +835,7 @@ rtc_rtime[tmr] = sim_os_msec (); rtc_vtime[tmr] = rtc_rtime[tmr]; rtc_nxintv[tmr] = 1000; rtc_ticks[tmr] = 0; +rtc_last_hz[tmr] = rtc_hz[tmr]; rtc_hz[tmr] = 0; rtc_based[tmr] = time; rtc_currd[tmr] = time; @@ -873,6 +875,7 @@ else { if (rtc_hz[tmr] != ticksper) { /* changing tick rate? */ if (rtc_hz[tmr] == 0) rtc_clock_tick_start_time[tmr] = sim_timenow_double (); + rtc_last_hz[tmr] = rtc_hz[tmr]; rtc_hz[tmr] = ticksper; _rtcn_configure_calibrated_clock (tmr); if (ticksper != 0) { @@ -2090,30 +2093,37 @@ for (tmr=0; tmrusecs_remaining = usecs_remaining; } + rtc_hz[sim_calb_tmr] = 0; /* back to 0 */ + if (sim_clock_unit[sim_calb_tmr]) + sim_cancel (sim_clock_unit[sim_calb_tmr]); + sim_cancel (&sim_timer_units[sim_calb_tmr]); } /* Start the internal timer */ sim_calb_tmr = SIM_NTIMERS; sim_debug (DBG_CAL, &sim_timer_dev, "_rtcn_configure_calibrated_clock(newtmr=%d) - Starting Internal Calibrated Timer at %dHz\n", newtmr, sim_int_clk_tps); SIM_INTERNAL_UNIT.action = &sim_timer_clock_tick_svc; SIM_INTERNAL_UNIT.flags = UNIT_IDLE; - sim_register_internal_device (&sim_int_timer_dev); /* Register Internal timer device */ + sim_register_internal_device (&sim_int_timer_dev); /* Register Internal timer device */ sim_rtcn_init_unit (&SIM_INTERNAL_UNIT, (CLK_INIT*CLK_TPS)/sim_int_clk_tps, SIM_INTERNAL_CLK); - SIM_INTERNAL_UNIT.action (&SIM_INTERNAL_UNIT); /* Force tick to activate timer */ + SIM_INTERNAL_UNIT.action (&SIM_INTERNAL_UNIT); /* Force tick to activate timer */ } return; } @@ -2124,21 +2134,28 @@ if (sim_calb_tmr == SIM_NTIMERS) { /* was old the internal timer? */ sim_debug (DBG_CAL, &sim_timer_dev, "_rtcn_configure_calibrated_clock(newtmr=%d) - Stopping Internal Calibrated Timer, New Timer = %d (%dHz)\n", newtmr, tmr, rtc_hz[tmr]); rtc_initd[SIM_NTIMERS] = 0; rtc_hz[SIM_NTIMERS] = 0; + sim_register_clock_unit_tmr (NULL, SIM_INTERNAL_CLK); sim_cancel (&SIM_INTERNAL_UNIT); sim_cancel (&sim_timer_units[SIM_NTIMERS]); - sim_register_clock_unit_tmr (NULL, SIM_INTERNAL_CLK); } else { if ((sim_calb_tmr != -1) && (rtc_hz[sim_calb_tmr] == 0)) { /* Migrate any coscheduled devices to the standard queue */ - /* they will fire and subsequently requeue themselves */ + /* with appropriate usecs_remaining reflecting their currently */ + /* scheduled firing time. sim_process_event() will coschedule */ + /* appropriately. */ + /* temporarily restore prior hz to get correct remaining time */ + rtc_hz[sim_calb_tmr] = rtc_last_hz[sim_calb_tmr]; while (sim_clock_cosched_queue[tmr] != QUEUE_LIST_END) { UNIT *uptr = sim_clock_cosched_queue[tmr]; + double usecs_remaining = sim_timer_activate_time_usecs (uptr) - 1; _sim_coschedule_cancel (uptr); _sim_activate (uptr, 1); + uptr->usecs_remaining = usecs_remaining; } + rtc_hz[sim_calb_tmr] = 0; /* back to 0 */ } sim_debug (DBG_CAL, &sim_timer_dev, "_rtcn_configure_calibrated_clock(newtmr=%d) - Changing Calibrated Timer from %d (%dHz) to %d (%dHz)\n", newtmr, sim_calb_tmr, rtc_hz[sim_calb_tmr], tmr, rtc_hz[tmr]); sim_calb_tmr = tmr; @@ -2205,13 +2222,16 @@ for (tmr=0; tmr<=SIM_NTIMERS; tmr++) { accum = 0; while (sim_clock_cosched_queue[tmr] != QUEUE_LIST_END) { UNIT *cptr = sim_clock_cosched_queue[tmr]; + double usecs_remaining = cptr->usecs_remaining; + cptr->usecs_remaining = 0; sim_clock_cosched_queue[tmr] = cptr->next; cptr->next = NULL; cptr->cancel = NULL; accum += cptr->time; sim_debug (DBG_QUE, &sim_timer_dev, "sim_stop_timer_services() - tmr=%d scheduling %s after %d\n", tmr, sim_uname (cptr), clock_time + accum*rtc_currd[tmr]); _sim_activate (cptr, clock_time + accum*rtc_currd[tmr]); + cptr->usecs_remaining = usecs_remaining; } sim_cosched_interval[tmr] = 0; } @@ -2413,9 +2433,11 @@ if (NULL == uptr) { /* deregistering? */ /* they will fire and subsequently requeue themselves */ while (sim_clock_cosched_queue[tmr] != QUEUE_LIST_END) { UNIT *uptr = sim_clock_cosched_queue[tmr]; + double usecs_remaining = sim_timer_activate_time_usecs (uptr) - 1; _sim_coschedule_cancel (uptr); _sim_activate (uptr, 1); + uptr->usecs_remaining = usecs_remaining; } if (sim_clock_unit[tmr]) { sim_cancel (sim_clock_unit[tmr]); @@ -2435,18 +2457,11 @@ return SCPE_OK; } /* Default timer is 0, otherwise use a calibrated one if it exists */ -static int32 _default_tmr () +int32 sim_rtcn_calibrated_tmr (void) { return ((rtc_currd[0] && rtc_hz[0]) ? 0 : ((sim_calb_tmr != -1) ? sim_calb_tmr : 0)); } -static int32 _tick_size () -{ -int32 tmr = _default_tmr (); - -return ((rtc_currd[tmr] && rtc_hz[tmr]) ? rtc_currd[tmr] : 10000); -} - int32 sim_rtcn_tick_size (int32 tmr) { return (rtc_currd[tmr]) ? rtc_currd[tmr] : 10000; @@ -2459,19 +2474,18 @@ return sim_register_clock_unit_tmr (uptr, 0); t_stat sim_clock_coschedule (UNIT *uptr, int32 interval) { -int32 ticks = (interval + (_tick_size ()/2))/_tick_size ();/* Convert to ticks */ +int32 tmr = sim_rtcn_calibrated_tmr (); +int32 ticks = (interval + (sim_rtcn_tick_size (tmr)/2))/sim_rtcn_tick_size (tmr);/* Convert to ticks */ sim_debug (DBG_QUE, &sim_timer_dev, "sim_clock_coschedule(%s, interval=%d, ticks=%d)\n", sim_uname(uptr), interval, ticks); -return sim_clock_coschedule_tmr (uptr, _default_tmr (), ticks); +return sim_clock_coschedule_tmr (uptr, tmr, ticks); } t_stat sim_clock_coschedule_abs (UNIT *uptr, int32 interval) { -int32 ticks = (interval + (_tick_size ()/2))/_tick_size ();/* Convert to ticks */ - -sim_debug (DBG_QUE, &sim_timer_dev, "sim_clock_coschedule_abs(%s, interval=%d, ticks=%d)\n", sim_uname(uptr), interval, ticks); +sim_debug (DBG_QUE, &sim_timer_dev, "sim_clock_coschedule_abs(%s, interval=%d)\n", sim_uname(uptr), interval); sim_cancel (uptr); -return sim_clock_coschedule_tmr (uptr, _default_tmr (), ticks); +return sim_clock_coschedule (uptr, interval); } t_stat sim_clock_coschedule_tmr (UNIT *uptr, int32 tmr, int32 ticks) @@ -2488,15 +2502,15 @@ else { if ((tmr < 0) || (tmr > SIM_NTIMERS)) return sim_activate (uptr, MAX(1, ticks) * 10000); } -if (NULL == sim_clock_unit[tmr]) { - sim_debug (DBG_TIM, &sim_timer_dev, "sim_clock_coschedule_tmr(%s, tmr=%d, ticks=%d) - no clock activating after %d instructions\n", sim_uname (uptr), tmr, ticks, ticks * (rtc_currd[tmr] ? rtc_currd[tmr] : _tick_size ())); - return sim_activate (uptr, ticks * (rtc_currd[tmr] ? rtc_currd[tmr] : _tick_size ())); +if ((NULL == sim_clock_unit[tmr]) || (rtc_hz[tmr] == 0)) { + sim_debug (DBG_TIM, &sim_timer_dev, "sim_clock_coschedule_tmr(%s, tmr=%d, ticks=%d) - no clock activating after %d instructions\n", sim_uname (uptr), tmr, ticks, ticks * (rtc_currd[tmr] ? rtc_currd[tmr] : rtc_currd[sim_rtcn_calibrated_tmr ()])); + return sim_activate (uptr, ticks * (rtc_currd[tmr] ? rtc_currd[tmr] : rtc_currd[sim_rtcn_calibrated_tmr ()])); } else { UNIT *cptr, *prvptr; int32 accum; - sim_debug (DBG_QUE, &sim_timer_dev, "sim_clock_coschedule_tmr(%s, tmr=%d, ticks=%d) - queueing for clock co-schedule\n", sim_uname (uptr), tmr, ticks); + sim_debug (DBG_QUE, &sim_timer_dev, "sim_clock_coschedule_tmr(%s, tmr=%d, ticks=%d, hz=%d) - queueing for clock co-schedule\n", sim_uname (uptr), tmr, ticks, rtc_hz[tmr]); prvptr = NULL; accum = 0; for (cptr = sim_clock_cosched_queue[tmr]; cptr != QUEUE_LIST_END; cptr = cptr->next) { @@ -2725,6 +2739,7 @@ double sim_timer_activate_time_usecs (UNIT *uptr) { UNIT *cptr; int32 tmr; +double result = -1.0; /* If this is a clock unit, we need to return the related clock assist unit instead */ for (tmr=0; tmr<=SIM_NTIMERS; tmr++) { @@ -2736,30 +2751,35 @@ for (tmr=0; tmr<=SIM_NTIMERS; tmr++) { #if defined(SIM_ASYNCH_CLOCKS) if (uptr->a_is_active == &_sim_wallclock_is_active) { - double d_result; - pthread_mutex_lock (&sim_timer_lock); if (uptr == sim_wallclock_entry) { - d_result = uptr->a_due_gtime - sim_gtime (); - if (d_result < 0.0) - d_result = 0.0; + result = uptr->a_due_gtime - sim_gtime (); + if (result < 0.0) + result = 0.0; pthread_mutex_unlock (&sim_timer_lock); - return uptr->usecs_remaining + (1000000.0 * (d_result / sim_timer_inst_per_sec ())) + 1; + result = uptr->usecs_remaining + (1000000.0 * (result / sim_timer_inst_per_sec ())) + 1; + sim_debug (DBG_QUE, &sim_timer_dev, "sim_timer_activate_time_usecs(%s) wallclock_entry - %.0f usecs, inst_per_sec=%.0f\n", sim_uname (uptr), result, sim_timer_inst_per_sec ()); + return result; } for (cptr = sim_wallclock_queue; cptr != QUEUE_LIST_END; cptr = cptr->a_next) if (uptr == cptr) { - d_result = uptr->a_due_gtime - sim_gtime (); - if (d_result < 0.0) - d_result = 0.0; + result = uptr->a_due_gtime - sim_gtime (); + if (result < 0.0) + result = 0.0; pthread_mutex_unlock (&sim_timer_lock); - return uptr->usecs_remaining + (1000000.0 * (d_result / sim_timer_inst_per_sec ())) + 1; + result = uptr->usecs_remaining + (1000000.0 * (result / sim_timer_inst_per_sec ())) + 1; + sim_debug (DBG_QUE, &sim_timer_dev, "sim_timer_activate_time_usecs(%s) wallclock - %.0f usecs, inst_per_sec=%.0f\n", sim_uname (uptr), result, sim_timer_inst_per_sec ()); + return result; } pthread_mutex_unlock (&sim_timer_lock); } -if (uptr->a_next) - return uptr->usecs_remaining + (1000000.0 * (uptr->a_event_time / sim_timer_inst_per_sec ())) + 1; +if (uptr->a_next) { + result = uptr->usecs_remaining + (1000000.0 * (uptr->a_event_time / sim_timer_inst_per_sec ())) + 1; + sim_debug (DBG_QUE, &sim_timer_dev, "sim_timer_activate_time_usecs(%s) asynch - %.0f usecs, inst_per_sec=%.0f\n", sim_uname (uptr), result, sim_timer_inst_per_sec ()); + return result; + } #endif /* defined(SIM_ASYNCH_CLOCKS) */ if (uptr->cancel == &_sim_coschedule_cancel) { @@ -2773,15 +2793,21 @@ if (uptr->cancel == &_sim_coschedule_cancel) { if (cptr == uptr) { if (accum > 0) --accum; - return uptr->usecs_remaining + (1000000.0 * ((rtc_currd[tmr] * accum) + sim_activate_time (&sim_timer_units[tmr])) / sim_timer_inst_per_sec ()); + result = uptr->usecs_remaining + (1000000.0 * ((rtc_currd[tmr] * accum) + sim_activate_time (&sim_timer_units[tmr])) / sim_timer_inst_per_sec ()); + sim_debug (DBG_QUE, &sim_timer_dev, "sim_timer_activate_time_usecs(%s) coscheduled - %.0f usecs, inst_per_sec=%.0f, tmr=%d, hz=%d\n", sim_uname (uptr), result, sim_timer_inst_per_sec (), sim_calb_tmr, rtc_hz[sim_calb_tmr]); + return result; } } } } -for (tmr=0; tmr<=SIM_NTIMERS; tmr++) - if (sim_clock_unit[tmr] == uptr) - return sim_clock_unit[tmr]->usecs_remaining + (1000000.0 * sim_activate_time (&sim_timer_units[tmr])) / sim_timer_inst_per_sec (); -return -1.0; /* Not found. */ +for (tmr=0; tmr<=SIM_NTIMERS; tmr++) { + if (sim_clock_unit[tmr] == uptr) { + result = sim_clock_unit[tmr]->usecs_remaining + (1000000.0 * sim_activate_time (&sim_timer_units[tmr])) / sim_timer_inst_per_sec (); + sim_debug (DBG_QUE, &sim_timer_dev, "sim_timer_activate_time_usecs(%s) clock - %.0f usecs, inst_per_sec=%.0f\n", sim_uname (uptr), result, sim_timer_inst_per_sec ()); + return result; + } + } +return result; /* Not found. */ } /* read only memory delayed support diff --git a/sim_timer.h b/sim_timer.h index aeb92cff..4a72d686 100644 --- a/sim_timer.h +++ b/sim_timer.h @@ -146,6 +146,7 @@ t_stat sim_clock_coschedule_tmr (UNIT *uptr, int32 tmr, int32 ticks); t_stat sim_clock_coschedule_tmr_abs (UNIT *uptr, int32 tmr, int32 ticks); double sim_timer_inst_per_sec (void); int32 sim_rtcn_tick_size (int32 tmr); +int32 sim_rtcn_calibrated_tmr (void); t_bool sim_timer_idle_capable (uint32 *host_ms_sleep_1, uint32 *host_tick_ms); #define PRIORITY_BELOW_NORMAL -1 #define PRIORITY_NORMAL 0 diff --git a/sim_tmxr.c b/sim_tmxr.c index 79ae2b53..b212e11b 100644 --- a/sim_tmxr.c +++ b/sim_tmxr.c @@ -3895,17 +3895,16 @@ return _sim_activate_after_abs (uptr, (double)usecs_walltime); t_stat tmxr_clock_coschedule (UNIT *uptr, int32 interval) { -int32 ticks = (interval + (sim_rtcn_tick_size (0)/2))/sim_rtcn_tick_size (0);/* Convert to ticks */ +int32 tmr = sim_rtcn_calibrated_tmr (); +int32 ticks = (interval + (sim_rtcn_tick_size (tmr)/2))/sim_rtcn_tick_size (tmr);/* Convert to ticks */ -return tmxr_clock_coschedule_tmr (uptr, 0, ticks); +return tmxr_clock_coschedule_tmr (uptr, tmr, ticks); } t_stat tmxr_clock_coschedule_abs (UNIT *uptr, int32 interval) { -int32 ticks = (interval + (sim_rtcn_tick_size (0)/2))/sim_rtcn_tick_size (0);/* Convert to ticks */ - sim_cancel (uptr); -return tmxr_clock_coschedule_tmr (uptr, 0, ticks); +return tmxr_clock_coschedule (uptr, interval); } #define MIN(a,b) (((a) < (b)) ? (a) : (b))