Skip to content

Gather compilation statistics #1236

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 39 commits into from
Jun 2, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
9372b34
Add basic Statistics struct and its builder
JulianGCalderon May 16, 2025
8e854cf
Add Serialzie to Statistics
JulianGCalderon May 16, 2025
9bb64b7
Generate basic sierra statistics
JulianGCalderon May 16, 2025
e9246eb
Add stats argument to compile
JulianGCalderon May 16, 2025
27baa77
Save sierra to mlir and mlir passes time
JulianGCalderon May 16, 2025
5ef4dcf
Add stats argument to object_to_shared_lib
JulianGCalderon May 16, 2025
dc0f05c
Save linking time
JulianGCalderon May 16, 2025
5300e17
Add stats argument to module_to_object
JulianGCalderon May 16, 2025
6ef8644
Save llvm time
JulianGCalderon May 16, 2025
2ca97ec
Save total compilation time
JulianGCalderon May 16, 2025
0b5653e
Save object size in statistics
JulianGCalderon May 16, 2025
c375c23
Remove StatisticsBuilder
JulianGCalderon May 19, 2025
76f5b24
Add libfunc frequency
JulianGCalderon May 19, 2025
8668e78
Remove work
JulianGCalderon May 19, 2025
1e0b656
Assert frequency map is not empty
JulianGCalderon May 19, 2025
e8a1a97
Save mlir operation count
JulianGCalderon May 19, 2025
0fdf9b9
Save llvmir instructions and opcode frequency
JulianGCalderon May 19, 2025
da2e299
Save llvmir virtual register count
JulianGCalderon May 19, 2025
ba474c0
Adapt trace_dump.rs
JulianGCalderon May 19, 2025
6774ec1
Don't rely on transmute
JulianGCalderon May 19, 2025
1b8177d
Move MLIR walking logic to walk_ir module
JulianGCalderon May 19, 2025
97f4094
Move LLVMIR walking to walk_ir module
JulianGCalderon May 19, 2025
458bf97
Improve comments
JulianGCalderon May 19, 2025
29766ea
Pass statistics to compile stats
JulianGCalderon May 20, 2025
faf020f
Save MLIR operations by libfunc
JulianGCalderon May 20, 2025
24321a0
Add clone_option_mut macro
JulianGCalderon May 21, 2025
eb1a060
Validate statistics
JulianGCalderon May 21, 2025
1c516dc
Use clone_option_mut
JulianGCalderon May 21, 2025
ebbc29f
Document statistics
JulianGCalderon May 21, 2025
e7b00b4
Document walk_ir module
JulianGCalderon May 21, 2025
22f4e2c
Add API to statistics
JulianGCalderon May 22, 2025
8c7976c
Add support for saving stats on `starknet-native-compile`
JulianGCalderon May 22, 2025
e9e2483
Add documentation
JulianGCalderon May 22, 2025
2eae3f5
Fix clippy
JulianGCalderon May 22, 2025
01adb3f
Update starknet-blocks.yml ref
JulianGCalderon May 30, 2025
714eea1
Merge branch 'main' into comp-stats
JulianGCalderon May 30, 2025
dcd3cd1
Merge branch 'main' into comp-stats
gabrielbosio May 30, 2025
d6d382c
Rephrase docs
JulianGCalderon May 30, 2025
570d63d
Update script for comparing state dumps
JulianGCalderon May 30, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .github/workflows/daily.yml
Original file line number Diff line number Diff line change
Expand Up @@ -199,8 +199,7 @@ jobs:
continue-on-error: true

- name: Compare states
run: |
./scripts/cmp_state_dumps.sh | tee output
run: python ./scripts/cmp_state_dumps.py | tee output

