diff options
Diffstat (limited to 'kernel/sched.c')
| -rw-r--r-- | kernel/sched.c | 43 |
1 files changed, 40 insertions, 3 deletions
diff --git a/kernel/sched.c b/kernel/sched.c index 9b302e355791..9e01b7100ef6 100644 --- a/kernel/sched.c +++ b/kernel/sched.c | |||
| @@ -491,6 +491,7 @@ struct rq { | |||
| 491 | struct mm_struct *prev_mm; | 491 | struct mm_struct *prev_mm; |
| 492 | 492 | ||
| 493 | u64 clock; | 493 | u64 clock; |
| 494 | u64 clock_task; | ||
| 494 | 495 | ||
| 495 | atomic_t nr_iowait; | 496 | atomic_t nr_iowait; |
| 496 | 497 | ||
| @@ -641,10 +642,19 @@ static inline struct task_group *task_group(struct task_struct *p) | |||
| 641 | 642 | ||
| 642 | #endif /* CONFIG_CGROUP_SCHED */ | 643 | #endif /* CONFIG_CGROUP_SCHED */ |
| 643 | 644 | ||
| 645 | static u64 irq_time_cpu(int cpu); | ||
| 646 | |||
| 644 | inline void update_rq_clock(struct rq *rq) | 647 | inline void update_rq_clock(struct rq *rq) |
| 645 | { | 648 | { |
| 646 | if (!rq->skip_clock_update) | 649 | if (!rq->skip_clock_update) { |
| 647 | rq->clock = sched_clock_cpu(cpu_of(rq)); | 650 | int cpu = cpu_of(rq); |
| 651 | u64 irq_time; | ||
| 652 | |||
| 653 | rq->clock = sched_clock_cpu(cpu); | ||
| 654 | irq_time = irq_time_cpu(cpu); | ||
| 655 | if (rq->clock - irq_time > rq->clock_task) | ||
| 656 | rq->clock_task = rq->clock - irq_time; | ||
| 657 | } | ||
| 648 | } | 658 | } |
| 649 | 659 | ||
| 650 | /* | 660 | /* |
| @@ -1910,6 +1920,18 @@ static void deactivate_task(struct rq *rq, struct task_struct *p, int flags) | |||
| 1910 | 1920 | ||
| 1911 | #ifdef CONFIG_IRQ_TIME_ACCOUNTING | 1921 | #ifdef CONFIG_IRQ_TIME_ACCOUNTING |
| 1912 | 1922 | ||
| 1923 | /* | ||
| 1924 | * There are no locks covering percpu hardirq/softirq time. | ||
| 1925 | * They are only modified in account_system_vtime, on corresponding CPU | ||
| 1926 | * with interrupts disabled. So, writes are safe. | ||
| 1927 | * They are read and saved off onto struct rq in update_rq_clock(). | ||
| 1928 | * This may result in other CPU reading this CPU's irq time and can | ||
| 1929 | * race with irq/account_system_vtime on this CPU. We would either get old | ||
| 1930 | * or new value (or semi updated value on 32 bit) with a side effect of | ||
| 1931 | * accounting a slice of irq time to wrong task when irq is in progress | ||
| 1932 | * while we read rq->clock. That is a worthy compromise in place of having | ||
| 1933 | * locks on each irq in account_system_time. | ||
| 1934 | */ | ||
| 1913 | static DEFINE_PER_CPU(u64, cpu_hardirq_time); | 1935 | static DEFINE_PER_CPU(u64, cpu_hardirq_time); |
| 1914 | static DEFINE_PER_CPU(u64, cpu_softirq_time); | 1936 | static DEFINE_PER_CPU(u64, cpu_softirq_time); |
| 1915 | 1937 | ||
| @@ -1926,6 +1948,14 @@ void disable_sched_clock_irqtime(void) | |||
| 1926 | sched_clock_irqtime = 0; | 1948 | sched_clock_irqtime = 0; |
| 1927 | } | 1949 | } |
| 1928 | 1950 | ||
| 1951 | static u64 irq_time_cpu(int cpu) | ||
| 1952 | { | ||
| 1953 | if (!sched_clock_irqtime) | ||
| 1954 | return 0; | ||
| 1955 | |||
| 1956 | return per_cpu(cpu_softirq_time, cpu) + per_cpu(cpu_hardirq_time, cpu); | ||
| 1957 | } | ||
| 1958 | |||
| 1929 | void account_system_vtime(struct task_struct *curr) | 1959 | void account_system_vtime(struct task_struct *curr) |
| 1930 | { | 1960 | { |
| 1931 | unsigned long flags; | 1961 | unsigned long flags; |
| @@ -1955,6 +1985,13 @@ void account_system_vtime(struct task_struct *curr) | |||
| 1955 | local_irq_restore(flags); | 1985 | local_irq_restore(flags); |
| 1956 | } | 1986 | } |
| 1957 | 1987 | ||
| 1988 | #else | ||
| 1989 | |||
| 1990 | static u64 irq_time_cpu(int cpu) | ||
| 1991 | { | ||
| 1992 | return 0; | ||
| 1993 | } | ||
| 1994 | |||
| 1958 | #endif | 1995 | #endif |
| 1959 | 1996 | ||
| 1960 | #include "sched_idletask.c" | 1997 | #include "sched_idletask.c" |
| @@ -3322,7 +3359,7 @@ static u64 do_task_delta_exec(struct task_struct *p, struct rq *rq) | |||
| 3322 | 3359 | ||
| 3323 | if (task_current(rq, p)) { | 3360 | if (task_current(rq, p)) { |
| 3324 | update_rq_clock(rq); | 3361 | update_rq_clock(rq); |
| 3325 | ns = rq->clock - p->se.exec_start; | 3362 | ns = rq->clock_task - p->se.exec_start; |
| 3326 | if ((s64)ns < 0) | 3363 | if ((s64)ns < 0) |
| 3327 | ns = 0; | 3364 | ns = 0; |
| 3328 | } | 3365 | } |
