aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/atomic.h21
-rw-r--r--include/linux/perf_event.h6
-rw-r--r--include/linux/posix-timers.h3
-rw-r--r--include/linux/sched.h11
-rw-r--r--include/linux/tick.h97
-rw-r--r--include/trace/events/timer.h36
-rw-r--r--kernel/events/core.c65
-rw-r--r--kernel/sched/clock.c5
-rw-r--r--kernel/sched/core.c49
-rw-r--r--kernel/sched/rt.c16
-rw-r--r--kernel/sched/sched.h48
-rw-r--r--kernel/time/posix-cpu-timers.c52
-rw-r--r--kernel/time/tick-sched.c175
-rw-r--r--kernel/time/tick-sched.h1
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) { }
1109static inline int perf_event_release_kernel(struct perf_event *event) { return 0; } 1109static 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)
1113extern bool perf_event_can_stop_tick(void);
1114#else
1115static 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)
1119extern void perf_restore_debug_store(void); 1113extern 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);
128void run_posix_cpu_timers(struct task_struct *task); 128void run_posix_cpu_timers(struct task_struct *task);
129void posix_cpu_timers_exit(struct task_struct *task); 129void posix_cpu_timers_exit(struct task_struct *task);
130void posix_cpu_timers_exit_group(struct task_struct *task); 130void posix_cpu_timers_exit_group(struct task_struct *task);
131
132bool posix_cpu_timers_can_stop_tick(struct task_struct *tsk);
133
134void set_process_cpu_timer(struct task_struct *task, unsigned int clock_idx, 131void 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
2359extern bool sched_can_stop_tick(void);
2360extern u64 scheduler_tick_max_deferment(void); 2367extern u64 scheduler_tick_max_deferment(void);
2361#else
2362static 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
100enum 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
101extern int tick_nohz_enabled; 114extern int tick_nohz_enabled;
102extern int tick_nohz_tick_stopped(void); 115extern 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
157extern void tick_nohz_full_kick(void); 170extern void tick_nohz_dep_set(enum tick_dep_bits bit);
171extern void tick_nohz_dep_clear(enum tick_dep_bits bit);
172extern void tick_nohz_dep_set_cpu(int cpu, enum tick_dep_bits bit);
173extern void tick_nohz_dep_clear_cpu(int cpu, enum tick_dep_bits bit);
174extern void tick_nohz_dep_set_task(struct task_struct *tsk,
175 enum tick_dep_bits bit);
176extern void tick_nohz_dep_clear_task(struct task_struct *tsk,
177 enum tick_dep_bits bit);
178extern void tick_nohz_dep_set_signal(struct signal_struct *signal,
179 enum tick_dep_bits bit);
180extern 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 */
187static 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
193static 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
199static 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
205static 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
211static 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}
217static 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}
223static 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);