Some optimizations for kqueue timers.

There is no need to do two allocations per kqueue timer. Gather all
data needed by the timer callout into the structure and allocate it at
once.

Use the structure to preserve the result of timer2sbintime(), to not
perform repeated 64bit calculations in callout.

Remove tautological casts.
Remove now unused p_nexttime [1].

Noted by:	markj [1]
Reviewed by:	markj (previous version)
Sponsored by:	The FreeBSD Foundation
MFC after:	1 week
X-MFC note:	do not remove p_nexttime
Differential revision:	https://reviews.freebsd.org/D8901
This commit is contained in:
kib 2016-12-25 19:49:35 +00:00
parent bc7c5848fe
commit 5da38b3b08
2 changed files with 28 additions and 25 deletions

View File

@ -631,23 +631,29 @@ timer2sbintime(intptr_t data, int flags)
return (-1);
}
struct kq_timer_cb_data {
struct callout c;
sbintime_t next; /* next timer event fires at */
sbintime_t to; /* precalculated timer period */
};
static void
filt_timerexpire(void *knx)
{
struct callout *calloutp;
struct knote *kn;
struct kq_timer_cb_data *kc;
kn = knx;
kn->kn_data++;
KNOTE_ACTIVATE(kn, 0); /* XXX - handle locking */
if ((kn->kn_flags & EV_ONESHOT) != EV_ONESHOT) {
calloutp = (struct callout *)kn->kn_hook;
*kn->kn_ptr.p_nexttime += timer2sbintime(kn->kn_sdata,
kn->kn_sfflags);
callout_reset_sbt_on(calloutp, *kn->kn_ptr.p_nexttime, 0,
filt_timerexpire, kn, PCPU_GET(cpuid), C_ABSOLUTE);
}
if ((kn->kn_flags & EV_ONESHOT) != 0)
return;
kc = kn->kn_ptr.p_v;
kc->next += kc->to;
callout_reset_sbt_on(&kc->c, kc->next, 0, filt_timerexpire, kn,
PCPU_GET(cpuid), C_ABSOLUTE);
}
/*
@ -656,16 +662,16 @@ filt_timerexpire(void *knx)
static int
filt_timerattach(struct knote *kn)
{
struct callout *calloutp;
struct kq_timer_cb_data *kc;
sbintime_t to;
unsigned int ncallouts;
if ((intptr_t)kn->kn_sdata < 0)
if (kn->kn_sdata < 0)
return (EINVAL);
if ((intptr_t)kn->kn_sdata == 0 && (kn->kn_flags & EV_ONESHOT) == 0)
if (kn->kn_sdata == 0 && (kn->kn_flags & EV_ONESHOT) == 0)
kn->kn_sdata = 1;
/* Only precision unit are supported in flags so far */
if (kn->kn_sfflags & ~NOTE_TIMER_PRECMASK)
if ((kn->kn_sfflags & ~NOTE_TIMER_PRECMASK) != 0)
return (EINVAL);
to = timer2sbintime(kn->kn_sdata, kn->kn_sfflags);
@ -680,13 +686,12 @@ filt_timerattach(struct knote *kn)
kn->kn_flags |= EV_CLEAR; /* automatically set */
kn->kn_status &= ~KN_DETACHED; /* knlist_add clears it */
kn->kn_ptr.p_nexttime = malloc(sizeof(sbintime_t), M_KQUEUE, M_WAITOK);
calloutp = malloc(sizeof(*calloutp), M_KQUEUE, M_WAITOK);
callout_init(calloutp, 1);
kn->kn_hook = calloutp;
*kn->kn_ptr.p_nexttime = to + sbinuptime();
callout_reset_sbt_on(calloutp, *kn->kn_ptr.p_nexttime, 0,
filt_timerexpire, kn, PCPU_GET(cpuid), C_ABSOLUTE);
kn->kn_ptr.p_v = kc = malloc(sizeof(*kc), M_KQUEUE, M_WAITOK);
callout_init(&kc->c, 1);
kc->next = to + sbinuptime();
kc->to = to;
callout_reset_sbt_on(&kc->c, kc->next, 0, filt_timerexpire, kn,
PCPU_GET(cpuid), C_ABSOLUTE);
return (0);
}
@ -694,13 +699,12 @@ filt_timerattach(struct knote *kn)
static void
filt_timerdetach(struct knote *kn)
{
struct callout *calloutp;
struct kq_timer_cb_data *kc;
unsigned int old;
calloutp = (struct callout *)kn->kn_hook;
callout_drain(calloutp);
free(calloutp, M_KQUEUE);
free(kn->kn_ptr.p_nexttime, M_KQUEUE);
kc = kn->kn_ptr.p_v;
callout_drain(&kc->c);
free(kc, M_KQUEUE);
old = atomic_fetchadd_int(&kq_ncallouts, -1);
KASSERT(old > 0, ("Number of callouts cannot become negative"));
kn->kn_status |= KN_DETACHED; /* knlist_remove sets it */

View File

@ -231,7 +231,6 @@ struct knote {
struct proc *p_proc; /* proc pointer */
struct kaiocb *p_aio; /* AIO job pointer */
struct aioliojob *p_lio; /* LIO job pointer */
sbintime_t *p_nexttime; /* next timer event fires at */
void *p_v; /* generic other pointer */
} kn_ptr;
struct filterops *kn_fop;