-
Notifications
You must be signed in to change notification settings - Fork 37.8k
[Qt] reduce cs_main locks during tip update, more fluently update UI #7112
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Status bar during IBD looks like: https://bitcoin.jonasschnelli.ch/qt/statusbar.mov |
Concept ACK, I've been wanting to do this for a long time |
8e163b1
to
a976224
Compare
a976224
to
f60a931
Compare
Updated. Much smaller diff/changeset now. |
This fixes #5664 for me. Even during catching-up and heavy verification, it keeps updating the block number consistently. |
} | ||
|
||
// no locking required at this point | ||
// the following calls will aquire the required lock | ||
Q_EMIT mempoolSizeChanged(getMempoolSize(), getMempoolDynamicUsage()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, spoke too soon. It does hang on long contention of cs_main, I think here.
The TRY_LOCK should be re-added here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm no that can't be it, none of these require cs_main. Weird.
Looks like it can still hang here:
getVerificationProgress takes a lock on cs_main |
Concept ACK. f60a931d9137854f3bbcbc0589ab31563662c3c3 Looks a lot smoother on my system. |
Added another commit that solves the |
@@ -672,7 +672,7 @@ void BitcoinGUI::setNumConnections(int count) | |||
labelConnectionsIcon->setToolTip(tr("%n active connection(s) to Bitcoin network", "", count)); | |||
} | |||
|
|||
void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate) | |||
void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, const CBlockIndex *tip) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't like passing the tip through the view code. Let's just pass the verification progress directly
(could even remove ClientModel::getVerificationProgress()
after that)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm... but i don't want to execute getVerificationProgress()
during the synchronous core signal. I guess it's better to call this function over the UI thread.
But let me have a closer look...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm okay you have a point.
But ideally these kind of things happen in the model (ClientModel) in this case, not in the view class. But that'd require 'intercepting' the signal there to add this information.
Don't like how core's handles leak all over the place now.
But yes maybe better to live with this for now...
@jonasschnelli @laanwj I benchmark GuessVerificationProgress (+random fetch from chainActive) here at around 80ns. I think it's perfectly acceptable to compute it before passing to the GUI. |
@sipa thanks; absolutely, in that case we should call it in the signal handler directly before sendingto the GUI. I expect |
cf50f04
to
1db6f9a
Compare
@sipa: Thanks for the info. Just added another commit that calculate the verification progress during the synchronous core signal, and passes a double through the UI signal. |
CBlockIndex *tip = (CBlockIndex *)tipIn; | ||
if (!tip) | ||
{ | ||
LOCK(cs_main); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This lock is only required when initially update the UI (first time, outside of the core signal scope).
1db6f9a
to
e6d07cc
Compare
Binares are built if someone likes to test this: https://bitcoin.jonasschnelli.ch/pulls/7112/ |
{ | ||
LOCK(cs_main); | ||
return Checkpoints::GuessVerificationProgress(Params().Checkpoints(), chainActive.Tip()); | ||
CBlockIndex *tip = (CBlockIndex *)tipIn; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't recast to non-const, and certainly not with a C-style cast.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Better like this (it's now const_cast<CBlockIndex *>(tipIn)
)?
Or would it make more sense to pass a non-const through the core signal?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, I think GuessVerificationProgress should take a const CBlockIndex* :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah. Would be nice.. but i guess this would be a too-broad change for this PR scope.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just change the argument to const there. No other changes needed (I tried) :)
e6d07cc
to
f87be71
Compare
} | ||
//TODO: remove tip notification benchmark |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe remove this again :)
- also adds a boolean for indication if the tip update was happening during initial sync - emit notification also during initial sync
…te always (each block)
f87be71
to
b28c61e
Compare
} | ||
} | ||
if (!vHashes.empty()) { | ||
uiInterface.NotifyBlockTip(fInitialDownload, pindexNewTip); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@sdaftuar: I'm not familiar with the block announcements with headers, could you check if this rebase makes sense?
…ass double over UI signal
b28c61e
to
4082e46
Compare
} | ||
} | ||
// Always notify the UI if a new block tip was connected | ||
uiInterface.NotifyBlockTip(fInitialDownload, pindexNewTip); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@sdaftuar: I'm not familiar with the block announcements with headers, could you check if this rebase makes sense?
I'm firing off this event even when vHashes
is empty now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rebased. Removed notification benchmark. |
ACK. Works great now. The spinner is actually spinning again while syncing instead of blundering and glitching along :) |
- This will keep getbestblockhash more in sync with blocknotify callbacks
fa0ced4
to
9af5f9c
Compare
utACK non-GUI code. |
9af5f9c Move uiInterface.NotifyBlockTip signal above the core/wallet signal - This will keep getbestblockhash more in sync with blocknotify callbacks (Jonas Schnelli) 4082e46 [Qt] call GuessVerificationProgress synchronous during core signal, pass double over UI signal (Jonas Schnelli) 947d20b [Qt] reduce cs_main in getVerificationProgress() (Jonas Schnelli) e6d50fc [Qt] update block tip (height and date) without locking cs_main, update always (each block) (Jonas Schnelli) 012fc91 NotifyBlockTip signal: switch from hash (uint256) to CBlockIndex* - also adds a boolean for indication if the tip update was happening during initial sync - emit notification also during initial sync (Jonas Schnelli)
Small httpserver.cpp backports Also includes a change to the `uiInterface.NotifyBlockTip` signal API. These remove merge conflicts from subsequent backports for `sync.h`. Cherry-picked from the following upstream PRs: - bitcoin/bitcoin#6859 - bitcoin/bitcoin#7112 - Only the non-QT changes. - bitcoin/bitcoin#7966 - bitcoin/bitcoin#8421 - We already backported the second commit in #2555
This replaces using inv messages to announce new blocks, when a peer requests (via the new "sendheaders" message) that blocks be announced with headers instead of inv's. Since headers-first was introduced, peers send getheaders messages in response to an inv, which requires generating a block locator that is large compared to the size of the header being requested, and requires an extra round-trip before a reorg can be relayed. Save time by tracking headers that a peer is likely to know about, and send a headers chain that would connect to a peer's known headers, unless the chain would be too big, in which case we revert to sending an inv instead. Based off of @sipa's commit to announce all blocks in a reorg via inv, which has been squashed into this commit. Rebased-by: Pieter Wuille Zcash: Includes changes from the following subsequent upstream commits from bitcoin/bitcoin#7112 (which we already backported): - 012fc91 - 4082e46 - 9af5f9c
At the moment, the UI gets often not updated during initial sync or a catch-up of serval blocks. The UI's try_lock often can't acquire the lock which result in a bad user experience ("Baby, it's not updating!").
This PR changes the blocktip-update signal parameter form a bare hash (
uint256
) to aCBlockIndex*
, which allows to safely get it's height and timestamp without locking anything. In addition, the blocktip-update signal now gets fired also during initial sync, but with an extra boolean flag that indicates the initial sync state.The PR temporarily has a benchmark for the tip update signal. On my standard system it uses 0.03ms for the signal (=reasonable). Keep in mind that this signal is synchronous, but it will emit another asynchronous QT signal to the UI thread that will care about the UI update!
The timer based update (every 250ms) is still active for bandwidth and mempool UI observation, although there no cs_main lock is required.