txgraph: track amount of work done in linearization (preparation)

This commit is contained in:
Pieter Wuille
2025-04-13 11:09:04 -04:00
parent 6ba316eaa0
commit cfe9958852
4 changed files with 16 additions and 13 deletions

View File

@@ -229,8 +229,8 @@ void BenchLinearizeOptimally(benchmark::Bench& bench, const std::array<uint8_t,
reader >> Using<DepGraphFormatter>(depgraph);
uint64_t rng_seed = 0;
bench.run([&] {
auto res = Linearize(depgraph, /*max_iterations=*/10000000, rng_seed++);
assert(res.second);
auto [_lin, optimal, _cost] = Linearize(depgraph, /*max_iterations=*/10000000, rng_seed++);
assert(optimal);
});
};

View File

@@ -1030,19 +1030,20 @@ public:
* linearize.
* @param[in] old_linearization An existing linearization for the cluster (which must be
* topologically valid), or empty.
* @return A pair of:
* @return A tuple of:
* - The resulting linearization. It is guaranteed to be at least as
* good (in the feerate diagram sense) as old_linearization.
* - A boolean indicating whether the result is guaranteed to be
* optimal.
* - How many optimization steps were actually performed.
*
* Complexity: possibly O(N * min(max_iterations + N, sqrt(2^N))) where N=depgraph.TxCount().
*/
template<typename SetType>
std::pair<std::vector<DepGraphIndex>, bool> Linearize(const DepGraph<SetType>& depgraph, uint64_t max_iterations, uint64_t rng_seed, std::span<const DepGraphIndex> old_linearization = {}) noexcept
std::tuple<std::vector<DepGraphIndex>, bool, uint64_t> Linearize(const DepGraph<SetType>& depgraph, uint64_t max_iterations, uint64_t rng_seed, std::span<const DepGraphIndex> old_linearization = {}) noexcept
{
Assume(old_linearization.empty() || old_linearization.size() == depgraph.TxCount());
if (depgraph.TxCount() == 0) return {{}, true};
if (depgraph.TxCount() == 0) return {{}, true, 0};
uint64_t iterations_left = max_iterations;
std::vector<DepGraphIndex> linearization;
@@ -1113,7 +1114,7 @@ std::pair<std::vector<DepGraphIndex>, bool> Linearize(const DepGraph<SetType>& d
}
}
return {std::move(linearization), optimal};
return {std::move(linearization), optimal, max_iterations - iterations_left};
}
/** Improve a given linearization.

View File

@@ -1154,7 +1154,8 @@ FUZZ_TARGET(clusterlin_linearize)
// Invoke Linearize().
iter_count &= 0x7ffff;
auto [linearization, optimal] = Linearize(depgraph, iter_count, rng_seed, old_linearization);
auto [linearization, optimal, cost] = Linearize(depgraph, iter_count, rng_seed, old_linearization);
assert(cost <= iter_count);
SanityCheck(depgraph, linearization);
auto chunking = ChunkLinearization(depgraph, linearization);
@@ -1322,7 +1323,7 @@ FUZZ_TARGET(clusterlin_postlinearize_tree)
// Try to find an even better linearization directly. This must not change the diagram for the
// same reason.
auto [opt_linearization, _optimal] = Linearize(depgraph_tree, 100000, rng_seed, post_linearization);
auto [opt_linearization, _optimal, _cost] = Linearize(depgraph_tree, 100000, rng_seed, post_linearization);
auto opt_chunking = ChunkLinearization(depgraph_tree, opt_linearization);
auto cmp_opt = CompareChunks(opt_chunking, post_chunking);
assert(cmp_opt == 0);

View File

@@ -189,8 +189,8 @@ public:
void Merge(TxGraphImpl& graph, Cluster& cluster) noexcept;
/** Given a span of (parent, child) pairs that all belong to this Cluster, apply them. */
void ApplyDependencies(TxGraphImpl& graph, std::span<std::pair<GraphIndex, GraphIndex>> to_apply) noexcept;
/** Improve the linearization of this Cluster. */
void Relinearize(TxGraphImpl& graph, uint64_t max_iters) noexcept;
/** Improve the linearization of this Cluster. Returns how much work was performed. */
uint64_t Relinearize(TxGraphImpl& graph, uint64_t max_iters) noexcept;
/** For every chunk in the cluster, append its FeeFrac to ret. */
void AppendChunkFeerates(std::vector<FeeFrac>& ret) const noexcept;
/** Add a TrimTxData entry (filling m_chunk_feerate, m_index, m_tx_size) for every
@@ -1651,15 +1651,15 @@ void TxGraphImpl::ApplyDependencies(int level) noexcept
clusterset.m_group_data = GroupData{};
}
void Cluster::Relinearize(TxGraphImpl& graph, uint64_t max_iters) noexcept
uint64_t Cluster::Relinearize(TxGraphImpl& graph, uint64_t max_iters) noexcept
{
// We can only relinearize Clusters that do not need splitting.
Assume(!NeedsSplitting());
// No work is required for Clusters which are already optimally linearized.
if (IsOptimal()) return;
if (IsOptimal()) return 0;
// Invoke the actual linearization algorithm (passing in the existing one).
uint64_t rng_seed = graph.m_rng.rand64();
auto [linearization, optimal] = Linearize(m_depgraph, max_iters, rng_seed, m_linearization);
auto [linearization, optimal, cost] = Linearize(m_depgraph, max_iters, rng_seed, m_linearization);
// Postlinearize if the result isn't optimal already. This guarantees (among other things)
// that the chunks of the resulting linearization are all connected.
if (!optimal) PostLinearize(m_depgraph, linearization);
@@ -1670,6 +1670,7 @@ void Cluster::Relinearize(TxGraphImpl& graph, uint64_t max_iters) noexcept
graph.SetClusterQuality(m_level, m_quality, m_setindex, new_quality);
// Update the Entry objects.
Updated(graph);
return cost;
}
void TxGraphImpl::MakeAcceptable(Cluster& cluster) noexcept