Skip to content

Commit 9751481

Browse files
authored
the revive-explorer utility (#364)
A maintainable and more precise version of what was a hacky but useful script, exploring the compilers YUL lowering unit. It analyzes a given shared objects from the debug dump and outputs: - The count of each YUL statement translated. - A per YUL statement break-down of bytecode size contributed per. - Estimated `yul-phaser` cost parameters. Signed-off-by: Cyrill Leutwiler <[email protected]>
1 parent c285a6e commit 9751481

File tree

15 files changed

+709
-1
lines changed

15 files changed

+709
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ Supported `polkadot-sdk` rev: `2503.0.1`
1616
- Line debug information per YUL builtin and for `if` statements.
1717
- Column numbers in debug information.
1818
- Support for the YUL optimizer details in the standard json input definition.
19+
- The `revive-explorer` compiler utility.
1920

2021
### Fixed
2122
- The debug info source file matches the YUL path in `--debug-output-dir`, allowing tools to display the source line.

Cargo.lock

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ revive-benchmarks = { version = "0.1.0", path = "crates/benchmarks" }
1919
revive-builtins = { version = "0.1.0", path = "crates/builtins" }
2020
revive-common = { version = "0.1.0", path = "crates/common" }
2121
revive-differential = { version = "0.1.0", path = "crates/differential" }
22+
revive-explorer = { version = "0.1.0", path = "crates/explore" }
2223
revive-integration = { version = "0.1.1", path = "crates/integration" }
2324
revive-linker = { version = "0.1.0", path = "crates/linker" }
2425
lld-sys = { version = "0.1.0", path = "crates/lld-sys" }

Makefile

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
install-llvm-builder \
77
install-llvm \
88
install-revive-runner \
9+
install-revive-explorer \
910
format \
1011
clippy \
1112
machete \
@@ -43,6 +44,9 @@ install-llvm: install-llvm-builder
4344
install-revive-runner:
4445
cargo install --locked --force --path crates/runner --no-default-features
4546

47+
install-revive-explorer:
48+
cargo install --locked --force --path crates/explorer --no-default-features
49+
4650
format:
4751
cargo fmt --all --check
4852

@@ -53,7 +57,7 @@ machete:
5357
cargo install cargo-machete
5458
cargo machete
5559

56-
test: format clippy machete test-cli test-workspace install-revive-runner
60+
test: format clippy machete test-cli test-workspace install-revive-runner install-revive-explorer
5761

5862
test-integration: install-bin
5963
cargo test --package revive-integration

crates/explorer/Cargo.toml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
[package]
2+
name = "revive-explorer"
3+
version.workspace = true
4+
license.workspace = true
5+
edition.workspace = true
6+
repository.workspace = true
7+
authors.workspace = true
8+
description = "Helper utility to inspect debug builds"
9+
10+
[[bin]]
11+
name = "revive-explorer"
12+
path = "src/main.rs"
13+
14+
[dependencies]
15+
anyhow = { workspace = true }
16+
clap = { workspace = true, features = ["help", "std", "derive"] }
17+
num_cpus = { workspace = true }
18+
19+
revive-yul = { workspace = true }
20+

crates/explorer/README.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# revive-explorer
2+
3+
The `revive-explorer` is a helper utility for exploring the compilers YUL lowering unit.
4+
5+
It analyzes a given shared objects from the debug dump and outputs:
6+
- The count of each YUL statement translated.
7+
- A per YUL statement break-down of bytecode size contributed per.
8+
- Estimated `yul-phaser` cost parameters.
9+
10+
Example:
11+
12+
```
13+
statements count:
14+
block 532
15+
Caller 20
16+
Not 73
17+
Gas 24
18+
Shr 2
19+
...
20+
Shl 259
21+
SetImmutable 2
22+
CodeSize 1
23+
CallDataLoad 87
24+
Return 56
25+
bytes per statement:
26+
Or 756
27+
CodeCopy 158
28+
Log3 620
29+
Return 1562
30+
MStore 36128
31+
...
32+
ReturnDataCopy 2854
33+
DataOffset 28
34+
assignment 1194
35+
Number 540
36+
CallValue 4258
37+
yul-phaser parameters:
38+
--break-cost 1
39+
--variable-declaration-cost 3
40+
--function-call-cost 8
41+
--if-cost 4
42+
--expression-statement-cost 6
43+
--function-definition-cost 11
44+
--switch-cost 3
45+
--block-cost 1
46+
--leave-cost 1
47+
--assignment-cost 1
48+
```
49+

crates/explorer/src/dwarfdump.rs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
//! The `llvm-dwarfdump` utility helper library.
2+
3+
use std::{
4+
path::{Path, PathBuf},
5+
process::{Command, Stdio},
6+
};
7+
8+
pub static EXECUTABLE: &str = "llvm-dwarfdump";
9+
pub static DEBUG_LINES_ARGUMENTS: [&str; 1] = ["--debug-line"];
10+
pub static SOURCE_FILE_ARGUMENTS: [&str; 1] = ["--show-sources"];
11+
12+
/// Calls the `llvm-dwarfdump` tool to extract debug line information
13+
/// from the shared object at `path`. Returns the output.
14+
///
15+
/// Provide `Some(dwarfdump_exectuable)` to override the default executable.
16+
pub fn debug_lines(
17+
shared_object: &Path,
18+
dwarfdump_executable: &Option<PathBuf>,
19+
) -> anyhow::Result<String> {
20+
dwarfdump(shared_object, dwarfdump_executable, &DEBUG_LINES_ARGUMENTS)
21+
}
22+
23+
/// Calls the `llvm-dwarfdump` tool to extract the source file name.
24+
/// Returns the source file path.
25+
///
26+
/// Provide `Some(dwarfdump_exectuable)` to override the default executable.
27+
pub fn source_file(
28+
shared_object: &Path,
29+
dwarfdump_executable: &Option<PathBuf>,
30+
) -> anyhow::Result<PathBuf> {
31+
let output = dwarfdump(shared_object, dwarfdump_executable, &SOURCE_FILE_ARGUMENTS)?;
32+
Ok(output.trim().into())
33+
}
34+
35+
/// The internal `llvm-dwarfdump` helper function.
36+
fn dwarfdump(
37+
shared_object: &Path,
38+
dwarfdump_executable: &Option<PathBuf>,
39+
arguments: &[&str],
40+
) -> anyhow::Result<String> {
41+
let executable = dwarfdump_executable
42+
.to_owned()
43+
.unwrap_or_else(|| PathBuf::from(EXECUTABLE));
44+
45+
let output = Command::new(executable)
46+
.args(arguments)
47+
.arg(shared_object)
48+
.stdin(Stdio::null())
49+
.stdout(Stdio::piped())
50+
.stderr(Stdio::piped())
51+
.spawn()?
52+
.wait_with_output()?;
53+
54+
if !output.status.success() {
55+
anyhow::bail!(String::from_utf8_lossy(&output.stderr).to_string());
56+
}
57+
58+
Ok(String::from_utf8_lossy(&output.stdout).to_string())
59+
}

0 commit comments

Comments
 (0)