Refactor benchmarking suite to use Criterion

This commit is contained in:
Tom Forbes committed 2020-12-11 00:28:22 +00:00
1 parent 472e53542b
commit 5788e7bf8e
14 files changed
+370 -198

No files matched your search

+1
View File
@@ -16,3 +16,4 @@ flame.txt
flamescope.json
/wapm.lock
/wapm_packages
/.cargo/config
Generated
+185
View File
@@ -243,6 +243,15 @@ dependencies = [
"unicode-normalization",
]
[[package]]
name = "cast"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b9434b9a5aa1450faa3f9cb14ea0e8c53bb5d2b3c1bfd1ab4fc03e9f33fbfb0"
dependencies = [
"rustc_version",
]
[[package]]
name = "cc"
version = "1.0.66"
@@ -305,6 +314,12 @@ dependencies = [
"winapi",
]
[[package]]
name = "const_fn"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd51eab21ab4fd6a3bf889e2d0958c0a6e3a61ad04260325e919e652a2a62826"
[[package]]
name = "constant_time_eq"
version = "0.1.5"
@@ -454,6 +469,77 @@ dependencies = [
"cfg-if 1.0.0",
]
[[package]]
name = "criterion"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70daa7ceec6cf143990669a04c7df13391d55fb27bd4079d252fca774ba244d8"
dependencies = [
"atty",
"cast",
"clap",
"criterion-plot",
"csv",
"itertools",
"lazy_static 1.4.0",
"num-traits",
"oorandom",
"plotters",
"rayon",
"regex",
"serde",
"serde_cbor",
"serde_derive",
"serde_json",
"tinytemplate",
"walkdir",
]
[[package]]
name = "criterion-plot"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e022feadec601fba1649cfa83586381a4ad31c6bf3a9ab7d408118b05dd9889d"
dependencies = [
"cast",
"itertools",
]
[[package]]
name = "crossbeam-channel"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dca26ee1f8d361640700bde38b2c37d8c22b3ce2d360e1fc1c74ea4b0aa7d775"
dependencies = [
"cfg-if 1.0.0",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-deque"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9"
dependencies = [
"cfg-if 1.0.0",
"crossbeam-epoch",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-epoch"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1aaa739f95311c2c7887a76863f500026092fb1dce0161dab577e559ef3569d"
dependencies = [
"cfg-if 1.0.0",
"const_fn",
"crossbeam-utils",
"lazy_static 1.4.0",
"memoffset",
"scopeguard",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.1"
@@ -802,6 +888,12 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "half"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d36fab90f82edc3c747f9d438e06cf0a491055896f2a279638bb5beed6c40177"
[[package]]
name = "hashbrown"
version = "0.9.1"
@@ -1093,6 +1185,15 @@ version = "2.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525"
[[package]]
name = "memoffset"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "157b4208e3059a8f9e78d559edc658e13df41410cb3ae03979c83130067fdd87"
dependencies = [
"autocfg",
]
[[package]]
name = "miniz_oxide"
version = "0.4.3"
@@ -1233,6 +1334,12 @@ version = "1.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13bd41f508810a131401606d54ac32a467c97172d74ba7662562ebba5ad07fa0"
[[package]]
name = "oorandom"
version = "11.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575"
[[package]]
name = "opaque-debug"
version = "0.2.3"
@@ -1351,6 +1458,18 @@ version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c"
[[package]]
name = "plotters"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d1685fbe7beba33de0330629da9d955ac75bd54f33d7b79f9a895590124f6bb"
dependencies = [
"js-sys",
"num-traits",
"wasm-bindgen",
"web-sys",
]
[[package]]
name = "pmutil"
version = "0.5.3"
@@ -1475,6 +1594,31 @@ dependencies = [
"rustc_version",
]
[[package]]
name = "rayon"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b0d8e0819fadc20c74ea8373106ead0600e3a67ef1fe8da56e39b9ae7275674"
dependencies = [
"autocfg",
"crossbeam-deque",
"either",
"rayon-core",
]
[[package]]
name = "rayon-core"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ab346ac5921dc62ffa9f89b7a773907511cdfa5490c572ae9be1be33e8afa4a"
dependencies = [
"crossbeam-channel",
"crossbeam-deque",
"crossbeam-utils",
"lazy_static 1.4.0",
"num_cpus",
]
[[package]]
name = "redox_syscall"
version = "0.1.57"
@@ -1595,6 +1739,7 @@ dependencies = [
"cfg-if 0.1.10",
"clap",
"cpython",
"criterion",
"dirs-next",
"env_logger",
"flame",
@@ -1863,6 +2008,15 @@ version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
[[package]]
name = "same-file"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
dependencies = [
"winapi-util",
]
[[package]]
name = "schannel"
version = "0.1.19"
@@ -1915,6 +2069,16 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "serde_cbor"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e18acfa2f90e8b735b2836ab8d538de304cbb6729a7360729ea5a895d15a622"
dependencies = [
"half",
"serde",
]
[[package]]
name = "serde_derive"
version = "1.0.118"
@@ -2196,6 +2360,16 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3cb4fa83bb73adf1c7219f4fe4bf3c0ac5635e4e51e070fad5df745a41bedfb8"
[[package]]
name = "tinytemplate"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d3dc76004a03cec1c5932bca4cdc2e39aaa798e3f82363dd94f9adf6098c12f"
dependencies = [
"serde",
"serde_json",
]
[[package]]
name = "tinyvec"
version = "1.1.0"
@@ -2434,6 +2608,17 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8e76fae08f03f96e166d2dfda232190638c10e0383841252416f9cfe2ae60e6"
[[package]]
name = "walkdir"
version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d"
dependencies = [
"same-file",
"winapi",
"winapi-util",
]
[[package]]
name = "wasi"
version = "0.9.0+wasi-snapshot-preview1"
+13 -4
View File
@@ -14,10 +14,6 @@ members = [
"derive", "jit", "parser", "vm", "vm/pylib-crate", "wasm/lib",
]
[[bench]]
name = "bench"
path = "./benchmarks/bench.rs"
[features]
default = ["threading", "pylib"]
flame-it = ["rustpython-vm/flame-it", "flame", "flamescope"]
@@ -43,11 +39,22 @@ libc = "0.2"
flame = { version = "0.2", optional = true }
flamescope = { version = "0.1", optional = true }
cpython = "0.5.0"
[target.'cfg(not(target_os = "wasi"))'.dependencies]
rustyline = "6.0"
[dev-dependencies]
cpython = "0.5.0"
criterion = "0.3"
[[bench]]
name = "parsing"
harness = false
[[bench]]
name = "execution"
harness = false
[[bin]]
name = "rustpython"
@@ -63,3 +70,5 @@ opt-level = 3
# crossbeam-utils = { git = "https://github.com/crossbeam-rs/crossbeam" }
# socket2 = { git = "https://github.com/alexcrichton/socket2-rs" }
# REDOX END
[target.bench]
+38
View File
@@ -0,0 +1,38 @@
# Benchmarking
These are some files to determine performance of rustpython.
## Usage
Install pytest and pytest-benchmark:
$ pip install pytest-benchmark
Then run:
$ pytest
You can also benchmark the Rust benchmarks by just running
`cargo bench` from the root of the repository. To view Python tracebacks during benchmarks,
run `RUST_BACKTRACE=1 cargo bench`.
You can bench against a specific Python version by running:
```shell
$ PYTHON_SYS_EXECUTABLE=python3.7 cargo bench
```
On MacOS you will need to
add the following to a `.cargo/config` file:
```toml
[target.x86_64-apple-darwin]
rustflags = [
"-C", "link-arg=-undefined",
"-C", "link-arg=dynamic_lookup",
]
```
## Benchmark source
- https://benchmarksgame-team.pages.debian.net/benchmarksgame/program/nbody-python3-2.html
File renamed without changes.
File renamed without changes.
@@ -1,22 +1,11 @@
# The Computer Language Benchmarks Game
# https://salsa.debian.org/benchmarksgame-team/benchmarksgame/
# http://benchmarksgame.alioth.debian.org/
#
# originally by Kevin Carson
# contributed by Kevin Carson
# modified by Tupteq, Fredrik Johansson, and Daniel Nanz
# modified by Maciej Fijalkowski
# 2to3
# modified by Andriy Misyura
from math import sqrt
def combinations(l):
result = []
for x in range(len(l) - 1):
ls = l[x+1:]
for y in ls:
result.append((l[x][0],l[x][1],l[x][2],y[0],y[1],y[2]))
return result
import itertools
import sys
PI = 3.14159265358979323
SOLAR_MASS = 4 * PI * PI
@@ -55,41 +44,44 @@ BODIES = {
[2.68067772490389322e-03 * DAYS_PER_YEAR,
1.62824170038242295e-03 * DAYS_PER_YEAR,
-9.51592254519715870e-05 * DAYS_PER_YEAR],
5.15138902046611451e-05 * SOLAR_MASS) }
5.15138902046611451e-05 * SOLAR_MASS)}
SYSTEM = BODIES.values()
PAIRS = list(itertools.combinations(SYSTEM, 2))
SYSTEM = tuple(BODIES.values())
PAIRS = tuple(combinations(SYSTEM))
def advance(dt, n, bodies=SYSTEM, pairs=PAIRS):
for i in range(n):
for ([x1, y1, z1], v1, m1, [x2, y2, z2], v2, m2) in pairs:
for (([x1, y1, z1], v1, m1),
([x2, y2, z2], v2, m2)) in pairs:
dx = x1 - x2
dy = y1 - y2
dz = z1 - z2
dist = sqrt(dx * dx + dy * dy + dz * dz);
mag = dt / (dist*dist*dist)
mag = dt * ((dx * dx + dy * dy + dz * dz) ** (-1.5))
b1m = m1 * mag
b2m = m2 * mag
v1[0] -= dx * b2m
v1[1] -= dy * b2m
v1[2] -= dz * b2m
v2[2] += dz * b1m
v2[1] += dy * b1m
v2[0] += dx * b1m
v2[1] += dy * b1m
v2[2] += dz * b1m
for (r, [vx, vy, vz], m) in bodies:
r[0] += dt * vx
r[1] += dt * vy
r[2] += dt * vz
def report_energy(bodies=SYSTEM, pairs=PAIRS, e=0.0):
for ((x1, y1, z1), v1, m1, (x2, y2, z2), v2, m2) in pairs:
for (((x1, y1, z1), v1, m1),
((x2, y2, z2), v2, m2)) in pairs:
dx = x1 - x2
dy = y1 - y2
dz = z1 - z2
e -= (m1 * m2) / ((dx * dx + dy * dy + dz * dz) ** 0.5)
for (r, [vx, vy, vz], m) in bodies:
e += m * (vx * vx + vy * vy + vz * vz) / 2.
# print(f"{e}")
def offset_momentum(ref, bodies=SYSTEM, px=0.0, py=0.0, pz=0.0):
for (r, [vx, vy, vz], m) in bodies:
@@ -101,10 +93,12 @@ def offset_momentum(ref, bodies=SYSTEM, px=0.0, py=0.0, pz=0.0):
v[1] = py / m
v[2] = pz / m
def main(n, ref='sun'):
offset_momentum(BODIES[ref])
report_energy()
advance(0.01, n)
report_energy()
main(500)
main(int(25))
@@ -41,10 +41,6 @@ Version History:
"""
from __future__ import print_function
LOOPS = 50000
from time import time as clock
__version__ = "1.1.1"
@@ -68,15 +64,6 @@ class Record:
TRUE = 1
FALSE = 0
def main(loops=LOOPS):
benchtime, stones = pystones(loops)
print("Pystone(%s) time for %d passes = %f" % \
(__version__, loops, benchtime))
print("This machine benchmarks at %f pystones/second" % stones)
def pystones(loops=LOOPS):
return Proc0(loops)
IntGlob = 0
BoolGlob = FALSE
@@ -264,18 +251,4 @@ def Func3(EnumParIn):
return FALSE
if __name__ == '__main__':
import sys
def error(msg):
print(msg, end=' ', file=sys.stderr)
print("usage: %s [number_of_loops]" % sys.argv[0], file=sys.stderr)
sys.exit(100)
nargs = len(sys.argv) - 1
if nargs > 1:
error("%d arguments are too many;" % nargs)
elif nargs == 1:
try: loops = int(sys.argv[1])
except ValueError:
error("Invalid argument %r;" % sys.argv[1])
else:
loops = LOOPS
main(loops)
Proc0(LOOPS)
File renamed without changes.
+67
View File
@@ -0,0 +1,67 @@
use criterion::{black_box, criterion_group, criterion_main, Bencher, Criterion, BenchmarkId, Throughput};
use rustpython_compiler::{Mode};
use rustpython_vm::pyobject::PyResult;
use rustpython_vm::Interpreter;
const NBODY: &str = include_str!("./benchmarks/nbody.py");
const MANDELBROT: &str = include_str!("./benchmarks/mandelbrot.py");
const PYSTONE: &str = include_str!("./benchmarks/pystone.py");
fn bench_cpython(b: &mut Bencher, source: &str) {
let gil = cpython::Python::acquire_gil();
let python = gil.python();
b.iter(|| {
let res: cpython::PyResult<()> = python.run(source, None, None);
if let Err(e) = res {
e.print(python);
panic!("Error running source")
}
});
}
fn bench_rustpy(b: &mut Bencher, name: &str, source: &str) {
// NOTE: Take long time.
Interpreter::default().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(c: &mut Criterion, name: &str, contents: &str) {
let mut group = c.benchmark_group(name);
group.bench_function(BenchmarkId::new("cpython", name), |b| bench_cpython(b, black_box(contents)));
group.bench_function(BenchmarkId::new("rustpython", name), |b| bench_rustpy(b, name, black_box(contents)));
group.finish();
}
pub fn benchmark_pystone(c: &mut Criterion) {
let mut group = c.benchmark_group("pystone");
// Default is 50_000
for idx in (10_000..=50_000).step_by(10_000) {
let code_with_loops = format!("LOOPS = {}\n{}", idx, PYSTONE);
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(b, black_box(code_str)));
group.bench_function(BenchmarkId::new("rustpython", idx), |b| bench_rustpy(b, "pystone", black_box(code_str)));
}
group.finish();
}
pub fn criterion_benchmark(c: &mut Criterion) {
benchmark_pystone(c);
benchmark_file(c, "nbody.py", NBODY);
benchmark_file(c, "mandlebrot.py", MANDELBROT);
benchmark_file(c, "pystone.py", PYSTONE);
benchmark_file(c, "strings.py", PYSTONE);
}
criterion_group!(benches, criterion_benchmark);
criterion_main!(benches);
+45
View File
@@ -0,0 +1,45 @@
use criterion::{black_box, criterion_group, criterion_main, Criterion, Throughput};
use rustpython_parser::lexer::{make_tokenizer, Tok};
use rustpython_parser::parser::parse_program;
const MINIDOM: &str = include_str!("./benchmarks/minidom.py");
pub fn criterion_benchmark(c: &mut Criterion) {
let mut group = c.benchmark_group("tokenization");
group.throughput(Throughput::Bytes(MINIDOM.len() as u64));
group.bench_function("tokenization", |b| {
b.iter(|| {
let lexer = make_tokenizer(black_box(MINIDOM));
for res in lexer {
let _token: Tok = res.unwrap().1;
}
})
});
group.finish();
let mut group = c.benchmark_group("parse_to_ast");
group.throughput(Throughput::Bytes(MINIDOM.len() as u64));
group.bench_function("rustpy", |b| {
b.iter(|| parse_program(black_box(MINIDOM)).unwrap())
});
group.bench_function("cpython", |b| {
let gil = cpython::Python::acquire_gil();
let python = gil.python();
let globals = None;
let locals = cpython::PyDict::new(python);
locals.set_item(python, "SOURCE_CODE", MINIDOM).unwrap();
let code = "compile(SOURCE_CODE, mode=\"exec\", filename=\"minidom.py\")";
b.iter(|| {
let res: cpython::PyResult<cpython::PyObject> =
python.eval(black_box(code), globals, Some(&locals));
assert!(res.is_ok());
})
});
group.finish();
}
criterion_group!(benches, criterion_benchmark);
criterion_main!(benches);
File renamed without changes.
-22
View File
@@ -1,22 +0,0 @@
# Benchmarking
These are some files to determine performance of rustpython.
## Usage
Install pytest and pytest-benchmark:
$ pip install pytest-benchmark
Then run:
$ pytest
You can also benchmark the Rust benchmarks by just running
`cargo +nightly bench` from the root of the repository. Make sure you have Rust
nightly installed, as the benchmarking parts of the standard library are still
unstable.
## Benchmark source
- https://benchmarksgame-team.pages.debian.net/benchmarksgame/program/nbody-python3-2.html
-118
View File
@@ -1,118 +0,0 @@
#![feature(test)]
extern crate test;
use test::Bencher;
use rustpython_compiler::compile;
use rustpython_vm::pyobject::PyResult;
use rustpython_vm::Interpreter;
const MINIDOM: &str = include_str!("./benchmarks/minidom.py");
const NBODY: &str = include_str!("./benchmarks/nbody.py");
const MANDELBROT: &str = include_str!("./benchmarks/mandelbrot.py");
const PYSTONE: &str = include_str!("./benchmarks/pystone.py");
#[bench]
fn bench_tokenization(b: &mut Bencher) {
use rustpython_parser::lexer::{make_tokenizer, Tok};
let source = MINIDOM;
b.bytes = source.len() as _;
b.iter(|| {
let lexer = make_tokenizer(source);
for res in lexer {
let _token: Tok = res.unwrap().1;
}
})
}
#[bench]
fn bench_rustpy_parse_to_ast(b: &mut Bencher) {
use rustpython_parser::parser::parse_program;
let source = MINIDOM;
b.bytes = source.len() as _;
b.iter(|| parse_program(source).unwrap())
}
#[bench]
fn bench_cpython_parse_to_ast(b: &mut Bencher) {
let source = MINIDOM;
let gil = cpython::Python::acquire_gil();
let python = gil.python();
let globals = None;
let locals = cpython::PyDict::new(python);
locals.set_item(python, "SOURCE_CODE", source).unwrap();
let code = "compile(SOURCE_CODE, mode=\"exec\", filename=\"minidom.py\")";
b.bytes = source.len() as _;
b.iter(|| {
let res: cpython::PyResult<cpython::PyObject> = python.eval(code, globals, Some(&locals));
assert!(res.is_ok());
})
}
fn bench_cpython(b: &mut Bencher, source: &str) {
let gil = cpython::Python::acquire_gil();
let python = gil.python();
let globals = None;
let locals = None;
b.iter(|| {
let res: cpython::PyResult<()> = python.run(source, globals, locals);
assert!(res.is_ok());
})
}
#[bench]
fn bench_cpython_nbody(b: &mut Bencher) {
bench_cpython(b, NBODY)
}
#[bench]
fn bench_cpython_mandelbrot(b: &mut Bencher) {
bench_cpython(b, MANDELBROT)
}
#[bench]
fn bench_cpython_pystone(b: &mut Bencher) {
bench_cpython(b, PYSTONE)
}
fn bench_rustpy(b: &mut Bencher, name: &str, source: &str) {
// NOTE: Take long time.
Interpreter::default().enter(|vm| {
let code = vm
.compile(source, compile::Mode::Exec, name.to_owned())
.unwrap();
b.iter(|| {
let scope = vm.new_scope_with_builtins();
let res: PyResult = vm.run_code_obj(code.clone(), scope);
vm.unwrap_pyresult(res);
})
})
}
#[bench]
fn bench_rustpy_nbody(b: &mut Bencher) {
bench_rustpy(b, "nbody.py", NBODY)
}
#[bench]
fn bench_rustpy_mandelbrot(b: &mut Bencher) {
bench_rustpy(b, "mandelbrot.py", MANDELBROT)
}
#[bench]
fn bench_rustpy_pystone(b: &mut Bencher) {
bench_rustpy(b, "pystone.py", PYSTONE)
}