diff options
author | Frederic Weisbecker <fweisbec@gmail.com> | 2016-03-24 10:38:00 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2016-03-29 05:52:11 -0400 |
commit | f009a7a767e792d5ab0b46c08d46236ea5271dd9 (patch) | |
tree | 68a22ef0eee00723de6f05e9f8b0d68eeacd195f | |
parent | 5acba71e18833b9d06686b3751598bfa263a3ac3 (diff) |
timers/nohz: Convert tick dependency mask to atomic_t
The tick dependency mask was intially unsigned long because this is the
type on which clear_bit() operates on and fetch_or() accepts it.
But now that we have atomic_fetch_or(), we can instead use
atomic_andnot() to clear the bit. This consolidates the type of our
tick dependency mask, reduce its size on structures and benefit from
possible architecture optimizations on atomic_t operations.
Suggested-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/1458830281-4255-3-git-send-email-fweisbec@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r-- | include/linux/sched.h | 4 | ||||
-rw-r--r-- | kernel/time/tick-sched.c | 61 | ||||
-rw-r--r-- | kernel/time/tick-sched.h | 2 |
3 files changed, 33 insertions, 34 deletions
diff --git a/include/linux/sched.h b/include/linux/sched.h index 60bba7e032dc..52c4847b05e2 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h | |||
@@ -720,7 +720,7 @@ struct signal_struct { | |||
720 | struct task_cputime cputime_expires; | 720 | struct task_cputime cputime_expires; |
721 | 721 | ||
722 | #ifdef CONFIG_NO_HZ_FULL | 722 | #ifdef CONFIG_NO_HZ_FULL |
723 | unsigned long tick_dep_mask; | 723 | atomic_t tick_dep_mask; |
724 | #endif | 724 | #endif |
725 | 725 | ||
726 | struct list_head cpu_timers[3]; | 726 | struct list_head cpu_timers[3]; |
@@ -1549,7 +1549,7 @@ struct task_struct { | |||
1549 | #endif | 1549 | #endif |
1550 | 1550 | ||
1551 | #ifdef CONFIG_NO_HZ_FULL | 1551 | #ifdef CONFIG_NO_HZ_FULL |
1552 | unsigned long tick_dep_mask; | 1552 | atomic_t tick_dep_mask; |
1553 | #endif | 1553 | #endif |
1554 | unsigned long nvcsw, nivcsw; /* context switch counts */ | 1554 | unsigned long nvcsw, nivcsw; /* context switch counts */ |
1555 | u64 start_time; /* monotonic time in nsec */ | 1555 | u64 start_time; /* monotonic time in nsec */ |
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index 084b79f5917e..58e3310c9b21 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c | |||
@@ -157,52 +157,50 @@ static void tick_sched_handle(struct tick_sched *ts, struct pt_regs *regs) | |||
157 | cpumask_var_t tick_nohz_full_mask; | 157 | cpumask_var_t tick_nohz_full_mask; |
158 | cpumask_var_t housekeeping_mask; | 158 | cpumask_var_t housekeeping_mask; |
159 | bool tick_nohz_full_running; | 159 | bool tick_nohz_full_running; |
160 | static unsigned long tick_dep_mask; | 160 | static atomic_t tick_dep_mask; |
161 | 161 | ||
162 | static void trace_tick_dependency(unsigned long dep) | 162 | static bool check_tick_dependency(atomic_t *dep) |
163 | { | 163 | { |
164 | if (dep & TICK_DEP_MASK_POSIX_TIMER) { | 164 | int val = atomic_read(dep); |
165 | |||
166 | if (val & TICK_DEP_MASK_POSIX_TIMER) { | ||
165 | trace_tick_stop(0, TICK_DEP_MASK_POSIX_TIMER); | 167 | trace_tick_stop(0, TICK_DEP_MASK_POSIX_TIMER); |
166 | return; | 168 | return true; |
167 | } | 169 | } |
168 | 170 | ||
169 | if (dep & TICK_DEP_MASK_PERF_EVENTS) { | 171 | if (val & TICK_DEP_MASK_PERF_EVENTS) { |
170 | trace_tick_stop(0, TICK_DEP_MASK_PERF_EVENTS); | 172 | trace_tick_stop(0, TICK_DEP_MASK_PERF_EVENTS); |
171 | return; | 173 | return true; |
172 | } | 174 | } |
173 | 175 | ||
174 | if (dep & TICK_DEP_MASK_SCHED) { | 176 | if (val & TICK_DEP_MASK_SCHED) { |
175 | trace_tick_stop(0, TICK_DEP_MASK_SCHED); | 177 | trace_tick_stop(0, TICK_DEP_MASK_SCHED); |
176 | return; | 178 | return true; |
177 | } | 179 | } |
178 | 180 | ||
179 | if (dep & TICK_DEP_MASK_CLOCK_UNSTABLE) | 181 | if (val & TICK_DEP_MASK_CLOCK_UNSTABLE) { |
180 | trace_tick_stop(0, TICK_DEP_MASK_CLOCK_UNSTABLE); | 182 | trace_tick_stop(0, TICK_DEP_MASK_CLOCK_UNSTABLE); |
183 | return true; | ||
184 | } | ||
185 | |||
186 | return false; | ||
181 | } | 187 | } |
182 | 188 | ||
183 | static bool can_stop_full_tick(struct tick_sched *ts) | 189 | static bool can_stop_full_tick(struct tick_sched *ts) |
184 | { | 190 | { |
185 | WARN_ON_ONCE(!irqs_disabled()); | 191 | WARN_ON_ONCE(!irqs_disabled()); |
186 | 192 | ||
187 | if (tick_dep_mask) { | 193 | if (check_tick_dependency(&tick_dep_mask)) |
188 | trace_tick_dependency(tick_dep_mask); | ||
189 | return false; | 194 | return false; |
190 | } | ||
191 | 195 | ||
192 | if (ts->tick_dep_mask) { | 196 | if (check_tick_dependency(&ts->tick_dep_mask)) |
193 | trace_tick_dependency(ts->tick_dep_mask); | ||
194 | return false; | 197 | return false; |
195 | } | ||
196 | 198 | ||
197 | if (current->tick_dep_mask) { | 199 | if (check_tick_dependency(¤t->tick_dep_mask)) |
198 | trace_tick_dependency(current->tick_dep_mask); | ||
199 | return false; | 200 | return false; |
200 | } | ||
201 | 201 | ||
202 | if (current->signal->tick_dep_mask) { | 202 | if (check_tick_dependency(¤t->signal->tick_dep_mask)) |
203 | trace_tick_dependency(current->signal->tick_dep_mask); | ||
204 | return false; | 203 | return false; |
205 | } | ||
206 | 204 | ||
207 | return true; | 205 | return true; |
208 | } | 206 | } |
@@ -259,12 +257,12 @@ static void tick_nohz_full_kick_all(void) | |||
259 | preempt_enable(); | 257 | preempt_enable(); |
260 | } | 258 | } |
261 | 259 | ||
262 | static void tick_nohz_dep_set_all(unsigned long *dep, | 260 | static void tick_nohz_dep_set_all(atomic_t *dep, |
263 | enum tick_dep_bits bit) | 261 | enum tick_dep_bits bit) |
264 | { | 262 | { |
265 | unsigned long prev; | 263 | int prev; |
266 | 264 | ||
267 | prev = fetch_or(dep, BIT_MASK(bit)); | 265 | prev = atomic_fetch_or(dep, BIT(bit)); |
268 | if (!prev) | 266 | if (!prev) |
269 | tick_nohz_full_kick_all(); | 267 | tick_nohz_full_kick_all(); |
270 | } | 268 | } |
@@ -280,7 +278,7 @@ void tick_nohz_dep_set(enum tick_dep_bits bit) | |||
280 | 278 | ||
281 | void tick_nohz_dep_clear(enum tick_dep_bits bit) | 279 | void tick_nohz_dep_clear(enum tick_dep_bits bit) |
282 | { | 280 | { |
283 | clear_bit(bit, &tick_dep_mask); | 281 | atomic_andnot(BIT(bit), &tick_dep_mask); |
284 | } | 282 | } |
285 | 283 | ||
286 | /* | 284 | /* |
@@ -289,12 +287,12 @@ void tick_nohz_dep_clear(enum tick_dep_bits bit) | |||
289 | */ | 287 | */ |
290 | void tick_nohz_dep_set_cpu(int cpu, enum tick_dep_bits bit) | 288 | void tick_nohz_dep_set_cpu(int cpu, enum tick_dep_bits bit) |
291 | { | 289 | { |
292 | unsigned long prev; | 290 | int prev; |
293 | struct tick_sched *ts; | 291 | struct tick_sched *ts; |
294 | 292 | ||
295 | ts = per_cpu_ptr(&tick_cpu_sched, cpu); | 293 | ts = per_cpu_ptr(&tick_cpu_sched, cpu); |
296 | 294 | ||
297 | prev = fetch_or(&ts->tick_dep_mask, BIT_MASK(bit)); | 295 | prev = atomic_fetch_or(&ts->tick_dep_mask, BIT(bit)); |
298 | if (!prev) { | 296 | if (!prev) { |
299 | preempt_disable(); | 297 | preempt_disable(); |
300 | /* Perf needs local kick that is NMI safe */ | 298 | /* Perf needs local kick that is NMI safe */ |
@@ -313,7 +311,7 @@ void tick_nohz_dep_clear_cpu(int cpu, enum tick_dep_bits bit) | |||
313 | { | 311 | { |
314 | struct tick_sched *ts = per_cpu_ptr(&tick_cpu_sched, cpu); | 312 | struct tick_sched *ts = per_cpu_ptr(&tick_cpu_sched, cpu); |
315 | 313 | ||
316 | clear_bit(bit, &ts->tick_dep_mask); | 314 | atomic_andnot(BIT(bit), &ts->tick_dep_mask); |
317 | } | 315 | } |
318 | 316 | ||
319 | /* | 317 | /* |
@@ -331,7 +329,7 @@ void tick_nohz_dep_set_task(struct task_struct *tsk, enum tick_dep_bits bit) | |||
331 | 329 | ||
332 | void tick_nohz_dep_clear_task(struct task_struct *tsk, enum tick_dep_bits bit) | 330 | void tick_nohz_dep_clear_task(struct task_struct *tsk, enum tick_dep_bits bit) |
333 | { | 331 | { |
334 | clear_bit(bit, &tsk->tick_dep_mask); | 332 | atomic_andnot(BIT(bit), &tsk->tick_dep_mask); |
335 | } | 333 | } |
336 | 334 | ||
337 | /* | 335 | /* |
@@ -345,7 +343,7 @@ void tick_nohz_dep_set_signal(struct signal_struct *sig, enum tick_dep_bits bit) | |||
345 | 343 | ||
346 | void tick_nohz_dep_clear_signal(struct signal_struct *sig, enum tick_dep_bits bit) | 344 | void tick_nohz_dep_clear_signal(struct signal_struct *sig, enum tick_dep_bits bit) |
347 | { | 345 | { |
348 | clear_bit(bit, &sig->tick_dep_mask); | 346 | atomic_andnot(BIT(bit), &sig->tick_dep_mask); |
349 | } | 347 | } |
350 | 348 | ||
351 | /* | 349 | /* |
@@ -366,7 +364,8 @@ void __tick_nohz_task_switch(void) | |||
366 | ts = this_cpu_ptr(&tick_cpu_sched); | 364 | ts = this_cpu_ptr(&tick_cpu_sched); |
367 | 365 | ||
368 | if (ts->tick_stopped) { | 366 | if (ts->tick_stopped) { |
369 | if (current->tick_dep_mask || current->signal->tick_dep_mask) | 367 | if (atomic_read(¤t->tick_dep_mask) || |
368 | atomic_read(¤t->signal->tick_dep_mask)) | ||
370 | tick_nohz_full_kick(); | 369 | tick_nohz_full_kick(); |
371 | } | 370 | } |
372 | out: | 371 | out: |
diff --git a/kernel/time/tick-sched.h b/kernel/time/tick-sched.h index eb4e32566a83..bf38226e5c17 100644 --- a/kernel/time/tick-sched.h +++ b/kernel/time/tick-sched.h | |||
@@ -60,7 +60,7 @@ struct tick_sched { | |||
60 | u64 next_timer; | 60 | u64 next_timer; |
61 | ktime_t idle_expires; | 61 | ktime_t idle_expires; |
62 | int do_timer_last; | 62 | int do_timer_last; |
63 | unsigned long tick_dep_mask; | 63 | atomic_t tick_dep_mask; |
64 | }; | 64 | }; |
65 | 65 | ||
66 | extern struct tick_sched *tick_get_tick_sched(int cpu); | 66 | extern struct tick_sched *tick_get_tick_sched(int cpu); |