Skip to content

Conversation

jonatack
Copy link
Member

@jonatack jonatack commented Aug 18, 2021

To enable lock contention logging, DEBUG_LOCKCONTENTION has to be defined at compilation. Once built, the logging is not limited to a category and is high frequency, verbose and in all-caps. With these factors combined, it seems likely to be rarely used.

This patch:

  • adds a lock logging category
  • adds a timing macro in microseconds, LOG_TIME_MICROS_WITH_CATEGORY
  • updates BCLog::LogMsg() to omit irrelevant decimals for microseconds and skip unneeded code and math
  • improves the lock contention logging, drops the all-caps, and displays the duration in microseconds
  • removes the conditional compilation directives
  • allows lock contentions to be logged on startup with -debug=lock or at run time with bitcoin-cli logging '["lock"]'
$ bitcoind -signet -debug=lock
2021-09-01T12:40:01Z LockContention: cs_vNodes, net.cpp:1920 started
2021-09-01T12:40:01Z LockContention: cs_vNodes, net.cpp:1920 completed (4μs)
2021-09-01T12:40:01Z LockContention: cs_vNodes, net.cpp:1302 started
2021-09-01T12:40:01Z LockContention: cs_vNodes, net.cpp:1302 completed (4μs)
2021-09-01T12:40:02Z LockContention: cs_vNodes, net.cpp:2242 started
2021-09-01T12:40:02Z LockContention: cs_vNodes, net.cpp:2242 completed (20μs)
2021-09-01T12:43:04Z LockContention: ::cs_main, validation.cpp:4980 started
2021-09-01T12:43:04Z LockContention: ::cs_main, validation.cpp:4980 completed (3μs)

$ bitcoin-cli -signet logging
  "lock": true,

$ bitcoin-cli -signet logging [] '["lock"]'
  "lock": false,

$ bitcoin-cli -signet logging '["lock"]'
  "lock": true,

I've tested this with Clang 13 and GCC 10.2.1, on Debian, with and without --enable-debug.

