Skip to content

Commit ecdbe04

Browse files
committed
Add profiling using flamescope/speedscope
1 parent 98e6486 commit ecdbe04

File tree

5 files changed

+77
-22
lines changed

5 files changed

+77
-22
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,7 @@ __pycache__
1010
wasm-pack.log
1111
.idea/
1212
tests/snippets/resources
13+
1314
flame-graph.html
15+
flame.txt
16+
flamescope.json

Cargo.lock

Lines changed: 13 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: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ path = "./benchmarks/bench.rs"
1616

1717
[features]
1818
default = []
19-
flame-it = ["rustpython-vm/flame-it", "flame"]
19+
flame-it = ["rustpython-vm/flame-it", "flame", "flamescope"]
2020

2121
[dependencies]
2222
log="0.4.1"
@@ -29,6 +29,7 @@ rustyline = "4.1.0"
2929
xdg = "2.2.0"
3030

3131
flame = { version = "0.2", optional = true }
32+
flamescope = { version = "0.1", optional = true }
3233

3334
[dev-dependencies.cpython]
3435
version = "0.2"

src/main.rs

Lines changed: 57 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ fn main() {
2929
}
3030

3131
fn run() -> Result<(), Box<dyn std::error::Error>> {
32+
#[cfg(feature = "flame-it")]
33+
let main_guard = flame::start_guard("RustPython main");
3234
env_logger::init();
3335
let app = App::new("RustPython")
3436
.version(crate_version!())
@@ -55,15 +57,25 @@ fn run() -> Result<(), Box<dyn std::error::Error>> {
5557
)
5658
.arg(Arg::from_usage("[pyargs] 'args for python'").multiple(true));
5759
#[cfg(feature = "flame-it")]
58-
let app = app.arg(
59-
Arg::with_name("profile_output")
60-
.long("profile-output")
61-
.takes_value(true)
62-
.help(
63-
"the file to output the profile graph to. present due to being \
64-
built with feature 'flame-it'",
65-
),
66-
);
60+
let app = app
61+
.arg(
62+
Arg::with_name("profile_output")
63+
.long("profile-output")
64+
.takes_value(true)
65+
.help(
66+
"the file to output the profiling information to. present due to being \
67+
built with feature 'flame-it'",
68+
),
69+
)
70+
.arg(
71+
Arg::with_name("profile_format")
72+
.long("profile-format")
73+
.takes_value(true)
74+
.help(
75+
"the profile format to output the profiling information in. present due to \
76+
being built with feature 'flame-it'",
77+
),
78+
);
6779
let matches = app.get_matches();
6880

6981
// Construct vm:
@@ -92,13 +104,43 @@ fn run() -> Result<(), Box<dyn std::error::Error>> {
92104
{
93105
use std::fs::File;
94106

95-
let profile_output = matches
96-
.value_of_os("profile_output")
97-
.unwrap_or_else(|| "flame-graph.html".as_ref());
98-
if profile_output == "-" {
99-
flame::dump_stdout();
107+
main_guard.end();
108+
109+
enum ProfileFormat {
110+
Html,
111+
Text,
112+
Speedscope,
113+
}
114+
115+
let profile_output = matches.value_of_os("profile_output");
116+
117+
let profile_format = match matches.value_of("profile_format") {
118+
Some("html") => ProfileFormat::Html,
119+
Some("text") => ProfileFormat::Text,
120+
None if profile_output == Some("-".as_ref()) => ProfileFormat::Text,
121+
Some("speedscope") | None => ProfileFormat::Speedscope,
122+
Some(other) => {
123+
error!("Unknown profile format {}", other);
124+
process::exit(1);
125+
}
126+
};
127+
128+
let profile_output = profile_output.unwrap_or_else(|| match profile_format {
129+
ProfileFormat::Html => "flame-graph.html".as_ref(),
130+
ProfileFormat::Text => "flame.txt".as_ref(),
131+
ProfileFormat::Speedscope => "flamescope.json".as_ref(),
132+
});
133+
134+
let profile_output: Box<dyn std::io::Write> = if profile_output == "-" {
135+
Box::new(std::io::stdout())
100136
} else {
101-
flame::dump_html(&mut File::create(profile_output)?)?;
137+
Box::new(File::create(profile_output)?)
138+
};
139+
140+
match profile_format {
141+
ProfileFormat::Html => flame::dump_html(profile_output)?,
142+
ProfileFormat::Text => flame::dump_text_to_writer(profile_output)?,
143+
ProfileFormat::Speedscope => flamescope::dump(profile_output)?,
102144
}
103145
}
104146

vm/src/frame.rs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -271,11 +271,6 @@ impl Frame {
271271
// #[cfg_attr(feature = "flame-it", flame("Frame"))]
272272
pub fn run(&self, vm: &VirtualMachine) -> Result<ExecutionResult, PyObjectRef> {
273273
flame_guard!(format!("Frame::run({})", self.code.obj_name));
274-
// flame doesn't include notes in the html graph :(
275-
flame_note!(
276-
flame::StrCow::from("CodeObj name"),
277-
self.code.obj_name.clone().into()
278-
);
279274

280275
let filename = &self.code.source_path.to_string();
281276

@@ -342,10 +337,11 @@ impl Frame {
342337

343338
/// Execute a single instruction.
344339
#[allow(clippy::cognitive_complexity)]
345-
#[cfg_attr(feature = "flame-it", flame("Frame"))]
346340
fn execute_instruction(&self, vm: &VirtualMachine) -> FrameResult {
347341
let instruction = self.fetch_instruction();
348342

343+
flame_guard!(format!("Frame::execute_instruction({:?})", instruction));
344+
349345
#[cfg(feature = "vm-tracing-logging")]
350346
{
351347
trace!("=======");

0 commit comments

Comments
 (0)