From cfe9958852be0e0763c924bdbadc37e784f5aee5 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Sun, 13 Apr 2025 11:09:04 -0400 Subject: [PATCH] txgraph: track amount of work done in linearization (preparation) --- src/bench/cluster_linearize.cpp | 4 ++-- src/cluster_linearize.h | 9 +++++---- src/test/fuzz/cluster_linearize.cpp | 5 +++-- src/txgraph.cpp | 11 ++++++----- 4 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/bench/cluster_linearize.cpp b/src/bench/cluster_linearize.cpp index cb06f3fc28a..1cd36b53939 100644 --- a/src/bench/cluster_linearize.cpp +++ b/src/bench/cluster_linearize.cpp @@ -229,8 +229,8 @@ void BenchLinearizeOptimally(benchmark::Bench& bench, const std::array> Using(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); }); }; diff --git a/src/cluster_linearize.h b/src/cluster_linearize.h index 17b7e6b27a0..bec44d973e3 100644 --- a/src/cluster_linearize.h +++ b/src/cluster_linearize.h @@ -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 -std::pair, bool> Linearize(const DepGraph& depgraph, uint64_t max_iterations, uint64_t rng_seed, std::span old_linearization = {}) noexcept +std::tuple, bool, uint64_t> Linearize(const DepGraph& depgraph, uint64_t max_iterations, uint64_t rng_seed, std::span 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 linearization; @@ -1113,7 +1114,7 @@ std::pair, bool> Linearize(const DepGraph& d } } - return {std::move(linearization), optimal}; + return {std::move(linearization), optimal, max_iterations - iterations_left}; } /** Improve a given linearization. diff --git a/src/test/fuzz/cluster_linearize.cpp b/src/test/fuzz/cluster_linearize.cpp index ef20eeaea0d..4cd93e20793 100644 --- a/src/test/fuzz/cluster_linearize.cpp +++ b/src/test/fuzz/cluster_linearize.cpp @@ -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); diff --git a/src/txgraph.cpp b/src/txgraph.cpp index 247c2642604..8decb5d0099 100644 --- a/src/txgraph.cpp +++ b/src/txgraph.cpp @@ -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> 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& 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