There are some compiler bugs around some single-bit test-and-set or test-and-reset operations, mostly affecting the most significant bit of a word.
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102566
https://github.com/llvm/llvm-project/issues/37322
That is, when the compilers generate code for the IA-32 or AMD64 ISA, they would emit a loop around the LOCK CMPXCHG instruction, instead of emitting LOCK BTS, LOCK BTR, LOCK OR or LOCK AND. Here is a test program:
#include <atomic>
|
uint32_t fa(std::atomic<uint32_t>&a) { return a.fetch_and(~(1U<<31)) & 1U<<31;}
|
uint32_t fo(std::atomic<uint32_t>&a) { return a.fetch_or(1U<<31) & 1U<<31;}
|
Starting with clang++-15 or GCC 7.1 (the first GA release of that GCC series), no LOCK CMPXCHG will be generated for the above.
Fortunately, the oldest major GCC version that is included in any currently supported GNU/Linux distribution is 7. Also, FreeBSD 14 is using clang version 16. So, there should not be any need to worry about older versions of these compilers anymore.
However, even the most recent version of MSVC would generate LOCK CMPXCHG for these. We would be forced to use _interlockedbittestandset() or _interlockedbittestandreset() on that platform in order to avoid a performance regression.
{"report":{"fcp":935.5,"ttfb":270.09999990463257,"pageVisibility":"visible","entityId":130852,"key":"jira.project.issue.view-issue","isInitial":true,"threshold":1000,"elementTimings":{},"userDeviceMemory":8,"userDeviceProcessors":64,"apdex":0.5,"journeyId":"aae78d2b-a858-4ade-8572-8880db1b1829","navigationType":0,"readyForUser":1010.0999999046326,"redirectCount":0,"resourceLoadedEnd":639.5999999046326,"resourceLoadedStart":276.2000002861023,"resourceTiming":[{"duration":41.19999980926514,"initiatorType":"link","name":"https://jira.mariadb.org/s/2c21342762a6a02add1c328bed317ffd-CDN/lu2cib/820016/12ta74/0a8bac35585be7fc6c9cc5a0464cd4cf/_/download/contextbatch/css/_super/batch.css","startTime":276.2000002861023,"connectEnd":0,"connectStart":0,"domainLookupEnd":0,"domainLookupStart":0,"fetchStart":276.2000002861023,"redirectEnd":0,"redirectStart":0,"requestStart":0,"responseEnd":317.40000009536743,"responseStart":0,"secureConnectionStart":0},{"duration":42.59999990463257,"initiatorType":"link","name":"https://jira.mariadb.org/s/7ebd35e77e471bc30ff0eba799ebc151-CDN/lu2cib/820016/12ta74/494e4c556ecbb29f90a3d3b4f09cb99c/_/download/contextbatch/css/jira.browse.project,project.issue.navigator,jira.view.issue,jira.general,jira.global,atl.general,-_super/batch.css?agile_global_admin_condition=true&jag=true&jira.create.linked.issue=true&slack-enabled=true&whisper-enabled=true","startTime":276.5,"connectEnd":0,"connectStart":0,"domainLookupEnd":0,"domainLookupStart":0,"fetchStart":276.5,"redirectEnd":0,"redirectStart":0,"requestStart":0,"responseEnd":319.09999990463257,"responseStart":0,"secureConnectionStart":0},{"duration":217.39999961853027,"initiatorType":"script","name":"https://jira.mariadb.org/s/0917945aaa57108d00c5076fea35e069-CDN/lu2cib/820016/12ta74/0a8bac35585be7fc6c9cc5a0464cd4cf/_/download/contextbatch/js/_super/batch.js?locale=en","startTime":276.7000002861023,"connectEnd":276.7000002861023,"connectStart":276.7000002861023,"domainLookupEnd":276.7000002861023,"domainLookupStart":276.7000002861023,"fetchStart":276.7000002861023,"redirectEnd":0,"redirectStart":0,"requestStart":326,"responseEnd":494.09999990463257,"responseStart":352.40000009536743,"secureConnectionStart":276.7000002861023},{"duration":362.69999980926514,"initiatorType":"script","name":"https://jira.mariadb.org/s/2d8175ec2fa4c816e8023260bd8c1786-CDN/lu2cib/820016/12ta74/494e4c556ecbb29f90a3d3b4f09cb99c/_/download/contextbatch/js/jira.browse.project,project.issue.navigator,jira.view.issue,jira.general,jira.global,atl.general,-_super/batch.js?agile_global_admin_condition=true&jag=true&jira.create.linked.issue=true&locale=en&slack-enabled=true&whisper-enabled=true","startTime":276.90000009536743,"connectEnd":276.90000009536743,"connectStart":276.90000009536743,"domainLookupEnd":276.90000009536743,"domainLookupStart":276.90000009536743,"fetchStart":276.90000009536743,"redirectEnd":0,"redirectStart":0,"requestStart":327.09999990463257,"responseEnd":639.5999999046326,"responseStart":354.80000019073486,"secureConnectionStart":276.90000009536743},{"duration":84,"initiatorType":"script","name":"https://jira.mariadb.org/s/a9324d6758d385eb45c462685ad88f1d-CDN/lu2cib/820016/12ta74/c92c0caa9a024ae85b0ebdbed7fb4bd7/_/download/contextbatch/js/atl.global,-_super/batch.js?locale=en","startTime":277,"connectEnd":277,"connectStart":277,"domainLookupEnd":277,"domainLookupStart":277,"fetchStart":277,"redirectEnd":0,"redirectStart":0,"requestStart":328.2000002861023,"responseEnd":361,"responseStart":358,"secureConnectionStart":277},{"duration":81.69999980926514,"initiatorType":"script","name":"https://jira.mariadb.org/s/d41d8cd98f00b204e9800998ecf8427e-CDN/lu2cib/820016/12ta74/1.0/_/download/batch/jira.webresources:calendar-en/jira.webresources:calendar-en.js","startTime":277.2000002861023,"connectEnd":277.2000002861023,"connectStart":277.2000002861023,"domainLookupEnd":277.2000002861023,"domainLookupStart":277.2000002861023,"fetchStart":277.2000002861023,"redirectEnd":0,"redirectStart":0,"requestStart":328.09999990463257,"responseEnd":358.90000009536743,"responseStart":357,"secureConnectionStart":277.2000002861023},{"duration":84,"initiatorType":"script","name":"https://jira.mariadb.org/s/d41d8cd98f00b204e9800998ecf8427e-CDN/lu2cib/820016/12ta74/1.0/_/download/batch/jira.webresources:calendar-localisation-moment/jira.webresources:calendar-localisation-moment.js","startTime":277.40000009536743,"connectEnd":277.40000009536743,"connectStart":277.40000009536743,"domainLookupEnd":277.40000009536743,"domainLookupStart":277.40000009536743,"fetchStart":277.40000009536743,"redirectEnd":0,"redirectStart":0,"requestStart":329.7000002861023,"responseEnd":361.40000009536743,"responseStart":359,"secureConnectionStart":277.40000009536743},{"duration":48,"initiatorType":"link","name":"https://jira.mariadb.org/s/b04b06a02d1959df322d9cded3aeecc1-CDN/lu2cib/820016/12ta74/a2ff6aa845ffc9a1d22fe23d9ee791fc/_/download/contextbatch/css/jira.global.look-and-feel,-_super/batch.css","startTime":277.59999990463257,"connectEnd":0,"connectStart":0,"domainLookupEnd":0,"domainLookupStart":0,"fetchStart":277.59999990463257,"redirectEnd":0,"redirectStart":0,"requestStart":0,"responseEnd":325.59999990463257,"responseStart":0,"secureConnectionStart":0},{"duration":83.7999997138977,"initiatorType":"script","name":"https://jira.mariadb.org/rest/api/1.0/shortcuts/820016/47140b6e0a9bc2e4913da06536125810/shortcuts.js?context=issuenavigation&context=issueaction","startTime":277.80000019073486,"connectEnd":277.80000019073486,"connectStart":277.80000019073486,"domainLookupEnd":277.80000019073486,"domainLookupStart":277.80000019073486,"fetchStart":277.80000019073486,"redirectEnd":0,"redirectStart":0,"requestStart":330.90000009536743,"responseEnd":361.59999990463257,"responseStart":359.59999990463257,"secureConnectionStart":277.80000019073486},{"duration":47.80000019073486,"initiatorType":"link","name":"https://jira.mariadb.org/s/3ac36323ba5e4eb0af2aa7ac7211b4bb-CDN/lu2cib/820016/12ta74/d176f0986478cc64f24226b3d20c140d/_/download/contextbatch/css/com.atlassian.jira.projects.sidebar.init,-_super,-project.issue.navigator,-jira.view.issue/batch.css?jira.create.linked.issue=true","startTime":278,"connectEnd":0,"connectStart":0,"domainLookupEnd":0,"domainLookupStart":0,"fetchStart":278,"redirectEnd":0,"redirectStart":0,"requestStart":0,"responseEnd":325.80000019073486,"responseStart":0,"secureConnectionStart":0},{"duration":83.59999990463257,"initiatorType":"script","name":"https://jira.mariadb.org/s/5d5e8fe91fbc506585e83ea3b62ccc4b-CDN/lu2cib/820016/12ta74/d176f0986478cc64f24226b3d20c140d/_/download/contextbatch/js/com.atlassian.jira.projects.sidebar.init,-_super,-project.issue.navigator,-jira.view.issue/batch.js?jira.create.linked.issue=true&locale=en","startTime":278.2000002861023,"connectEnd":278.2000002861023,"connectStart":278.2000002861023,"domainLookupEnd":278.2000002861023,"domainLookupStart":278.2000002861023,"fetchStart":278.2000002861023,"redirectEnd":0,"redirectStart":0,"requestStart":331.09999990463257,"responseEnd":361.80000019073486,"responseStart":360.09999990463257,"secureConnectionStart":278.2000002861023},{"duration":305,"initiatorType":"script","name":"https://jira.mariadb.org/s/d41d8cd98f00b204e9800998ecf8427e-CDN/lu2cib/820016/12ta74/1.0/_/download/batch/jira.webresources:bigpipe-js/jira.webresources:bigpipe-js.js","startTime":278.90000009536743,"connectEnd":278.90000009536743,"connectStart":278.90000009536743,"domainLookupEnd":278.90000009536743,"domainLookupStart":278.90000009536743,"fetchStart":278.90000009536743,"redirectEnd":0,"redirectStart":0,"requestStart":396.7000002861023,"responseEnd":583.9000000953674,"responseStart":577,"secureConnectionStart":278.90000009536743},{"duration":306.19999980926514,"initiatorType":"script","name":"https://jira.mariadb.org/s/d41d8cd98f00b204e9800998ecf8427e-CDN/lu2cib/820016/12ta74/1.0/_/download/batch/jira.webresources:bigpipe-init/jira.webresources:bigpipe-init.js","startTime":278.90000009536743,"connectEnd":278.90000009536743,"connectStart":278.90000009536743,"domainLookupEnd":278.90000009536743,"domainLookupStart":278.90000009536743,"fetchStart":278.90000009536743,"redirectEnd":0,"redirectStart":0,"requestStart":429.2000002861023,"responseEnd":585.0999999046326,"responseStart":581.2000002861023,"secureConnectionStart":278.90000009536743},{"duration":140.30000019073486,"initiatorType":"xmlhttprequest","name":"https://jira.mariadb.org/rest/webResources/1.0/resources","startTime":670,"connectEnd":670,"connectStart":670,"domainLookupEnd":670,"domainLookupStart":670,"fetchStart":670,"redirectEnd":0,"redirectStart":0,"requestStart":776.7000002861023,"responseEnd":810.3000001907349,"responseStart":809.4000000953674,"secureConnectionStart":670}],"fetchStart":0,"domainLookupStart":56,"domainLookupEnd":68,"connectStart":68,"connectEnd":87,"secureConnectionStart":76,"requestStart":89,"responseStart":270,"responseEnd":274,"domLoading":274,"domInteractive":1107,"domContentLoadedEventStart":1107,"domContentLoadedEventEnd":1165,"domComplete":1561,"loadEventStart":1561,"loadEventEnd":1561,"userAgent":"Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; ClaudeBot/1.0; +claudebot@anthropic.com)","marks":[{"name":"bigPipe.sidebar-id.start","time":1085},{"name":"bigPipe.sidebar-id.end","time":1085.9000000953674},{"name":"bigPipe.activity-panel-pipe-id.start","time":1086.0999999046326},{"name":"bigPipe.activity-panel-pipe-id.end","time":1087.2000002861023},{"name":"activityTabFullyLoaded","time":1178.5999999046326}],"measures":[],"correlationId":"1c185ad76c42ea","effectiveType":"4g","downlink":10,"rtt":0,"serverDuration":104,"dbReadsTimeInMs":10,"dbConnsTimeInMs":18,"applicationHash":"9d11dbea5f4be3d4cc21f03a88dd11d8c8687422","experiments":[]}}
It turns out that only starting with GCC 13, a test-and-set of the most significant bit actually works efficiently in srw_lock.cc. Any version of clang would still emit a loop around lock cmpxchg.
This can be worked around by moving the HOLDER flag from the most significant to the least significant end of the lock word; then it will work starting with clang 15 and GCC 7.
Note: Switching from uint32_t to int32_t is not an option, because then it would be UB to toggle the most significant bit of the lock word in some std::atomic::fetch_add() operations, which is what the code is doing elsewhere.