-
Notifications
You must be signed in to change notification settings - Fork 486
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
performance: turn cache misses during assembly into cache hits during eval #4617
Changes from all commits
728238f
b831223
28c7d06
974968e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -328,6 +328,17 @@ func (au *accountUpdates) close() { | |
au.baseKVs.prune(0) | ||
} | ||
|
||
// flushCaches flushes any pending data in caches so that it is fully available during future lookups. | ||
func (au *accountUpdates) flushCaches() { | ||
au.accountsMu.Lock() | ||
|
||
au.baseAccounts.flushPendingWrites() | ||
au.baseResources.flushPendingWrites() | ||
au.baseKVs.flushPendingWrites() | ||
|
||
au.accountsMu.Unlock() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Prefer defer? |
||
} | ||
|
||
func (au *accountUpdates) LookupResource(rnd basics.Round, addr basics.Address, aidx basics.CreatableIndex, ctype basics.CreatableType) (ledgercore.AccountResource, basics.Round, error) { | ||
return au.lookupResource(rnd, addr, aidx, ctype, true /* take lock */) | ||
} | ||
|
@@ -816,6 +827,8 @@ type accountUpdatesLedgerEvaluator struct { | |
prevHeader bookkeeping.BlockHeader | ||
} | ||
|
||
func (aul *accountUpdatesLedgerEvaluator) FlushCaches() {} | ||
|
||
// GenesisHash returns the genesis hash | ||
func (aul *accountUpdatesLedgerEvaluator) GenesisHash() crypto.Digest { | ||
return aul.au.ledger.GenesisHash() | ||
|
@@ -1327,6 +1340,12 @@ func (au *accountUpdates) lookupResource(rnd basics.Round, addr basics.Address, | |
return macct.AccountResource(), rnd, nil | ||
} | ||
|
||
// check baseAccoiunts again to see if it does not exist | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "baseResources" |
||
if au.baseResources.readNotFound(addr, aidx) { | ||
// it seems the account doesnt exist | ||
return ledgercore.AccountResource{}, rnd, nil | ||
} | ||
|
||
if synchronized { | ||
au.accountsMu.RUnlock() | ||
needUnlock = false | ||
|
@@ -1346,6 +1365,7 @@ func (au *accountUpdates) lookupResource(rnd basics.Round, addr basics.Address, | |
au.baseResources.writePending(persistedData, addr) | ||
return persistedData.AccountResource(), rnd, nil | ||
} | ||
au.baseResources.writeNotFoundPending(addr, aidx) | ||
// otherwise return empty | ||
return ledgercore.AccountResource{}, rnd, nil | ||
} | ||
|
@@ -1428,6 +1448,12 @@ func (au *accountUpdates) lookupWithoutRewards(rnd basics.Round, addr basics.Add | |
return macct.accountData.GetLedgerCoreAccountData(), rnd, rewardsVersion, rewardsLevel, nil | ||
} | ||
|
||
// check baseAccoiunts again to see if it does not exist | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "baseAccounts" (sp) |
||
if au.baseAccounts.readNotFound(addr) { | ||
// it seems the account doesnt exist | ||
return ledgercore.AccountData{}, rnd, rewardsVersion, rewardsLevel, nil | ||
} | ||
|
||
if synchronized { | ||
au.accountsMu.RUnlock() | ||
needUnlock = false | ||
|
@@ -1447,6 +1473,7 @@ func (au *accountUpdates) lookupWithoutRewards(rnd basics.Round, addr basics.Add | |
au.baseAccounts.writePending(persistedData) | ||
return persistedData.accountData.GetLedgerCoreAccountData(), rnd, rewardsVersion, rewardsLevel, nil | ||
} | ||
au.baseAccounts.writeNotFoundPending(addr) | ||
// otherwise return empty | ||
return ledgercore.AccountData{}, rnd, rewardsVersion, rewardsLevel, nil | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -37,6 +37,9 @@ type lruAccounts struct { | |
log logging.Logger | ||
// pendingWritesWarnThreshold is the threshold beyond we would write a warning for exceeding the number of pendingAccounts entries | ||
pendingWritesWarnThreshold int | ||
|
||
pendingNotFound chan basics.Address | ||
notFound map[basics.Address]struct{} | ||
} | ||
|
||
// init initializes the lruAccounts for use. | ||
|
@@ -45,6 +48,8 @@ func (m *lruAccounts) init(log logging.Logger, pendingWrites int, pendingWritesW | |
m.accountsList = newPersistedAccountList().allocateFreeNodes(pendingWrites) | ||
m.accounts = make(map[basics.Address]*persistedAccountDataListNode, pendingWrites) | ||
m.pendingAccounts = make(chan persistedAccountData, pendingWrites) | ||
m.notFound = make(map[basics.Address]struct{}, pendingWrites) | ||
m.pendingNotFound = make(chan basics.Address, pendingWrites) | ||
m.log = log | ||
m.pendingWritesWarnThreshold = pendingWritesWarnThreshold | ||
} | ||
|
@@ -58,19 +63,39 @@ func (m *lruAccounts) read(addr basics.Address) (data persistedAccountData, has | |
return persistedAccountData{}, false | ||
} | ||
|
||
// readNotFound returns whether we have attempted to read this address but it did not exist in the db. | ||
// thread locking semantics : read lock | ||
func (m *lruAccounts) readNotFound(addr basics.Address) bool { | ||
_, ok := m.notFound[addr] | ||
return ok | ||
} | ||
|
||
// flushPendingWrites flushes the pending writes to the main lruAccounts cache. | ||
// thread locking semantics : write lock | ||
func (m *lruAccounts) flushPendingWrites() { | ||
pendingEntriesCount := len(m.pendingAccounts) | ||
if pendingEntriesCount >= m.pendingWritesWarnThreshold { | ||
m.log.Warnf("lruAccounts: number of entries in pendingAccounts(%d) exceed the warning threshold of %d", pendingEntriesCount, m.pendingWritesWarnThreshold) | ||
} | ||
|
||
outer: | ||
for ; pendingEntriesCount > 0; pendingEntriesCount-- { | ||
select { | ||
case pendingAccountData := <-m.pendingAccounts: | ||
m.write(pendingAccountData) | ||
default: | ||
return | ||
break outer | ||
} | ||
} | ||
|
||
pendingEntriesCount = len(m.pendingNotFound) | ||
outer2: | ||
for ; pendingEntriesCount > 0; pendingEntriesCount-- { | ||
select { | ||
case addr := <-m.pendingNotFound: | ||
m.notFound[addr] = struct{}{} | ||
default: | ||
break outer2 | ||
} | ||
} | ||
} | ||
|
@@ -85,6 +110,16 @@ func (m *lruAccounts) writePending(acct persistedAccountData) { | |
} | ||
} | ||
|
||
// writeNotFoundPending tags an address as not existing in the db. | ||
// the function doesn't block, and in case of a buffer overflow the entry would not be added. | ||
// thread locking semantics : no lock is required. | ||
func (m *lruAccounts) writeNotFoundPending(addr basics.Address) { | ||
select { | ||
case m.pendingNotFound <- addr: | ||
default: | ||
} | ||
} | ||
|
||
// write a single persistedAccountData to the lruAccounts cache. | ||
// when writing the entry, the round number would be used to determine if it's a newer | ||
// version of what's already on the cache or not. In all cases, the entry is going | ||
|
@@ -117,5 +152,8 @@ func (m *lruAccounts) prune(newSize int) (removed int) { | |
m.accountsList.remove(back) | ||
removed++ | ||
} | ||
|
||
// clear the notFound list | ||
m.notFound = make(map[basics.Address]struct{}, len(m.notFound)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Supposedly, deleting in a loop over all keys is recognized by the compiler and optimized to be cheaper than reallocating. @cce posted something about it. https://go-review.googlesource.com/c/go/+/110055 |
||
return | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -48,6 +48,9 @@ type lruResources struct { | |
|
||
// pendingWritesWarnThreshold is the threshold beyond we would write a warning for exceeding the number of pendingResources entries | ||
pendingWritesWarnThreshold int | ||
|
||
pendingNotFound chan accountCreatable | ||
notFound map[accountCreatable]struct{} | ||
} | ||
|
||
// init initializes the lruResources for use. | ||
|
@@ -56,6 +59,8 @@ func (m *lruResources) init(log logging.Logger, pendingWrites int, pendingWrites | |
m.resourcesList = newPersistedResourcesList().allocateFreeNodes(pendingWrites) | ||
m.resources = make(map[accountCreatable]*persistedResourcesDataListNode, pendingWrites) | ||
m.pendingResources = make(chan cachedResourceData, pendingWrites) | ||
m.notFound = make(map[accountCreatable]struct{}, pendingWrites) | ||
m.pendingNotFound = make(chan accountCreatable, pendingWrites) | ||
m.log = log | ||
m.pendingWritesWarnThreshold = pendingWritesWarnThreshold | ||
} | ||
|
@@ -69,6 +74,13 @@ func (m *lruResources) read(addr basics.Address, aidx basics.CreatableIndex) (da | |
return persistedResourcesData{}, false | ||
} | ||
|
||
// readNotFound returns whether we have attempted to read this address but it did not exist in the db. | ||
// thread locking semantics : read lock | ||
func (m *lruResources) readNotFound(addr basics.Address, idx basics.CreatableIndex) bool { | ||
_, ok := m.notFound[accountCreatable{address: addr, index: idx}] | ||
return ok | ||
} | ||
|
||
// read the persistedResourcesData object that the lruResources has for the given address. | ||
// thread locking semantics : read lock | ||
func (m *lruResources) readAll(addr basics.Address) (ret []persistedResourcesData) { | ||
|
@@ -87,12 +99,25 @@ func (m *lruResources) flushPendingWrites() { | |
if pendingEntriesCount >= m.pendingWritesWarnThreshold { | ||
m.log.Warnf("lruResources: number of entries in pendingResources(%d) exceed the warning threshold of %d", pendingEntriesCount, m.pendingWritesWarnThreshold) | ||
} | ||
|
||
outer: | ||
for ; pendingEntriesCount > 0; pendingEntriesCount-- { | ||
select { | ||
case pendingResourceData := <-m.pendingResources: | ||
m.write(pendingResourceData.persistedResourcesData, pendingResourceData.address) | ||
default: | ||
return | ||
break outer | ||
} | ||
} | ||
|
||
pendingEntriesCount = len(m.pendingNotFound) | ||
outer2: | ||
for ; pendingEntriesCount > 0; pendingEntriesCount-- { | ||
select { | ||
case key := <-m.pendingNotFound: | ||
m.notFound[key] = struct{}{} | ||
default: | ||
break outer2 | ||
} | ||
} | ||
} | ||
|
@@ -107,6 +132,16 @@ func (m *lruResources) writePending(acct persistedResourcesData, addr basics.Add | |
} | ||
} | ||
|
||
// writeNotFoundPending tags an address as not existing in the db. | ||
// the function doesn't block, and in case of a buffer overflow the entry would not be added. | ||
// thread locking semantics : no lock is required. | ||
func (m *lruResources) writeNotFoundPending(addr basics.Address, idx basics.CreatableIndex) { | ||
select { | ||
case m.pendingNotFound <- accountCreatable{address: addr, index: idx}: | ||
default: | ||
} | ||
} | ||
|
||
// write a single persistedAccountData to the lruResources cache. | ||
// when writing the entry, the round number would be used to determine if it's a newer | ||
// version of what's already on the cache or not. In all cases, the entry is going | ||
|
@@ -139,5 +174,8 @@ func (m *lruResources) prune(newSize int) (removed int) { | |
m.resourcesList.remove(back) | ||
removed++ | ||
} | ||
|
||
// clear the notFound list | ||
m.notFound = make(map[accountCreatable]struct{}, len(m.notFound)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same |
||
return | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -36,6 +36,7 @@ type PpConfig struct { | |
RandomizeFee bool | ||
RandomizeAmt bool | ||
RandomizeDst bool | ||
MaxRandomDst uint64 | ||
MaxFee uint64 | ||
MinFee uint64 | ||
MaxAmt uint64 | ||
|
@@ -98,6 +99,7 @@ var DefaultConfig = PpConfig{ | |
RandomizeFee: false, | ||
RandomizeAmt: false, | ||
RandomizeDst: false, | ||
MaxRandomDst: 200000, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
MaxFee: 10000, | ||
MinFee: 1000, | ||
MaxAmt: 1000, | ||
|
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 on master to get the boxes feature and added a flush on the baseKVs LRU.