- name: Upload Compare Results
id: upload_compare_results
Expand Down
7 changes: 3 additions & 4 deletions .github/workflows/starknet-blocks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ jobs:
with:
repository: lambdaclass/starknet-replay
path: starknet-replay
ref: 135ba7cd5b45fe137b11b7f75654dcd472363033
ref: 1b8e2e0be21a8df9f5f6b8f8514d1a40b456ef58
# We need native to use the linux deps ci action
- name: Checkout Native
uses: actions/checkout@v4
Expand All @@ -43,7 +43,7 @@ jobs:
with:
repository: lambdaclass/sequencer
path: sequencer
ref: b61262980394dab0e0a4c4cab85f12d31d0ce878
ref: 40331042c1149f5cb84b27f9dd8d47994a010bbe

- name: Cache RPC Calls
uses: actions/cache@v4.2.0
Expand Down Expand Up @@ -126,5 +126,4 @@ jobs:
continue-on-error: true

- name: Compare states
run: |
./scripts/cmp_state_dumps.sh
run: python ./scripts/cmp_state_dumps.py
16 changes: 8 additions & 8 deletions benches/compile_time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pub fn bench_compile_time(c: &mut Criterion) {
b.iter(|| {
let native_context = NativeContext::new();
native_context
.compile(program, false, Some(Default::default()))
.compile(program, false, Some(Default::default()), None)
.unwrap();
// pass manager internally verifies the MLIR output is correct.
})
Expand All @@ -32,7 +32,7 @@ pub fn bench_compile_time(c: &mut Criterion) {
c.bench_with_input(BenchmarkId::new(filename, 1), &program, |b, program| {
b.iter(|| {
native_context
.compile(program, false, Some(Default::default()))
.compile(program, false, Some(Default::default()), None)
.unwrap();
// pass manager internally verifies the MLIR output is correct.
})
Expand All @@ -48,9 +48,9 @@ pub fn bench_compile_time(c: &mut Criterion) {
b.iter(|| {
let native_context = NativeContext::new();
let module = native_context
.compile(black_box(program), false, Some(Default::default()))
.compile(black_box(program), false, Some(Default::default()), None)
.unwrap();
let object = module_to_object(module.module(), OptLevel::None)
let object = module_to_object(module.module(), OptLevel::None, None)
.expect("to compile correctly to a object file");
black_box(object)
})
Expand All @@ -67,9 +67,9 @@ pub fn bench_compile_time(c: &mut Criterion) {
c.bench_with_input(BenchmarkId::new(filename, 1), &program, |b, program| {
b.iter(|| {
let module = native_context
.compile(black_box(program), false, Some(Default::default()))
.compile(black_box(program), false, Some(Default::default()), None)
.unwrap();
let object = module_to_object(module.module(), OptLevel::None)
let object = module_to_object(module.module(), OptLevel::None, None)
.expect("to compile correctly to a object file");
black_box(object)
})
Expand All @@ -86,9 +86,9 @@ pub fn bench_compile_time(c: &mut Criterion) {
c.bench_with_input(BenchmarkId::new(filename, 1), &program, |b, program| {
b.iter(|| {
let module = native_context
.compile(black_box(program), false, Some(Default::default()))
.compile(black_box(program), false, Some(Default::default()), None)
.unwrap();
let object = module_to_object(module.module(), OptLevel::Aggressive)
let object = module_to_object(module.module(), OptLevel::Aggressive, None)
.expect("to compile correctly to a object file");
black_box(object)
})
Expand Down
8 changes: 4 additions & 4 deletions benches/libfuncs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ pub fn bench_libfuncs(c: &mut Criterion) {
let native_context = NativeContext::new();
b.iter(|| {
let module = native_context
.compile(program, false, Some(Default::default()))
.compile(program, false, Some(Default::default()), None)
.unwrap();
// pass manager internally verifies the MLIR output is correct.
let native_executor =
Expand All @@ -77,7 +77,7 @@ pub fn bench_libfuncs(c: &mut Criterion) {
|b, program| {
let native_context = NativeContext::new();
let module = native_context
.compile(program, false, Some(Default::default()))
.compile(program, false, Some(Default::default()), None)
.unwrap();
// pass manager internally verifies the MLIR output is correct.
let native_executor =
Expand Down Expand Up @@ -108,7 +108,7 @@ pub fn bench_libfuncs(c: &mut Criterion) {
let native_context = NativeContext::new();
b.iter(|| {
let module = native_context
.compile(program, false, Some(Default::default()))
.compile(program, false, Some(Default::default()), None)
.unwrap();
// pass manager internally verifies the MLIR output is correct.
let native_executor =
Expand All @@ -130,7 +130,7 @@ pub fn bench_libfuncs(c: &mut Criterion) {
|b, program| {
let native_context = NativeContext::new();
let module = native_context
.compile(program, false, Some(Default::default()))
.compile(program, false, Some(Default::default()), None)
.unwrap();
// pass manager internally verifies the MLIR output is correct.
let native_executor =
Expand Down
2 changes: 1 addition & 1 deletion examples/easy_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ fn main() {

// Compile the sierra program into a MLIR module.
let native_program = native_context
.compile(&sierra_program, false, Some(Default::default()))
.compile(&sierra_program, false, Some(Default::default()), None)
.unwrap();

// The parameters of the entry point.
Expand Down
2 changes: 1 addition & 1 deletion examples/erc20.rs
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,7 @@ fn main() {
let native_context = NativeContext::new();

let native_program = native_context
.compile(&sierra_program, false, Some(Default::default()))
.compile(&sierra_program, false, Some(Default::default()), None)
.unwrap();

let entry_point_fn =
Expand Down
2 changes: 1 addition & 1 deletion examples/invoke.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ fn main() {
let native_context = NativeContext::new();

let native_program = native_context
.compile(&sierra_program, false, Some(Default::default()))
.compile(&sierra_program, false, Some(Default::default()), None)
.unwrap();

// Call the echo function from the contract using the generated wrapper.
Expand Down
2 changes: 1 addition & 1 deletion examples/starknet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,7 @@ fn main() {
let native_context = NativeContext::new();

let native_program = native_context
.compile(&sierra_program, false, Some(Default::default()))
.compile(&sierra_program, false, Some(Default::default()), None)
.unwrap();

// Call the echo function from the contract using the generated wrapper.
Expand Down
97 changes: 97 additions & 0 deletions scripts/cmp_state_dumps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
#!/usr/bin/env python
#
# usage: cmp-state-dumps [-h] [-d]
# Compare all files in the state_dumps directory and outputs a summary
# options:
# -h, --help show this help message and exit
# -d, --delete removes matching files
#
# Uses a pool of worker threads that compare each state dump.
# possible improvements: use a pool of workers for file removing.

import argparse
import glob
import re
import multiprocessing as mp
import os
from collections import defaultdict

POOL_SIZE = 16

STATE_DUMPS_PATH = "state_dumps"
VM_DIRECTORY = "vm"
NATIVE_DIRECTORY = "native"

LOG_PATH = "state_dumps/matching.log"


def compare(vm_dump_path: str):
native_dump_path = re.sub(VM_DIRECTORY, NATIVE_DIRECTORY, vm_dump_path, count=1)

if not (m := re.findall(r"/(0x.*).json", vm_dump_path)):
raise Exception("bad path")
tx = m[0]

if not (m := re.findall(r"block(\d+)", vm_dump_path)):
raise Exception("bad path")
block = m[0]

try:
with open(native_dump_path) as f:
native_dump = f.read()
with open(vm_dump_path) as f:
vm_dump = f.read()
except: # noqa: E722
return ("MISS", block, tx)

native_dump = re.sub(r".*reverted.*", "", native_dump, count=1)
vm_dump = re.sub(r".*reverted.*", "", vm_dump, count=1)

if native_dump == vm_dump:
return ("MATCH", block, tx, vm_dump_path, native_dump_path)
else:
return ("DIFF", block, tx)


if __name__ == "__main__":
parser = argparse.ArgumentParser(
prog="cmp-state-dumps",
description="Compare all files in the state_dumps directory and outputs a summary",
)
parser.add_argument(
"-d", "--delete", action="store_true", help="removes matching files"
)
config = parser.parse_args()

files = glob.glob(f"{STATE_DUMPS_PATH}/{VM_DIRECTORY}/*/*.json")
files.sort(key=os.path.getmtime)

print(f"Starting comparison with {POOL_SIZE} workers")

stats = defaultdict(int)
with mp.Pool(POOL_SIZE) as pool, open(LOG_PATH, mode="a") as log:
for status, *info in pool.imap(compare, files):
stats[status] += 1

if status != "MATCH":
(block, tx) = info
print(status, block, tx)

elif status == "MATCH" and config.delete:
(block, tx, vm_dump_path, native_dump_path) = info

log.write(f"{block} {tx}\n")
log.flush()
os.remove(native_dump_path)
os.remove(vm_dump_path)

print("Finished comparison")

print()
for key, count in stats.items():
print(key, count)

if stats["DIFF"] != 0 or stats["MISS"] != 0:
exit(1)
else:
exit(0)
51 changes: 0 additions & 51 deletions scripts/cmp_state_dumps.sh

This file was deleted.

7 changes: 4 additions & 3 deletions src/bin/cairo-native-compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ fn main() -> anyhow::Result<()> {

// Compile the sierra program into a MLIR module.
let native_module = native_context
.compile(&sierra_program, false, Some(Default::default()))
.compile(&sierra_program, false, Some(Default::default()), None)
.unwrap();

let output_mlir = args
Expand All @@ -79,9 +79,10 @@ fn main() -> anyhow::Result<()> {
})
});

let object_data = module_to_object(native_module.module(), args.opt_level.into())
let object_data = module_to_object(native_module.module(), args.opt_level.into(), None)
.context("Failed to convert module to object.")?;
object_to_shared_lib(&object_data, &output_lib).context("Failed to write shared library.")?;
object_to_shared_lib(&object_data, &output_lib, None)
.context("Failed to write shared library.")?;

Ok(())
}
2 changes: 1 addition & 1 deletion src/bin/cairo-native-dump.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let program = load_program(Path::new(&args.input), args.starknet)?;

// Compile the program.
let module = context.compile(&program, false, Some(Default::default()))?;
let module = context.compile(&program, false, Some(Default::default()), None)?;

// Write the output.
let output_str = module
Expand Down
2 changes: 1 addition & 1 deletion src/bin/cairo-native-run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ fn main() -> anyhow::Result<()> {

// Compile the sierra program into a MLIR module.
let native_module = native_context
.compile(&sierra_program, false, Some(Default::default()))
.compile(&sierra_program, false, Some(Default::default()), None)
.unwrap();

let native_executor: Box<dyn Fn(_, _, _, &mut StubSyscallHandler) -> _> = match args.run_mode {
Expand Down
6 changes: 3 additions & 3 deletions src/bin/cairo-native-stress/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ where
) -> Arc<AotNativeExecutor> {
let native_module = self
.context
.compile(program, false, Some(Default::default()))
.compile(program, false, Some(Default::default()), None)
.expect("failed to compile program");

let registry = ProgramRegistry::new(program).expect("failed to get program registry");
Expand All @@ -291,15 +291,15 @@ where
.expect("module should have gas metadata");

let shared_library = {
let object_data = module_to_object(native_module.module(), opt_level)
let object_data = module_to_object(native_module.module(), opt_level, None)
.expect("failed to convert MLIR to object");

let shared_library_dir = Path::new(AOT_CACHE_DIR);
create_dir_all(shared_library_dir).expect("failed to create shared library directory");
let shared_library_name = format!("lib{key}{SHARED_LIBRARY_EXT}");
let shared_library_path = shared_library_dir.join(shared_library_name);

object_to_shared_lib(&object_data, &shared_library_path)
object_to_shared_lib(&object_data, &shared_library_path, None)
.expect("failed to link object into shared library");

unsafe {
Expand Down
1 change: 1 addition & 0 deletions src/bin/scarb-native-dump.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ fn main() -> anyhow::Result<()> {
&compiled.into_v1().unwrap().program,
false,
Some(Default::default()),
None,
)
.unwrap();

Expand Down
Loading
Loading