Index: sys/sys/callout.h =================================================================== --- sys/sys/callout.h (revision 242516) +++ sys/sys/callout.h (working copy) @@ -51,29 +51,23 @@ #define CALLOUT_DIRECT 0x0100 /* allow exec from hw int context */ #define C_DIRECT_EXEC 0x0001 /* direct execution of callout */ -#define C_P1S 0x0002 /* fields related to precision */ -#define C_P500MS 0x0006 -#define C_P250MS 0x000a -#define C_P125MS 0x000e -#define C_P64MS 0x0012 -#define C_P32MS 0x0016 -#define C_P16MS 0x001a -#define C_P8MS 0x001e -#define C_P4MS 0x0022 -#define C_P2MS 0x0026 -#define C_P1MS 0x002a -#define C_P500US 0x002e -#define C_P250US 0x0032 -#define C_P125US 0x0036 -#define C_P64US 0x003a -#define C_P32US 0x003e -#define C_P16US 0x0042 -#define C_P8US 0x0046 -#define C_P4US 0x004a -#define C_P2US 0x004e -#define PRECISION_BITS 7 -#define PRECISION_RANGE ((1 << PRECISION_BITS) - 1) +#define C_PRECISION 0x0002 /* precision specified */ +#define C_PREC(x) (((x) << 2) | C_PRECISION) +/* + * Common values used for precision. In some cases, e.g. 1ms, the precision + * value is approximated to the nearest power-of-two, as long as we deal with + * that timescale. + */ +#define C_P1S (C_PREC(0)) +#define C_P500MS (C_PREC(1)) +#define C_P1MS (C_PREC(10)) + +u_int precision_flags, pthreshold; + +#define TIMESEL(x, bt) \ + (((x) < (pthreshold)) ? binuptime(&bt) : getbinuptime(&bt)) + struct callout_handle { struct callout *callout; }; Index: sys/kern/kern_timeout.c =================================================================== --- sys/kern/kern_timeout.c (revision 242516) +++ sys/kern/kern_timeout.c (working copy) @@ -94,6 +94,11 @@ SYSCTL_INT(_debug, OID_AUTO, to_avg_mpcalls_dir, C 0, "Average number of MP direct callouts made per callout_process call. " "Units = 1/1000"); #endif +SYSCTL_INT(_kern, OID_AUTO, pthreshold, CTLFLAG_RW, &pthreshold, 0, + "Precision threshold for callout time-interval measurements"); +SYSCTL_INT(_kern, OID_AUTO, precision_flags, CTLFLAG_RW, &precision_flags, 0, + "Precision tolerance for callouts"); + /* * TODO: * allocate more timeout table slots when table overflows. @@ -170,7 +175,6 @@ struct callout_cpu cc_cpu; #define CC_LOCK(cc) mtx_lock_spin(&(cc)->cc_lock) #define CC_UNLOCK(cc) mtx_unlock_spin(&(cc)->cc_lock) #define CC_LOCK_ASSERT(cc) mtx_assert(&(cc)->cc_lock, MA_OWNED) -#define C_PRECISION 0x2 #define FREQ2BT(freq, bt) \ { \ @@ -369,6 +373,21 @@ start_softclock(void *dummy) SYSINIT(start_softclock, SI_SUB_SOFTINTR, SI_ORDER_FIRST, start_softclock, NULL); +static void +callout_init_precision(void) +{ + u_int pow2; + + pthreshold = 20 * imin(1000000000 / hz, 1000000); + pow2 = (pthreshold & (pthreshold - 1)) == 0; + precision_flags = fls(pthreshold); + if (pow2) + precision_flags += 1; +} + +SYSINIT(callout_init_precision, SI_SUB_CLOCKS, SI_ORDER_ANY, + callout_init_precision, NULL); + static inline int callout_hash(struct bintime *bt) { @@ -567,7 +586,7 @@ callout_cc_add(struct callout *c, struct callout_c c->c_time = to_bintime; bintime_clear(&c->c_precision); if (flags & C_PRECISION) { - r_shift = ((flags >> 2) & PRECISION_RANGE); + r_shift = flags >> 2; r_val = (r_shift != 0) ? (uint64_t)1 << (64 - r_shift) : 0; /* * Round as far as precision specified is coarse (up to 8ms).