From d90f98ab4aaaa6d524d8a2ab9fb3a8ba162ebb00 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 26 Dec 2025 13:54:25 -0500 Subject: [PATCH] clusterlin: inline UpdateChunk into (De)Activate (optimization) The two calls to UpdateChunk, in Activate and Deactive each, are subtly different: the top one needs to update the chunk_idx of iterated transactions, while the bottom one leaves it unchanged. To exploit this difference, inline the four function calls, getting rid of UpdateChunks. This is also a preparation for a future improvement that inlines the recomputation of reachable sets in the same loop in Deactivate. --- src/cluster_linearize.h | 80 ++++++++++++++++++----------------------- 1 file changed, 35 insertions(+), 45 deletions(-) diff --git a/src/cluster_linearize.h b/src/cluster_linearize.h index 7e20f802339..a53edf77282 100644 --- a/src/cluster_linearize.h +++ b/src/cluster_linearize.h @@ -723,36 +723,6 @@ private: return TxIdx(-1); } - /** Update a chunk: - * - All transactions have their chunk index set to `chunk_idx`. - * - All dependencies which have `query` in their top set get `dep_change` added to it - * (if `!Subtract`) or removed from it (if `Subtract`). - */ - template - void UpdateChunk(const SetType& tx_idxs, TxIdx query, SetIdx chunk_idx, const SetInfo& dep_change) noexcept - { - // Iterate over all the chunk's transactions. - for (auto tx_idx : tx_idxs) { - auto& tx_data = m_tx_data[tx_idx]; - // Update the chunk index for this transaction. - tx_data.chunk_idx = chunk_idx; - // Iterate over all active dependencies with tx_idx as parent. Combined with the outer - // loop this iterates over all internal active dependencies of the chunk. - for (auto child_idx : tx_data.active_children) { - auto& top_set_info = m_set_info[tx_data.dep_top_idx[child_idx]]; - // If this dependency's top set contains query, update it to add/remove - // dep_change. - if (top_set_info.transactions[query]) { - if constexpr (Subtract) { - top_set_info -= dep_change; - } else { - top_set_info |= dep_change; - } - } - } - } - } - /** Find the set of out-of-chunk transactions reachable from tx_idxs, both in upwards and * downwards direction. */ std::pair GetReachable(const SetType& tx_idxs) const noexcept @@ -801,17 +771,26 @@ private: // dependency being activated (E->C here) in its top set, will have the opposite part added // to it. This is true for B->A and F->E, but not for C->A and F->D. // - // Let UpdateChunk traverse the old parent chunk top_info (ABC in example), and add - // bottom_info (DEF) to every dependency's top set which has the parent (C) in it. At the - // same time, change the chunk_idx for each to be child_chunk_idx, which becomes the set for - // the merged chunk. - UpdateChunk(/*tx_idxs=*/top_info.transactions, /*query=*/parent_idx, - /*chunk_idx=*/child_chunk_idx, /*dep_change=*/bottom_info); - // Let UpdateChunk traverse the old child chunk bottom_info (DEF in example), and add - // top_info (ABC) to every dependency's top set which has the child (E) in it. The chunk - // these are part of isn't being changed here (already child_chunk_idx for each). - UpdateChunk(/*tx_idxs=*/bottom_info.transactions, /*query=*/child_idx, - /*chunk_idx=*/child_chunk_idx, /*dep_change=*/top_info); + // Traverse the old parent chunk top_info (ABC in example), and add bottom_info (DEF) to + // every dependency's top set which has the parent (C) in it. At the same time, change the + // chunk_idx for each to be child_chunk_idx, which becomes the set for the merged chunk. + for (auto tx_idx : top_info.transactions) { + auto& tx_data = m_tx_data[tx_idx]; + tx_data.chunk_idx = child_chunk_idx; + for (auto dep_child_idx : tx_data.active_children) { + auto& dep_top_info = m_set_info[tx_data.dep_top_idx[dep_child_idx]]; + if (dep_top_info.transactions[parent_idx]) dep_top_info |= bottom_info; + } + } + // Traverse the old child chunk bottom_info (DEF in example), and add top_info (ABC) to + // every dependency's top set which has the child (E) in it. + for (auto tx_idx : bottom_info.transactions) { + auto& tx_data = m_tx_data[tx_idx]; + for (auto dep_child_idx : tx_data.active_children) { + auto& dep_top_info = m_set_info[tx_data.dep_top_idx[dep_child_idx]]; + if (dep_top_info.transactions[child_idx]) dep_top_info |= top_info; + } + } // Merge top_info into bottom_info, which becomes the merged chunk. bottom_info |= top_info; m_cost += bottom_info.transactions.Count(); @@ -856,10 +835,21 @@ private: bottom_info -= top_info; // See the comment above in Activate(). We perform the opposite operations here, removing // instead of adding. - UpdateChunk(/*tx_idxs=*/top_info.transactions, /*query=*/parent_idx, - /*chunk_idx=*/parent_chunk_idx, /*dep_change=*/bottom_info); - UpdateChunk(/*tx_idxs=*/bottom_info.transactions, /*query=*/child_idx, - /*chunk_idx=*/child_chunk_idx, /*dep_change=*/top_info); + for (auto tx_idx : top_info.transactions) { + auto& tx_data = m_tx_data[tx_idx]; + tx_data.chunk_idx = parent_chunk_idx; + for (auto dep_child_idx : tx_data.active_children) { + auto& dep_top_info = m_set_info[tx_data.dep_top_idx[dep_child_idx]]; + if (dep_top_info.transactions[parent_idx]) dep_top_info -= bottom_info; + } + } + for (auto tx_idx : bottom_info.transactions) { + auto& tx_data = m_tx_data[tx_idx]; + for (auto dep_child_idx : tx_data.active_children) { + auto& dep_top_info = m_set_info[tx_data.dep_top_idx[dep_child_idx]]; + if (dep_top_info.transactions[child_idx]) dep_top_info -= top_info; + } + } // Compute the new sets of reachable transactions for each new chunk. m_reachable[child_chunk_idx] = GetReachable(bottom_info.transactions); m_reachable[parent_chunk_idx] = GetReachable(top_info.transactions);