From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752808AbcHLRQ3 (ORCPT ); Fri, 12 Aug 2016 13:16:29 -0400 Received: from mga09.intel.com ([134.134.136.24]:13886 "EHLO mga09.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752461AbcHLRQ2 (ORCPT ); Fri, 12 Aug 2016 13:16:28 -0400 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.28,511,1464678000"; d="scan'208";a="154907940" Subject: Re: [RESEND PATCH v4] x86/hpet: Reduce HPET counter read contention To: Waiman Long References: <1470853770-37625-1-git-send-email-Waiman.Long@hpe.com> <57ACD2DE.6080306@intel.com> <57AD0898.7030506@hpe.com> <57AD18D1.1050107@intel.com> <57AE00EE.8070904@hpe.com> Cc: Thomas Gleixner , Ingo Molnar , "H. Peter Anvin" , linux-kernel@vger.kernel.org, x86@kernel.org, Jiang Liu , Borislav Petkov , Andy Lutomirski , Prarit Bhargava , Scott J Norton , Douglas Hatch , Randy Wright , John Stultz From: Dave Hansen Message-ID: <57AE0469.10503@intel.com> Date: Fri, 12 Aug 2016 10:16:25 -0700 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Thunderbird/38.8.0 MIME-Version: 1.0 In-Reply-To: <57AE00EE.8070904@hpe.com> Content-Type: text/plain; charset=windows-1252 Content-Transfer-Encoding: 7bit Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On 08/12/2016 10:01 AM, Waiman Long wrote: > The reason for using a special lock is that I want both sequence number > update and locking to be done together atomically. They can be made > separate as is in the seqlock. However, that will make the code more > complex to make sure that all the threads see a consistent set of lock > state and sequence number. Why do we need a sequence number? The "cached" HPET itself could be used. I'm thinking something like below could use a spinlock instead of the doing a custom cmpxchg sequence. The spin_is_locked() should allow the contended "readers" to avoid using atomics. spinlock_t hpet_lock; u32 hpet_value; ... { u32 old_hpet = READ_ONCE(hpet_value); u32 new_hpet; // need to ensure that the spin_is_locked() is ordered after // the READ_ONCE(). smp_rmb(); // spin_is_locked() doesn't do atomics if (!spin_is_locked(&hpet_lock) && spin_trylock(&hpet_lock)) { WRITE_ONCE(hpet_value, real_read_hpet()); spin_unlock(&hpet_lock); return hpet_value; } // Contended case. We spin here waiting for the guy who holds // the lock to write a new value to 'hpet_value'. // // We know that our old_hpet is older than our check for the // spinlock being locked. So, someone must either have already // updated it or be updating it. do { cpu_relax(); // We do not do a rmb() here. We don't need a guarantee // that this read is up-to-date, just that it will // _eventually_ see an up-to-date value. new_hpet = READ_ONCE(hpet_value); } while (old_hpet == new_hpet); return new_hpet; }