Skip to content
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

Fix largest part of GUI lockups with large wallets #3155

Merged
merged 15 commits into from
Oct 19, 2019

Conversation

codablock
Copy link

This is an alternative to #3152 and #3154

Profiling has shown that large wallets spend nearly all the time in TransactionFilterProxy::filterAcceptsRow. The most expensive part was the datetime comparison as Qt internally does a conversion from local time to UTC before doing the actual comparison. Simply using seconds since epoch instead of QDateTime solves the issue.

The second most time was spent in the index.data(TransactionTableModel::LabelRole) which performed conversion from a string into CBitcoinAddress and then into CTxDestination. I'm avoiding this now by also holding these types in TransactionRecord.

A lot of time was also lost due to unnecessary updates of the TransactionRecord in regard to the IS lock status. This is fixed by only doing this when really necessary (NotifyTransactionChanged was called on this TX and the IS lock state is still false).

For more details, see individual commits.

There is still potential for optimization. I think that we can optimize the time spent in filterAcceptsRow to nearly zero by introducing some cache. But this is for another PR.

@codablock codablock added this to the 14.1 milestone Oct 15, 2019
Copy link

@UdjinM6 UdjinM6 left a comment

Choose a reason for hiding this comment

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

I like optimizations for address and date strings but I think changes made in updateStatus, statusUpdateNeeded etc. look better in #3152 tbh (for example, the overhead of IsChainLocked() is minimal imo, it basically does the same as your new similar code here, but it's much more readable in 3152).

Also, it looks like the idea in 04e3ce3 is very similar to bitcoin@6d7104c... which we missed earlier 🙈 probably because it's a part of a PR with fixes for feebump. I think we should backport that instead (and add Q_EMIT part on top).

And finally, updateConfirmations() is still the major source of freezes for me, applying #3154 fixes them.

So to sum it up: I'd prefer to merge #3152 + #3154 + 6d7104c backport (+Q_EMIT) and then this PR should only add optimizations for addresses and dates.

src/qt/transactionrecord.cpp Outdated Show resolved Hide resolved
@codablock
Copy link
Author

codablock commented Oct 15, 2019

I like optimizations for address and date strings but I think changes made in updateStatus, statusUpdateNeeded etc. look better in #3152 tbh (for example, the overhead of IsChainLocked() is minimal imo, it basically does the same as your new similar code here, but it's much more readable in 3152).

The reason I re-implemented #3152 was that the IsLockedByInstantSend and the IsChainLocked calls have shown up in profiling sessions with a quite measurable impact. IsLockedByInstantSend was clearly the most expensive of both, but IsChainLocked still had an impact due to one additional lock happening. I've changed this PR to not do the custom chainLocks check but instead call IsChainLocked, but only when lockedByChainLocks is not already true, which should avoid most of the calls.

Also, it looks like the idea in 04e3ce3 is very similar to bitcoin@6d7104c... which we missed earlier probably because it's a part of a PR with fixes for feebump. I think we should backport that instead (and add Q_EMIT part on top).

I've replaced my solution with a backport of 6d7104c and the Q_EMIT line. Funny how much simpler the Bitcoin solution actually was 🙈

And finally, updateConfirmations() is still the major source of freezes for me, applying #3154 fixes them.

Yes it is still the major source of freezes, but it got a lot better. It's down from multiple seconds to slightly less then a second on my machine.

So to sum it up: I'd prefer to merge #3152 + #3154 + 6d7104c backport (+Q_EMIT) and then this PR should only add optimizations for addresses and dates.

I would prefer to not merge #3154 as it is a hack. It's unlikely, but it can lead to stale data shown in the UI. I would prefer to fix the actual bottlenecks.

I've added another commit on top which puts the label into the TransactionRecord and updates it when the address book changes. This avoids the expensive lookups done in TransactionTableModel::data which was the remaining large bottleneck for me.

EDIT: I was referring to #3142 being a hack, but I actually meant #3154

src/qt/transactionrecord.h Show resolved Hide resolved
src/qt/transactionrecord.h Show resolved Hide resolved
src/qt/transactionrecord.h Outdated Show resolved Hide resolved
src/qt/transactiontablemodel.cpp Outdated Show resolved Hide resolved
src/qt/transactiontablemodel.cpp Outdated Show resolved Hide resolved
UdjinM6
UdjinM6 previously approved these changes Oct 16, 2019
Copy link

