aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStanislaw Gruszka <sgruszka@redhat.com>2009-07-29 06:15:27 -0400
committerIngo Molnar <mingo@elte.hu>2009-08-03 08:48:35 -0400
commit8356b5f9c424e5831715abbce747197c30d1fd71 (patch)
tree87de74cc86f6eebf88eba9a4c335614787d984c5
parent42c4ab41a176ee784c0f28c0b29025a8fc34f05a (diff)
itimers: Fix periodic tics precision
Measure ITIMER_PROF and ITIMER_VIRT timers interval error between real ticks and requested by user. 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@redhat.com> Acked-by: Peter Zijlstra <a.p.zijlstra@chello.nl> Acked-by: Thomas Gleixner <tglx@linutronix.de> Cc: Oleg Nesterov <oleg@redhat.com> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Paul Mackerras <paulus@samba.org> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> LKML-Reference: <1248862529-6063-3-git-send-email-sgruszka@redhat.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r--include/linux/sched.h2
-rw-r--r--kernel/itimer.c24
-rw-r--r--kernel/posix-cpu-timers.c20
3 files changed, 40 insertions, 6 deletions
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 3b3efaddd953..a069e65e8bb7 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -473,6 +473,8 @@ struct pacct_struct {
473struct cpu_itimer { 473struct cpu_itimer {
474 cputime_t expires; 474 cputime_t expires;
475 cputime_t incr; 475 cputime_t incr;
476 u32 error;
477 u32 incr_error;
476}; 478};
477 479
478/** 480/**
diff --git a/kernel/itimer.c b/kernel/itimer.c
index 852c88ddd1f0..21adff7b2a17 100644
--- a/kernel/itimer.c
+++ b/kernel/itimer.c
@@ -42,7 +42,7 @@ static struct timeval itimer_get_remtime(struct hrtimer *timer)
42} 42}
43 43
44static void get_cpu_itimer(struct task_struct *tsk, unsigned int clock_id, 44static void get_cpu_itimer(struct task_struct *tsk, unsigned int clock_id,
45 struct itimerval *value) 45 struct itimerval *const value)
46{ 46{
47 cputime_t cval, cinterval; 47 cputime_t cval, cinterval;
48 struct cpu_itimer *it = &tsk->signal->it[clock_id]; 48 struct cpu_itimer *it = &tsk->signal->it[clock_id];
@@ -127,14 +127,32 @@ enum hrtimer_restart it_real_fn(struct hrtimer *timer)
127 return HRTIMER_NORESTART; 127 return HRTIMER_NORESTART;
128} 128}
129 129
130static inline u32 cputime_sub_ns(cputime_t ct, s64 real_ns)
131{
132 struct timespec ts;
133 s64 cpu_ns;
134
135 cputime_to_timespec(ct, &ts);
136 cpu_ns = timespec_to_ns(&ts);
137
138 return (cpu_ns <= real_ns) ? 0 : cpu_ns - real_ns;
139}
140
130static void set_cpu_itimer(struct task_struct *tsk, unsigned int clock_id, 141static void set_cpu_itimer(struct task_struct *tsk, unsigned int clock_id,
131 struct itimerval *value, struct itimerval *ovalue) 142 const struct itimerval *const value,
143 struct itimerval *const ovalue)
132{ 144{
133 cputime_t cval, cinterval, nval, ninterval; 145 cputime_t cval, nval, cinterval, ninterval;
146 s64 ns_ninterval, ns_nval;
134 struct cpu_itimer *it = &tsk->signal->it[clock_id]; 147 struct cpu_itimer *it = &tsk->signal->it[clock_id];
135 148
136 nval = timeval_to_cputime(&value->it_value); 149 nval = timeval_to_cputime(&value->it_value);
150 ns_nval = timeval_to_ns(&value->it_value);
137 ninterval = timeval_to_cputime(&value->it_interval); 151 ninterval = timeval_to_cputime(&value->it_interval);
152 ns_ninterval = timeval_to_ns(&value->it_interval);
153
154 it->incr_error = cputime_sub_ns(ninterval, ns_ninterval);
155 it->error = cputime_sub_ns(nval, ns_nval);
138 156
139 spin_lock_irq(&tsk->sighand->siglock); 157 spin_lock_irq(&tsk->sighand->siglock);
140 158
diff --git a/kernel/posix-cpu-timers.c b/kernel/posix-cpu-timers.c
index 9b2d5e4dc8c4..b60d644ea4b3 100644
--- a/kernel/posix-cpu-timers.c
+++ b/kernel/posix-cpu-timers.c
@@ -1070,6 +1070,8 @@ static void stop_process_timers(struct task_struct *tsk)
1070 spin_unlock_irqrestore(&cputimer->lock, flags); 1070 spin_unlock_irqrestore(&cputimer->lock, flags);
1071} 1071}
1072 1072
1073static u32 onecputick;
1074
1073static void check_cpu_itimer(struct task_struct *tsk, struct cpu_itimer *it, 1075static void check_cpu_itimer(struct task_struct *tsk, struct cpu_itimer *it,
1074 cputime_t *expires, cputime_t cur_time, int signo) 1076 cputime_t *expires, cputime_t cur_time, int signo)
1075{ 1077{
@@ -1077,9 +1079,16 @@ static void check_cpu_itimer(struct task_struct *tsk, struct cpu_itimer *it,
1077 return; 1079 return;
1078 1080
1079 if (cputime_ge(cur_time, it->expires)) { 1081 if (cputime_ge(cur_time, it->expires)) {
1080 it->expires = it->incr; 1082 if (!cputime_eq(it->incr, cputime_zero)) {
1081 if (!cputime_eq(it->expires, cputime_zero)) 1083 it->expires = cputime_add(it->expires, it->incr);
1082 it->expires = cputime_add(it->expires, cur_time); 1084 it->error += it->incr_error;
1085 if (it->error >= onecputick) {
1086 it->expires = cputime_sub(it->expires,
1087 jiffies_to_cputime(1));
1088 it->error -= onecputick;
1089 }
1090 } else
1091 it->expires = cputime_zero;
1083 1092
1084 __group_send_sig_info(signo, SEND_SIG_PRIV, tsk); 1093 __group_send_sig_info(signo, SEND_SIG_PRIV, tsk);
1085 } 1094 }
@@ -1696,10 +1705,15 @@ static __init int init_posix_cpu_timers(void)
1696 .nsleep = thread_cpu_nsleep, 1705 .nsleep = thread_cpu_nsleep,
1697 .nsleep_restart = thread_cpu_nsleep_restart, 1706 .nsleep_restart = thread_cpu_nsleep_restart,
1698 }; 1707 };
1708 struct timespec ts;
1699 1709
1700 register_posix_clock(CLOCK_PROCESS_CPUTIME_ID, &process); 1710 register_posix_clock(CLOCK_PROCESS_CPUTIME_ID, &process);
1701 register_posix_clock(CLOCK_THREAD_CPUTIME_ID, &thread); 1711 register_posix_clock(CLOCK_THREAD_CPUTIME_ID, &thread);
1702 1712
1713 cputime_to_timespec(jiffies_to_cputime(1), &ts);
1714 onecputick = ts.tv_nsec;
1715 WARN_ON(ts.tv_sec != 0);
1716
1703 return 0; 1717 return 0;
1704} 1718}
1705__initcall(init_posix_cpu_timers); 1719__initcall(init_posix_cpu_timers);