@@ -130,22 +130,22 @@ hash_tree::proof_type hash_tree::get_proof(address_ranges ars, uint64_t address,
130
130
// hit pristine node
131
131
if (is_pristine (node_index)) {
132
132
get_pristine_proof (curr_log2_size, proof);
133
- return proof ;
133
+ break ;
134
134
}
135
135
const auto &node = m_sparse_nodes[node_index];
136
136
assert (static_cast <int >(node.log2_size ) == curr_log2_size && " incorrect node log2_size" );
137
137
// hit sparse tree node
138
138
if (curr_log2_size == log2_size) {
139
139
proof.set_target_hash (node.hash );
140
- return proof ;
140
+ break ;
141
141
}
142
142
// transition to dense tree
143
143
if (is_ar_node (node)) {
144
144
auto &ar = ars[node.right ];
145
145
const int ar_log2_size = HASH_TREE_LOG2_PAGE_SIZE + ar.get_level_count () - 1 ;
146
146
assert (curr_log2_size == ar_log2_size && " incorrect ar node log2_size" );
147
147
get_dense_proof (ar, ar_log2_size, address, proof);
148
- return proof ;
148
+ break ;
149
149
}
150
150
// go down left or right on sparse tree depending on address
151
151
--curr_log2_size;
@@ -157,6 +157,7 @@ hash_tree::proof_type hash_tree::get_proof(address_ranges ars, uint64_t address,
157
157
node_index = node.right ;
158
158
}
159
159
}
160
+ return proof;
160
161
}
161
162
162
163
hash_tree_stats hash_tree::get_stats (bool clear) noexcept {
@@ -211,7 +212,7 @@ bool hash_tree::enqueue_hash_dirty_page(page_hash_tree_cache::simd_page_hasher<v
211
212
bool hash_tree::return_updated_dirty_pages (address_ranges ars, dirty_pages &batch,
212
213
changed_address_ranges &changed_ars) {
213
214
if (batch.empty ()) {
214
- return true ;
215
+ return false ;
215
216
}
216
217
// ??D The batch size past which we switch to parallel updates needs to be tuned empirically
217
218
const int batch_size = static_cast <int >(batch.size ());
@@ -577,6 +578,7 @@ bool hash_tree::verify(address_ranges ars) const {
577
578
auto actually_dirty = !std::ranges::equal (page_hash, dht.node_hash_view (offset, HASH_TREE_LOG2_PAGE_SIZE));
578
579
ar_actually_dirty = ar_actually_dirty || actually_dirty;
579
580
auto marked_dirty = dpt.is_node_dirty (offset, HASH_TREE_LOG2_PAGE_SIZE);
581
+ // LCOV_EXCL_START
580
582
if (actually_dirty != marked_dirty) {
581
583
if (!marked_dirty) {
582
584
ret = false ;
@@ -621,6 +623,7 @@ bool hash_tree::verify(address_ranges ars) const {
621
623
if (!std::ranges::equal (ar_node.hash , dht.node_hash_view (0 , ar_log2_size))) {
622
624
std::cerr << ar.get_description () << " dense hash tree root does not match sparse node hash\n " ;
623
625
}
626
+ // LCOV_EXCL_STOP
624
627
++ar_node_index;
625
628
}
626
629
return ret;
@@ -641,7 +644,7 @@ bool hash_tree::update(address_ranges ars) {
641
644
}
642
645
643
646
bool hash_tree::update_words (address_ranges ars, dirty_words_type dirty_words) {
644
- constexpr auto page_mask = ~UINT64_C (HASH_TREE_PAGE_SIZE - 1 );
647
+ constexpr auto page_mask = ~(HASH_TREE_PAGE_SIZE - 1 );
645
648
// Dirty_words contains an unordered set of the address of all words that became dirty since last update
646
649
// We copy these to a sorted vector "words"
647
650
// Every word in the same page must be updated by the same thread
@@ -671,9 +674,6 @@ bool hash_tree::update_words(address_ranges ars, dirty_words_type dirty_words) {
671
674
uint64_t update_failures{0 }; // NOLINT(misc-const-correctness)
672
675
int ar_index = 0 ;
673
676
int max_level_count = 0 ;
674
- variant_hasher h{m_hash_function};
675
- std::vector<uint64_t > curr_page_node;
676
- std::vector<uint64_t > next_page_node;
677
677
dense_node_entries curr_dense_node;
678
678
dense_node_entries next_dense_node;
679
679
changed_address_ranges changed_ars;
@@ -688,13 +688,15 @@ bool hash_tree::update_words(address_ranges ars, dirty_words_type dirty_words) {
688
688
continue ;
689
689
}
690
690
auto &cache_entry = opt_br->get ();
691
- while (!ars[ar_index].contains_absolute (paddr_page, HASH_TREE_PAGE_SIZE)) {
692
- if (ar_index >= static_cast <int >(ars.size ())) {
693
- ++update_failures;
694
- m_page_cache.return_entry (cache_entry);
695
- continue ;
691
+ for (; ar_index < static_cast <int >(ars.size ()); ++ar_index) {
692
+ if (ars[ar_index].contains_absolute (paddr_page, HASH_TREE_PAGE_SIZE)) {
693
+ break ;
696
694
}
697
- ++ar_index;
695
+ }
696
+ if (ar_index >= static_cast <int >(ars.size ())) {
697
+ ++update_failures;
698
+ m_page_cache.return_entry (cache_entry);
699
+ continue ;
698
700
}
699
701
auto &ar = ars[ar_index];
700
702
if (changed_ars.empty () || changed_ars.back () != ar_index) {
@@ -710,41 +712,30 @@ bool hash_tree::update_words(address_ranges ars, dirty_words_type dirty_words) {
710
712
const auto page_offset = paddr_page - ar.get_start ();
711
713
// if we had a cache hit, update only the words that changed in the cache
712
714
if (hit) {
713
- auto page = std::span<const unsigned char , HASH_TREE_PAGE_SIZE>{base + page_offset, HASH_TREE_PAGE_SIZE};
715
+ variant_hasher h{m_hash_function};
716
+ page_hash_tree_cache::simd_page_hasher<variant_hasher> queue (h);
717
+ const auto page =
718
+ std::span<const unsigned char , HASH_TREE_PAGE_SIZE>{base + page_offset, HASH_TREE_PAGE_SIZE};
714
719
auto &page_tree = cache_entry.get_page_hash_tree ();
715
720
const page_hash_tree_cache::page_view entry_page{cache_entry.get_page ()};
716
- curr_page_node.clear ();
717
721
for (auto word_address : std::span (words).subspan (begin, end - begin)) {
718
722
const auto word_offset = word_address - paddr_page;
719
- const auto page_word = page.subspan (word_offset, HASH_TREE_WORD_SIZE);
720
- const auto entry_word = entry_page.subspan (word_offset, HASH_TREE_WORD_SIZE);
721
- auto index = (HASH_TREE_PAGE_SIZE + word_offset) / HASH_TREE_WORD_SIZE;
722
- get_hash (h, page_word, page_tree[index]);
723
+ const auto page_word =
724
+ std::span<const unsigned char , HASH_TREE_WORD_SIZE>{page.subspan (word_offset, HASH_TREE_WORD_SIZE)};
725
+ const auto entry_word =
726
+ std::span<unsigned char , HASH_TREE_WORD_SIZE>{entry_page.subspan (word_offset, HASH_TREE_WORD_SIZE)};
727
+ const auto index = static_cast <int >((HASH_TREE_PAGE_SIZE + word_offset) / HASH_TREE_WORD_SIZE);
728
+ queue.enqueue_leaf (page_word, page_tree, index);
723
729
std::ranges::copy (page_word, entry_word.begin ());
724
- auto parent = index / 2 ;
725
- if (curr_page_node.empty () || curr_page_node.back () != parent) {
726
- curr_page_node.push_back (parent);
727
- }
728
- }
729
- for (int log2_size = HASH_TREE_LOG2_WORD_SIZE + 1 ; log2_size <= HASH_TREE_LOG2_PAGE_SIZE; ++log2_size) {
730
- next_page_node.clear ();
731
- for (auto index : curr_page_node) {
732
- auto left = index * 2 ;
733
- auto right = (index * 2 ) + 1 ;
734
- get_concat_hash (h, page_tree[left], page_tree[right], page_tree[index]);
735
- auto parent = index / 2 ;
736
- if (next_page_node.empty () || next_page_node.back () != parent) { // We know parent != 0
737
- next_page_node.push_back (parent);
738
- }
739
- }
740
- std::swap (curr_page_node, next_page_node);
741
730
}
731
+ queue.flush ();
742
732
// otherwise, the update from scratch
743
733
} else {
744
734
bool changed = false ;
745
735
if (!update_dirty_page (ar, cache_entry, changed)) {
746
736
++update_failures;
747
737
m_page_cache.return_entry (cache_entry);
738
+ continue ;
748
739
}
749
740
}
750
741
auto &dht = ar.get_dense_hash_tree ();
@@ -760,17 +751,20 @@ bool hash_tree::update_words(address_ranges ars, dirty_words_type dirty_words) {
760
751
for (int level = 1 ; level < max_level_count; ++level) {
761
752
auto log2_size = HASH_TREE_LOG2_PAGE_SIZE + level;
762
753
next_dense_node.clear ();
754
+ variant_hasher h{m_hash_function};
755
+ simd_concat_hasher<variant_hasher, const_machine_hash_view> queue (h);
763
756
for (auto &[dht, offset] : curr_dense_node) {
764
757
auto child_size = UINT64_C (1 ) << (log2_size - 1 );
765
758
auto parent = dht.node_hash_view (offset, log2_size);
766
759
auto left = dht.node_hash_view (offset, log2_size - 1 );
767
760
auto right = dht.node_hash_view (offset + child_size, log2_size - 1 );
768
- get_concat_hash (h, left, right, parent);
761
+ queue. enqueue ( left, right, parent);
769
762
auto dense_node = dense_node_entry{.dht = dht, .offset = get_aligned_address (offset, log2_size + 1 )};
770
763
if (next_dense_node.empty () || next_dense_node.back () != dense_node) {
771
764
next_dense_node.push_back (dense_node);
772
765
}
773
766
}
767
+ queue.flush ();
774
768
std::swap (curr_dense_node, next_dense_node);
775
769
}
776
770
return !static_cast <bool >(update_failures > 0 ) && update_sparse_tree (ars, changed_ars);
@@ -990,6 +984,7 @@ hash_tree::nodes_type hash_tree::create_nodes(const_address_ranges ars) {
990
984
return nodes;
991
985
}
992
986
987
+ // LCOV_EXCL_START
993
988
void hash_tree::dump (const_address_ranges ars, std::ostream &out) {
994
989
out << " digraph HashTree {\n " ;
995
990
out << " rankdir=TB;\n " ;
@@ -1059,5 +1054,6 @@ void hash_tree::dump(const_address_ranges ars, std::ostream &out) {
1059
1054
}
1060
1055
out << " }\n " ;
1061
1056
}
1057
+ // LCOV_EXCL_STOP
1062
1058
1063
1059
} // namespace cartesi
0 commit comments