clusterlin: split tx/chunk dep counting (preparation)

This splits the chunk_deps variable in LoadLinearization in two, one for
tracking tx dependencies and one for chunk dependencies. This is a
preparation for a later commit, where chunks won't be identified anymore
by a representative transaction in them, but by a separate index. With
that, it seems weird to keep them both in the same structure if they
will be indexed in an unrelated way.

Note that the changes in src/test/util/cluster_linearize.h to the table
of worst observed iteration counts are due to switching to a different
data set, and are unrelated to the changes in this commit.
This commit is contained in:
Pieter Wuille
2025-12-22 14:47:16 -05:00
parent 900e459778
commit f66fa69ce0
2 changed files with 24 additions and 26 deletions

View File

@@ -1274,28 +1274,26 @@ public:
* 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<TxIdx, TxIdx>> ready_chunks;
/** Information about chunks:
* - The first value is only used for chunk representatives, and counts the number of
* unmet dependencies this chunk has on other chunks (not including dependencies within
* the chunk itself).
* - The second value is the number of unmet dependencies overall.
*/
std::vector<std::pair<TxIdx, TxIdx>> chunk_deps(m_tx_data.size(), {0, 0});
/** For every chunk, indexed by representative, the number of unmet dependencies the chunk has on
* other chunks (not including dependencies within the chunk itself). */
std::vector<TxIdx> chunk_deps(m_tx_data.size(), 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);
/** The set of all chunk representatives. */
SetType chunk_reps;
/** 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;
// Populate chunk_deps[c] with the number of {out-of-chunk dependencies, dependencies} the
// child has.
// Populate chunk_deps and tx_deps.
for (TxIdx chl_idx : m_transaction_idxs) {
const auto& chl_data = m_tx_data[chl_idx];
chunk_deps[chl_idx].second = chl_data.parents.Count();
tx_deps[chl_idx] = chl_data.parents.Count();
auto chl_chunk_rep = chl_data.chunk_rep;
chunk_reps.Set(chl_chunk_rep);
for (auto par_idx : chl_data.parents) {
auto par_chunk_rep = m_tx_data[par_idx].chunk_rep;
chunk_deps[chl_chunk_rep].first += (par_chunk_rep != chl_chunk_rep);
chunk_deps[chl_chunk_rep] += (par_chunk_rep != chl_chunk_rep);
}
}
/** Function to compute the highest element of a chunk, by fallback_order. */
@@ -1355,7 +1353,7 @@ public:
};
// Construct a heap with all chunks that have no out-of-chunk dependencies.
for (TxIdx chunk_rep : chunk_reps) {
if (chunk_deps[chunk_rep].first == 0) {
if (chunk_deps[chunk_rep] == 0) {
ready_chunks.emplace_back(chunk_rep, max_fallback_fn(chunk_rep));
}
}
@@ -1366,12 +1364,12 @@ public:
std::pop_heap(ready_chunks.begin(), ready_chunks.end(), chunk_cmp_fn);
ready_chunks.pop_back();
Assume(m_tx_data[chunk_rep].chunk_rep == chunk_rep);
Assume(chunk_deps[chunk_rep].first == 0);
Assume(chunk_deps[chunk_rep] == 0);
const auto& chunk_txn = m_tx_data[chunk_rep].chunk_setinfo.transactions;
// Build heap of all includable transactions in chunk.
Assume(ready_tx.empty());
for (TxIdx tx_idx : chunk_txn) {
if (chunk_deps[tx_idx].second == 0) ready_tx.push_back(tx_idx);
if (tx_deps[tx_idx] == 0) ready_tx.push_back(tx_idx);
}
Assume(!ready_tx.empty());
std::make_heap(ready_tx.begin(), ready_tx.end(), tx_cmp_fn);
@@ -1389,16 +1387,16 @@ public:
for (TxIdx chl_idx : tx_data.children) {
auto& chl_data = m_tx_data[chl_idx];
// Decrement tx dependency count.
Assume(chunk_deps[chl_idx].second > 0);
if (--chunk_deps[chl_idx].second == 0 && chunk_txn[chl_idx]) {
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);
}
// Decrement chunk dependency count if this is out-of-chunk dependency.
if (chl_data.chunk_rep != chunk_rep) {
Assume(chunk_deps[chl_data.chunk_rep].first > 0);
if (--chunk_deps[chl_data.chunk_rep].first == 0) {
Assume(chunk_deps[chl_data.chunk_rep] > 0);
if (--chunk_deps[chl_data.chunk_rep] == 0) {
// Child chunk has no dependencies left. Add it to the chunk heap.
ready_chunks.emplace_back(chl_data.chunk_rep, max_fallback_fn(chl_data.chunk_rep));
std::push_heap(ready_chunks.begin(), ready_chunks.end(), chunk_cmp_fn);

View File

@@ -402,14 +402,14 @@ inline uint64_t MaxOptimalLinearizationIters(DepGraphIndex cluster_count)
// *some* reasonable cost bound, optimal linearizations are always found.
static constexpr uint64_t ITERS[65] = {
0,
0, 4, 10, 34, 76, 118, 184, 225,
320, 376, 464, 573, 830, 868, 1019, 1468,
1375, 1785, 1880, 1854, 2551, 2559, 4336, 4784,
5547, 5807, 6157, 6075, 6961, 7403, 7756, 8001,
8041, 7579, 8483, 10077, 9015, 9388, 9626, 12371,
12847, 12102, 15173, 15800, 20319, 22190, 23183, 24361,
24909, 19225, 27419, 23789, 25909, 21993, 25596, 24130,
26349, 31823, 31855, 31250, 32688, 34825, 41710, 45478
0, 4, 10, 34, 76, 156, 229, 380,
432, 607, 738, 896, 1037, 1366, 1464, 1711,
2060, 2542, 3068, 3116, 4029, 3949, 5324, 5402,
6481, 7161, 7441, 8329, 9307, 9353, 11104, 11269,
11791, 11981, 12413, 14513, 15331, 12397, 13581, 19665,
18737, 16581, 23217, 25542, 27123, 28913, 32969, 33951,
34414, 26227, 38792, 38045, 40814, 29622, 38732, 32122,
35915, 49823, 39722, 43765, 44002, 49716, 59417, 67035
};
assert(cluster_count < std::size(ITERS));
// Multiply the table number by two, to account for the fact that they are not absolutes.