Re: [PATCH 2/2] itimers: fix periodic tics precision

From: Ingo Molnar
Date: Thu Apr 02 2009 - 12:47:31 EST



(Cc:s added)

* Stanislaw Gruszka <sgruszka@xxxxxxxxxx> wrote:

> Measure interval of tics generated by ITIMER_VIRT and ITIMER_PROF using ktime
> instead of cputime. Calculate error between requested interval and current one,
> take it into account when scheduling next tick.
>
> This patch introduce possibility where time between two consecutive tics is
> smaller then requested interval, it preserve however dependency that n tick
> is generated not earlier than n*interval time - counting from the beginning
> of periodic signal generation.
>
> Signed-off-by: Stanislaw Gruszka <sgruszka@xxxxxxxxxx>
> ---
> include/linux/sched.h | 3 ++-
> kernel/fork.c | 6 ++++--
> kernel/itimer.c | 21 +++++++++++++--------
> kernel/posix-cpu-timers.c | 24 +++++++++++++++++++++---
> 4 files changed, 40 insertions(+), 14 deletions(-)
>
> diff --git a/include/linux/sched.h b/include/linux/sched.h
> index b4c19c2..c6e1946 100644
> --- a/include/linux/sched.h
> +++ b/include/linux/sched.h
> @@ -529,7 +529,8 @@ struct signal_struct {
>
> /* ITIMER_PROF and ITIMER_VIRTUAL timers for the process */
> cputime_t it_expires[2];
> - cputime_t it_incr[2];
> + ktime_t it_incr[2];
> + u32 it_err_ns[2];
>
> /*
> * Thread group totals for process CPU timers.
> diff --git a/kernel/fork.c b/kernel/fork.c
> index 6c7044a..b1bb3e4 100644
> --- a/kernel/fork.c
> +++ b/kernel/fork.c
> @@ -805,8 +805,10 @@ static void posix_cpu_timers_init_group(struct signal_struct *sig)
> /* Expiration times and increments. */
> sig->it_expires[IT_VIRT] = cputime_zero;
> sig->it_expires[IT_PROF] = cputime_zero;
> - sig->it_incr[IT_VIRT] = cputime_zero;
> - sig->it_incr[IT_PROF] = cputime_zero;
> + sig->it_incr[IT_VIRT] = ktime_set(0, 0);
> + sig->it_incr[IT_PROF] = ktime_set(0, 0);
> + sig->it_err_ns[IT_VIRT] = 0;
> + sig->it_err_ns[IT_PROF] = 0;
>
> /* Cached expiration times. */
> sig->cputime_expires.prof_exp = cputime_zero;
> diff --git a/kernel/itimer.c b/kernel/itimer.c
> index ec64fea..ad06bd5 100644
> --- a/kernel/itimer.c
> +++ b/kernel/itimer.c
> @@ -44,11 +44,13 @@ static struct timeval itimer_get_remtime(struct hrtimer *timer)
> static void get_cpu_itimer(struct task_struct *tsk, enum itimer_number i,
> struct itimerval *value)
> {
> - cputime_t cval, cinterval;
> + cputime_t cval;
> + ktime_t kt_cinterval;
>
> spin_lock_irq(&tsk->sighand->siglock);
> +
> cval = tsk->signal->it_expires[i];
> - cinterval = tsk->signal->it_incr[i];
> + kt_cinterval = tsk->signal->it_incr[i];
> if (!cputime_eq(cval, cputime_zero)) {
> struct task_cputime cputime;
> cputime_t utime;
> @@ -61,9 +63,11 @@ static void get_cpu_itimer(struct task_struct *tsk, enum itimer_number i,
> cval = cputime_sub(cval, utime);
> }
> }
> +
> spin_unlock_irq(&tsk->sighand->siglock);
> +
> cputime_to_timeval(cval, &value->it_value);
> - cputime_to_timeval(cinterval, &value->it_interval);
> + value->it_interval = ktime_to_timeval(kt_cinterval);
> }
>
> int do_getitimer(int which, struct itimerval *value)
> @@ -121,15 +125,16 @@ enum hrtimer_restart it_real_fn(struct hrtimer *timer)
> static void set_cpu_itimer(struct task_struct *tsk, enum itimer_number i,
> struct itimerval *value, struct itimerval *ovalue)
> {
> - cputime_t cval, cinterval, nval, ninterval;
> + cputime_t cval, nval;
> + ktime_t kt_cinterval, kt_ninterval;
>
> nval = timeval_to_cputime(&value->it_value);
> - ninterval = timeval_to_cputime(&value->it_interval);
> + kt_ninterval = timeval_to_ktime(value->it_interval);
>
> spin_lock_irq(&tsk->sighand->siglock);
>
> cval = tsk->signal->it_expires[i];
> - cinterval = tsk->signal->it_incr[i];
> + kt_cinterval = tsk->signal->it_incr[i];
> if (!cputime_eq(cval, cputime_zero) ||
> !cputime_eq(nval, cputime_zero)) {
> if (cputime_gt(nval, cputime_zero))
> @@ -137,13 +142,13 @@ static void set_cpu_itimer(struct task_struct *tsk, enum itimer_number i,
> set_process_cpu_timer(tsk, i, &nval, &cval);
> }
> tsk->signal->it_expires[i] = nval;
> - tsk->signal->it_incr[i] = ninterval;
> + tsk->signal->it_incr[i] = kt_ninterval;
>
> spin_unlock_irq(&tsk->sighand->siglock);
>
> if (ovalue) {
> cputime_to_timeval(cval, &ovalue->it_value);
> - cputime_to_timeval(cinterval, &ovalue->it_interval);
> + ovalue->it_interval = ktime_to_timeval(kt_cinterval);
> }
> }
>
> diff --git a/kernel/posix-cpu-timers.c b/kernel/posix-cpu-timers.c
> index 76e125c..9c3ea39 100644
> --- a/kernel/posix-cpu-timers.c
> +++ b/kernel/posix-cpu-timers.c
> @@ -1080,10 +1080,28 @@ static cputime_t check_cpu_itimer(struct task_struct *tsk, enum itimer_number i,
> if (cputime_ge(cur_time, sig->it_expires[i])) {
> int signo;
>
> - sig->it_expires[i] = sig->it_incr[i];
> - if (!cputime_eq(sig->it_expires[i], cputime_zero)) {
> + if (sig->it_incr[i].tv64 != 0) {
> + ktime_t incr, real_incr, diff;
> + cputime_t cpu_incr;
> + struct timespec ts_incr, ts_real_incr;
> +
> + incr = ktime_sub_ns(sig->it_incr[i], sig->it_err_ns[i]);
> + if (unlikely(incr.tv64 <= 0))
> + incr = ktime_set(0, 1);
> +
> + ts_incr = ktime_to_timespec(incr);
> + cpu_incr = timespec_to_cputime(&ts_incr);
> +
> + cputime_to_timespec(cpu_incr, &ts_real_incr);
> + real_incr = timespec_to_ktime(ts_real_incr);
> +
> + diff = ktime_sub(real_incr, incr);
> + sig->it_err_ns[i] = ktime_to_ns(diff);
> sig->it_expires[i] = cputime_add(sig->it_expires[i],
> - cur_time);
> + cpu_incr);
> + } else {
> + sig->it_expires[i] = cputime_zero;
> + sig->it_err_ns[i] = 0;
> }
>
> signo = (i == IT_VIRT) ? SIGVTALRM : SIGPROF;
> --
> 1.6.0.6
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@xxxxxxxxxxxxxxx
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/