Skip to content

Commit 17fe594

Browse files
authored
Add benchmark test cases for the new binder (#1455)
This PR adds a benchmark case to measure the performance of the new binder. I'd like to have a good baseline before making any big changes in the implementation (eg. using red-green trees for the CST and IR nodes). It would also be nice to have this merged before #1443 in order to measure how the simplification of the IR used by the binder affects performance.
1 parent 689d189 commit 17fe594

File tree

7 files changed

+130
-50
lines changed

7 files changed

+130
-50
lines changed

crates/solidity/outputs/cargo/crate/src/backend/binder/mod.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,6 @@ impl Binder {
231231
}
232232
}
233233

234-
#[cfg(feature = "__private_testing_utils")]
235234
pub(crate) fn get_linearised_bases(&self, node_id: NodeId) -> Option<&Vec<NodeId>> {
236235
self.linearisations.get(&node_id)
237236
}

crates/solidity/testing/perf/cargo/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ paste = { workspace = true }
1313
semver = { workspace = true }
1414
serde = { workspace = true }
1515
serde_json = { workspace = true }
16-
slang_solidity = { workspace = true }
16+
slang_solidity = { workspace = true, features = ["__private_backend_api"] }
1717
solar = { workspace = true }
1818
solidity_testing_utils = { workspace = true }
1919
streaming-iterator = { workspace = true }

crates/solidity/testing/perf/cargo/benches/slang/main.rs

