Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
execution_trace_usage_tracker.hpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: not started, auditors: [], date: YYYY-MM-DD }
3// external_1: { status: not started, auditors: [], date: YYYY-MM-DD }
4// external_2: { status: not started, auditors: [], date: YYYY-MM-DD }
5// =====================
6
7#pragma once
8
11#include <iostream>
12
13namespace bb {
14
26
27 TraceStructure max_sizes; // max utilization of each block
28 MegaTraceFixedBlockSizes fixed_sizes; // fixed size of each block prescribed by structuring
29 // Store active ranges based on the most current accumulator and those based on all but the most recently
30 // accumulated circuit. The former is needed for the combiner calculation and the latter for the perturbator.
31 // The ranges cover all areas in the trace where relations have nontrivial values.
32 std::vector<Range> active_ranges;
33 std::vector<Range> previous_active_ranges;
34
36 thread_ranges; // ranges within the ambient space over which utilized space is evenly distibuted
37
38 // Max sizes of the "tables" for databus and conventional lookups (distinct from the sizes of their gate blocks)
39 size_t max_databus_size = 0;
40 size_t max_tables_size = 0;
41 size_t max_gates_size = 0;
42
43 // For printing only. Must match the order of the members in the arithmetization
44
45 static constexpr std::array<std::string_view, 14> block_labels{ "ecc_op",
46 "busread",
47 "lookup",
48 "pub_inputs",
49 "arithmetic",
50 "delta_range",
51 "elliptic",
52 "memory",
53 "nnf",
54 "poseidon2_external",
55 "poseidon2_internal",
56 "overflow",
57 "databus_table_data",
58 "lookup_table_data" };
59
61
64 {
65 for (auto& size : max_sizes.get()) {
66 size = 0; // init max sizes to zero
67 }
68
71 }
72
73 fixed_sizes.compute_offsets(/*is_structured=*/true);
74 }
75
76 // Update the max block utilization and active trace ranges based on the data from a provided circuit
77 void update(const Builder& circuit)
78 {
79 // Update the max utilization of each gate block
80 for (auto [block, max_size] : zip_view(circuit.blocks.get(), max_sizes.get())) {
81 max_size = std::max(static_cast<uint32_t>(block.size()), max_size);
82 }
83
85
86 // update the max sixe of the databus and lookup tables
88 circuit.get_calldata().size(),
89 circuit.get_secondary_calldata().size(),
90 circuit.get_return_data().size() });
92
93 // Update the active ranges of the trace based on max block utilization
94 previous_active_ranges = active_ranges; // store active ranges based on all but the present circuit
95 active_ranges.clear();
96 for (auto [max_size, fixed_block] : zip_view(max_sizes.get(), fixed_sizes.get())) {
97 size_t start_idx = fixed_block.trace_offset();
98 size_t end_idx = start_idx + max_size;
99 active_ranges.push_back(Range{ start_idx, end_idx });
100 }
101
102 // The active range for lookup-style blocks consists of two components: (1) rows containing the lookup/read
103 // gates and (2) rows containing the table data itself. The Mega arithmetization contains two such blocks:
104 // conventional lookups (lookup block) and the databus (busread block). Here we add the ranges corresponding
105 // to the "table" data for these two blocks. The corresponding gate ranges were added above.
106 size_t databus_data_start = 0; // Databus column data starts at idx 0
107 size_t databus_data_end = databus_data_start + max_databus_size;
108 active_ranges.push_back(Range{ databus_data_start, databus_data_end }); // region where databus contains data
109
110 // Note: start of table data is aligned with start of the lookup gates block
111 size_t tables_start = fixed_sizes.lookup.trace_offset();
112 size_t tables_end = tables_start + max_tables_size;
113 active_ranges.emplace_back(Range{ tables_start, tables_end }); // region where table data is stored
114 }
115
116 void print()
117 {
118 // NOTE: This is used by downstream tools for parsing the required block sizes. Do not change this
119 // without updating (or consulting Grego).
120 info("Largest circuit: ", max_gates_size, " gates. Trace details:");
121 info("Minimum required block sizes for structured trace: ");
122 size_t idx = 0;
123 for (auto max_size : max_sizes.get()) {
124 std::cerr << std::left << std::setw(20) << block_labels[idx] << ": " << max_size << std::endl;
125 idx++;
126 }
127 info("");
128 }
129
131 {
132 info("Active regions of accumulator: ");
133 for (auto [label, range] : zip_view(block_labels, active_ranges)) {
134 std::cerr << std::left << std::setw(20) << label << ": (" << range.first << ", " << range.second << ")"
135 << std::endl;
136 }
137 info("");
138 }
139
141 {
142 info("Active regions of previous accumulator: ");
143 for (auto [label, range] : zip_view(block_labels, previous_active_ranges)) {
144 std::cerr << std::left << std::setw(20) << label << ": (" << range.first << ", " << range.second << ")"
145 << std::endl;
146 }
147 info("");
148 }
149
151 {
152 info("Thread ranges: ");
153 for (const auto& ranges : thread_ranges) {
154 std::cerr << "[" << std::endl;
155 for (auto range : ranges) {
156 std::cerr << "(" << range.first << ", " << range.second << ")" << std::endl;
157 }
158 std::cerr << "]" << std::endl;
159 }
160 info("");
161 }
162
171 void construct_thread_ranges(const size_t num_threads,
172 const size_t full_domain_size,
173 bool use_prev_accumulator = false)
174 {
175 // Convert the active ranges for each gate type into a set of sorted non-overlapping ranges (union of the input)
176 std::vector<Range> simplified_active_ranges;
178 // If not using a structured trace, set the active range to the whole domain
179 simplified_active_ranges.push_back(Range{ 0, full_domain_size });
180 } else {
181 simplified_active_ranges = use_prev_accumulator ? construct_union_of_ranges(previous_active_ranges)
183 }
184
185 // Determine ranges in the structured trace that even distibute the active content across threads
186 thread_ranges = construct_ranges_for_equal_content_distribution(simplified_active_ranges, num_threads);
187 }
188
197 static std::vector<Range> construct_union_of_ranges(std::vector<Range>& ranges)
198 {
199 std::vector<Range> union_ranges;
200
201 // Sort the ranges by start index (secondarily by end_idx if start indices agree)
202 std::sort(ranges.begin(), ranges.end());
203
204 union_ranges.push_back(ranges.front());
205
206 for (const Range& range : ranges) {
207 Range& prev_range = union_ranges.back();
208
209 // If the two ranges overlap or are contiguous, merge them
210 if (range.first <= prev_range.second) {
211 prev_range.second = std::max(range.second, prev_range.second);
212 } else { // otherwise add the present range to the union
213 union_ranges.push_back(range);
214 }
215 }
216
217 return union_ranges;
218 }
219
234 const std::vector<Range>& union_ranges, const size_t num_threads)
235 {
237
238 for (const Range& range : union_ranges) {
239 size_t start_idx = range.first;
240 size_t total_content = range.second - start_idx;
241 size_t content_per_thread = total_content / num_threads;
242 size_t leftovers = total_content % num_threads;
243 for (size_t i = 0; i < num_threads; i++) {
244 size_t end_idx =
245 start_idx + content_per_thread + (i < leftovers ? 1 : 0); // Distribute leftovers evenly
246 if (start_idx < end_idx) {
247 thread_ranges[i].push_back(Range{ start_idx, end_idx });
248 start_idx = end_idx;
249 }
250 }
251 }
252
253 return thread_ranges;
254 }
255};
256} // namespace bb
const BusVector & get_calldata() const
const BusVector & get_secondary_calldata() const
const BusVector & get_return_data() const
void compute_offsets(bool is_structured)
void set_fixed_block_sizes(const TraceSettings &settings)
size_t get_tables_size() const
Get combined size of all tables used in circuit.
void info(Args... args)
Definition log.hpp:70
Entry point for Barretenberg command-line interface.
MegaCircuitBuilder_< field< Bn254FrParams > > MegaCircuitBuilder
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
size_t size() const
Definition databus.hpp:42
Tracks the cumulative usage of the execution trace across a series of circuits.
std::vector< std::vector< Range > > thread_ranges
ExecutionTraceUsageTracker(const TraceSettings &trace_settings=TraceSettings{})
void construct_thread_ranges(const size_t num_threads, const size_t full_domain_size, bool use_prev_accumulator=false)
Construct ranges of execution trace rows that evenly distribute the active content of the trace acros...
static constexpr std::array< std::string_view, 14 > block_labels
static std::vector< Range > construct_union_of_ranges(std::vector< Range > &ranges)
Construct sorted disjoint ranges representing the union of an arbitrary set of ranges.
static std::vector< std::vector< Range > > construct_ranges_for_equal_content_distribution(const std::vector< Range > &union_ranges, const size_t num_threads)
Given a set of ranges indicating "active" regions of an ambient space, define a given number of new r...
std::optional< TraceStructure > structure