@jonatack jonatack marked this pull request as draft August 18, 2021 14:05
src/sync.h Outdated
@@ -138,14 +137,10 @@ class SCOPED_LOCKABLE UniqueLock : public Base
void Enter(const char* pszName, const char* pszFile, int nLine)
{
EnterCritical(pszName, pszFile, nLine, Base::mutex());
#ifdef DEBUG_LOCKCONTENTION
if (!Base::try_lock()) {
Copy link
Member

@laanwj laanwj Aug 18, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am somewhat worried that the extra calls to Base::try_lock cause performance overhead in the non-lock contention debugging case. It's unnecessary. We might want to gate that too on the log category being enabled.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, wondering that as well (or alternatively, leave the directives in place and just improve the logging experience when DEBUG_LOCKCONTENTION is defined).

Copy link
Member Author

@jonatack jonatack Aug 18, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implemented your suggestion (thanks!)

(Behind the gate it could now be just LogPrintf if anyone prefers.)

@DrahtBot DrahtBot added the Tests label Aug 18, 2021
@jonatack jonatack force-pushed the lockcontention-log-instead-of-define branch from 6f6abbe to ccd73de Compare August 18, 2021 18:02
@jonatack
Copy link
Member Author

Moving this out of draft now, ready for review.

@jonatack jonatack marked this pull request as ready for review August 18, 2021 20:15
@DrahtBot
Copy link
Contributor

The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

Conflicts

Reviewers, this pull request conflicts with the following ones:

  • #20487 (Add syscall sandboxing using seccomp-bpf (Linux secure computing mode) by practicalswift)
  • #16365 (Log RPC parameters (arguments) if -debug=rpcparams by LarryRuane)

If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

@laanwj
Copy link
Member

laanwj commented Aug 19, 2021

Code review ACK ccd73de

Copy link
Member

@maflcko maflcko left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cr ACK ccd73de

@practicalswift
Copy link
Contributor

Concept ACK

Nice idea. I've used something similar in my local tree when analysing lock contention locally.

Non-blocking suggestions:

  • In my version I printed the duration too to make it clear from the log entry if the lock contention was significant or not. Perhaps worth adding here too?
  • In addition to __FILE__ and __LINE__ it would be nice to have __FUNCTION__ printed as part of the log message too.

To rule out any accidental performance regressions: would it be possible to benchmark before vs after this PR (with and without -debug=lock) in some intelligent way?

@jonatack jonatack force-pushed the lockcontention-log-instead-of-define branch from ccd73de to 6e7b6bf Compare August 19, 2021 23:11
@jonatack
Copy link
Member Author

jonatack commented Aug 19, 2021

In my version I printed the duration too to make it clear from the log entry if the lock contention was significant or not. Perhaps worth adding here too?

In addition to __FILE__ and __LINE__ it would be nice to have __FUNCTION__ printed as part of the log message too.

I think I'd need your help (propose a commit to pull in?) or you could do it as a follow-up.

To rule out any accidental performance regressions: would it be possible to benchmark before vs after this PR (with and without -debug=lock) in some intelligent way?

I'll look. Without -debug=lock it should be the same, and I'm not sure anyone besides developers would use the lock logging; it's still fairly verbose. In the worst case I suppose we could add a warning in the RPC logging help.

@jonatack
Copy link
Member Author

@laanwj: following up on our IRC convo in #bitcoin-core-builds, as a test just pushed a version with the HAVE_THREAD_LOCAL conditional compilation directives removed to see what happens...

@jonatack
Copy link
Member Author

jonatack commented Aug 20, 2021

To-do:

  • add a smoke test with -debug=lock
  • do some invocation frequency checks and research
  • try benchmarking Mutex::UniqueLock lock() versus try_lock() and the overhead of LogAcceptCategory(BCLog::LOCK), which evaluates to m_categories.load(std::memory_order_relaxed) & category) != 0

@maflcko
Copy link
Member

maflcko commented Aug 20, 2021

add a smoke test with -debug=lock

Shouldn't this be enabled in the functional test already by default?

@jonatack
Copy link
Member Author

Shouldn't this be enabled in the functional test already by default?

You're right, TIL. I was thinking of adding something like this assertion but probably not worth it or reliable enough:

        with node.assert_debug_log(expected_msgs=["Lock contention: cs_main"]):
            node.generate(COINBASE_MATURITY)

@theStack
Copy link
Contributor

Concept ACK

@jonatack
Copy link
Member Author

jonatack commented Aug 20, 2021

Observations

  • void Mutex::UniqueLock::lock() acquires the mutex and blocks until it gains access to it

  • bool Mutex::UniqueLock::try_lock() doesn't block but instead immediately returns whether it acquired the mutex; it may be used by lock() internally as part of the deadlock-avoidance algorithm

  • IIUC the test-and-set logic of these calls is ~constant time, optimised and light/quick if used carefully (i.e. no mutex convoying), compared to system calls, memory/cache coherency and fences, wait queues, lock contentions

  • added the following patch and tested a regular, non-debug clang 13 build of bitcoind synced on mainnet

        if (LogAcceptCategory(BCLog::LOCK)) {
             if (!Base::try_lock()) {
                 LogPrintf("Lock contention: %s, %s:%d\n", pszName, pszFile, nLine);
                 Base::lock();
+            } else {
+                LogPrintf("No lock contention\n");
             }
  • with this, I'm seeing src/sync.h::UniqueLock::Enter() invoked 2500-5000 times per minute, sampled roughly an hour after startup

  • of those, try_lock() returns true 99.26% to 99.91% of the time. In the true case the lock logging should have essentially the same performance as when the lock logging is off

  • thus 0.09% to 0.74% of the time try_lock() returns false, the contention is logged and lock() is then called, in which case the additional overhead compared to lock() alone, if any (~depending on how long the mutex was blocked), is of trying the lock and initially returning false

  • Overall, lock contention seems to be relatively infrequent as a percentage of locks. I'm seeing a few per minute. The most common one I see is cs_vNodes in net.cpp::2242/2277::ThreadMessageHandler.

Edit: recalculated the numbers and updated.

Some resources:

Copy link
Contributor

@theStack theStack left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code-review ACK 6e7b6bf

@hebasto
Copy link
Member

hebasto commented Sep 1, 2021

Concept ACK.

@hebasto
Copy link
Member

hebasto commented Sep 1, 2021

* benchmarking ... the overhead of `LogAcceptCategory(BCLog::LOCK)`, which evaluates to `m_categories.load(std::memory_order_relaxed) & category) != 0`

I think the benchmarking results could depend on a platform.

Could we sacrifice the ability to turn "lock" debugging on/off at runtime, and use just a const?

@jonatack
Copy link
Member Author

jonatack commented Sep 1, 2021

Could we sacrifice the ability to turn "lock" debugging on/off at runtime, and use just a const?

I could be wrong, and this goes way beyond my competence, but readings suggest that these options are low-level, fast, and near constant time compared to system calls, memory/cache coherency and fences, wait queues and (particularly) lock contentions. (Would a difference be apparent in, say, https://bitcoinperf.com? I don't know, but if this helps us reduce contentions, that may be a win. @jamesob, @0xB10C, @martinus thoughts?)

@hebasto
Copy link
Member

hebasto commented Sep 1, 2021

Could we sacrifice the ability to turn "lock" debugging on/off at runtime, and use just a const?

I could be wrong, and this goes way beyond my competence, but readings suggest that these options are low-level, fast, and near constant time compared to system calls, memory/cache coherency and fences, wait queues and (particularly) lock contentions. Would a difference be apparent in, say, https://bitcoinperf.com? I don't know, but if this helps us reduce contentions, that may be a win.

And m_categories.load(std::memory_order_relaxed) could cause cache lines switching, no?

@jonatack
Copy link
Member Author

jonatack commented Sep 1, 2021

And m_categories.load(std::memory_order_relaxed) could cause cache lines switching, no?

Alternative version:

    void Enter(const char* pszName, const char* pszFile, int nLine)
    {
        EnterCritical(pszName, pszFile, nLine, Base::mutex());
        if (Base::try_lock()) return;
        Base::lock();
        LogPrint(BCLog::LOCK, "Lock contention: %s, %s:%d\n", pszName, pszFile, nLine);
    }

@hebasto
Copy link
Member

hebasto commented Sep 1, 2021

And m_categories.load(std::memory_order_relaxed) could cause cache lines switching, no?

Alternative version:

    void Enter(const char* pszName, const char* pszFile, int nLine)
    {
        EnterCritical(pszName, pszFile, nLine, Base::mutex());
        if (Base::try_lock()) return;
        Base::lock();
        LogPrint(BCLog::LOCK, "Lock contention: %s, %s:%d\n", pszName, pszFile, nLine);
    }

Nice!

Maybe put logging before the blocking call Base::lock(); as it is now? The LogPrint call takes some time, and it could increase probability of releasing a mutex by another thread before the Base::lock() call.

@jonatack
Copy link
Member Author

jonatack commented Sep 1, 2021

And m_categories.load(std::memory_order_relaxed) could cause cache lines switching, no?

I don't know.

Maybe put logging before the blocking call Base::lock(); as it is now? The LogPrint call takes some time, and it could increase probability of releasing a mutex by another thread before the Base::lock() call.

Seems like a good idea--done.

@bitcoin bitcoin deleted a comment from jaysonmald35 Sep 1, 2021
@bitcoin bitcoin deleted a comment from jaysonmald35 Sep 1, 2021
@jonatack
Copy link
Member Author

jonatack commented Sep 1, 2021

How about microseconds?

diff --git a/src/logging/timer.h b/src/logging/timer.h
index 159920e397..cadfe395ee 100644
--- a/src/logging/timer.h
+++ b/src/logging/timer.h
@@ -93,6 +93,8 @@ private:
 } // namespace BCLog
 
 
+#define LOG_TIME_MICROS_WITH_CATEGORY(end_msg, log_category) \
+    BCLog::Timer<std::chrono::microseconds> PASTE2(logging_timer, __COUNTER__)(__func__, end_msg, log_category)
 #define LOG_TIME_MILLIS_WITH_CATEGORY(end_msg, log_category) \
     BCLog::Timer<std::chrono::milliseconds> PASTE2(logging_timer, __COUNTER__)(__func__, end_msg, log_category)
 #define LOG_TIME_SECONDS(end_msg) \
diff --git a/src/sync.cpp b/src/sync.cpp
index a7b63ea986..eace86d9dd 100644
--- a/src/sync.cpp
+++ b/src/sync.cpp
@@ -24,9 +24,9 @@
 #include <utility>
 #include <vector>
 
-void PrintLockContention(const char* pszName, const char* pszFile, int nLine)
+void LockContention(const char* pszName, const char* pszFile, int nLine)
 {
-    LOG_TIME_MILLIS_WITH_CATEGORY(strprintf("%s, %s:%d", pszName, pszFile, nLine), BCLog::LOCK);
+    LOG_TIME_MICROS_WITH_CATEGORY(strprintf("%s, %s:%d", pszName, pszFile, nLine), BCLog::LOCK);
 }
 
 #ifdef DEBUG_LOCKORDER
diff --git a/src/sync.h b/src/sync.h
index 252dc95845..0a8ec9e58f 100644
--- a/src/sync.h
+++ b/src/sync.h
@@ -126,7 +126,8 @@ using RecursiveMutex = AnnotatedMixin<std::recursive_mutex>;
 /** Wrapped mutex: supports waiting but not recursive locking */
 typedef AnnotatedMixin<std::mutex> Mutex;
 
-void PrintLockContention(const char* pszName, const char* pszFile, int nLine);
+/** Print a lock contention to the log */
+void LockContention(const char* pszName, const char* pszFile, int nLine);
 
 /** Wrapper around std::unique_lock style lock for Mutex. */
 template <typename Mutex, typename Base = typename Mutex::UniqueLock>
@@ -137,7 +138,7 @@ private:
     {
         EnterCritical(pszName, pszFile, nLine, Base::mutex());
         if (Base::try_lock()) return;
-        PrintLockContention(pszName, pszFile, nLine);
+        LockContention(pszName, pszFile, nLine);
         Base::lock();
     }

2021-09-01T11:29:03Z LockContention: cs_vNodes, net.cpp:1251 started
2021-09-01T11:29:03Z LockContention: cs_vNodes, net.cpp:1251 completed (5μs)
2021-09-01T11:29:03Z LockContention: pnode->cs_vSend, net.cpp:1373 started
2021-09-01T11:29:03Z LockContention: pnode->cs_vSend, net.cpp:1373 completed (31μs)
2021-09-01T11:29:03Z LockContention: cs_vNodes, net.cpp:2277 started
2021-09-01T11:29:03Z LockContention: cs_vNodes, net.cpp:2277 completed (6μs)
2021-09-01T11:29:04Z LockContention: cs_vNodes, net.cpp:2242 started
2021-09-01T11:29:04Z LockContention: cs_vNodes, net.cpp:2242 completed (3μs)

@martinus
Copy link
Contributor

martinus commented Sep 1, 2021

And m_categories.load(std::memory_order_relaxed) could cause cache lines switching, no?

yes, the only guarantee with memory_order_relaxed is that the operation itself is atomic, but other operations are allowed to be shuffled that by the compiler. I personally try to avoid using any of the memory order stuff. It's too easy to get wrong.

By the way, I think that in that patch:

        if (LogAcceptCategory(BCLog::LOCK)) {
             if (!Base::try_lock()) {
                 LogPrintf("Lock contention: %s, %s:%d\n", pszName, pszFile, nLine);
                 Base::lock();
+            } else {
+                LogPrintf("No lock contention\n");
             }

If Base::try_lock() fails strictly speaking that does not necessarily mean that there's a lock contention. std::mutex's try_lock() can also spuriously fail even when no other thread is currently holding a lock: https://en.cppreference.com/w/cpp/thread/mutex/try_lock I have no idea though how often that can happen.

@jonatack jonatack force-pushed the lockcontention-log-instead-of-define branch 2 times, most recently from 1edbd5d to 27392e2 Compare September 1, 2021 12:59
and update BCLog::LogMsg() to omit irrelevant decimals for microseconds
and skip unneeded code and math.
@jonatack jonatack force-pushed the lockcontention-log-instead-of-define branch from 27392e2 to e2ab1a6 Compare September 1, 2021 13:15
@jonatack
Copy link
Member Author

jonatack commented Sep 1, 2021

Thanks for the ideas and feedback. Updates:

  • added a timing macro in microseconds, LOG_TIME_MICROS_WITH_CATEGORY
  • improved BCLog::LogMsg() to omit irrelevant decimals for microseconds and skip unnecessary code/math
  • added time duration in microseconds to the lock contention logging

If Base::try_lock() fails strictly speaking that does not necessarily mean that there's a lock contention. std::mutex's try_lock() can also spuriously fail even when no other thread is currently holding a lock: en.cppreference.com/w/cpp/thread/mutex/try_lock. I have no idea though how often that can happen.

Good point. I read that doc previously and admit to discounting the spurious failures a little, as we don't know the frequency. It seems to be an additional reason to log the contention duration.

jonatack and others added 2 commits September 1, 2021 15:25
in microseconds.

Change the function name in order to print "LockContention" instead
of "PrintLockContention" to the log.  Add Doxygen documentation.

With this change, the lock contention log prints:

2021-09-01T11:29:03Z LockContention: pnode->cs_vSend, net.cpp:1373 started
2021-09-01T11:29:03Z LockContention: pnode->cs_vSend, net.cpp:1373 completed (31μs)
2021-09-01T11:29:03Z LockContention: cs_vNodes, net.cpp:2277 started
2021-09-01T11:29:03Z LockContention: cs_vNodes, net.cpp:2277 completed (6μs)
2021-09-01T11:29:04Z LockContention: cs_vNodes, net.cpp:2242 started
2021-09-01T11:29:04Z LockContention: cs_vNodes, net.cpp:2242 completed (3μs)

Co-authored-by: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com>
Co-authored-by: practicalswift <practicalswift@users.noreply.github.com>
to allow logging the lock contentions without the need to define
DEBUG_LOCKCONTENTION at compile time.
@jonatack jonatack force-pushed the lockcontention-log-instead-of-define branch from e2ab1a6 to 7e69873 Compare September 1, 2021 13:27
Copy link
Member

@hebasto hebasto left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

re-ACK 7e69873, added a contention duration to the log message since my previous review.

Copy link
Contributor

@theStack theStack left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

re-ACK 7e69873 🔏 ⏲️

Since my last ACK, the lock contention logging was improved by also showing the duration in micro-seconds, and an alternate (more elegant) version of UniqueLock::Enter is now used that doesn't need to check whether the lock category is on if there is no contention (#22736 (comment)).

Tested by building with clang 10.0.1 on OpenBSD 6.9 and running ./src/bitcoind -signet -debug=lock on an empty signet datadir.

On my system, during IBD the vast majority of lock contentions happen in

  • cs_main, net_processing.cpp:1476
  • m_mutex, ./checkqueue.h:168
  • m_mutex, ./checkqueue.h:77

After IBD is finished, all lock contentions are in

  • cs_vNodes, net.cpp (different lines)

Most contentions are in the range of 5-10us. (Note that these results are not based on deeper analysis, but on what I saw scrolling through the logs after a few minutes).

@jonatack
Copy link
Member Author

jonatack commented Sep 5, 2021

Thanks for testing! For me, there seems to be a higher frequency of contention and occuring in more places on mainnet than on signet, presumably as the scale/numbers are larger. Also, a big difference in contention durations between a regular build and a debug build, which makes sense.

@maflcko maflcko merged commit fa92777 into bitcoin:master Sep 6, 2021
@jonatack jonatack deleted the lockcontention-log-instead-of-define branch September 6, 2021 08:38
sidhujag pushed a commit to syscoin/syscoin that referenced this pull request Sep 7, 2021
maflcko pushed a commit to bitcoin-core/gui that referenced this pull request Sep 9, 2021
…g macro to fix duration, improve BCLog::LogMsg()

f530202 Make unexpected time type in BCLog::LogMsg() a compile-time error (Martin Ankerl)
bddae7e Add util/types.h with ALWAYS_FALSE template (MarcoFalke)
498b323 log, timer: improve BCLog::LogMsg() (Jon Atack)
8d2f847 sync: inline lock contention logging macro to fix time duration (Jon Atack)

Pull request description:

  Follow-up to #22736.

  The first commit addresses the issue identified and reported by Martin Ankerl in bitcoin/bitcoin#22736 (comment) to fix the lock contention duration reporting.

  The next three commits make improvements to the timer code in `BCLog::LogMsg()` and add `util/types.h` with an `ALWAYS_FALSE` template, that springboard from bitcoin/bitcoin#22736 (comment) by Marco Falke.

ACKs for top commit:
  martinus:
    re-ACK f530202. I ran a fully synced node for about a day. My node was mostly idle though so not much was going on. I [wrote a little script](https://github.com/martinus/bitcoin-stuff/blob/main/scripts/parse-debuglog-contention-single.rb) to parse the `debug.log` and summarize the output to see if anything interesting was going on, here is the result:
  theStack:
    ACK f530202

Tree-SHA512: 37d093eac5590e1b5846ab5994d0950d71e131177d1afe4a5f7fcd614270f977e0ea117e7af788e9a74ddcccab35b42ec8fa4db3a3378940d4988df7d21cdaaa
sidhujag pushed a commit to syscoin/syscoin that referenced this pull request Sep 11, 2021
…to fix duration, improve BCLog::LogMsg()

f530202 Make unexpected time type in BCLog::LogMsg() a compile-time error (Martin Ankerl)
bddae7e Add util/types.h with ALWAYS_FALSE template (MarcoFalke)
498b323 log, timer: improve BCLog::LogMsg() (Jon Atack)
8d2f847 sync: inline lock contention logging macro to fix time duration (Jon Atack)

Pull request description:

  Follow-up to bitcoin#22736.

  The first commit addresses the issue identified and reported by Martin Ankerl in bitcoin#22736 (comment) to fix the lock contention duration reporting.

  The next three commits make improvements to the timer code in `BCLog::LogMsg()` and add `util/types.h` with an `ALWAYS_FALSE` template, that springboard from bitcoin#22736 (comment) by Marco Falke.

ACKs for top commit:
  martinus:
    re-ACK f530202. I ran a fully synced node for about a day. My node was mostly idle though so not much was going on. I [wrote a little script](https://github.com/martinus/bitcoin-stuff/blob/main/scripts/parse-debuglog-contention-single.rb) to parse the `debug.log` and summarize the output to see if anything interesting was going on, here is the result:
  theStack:
    ACK f530202

Tree-SHA512: 37d093eac5590e1b5846ab5994d0950d71e131177d1afe4a5f7fcd614270f977e0ea117e7af788e9a74ddcccab35b42ec8fa4db3a3378940d4988df7d21cdaaa
fanquake added a commit to bitcoin-core/gui that referenced this pull request Apr 8, 2022
…TION preprocessor directive

4394733 Add DEBUG_LOCKCONTENTION documentation to the developer notes (Jon Atack)
39a34b6 Put lock logging behind DEBUG_LOCKCONTENTION preprocessor directive (Jon Atack)

Pull request description:

  This is a more minimal, no-frills version of #24734 for backport. The other fixes and improvements in that pull can be done after.

  *Copy of the PR 24734 description:*

  PRs #22736, #22904 and #23223 changed lock contention logging from a `DEBUG_LOCKCONTENTION` compile-time preprocessor directive to a runtime `lock` log category and improved the logging output. This changed the locking from using `lock()` to `try_lock()`:

  - `void Mutex::UniqueLock::lock()` acquires the mutex and blocks until it gains access to it

  - `bool Mutex::UniqueLock::try_lock()` doesn't block but instead immediately returns whether it acquired the mutex; it may be used by `lock()` internally as part of the deadlock-avoidance algorithm

  In theory the cost of `try_lock` might be essentially the [same](https://www.erisian.com.au/bitcoin-core-dev/log-2022-03-31.html#l-697) relative to `lock`. The test-and-set logic of these calls is purported to be ~ constant time, optimised and light/quick if used carefully (i.e. no mutex convoying), compared to system calls, memory/cache coherency and fences, wait queues, and (particularly) lock contentions. See the discussion around bitcoin/bitcoin#22736 (comment) and after with respect to performance/cost aspects.  However, there are reasonable concerns (see [here](bitcoin/bitcoin#22736 (comment)) and [here](https://www.erisian.com.au/bitcoin-core-dev/log-2022-03-31.html#l-620)) that `Base::try_lock()` may be potentially [costly](https://www.erisian.com.au/bitcoin-core-dev/log-2022-03-31.html#l-700) or [risky](bitcoin/bitcoin#22904 (comment)) compared to `Base::lock()` in this very frequently called code.

  One alternative to keep the run-time lock logging would be to gate the `try_lock` call behind the logging conditional, for example as proposed in bitcoin/bitcoin@ccd73de and ACKed [here](bitcoin/bitcoin#22736 (comment)). However, this would add the [cost](bitcoin/bitcoin#22736 (comment)) of `if (LogAcceptCategory(BCLog::LOCK))` to the hotspot, instead of replacing `lock` with `try_lock`, for the most frequent happy path (non-contention).

  It turns out we can keep the advantages of the runtime lock contention logging (the ability to turn it on/off at runtime) while out of prudence putting the `try_lock()` call and `lock` logging category behind a  `DEBUG_LOCKCONTENTION` compile-time preprocessor directive, and also still retain the lock logging enhancements of the mentioned PRs, as suggested in bitcoin/bitcoin#24734 (comment) by W. J. van der Laan, in bitcoin/bitcoin#22736 (comment), and in the linked IRC discussion.

  Proposed here and for backport to v23.

ACKs for top commit:
  laanwj:
    Code review ACK 4394733

Tree-SHA512: 89b1271cae1dca0eb251914b1a60fc5b68320aab4a3939c57eec3a33a3c8f01688f05d95dfc31f91d71a6ed80cfe2d67b77ff14742611cc206175e47b2e5d3b1
@bitcoin bitcoin locked as resolved and limited conversation to collaborators Sep 6, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants