From owner-svn-src-head@freebsd.org Thu Mar 12 02:16:21 2020 Return-Path: Delivered-To: svn-src-head@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id 36223272073; Thu, 12 Mar 2020 02:16:21 +0000 (UTC) (envelope-from mjguzik@gmail.com) Received: from mail-wm1-x344.google.com (mail-wm1-x344.google.com [IPv6:2a00:1450:4864:20::344]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits) server-signature RSA-PSS (4096 bits) client-signature RSA-PSS (2048 bits) client-digest SHA256) (Client CN "smtp.gmail.com", Issuer "GTS CA 1O1" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 48dC9v44k2z4Sr3; Thu, 12 Mar 2020 02:16:19 +0000 (UTC) (envelope-from mjguzik@gmail.com) Received: by mail-wm1-x344.google.com with SMTP id h83so979625wmf.3; Wed, 11 Mar 2020 19:16:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=mime-version:in-reply-to:references:from:date:message-id:subject:to :cc; bh=9Rc+IkO89V8i3yttOjoFQ67aVR1M7BknWa4hXEWDJeQ=; b=aLc1pUHPy9I00VB52KwdXAvAzVLGhtBqTqf76QwVdCaK1O4/NKG4wIqR/sMCa6HLJ6 /Tbg3yM240NgDgpQwn9z00KU3CUyEnQiXVu9beI+1u4moeRWUYj2fJdWChbjD+1d2BWk RQnnB7PX/Urx26wPEjmk3z42ygi0woneKA1wjYbYJJQQ2SxGwHyPfZulPSrWNfI1orC3 3z/5RVTvCmLktaNlo3khsoLrtml4PQeUti0xQA6yAWb5TSjCPycn4W2tfh5K9yPzSjOj jz6n96SfitFJZfNxQHFlY89eD0jrQdmLwLdRR8Ft1UybiA7XFKC/H4H7n2s0cJzvEkFN 0Byg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:in-reply-to:references:from:date :message-id:subject:to:cc; bh=9Rc+IkO89V8i3yttOjoFQ67aVR1M7BknWa4hXEWDJeQ=; b=M0st8EVI48rltzV2zFSWvaeoBqNKzKrWXBML7Fexco0nFzKkw60tgWV1cB2wf+vbHg 0lgaTx9ahMAt/i4yvi05pJiiY+VmhzUgznOBZmhQlf0IT0IEoFU7gE4VyG5tpnT8sLa0 nZwPSfw9nh/zDRyfDyYq4Cac+FtcllQxQvACGEgfKJS1Yh11uEgNOF8JtEz7mQqHQfFC slmLpuSshPhhAVBdtiL3aSurvFDP007OOsEmS+aAR9E+DKVhZ940k10FnLwIOmCe9I6J OB6UAfultOHsFl4X1BGiQQOWDV6T30gqW37fPsN7NM2ymEHdjn4tsYaXUBxRekYd2Uoi IlaA== X-Gm-Message-State: ANhLgQ0Sa08xvcPDTMRwLgk8dv8mR2BcrHBn8jyjH6V5jo1XhUr77uIT /s7PctCGf+GQfmUOCWy4ZQJNSj4yOMbun0KO4MU= X-Google-Smtp-Source: ADFU+vufR0worly8Rm9QUhw8/+cpLU2pw4bAcLg6GZ7Y+XI6iWeSYnZAdDEFSXoI6OSMlcmuRq4vFYbSd8tdWEErHTQ= X-Received: by 2002:a05:600c:20c9:: with SMTP id y9mr1864032wmm.83.1583979376887; Wed, 11 Mar 2020 19:16:16 -0700 (PDT) MIME-Version: 1.0 Received: by 2002:adf:f089:0:0:0:0:0 with HTTP; Wed, 11 Mar 2020 19:16:15 -0700 (PDT) In-Reply-To: <20200310192326.GC1992@kib.kiev.ua> References: <202003080022.0280MX9j055805@repo.freebsd.org> <20200309213512.GS98340@kib.kiev.ua> <20200310192326.GC1992@kib.kiev.ua> From: Mateusz Guzik Date: Thu, 12 Mar 2020 03:16:15 +0100 Message-ID: Subject: Re: svn commit: r358733 - head/sys/sys To: Konstantin Belousov Cc: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Content-Type: text/plain; charset="UTF-8" X-Rspamd-Queue-Id: 48dC9v44k2z4Sr3 X-Spamd-Bar: -- Authentication-Results: mx1.freebsd.org; dkim=pass header.d=gmail.com header.s=20161025 header.b=aLc1pUHP; dmarc=pass (policy=none) header.from=gmail.com; spf=pass (mx1.freebsd.org: domain of mjguzik@gmail.com designates 2a00:1450:4864:20::344 as permitted sender) smtp.mailfrom=mjguzik@gmail.com X-Spamd-Result: default: False [-3.00 / 15.00]; ARC_NA(0.00)[]; NEURAL_HAM_MEDIUM(-1.00)[-1.000,0]; R_DKIM_ALLOW(-0.20)[gmail.com:s=20161025]; FROM_HAS_DN(0.00)[]; RCPT_COUNT_THREE(0.00)[4]; FREEMAIL_FROM(0.00)[gmail.com]; R_SPF_ALLOW(-0.20)[+ip6:2a00:1450:4000::/36]; MIME_GOOD(-0.10)[text/plain]; IP_SCORE(0.00)[ip: (2.61), ipnet: 2a00:1450::/32(-2.40), asn: 15169(-1.65), country: US(-0.05)]; NEURAL_HAM_LONG(-1.00)[-1.000,0]; TO_DN_SOME(0.00)[]; IP_SCORE_FREEMAIL(0.00)[]; TO_MATCH_ENVRCPT_SOME(0.00)[]; DKIM_TRACE(0.00)[gmail.com:+]; DMARC_POLICY_ALLOW(-0.50)[gmail.com,none]; RCVD_IN_DNSWL_NONE(0.00)[4.4.3.0.0.0.0.0.0.0.0.0.0.0.0.0.0.2.0.0.4.6.8.4.0.5.4.1.0.0.a.2.list.dnswl.org : 127.0.5.0]; FREEMAIL_TO(0.00)[gmail.com]; FROM_EQ_ENVFROM(0.00)[]; MIME_TRACE(0.00)[0:+]; FREEMAIL_ENVFROM(0.00)[gmail.com]; ASN(0.00)[asn:15169, ipnet:2a00:1450::/32, country:US]; RCVD_COUNT_TWO(0.00)[2]; RCVD_TLS_ALL(0.00)[]; DWL_DNSWL_NONE(0.00)[gmail.com.dwl.dnswl.org : 127.0.5.0] X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 12 Mar 2020 02:16:21 -0000 On 3/10/20, Konstantin Belousov wrote: > On Tue, Mar 10, 2020 at 12:22:09AM +0100, Mateusz Guzik wrote: >> On 3/9/20, Konstantin Belousov wrote: >> > On Mon, Mar 09, 2020 at 01:56:17AM +0100, Mateusz Guzik wrote: >> >> On 3/8/20, Mateusz Guzik wrote: >> >> > Author: mjg >> >> > Date: Sun Mar 8 00:22:32 2020 >> >> > New Revision: 358733 >> >> > URL: https://svnweb.freebsd.org/changeset/base/358733 >> >> > >> >> > Log: >> >> > seqc: tidy up >> >> > >> >> > - avoid hand-rolled read >> >> > - match begin/end in terms of fence style >> >> > >> >> >> >> There were off lists questions about this so let me clarify. >> >> >> >> The first bit is a cosmetic change, but the second one is not. >> >> >> >> > Modified: >> >> > head/sys/sys/seqc.h >> >> > >> >> > Modified: head/sys/sys/seqc.h >> >> > ============================================================================== >> >> > --- head/sys/sys/seqc.h Sat Mar 7 15:37:23 2020 (r358732) >> >> > +++ head/sys/sys/seqc.h Sun Mar 8 00:22:32 2020 (r358733) >> >> > @@ -66,7 +66,8 @@ static __inline void >> >> > seqc_write_end(seqc_t *seqcp) >> >> > { >> >> > >> >> > - atomic_store_rel_int(seqcp, *seqcp + 1); >> >> > + atomic_thread_fence_rel(); >> >> > + *seqcp += 1; >> >> > MPASS(!seqc_in_modify(*seqcp)); >> >> > critical_exit(); >> >> > } >> >> >> >> For correct operation the counter has to be modified *before* any work >> >> is done and *after* it is completed. >> >> >> >> Consider a trivial case: >> >> seqc++; >> >> foo[0] = 0; >> >> foo[1] = 1; >> >> seqc++; >> >> >> >> There are 2 ways in which this can be mucked with: >> >> - the compiler can be looking at reordering or reworking the increment >> >> (e.g., to collapse it to just += 2 instead). a compiler barrier >> >> prevents that. >> >> - even with generated machine code which increments in correct places >> >> the cpu can be looking at reordering the operation (which is heavily >> >> dependent on architecture), in particular it could end up issuing >> >> seqc++; foo[1] = 1; which would defeat the point. This is where >> >> release fences come in. >> >> >> >> With the patched code there is: >> >> seqc++; >> >> atomic_thread_fence_rel(); /* make sure seqc++ is issued before foo >> >> starts getting modified */ >> >> foo[0] = 0; >> >> foo[1] = 1; >> >> atomic_thread_fence_rel(); /* make sure modifications to foo don't >> >> leak past this spot */ >> >> seqc++; >> >> >> >> In comparison, the previous code was: >> >> seqc++; >> >> atomic_thread_fence_rel(); /* make sure seqc++ is issued before foo >> >> starts getting modified */ >> >> foo[0] = 0; >> >> foo[1] = 1; >> >> atomic_store_rel_int(seqcp, *seqcp + 1); /* make sure modifications to >> >> too don't leak past this spot and update seqc immediately */ >> >> >> >> There are 2 differences here -- one is an improvement and second one >> >> does not matter: >> >> the win is: the previous code forces the compiler to compute an >> >> incremented value and then store it. On amd64 this translates to the >> >> following (with rdx holding the address of the counter): >> >> >> >> mov (%rdx),%eax /* load the value */ >> >> add $0x1,%eax /* add 1 */ >> >> mov %eax,(%rdx) /* store it */ >> >> >> >> On patched kernel this is: >> >> addl $0x1,(%rdx) >> >> >> >> which is clearly much nicer. >> > I am not sure that the new code on amd64 is much nicer. >> > >> > But the point was that on non-amd64, i.e. armv8 and potentially on >> > powerpc 3.0, the patch substitutes release store with full barrier. The >> > later is (much) slower. >> > >> >> If an arch performs something significantly more expensive here it's >> probably a performance bug in the port. > It is a question of how much hardware support for fine-grained fences. > Relaxed architectures add some optimized operations already, but did not > (yet) implemented complete C11 optimized set. > I think they eventually converge. > > Until they did not, I think it is more important to not pessimize > to-be Tier1 arches than to collapse three fast integer instructions > on amd64 into one rw op. > >> But perhaps more importantly >> there are significantly more frequent users of >> atomic_thread_fence_rel, like refcount(9). If the issue is real that >> should be looked at. > For refcount(9) use of release fence removal, we would need > atomic_fetchadd_rel_int(). > To reiterate, if atomic_thread_fence_rel is indeed very expensive on certain architectures compared to other _rel variants, the kernel is already heavily pessimized because of use of said standalone fence in refcount(9) and few other places and this needs to be fixed. If the cost can't be reduced (e.g., perhaps this can do a no-op store + fence somewhere akin to how lock xadd 0,(%esp) trickery used to work), then the atomic APIs do indeed not to be completed w.r.t. adding all the missing acq/rel variants (that's at least fetchadd and swap). We can also extend the API to do relevant addition/subtraction without guaranteeing atomicity vs concurrent updates, but while providing relevant fences. This would preserve the intended state achieved with this commit while not interfering with others. I can add the missing amd64 bits if other people cover their architectures, but otherwise I'm not interested in doing anything here. seqc itself, apart from being a minor consumer compared to refcount, was already using the standalone fence even prior to this change thus I don't think there is any rush to do anything with regards to this particular commit. >> >> >> >> >> the not a problem: the code does not issue the release fence after >> >> incrementing the counter the second time, meaning that in principle it >> >> can happen arbitrarily late, possibly disturbing code which waits for >> >> the counter to become even. This is not a problem because in whoever >> >> modifies it is supposed to have a lock and release it shortly after, >> >> which also posts the release fence and consequently makes sure the >> >> counter update is visible. Also note these routines come with >> >> preemption disablement around the modification -- if the thread gets >> >> preempted as a result of critical_exit from seqc_write_end, it will >> >> also publish the updated counter. If the updater never does anything >> >> which flushes the store buffer then in the absolute worst case they >> >> will get preempted, at which point once more we are covered. Note that >> >> code which wants more deterministic behavior will want to >> >> seqc_read_any, test the counter once and if it is caught uneven resort >> >> to locking. >> >> >> >> > @@ -84,7 +85,7 @@ seqc_read(const seqc_t *seqcp) >> >> > seqc_t ret; >> >> > >> >> > for (;;) { >> >> > - ret = atomic_load_acq_int(__DECONST(seqc_t *, seqcp)); >> >> > + ret = seqc_read_any(seqcp); >> >> > if (__predict_false(seqc_in_modify(ret))) { >> >> > cpu_spinwait(); >> >> > continue; >> >> > _______________________________________________ >> >> > svn-src-all@freebsd.org mailing list >> >> > https://lists.freebsd.org/mailman/listinfo/svn-src-all >> >> > To unsubscribe, send any mail to >> >> > "svn-src-all-unsubscribe@freebsd.org" >> >> > >> >> >> >> >> >> -- >> >> Mateusz Guzik >> > >> >> >> -- >> Mateusz Guzik > -- Mateusz Guzik