Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
execution_trace_block.hpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: Complete, auditors: [Luke, Raju], commit: }
3// external_1: { status: not started, auditors: [], commit: }
4// external_2: { status: not started, auditors: [], commit: }
5// =====================
6
7#pragma once
14#include <cstddef>
15
16#ifdef CHECK_CIRCUIT_STACKTRACES
17#include <backward.hpp>
18#endif
19
20namespace bb {
21
22#ifdef CHECK_CIRCUIT_STACKTRACES
23struct BbStackTrace : backward::StackTrace {
24 BbStackTrace() { load_here(32); }
25};
26struct StackTraces {
27 std::vector<BbStackTrace> stack_traces;
28 void populate() { stack_traces.emplace_back(); }
29 void print(size_t gate_idx) const { backward::Printer{}.print(stack_traces.at(gate_idx)); }
30 // Don't interfere with equality semantics of structs that include this in debug builds
31 bool operator==(const StackTraces& other) const
32 {
33 static_cast<void>(other);
34 return true;
35 }
36};
37#endif
38
46template <typename FF> class Selector {
47 public:
48 Selector() = default;
49 virtual ~Selector() = default;
50
51 // Delete copy/move to avoid object slicing and unintended behavior
52 Selector(const Selector&) = default;
53 Selector& operator=(const Selector&) = default;
54 Selector(Selector&&) = delete;
56
61 void emplace_back(const FF& value) { push_back(value); }
62
67 virtual void emplace_back(int value) = 0;
68
73 virtual void push_back(const FF& value) = 0;
74
79 virtual void resize(size_t new_size) = 0;
80
86 virtual const FF& operator[](size_t index) const = 0;
87
92 virtual const FF& back() const = 0;
93
97 virtual size_t size() const = 0;
98
102 virtual bool empty() const = 0;
103
109 virtual void set(size_t idx, int value) = 0;
110
116 virtual void set(size_t idx, const FF& value) = 0;
117
121 virtual void free_memory() {}
122};
123
130template <typename FF> class ZeroSelector : public Selector<FF> {
131 public:
133
134 void emplace_back(int value) override
135 {
136 BB_ASSERT_EQ(value, 0, "Calling ZeroSelector::emplace_back with a non zero value.");
137 size_++;
138 }
139
140 void push_back(const FF& value) override
141 {
143 size_++;
144 }
145
146 void set(size_t, int) override { BB_ASSERT(false, "ZeroSelector::set should not be called"); }
147 void set(size_t, const FF&) override { BB_ASSERT(false, "ZeroSelector::set should not be called"); }
148
149 void resize(size_t new_size) override { size_ = new_size; }
150
151 bool operator==(const ZeroSelector& other) const { return size_ == other.size(); }
152
153 const FF& operator[](size_t index) const override
154 {
156 return zero;
157 }
158
159 const FF& back() const override { return zero; }
160
161 size_t size() const override { return size_; }
162
163 bool empty() const override { return size_ == 0; }
164
165 void free_memory() override { size_ = 0; }
166
167 private:
168 static constexpr FF zero = 0;
169 size_t size_ = 0;
170};
171
178template <typename FF> class SlabVectorSelector : public Selector<FF> {
179 public:
181
182 void emplace_back(int i) override { data.emplace_back(i); }
183 void push_back(const FF& value) override { data.push_back(value); }
184 void set(size_t idx, int i) override { data[idx] = i; }
185 void set(size_t idx, const FF& value) override { data[idx] = value; }
186 void resize(size_t new_size) override { data.resize(new_size); }
187
188 bool operator==(const SlabVectorSelector& other) const { return data == other.data; }
189
190 const FF& operator[](size_t i) const override { return data[i]; }
191 const FF& back() const override { return data.back(); }
192
193 size_t size() const override { return data.size(); }
194 bool empty() const override { return data.empty(); }
195
196 void free_memory() override
197 {
198 data.clear();
199 data.shrink_to_fit();
200 }
201
202 private:
203 std::vector<FF> data;
204};
205
212template <typename FF, size_t NUM_WIRES_> class ExecutionTraceBlock {
213 public:
214 static constexpr size_t NUM_WIRES = NUM_WIRES_;
215
217 using WireType = std::vector<uint32_t>;
218 using Wires = std::array<WireType, NUM_WIRES>;
219
224 ExecutionTraceBlock& operator=(ExecutionTraceBlock&&) noexcept = default;
225
226 virtual ~ExecutionTraceBlock() = default;
227
228#ifdef CHECK_CIRCUIT_STACKTRACES
229 // If enabled, we keep slow stack traces to be able to correlate gates with code locations where they were added
230 StackTraces stack_traces;
231#endif
232#ifdef TRACY_HACK_GATES_AS_MEMORY
233 std::vector<size_t> allocated_gates;
234#endif
236 {
237#ifdef TRACY_HACK_GATES_AS_MEMORY
238 std::unique_lock<std::mutex> lock(GLOBAL_GATE_MUTEX);
239 GLOBAL_GATE++;
240 TRACY_GATE_ALLOC(GLOBAL_GATE);
241 allocated_gates.push_back(GLOBAL_GATE);
242#endif
243 }
244
245 Wires wires; // vectors of indices into a witness variables array
246 size_t cached_size_ = 0; // set by free_data() so size() works after freeing
247 bool data_freed_ = false; // true after free_data() has been called
248 uint32_t trace_offset_ = std::numeric_limits<uint32_t>::max(); // where this block starts in the trace
249
250 uint32_t trace_offset() const
251 {
252 BB_ASSERT(trace_offset_ != std::numeric_limits<uint32_t>::max());
253 return trace_offset_;
254 }
255
256 bool operator==(const ExecutionTraceBlock& other) const = default;
257
258 size_t size() const { return data_freed_ ? cached_size_ : std::get<0>(this->wires).size(); }
259
260#ifdef TRACY_HACK_GATES_AS_MEMORY
262 {
263 std::unique_lock<std::mutex> lock(GLOBAL_GATE_MUTEX);
264 for ([[maybe_unused]] size_t gate : allocated_gates) {
265 if (!FREED_GATES.contains(gate)) {
266 TRACY_GATE_FREE(gate);
267 FREED_GATES.insert(gate);
268 }
269 }
270 }
271#endif
272
274
280 {
282 data_freed_ = true;
283 for (auto& wire : wires) {
284 wire.clear();
285 wire.shrink_to_fit();
286 }
287 for (auto& sel : get_selectors()) {
288 sel.free_memory();
289 }
290 }
291
292 void populate_wires(const uint32_t& idx_1, const uint32_t& idx_2, const uint32_t& idx_3, const uint32_t& idx_4)
293 {
294#ifdef CHECK_CIRCUIT_STACKTRACES
295 this->stack_traces.populate();
296#endif
297 this->tracy_gate();
298 this->wires[0].emplace_back(idx_1);
299 this->wires[1].emplace_back(idx_2);
300 this->wires[2].emplace_back(idx_3);
301 this->wires[3].emplace_back(idx_4);
302 }
303
304 auto& w_l() { return std::get<0>(this->wires); };
305 auto& w_r() { return std::get<1>(this->wires); };
306 auto& w_o() { return std::get<2>(this->wires); };
307 auto& w_4() { return std::get<3>(this->wires); };
308
315
316 protected:
318};
319
320} // namespace bb
#define BB_ASSERT(expression,...)
Definition assert.hpp:70
#define BB_ASSERT_DEBUG(expression,...)
Definition assert.hpp:55
#define BB_ASSERT_EQ(actual, expected,...)
Definition assert.hpp:83
Basic structure for storing gate data in a builder.
std::vector< uint32_t > WireType
std::array< WireType, NUM_WIRES > Wires
ExecutionTraceBlock(ExecutionTraceBlock &&) noexcept=default
static constexpr size_t NUM_WIRES
bool operator==(const ExecutionTraceBlock &other) const =default
virtual ~ExecutionTraceBlock()=default
ExecutionTraceBlock & operator=(const ExecutionTraceBlock &)=default
void populate_wires(const uint32_t &idx_1, const uint32_t &idx_2, const uint32_t &idx_3, const uint32_t &idx_4)
void free_data()
Release wire and selector memory. Caches block size so size() still works.
virtual RefVector< Selector< FF > > get_selectors()=0
std::array< SlabVectorSelector< FF >, 6 > non_gate_selectors
ExecutionTraceBlock(const ExecutionTraceBlock &)=default
A template class for a reference vector. Behaves as if std::vector<T&> was possible.
Abstract interface for a generic selector.
virtual void resize(size_t new_size)=0
Resize the selector.
virtual size_t size() const =0
Get the number of elements.
virtual ~Selector()=default
virtual void emplace_back(int value)=0
Append an integer value to the selector.
virtual const FF & back() const =0
Get the last value in the selector.
Selector(Selector &&)=delete
virtual void set(size_t idx, int value)=0
Set the value at index using integer.
virtual bool empty() const =0
Check if the selector is empty.
virtual void push_back(const FF &value)=0
Push a field element to the selector.
Selector & operator=(const Selector &)=default
Selector & operator=(Selector &&)=delete
virtual void set(size_t idx, const FF &value)=0
Set the value at index using a field element.
virtual const FF & operator[](size_t index) const =0
Get value at specified index.
virtual void free_memory()
Release all memory held by this selector.
Selector()=default
void emplace_back(const FF &value)
Append a field element to the selector.
Selector(const Selector &)=default
Selector backed by a slab allocator vector.
void push_back(const FF &value) override
Push a field element to the selector.
void free_memory() override
Release all memory held by this selector.
void set(size_t idx, const FF &value) override
Set the value at index using a field element.
void resize(size_t new_size) override
Resize the selector.
size_t size() const override
Get the number of elements.
bool operator==(const SlabVectorSelector &other) const
const FF & operator[](size_t i) const override
Get value at specified index.
void emplace_back(int i) override
Append an integer value to the selector.
const FF & back() const override
Get the last value in the selector.
void set(size_t idx, int i) override
Set the value at index using integer.
bool empty() const override
Check if the selector is empty.
Selector specialization that only allows zeros.
void free_memory() override
Release all memory held by this selector.
static constexpr FF zero
const FF & operator[](size_t index) const override
Get value at specified index.
void emplace_back(int value) override
Append an integer value to the selector.
void set(size_t, int) override
Set the value at index using integer.
bool empty() const override
Check if the selector is empty.
bool operator==(const ZeroSelector &other) const
const FF & back() const override
Get the last value in the selector.
size_t size() const override
Get the number of elements.
void push_back(const FF &value) override
Push a field element to the selector.
void set(size_t, const FF &) override
Set the value at index using a field element.
void resize(size_t new_size) override
Resize the selector.
#define TRACY_GATE_ALLOC(t)
Definition mem.hpp:16
#define TRACY_GATE_FREE(t)
Definition mem.hpp:17
bool operator==(schnorr_signature const &lhs, schnorr_signature const &rhs)
Definition schnorr.hpp:45
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
BB_INLINE constexpr bool is_zero() const noexcept