diff options
| -rw-r--r-- | include/linux/atomic.h | 21 | ||||
| -rw-r--r-- | include/linux/perf_event.h | 6 | ||||
| -rw-r--r-- | include/linux/posix-timers.h | 3 | ||||
| -rw-r--r-- | include/linux/sched.h | 11 | ||||
| -rw-r--r-- | include/linux/tick.h | 97 | ||||
| -rw-r--r-- | include/trace/events/timer.h | 36 | ||||
| -rw-r--r-- | kernel/events/core.c | 65 | ||||
| -rw-r--r-- | kernel/sched/clock.c | 5 | ||||
| -rw-r--r-- | kernel/sched/core.c | 49 | ||||
| -rw-r--r-- | kernel/sched/rt.c | 16 | ||||
| -rw-r--r-- | kernel/sched/sched.h | 48 | ||||
| -rw-r--r-- | kernel/time/posix-cpu-timers.c | 52 | ||||
| -rw-r--r-- | kernel/time/tick-sched.c | 175 | ||||
| -rw-r--r-- | kernel/time/tick-sched.h | 1 |
14 files changed, 424 insertions, 161 deletions
diff --git a/include/linux/atomic.h b/include/linux/atomic.h index 301de78d65f7..6c502cb13c95 100644 --- a/include/linux/atomic.h +++ b/include/linux/atomic.h | |||
| @@ -548,6 +548,27 @@ static inline int atomic_dec_if_positive(atomic_t *v) | |||
| 548 | } | 548 | } |
| 549 | #endif | 549 | #endif |
| 550 | 550 | ||
| 551 | /** | ||
| 552 | * fetch_or - perform *ptr |= mask and return old value of *ptr | ||
| 553 | * @ptr: pointer to value | ||
| 554 | * @mask: mask to OR on the value | ||
| 555 | * | ||
| 556 | * cmpxchg based fetch_or, macro so it works for different integer types | ||
| 557 | */ | ||
| 558 | #ifndef fetch_or | ||
| 559 | #define fetch_or(ptr, mask) \ | ||
| 560 | ({ typeof(*(ptr)) __old, __val = *(ptr); \ | ||
| 561 | for (;;) { \ | ||
| 562 | __old = cmpxchg((ptr), __val, __val | (mask)); \ | ||
| 563 | if (__old == __val) \ | ||
| 564 | break; \ | ||
| 565 | __val = __old; \ | ||
| 566 | } \ | ||
| 567 | __old; \ | ||
| 568 | }) | ||
| 569 | #endif | ||
| 570 | |||
| 571 | |||
| 551 | #ifdef CONFIG_GENERIC_ATOMIC64 | 572 | #ifdef CONFIG_GENERIC_ATOMIC64 |
| 552 | #include <asm-generic/atomic64.h> | 573 | #include <asm-generic/atomic64.h> |
| 553 | #endif | 574 | #endif |
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index f5c5a3fa2c81..6e44efc19a6a 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h | |||
| @@ -1109,12 +1109,6 @@ static inline void perf_event_task_tick(void) { } | |||
| 1109 | static inline int perf_event_release_kernel(struct perf_event *event) { return 0; } | 1109 | static inline int perf_event_release_kernel(struct perf_event *event) { return 0; } |
| 1110 | #endif | 1110 | #endif |
| 1111 | 1111 | ||
| 1112 | #if defined(CONFIG_PERF_EVENTS) && defined(CONFIG_NO_HZ_FULL) | ||
| 1113 | extern bool perf_event_can_stop_tick(void); | ||
| 1114 | #else | ||
| 1115 | static inline bool perf_event_can_stop_tick(void) { return true; } | ||
| 1116 | #endif | ||
| 1117 | |||
| 1118 | #if defined(CONFIG_PERF_EVENTS) && defined(CONFIG_CPU_SUP_INTEL) | 1112 | #if defined(CONFIG_PERF_EVENTS) && defined(CONFIG_CPU_SUP_INTEL) |
| 1119 | extern void perf_restore_debug_store(void); | 1113 | extern void perf_restore_debug_store(void); |
| 1120 | #else | 1114 | #else |
diff --git a/include/linux/posix-timers.h b/include/linux/posix-timers.h index 907f3fd191ac..62d44c176071 100644 --- a/include/linux/posix-timers.h +++ b/include/linux/posix-timers.h | |||
| @@ -128,9 +128,6 @@ void posix_cpu_timer_schedule(struct k_itimer *timer); | |||
| 128 | void run_posix_cpu_timers(struct task_struct *task); | 128 | void run_posix_cpu_timers(struct task_struct *task); |
| 129 | void posix_cpu_timers_exit(struct task_struct *task); | 129 | void posix_cpu_timers_exit(struct task_struct *task); |
| 130 | void posix_cpu_timers_exit_group(struct task_struct *task); | 130 | void posix_cpu_timers_exit_group(struct task_struct *task); |
| 131 | |||
| 132 | bool posix_cpu_timers_can_stop_tick(struct task_struct *tsk); | ||
| 133 | |||
| 134 | void set_process_cpu_timer(struct task_struct *task, unsigned int clock_idx, | 131 | void set_process_cpu_timer(struct task_struct *task, unsigned int clock_idx, |
| 135 | cputime_t *newval, cputime_t *oldval); | 132 | cputime_t *newval, cputime_t *oldval); |
| 136 | 133 | ||
diff --git a/include/linux/sched.h b/include/linux/sched.h index a10494a94cc3..2b10348806d8 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h | |||
| @@ -719,6 +719,10 @@ struct signal_struct { | |||
| 719 | /* Earliest-expiration cache. */ | 719 | /* Earliest-expiration cache. */ |
| 720 | struct task_cputime cputime_expires; | 720 | struct task_cputime cputime_expires; |
| 721 | 721 | ||
| 722 | #ifdef CONFIG_NO_HZ_FULL | ||
| 723 | unsigned long tick_dep_mask; | ||
| 724 | #endif | ||
| 725 | |||
| 722 | struct list_head cpu_timers[3]; | 726 | struct list_head cpu_timers[3]; |
| 723 | 727 | ||
| 724 | struct pid *tty_old_pgrp; | 728 | struct pid *tty_old_pgrp; |
| @@ -1542,6 +1546,10 @@ struct task_struct { | |||
| 1542 | VTIME_SYS, | 1546 | VTIME_SYS, |
| 1543 | } vtime_snap_whence; | 1547 | } vtime_snap_whence; |
| 1544 | #endif | 1548 | #endif |
| 1549 | |||
| 1550 | #ifdef CONFIG_NO_HZ_FULL | ||
| 1551 | unsigned long tick_dep_mask; | ||
| 1552 | #endif | ||
| 1545 | unsigned long nvcsw, nivcsw; /* context switch counts */ | 1553 | unsigned long nvcsw, nivcsw; /* context switch counts */ |
| 1546 | u64 start_time; /* monotonic time in nsec */ | 1554 | u64 start_time; /* monotonic time in nsec */ |
| 1547 | u64 real_start_time; /* boot based time in nsec */ | 1555 | u64 real_start_time; /* boot based time in nsec */ |
| @@ -2356,10 +2364,7 @@ static inline void wake_up_nohz_cpu(int cpu) { } | |||
| 2356 | #endif | 2364 | #endif |
| 2357 | 2365 | ||
| 2358 | #ifdef CONFIG_NO_HZ_FULL | 2366 | #ifdef CONFIG_NO_HZ_FULL |
| 2359 | extern bool sched_can_stop_tick(void); | ||
| 2360 | extern u64 scheduler_tick_max_deferment(void); | 2367 | extern u64 scheduler_tick_max_deferment(void); |
| 2361 | #else | ||
| 2362 | static inline bool sched_can_stop_tick(void) { return false; } | ||
| 2363 | #endif | 2368 | #endif |
| 2364 | 2369 | ||
| 2365 | #ifdef CONFIG_SCHED_AUTOGROUP | 2370 | #ifdef CONFIG_SCHED_AUTOGROUP |
diff --git a/include/linux/tick.h b/include/linux/tick.h index 97fd4e543846..21f73649a4dc 100644 --- a/include/linux/tick.h +++ b/include/linux/tick.h | |||
| @@ -97,6 +97,19 @@ static inline void tick_broadcast_exit(void) | |||
| 97 | tick_broadcast_oneshot_control(TICK_BROADCAST_EXIT); | 97 | tick_broadcast_oneshot_control(TICK_BROADCAST_EXIT); |
| 98 | } | 98 | } |
| 99 | 99 | ||
| 100 | enum tick_dep_bits { | ||
| 101 | TICK_DEP_BIT_POSIX_TIMER = 0, | ||
| 102 | TICK_DEP_BIT_PERF_EVENTS = 1, | ||
| 103 | TICK_DEP_BIT_SCHED = 2, | ||
| 104 | TICK_DEP_BIT_CLOCK_UNSTABLE = 3 | ||
| 105 | }; | ||
| 106 | |||
| 107 | #define TICK_DEP_MASK_NONE 0 | ||
| 108 | #define TICK_DEP_MASK_POSIX_TIMER (1 << TICK_DEP_BIT_POSIX_TIMER) | ||
| 109 | #define TICK_DEP_MASK_PERF_EVENTS (1 << TICK_DEP_BIT_PERF_EVENTS) | ||
| 110 | #define TICK_DEP_MASK_SCHED (1 << TICK_DEP_BIT_SCHED) | ||
| 111 | #define TICK_DEP_MASK_CLOCK_UNSTABLE (1 << TICK_DEP_BIT_CLOCK_UNSTABLE) | ||
| 112 | |||
| 100 | #ifdef CONFIG_NO_HZ_COMMON | 113 | #ifdef CONFIG_NO_HZ_COMMON |
| 101 | extern int tick_nohz_enabled; | 114 | extern int tick_nohz_enabled; |
| 102 | extern int tick_nohz_tick_stopped(void); | 115 | extern int tick_nohz_tick_stopped(void); |
| @@ -154,9 +167,73 @@ static inline int housekeeping_any_cpu(void) | |||
| 154 | return cpumask_any_and(housekeeping_mask, cpu_online_mask); | 167 | return cpumask_any_and(housekeeping_mask, cpu_online_mask); |
| 155 | } | 168 | } |
| 156 | 169 | ||
| 157 | extern void tick_nohz_full_kick(void); | 170 | extern void tick_nohz_dep_set(enum tick_dep_bits bit); |
| 171 | extern void tick_nohz_dep_clear(enum tick_dep_bits bit); | ||
| 172 | extern void tick_nohz_dep_set_cpu(int cpu, enum tick_dep_bits bit); | ||
| 173 | extern void tick_nohz_dep_clear_cpu(int cpu, enum tick_dep_bits bit); | ||
| 174 | extern void tick_nohz_dep_set_task(struct task_struct *tsk, | ||
| 175 | enum tick_dep_bits bit); | ||
| 176 | extern void tick_nohz_dep_clear_task(struct task_struct *tsk, | ||
| 177 | enum tick_dep_bits bit); | ||
| 178 | extern void tick_nohz_dep_set_signal(struct signal_struct *signal, | ||
| 179 | enum tick_dep_bits bit); | ||
| 180 | extern void tick_nohz_dep_clear_signal(struct signal_struct *signal, | ||
| 181 | enum tick_dep_bits bit); | ||
| 182 | |||
| 183 | /* | ||
| 184 | * The below are tick_nohz_[set,clear]_dep() wrappers that optimize off-cases | ||
| 185 | * on top of static keys. | ||
| 186 | */ | ||
| 187 | static inline void tick_dep_set(enum tick_dep_bits bit) | ||
| 188 | { | ||
| 189 | if (tick_nohz_full_enabled()) | ||
| 190 | tick_nohz_dep_set(bit); | ||
| 191 | } | ||
| 192 | |||
| 193 | static inline void tick_dep_clear(enum tick_dep_bits bit) | ||
| 194 | { | ||
| 195 | if (tick_nohz_full_enabled()) | ||
| 196 | tick_nohz_dep_clear(bit); | ||
| 197 | } | ||
| 198 | |||
| 199 | static inline void tick_dep_set_cpu(int cpu, enum tick_dep_bits bit) | ||
| 200 | { | ||
| 201 | if (tick_nohz_full_cpu(cpu)) | ||
| 202 | tick_nohz_dep_set_cpu(cpu, bit); | ||
| 203 | } | ||
| 204 | |||
| 205 | static inline void tick_dep_clear_cpu(int cpu, enum tick_dep_bits bit) | ||
| 206 | { | ||
| 207 | if (tick_nohz_full_cpu(cpu)) | ||
| 208 | tick_nohz_dep_clear_cpu(cpu, bit); | ||
| 209 | } | ||
| 210 | |||
| 211 | static inline void tick_dep_set_task(struct task_struct *tsk, | ||
| 212 | enum tick_dep_bits bit) | ||
| 213 | { | ||
| 214 | if (tick_nohz_full_enabled()) | ||
| 215 | tick_nohz_dep_set_task(tsk, bit); | ||
| 216 | } | ||
| 217 | static inline void tick_dep_clear_task(struct task_struct *tsk, | ||
| 218 | enum tick_dep_bits bit) | ||
| 219 | { | ||
| 220 | if (tick_nohz_full_enabled()) | ||
| 221 | tick_nohz_dep_clear_task(tsk, bit); | ||
| 222 | } | ||
| 223 | static inline void tick_dep_set_signal(struct signal_struct *signal, | ||
| 224 | enum tick_dep_bits bit) | ||
| 225 | { | ||
| 226 | if (tick_nohz_full_enabled()) | ||
| 227 | tick_nohz_dep_set_signal(signal, bit); | ||
