aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFrederic Weisbecker <fweisbec@gmail.com>2016-03-24 10:38:00 -0400
committerIngo Molnar <mingo@kernel.org>2016-03-29 05:52:11 -0400
commitf009a7a767e792d5ab0b46c08d46236ea5271dd9 (patch)
tree68a22ef0eee00723de6f05e9f8b0d68eeacd195f
parent5acba71e18833b9d06686b3751598bfa263a3ac3 (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.h4
-rw-r--r--kernel/time/tick-sched.c61
-rw-r--r--kernel/time/tick-sched.h2
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)
157cpumask_var_t tick_nohz_full_mask; 157cpumask_var_t tick_nohz_full_mask;
158cpumask_var_t housekeeping_mask; 158cpumask_var_t housekeeping_mask;
159bool tick_nohz_full_running; 159bool tick_nohz_full_running;
160static unsigned long tick_dep_mask; 160static atomic_t tick_dep_mask;
161 161
162static void trace_tick_dependency(unsigned long dep) 162static 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
183static bool can_stop_full_tick(struct tick_sched *ts) 189static 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(&current->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(&current->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
262static void tick_nohz_dep_set_all(unsigned long *dep, 260static 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
281void tick_nohz_dep_clear(enum tick_dep_bits bit) 279void 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 */
290void tick_nohz_dep_set_cpu(int cpu, enum tick_dep_bits bit) 288void 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
332void tick_nohz_dep_clear_task(struct task_struct *tsk, enum tick_dep_bits bit) 330void 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
346void tick_nohz_dep_clear_signal(struct signal_struct *sig, enum tick_dep_bits bit) 344void 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(&current->tick_dep_mask) ||
368 atomic_read(&current->signal->tick_dep_mask))
370 tick_nohz_full_kick(); 369 tick_nohz_full_kick();
371 } 370 }
372out: 371out:
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
66extern struct tick_sched *tick_get_tick_sched(int cpu); 66extern struct tick_sched *tick_get_tick_sched(int cpu);