Skip to content

Commit 4c560ab

Browse files
authored
feat: improve trace utilization tracking (#10008)
Add functionality for considering previous active ranges in `ExecutionTraceUsageTracker` (needed for perturbator calculation in PG). Also update active ranges calculation to separately consider rows for lookup tables / databus vectors rather than a single range which covers both.
1 parent 8628b32 commit 4c560ab

File tree

2 files changed

+35
-31
lines changed

2 files changed

+35
-31
lines changed

barretenberg/cpp/src/barretenberg/plonk_honk_shared/execution_trace/execution_trace_usage_tracker.hpp

+33-29
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,10 @@ struct ExecutionTraceUsageTracker {
2020

2121
TraceStructure max_sizes; // max utilization of each block
2222
MegaTraceFixedBlockSizes fixed_sizes; // fixed size of each block prescribed by structuring
23-
MegaTraceActiveRanges active_ranges; // ranges utlized by the accumulator within the ambient structured trace
23+
// Store active ranges based on the most current accumulator and those based on all but the most recently
24+
// accumulated circuit. The former is needed for the combiner calculation and the latter for the perturbator.
25+
std::vector<Range> active_ranges;
26+
std::vector<Range> previous_active_ranges;
2427

2528
std::vector<Range> thread_ranges; // ranges within the ambient space over which utilized space is evenly distibuted
2629

@@ -60,36 +63,39 @@ struct ExecutionTraceUsageTracker {
6063
max_tables_size = std::max(max_tables_size, circuit.get_tables_size());
6164

6265
// Update the active ranges of the trace based on max block utilization
63-
for (auto [max_size, fixed_block, active_range] :
64-
zip_view(max_sizes.get(), fixed_sizes.get(), active_ranges.get())) {
66+
previous_active_ranges = active_ranges; // store active ranges based on all but the present circuit
67+
active_ranges.clear();
68+
for (auto [max_size, fixed_block] : zip_view(max_sizes.get(), fixed_sizes.get())) {
6569
size_t start_idx = fixed_block.trace_offset;
6670
size_t end_idx = start_idx + max_size;
67-
active_range = Range{ start_idx, end_idx };
71+
active_ranges.push_back(Range{ start_idx, end_idx });
6872
}
6973

70-
// The active ranges for the databus and lookup relations (both based on log-deriv lookup argument) must
71-
// incorporate both the lookup/read gate blocks as well as the rows containing the data that is being read.
72-
// Update the corresponding ranges accordingly. (Note: tables are constructed at the 'bottom' of the trace).
74+
// The active ranges must also include the rows where the actual databus and lookup table data are stored.
75+
// (Note: lookup tables are constructed at the end of the trace; databus data is constructed at the start).
7376
size_t dyadic_circuit_size = fixed_sizes.get_structured_dyadic_size();
74-
active_ranges.busread.first = 0; // databus data is stored at the top of the trace
75-
active_ranges.busread.second = std::max(max_databus_size, active_ranges.busread.second);
76-
active_ranges.lookup.first = std::min(dyadic_circuit_size - max_tables_size, active_ranges.lookup.first);
77-
active_ranges.lookup.second = dyadic_circuit_size; // lookups are stored at the bottom of the trace
77+
78+
// TODO(https://github.com/AztecProtocol/barretenberg/issues/1152): should be able to use simply Range{ 0,
79+
// max_databus_size } but this breaks for certain choices of num_threads.
80+
size_t databus_end =
81+
std::max(max_databus_size, static_cast<size_t>(fixed_sizes.busread.trace_offset + max_sizes.busread));
82+
active_ranges.push_back(Range{ 0, databus_end });
83+
size_t lookups_start =
84+
std::min(dyadic_circuit_size - max_tables_size, static_cast<size_t>(fixed_sizes.lookup.trace_offset));
85+
active_ranges.push_back(Range{ lookups_start, dyadic_circuit_size });
7886
}
7987

80-
// Check whether an index is contained within the active ranges
81-
bool check_is_active(const size_t idx)
88+
// Check whether an index is contained within the active ranges (or previous active ranges; needed for perturbator)
89+
bool check_is_active(const size_t idx, bool use_prev_accumulator = false)
8290
{
8391
// If structured trace is not in use, assume the whole trace is active
8492
if (!trace_settings.structure) {
8593
return true;
8694
}
87-
for (auto& range : active_ranges.get()) {
88-
if (idx >= range.first && idx < range.second) {
89-
return true;
90-
}
91-
}
92-
return false;
95+
std::vector<Range> ranges_to_check = use_prev_accumulator ? previous_active_ranges : active_ranges;
96+
return std::any_of(ranges_to_check.begin(), ranges_to_check.end(), [idx](const auto& range) {
97+
return idx >= range.first && idx < range.second;
98+
});
9399
}
94100

95101
// For printing only. Must match the order of the members in the arithmetization
@@ -117,7 +123,7 @@ struct ExecutionTraceUsageTracker {
117123
void print_active_ranges()
118124
{
119125
info("Active regions of accumulator: ");
120-
for (auto [label, range] : zip_view(block_labels, active_ranges.get())) {
126+
for (auto [label, range] : zip_view(block_labels, active_ranges)) {
121127
std::cout << std::left << std::setw(20) << (label + ":") << "(" << range.first << ", " << range.second
122128
<< ")" << std::endl;
123129
}
@@ -134,27 +140,25 @@ struct ExecutionTraceUsageTracker {
134140
}
135141

136142
/**
137-
* @brief Construct ranges of execution trace rows that evenly distribute the active content of the trace across a
143+
* @brief Construct ranges of execution trace rows that evenly distribute the active content of the trace across a
138144
* given number of threads.
139145
*
140146
* @param num_threads Num ranges over which to distribute the data
141147
* @param full_domain_size Size of full domain; needed only for unstructured case
148+
* @param use_prev_accumulator Base ranges on previous or current accumulator
142149
*/
143-
void construct_thread_ranges(const size_t num_threads, const size_t full_domain_size)
150+
void construct_thread_ranges(const size_t num_threads,
151+
const size_t full_domain_size,
152+
bool use_prev_accumulator = false)
144153
{
145-
// Copy the ranges into a simple std container for processing by subsequent methods (cheap)
146-
std::vector<Range> active_ranges_copy;
147-
for (const auto& range : active_ranges.get()) {
148-
active_ranges_copy.push_back(range);
149-
}
150-
151154
// Convert the active ranges for each gate type into a set of sorted non-overlapping ranges (union of the input)
152155
std::vector<Range> simplified_active_ranges;
153156
if (!trace_settings.structure) {
154157
// If not using a structured trace, set the active range to the whole domain
155158
simplified_active_ranges.push_back(Range{ 0, full_domain_size });
156159
} else {
157-
simplified_active_ranges = construct_union_of_ranges(active_ranges_copy);
160+
simplified_active_ranges = use_prev_accumulator ? construct_union_of_ranges(previous_active_ranges)
161+
: construct_union_of_ranges(active_ranges);
158162
}
159163

160164
// Determine ranges in the structured trace that even distibute the active content across threads

barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover_internal.hpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -135,15 +135,15 @@ template <class DeciderProvingKeys_> class ProtogalaxyProverInternal {
135135
std::vector<FF> linearly_dependent_contribution_accumulators(num_threads);
136136

137137
// Distribute the execution trace rows across threads so that each handles an equal number of active rows
138-
trace_usage_tracker.construct_thread_ranges(num_threads, polynomial_size);
138+
trace_usage_tracker.construct_thread_ranges(num_threads, polynomial_size, /*use_prev_accumulator=*/true);
139139

140140
parallel_for(num_threads, [&](size_t thread_idx) {
141141
const size_t start = trace_usage_tracker.thread_ranges[thread_idx].first;
142142
const size_t end = trace_usage_tracker.thread_ranges[thread_idx].second;
143143

144144
for (size_t idx = start; idx < end; idx++) {
145145
// The contribution is only non-trivial at a given row if the accumulator is active at that row
146-
if (trace_usage_tracker.check_is_active(idx)) {
146+
if (trace_usage_tracker.check_is_active(idx, /*use_prev_accumulator=*/true)) {
147147
const AllValues row = polynomials.get_row(idx);
148148
// Evaluate all subrelations on given row. Separator is 1 since we are not summing across rows here.
149149
const RelationEvaluations evals =

0 commit comments

Comments
 (0)