version 1.74, 2001/01/17 18:21:41 |
version 1.74.2.4, 2001/11/14 19:16:33 |
|
|
* @(#)kern_clock.c 8.5 (Berkeley) 1/21/94 |
* @(#)kern_clock.c 8.5 (Berkeley) 1/21/94 |
*/ |
*/ |
|
|
|
#include <sys/cdefs.h> |
|
__KERNEL_RCSID(0, "$NetBSD$"); |
|
|
|
#include "opt_callout.h" |
#include "opt_ntp.h" |
#include "opt_ntp.h" |
|
|
#include <sys/param.h> |
#include <sys/param.h> |
|
|
#include <sys/dkstat.h> |
#include <sys/dkstat.h> |
#include <sys/callout.h> |
#include <sys/callout.h> |
#include <sys/kernel.h> |
#include <sys/kernel.h> |
|
#include <sys/lwp.h> |
#include <sys/proc.h> |
#include <sys/proc.h> |
#include <sys/resourcevar.h> |
#include <sys/resourcevar.h> |
#include <sys/signalvar.h> |
#include <sys/signalvar.h> |
|
|
#include <sys/sysctl.h> |
#include <sys/sysctl.h> |
#include <sys/timex.h> |
#include <sys/timex.h> |
#include <sys/sched.h> |
#include <sys/sched.h> |
|
#ifdef CALLWHEEL_STATS |
|
#include <sys/device.h> |
|
#endif |
|
|
#include <machine/cpu.h> |
#include <machine/cpu.h> |
#ifdef __HAVE_GENERIC_SOFT_INTERRUPTS |
#ifdef __HAVE_GENERIC_SOFT_INTERRUPTS |
Line 314 long clock_cpu = 0; /* CPU clock adjust |
|
Line 322 long clock_cpu = 0; /* CPU clock adjust |
|
|
|
int stathz; |
int stathz; |
int profhz; |
int profhz; |
|
int schedhz; |
int profprocs; |
int profprocs; |
int softclock_running; /* 1 => softclock() is running */ |
int softclock_running; /* 1 => softclock() is running */ |
static int psdiv; /* prof => stat divider */ |
static int psdiv; /* prof => stat divider */ |
Line 353 int callwheelsize, callwheelbits, callwh |
|
Line 362 int callwheelsize, callwheelbits, callwh |
|
static struct callout *nextsoftcheck; /* next callout to be checked */ |
static struct callout *nextsoftcheck; /* next callout to be checked */ |
|
|
#ifdef CALLWHEEL_STATS |
#ifdef CALLWHEEL_STATS |
int callwheel_collisions; /* number of hash collisions */ |
int *callwheel_sizes; /* per-bucket length count */ |
int callwheel_maxlength; /* length of the longest hash chain */ |
struct evcnt callwheel_collisions; /* number of hash collisions */ |
int *callwheel_sizes; /* per-bucket length count */ |
struct evcnt callwheel_maxlength; /* length of the longest hash chain */ |
u_int64_t callwheel_count; /* # callouts currently */ |
struct evcnt callwheel_count; /* # callouts currently */ |
u_int64_t callwheel_established; /* # callouts established */ |
struct evcnt callwheel_established; /* # callouts established */ |
u_int64_t callwheel_fired; /* # callouts that fired */ |
struct evcnt callwheel_fired; /* # callouts that fired */ |
u_int64_t callwheel_disestablished; /* # callouts disestablished */ |
struct evcnt callwheel_disestablished; /* # callouts disestablished */ |
u_int64_t callwheel_changed; /* # callouts changed */ |
struct evcnt callwheel_changed; /* # callouts changed */ |
u_int64_t callwheel_softclocks; /* # times softclock() called */ |
struct evcnt callwheel_softclocks; /* # times softclock() called */ |
u_int64_t callwheel_softchecks; /* # checks per softclock() */ |
struct evcnt callwheel_softchecks; /* # checks per softclock() */ |
u_int64_t callwheel_softempty; /* # empty buckets seen */ |
struct evcnt callwheel_softempty; /* # empty buckets seen */ |
|
struct evcnt callwheel_hintworked; /* # times hint saved scan */ |
#endif /* CALLWHEEL_STATS */ |
#endif /* CALLWHEEL_STATS */ |
|
|
/* |
/* |
Line 509 initclocks(void) |
|
Line 519 initclocks(void) |
|
void |
void |
hardclock(struct clockframe *frame) |
hardclock(struct clockframe *frame) |
{ |
{ |
|
struct lwp *l; |
struct proc *p; |
struct proc *p; |
int delta; |
int delta; |
extern int tickdelta; |
extern int tickdelta; |
Line 519 hardclock(struct clockframe *frame) |
|
Line 530 hardclock(struct clockframe *frame) |
|
int ltemp; |
int ltemp; |
#endif |
#endif |
|
|
p = curproc; |
l = curproc; |
if (p) { |
if (l) { |
struct pstats *pstats; |
struct pstats *pstats; |
|
p = l->l_proc; |
/* |
/* |
* Run current process's virtual and profile time, as needed. |
* Run current process's virtual and profile time, as needed. |
*/ |
*/ |
Line 880 hardclock(struct clockframe *frame) |
|
Line 891 hardclock(struct clockframe *frame) |
|
*/ |
*/ |
simple_lock(&callwheel_slock); /* already at splclock() */ |
simple_lock(&callwheel_slock); /* already at splclock() */ |
hardclock_ticks++; |
hardclock_ticks++; |
if (TAILQ_FIRST(&callwheel[hardclock_ticks & callwheelmask]) != NULL) { |
if (! TAILQ_EMPTY(&callwheel[hardclock_ticks & callwheelmask].cq_q)) { |
simple_unlock(&callwheel_slock); |
simple_unlock(&callwheel_slock); |
if (CLKF_BASEPRI(frame)) { |
if (CLKF_BASEPRI(frame)) { |
/* |
/* |
Line 930 softclock(void *v) |
|
Line 941 softclock(void *v) |
|
softclock_running = 1; |
softclock_running = 1; |
|
|
#ifdef CALLWHEEL_STATS |
#ifdef CALLWHEEL_STATS |
callwheel_softclocks++; |
callwheel_softclocks.ev_count++; |
#endif |
#endif |
|
|
while (softclock_ticks != hardclock_ticks) { |
while (softclock_ticks != hardclock_ticks) { |
softclock_ticks++; |
softclock_ticks++; |
idx = (int)(softclock_ticks & callwheelmask); |
idx = (int)(softclock_ticks & callwheelmask); |
bucket = &callwheel[idx]; |
bucket = &callwheel[idx]; |
c = TAILQ_FIRST(bucket); |
c = TAILQ_FIRST(&bucket->cq_q); |
|
if (c == NULL) { |
|
#ifdef CALLWHEEL_STATS |
|
callwheel_softempty.ev_count++; |
|
#endif |
|
continue; |
|
} |
|
if (softclock_ticks < bucket->cq_hint) { |
#ifdef CALLWHEEL_STATS |
#ifdef CALLWHEEL_STATS |
if (c == NULL) |
callwheel_hintworked.ev_count++; |
callwheel_softempty++; |
|
#endif |
#endif |
|
continue; |
|
} |
|
bucket->cq_hint = UQUAD_MAX; |
while (c != NULL) { |
while (c != NULL) { |
#ifdef CALLWHEEL_STATS |
#ifdef CALLWHEEL_STATS |
callwheel_softchecks++; |
callwheel_softchecks.ev_count++; |
#endif |
#endif |
if (c->c_time != softclock_ticks) { |
if (c->c_time != softclock_ticks) { |
|
if (c->c_time < bucket->cq_hint) |
|
bucket->cq_hint = c->c_time; |
c = TAILQ_NEXT(c, c_link); |
c = TAILQ_NEXT(c, c_link); |
if (++steps >= MAX_SOFTCLOCK_STEPS) { |
if (++steps >= MAX_SOFTCLOCK_STEPS) { |
nextsoftcheck = c; |
nextsoftcheck = c; |
Line 958 softclock(void *v) |
|
Line 980 softclock(void *v) |
|
} |
} |
} else { |
} else { |
nextsoftcheck = TAILQ_NEXT(c, c_link); |
nextsoftcheck = TAILQ_NEXT(c, c_link); |
TAILQ_REMOVE(bucket, c, c_link); |
TAILQ_REMOVE(&bucket->cq_q, c, c_link); |
#ifdef CALLWHEEL_STATS |
#ifdef CALLWHEEL_STATS |
callwheel_sizes[idx]--; |
callwheel_sizes[idx]--; |
callwheel_fired++; |
callwheel_fired.ev_count++; |
callwheel_count--; |
callwheel_count.ev_count--; |
#endif |
#endif |
func = c->c_func; |
func = c->c_func; |
arg = c->c_arg; |
arg = c->c_arg; |
Line 975 softclock(void *v) |
|
Line 997 softclock(void *v) |
|
c = nextsoftcheck; |
c = nextsoftcheck; |
} |
} |
} |
} |
|
if (TAILQ_EMPTY(&bucket->cq_q)) |
|
bucket->cq_hint = UQUAD_MAX; |
} |
} |
nextsoftcheck = NULL; |
nextsoftcheck = NULL; |
softclock_running = 0; |
softclock_running = 0; |
Line 1006 callout_startup(void) |
|
Line 1030 callout_startup(void) |
|
{ |
{ |
int i; |
int i; |
|
|
for (i = 0; i < callwheelsize; i++) |
for (i = 0; i < callwheelsize; i++) { |
TAILQ_INIT(&callwheel[i]); |
callwheel[i].cq_hint = UQUAD_MAX; |
|
TAILQ_INIT(&callwheel[i].cq_q); |
|
} |
|
|
simple_lock_init(&callwheel_slock); |
simple_lock_init(&callwheel_slock); |
|
|
|
#ifdef CALLWHEEL_STATS |
|
evcnt_attach_dynamic(&callwheel_collisions, EVCNT_TYPE_MISC, |
|
NULL, "callwheel", "collisions"); |
|
evcnt_attach_dynamic(&callwheel_maxlength, EVCNT_TYPE_MISC, |
|
NULL, "callwheel", "maxlength"); |
|
evcnt_attach_dynamic(&callwheel_count, EVCNT_TYPE_MISC, |
|
NULL, "callwheel", "count"); |
|
evcnt_attach_dynamic(&callwheel_established, EVCNT_TYPE_MISC, |
|
NULL, "callwheel", "established"); |
|
evcnt_attach_dynamic(&callwheel_fired, EVCNT_TYPE_MISC, |
|
NULL, "callwheel", "fired"); |
|
evcnt_attach_dynamic(&callwheel_disestablished, EVCNT_TYPE_MISC, |
|
NULL, "callwheel", "disestablished"); |
|
evcnt_attach_dynamic(&callwheel_changed, EVCNT_TYPE_MISC, |
|
NULL, "callwheel", "changed"); |
|
evcnt_attach_dynamic(&callwheel_softclocks, EVCNT_TYPE_MISC, |
|
NULL, "callwheel", "softclocks"); |
|
evcnt_attach_dynamic(&callwheel_softempty, EVCNT_TYPE_MISC, |
|
NULL, "callwheel", "softempty"); |
|
evcnt_attach_dynamic(&callwheel_hintworked, EVCNT_TYPE_MISC, |
|
NULL, "callwheel", "hintworked"); |
|
#endif /* CALLWHEEL_STATS */ |
} |
} |
|
|
/* |
/* |
Line 1048 callout_reset(struct callout *c, int tic |
|
Line 1097 callout_reset(struct callout *c, int tic |
|
if (c->c_flags & CALLOUT_PENDING) { |
if (c->c_flags & CALLOUT_PENDING) { |
callout_stop_locked(c); /* Already locked */ |
callout_stop_locked(c); /* Already locked */ |
#ifdef CALLWHEEL_STATS |
#ifdef CALLWHEEL_STATS |
callwheel_changed++; |
callwheel_changed.ev_count++; |
#endif |
#endif |
} |
} |
|
|
Line 1060 callout_reset(struct callout *c, int tic |
|
Line 1109 callout_reset(struct callout *c, int tic |
|
bucket = &callwheel[c->c_time & callwheelmask]; |
bucket = &callwheel[c->c_time & callwheelmask]; |
|
|
#ifdef CALLWHEEL_STATS |
#ifdef CALLWHEEL_STATS |
if (TAILQ_FIRST(bucket) != NULL) |
if (! TAILQ_EMPTY(&bucket->cq_q)) |
callwheel_collisions++; |
callwheel_collisions.ev_count++; |
#endif |
#endif |
|
|
TAILQ_INSERT_TAIL(bucket, c, c_link); |
TAILQ_INSERT_TAIL(&bucket->cq_q, c, c_link); |
|
if (c->c_time < bucket->cq_hint) |
|
bucket->cq_hint = c->c_time; |
|
|
#ifdef CALLWHEEL_STATS |
#ifdef CALLWHEEL_STATS |
callwheel_count++; |
callwheel_count.ev_count++; |
callwheel_established++; |
callwheel_established.ev_count++; |
if (++callwheel_sizes[c->c_time & callwheelmask] > callwheel_maxlength) |
if (++callwheel_sizes[c->c_time & callwheelmask] > |
callwheel_maxlength = |
callwheel_maxlength.ev_count) |
|
callwheel_maxlength.ev_count = |
callwheel_sizes[c->c_time & callwheelmask]; |
callwheel_sizes[c->c_time & callwheelmask]; |
#endif |
#endif |
|
|
Line 1085 callout_reset(struct callout *c, int tic |
|
Line 1137 callout_reset(struct callout *c, int tic |
|
static void |
static void |
callout_stop_locked(struct callout *c) |
callout_stop_locked(struct callout *c) |
{ |
{ |
|
struct callout_queue *bucket; |
|
|
/* |
/* |
* Don't attempt to delete a callout that's not on the queue. |
* Don't attempt to delete a callout that's not on the queue. |
Line 1099 callout_stop_locked(struct callout *c) |
|
Line 1152 callout_stop_locked(struct callout *c) |
|
if (nextsoftcheck == c) |
if (nextsoftcheck == c) |
nextsoftcheck = TAILQ_NEXT(c, c_link); |
nextsoftcheck = TAILQ_NEXT(c, c_link); |
|
|
TAILQ_REMOVE(&callwheel[c->c_time & callwheelmask], c, c_link); |
bucket = &callwheel[c->c_time & callwheelmask]; |
|
TAILQ_REMOVE(&bucket->cq_q, c, c_link); |
|
if (TAILQ_EMPTY(&bucket->cq_q)) |
|
bucket->cq_hint = UQUAD_MAX; |
#ifdef CALLWHEEL_STATS |
#ifdef CALLWHEEL_STATS |
callwheel_count--; |
callwheel_count.ev_count--; |
callwheel_disestablished++; |
callwheel_disestablished.ev_count++; |
callwheel_sizes[c->c_time & callwheelmask]--; |
callwheel_sizes[c->c_time & callwheelmask]--; |
#endif |
#endif |
|
|
Line 1142 callout_showstats(void) |
|
Line 1198 callout_showstats(void) |
|
splx(s); |
splx(s); |
|
|
printf("Callwheel statistics:\n"); |
printf("Callwheel statistics:\n"); |
printf("\tCallouts currently queued: %llu\n", callwheel_count); |
printf("\tCallouts currently queued: %llu\n", |
printf("\tCallouts established: %llu\n", callwheel_established); |
(long long) callwheel_count.ev_count); |
printf("\tCallouts disestablished: %llu\n", callwheel_disestablished); |
printf("\tCallouts established: %llu\n", |
if (callwheel_changed != 0) |
(long long) callwheel_established.ev_count); |
printf("\t\tOf those, %llu were changes\n", callwheel_changed); |
printf("\tCallouts disestablished: %llu\n", |
printf("\tCallouts that fired: %llu\n", callwheel_fired); |
(long long) callwheel_disestablished.ev_count); |
|
if (callwheel_changed.ev_count != 0) |
|
printf("\t\tOf those, %llu were changes\n", |
|
(long long) callwheel_changed.ev_count); |
|
printf("\tCallouts that fired: %llu\n", |
|
(long long) callwheel_fired.ev_count); |
printf("\tNumber of buckets: %d\n", callwheelsize); |
printf("\tNumber of buckets: %d\n", callwheelsize); |
printf("\tNumber of hash collisions: %d\n", callwheel_collisions); |
printf("\tNumber of hash collisions: %llu\n", |
printf("\tMaximum hash chain length: %d\n", callwheel_maxlength); |
(long long) callwheel_collisions.ev_count); |
|
printf("\tMaximum hash chain length: %llu\n", |
|
(long long) callwheel_maxlength.ev_count); |
printf("\tSoftclocks: %llu, Softchecks: %llu\n", |
printf("\tSoftclocks: %llu, Softchecks: %llu\n", |
callwheel_softclocks, callwheel_softchecks); |
(long long) callwheel_softclocks.ev_count, |
printf("\t\tEmpty buckets seen: %llu\n", callwheel_softempty); |
(long long) callwheel_softchecks.ev_count); |
|
printf("\t\tEmpty buckets seen: %llu\n", |
|
(long long) callwheel_softempty.ev_count); |
|
printf("\t\tTimes hint saved scan: %llu\n", |
|
(long long) callwheel_hintworked.ev_count); |
} |
} |
#endif |
#endif |
|
|
Line 1264 statclock(struct clockframe *frame) |
|
Line 1331 statclock(struct clockframe *frame) |
|
#endif |
#endif |
struct cpu_info *ci = curcpu(); |
struct cpu_info *ci = curcpu(); |
struct schedstate_percpu *spc = &ci->ci_schedstate; |
struct schedstate_percpu *spc = &ci->ci_schedstate; |
|
struct lwp *l; |
struct proc *p; |
struct proc *p; |
|
|
/* |
/* |
Line 1279 statclock(struct clockframe *frame) |
|
Line 1347 statclock(struct clockframe *frame) |
|
setstatclockrate(profhz); |
setstatclockrate(profhz); |
} |
} |
} |
} |
p = curproc; |
l = curproc; |
|
p = (l ? l->l_proc : 0); |
if (CLKF_USERMODE(frame)) { |
if (CLKF_USERMODE(frame)) { |
if (p->p_flag & P_PROFIL) |
if (p->p_flag & P_PROFIL) |
addupc_intr(p, CLKF_PC(frame)); |
addupc_intr(p, CLKF_PC(frame)); |
Line 1308 statclock(struct clockframe *frame) |
|
Line 1377 statclock(struct clockframe *frame) |
|
} |
} |
} |
} |
#endif |
#endif |
#ifdef PROC_PC |
#ifdef LWP_PC |
if (p && p->p_flag & P_PROFIL) |
if (p && p->p_flag & P_PROFIL) |
addupc_intr(p, PROC_PC(p)); |
addupc_intr(p, LWP_PC(l)); |
#endif |
#endif |
if (--spc->spc_pscnt > 0) |
if (--spc->spc_pscnt > 0) |
return; |
return; |
Line 1338 statclock(struct clockframe *frame) |
|
Line 1407 statclock(struct clockframe *frame) |
|
} |
} |
spc->spc_pscnt = psdiv; |
spc->spc_pscnt = psdiv; |
|
|
if (p != NULL) { |
if (l != NULL) { |
++p->p_cpticks; |
++p->p_cpticks; |
/* |
/* |
* If no separate schedclock is provided, call it here |
* If no separate schedclock is provided, call it here |
Line 1346 statclock(struct clockframe *frame) |
|
Line 1415 statclock(struct clockframe *frame) |
|
*/ |
*/ |
if (schedhz == 0) |
if (schedhz == 0) |
if ((++ci->ci_schedstate.spc_schedticks & 3) == 0) |
if ((++ci->ci_schedstate.spc_schedticks & 3) == 0) |
schedclock(p); |
schedclock(l); |
} |
} |
} |
} |
|
|