Lines changed: 63 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use iai_callgrind::{
88
LibraryBenchmarkConfig, Tool, ValgrindTool,
99
};
1010
use paste::paste;
11+
use slang_solidity::backend::BinderOutput;
1112
use slang_solidity::compilation::CompilationUnit;
1213
use solidity_testing_perf_cargo::dataset::SolidityProject;
1314
use solidity_testing_perf_cargo::tests;
@@ -32,54 +33,68 @@ macro_rules! slang_define_full_tests {
3233
*/
3334

3435
paste! {
35-
#[library_benchmark(setup = tests::parser::setup)]
36-
#[bench::test(stringify!($prj))]
37-
pub fn [< $prj _parser >](project: &SolidityProject) -> Rc<CompilationUnit> {
38-
black_box(tests::parser::run(project))
39-
}
40-
41-
#[library_benchmark(setup = tests::cursor::setup)]
42-
#[bench::test(stringify!($prj))]
43-
pub fn [<$prj _cursor >](unit: Rc<CompilationUnit>) -> Rc<CompilationUnit> {
44-
black_box(tests::cursor::run(unit))
45-
}
46-
47-
#[library_benchmark(setup = tests::query::setup)]
48-
#[bench::test(stringify!($prj))]
49-
pub fn [<$prj _query >](unit: Rc<CompilationUnit>) -> Rc<CompilationUnit> {
50-
black_box(tests::query::run(unit))
51-
}
52-
53-
#[library_benchmark(setup = tests::bindings_build::setup)]
54-
#[bench::test(stringify!($prj))]
55-
pub fn [<$prj _bindings_build >](unit: Rc<CompilationUnit>) -> BuiltBindingGraph {
56-
black_box(tests::bindings_build::run(unit))
57-
}
58-
59-
#[library_benchmark(setup = tests::bindings_resolve::setup)]
60-
#[bench::test(stringify!($prj))]
61-
pub fn [<$prj _bindings_resolve >](unit: BuiltBindingGraph) -> BuiltBindingGraph {
62-
black_box(tests::bindings_resolve::run(unit))
63-
}
64-
65-
// We add a cleanup phase to measure the destruction of the AST and the binding structures
66-
#[library_benchmark(setup = tests::bindings_resolve::setup)]
67-
#[bench::test(stringify!($prj))]
68-
pub fn [< $prj _cleanup >](unit: BuiltBindingGraph) {
69-
black_box(unit);
70-
}
71-
72-
library_benchmark_group!(
73-
name = [< $prj _full>];
74-
75-
// __SLANG_INFRA_BENCHMARKS_LIST__ (keep in sync)
76-
benchmarks =
77-
[< $prj _parser>],
78-
[< $prj _cursor>],
79-
[< $prj _query>],
80-
[< $prj _bindings_build>],
81-
[< $prj _bindings_resolve>],
82-
[< $prj _cleanup>],
36+
#[library_benchmark(setup = tests::parser::setup)]
37+
#[bench::test(stringify!($prj))]
38+
pub fn [< $prj _parser >](project: &SolidityProject) -> Rc<CompilationUnit> {
39+
black_box(tests::parser::run(project))
40+
}
41+
42+
#[library_benchmark(setup = tests::cursor::setup)]
43+
#[bench::test(stringify!($prj))]
44+
pub fn [< $prj _cursor >](unit: Rc<CompilationUnit>) -> Rc<CompilationUnit> {
45+
black_box(tests::cursor::run(unit))
46+
}
47+
48+
#[library_benchmark(setup = tests::query::setup)]
49+
#[bench::test(stringify!($prj))]
50+
pub fn [< $prj _query >](unit: Rc<CompilationUnit>) -> Rc<CompilationUnit> {
51+
black_box(tests::query::run(unit))
52+
}
53+
54+
#[library_benchmark(setup = tests::bindings_build::setup)]
55+
#[bench::test(stringify!($prj))]
56+
pub fn [< $prj _bindings_build >](unit: Rc<CompilationUnit>) -> BuiltBindingGraph {
57+
black_box(tests::bindings_build::run(unit))
58+
}
59+
60+
#[library_benchmark(setup = tests::bindings_resolve::setup)]
61+
#[bench::test(stringify!($prj))]
62+
pub fn [< $prj _bindings_resolve >](unit: BuiltBindingGraph) -> BuiltBindingGraph {
63+
black_box(tests::bindings_resolve::run(unit))
64+
}
65+
66+
// We add a cleanup phase to measure the destruction of the AST and the binding structures
67+
#[library_benchmark(setup = tests::bindings_resolve::setup)]
68+
#[bench::test(stringify!($prj))]
69+
pub fn [< $prj _cleanup >](unit: BuiltBindingGraph) {
70+
black_box(unit);
71+
}
72+
73+
#[library_benchmark(setup = tests::binder_v2_run::setup)]
74+
#[bench::test(stringify!($prj))]
75+
fn [< $prj _binder_v2_run >](unit: CompilationUnit) -> BinderOutput {
76+
black_box(tests::binder_v2_run::run(unit))
77+
}
78+
79+
#[library_benchmark(setup = tests::binder_v2_cleanup::setup)]
80+
#[bench::test(stringify!($prj))]
81+
fn [< $prj _binder_v2_cleanup >](output: BinderOutput) {
82+
black_box(output);
83+
}
84+
85+
library_benchmark_group!(
86+
name = [< $prj _full >];
87+
88+
// __SLANG_INFRA_BENCHMARKS_LIST__ (keep in sync)
89+
benchmarks =
90+
[< $prj _parser >],
91+
[< $prj _cursor >],
92+
[< $prj _query >],
93+
[< $prj _bindings_build >],
94+
[< $prj _bindings_resolve >],
95+
[< $prj _cleanup >],
96+
[< $prj _binder_v2_run >],
97+
[< $prj _binder_v2_cleanup >],
8398
);
8499
}
85100
};

crates/solidity/testing/perf/cargo/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ mod unit_tests {
4646
define_payload_test_and_assert_count_eq!(query, super::CONTRACT_COUNT);
4747
define_payload_test!(bindings_build);
4848
define_payload_test_and_assert_count_eq!(bindings_resolve, super::IDENTIFIER_COUNT);
49+
define_payload_test_and_assert_count_eq!(binder_v2_run, super::IDENTIFIER_COUNT);
4950
}
5051

5152
mod solar {
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
use slang_solidity::backend::{build_binder_output, BinderOutput};
2+
3+
pub fn setup(project: &str) -> BinderOutput {
4+
build_binder_output(
5+
super::setup::setup(project)
6+
.build_compilation_unit()
7+
.unwrap(),
8+
)
9+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
use slang_solidity::backend::binder::Resolution;
2+
use slang_solidity::backend::{build_binder_output, BinderOutput};
3+
use slang_solidity::compilation::CompilationUnit;
4+
use slang_solidity::cst::{NodeKind, TerminalKindExtensions};
5+
6+
pub fn setup(project: &str) -> CompilationUnit {
7+
let project = super::setup::setup(project);
8+
project.build_compilation_unit().unwrap()
9+
}
10+
11+
pub fn run(unit: CompilationUnit) -> BinderOutput {
12+
inner_run(unit).0
13+
}
14+
15+
pub fn test(unit: CompilationUnit) -> usize {
16+
inner_run(unit).1
17+
}
18+
19+
fn inner_run(unit: CompilationUnit) -> (BinderOutput, usize) {
20+
let data = build_binder_output(unit);
21+
22+
let mut ids = 0;
23+
24+
for file in data.compilation_unit.files() {
25+
let mut cursor = file.create_tree_cursor();
26+
27+
while cursor.go_to_next_terminal() {
28+
if !matches!(cursor.node().kind(), NodeKind::Terminal(kind) if kind.is_identifier()) {
29+
continue;
30+
}
31+
32+
ids += 1;
33+
let node_id = cursor.node().id();
34+
if data
35+
.binder
36+
.find_definition_by_identifier_node_id(node_id)
37+
.is_none()
38+
&& data
39+
.binder
40+
.find_reference_by_identifier_node_id(node_id)
41+
.is_none_or(|reference| reference.resolution == Resolution::Unresolved)
42+
{
43+
panic!(
44+
"Unbound identifier: '{value}' in '{file_path}:{line}:{column}'.",
45+
value = cursor.node().unparse(),
46+
file_path = file.id(),
47+
line = cursor.text_range().start.line + 1,
48+
column = cursor.text_range().start.column + 1,
49+
);
50+
}
51+
}
52+
}
53+
(data, ids)
54+
}

crates/solidity/testing/perf/cargo/src/tests/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
pub mod binder_v2_cleanup;
2+
pub mod binder_v2_run;
13
pub mod bindings_build;
24
pub mod bindings_resolve;
35
pub mod cursor;

0 commit comments

Comments
 (0)