Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1758972AbcCVRrJ (ORCPT ); Tue, 22 Mar 2016 13:47:09 -0400 Received: from g2t4622.austin.hp.com ([15.73.212.79]:33089 "EHLO g2t4622.austin.hp.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756078AbcCVRrE (ORCPT ); Tue, 22 Mar 2016 13:47:04 -0400 From: Waiman Long To: Ingo Molnar Cc: Peter Zijlstra , linux-kernel@vger.kernel.org, Linus Torvalds , Ding Tianhong , Jason Low , Davidlohr Bueso , "Paul E. McKenney" , Thomas Gleixner , Will Deacon , Tim Chen , Waiman Long Subject: [PATCH v3 2/3] locking/mutex: Enable optimistic spinning of woken task in wait queue Date: Tue, 22 Mar 2016 13:46:43 -0400 Message-Id: <1458668804-10138-3-git-send-email-Waiman.Long@hpe.com> X-Mailer: git-send-email 1.7.1 In-Reply-To: <1458668804-10138-1-git-send-email-Waiman.Long@hpe.com> References: <1458668804-10138-1-git-send-email-Waiman.Long@hpe.com> Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 2791 Lines: 85 Ding Tianhong reported a live-lock situation where a constant stream of incoming optimistic spinners blocked a task in the wait list from getting the mutex. This patch attempts to fix this live-lock condition by enabling the woken task in the wait queue to enter into an optimistic spinning loop itself in parallel with the regular spinners in the OSQ. This should prevent the live-lock condition from happening. Running the AIM7 benchmarks on a 4-socket E7-4820 v3 system (with ext4 filesystem), the additional spinning of the waiter-spinning improved performance for the following workloads at high user count: Workload % Improvement -------- ------------- alltests 3.9% disk 3.4% fserver 2.0% long 3.8% new_fserver 10.5% The other workloads were about the same as before. Signed-off-by: Waiman Long --- kernel/locking/mutex.c | 16 +++++++++++++++- 1 files changed, 15 insertions(+), 1 deletions(-) diff --git a/kernel/locking/mutex.c b/kernel/locking/mutex.c index 5dd6171..5c0acee 100644 --- a/kernel/locking/mutex.c +++ b/kernel/locking/mutex.c @@ -538,6 +538,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass, struct task_struct *task = current; struct mutex_waiter waiter; unsigned long flags; + bool acquired = false; /* True if the lock is acquired */ int ret; preempt_disable(); @@ -568,7 +569,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass, lock_contended(&lock->dep_map, ip); - for (;;) { + while (!acquired) { /* * Lets try to take the lock again - this is needed even if * we get here for the first time (shortly after failing to @@ -603,6 +604,15 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass, /* didn't get the lock, go to sleep: */ spin_unlock_mutex(&lock->wait_lock, flags); schedule_preempt_disabled(); + + /* + * Optimistically spinning on the mutex without the wait lock + * The state has to be set to running to avoid another waker + * spinning on the on_cpu flag while the woken waiter is + * spinning on the mutex. + */ + acquired = mutex_optimistic_spin(lock, ww_ctx, use_ww_ctx, + true); spin_lock_mutex(&lock->wait_lock, flags); } __set_task_state(task, TASK_RUNNING); @@ -613,6 +623,9 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass, atomic_set(&lock->count, 0); debug_mutex_free_waiter(&waiter); + if (acquired) + goto unlock; + skip_wait: /* got the lock - cleanup and rejoice! */ lock_acquired(&lock->dep_map, ip); @@ -623,6 +636,7 @@ skip_wait: ww_mutex_set_context_slowpath(ww, ww_ctx); } +unlock: spin_unlock_mutex(&lock->wait_lock, flags); preempt_enable(); return 0; -- 1.7.1