History

Merge branch 'locking-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull locking updates from Ingo Molnar: "The main changes in this cycle are: - rwsem scalability improvements, phase #2, by Waiman Long, which are rather impressive: "On a 2-socket 40-core 80-thread Skylake system with 40 reader and writer locking threads, the min/mean/max locking operations done in a 5-second testing window before the patchset were: 40 readers, Iterations Min/Mean/Max = 1,807/1,808/1,810 40 writers, Iterations Min/Mean/Max = 1,807/50,344/151,255 After the patchset, they became: 40 readers, Iterations Min/Mean/Max = 30,057/31,359/32,741 40 writers, Iterations Min/Mean/Max = 94,466/95,845/97,098" There's a lot of changes to the locking implementation that makes it similar to qrwlock, including owner handoff for more fair locking. Another microbenchmark shows how across the spectrum the improvements are: "With a locking microbenchmark running on 5.1 based kernel, the total locking rates (in kops/s) on a 2-socket Skylake system with equal numbers of readers and writers (mixed) before and after this patchset were: # of Threads Before Patch After Patch ------------ ------------ ----------- 2 2,618 4,193 4 1,202 3,726 8 802 3,622 16 729 3,359 32 319 2,826 64 102 2,744" The changes are extensive and the patch-set has been through several iterations addressing various locking workloads. There might be more regressions, but unless they are pathological I believe we want to use this new implementation as the baseline going forward. - jump-label optimizations by Daniel Bristot de Oliveira: the primary motivation was to remove IPI disturbance of isolated RT-workload CPUs, which resulted in the implementation of batched jump-label updates. Beyond the improvement of the real-time characteristics kernel, in one test this patchset improved static key update overhead from 57 msecs to just 1.4 msecs - which is a nice speedup as well. - atomic64_t cross-arch type cleanups by Mark Rutland: over the last ~10 years of atomic64_t existence the various types used by the APIs only had to be self-consistent within each architecture - which means they became wildly inconsistent across architectures. Mark puts and end to this by reworking all the atomic64 implementations to use 's64' as the base type for atomic64_t, and to ensure that this type is consistently used for parameters and return values in the API, avoiding further problems in this area. - A large set of small improvements to lockdep by Yuyang Du: type cleanups, output cleanups, function return type and othr cleanups all around the place. - A set of percpu ops cleanups and fixes by Peter Zijlstra. - Misc other changes - please see the Git log for more details" * 'locking-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (82 commits) locking/lockdep: increase size of counters for lockdep statistics locking/atomics: Use sed(1) instead of non-standard head(1) option locking/lockdep: Move mark_lock() inside CONFIG_TRACE_IRQFLAGS && CONFIG_PROVE_LOCKING x86/jump_label: Make tp_vec_nr static x86/percpu: Optimize raw_cpu_xchg() x86/percpu, sched/fair: Avoid local_clock() x86/percpu, x86/irq: Relax {set,get}_irq_regs() x86/percpu: Relax smp_processor_id() x86/percpu: Differentiate this_cpu_{}() and __this_cpu_{}() locking/rwsem: Guard against making count negative locking/rwsem: Adaptive disabling of reader optimistic spinning locking/rwsem: Enable time-based spinning on reader-owned rwsem locking/rwsem: Make rwsem->owner an atomic_long_t locking/rwsem: Enable readers spinning on writer locking/rwsem: Clarify usage of owner's nonspinaable bit locking/rwsem: Wake up almost all readers in wait queue locking/rwsem: More optimal RT task handling of null owner locking/rwsem: Always release wait_lock before waking up tasks locking/rwsem: Implement lock handoff to prevent lock starvation locking/rwsem: Make rwsem_spin_on_owner() return owner state ...

Linus Torvalds committed 7 years ago

Commit e1928322 parents 46f1ec2 9156e5455 files · +2788 −2020Browse files

Showing the changes to include/linux (7 of 55 files). Show all

Unified · Split

