diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-12-19 13:37:37 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-12-19 13:37:37 -0500 |
| commit | 21228e455756be11fbbcae7e1a184ad9d842f687 (patch) | |
| tree | 594ff10478aed5f264294e8a718e80a3e44ab34c /kernel | |
| parent | 0a59228168d3722b71f8e3dbc623316fb4be78f4 (diff) | |
| parent | 8e92c20183ed0579d94501311b81c42b65cb2129 (diff) | |
Merge branch 'sched-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip
* 'sched-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
sched: Fix the irqtime code for 32bit
sched: Fix the irqtime code to deal with u64 wraps
nohz: Fix get_next_timer_interrupt() vs cpu hotplug
Sched: fix skip_clock_update optimization
sched: Cure more NO_HZ load average woes
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/fork.c | 1 | ||||
| -rw-r--r-- | kernel/sched.c | 288 | ||||
| -rw-r--r-- | kernel/timer.c | 8 |
3 files changed, 245 insertions, 52 deletions
diff --git a/kernel/fork.c b/kernel/fork.c index 3b159c5991b7..5447dc7defa9 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
| @@ -273,6 +273,7 @@ static struct task_struct *dup_task_struct(struct task_struct *orig) | |||
| 273 | 273 | ||
| 274 | setup_thread_stack(tsk, orig); | 274 | setup_thread_stack(tsk, orig); |
| 275 | clear_user_return_notifier(tsk); | 275 | clear_user_return_notifier(tsk); |
| 276 | clear_tsk_need_resched(tsk); | ||
| 276 | stackend = end_of_stack(tsk); | 277 | stackend = end_of_stack(tsk); |
| 277 | *stackend = STACK_END_MAGIC; /* for overflow detection */ | 278 | *stackend = STACK_END_MAGIC; /* for overflow detection */ |
| 278 | 279 | ||
diff --git a/kernel/sched.c b/kernel/sched.c index dc91a4d09ac3..456c99054160 100644 --- a/kernel/sched.c +++ b/kernel/sched.c | |||
| @@ -636,22 +636,18 @@ static inline struct task_group *task_group(struct task_struct *p) | |||
| 636 | 636 | ||
| 637 | #endif /* CONFIG_CGROUP_SCHED */ | 637 | #endif /* CONFIG_CGROUP_SCHED */ |
| 638 | 638 | ||
| 639 | static u64 irq_time_cpu(int cpu); | 639 | static void update_rq_clock_task(struct rq *rq, s64 delta); |
| 640 | static void sched_irq_time_avg_update(struct rq *rq, u64 irq_time); | ||
| 641 | 640 | ||
| 642 | inline void update_rq_clock(struct rq *rq) | 641 | static void update_rq_clock(struct rq *rq) |
| 643 | { | 642 | { |
| 644 | if (!rq->skip_clock_update) { | 643 | s64 delta; |
| 645 | int cpu = cpu_of(rq); | ||
| 646 | u64 irq_time; | ||
| 647 | 644 | ||
| 648 | rq->clock = sched_clock_cpu(cpu); | 645 | if (rq->skip_clock_update) |
| 649 | irq_time = irq_time_cpu(cpu); | 646 | return; |
| 650 | if (rq->clock - irq_time > rq->clock_task) | ||
| 651 | rq->clock_task = rq->clock - irq_time; | ||
| 652 | 647 | ||
| 653 | sched_irq_time_avg_update(rq, irq_time); | 648 | delta = sched_clock_cpu(cpu_of(rq)) - rq->clock; |
| 654 | } | 649 | rq->clock += delta; |
| 650 | update_rq_clock_task(rq, delta); | ||
| 655 | } | 651 | } |
| 656 | 652 | ||
| 657 | /* | 653 | /* |
| @@ -1924,10 +1920,9 @@ static void deactivate_task(struct rq *rq, struct task_struct *p, int flags) | |||
| 1924 | * They are read and saved off onto struct rq in update_rq_clock(). | 1920 | * They are read and saved off onto struct rq in update_rq_clock(). |
| 1925 | * This may result in other CPU reading this CPU's irq time and can | 1921 | * This may result in other CPU reading this CPU's irq time and can |
| 1926 | * race with irq/account_system_vtime on this CPU. We would either get old | 1922 | * race with irq/account_system_vtime on this CPU. We would either get old |
| 1927 | * or new value (or semi updated value on 32 bit) with a side effect of | 1923 | * or new value with a side effect of accounting a slice of irq time to wrong |
| 1928 | * accounting a slice of irq time to wrong task when irq is in progress | 1924 | * task when irq is in progress while we read rq->clock. That is a worthy |
| 1929 | * while we read rq->clock. That is a worthy compromise in place of having | 1925 | * compromise in place of having locks on each irq in account_system_time. |
| 1930 | * locks on each irq in account_system_time. | ||
| 1931 | */ | 1926 | */ |
| 1932 | static DEFINE_PER_CPU(u64, cpu_hardirq_time); | 1927 | static DEFINE_PER_CPU(u64, cpu_hardirq_time); |
| 1933 | static DEFINE_PER_CPU(u64, cpu_softirq_time); | 1928 | static DEFINE_PER_CPU(u64, cpu_softirq_time); |
| @@ -1945,19 +1940,58 @@ void disable_sched_clock_irqtime(void) | |||
| 1945 | sched_clock_irqtime = 0; | 1940 | sched_clock_irqtime = 0; |
| 1946 | } | 1941 | } |
| 1947 | 1942 | ||
| 1948 | static u64 irq_time_cpu(int cpu) | 1943 | #ifndef CONFIG_64BIT |
| 1944 | static DEFINE_PER_CPU(seqcount_t, irq_time_seq); | ||
| 1945 | |||
| 1946 | static inline void irq_time_write_begin(void) | ||
| 1949 | { | 1947 | { |
| 1950 | if (!sched_clock_irqtime) | 1948 | __this_cpu_inc(irq_time_seq.sequence); |
| 1951 | return 0; | 1949 | smp_wmb(); |
| 1950 | } | ||
| 1951 | |||
| 1952 | static inline void irq_time_write_end(void) | ||
| 1953 | { | ||
| 1954 | smp_wmb(); | ||
| 1955 | __this_cpu_inc(irq_time_seq.sequence); | ||
| 1956 | } | ||
| 1957 | |||
| 1958 | static inline u64 irq_time_read(int cpu) | ||
| 1959 | { | ||
| 1960 | u64 irq_time; | ||
| 1961 | unsigned seq; | ||
| 1952 | 1962 | ||
| 1963 | do { | ||
| 1964 | seq = read_seqcount_begin(&per_cpu(irq_time_seq, cpu)); | ||
| 1965 | irq_time = per_cpu(cpu_softirq_time, cpu) + | ||
| 1966 | per_cpu(cpu_hardirq_time, cpu); | ||
| 1967 | } while (read_seqcount_retry(&per_cpu(irq_time_seq, cpu), seq)); | ||
| 1968 | |||
| 1969 | return irq_time; | ||
| 1970 | } | ||
| 1971 | #else /* CONFIG_64BIT */ | ||
| 1972 | static inline void irq_time_write_begin(void) | ||
| 1973 | { | ||
| 1974 | } | ||
| 1975 | |||
| 1976 | static inline void irq_time_write_end(void) | ||
| 1977 | { | ||
| 1978 | } | ||
| 1979 | |||
| 1980 | static inline u64 irq_time_read(int cpu) | ||
| 1981 | { | ||
| 1953 | return per_cpu(cpu_softirq_time, cpu) + per_cpu(cpu_hardirq_time, cpu); | 1982 | return per_cpu(cpu_softirq_time, cpu) + per_cpu(cpu_hardirq_time, cpu); |
| 1954 | } | 1983 | } |
| 1984 | #endif /* CONFIG_64BIT */ | ||
| 1955 | 1985 | ||
| 1986 | /* | ||
| 1987 | * Called before incrementing preempt_count on {soft,}irq_enter | ||
| 1988 | * and before decrementing preempt_count on {soft,}irq_exit. | ||
| 1989 | */ | ||
| 1956 | void account_system_vtime(struct task_struct *curr) | 1990 | void account_system_vtime(struct task_struct *curr) |
| 1957 | { | 1991 | { |
| 1958 | unsigned long flags; | 1992 | unsigned long flags; |
| 1993 | s64 delta; | ||
| 1959 | int cpu; | 1994 | int cpu; |
| 1960 | u64 now, delta; | ||
| 1961 | 1995 | ||
| 1962 | if (!sched_clock_irqtime) | 1996 | if (!sched_clock_irqtime) |
| 1963 | return; | 1997 | return; |
| @@ -1965,9 +1999,10 @@ void account_system_vtime(struct task_struct *curr) | |||
| 1965 | local_irq_save(flags); | 1999 | local_irq_save(flags); |
| 1966 | 2000 | ||
| 1967 | cpu = smp_processor_id(); | 2001 | cpu = smp_processor_id(); |
| 1968 | now = sched_clock_cpu(cpu); | 2002 | delta = sched_clock_cpu(cpu) - __this_cpu_read(irq_start_time); |
| 1969 | delta = now - per_cpu(irq_start_time, cpu); | 2003 | __this_cpu_add(irq_start_time, delta); |
| 1970 | per_cpu(irq_start_time, cpu) = now; | 2004 | |
| 2005 | irq_time_write_begin(); | ||
| 1971 | /* | 2006 | /* |
| 1972 | * We do not account for softirq time from ksoftirqd here. | 2007 | * We do not account for softirq time from ksoftirqd here. |
| 1973 | * We want to continue accounting softirq time to ksoftirqd thread | 2008 | * We want to continue accounting softirq time to ksoftirqd thread |
| @@ -1975,33 +2010,55 @@ void account_system_vtime(struct task_struct *curr) | |||
| 1975 | * that do not consume any time, but still wants to run. | 2010 | * that do not consume any time, but still wants to run. |
| 1976 | */ | 2011 | */ |
| 1977 | if (hardirq_count()) | 2012 | if (hardirq_count()) |
| 1978 | per_cpu(cpu_hardirq_time, cpu) += delta; | 2013 | __this_cpu_add(cpu_hardirq_time, delta); |
| 1979 | else if (in_serving_softirq() && !(curr->flags & PF_KSOFTIRQD)) | 2014 | else if (in_serving_softirq() && !(curr->flags & PF_KSOFTIRQD)) |
| 1980 | per_cpu(cpu_softirq_time, cpu) += delta; | 2015 | __this_cpu_add(cpu_softirq_time, delta); |
| 1981 | 2016 | ||
| 2017 | irq_time_write_end(); | ||
| 1982 | local_irq_restore(flags); | 2018 | local_irq_restore(flags); |
| 1983 | } | 2019 | } |
| 1984 | EXPORT_SYMBOL_GPL(account_system_vtime); | 2020 | EXPORT_SYMBOL_GPL(account_system_vtime); |
| 1985 | 2021 | ||
| 1986 | static void sched_irq_time_avg_update(struct rq *rq, u64 curr_irq_time) | 2022 | static void update_rq_clock_task(struct rq *rq, s64 delta) |
| 1987 | { | 2023 | { |
| 1988 | if (sched_clock_irqtime && sched_feat(NONIRQ_POWER)) { | 2024 | s64 irq_delta; |
| 1989 | u64 delta_irq = curr_irq_time - rq->prev_irq_time; | 2025 | |
| 1990 | rq->prev_irq_time = curr_irq_time; | 2026 | irq_delta = irq_time_read(cpu_of(rq)) - rq->prev_irq_time; |
| 1991 | sched_rt_avg_update(rq, delta_irq); | 2027 | |
| 1992 | } | 2028 | /* |
| 2029 | * Since irq_time is only updated on {soft,}irq_exit, we might run into | ||
| 2030 | * this case when a previous update_rq_clock() happened inside a | ||
| 2031 | * {soft,}irq region. | ||
| 2032 | * | ||
| 2033 | * When this happens, we stop ->clock_task and only update the | ||
| 2034 | * prev_irq_time stamp to account for the part that fit, so that a next | ||
| 2035 | * update will consume the rest. This ensures ->clock_task is | ||
| 2036 | * monotonic. | ||
| 2037 | * | ||
| 2038 | * It does however cause some slight miss-attribution of {soft,}irq | ||
| 2039 | * time, a more accurate solution would be to update the irq_time using | ||
| 2040 | * the current rq->clock timestamp, except that would require using | ||
| 2041 | * atomic ops. | ||
| 2042 | */ | ||
| 2043 | if (irq_delta > delta) | ||
| 2044 | irq_delta = delta; | ||
| 2045 | |||
| 2046 | rq->prev_irq_time += irq_delta; | ||
| 2047 | delta -= irq_delta; | ||
| 2048 | rq->clock_task += delta; | ||
