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
215215 enum jump_label_type type);
216216 extern void arch_jump_label_transform_static(struct jump_entry *entry,
217217 enum jump_label_type type);
218+extern bool arch_jump_label_transform_queue(struct jump_entry *entry,
219+ enum jump_label_type type);
220+extern void arch_jump_label_transform_apply(void);
218221 extern int jump_label_text_reserved(void *start, void *end);
219222 extern void static_key_slow_inc(struct static_key *key);
220223 extern 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
203203 struct lock_list *parent;
204204 };
205205
206−/*
207− * We record lock dependency chains, so that we can cache them:
206+/**
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
208214 */
209215 struct lock_chain {
210− /* see BUILD_BUG_ON()s in lookup_chain_cache() */
216+ /* see BUILD_BUG_ON()s in add_chain_cache() */
211217 unsigned int irq_context : 2,
212218 depth : 6,
213219 base : 24;
@@ -217,12 +223,8 @@ struct lock_chain { · 3 unmodified lines
217223 };
218224
219225 #define MAX_LOCKDEP_KEYS_BITS 13
220−/*
221− * Subtract one because we offset hlock->class_idx by 1 in order
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+#define MAX_LOCKDEP_KEYS (1UL << MAX_LOCKDEP_KEYS_BITS)
227+#define INITIAL_CHAIN_KEY -1
226228
227229 struct held_lock {
228230 /*
@@ -247,6 +249,11 @@ struct held_lock { · 18 unmodified lines
247249 u64 waittime_stamp;
248250 u64 holdtime_stamp;
249251 #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+ */
250257 unsigned int class_idx:MAX_LOCKDEP_KEYS_BITS;
251258 /*
252259 * 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
281288 extern asmlinkage void lockdep_sys_exit(void);
282289 extern void lockdep_set_selftest_task(struct task_struct *task);
283290
291+extern void lockdep_init_task(struct task_struct *task);
292+
284293 extern void lockdep_off(void);
285294 extern void lockdep_on(void);
286295
@@ -385,7 +394,7 @@ extern void lock_unpin_lock(struct lockdep_map *lock, struct pin_cookie); · 98 unmodified lines
385394 WARN_ON(debug_locks && !lockdep_is_held(l)); \
386395 } while (0)
387396
388−#define lockdep_assert_held_exclusive(l) do { \
397+#define lockdep_assert_held_write(l) do { \
389398 WARN_ON(debug_locks && !lockdep_is_held_type(l, 0)); \
390399 } while (0)
391400
@@ -405,6 +414,10 @@ extern void lock_unpin_lock(struct lockdep_map *lock, struct pin_cookie); · 13 unmodified lines
405414
406415 #else /* !CONFIG_LOCKDEP */
407416
417+static inline void lockdep_init_task(struct task_struct *task)
418+{
419+}
420+
408421 static inline void lockdep_off(void)
409422 {
410423 }
@@ -466,7 +479,7 @@ struct lockdep_map { }; · 55 unmodified lines
466479 #define lockdep_is_held_type(l, r) (1)
467480
468481 #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)
470483 #define lockdep_assert_held_read(l) do { (void)(l); } while (0)
471484 #define lockdep_assert_held_once(l) do { (void)(l); } while (0)
472485
@@ -497,7 +510,6 @@ enum xhlock_context_t { · 24 unmodified lines
497510 { .name = (_name), .key = (void *)(_key), }
498511
499512 static inline void lockdep_invariant_state(bool force) {}
500−static inline void lockdep_init_task(struct task_struct *task) {}
501513 static inline void lockdep_free_task(struct task_struct *task) {}
502514
503515 #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
121121 lock_release(&sem->rw_sem.dep_map, 1, ip);
122122 #ifdef CONFIG_RWSEM_SPIN_ON_OWNER
123123 if (!read)
124− sem->rw_sem.owner = RWSEM_OWNER_UNKNOWN;
124+ atomic_long_set(&sem->rw_sem.owner, RWSEM_OWNER_UNKNOWN);
125125 #endif
126126 }
127127
@@ -131,7 +131,7 @@ static inline void percpu_rwsem_acquire(struct percpu_rw_semaphore *sem, · 3 unmodified lines
131131 lock_acquire(&sem->rw_sem.dep_map, 0, 1, read, 1, NULL, ip);
132132 #ifdef CONFIG_RWSEM_SPIN_ON_OWNER
133133 if (!read)
134− sem->rw_sem.owner = current;
134+ atomic_long_set(&sem->rw_sem.owner, (long)current);
135135 #endif
136136 }
137137
include/linux/rwsem.h+9−7
@@ -34,12 +34,13 @@ · 33 unmodified lines
3434 */
3535 struct rw_semaphore {
3636 atomic_long_t count;
37−#ifdef CONFIG_RWSEM_SPIN_ON_OWNER
3837 /*
39− * Write owner. Used as a speculative check to see
40− * if the owner is running on the cpu.
38+ * Write owner or one of the read owners as well flags regarding
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.
4141 */
42− struct task_struct *owner;
42+ atomic_long_t owner;
43+#ifdef CONFIG_RWSEM_SPIN_ON_OWNER
4344 struct optimistic_spin_queue osq; /* spinner MCS lock */
4445 #endif
4546 raw_spinlock_t wait_lock;
@@ -50,10 +51,10 @@ struct rw_semaphore { · 4 unmodified lines
5051 };
5152
5253 /*
53− * Setting bit 1 of the owner field but not bit 0 will indicate
54+ * Setting all bits of the owner field except bit 0 will indicate
5455 * that the rwsem is writer-owned with an unknown owner.
5556 */
56−#define RWSEM_OWNER_UNKNOWN ((struct task_struct *)-2L)
57+#define RWSEM_OWNER_UNKNOWN (-2L)
5758
5859 /* In all implementations count != 0 means locked */
5960 static 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
7374 #endif
7475
7576 #ifdef CONFIG_RWSEM_SPIN_ON_OWNER
76−#define __RWSEM_OPT_INIT(lockname) , .osq = OSQ_LOCK_UNLOCKED, .owner = NULL
77+#define __RWSEM_OPT_INIT(lockname) , .osq = OSQ_LOCK_UNLOCKED
7778 #else
7879 #define __RWSEM_OPT_INIT(lockname)
7980 #endif
8081
8182 #define __RWSEM_INITIALIZER(name) \
8283 { __RWSEM_INIT_COUNT(name), \
84+ .owner = ATOMIC_LONG_INIT(0), \
8385 .wait_list = LIST_HEAD_INIT((name).wait_list), \
8486 .wait_lock = __RAW_SPIN_LOCK_UNLOCKED(name.wait_lock) \
8587 __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
5151 head->lastp = &head->first;
5252 }
5353
54+static inline bool wake_q_empty(struct wake_q_head *head)
55+{
56+ return head->first == WAKE_Q_TAIL;
57+}
58+
5459 extern void wake_q_add(struct wake_q_head *head, struct task_struct *task);
5560 extern void wake_q_add_safe(struct wake_q_head *head, struct task_struct *task);
5661 extern 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
180180
181181 #endif /* !SMP */
182182
183−/*
184− * smp_processor_id(): get the current CPU ID.
183+/**
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:
185197 *
186− * if DEBUG_PREEMPT is enabled then we check whether it is
187− * used in a preemption-safe way. (smp_processor_id() is safe
188− * if it's used in a preemption-off critical section, or in
189− * a thread that is bound to the current CPU.)
198+ * - IRQs are disabled;
199+ * - preemption is disabled;
200+ * - the task is CPU affine.
190201 *
191− * NOTE: raw_smp_processor_id() is for internal use only
192− * (smp_processor_id() is the preferred variant), but in rare
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.
202+ * When CONFIG_DEBUG_PREEMPT; we verify these assumption and WARN
203+ * when smp_processor_id() is used when the CPU id is not stable.
197204 */
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+
198215 #ifdef CONFIG_DEBUG_PREEMPT
199216 extern unsigned int debug_smp_processor_id(void);
200217 # define smp_processor_id() debug_smp_processor_id()
201218 #else
202−# define smp_processor_id() raw_smp_processor_id()
219+# define smp_processor_id() __smp_processor_id()
203220 #endif
204221
205−#define get_cpu() ({ preempt_disable(); smp_processor_id(); })
222+#define get_cpu() ({ preempt_disable(); __smp_processor_id(); })
206223 #define put_cpu() preempt_enable()
207224
208225 /*
include/linux/types.h+1−1
@@ -174,7 +174,7 @@ typedef struct { · 173 unmodified lines
174174
175175 #ifdef CONFIG_64BIT
176176 typedef struct {
177− long counter;
177+ s64 counter;
178178 } atomic64_t;
179179 #endif
180180

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