7 files
  1. include/linux/jump_label.h +3 −0
  2. include/linux/lockdep.h +24 −12
  3. include/linux/percpu-rwsem.h +2 −2
  4. include/linux/rwsem.h +9 −7
  5. include/linux/sched/wake_q.h +5 −0
  6. include/linux/smp.h +31 −14
  7. include/linux/types.h +1 −1
include/linux/jump_label.h+3−0
@@ -215,6 +215,9 @@ extern void arch_jump_label_transform(struct jump_entry *entry, · 214 unmodified lines
215 enum jump_label_type type);215 enum jump_label_type type);
216extern void arch_jump_label_transform_static(struct jump_entry *entry,216extern void arch_jump_label_transform_static(struct jump_entry *entry,
217 enum jump_label_type type);217 enum jump_label_type type);
218extern bool arch_jump_label_transform_queue(struct jump_entry *entry,
219 enum jump_label_type type);
220extern void arch_jump_label_transform_apply(void);
218extern int jump_label_text_reserved(void *start, void *end);221extern int jump_label_text_reserved(void *start, void *end);
219extern void static_key_slow_inc(struct static_key *key);222extern void static_key_slow_inc(struct static_key *key);
220extern void static_key_slow_dec(struct static_key *key);223extern void static_key_slow_dec(struct static_key *key);
include/linux/lockdep.h+24−12
@@ -203,11 +203,17 @@ struct lock_list { · 202 unmodified lines
203 struct lock_list *parent;203 struct lock_list *parent;
204};204};
205 205
206/*206/**
207 * We record lock dependency chains, so that we can cache them:207 * struct lock_chain - lock dependency chain record
208 *
209 * @irq_context: the same as irq_context in held_lock below
210 * @depth: the number of held locks in this chain
211 * @base: the index in chain_hlocks for this chain
212 * @entry: the collided lock chains in lock_chain hash list
213 * @chain_key: the hash key of this lock_chain
208 */214 */
209struct lock_chain {215struct lock_chain {
210 /* see BUILD_BUG_ON()s in lookup_chain_cache() */216 /* see BUILD_BUG_ON()s in add_chain_cache() */
211 unsigned int irq_context : 2,217 unsigned int irq_context : 2,
212 depth : 6,218 depth : 6,
213 base : 24;219 base : 24;
@@ -217,12 +223,8 @@ struct lock_chain { · 3 unmodified lines
217};223};
218 224
219#define MAX_LOCKDEP_KEYS_BITS 13225#define MAX_LOCKDEP_KEYS_BITS 13
220/*226#define MAX_LOCKDEP_KEYS (1UL << MAX_LOCKDEP_KEYS_BITS)
221 * Subtract one because we offset hlock->class_idx by 1 in order227#define INITIAL_CHAIN_KEY -1
222 * to make 0 mean no class. This avoids overflowing the class_idx
223 * bitfield and hitting the BUG in hlock_class().
224 */
225#define MAX_LOCKDEP_KEYS ((1UL << MAX_LOCKDEP_KEYS_BITS) - 1)
226 228
227struct held_lock {229struct held_lock {
228 /*230 /*
@@ -247,6 +249,11 @@ struct held_lock { · 18 unmodified lines
247 u64 waittime_stamp;249 u64 waittime_stamp;
248 u64 holdtime_stamp;250 u64 holdtime_stamp;
249#endif251#endif
252 /*
253 * class_idx is zero-indexed; it points to the element in
254 * lock_classes this held lock instance belongs to. class_idx is in
255 * the range from 0 to (MAX_LOCKDEP_KEYS-1) inclusive.
256 */
250 unsigned int class_idx:MAX_LOCKDEP_KEYS_BITS;257 unsigned int class_idx:MAX_LOCKDEP_KEYS_BITS;
251 /*258 /*
252 * The lock-stack is unified in that the lock chains of interrupt259 * The lock-stack is unified in that the lock chains of interrupt
@@ -281,6 +288,8 @@ extern void lockdep_free_key_range(void *start, unsigned long size); · 28 unmodified lines
281extern asmlinkage void lockdep_sys_exit(void);288extern asmlinkage void lockdep_sys_exit(void);
282extern void lockdep_set_selftest_task(struct task_struct *task);289extern void lockdep_set_selftest_task(struct task_struct *task);
283 290
291extern void lockdep_init_task(struct task_struct *task);
292
284extern void lockdep_off(void);293extern void lockdep_off(void);
285extern void lockdep_on(void);294extern void lockdep_on(void);
286 295
@@ -385,7 +394,7 @@ extern void lock_unpin_lock(struct lockdep_map *lock, struct pin_cookie); · 98 unmodified lines
385 WARN_ON(debug_locks && !lockdep_is_held(l)); \394 WARN_ON(debug_locks && !lockdep_is_held(l)); \
386 } while (0)395 } while (0)
387 396
388#define lockdep_assert_held_exclusive(l) do { \397#define lockdep_assert_held_write(l) do { \
389 WARN_ON(debug_locks && !lockdep_is_held_type(l, 0)); \398 WARN_ON(debug_locks && !lockdep_is_held_type(l, 0)); \
390 } while (0)399 } while (0)
391 400
@@ -405,6 +414,10 @@ extern void lock_unpin_lock(struct lockdep_map *lock, struct pin_cookie); · 13 unmodified lines
405 414
406#else /* !CONFIG_LOCKDEP */415#else /* !CONFIG_LOCKDEP */
407 416
417static inline void lockdep_init_task(struct task_struct *task)
418{
419}
420
408static inline void lockdep_off(void)421static inline void lockdep_off(void)
409{422{
410}423}
@@ -466,7 +479,7 @@ struct lockdep_map { }; · 55 unmodified lines
466#define lockdep_is_held_type(l, r) (1)479#define lockdep_is_held_type(l, r) (1)
467 480
468#define lockdep_assert_held(l) do { (void)(l); } while (0)481#define lockdep_assert_held(l) do { (void)(l); } while (0)
469#define lockdep_assert_held_exclusive(l) do { (void)(l); } while (0)482#define lockdep_assert_held_write(l) do { (void)(l); } while (0)
470#define lockdep_assert_held_read(l) do { (void)(l); } while (0)483#define lockdep_assert_held_read(l) do { (void)(l); } while (0)
471#define lockdep_assert_held_once(l) do { (void)(l); } while (0)484#define lockdep_assert_held_once(l) do { (void)(l); } while (0)
472 485
@@ -497,7 +510,6 @@ enum xhlock_context_t { · 24 unmodified lines
497 { .name = (_name), .key = (void *)(_key), }510 { .name = (_name), .key = (void *)(_key), }
498 511
499static inline void lockdep_invariant_state(bool force) {}512static inline void lockdep_invariant_state(bool force) {}
500static inline void lockdep_init_task(struct task_struct *task) {}
501static inline void lockdep_free_task(struct task_struct *task) {}513static inline void lockdep_free_task(struct task_struct *task) {}
502 514
503#ifdef CONFIG_LOCK_STAT515#ifdef CONFIG_LOCK_STAT
include/linux/percpu-rwsem.h+2−2
@@ -121,7 +121,7 @@ static inline void percpu_rwsem_release(struct percpu_rw_semaphore *sem, · 120 unmodified lines
121 lock_release(&sem->rw_sem.dep_map, 1, ip);121 lock_release(&sem->rw_sem.dep_map, 1, ip);
122#ifdef CONFIG_RWSEM_SPIN_ON_OWNER122#ifdef CONFIG_RWSEM_SPIN_ON_OWNER
123 if (!read)123 if (!read)
124 sem->rw_sem.owner = RWSEM_OWNER_UNKNOWN;124 atomic_long_set(&sem->rw_sem.owner, RWSEM_OWNER_UNKNOWN);
125#endif125#endif
126}126}
127 127
@@ -131,7 +131,7 @@ static inline void percpu_rwsem_acquire(struct percpu_rw_semaphore *sem, · 3 unmodified lines
131 lock_acquire(&sem->rw_sem.dep_map, 0, 1, read, 1, NULL, ip);131 lock_acquire(&sem->rw_sem.dep_map, 0, 1, read, 1, NULL, ip);
132#ifdef CONFIG_RWSEM_SPIN_ON_OWNER132#ifdef CONFIG_RWSEM_SPIN_ON_OWNER
133 if (!read)133 if (!read)
134 sem->rw_sem.owner = current;134 atomic_long_set(&sem->rw_sem.owner, (long)current);
135#endif135#endif
136}136}
137 137
include/linux/rwsem.h+9−7
@@ -34,12 +34,13 @@ · 33 unmodified lines
34 */34 */
35struct rw_semaphore {35struct rw_semaphore {
36 atomic_long_t count;36 atomic_long_t count;
37#ifdef CONFIG_RWSEM_SPIN_ON_OWNER
38 /*37 /*
39 * Write owner. Used as a speculative check to see38 * Write owner or one of the read owners as well flags regarding
40 * if the owner is running on the cpu.39 * the current state of the rwsem. Can be used as a speculative
40 * check to see if the write owner is running on the cpu.
41 */41 */
42 struct task_struct *owner;42 atomic_long_t owner;
43#ifdef CONFIG_RWSEM_SPIN_ON_OWNER
43 struct optimistic_spin_queue osq; /* spinner MCS lock */44 struct optimistic_spin_queue osq; /* spinner MCS lock */
44#endif45#endif
45 raw_spinlock_t wait_lock;46 raw_spinlock_t wait_lock;
@@ -50,10 +51,10 @@ struct rw_semaphore { · 4 unmodified lines
50};51};
51 52
52/*53/*
53 * Setting bit 1 of the owner field but not bit 0 will indicate54 * Setting all bits of the owner field except bit 0 will indicate
54 * that the rwsem is writer-owned with an unknown owner.55 * that the rwsem is writer-owned with an unknown owner.
55 */56 */
56#define RWSEM_OWNER_UNKNOWN ((struct task_struct *)-2L)57#define RWSEM_OWNER_UNKNOWN (-2L)
57 58
58/* In all implementations count != 0 means locked */59/* In all implementations count != 0 means locked */
59static inline int rwsem_is_locked(struct rw_semaphore *sem)60static inline int rwsem_is_locked(struct rw_semaphore *sem)
@@ -73,13 +74,14 @@ static inline int rwsem_is_locked(struct rw_semaphore *sem) · 13 unmodified lines
73#endif74#endif
74 75
75#ifdef CONFIG_RWSEM_SPIN_ON_OWNER76#ifdef CONFIG_RWSEM_SPIN_ON_OWNER
76#define __RWSEM_OPT_INIT(lockname) , .osq = OSQ_LOCK_UNLOCKED, .owner = NULL77#define __RWSEM_OPT_INIT(lockname) , .osq = OSQ_LOCK_UNLOCKED
77#else78#else
78#define __RWSEM_OPT_INIT(lockname)79#define __RWSEM_OPT_INIT(lockname)
79#endif80#endif
80 81
81#define __RWSEM_INITIALIZER(name) \82#define __RWSEM_INITIALIZER(name) \
82 { __RWSEM_INIT_COUNT(name), \83 { __RWSEM_INIT_COUNT(name), \
84 .owner = ATOMIC_LONG_INIT(0), \
83 .wait_list = LIST_HEAD_INIT((name).wait_list), \85 .wait_list = LIST_HEAD_INIT((name).wait_list), \
84 .wait_lock = __RAW_SPIN_LOCK_UNLOCKED(name.wait_lock) \86 .wait_lock = __RAW_SPIN_LOCK_UNLOCKED(name.wait_lock) \
85 __RWSEM_OPT_INIT(name) \87 __RWSEM_OPT_INIT(name) \
include/linux/sched/wake_q.h+5−0
@@ -51,6 +51,11 @@ static inline void wake_q_init(struct wake_q_head *head) · 50 unmodified lines
51 head->lastp = &head->first;51 head->lastp = &head->first;
52}52}
53 53
54static inline bool wake_q_empty(struct wake_q_head *head)
55{
56 return head->first == WAKE_Q_TAIL;
57}
58
54extern void wake_q_add(struct wake_q_head *head, struct task_struct *task);59extern void wake_q_add(struct wake_q_head *head, struct task_struct *task);
55extern void wake_q_add_safe(struct wake_q_head *head, struct task_struct *task);60extern void wake_q_add_safe(struct wake_q_head *head, struct task_struct *task);
56extern void wake_up_q(struct wake_q_head *head);61extern void wake_up_q(struct wake_q_head *head);
include/linux/smp.h+31−14
@@ -180,29 +180,46 @@ static inline int get_boot_cpu_id(void) · 179 unmodified lines
180 180
181#endif /* !SMP */181#endif /* !SMP */
182 182
183/*183/**
184 * smp_processor_id(): get the current CPU ID.184 * raw_processor_id() - get the current (unstable) CPU id
185 *
186 * For then you know what you are doing and need an unstable
187 * CPU id.
188 */
189
190/**
191 * smp_processor_id() - get the current (stable) CPU id
192 *
193 * This is the normal accessor to the CPU id and should be used
194 * whenever possible.
195 *
196 * The CPU id is stable when:
185 *197 *
186 * if DEBUG_PREEMPT is enabled then we check whether it is198 * - IRQs are disabled;
187 * used in a preemption-safe way. (smp_processor_id() is safe199 * - preemption is disabled;
188 * if it's used in a preemption-off critical section, or in200 * - the task is CPU affine.
189 * a thread that is bound to the current CPU.)
190 *201 *
191 * NOTE: raw_smp_processor_id() is for internal use only202 * When CONFIG_DEBUG_PREEMPT; we verify these assumption and WARN
192 * (smp_processor_id() is the preferred variant), but in rare203 * when smp_processor_id() is used when the CPU id is not stable.
193 * instances it might also be used to turn off false positives
194 * (i.e. smp_processor_id() use that the debugging code reports but
195 * which use for some reason is legal). Don't use this to hack around
196 * the warning message, as your code might not work under PREEMPT.
197 */204 */
205
206/*
207 * Allow the architecture to differentiate between a stable and unstable read.
208 * For example, x86 uses an IRQ-safe asm-volatile read for the unstable but a
209 * regular asm read for the stable.
210 */
211#ifndef __smp_processor_id
212#define __smp_processor_id(x) raw_smp_processor_id(x)
213#endif
214
198#ifdef CONFIG_DEBUG_PREEMPT215#ifdef CONFIG_DEBUG_PREEMPT
199 extern unsigned int debug_smp_processor_id(void);216 extern unsigned int debug_smp_processor_id(void);
200# define smp_processor_id() debug_smp_processor_id()217# define smp_processor_id() debug_smp_processor_id()
201#else218#else
202# define smp_processor_id() raw_smp_processor_id()219# define smp_processor_id() __smp_processor_id()
203#endif220#endif
204 221
205#define get_cpu() ({ preempt_disable(); smp_processor_id(); })222#define get_cpu() ({ preempt_disable(); __smp_processor_id(); })
206#define put_cpu() preempt_enable()223#define put_cpu() preempt_enable()
207 224
208/*225/*
include/linux/types.h+1−1
@@ -174,7 +174,7 @@ typedef struct { · 173 unmodified lines
174 174
175#ifdef CONFIG_64BIT175#ifdef CONFIG_64BIT
176typedef struct {176typedef struct {
177 long counter;177 s64 counter;
178} atomic64_t;178} atomic64_t;
179#endif179#endif
180 180

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t