@UdjinM6 UdjinM6 left a comment

Choose a reason for hiding this comment

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

Slightly tested ACK

codablock and others added 15 commits October 19, 2019 10:38
…ilterAcceptsRow

The QDateTime::operator< calls inside TransactionFilterProxy::filterAcceptsRow
turned out to be the slowest part in the UI when many TXs are inside
the wallet. DateRoleInt allows us to request the plain seconds since epoch
which we then use to compare against dateFrom/dateTo, which are also both
stored as seconds since epoch now.
This one avoids converting from string to CBitcoinAddress and calling
.Get() on the result.
…cord

This avoids frequent and slow conversion
This avoids unnecessary conversions
We already do this through updateTransaction(), which is also called when
an IS lock is received for one of our own TXs.
…is possible

lockedByChainLocks can never get back to false, so no need to re-check it.
Same with lockedByInstantSend, except when a ChainLock overrides it.
Instead of looking it up in data()
@codablock
Copy link
Author

Fiexed #3155 (comment) and rebased on develop to bring in latest Gitlab fixes

Copy link

@UdjinM6 UdjinM6 left a comment

Choose a reason for hiding this comment

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

re-utACK

barrystyle pushed a commit to PACGlobalOfficial/PAC that referenced this pull request Jan 22, 2020
* [Qt] make sure transaction table entry gets updated after bump

* Remove unnecessary tracking of IS lock count

* Track lockedByChainLocks in TransactionRecord

* Only update record when the TX was not ChainLocked before

* Emit dataChanged for CT_UPDATED transactions

* Use plain seconds since epoch comparison in TransactionFilterProxy::filterAcceptsRow

The QDateTime::operator< calls inside TransactionFilterProxy::filterAcceptsRow
turned out to be the slowest part in the UI when many TXs are inside
the wallet. DateRoleInt allows us to request the plain seconds since epoch
which we then use to compare against dateFrom/dateTo, which are also both
stored as seconds since epoch now.

* Don't invoke updateConfirmations directly and let pollBalanceChanged handle it

* Implement AddressTableModel::labelForDestination

This one avoids converting from string to CBitcoinAddress and calling
.Get() on the result.

* Also store CBitcoinAddress object and CTxDestination in TransactionRecord

This avoids frequent and slow conversion

* Use labelForDestination when possible

This avoids unnecessary conversions

* Don't set fForceCheckBalanceChanged to true when IS lock is received

We already do this through updateTransaction(), which is also called when
an IS lock is received for one of our own TXs.

* Only update lockedByChainLocks and lockedByInstantSend when a change is possible

lockedByChainLocks can never get back to false, so no need to re-check it.
Same with lockedByInstantSend, except when a ChainLock overrides it.

* Hold and update label in TransactionRecord

Instead of looking it up in data()

* Review suggestions

* Use proper columns in dataChanged call in updateAddressBook
UdjinM6 added a commit to UdjinM6/dash that referenced this pull request Feb 7, 2021
UdjinM6 added a commit to UdjinM6/dash that referenced this pull request Feb 7, 2021
UdjinM6 added a commit to UdjinM6/dash that referenced this pull request Feb 7, 2021
PastaPastaPasta pushed a commit that referenced this pull request Feb 11, 2021
* qt: Fix labels in transaction list

The issue was introduced in #3682

* qt: Always use labels from TransactionStatus for transaction list

Missed this in #3155

* Update src/qt/transactiontablemodel.cpp

Co-authored-by: dustinface <[email protected]>

Co-authored-by: dustinface <[email protected]>
@UdjinM6 UdjinM6 mentioned this pull request May 22, 2021
gades pushed a commit to cosanta/cosanta-core that referenced this pull request Mar 12, 2022
* qt: Fix labels in transaction list

The issue was introduced in dashpay#3682

* qt: Always use labels from TransactionStatus for transaction list

Missed this in dashpay#3155

* Update src/qt/transactiontablemodel.cpp

Co-authored-by: dustinface <[email protected]>

Co-authored-by: dustinface <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants