@@ -153,6 +153,9 @@ class Cluster
153153 return m_quality == QualityLevel::NEEDS_SPLIT ||
154154 m_quality == QualityLevel::NEEDS_SPLIT_ACCEPTABLE;
155155 }
156+ /* * Total memory usage currently for this Cluster, including all its dynamic memory, plus Cluster
157+ * structure itself, and ClusterSet::m_clusters entry. */
158+ size_t TotalMemoryUsage () const noexcept ;
156159 /* * Get the number of transactions in this Cluster. */
157160 LinearizationIndex GetTxCount () const noexcept { return m_linearization.size (); }
158161 /* * Get the total size of the transactions in this Cluster. */
@@ -308,6 +311,9 @@ class TxGraphImpl final : public TxGraph
308311 GraphIndex m_txcount_oversized{0 };
309312 /* * Whether this graph is oversized (if known). */
310313 std::optional<bool > m_oversized{false };
314+ /* * The combined TotalMemoryUsage of all clusters in this level (only Clusters that
315+ * are materialized; in staging, implicit Clusters from main are not counted), */
316+ size_t m_cluster_usage{0 };
311317
312318 ClusterSet () noexcept = default ;
313319 };
@@ -703,6 +709,18 @@ void TxGraphImpl::CreateChunkData(GraphIndex idx, LinearizationIndex chunk_count
703709 }
704710}
705711
712+ size_t Cluster::TotalMemoryUsage () const noexcept
713+ {
714+ return // Dynamic memory allocated in this Cluster.
715+ memusage::DynamicUsage (m_mapping) + memusage::DynamicUsage (m_linearization) +
716+ // Dynamic memory usage inside m_depgraph.
717+ m_depgraph.DynamicMemoryUsage () +
718+ // Memory usage of the allocated Cluster itself.
719+ memusage::MallocUsage (sizeof (Cluster)) +
720+ // Memory usage of the ClusterSet::m_clusters entry.
721+ sizeof (std::unique_ptr<Cluster>);
722+ }
723+
706724uint64_t Cluster::GetTotalTxSize () const noexcept
707725{
708726 uint64_t ret{0 };
@@ -851,9 +869,11 @@ Cluster* Cluster::CopyToStaging(TxGraphImpl& graph) const noexcept
851869 ptr->m_mapping = m_mapping;
852870 ptr->m_linearization = m_linearization;
853871 // Insert the new Cluster into the graph.
854- graph.InsertCluster (1 , std::move (ret), m_quality);
872+ graph.InsertCluster (/* level= */ 1 , std::move (ret), m_quality);
855873 // Update its Locators.
856874 ptr->Updated (graph, /* level=*/ 1 );
875+ // Update memory usage.
876+ graph.GetClusterSet (/* level=*/ 1 ).m_cluster_usage += ptr->TotalMemoryUsage ();
857877 return ptr;
858878}
859879
@@ -862,6 +882,7 @@ void Cluster::ApplyRemovals(TxGraphImpl& graph, int level, std::span<GraphIndex>
862882 // Iterate over the prefix of to_remove that applies to this cluster.
863883 Assume (!to_remove.empty ());
864884 SetType todo;
885+ graph.GetClusterSet (level).m_cluster_usage -= TotalMemoryUsage ();
865886 do {
866887 GraphIndex idx = to_remove.front ();
867888 Assume (idx < graph.m_entries .size ());
@@ -913,12 +934,14 @@ void Cluster::ApplyRemovals(TxGraphImpl& graph, int level, std::span<GraphIndex>
913934 quality = QualityLevel::NEEDS_SPLIT;
914935 }
915936 Compact ();
937+ graph.GetClusterSet (level).m_cluster_usage += TotalMemoryUsage ();
916938 graph.SetClusterQuality (level, m_quality, m_setindex, quality);
917939 Updated (graph, level);
918940}
919941
920942void Cluster::Clear (TxGraphImpl& graph, int level) noexcept
921943{
944+ graph.GetClusterSet (level).m_cluster_usage -= TotalMemoryUsage ();
922945 for (auto i : m_linearization) {
923946 graph.ClearLocator (level, m_mapping[i], m_quality == QualityLevel::OVERSIZED_SINGLETON);
924947 }
@@ -935,6 +958,10 @@ void Cluster::MoveToMain(TxGraphImpl& graph) noexcept
935958 entry.m_locator [1 ].SetMissing ();
936959 }
937960 auto quality = m_quality;
961+ // Subtract memory usage from staging and add it to main.
962+ graph.GetClusterSet (/* level=*/ 1 ).m_cluster_usage -= TotalMemoryUsage ();
963+ graph.GetClusterSet (/* level=*/ 0 ).m_cluster_usage += TotalMemoryUsage ();
964+ // Remove cluster itself from staging and add it to main.
938965 auto cluster = graph.ExtractCluster (1 , quality, m_setindex);
939966 graph.InsertCluster (/* level=*/ 0 , std::move (cluster), quality);
940967 Updated (graph, /* level=*/ 0 );
@@ -1036,6 +1063,8 @@ bool Cluster::Split(TxGraphImpl& graph, int level) noexcept
10361063 graph.InsertCluster (level, std::move (new_cluster), split_quality);
10371064 todo -= component;
10381065 }
1066+ // We have to split the Cluster up. Remove accounting for the existing one first.
1067+ graph.GetClusterSet (level).m_cluster_usage -= TotalMemoryUsage ();
10391068 // Redistribute the transactions.
10401069 for (auto i : m_linearization) {
10411070 /* * The cluster which transaction originally in position i is moved to. */
@@ -1057,10 +1086,11 @@ bool Cluster::Split(TxGraphImpl& graph, int level) noexcept
10571086 for (auto par : m_depgraph.GetReducedParents (i)) new_parents.Set (remap[par].second );
10581087 new_cluster->m_depgraph .AddDependencies (new_parents, remap[i].second );
10591088 }
1060- // Update all the Locators of moved transactions.
1089+ // Update all the Locators of moved transactions, and memory usage .
10611090 for (Cluster* new_cluster : new_clusters) {
10621091 new_cluster->Updated (graph, level);
10631092 new_cluster->Compact ();
1093+ graph.GetClusterSet (level).m_cluster_usage += new_cluster->TotalMemoryUsage ();
10641094 }
10651095 // Wipe this Cluster, and return that it needs to be deleted.
10661096 m_depgraph = DepGraph<SetType>{};
@@ -1624,7 +1654,9 @@ void TxGraphImpl::Merge(std::span<Cluster*> to_merge, int level) noexcept
16241654 // moves.
16251655 size_t max_size_pos{0 };
16261656 DepGraphIndex max_size = to_merge[max_size_pos]->GetTxCount ();
1657+ GetClusterSet (level).m_cluster_usage -= to_merge[max_size_pos]->TotalMemoryUsage ();
16271658 for (size_t i = 1 ; i < to_merge.size (); ++i) {
1659+ GetClusterSet (level).m_cluster_usage -= to_merge[i]->TotalMemoryUsage ();
16281660 DepGraphIndex size = to_merge[i]->GetTxCount ();
16291661 if (size > max_size) {
16301662 max_size_pos = i;
@@ -1639,6 +1671,7 @@ void TxGraphImpl::Merge(std::span<Cluster*> to_merge, int level) noexcept
16391671 DeleteCluster (*to_merge[i], level);
16401672 }
16411673 to_merge[0 ]->Compact ();
1674+ GetClusterSet (level).m_cluster_usage += to_merge[0 ]->TotalMemoryUsage ();
16421675}
16431676
16441677void TxGraphImpl::ApplyDependencies (int level) noexcept
@@ -1764,6 +1797,7 @@ TxGraph::Ref TxGraphImpl::AddTransaction(const FeePerWeight& feerate) noexcept
17641797 auto & clusterset = GetClusterSet (level);
17651798 InsertCluster (level, std::move (cluster), oversized ? QualityLevel::OVERSIZED_SINGLETON : QualityLevel::OPTIMAL);
17661799 cluster_ptr->Updated (*this , level);
1800+ clusterset.m_cluster_usage += cluster_ptr->TotalMemoryUsage ();
17671801 ++clusterset.m_txcount ;
17681802 // Deal with individually oversized transactions.
17691803 if (oversized) {
@@ -2116,6 +2150,7 @@ void TxGraphImpl::StartStaging() noexcept
21162150 m_staging_clusterset->m_group_data = m_main_clusterset.m_group_data ;
21172151 m_staging_clusterset->m_oversized = m_main_clusterset.m_oversized ;
21182152 Assume (m_staging_clusterset->m_oversized .has_value ());
2153+ m_staging_clusterset->m_cluster_usage = 0 ;
21192154}
21202155
21212156void TxGraphImpl::AbortStaging () noexcept
@@ -2413,6 +2448,7 @@ void TxGraphImpl::SanityCheck() const
24132448 assert (level < MAX_LEVELS);
24142449 auto & clusterset = GetClusterSet (level);
24152450 std::set<const Cluster*> actual_clusters;
2451+ size_t recomputed_cluster_usage{0 };
24162452
24172453 // For all quality levels...
24182454 for (int qual = 0 ; qual < int (QualityLevel::NONE); ++qual) {
@@ -2448,9 +2484,14 @@ void TxGraphImpl::SanityCheck() const
24482484 // Check that the cluster's quality and setindex matches its position in the quality list.
24492485 assert (cluster.m_quality == quality);
24502486 assert (cluster.m_setindex == setindex);
2487+ // Count memory usage.
2488+ recomputed_cluster_usage += cluster.TotalMemoryUsage ();
24512489 }
24522490 }
24532491
2492+ // Verify memory usage.
2493+ assert (clusterset.m_cluster_usage == recomputed_cluster_usage);
2494+
24542495 // Verify that all to-be-removed transactions have valid identifiers.
24552496 for (GraphIndex idx : clusterset.m_to_remove ) {
24562497 assert (idx < m_entries.size ());
0 commit comments