mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-07-29 09:38:52 +02:00
clusterlin: avoid heap allocations in GetLinearization
Replace GetLinearization's four per-call heap-allocated vectors (the ready chunk/transaction heaps and both dependency counters) with stack arrays and explicit size counters. This especially benefits linearization of small clusters, where the allocations make up a significant fraction of the total runtime.
This commit is contained in:
committed by
Pieter Wuille
parent
2d4065d1fe
commit
e6ca996255
@@ -1471,16 +1471,22 @@ public:
|
||||
/** A heap with all chunks (by set index) that can currently be included, sorted by
|
||||
* chunk feerate (high to low), chunk size (small to large), and by least maximum element
|
||||
* according to the fallback order (which is the second pair element). */
|
||||
std::vector<std::pair<SetIdx, TxIdx>> ready_chunks;
|
||||
std::array<std::pair<SetIdx, TxIdx>, SetType::Size()> ready_chunks;
|
||||
/** The number of entries of ready_chunks in use. */
|
||||
unsigned num_ready_chunks{0};
|
||||
/** For every chunk, indexed by SetIdx, the number of unmet dependencies the chunk has on
|
||||
* other chunks (not including dependencies within the chunk itself). */
|
||||
std::vector<TxIdx> chunk_deps(m_set_info.size(), 0);
|
||||
std::array<TxIdx, SetType::Size()> chunk_deps;
|
||||
std::fill_n(chunk_deps.begin(), m_set_info.size(), TxIdx{0});
|
||||
/** For every transaction, indexed by TxIdx, the number of unmet dependencies the
|
||||
* transaction has. */
|
||||
std::vector<TxIdx> tx_deps(m_tx_data.size(), 0);
|
||||
std::array<TxIdx, SetType::Size()> tx_deps;
|
||||
std::fill_n(tx_deps.begin(), m_tx_data.size(), TxIdx{0});
|
||||
/** A heap with all transactions within the current chunk that can be included, sorted by
|
||||
* tx feerate (high to low), tx size (small to large), and fallback order. */
|
||||
std::vector<TxIdx> ready_tx;
|
||||
std::array<TxIdx, SetType::Size()> ready_tx;
|
||||
/** The number of entries of ready_tx in use. */
|
||||
unsigned num_ready_tx{0};
|
||||
// Populate chunk_deps and tx_deps.
|
||||
unsigned num_deps{0};
|
||||
for (TxIdx chl_idx : m_transaction_idxs) {
|
||||
@@ -1549,31 +1555,31 @@ public:
|
||||
// Construct a heap with all chunks that have no out-of-chunk dependencies.
|
||||
for (SetIdx chunk_idx : m_chunk_idxs) {
|
||||
if (chunk_deps[chunk_idx] == 0) {
|
||||
ready_chunks.emplace_back(chunk_idx, max_fallback_fn(chunk_idx));
|
||||
ready_chunks[num_ready_chunks++] = {chunk_idx, max_fallback_fn(chunk_idx)};
|
||||
}
|
||||
}
|
||||
std::make_heap(ready_chunks.begin(), ready_chunks.end(), chunk_cmp_fn);
|
||||
std::make_heap(ready_chunks.begin(), ready_chunks.begin() + num_ready_chunks, chunk_cmp_fn);
|
||||
// Pop chunks off the heap.
|
||||
while (!ready_chunks.empty()) {
|
||||
while (num_ready_chunks > 0) {
|
||||
auto [chunk_idx, _rnd] = ready_chunks.front();
|
||||
std::pop_heap(ready_chunks.begin(), ready_chunks.end(), chunk_cmp_fn);
|
||||
ready_chunks.pop_back();
|
||||
std::pop_heap(ready_chunks.begin(), ready_chunks.begin() + num_ready_chunks, chunk_cmp_fn);
|
||||
--num_ready_chunks;
|
||||
Assume(chunk_deps[chunk_idx] == 0);
|
||||
const auto& chunk_txn = m_set_info[chunk_idx].transactions;
|
||||
// Build heap of all includable transactions in chunk.
|
||||
Assume(ready_tx.empty());
|
||||
Assume(num_ready_tx == 0);
|
||||
for (TxIdx tx_idx : chunk_txn) {
|
||||
if (tx_deps[tx_idx] == 0) ready_tx.push_back(tx_idx);
|
||||
if (tx_deps[tx_idx] == 0) ready_tx[num_ready_tx++] = tx_idx;
|
||||
}
|
||||
Assume(!ready_tx.empty());
|
||||
std::make_heap(ready_tx.begin(), ready_tx.end(), tx_cmp_fn);
|
||||
Assume(num_ready_tx > 0);
|
||||
std::make_heap(ready_tx.begin(), ready_tx.begin() + num_ready_tx, tx_cmp_fn);
|
||||
// Pick transactions from the ready heap, append them to linearization, and decrement
|
||||
// dependency counts.
|
||||
while (!ready_tx.empty()) {
|
||||
while (num_ready_tx > 0) {
|
||||
// Pop an element from the tx_ready heap.
|
||||
auto tx_idx = ready_tx.front();
|
||||
std::pop_heap(ready_tx.begin(), ready_tx.end(), tx_cmp_fn);
|
||||
ready_tx.pop_back();
|
||||
std::pop_heap(ready_tx.begin(), ready_tx.begin() + num_ready_tx, tx_cmp_fn);
|
||||
--num_ready_tx;
|
||||
// Append to linearization.
|
||||
ret.push_back(tx_idx);
|
||||
// Decrement dependency counts.
|
||||
@@ -1584,16 +1590,16 @@ public:
|
||||
Assume(tx_deps[chl_idx] > 0);
|
||||
if (--tx_deps[chl_idx] == 0 && chunk_txn[chl_idx]) {
|
||||
// Child tx has no dependencies left, and is in this chunk. Add it to the tx heap.
|
||||
ready_tx.push_back(chl_idx);
|
||||
std::push_heap(ready_tx.begin(), ready_tx.end(), tx_cmp_fn);
|
||||
ready_tx[num_ready_tx++] = chl_idx;
|
||||
std::push_heap(ready_tx.begin(), ready_tx.begin() + num_ready_tx, tx_cmp_fn);
|
||||
}
|
||||
// Decrement chunk dependency count if this is out-of-chunk dependency.
|
||||
if (chl_data.chunk_idx != chunk_idx) {
|
||||
Assume(chunk_deps[chl_data.chunk_idx] > 0);
|
||||
if (--chunk_deps[chl_data.chunk_idx] == 0) {
|
||||
// Child chunk has no dependencies left. Add it to the chunk heap.
|
||||
ready_chunks.emplace_back(chl_data.chunk_idx, max_fallback_fn(chl_data.chunk_idx));
|
||||
std::push_heap(ready_chunks.begin(), ready_chunks.end(), chunk_cmp_fn);
|
||||
ready_chunks[num_ready_chunks++] = {chl_data.chunk_idx, max_fallback_fn(chl_data.chunk_idx)};
|
||||
std::push_heap(ready_chunks.begin(), ready_chunks.begin() + num_ready_chunks, chunk_cmp_fn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user