forked from RustPython/RustPython
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathexecution.rs
123 lines (112 loc) · 4.39 KB
/
execution.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
use criterion::measurement::WallTime;
use criterion::{
black_box, criterion_group, criterion_main, Bencher, BenchmarkGroup, BenchmarkId, Criterion,
Throughput,
};
use rustpython_compiler::Mode;
use rustpython_parser::ast;
use rustpython_parser::Parse;
use rustpython_vm::{Interpreter, PyResult, Settings};
use std::collections::HashMap;
use std::path::Path;
fn bench_cpython_code(b: &mut Bencher, source: &str) {
pyo3::Python::with_gil(|py| {
b.iter(|| {
let module =
pyo3::types::PyModule::from_code(py, source, "", "").expect("Error running source");
black_box(module);
})
})
}
fn bench_rustpy_code(b: &mut Bencher, name: &str, source: &str) {
// NOTE: Take long time.
let mut settings = Settings::default();
settings.path_list.push("Lib/".to_string());
settings.dont_write_bytecode = true;
settings.no_user_site = true;
Interpreter::without_stdlib(settings).enter(|vm| {
// Note: bench_cpython is both compiling and executing the code.
// As such we compile the code in the benchmark loop as well.
b.iter(|| {
let code = vm.compile(source, Mode::Exec, name.to_owned()).unwrap();
let scope = vm.new_scope_with_builtins();
let res: PyResult = vm.run_code_obj(code.clone(), scope);
vm.unwrap_pyresult(res);
})
})
}
pub fn benchmark_file_execution(group: &mut BenchmarkGroup<WallTime>, name: &str, contents: &str) {
group.bench_function(BenchmarkId::new(name, "cpython"), |b| {
bench_cpython_code(b, contents)
});
group.bench_function(BenchmarkId::new(name, "rustpython"), |b| {
bench_rustpy_code(b, name, contents)
});
}
pub fn benchmark_file_parsing(group: &mut BenchmarkGroup<WallTime>, name: &str, contents: &str) {
group.throughput(Throughput::Bytes(contents.len() as u64));
group.bench_function(BenchmarkId::new("rustpython", name), |b| {
b.iter(|| ast::Suite::parse(contents, name).unwrap())
});
group.bench_function(BenchmarkId::new("cpython", name), |b| {
pyo3::Python::with_gil(|py| {
let builtins =
pyo3::types::PyModule::import(py, "builtins").expect("Failed to import builtins");
let compile = builtins.getattr("compile").expect("no compile in builtins");
b.iter(|| {
let x = compile
.call1((contents, name, "exec"))
.expect("Failed to parse code");
black_box(x);
})
})
});
}
pub fn benchmark_pystone(group: &mut BenchmarkGroup<WallTime>, contents: String) {
// Default is 50_000. This takes a while, so reduce it to 30k.
for idx in (10_000..=30_000).step_by(10_000) {
let code_with_loops = format!("LOOPS = {}\n{}", idx, contents);
let code_str = code_with_loops.as_str();
group.throughput(Throughput::Elements(idx as u64));
group.bench_function(BenchmarkId::new("cpython", idx), |b| {
bench_cpython_code(b, code_str)
});
group.bench_function(BenchmarkId::new("rustpython", idx), |b| {
bench_rustpy_code(b, "pystone", code_str)
});
}
}
pub fn criterion_benchmark(c: &mut Criterion) {
let benchmark_dir = Path::new("./benches/benchmarks/");
let mut benches = benchmark_dir
.read_dir()
.unwrap()
.map(|entry| {
let path = entry.unwrap().path();
(
path.file_name().unwrap().to_str().unwrap().to_owned(),
std::fs::read_to_string(path).unwrap(),
)
})
.collect::<HashMap<_, _>>();
// Benchmark parsing
let mut parse_group = c.benchmark_group("parse_to_ast");
for (name, contents) in &benches {
benchmark_file_parsing(&mut parse_group, name, contents);
}
parse_group.finish();
// Benchmark PyStone
if let Some(pystone_contents) = benches.remove("pystone.py") {
let mut pystone_group = c.benchmark_group("pystone");
benchmark_pystone(&mut pystone_group, pystone_contents);
pystone_group.finish();
}
// Benchmark execution
let mut execution_group = c.benchmark_group("execution");
for (name, contents) in &benches {
benchmark_file_execution(&mut execution_group, name, contents);
}
execution_group.finish();
}
criterion_group!(benches, criterion_benchmark);
criterion_main!(benches);