Skip to content

Commit a6446a8

Browse files
committed
issue/83: function-level memory profiling
1 parent e325e39 commit a6446a8

File tree

13 files changed

+411
-39
lines changed

13 files changed

+411
-39
lines changed

crates/lean_compiler/src/b_compile_intermediate.rs

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use utils::ToUsize;
1010
#[derive(Default)]
1111
struct Compiler {
1212
bytecode: BTreeMap<Label, Vec<IntermediateInstruction>>,
13-
match_blocks: Vec<Vec<Vec<IntermediateInstruction>>>, // each match = many bytecode blocks, each bytecode block = many instructions
13+
match_blocks: Vec<MatchBlock>,
1414
if_counter: usize,
1515
call_counter: usize,
1616
func_name: String,
@@ -152,10 +152,17 @@ fn compile_function(
152152
compiler.args_count = function.arguments.len();
153153

154154
let mut declared_vars: BTreeSet<Var> = function.arguments.iter().cloned().collect();
155-
compile_lines(&function.instructions, compiler, None, &mut declared_vars)
155+
compile_lines(
156+
&Label::function(function.name.clone()),
157+
&function.instructions,
158+
compiler,
159+
None,
160+
&mut declared_vars,
161+
)
156162
}
157163

158164
fn compile_lines(
165+
function_name: &Label,
159166
lines: &[SimpleLine],
160167
compiler: &mut Compiler,
161168
final_jump: Option<Label>,
@@ -212,6 +219,7 @@ fn compile_lines(
212219
let mut arm_declared_vars = declared_vars.clone();
213220
compiler.stack_size = original_stack_size;
214221
let arm_instructions = compile_lines(
222+
function_name,
215223
arm,
216224
compiler,
217225
Some(end_label.clone()),
@@ -229,7 +237,10 @@ fn compile_lines(
229237
};
230238
}
231239
compiler.stack_size = new_stack_size;
232-
compiler.match_blocks.push(compiled_arms);
240+
compiler.match_blocks.push(MatchBlock {
241+
function_name: function_name.clone(),
242+
match_cases: compiled_arms,
243+
});
233244

234245
let value_scaled_offset = IntermediateValue::MemoryAfterFp {
235246
offset: compiler.stack_size.into(),
@@ -261,8 +272,13 @@ fn compile_lines(
261272
updated_fp: None,
262273
});
263274

264-
let remaining =
265-
compile_lines(&lines[i + 1..], compiler, final_jump, declared_vars)?;
275+
let remaining = compile_lines(
276+
function_name,
277+
&lines[i + 1..],
278+
compiler,
279+
final_jump,
280+
declared_vars,
281+
)?;
266282
compiler.bytecode.insert(end_label, remaining);
267283

268284
return Ok(instructions);
@@ -349,6 +365,7 @@ fn compile_lines(
349365

350366
let mut then_declared_vars = declared_vars.clone();
351367
let then_instructions = compile_lines(
368+
function_name,
352369
then_branch,
353370
compiler,
354371
Some(end_label.clone()),
@@ -359,6 +376,7 @@ fn compile_lines(
359376
compiler.stack_size = original_stack;
360377
let mut else_declared_vars = declared_vars.clone();
361378
let else_instructions = compile_lines(
379+
function_name,
362380
else_branch,
363381
compiler,
364382
Some(end_label.clone()),
@@ -375,8 +393,13 @@ fn compile_lines(
375393
compiler.bytecode.insert(if_label, then_instructions);
376394
compiler.bytecode.insert(else_label, else_instructions);
377395

378-
let remaining =
379-
compile_lines(&lines[i + 1..], compiler, final_jump, declared_vars)?;
396+
let remaining = compile_lines(
397+
function_name,
398+
&lines[i + 1..],
399+
compiler,
400+
final_jump,
401+
declared_vars,
402+
)?;
380403
compiler.bytecode.insert(end_label, remaining);
381404

382405
return Ok(instructions);
@@ -399,7 +422,7 @@ fn compile_lines(
399422
}
400423

401424
SimpleLine::FunctionCall {
402-
function_name,
425+
function_name: callee_function_name,
403426
args,
404427
return_data,
405428
} => {
@@ -411,7 +434,7 @@ fn compile_lines(
411434
compiler.stack_size += 1;
412435

413436
instructions.extend(setup_function_call(
414-
function_name,
437+
callee_function_name,
415438
args,
416439
new_fp_pos,
417440
&return_label,
@@ -436,6 +459,7 @@ fn compile_lines(
436459
}
437460

438461
instructions.extend(compile_lines(
462+
function_name,
439463
&lines[i + 1..],
440464
compiler,
441465
final_jump,

crates/lean_compiler/src/c_compile_final.rs

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -52,47 +52,71 @@ pub fn compile_to_low_level_bytecode(
5252
.get("main")
5353
.unwrap();
5454

55+
let mut hints = BTreeMap::new();
5556
let mut label_to_pc = BTreeMap::new();
5657
label_to_pc.insert(Label::function("main"), 0);
5758
let entrypoint = intermediate_bytecode
5859
.bytecode
5960
.remove(&Label::function("main"))
6061
.ok_or("No main function found in the compiled program")?;
62+
hints.insert(
63+
0,
64+
vec![Hint::StackFrame {
65+
label: Label::function("main"),
66+
size: starting_frame_memory,
67+
}],
68+
);
6169

62-
let mut code_blocks = vec![(0, entrypoint.clone())];
70+
let mut code_blocks = vec![(Label::function("main"), 0, entrypoint.clone())];
6371
let mut pc = count_real_instructions(&entrypoint);
72+
6473
for (label, instructions) in &intermediate_bytecode.bytecode {
6574
label_to_pc.insert(label.clone(), pc);
66-
code_blocks.push((pc, instructions.clone()));
75+
if let Label::Function(function_name) = label {
76+
hints
77+
.entry(pc)
78+
.or_insert_with(Vec::new)
79+
.push(Hint::StackFrame {
80+
label: label.clone(),
81+
size: *intermediate_bytecode
82+
.memory_size_per_function
83+
.get(function_name)
84+
.unwrap(),
85+
});
86+
}
87+
code_blocks.push((label.clone(), pc, instructions.clone()));
6788
pc += count_real_instructions(instructions);
6889
}
6990

7091
let ending_pc = label_to_pc.get(&Label::EndProgram).copied().unwrap();
7192

7293
let mut match_block_sizes = Vec::new();
7394
let mut match_first_block_starts = Vec::new();
74-
for match_statement in intermediate_bytecode.match_blocks {
75-
let max_block_size = match_statement
95+
for MatchBlock {
96+
function_name,
97+
match_cases,
98+
} in intermediate_bytecode.match_blocks
99+
{
100+
let max_block_size = match_cases
76101
.iter()
77102
.map(|block| count_real_instructions(block))
78103
.max()
79104
.unwrap();
80105
match_first_block_starts.push(pc);
81106
match_block_sizes.push(max_block_size);
82107

83-
for mut block in match_statement {
108+
for mut block in match_cases {
84109
// fill the end of block with unreachable instructions
85110
block.extend(vec![
86111
IntermediateInstruction::Panic;
87112
max_block_size - count_real_instructions(&block)
88113
]);
89-
code_blocks.push((pc, block));
114+
code_blocks.push((function_name.clone(), pc, block));
90115
pc += max_block_size;
91116
}
92117
}
93118

94119
let mut low_level_bytecode = Vec::new();
95-
let mut hints = BTreeMap::new();
96120

97121
for (label, pc) in label_to_pc.clone() {
98122
hints
@@ -108,9 +132,10 @@ pub fn compile_to_low_level_bytecode(
108132
match_first_block_starts,
109133
};
110134

111-
for (pc_start, block) in code_blocks {
135+
for (function_name, pc_start, block) in code_blocks {
112136
compile_block(
113137
&compiler,
138+
&function_name,
114139
&block,
115140
pc_start,
116141
&mut low_level_bytecode,
@@ -130,6 +155,7 @@ pub fn compile_to_low_level_bytecode(
130155

131156
fn compile_block(
132157
compiler: &Compiler,
158+
function_name: &Label,
133159
block: &[IntermediateInstruction],
134160
pc_start: CodeAddress,
135161
low_level_bytecode: &mut Vec<Instruction>,
@@ -359,6 +385,7 @@ fn compile_block(
359385
.unwrap()
360386
.to_usize();
361387
let hint = Hint::RequestMemory {
388+
function_name: function_name.clone(),
362389
offset: eval_const_expression_usize(&offset, compiler),
363390
vectorized,
364391
size,

crates/lean_compiler/src/ir/bytecode.rs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,16 @@ use lean_vm::Label;
33
use std::collections::BTreeMap;
44
use std::fmt::{Display, Formatter};
55

6+
/// A match statement bytecode block
7+
#[derive(Debug, Clone)]
8+
pub struct MatchBlock {
9+
/// Name of the function containing the match block
10+
pub function_name: Label,
11+
12+
/// Cases of the match block
13+
pub match_cases: Vec<Vec<IntermediateInstruction>>,
14+
}
15+
616
/// Container for the complete intermediate representation of a program.
717
///
818
/// This structure holds all the compiled intermediate bytecode along with
@@ -17,7 +27,7 @@ pub struct IntermediateBytecode {
1727
/// Match statement bytecode blocks.
1828
///
1929
/// Each match statement produces multiple case blocks.
20-
pub match_blocks: Vec<Vec<Vec<IntermediateInstruction>>>,
30+
pub match_blocks: Vec<MatchBlock>,
2131

2232
/// Memory requirements for each function.
2333
///
@@ -29,13 +39,13 @@ impl Display for IntermediateBytecode {
2939
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
3040
for (label, instructions) in &self.bytecode {
3141
writeln!(f, "\n{label}:")?;
32-
for instruction in instructions {
42+
for instruction in instructions.iter() {
3343
writeln!(f, " {instruction}")?;
3444
}
3545
}
36-
for (i, match_blocks) in self.match_blocks.iter().enumerate() {
46+
for (i, MatchBlock { match_cases, .. }) in self.match_blocks.iter().enumerate() {
3747
writeln!(f, "\nMatch {i}:")?;
38-
for (j, case) in match_blocks.iter().enumerate() {
48+
for (j, case) in match_cases.iter().enumerate() {
3949
writeln!(f, " Case {j}:")?;
4050
for instruction in case {
4151
writeln!(f, " {instruction}")?;

crates/lean_compiler/src/ir/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ pub mod instruction;
55
pub mod operation;
66
pub mod value;
77

8-
pub use bytecode::IntermediateBytecode;
8+
pub use bytecode::{IntermediateBytecode, MatchBlock};
99
pub use instruction::IntermediateInstruction;
1010
pub use operation::HighLevelOperation;
1111
pub use value::{IntermediaryMemOrFpOrConstant, IntermediateValue};

crates/lean_vm/src/core/types.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,6 @@ pub type SourceLineNumber = usize;
1111

1212
/// Bytecode address (i.e., a value of the program counter)
1313
pub type CodeAddress = usize;
14+
15+
/// Memory address
16+
pub type MemoryAddress = usize;

crates/lean_vm/src/diagnostics/error.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::core::F;
2+
use crate::diagnostics::profiler::MemoryProfile;
23
use crate::execution::Memory;
34
use crate::witness::{
45
WitnessDotProduct, WitnessMultilinearEval, WitnessPoseidon16, WitnessPoseidon24,
@@ -46,4 +47,5 @@ pub struct ExecutionResult {
4647
pub dot_products: Vec<WitnessDotProduct>,
4748
pub multilinear_evals: Vec<WitnessMultilinearEval>,
4849
pub summary: String,
50+
pub memory_profile: Option<MemoryProfile>,
4951
}

0 commit comments

Comments
 (0)