mirror of
https://github.com/torvalds/linux.git
synced 2026-07-28 10:09:10 +02:00
timers/itimer: Convert internal cputime_t units to nsec
Use the new nsec based cputime accessors as part of the whole cputime conversion from cputime_t to nsecs. Also convert itimers to use nsec based internal counters. This simplifies it and removes the whole game with error/inc_error which served to deal with cputime_t random granularity. Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: Fenghua Yu <fenghua.yu@intel.com> Cc: Heiko Carstens <heiko.carstens@de.ibm.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Martin Schwidefsky <schwidefsky@de.ibm.com> Cc: Michael Ellerman <mpe@ellerman.id.au> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Rik van Riel <riel@redhat.com> Cc: Stanislaw Gruszka <sgruszka@redhat.com> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Tony Luck <tony.luck@intel.com> Cc: Wanpeng Li <wanpeng.li@hotmail.com> Link: http://lkml.kernel.org/r/1485832191-26889-20-git-send-email-fweisbec@gmail.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
parent
ebd7e7fc4b
commit
858cf3a8c5
|
|
@ -119,7 +119,7 @@ void run_posix_cpu_timers(struct task_struct *task);
|
||||||
void posix_cpu_timers_exit(struct task_struct *task);
|
void posix_cpu_timers_exit(struct task_struct *task);
|
||||||
void posix_cpu_timers_exit_group(struct task_struct *task);
|
void posix_cpu_timers_exit_group(struct task_struct *task);
|
||||||
void set_process_cpu_timer(struct task_struct *task, unsigned int clock_idx,
|
void set_process_cpu_timer(struct task_struct *task, unsigned int clock_idx,
|
||||||
cputime_t *newval, cputime_t *oldval);
|
u64 *newval, u64 *oldval);
|
||||||
|
|
||||||
long clock_nanosleep_restart(struct restart_block *restart_block);
|
long clock_nanosleep_restart(struct restart_block *restart_block);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -568,10 +568,8 @@ struct pacct_struct {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct cpu_itimer {
|
struct cpu_itimer {
|
||||||
cputime_t expires;
|
u64 expires;
|
||||||
cputime_t incr;
|
u64 incr;
|
||||||
u32 error;
|
|
||||||
u32 incr_error;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -269,17 +269,17 @@ DEFINE_EVENT(hrtimer_class, hrtimer_cancel,
|
||||||
TRACE_EVENT(itimer_state,
|
TRACE_EVENT(itimer_state,
|
||||||
|
|
||||||
TP_PROTO(int which, const struct itimerval *const value,
|
TP_PROTO(int which, const struct itimerval *const value,
|
||||||
cputime_t expires),
|
unsigned long long expires),
|
||||||
|
|
||||||
TP_ARGS(which, value, expires),
|
TP_ARGS(which, value, expires),
|
||||||
|
|
||||||
TP_STRUCT__entry(
|
TP_STRUCT__entry(
|
||||||
__field( int, which )
|
__field( int, which )
|
||||||
__field( cputime_t, expires )
|
__field( unsigned long long, expires )
|
||||||
__field( long, value_sec )
|
__field( long, value_sec )
|
||||||
__field( long, value_usec )
|
__field( long, value_usec )
|
||||||
__field( long, interval_sec )
|
__field( long, interval_sec )
|
||||||
__field( long, interval_usec )
|
__field( long, interval_usec )
|
||||||
),
|
),
|
||||||
|
|
||||||
TP_fast_assign(
|
TP_fast_assign(
|
||||||
|
|
@ -292,7 +292,7 @@ TRACE_EVENT(itimer_state,
|
||||||
),
|
),
|
||||||
|
|
||||||
TP_printk("which=%d expires=%llu it_value=%ld.%ld it_interval=%ld.%ld",
|
TP_printk("which=%d expires=%llu it_value=%ld.%ld it_interval=%ld.%ld",
|
||||||
__entry->which, (unsigned long long)__entry->expires,
|
__entry->which, __entry->expires,
|
||||||
__entry->value_sec, __entry->value_usec,
|
__entry->value_sec, __entry->value_usec,
|
||||||
__entry->interval_sec, __entry->interval_usec)
|
__entry->interval_sec, __entry->interval_usec)
|
||||||
);
|
);
|
||||||
|
|
@ -305,14 +305,14 @@ TRACE_EVENT(itimer_state,
|
||||||
*/
|
*/
|
||||||
TRACE_EVENT(itimer_expire,
|
TRACE_EVENT(itimer_expire,
|
||||||
|
|
||||||
TP_PROTO(int which, struct pid *pid, cputime_t now),
|
TP_PROTO(int which, struct pid *pid, unsigned long long now),
|
||||||
|
|
||||||
TP_ARGS(which, pid, now),
|
TP_ARGS(which, pid, now),
|
||||||
|
|
||||||
TP_STRUCT__entry(
|
TP_STRUCT__entry(
|
||||||
__field( int , which )
|
__field( int , which )
|
||||||
__field( pid_t, pid )
|
__field( pid_t, pid )
|
||||||
__field( cputime_t, now )
|
__field( unsigned long long, now )
|
||||||
),
|
),
|
||||||
|
|
||||||
TP_fast_assign(
|
TP_fast_assign(
|
||||||
|
|
@ -322,7 +322,7 @@ TRACE_EVENT(itimer_expire,
|
||||||
),
|
),
|
||||||
|
|
||||||
TP_printk("which=%d pid=%d now=%llu", __entry->which,
|
TP_printk("which=%d pid=%d now=%llu", __entry->which,
|
||||||
(int) __entry->pid, (unsigned long long)__entry->now)
|
(int) __entry->pid, __entry->now)
|
||||||
);
|
);
|
||||||
|
|
||||||
#ifdef CONFIG_NO_HZ_COMMON
|
#ifdef CONFIG_NO_HZ_COMMON
|
||||||
|
|
|
||||||
|
|
@ -45,35 +45,35 @@ static struct timeval itimer_get_remtime(struct hrtimer *timer)
|
||||||
static void get_cpu_itimer(struct task_struct *tsk, unsigned int clock_id,
|
static void get_cpu_itimer(struct task_struct *tsk, unsigned int clock_id,
|
||||||
struct itimerval *const value)
|
struct itimerval *const value)
|
||||||
{
|
{
|
||||||
cputime_t cval, cinterval;
|
u64 val, interval;
|
||||||
struct cpu_itimer *it = &tsk->signal->it[clock_id];
|
struct cpu_itimer *it = &tsk->signal->it[clock_id];
|
||||||
|
|
||||||
spin_lock_irq(&tsk->sighand->siglock);
|
spin_lock_irq(&tsk->sighand->siglock);
|
||||||
|
|
||||||
cval = it->expires;
|
val = it->expires;
|
||||||
cinterval = it->incr;
|
interval = it->incr;
|
||||||
if (cval) {
|
if (val) {
|
||||||
struct task_cputime cputime;
|
struct task_cputime cputime;
|
||||||
cputime_t t;
|
u64 t;
|
||||||
|
|
||||||
thread_group_cputimer(tsk, &cputime);
|
thread_group_cputimer(tsk, &cputime);
|
||||||
if (clock_id == CPUCLOCK_PROF)
|
if (clock_id == CPUCLOCK_PROF)
|
||||||
t = nsecs_to_cputime(cputime.utime + cputime.stime);
|
t = cputime.utime + cputime.stime;
|
||||||
else
|
else
|
||||||
/* CPUCLOCK_VIRT */
|
/* CPUCLOCK_VIRT */
|
||||||
t = nsecs_to_cputime(cputime.utime);
|
t = cputime.utime;
|
||||||
|
|
||||||
if (cval < t)
|
if (val < t)
|
||||||
/* about to fire */
|
/* about to fire */
|
||||||
cval = cputime_one_jiffy;
|
val = TICK_NSEC;
|
||||||
else
|
else
|
||||||
cval = cval - t;
|
val -= t;
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_unlock_irq(&tsk->sighand->siglock);
|
spin_unlock_irq(&tsk->sighand->siglock);
|
||||||
|
|
||||||
cputime_to_timeval(cval, &value->it_value);
|
value->it_value = ns_to_timeval(val);
|
||||||
cputime_to_timeval(cinterval, &value->it_interval);
|
value->it_interval = ns_to_timeval(interval);
|
||||||
}
|
}
|
||||||
|
|
||||||
int do_getitimer(int which, struct itimerval *value)
|
int do_getitimer(int which, struct itimerval *value)
|
||||||
|
|
@ -129,55 +129,35 @@ enum hrtimer_restart it_real_fn(struct hrtimer *timer)
|
||||||
return HRTIMER_NORESTART;
|
return HRTIMER_NORESTART;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline u32 cputime_sub_ns(cputime_t ct, s64 real_ns)
|
|
||||||
{
|
|
||||||
struct timespec ts;
|
|
||||||
s64 cpu_ns;
|
|
||||||
|
|
||||||
cputime_to_timespec(ct, &ts);
|
|
||||||
cpu_ns = timespec_to_ns(&ts);
|
|
||||||
|
|
||||||
return (cpu_ns <= real_ns) ? 0 : cpu_ns - real_ns;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void set_cpu_itimer(struct task_struct *tsk, unsigned int clock_id,
|
static void set_cpu_itimer(struct task_struct *tsk, unsigned int clock_id,
|
||||||
const struct itimerval *const value,
|
const struct itimerval *const value,
|
||||||
struct itimerval *const ovalue)
|
struct itimerval *const ovalue)
|
||||||
{
|
{
|
||||||
cputime_t cval, nval, cinterval, ninterval;
|
u64 oval, nval, ointerval, ninterval;
|
||||||
s64 ns_ninterval, ns_nval;
|
|
||||||
u32 error, incr_error;
|
|
||||||
struct cpu_itimer *it = &tsk->signal->it[clock_id];
|
struct cpu_itimer *it = &tsk->signal->it[clock_id];
|
||||||
|
|
||||||
nval = timeval_to_cputime(&value->it_value);
|
nval = timeval_to_ns(&value->it_value);
|
||||||
ns_nval = timeval_to_ns(&value->it_value);
|
ninterval = timeval_to_ns(&value->it_interval);
|
||||||
ninterval = timeval_to_cputime(&value->it_interval);
|
|
||||||
ns_ninterval = timeval_to_ns(&value->it_interval);
|
|
||||||
|
|
||||||
error = cputime_sub_ns(nval, ns_nval);
|
|
||||||
incr_error = cputime_sub_ns(ninterval, ns_ninterval);
|
|
||||||
|
|
||||||
spin_lock_irq(&tsk->sighand->siglock);
|
spin_lock_irq(&tsk->sighand->siglock);
|
||||||
|
|
||||||
cval = it->expires;
|
oval = it->expires;
|
||||||
cinterval = it->incr;
|
ointerval = it->incr;
|
||||||
if (cval || nval) {
|
if (oval || nval) {
|
||||||
if (nval > 0)
|
if (nval > 0)
|
||||||
nval += cputime_one_jiffy;
|
nval += TICK_NSEC;
|
||||||
set_process_cpu_timer(tsk, clock_id, &nval, &cval);
|
set_process_cpu_timer(tsk, clock_id, &nval, &oval);
|
||||||
}
|
}
|
||||||
it->expires = nval;
|
it->expires = nval;
|
||||||
it->incr = ninterval;
|
it->incr = ninterval;
|
||||||
it->error = error;
|
|
||||||
it->incr_error = incr_error;
|
|
||||||
trace_itimer_state(clock_id == CPUCLOCK_VIRT ?
|
trace_itimer_state(clock_id == CPUCLOCK_VIRT ?
|
||||||
ITIMER_VIRTUAL : ITIMER_PROF, value, nval);
|
ITIMER_VIRTUAL : ITIMER_PROF, value, nval);
|
||||||
|
|
||||||
spin_unlock_irq(&tsk->sighand->siglock);
|
spin_unlock_irq(&tsk->sighand->siglock);
|
||||||
|
|
||||||
if (ovalue) {
|
if (ovalue) {
|
||||||
cputime_to_timeval(cval, &ovalue->it_value);
|
ovalue->it_value = ns_to_timeval(oval);
|
||||||
cputime_to_timeval(cinterval, &ovalue->it_interval);
|
ovalue->it_interval = ns_to_timeval(ointerval);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,10 +20,10 @@
|
||||||
*/
|
*/
|
||||||
void update_rlimit_cpu(struct task_struct *task, unsigned long rlim_new)
|
void update_rlimit_cpu(struct task_struct *task, unsigned long rlim_new)
|
||||||
{
|
{
|
||||||
cputime_t cputime = secs_to_cputime(rlim_new);
|
u64 nsecs = rlim_new * NSEC_PER_SEC;
|
||||||
|
|
||||||
spin_lock_irq(&task->sighand->siglock);
|
spin_lock_irq(&task->sighand->siglock);
|
||||||
set_process_cpu_timer(task, CPUCLOCK_PROF, &cputime, NULL);
|
set_process_cpu_timer(task, CPUCLOCK_PROF, &nsecs, NULL);
|
||||||
spin_unlock_irq(&task->sighand->siglock);
|
spin_unlock_irq(&task->sighand->siglock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -860,17 +860,11 @@ static void check_cpu_itimer(struct task_struct *tsk, struct cpu_itimer *it,
|
||||||
if (!it->expires)
|
if (!it->expires)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (cur_time >= cputime_to_nsecs(it->expires)) {
|
if (cur_time >= it->expires) {
|
||||||
if (it->incr) {
|
if (it->incr)
|
||||||
it->expires += it->incr;
|
it->expires += it->incr;
|
||||||
it->error += it->incr_error;
|
else
|
||||||
if (it->error >= TICK_NSEC) {
|
|
||||||
it->expires -= cputime_one_jiffy;
|
|
||||||
it->error -= TICK_NSEC;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
it->expires = 0;
|
it->expires = 0;
|
||||||
}
|
|
||||||
|
|
||||||
trace_itimer_expire(signo == SIGPROF ?
|
trace_itimer_expire(signo == SIGPROF ?
|
||||||
ITIMER_PROF : ITIMER_VIRTUAL,
|
ITIMER_PROF : ITIMER_VIRTUAL,
|
||||||
|
|
@ -878,9 +872,8 @@ static void check_cpu_itimer(struct task_struct *tsk, struct cpu_itimer *it,
|
||||||
__group_send_sig_info(signo, SEND_SIG_PRIV, tsk);
|
__group_send_sig_info(signo, SEND_SIG_PRIV, tsk);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (it->expires && (!*expires || cputime_to_nsecs(it->expires) < *expires)) {
|
if (it->expires && (!*expires || it->expires < *expires))
|
||||||
*expires = cputime_to_nsecs(it->expires);
|
*expires = it->expires;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -1174,9 +1167,9 @@ void run_posix_cpu_timers(struct task_struct *tsk)
|
||||||
* The tsk->sighand->siglock must be held by the caller.
|
* The tsk->sighand->siglock must be held by the caller.
|
||||||
*/
|
*/
|
||||||
void set_process_cpu_timer(struct task_struct *tsk, unsigned int clock_idx,
|
void set_process_cpu_timer(struct task_struct *tsk, unsigned int clock_idx,
|
||||||
cputime_t *newval, cputime_t *oldval)
|
u64 *newval, u64 *oldval)
|
||||||
{
|
{
|
||||||
u64 now, new;
|
u64 now;
|
||||||
|
|
||||||
WARN_ON_ONCE(clock_idx == CPUCLOCK_SCHED);
|
WARN_ON_ONCE(clock_idx == CPUCLOCK_SCHED);
|
||||||
cpu_timer_sample_group(clock_idx, tsk, &now);
|
cpu_timer_sample_group(clock_idx, tsk, &now);
|
||||||
|
|
@ -1188,33 +1181,31 @@ void set_process_cpu_timer(struct task_struct *tsk, unsigned int clock_idx,
|
||||||
* it to be absolute.
|
* it to be absolute.
|
||||||
*/
|
*/
|
||||||
if (*oldval) {
|
if (*oldval) {
|
||||||
if (cputime_to_nsecs(*oldval) <= now) {
|
if (*oldval <= now) {
|
||||||
/* Just about to fire. */
|
/* Just about to fire. */
|
||||||
*oldval = cputime_one_jiffy;
|
*oldval = TICK_NSEC;
|
||||||
} else {
|
} else {
|
||||||
*oldval -= nsecs_to_cputime(now);
|
*oldval -= now;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!*newval)
|
if (!*newval)
|
||||||
return;
|
return;
|
||||||
*newval += nsecs_to_cputime(now);
|
*newval += now;
|
||||||
}
|
}
|
||||||
|
|
||||||
new = cputime_to_nsecs(*newval);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Update expiration cache if we are the earliest timer, or eventually
|
* Update expiration cache if we are the earliest timer, or eventually
|
||||||
* RLIMIT_CPU limit is earlier than prof_exp cpu timer expire.
|
* RLIMIT_CPU limit is earlier than prof_exp cpu timer expire.
|
||||||
*/
|
*/
|
||||||
switch (clock_idx) {
|
switch (clock_idx) {
|
||||||
case CPUCLOCK_PROF:
|
case CPUCLOCK_PROF:
|
||||||
if (expires_gt(tsk->signal->cputime_expires.prof_exp, new))
|
if (expires_gt(tsk->signal->cputime_expires.prof_exp, *newval))
|
||||||
tsk->signal->cputime_expires.prof_exp = new;
|
tsk->signal->cputime_expires.prof_exp = *newval;
|
||||||
break;
|
break;
|
||||||
case CPUCLOCK_VIRT:
|
case CPUCLOCK_VIRT:
|
||||||
if (expires_gt(tsk->signal->cputime_expires.virt_exp, new))
|
if (expires_gt(tsk->signal->cputime_expires.virt_exp, *newval))
|
||||||
tsk->signal->cputime_expires.virt_exp = new;
|
tsk->signal->cputime_expires.virt_exp = *newval;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user