summaryrefslogtreecommitdiffstats
path: root/sys/kern/kern_tc.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/kern/kern_tc.c')
-rw-r--r--sys/kern/kern_tc.c59
1 files changed, 59 insertions, 0 deletions
diff --git a/sys/kern/kern_tc.c b/sys/kern/kern_tc.c
index 6e1f486..9fe7ebe 100644
--- a/sys/kern/kern_tc.c
+++ b/sys/kern/kern_tc.c
@@ -22,6 +22,7 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/kernel.h>
+#include <sys/limits.h>
#ifdef FFCLOCK
#include <sys/lock.h>
#include <sys/mutex.h>
@@ -119,6 +120,21 @@ static int timestepwarnings;
SYSCTL_INT(_kern_timecounter, OID_AUTO, stepwarnings, CTLFLAG_RW,
&timestepwarnings, 0, "Log time steps");
+struct bintime bt_timethreshold;
+struct bintime bt_tickthreshold;
+sbintime_t sbt_timethreshold;
+sbintime_t sbt_tickthreshold;
+struct bintime tc_tick_bt;
+sbintime_t tc_tick_sbt;
+int tc_precexp;
+int tc_timepercentage = TC_DEFAULTPERC;
+TUNABLE_INT("kern.timecounter.alloweddeviation", &tc_timepercentage);
+static int sysctl_kern_timecounter_adjprecision(SYSCTL_HANDLER_ARGS);
+SYSCTL_PROC(_kern_timecounter, OID_AUTO, alloweddeviation,
+ CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 0,
+ sysctl_kern_timecounter_adjprecision, "I",
+ "Allowed time interval deviation in percents");
+
static void tc_windup(void);
static void cpu_tick_calibrate(int);
@@ -1746,10 +1762,47 @@ tc_ticktock(int cnt)
tc_windup();
}
+static void __inline
+tc_adjprecision(void)
+{
+ int t;
+
+ if (tc_timepercentage > 0) {
+ t = (99 + tc_timepercentage) / tc_timepercentage;
+ tc_precexp = fls(t + (t >> 1)) - 1;
+ FREQ2BT(hz / tc_tick, &bt_timethreshold);
+ FREQ2BT(hz, &bt_tickthreshold);
+ bintime_shift(&bt_timethreshold, tc_precexp);
+ bintime_shift(&bt_tickthreshold, tc_precexp);
+ } else {
+ tc_precexp = 31;
+ bt_timethreshold.sec = INT_MAX;
+ bt_timethreshold.frac = ~(uint64_t)0;
+ bt_tickthreshold = bt_timethreshold;
+ }
+ sbt_timethreshold = bttosbt(bt_timethreshold);
+ sbt_tickthreshold = bttosbt(bt_tickthreshold);
+}
+
+static int
+sysctl_kern_timecounter_adjprecision(SYSCTL_HANDLER_ARGS)
+{
+ int error, val;
+
+ val = tc_timepercentage;
+ error = sysctl_handle_int(oidp, &val, 0, req);
+ if (error != 0 || req->newptr == NULL)
+ return (error);
+ tc_timepercentage = val;
+ tc_adjprecision();
+ return (0);
+}
+
static void
inittimecounter(void *dummy)
{
u_int p;
+ int tick_rate;
/*
* Set the initial timeout to
@@ -1763,6 +1816,12 @@ inittimecounter(void *dummy)
tc_tick = (hz + 500) / 1000;
else
tc_tick = 1;
+ tc_adjprecision();
+ FREQ2BT(hz, &tick_bt);
+ tick_sbt = bttosbt(tick_bt);
+ tick_rate = hz / tc_tick;
+ FREQ2BT(tick_rate, &tc_tick_bt);
+ tc_tick_sbt = bttosbt(tc_tick_bt);
p = (tc_tick * 1000000) / hz;
printf("Timecounters tick every %d.%03u msec\n", p / 1000, p % 1000);
OpenPOWER on IntegriCloud