mirror of
https://github.com/RustPython/RustPython.git
synced 2026-06-02 19:39:49 +09:00
Merge pull request #2541 from RustPython/coolreader18/try-microbenchmarks-again
Optimize(?) microbenchmarks some more
This commit is contained in:
4
Cargo.lock
generated
4
Cargo.lock
generated
@@ -1201,9 +1201,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mt19937"
|
||||
version = "2.0.0"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3e6dd1b4462edbfbc0c4ad4c3205d94623bb94b4819aa0888936988d38834158"
|
||||
checksum = "12ca7f22ed370d5991a9caec16a83187e865bc8a532f889670337d5a5689e3a1"
|
||||
dependencies = [
|
||||
"rand_core 0.6.2",
|
||||
]
|
||||
|
||||
@@ -422,20 +422,11 @@ class MersenneTwister_TestBasicOps(TestBasicOps, unittest.TestCase):
|
||||
def test_seedargs(self):
|
||||
super().test_seedargs()
|
||||
|
||||
@unittest.skip("TODO: RUSTPYTHON, hangs?")
|
||||
def test_choice(self):
|
||||
super().test_choice()
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_pickling(self):
|
||||
super().test_pickling()
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_bug_9025(self):
|
||||
super().test_bug_9025()
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_seed_when_randomness_source_not_found(self):
|
||||
@@ -613,8 +604,6 @@ class MersenneTwister_TestBasicOps(TestBasicOps, unittest.TestCase):
|
||||
cum |= int(self.gen.random() * span)
|
||||
self.assertEqual(cum, span-1)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_bigrand(self):
|
||||
# The randrange routine should build-up the required number of bits
|
||||
# in stages so that all bit positions are active.
|
||||
@@ -665,8 +654,6 @@ class MersenneTwister_TestBasicOps(TestBasicOps, unittest.TestCase):
|
||||
self.assertRaises(ValueError, self.gen.getrandbits, 0)
|
||||
self.assertRaises(ValueError, self.gen.getrandbits, -1)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_randrange_uses_getrandbits(self):
|
||||
# Verify use of getrandbits by randrange
|
||||
# Use same seed as in the cross-platform repeatability test
|
||||
|
||||
@@ -7,7 +7,7 @@ use rustpython_vm::pyobject::ItemProtocol;
|
||||
use rustpython_vm::pyobject::PyResult;
|
||||
use rustpython_vm::{InitParameter, Interpreter, PySettings};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::{fs, io};
|
||||
use std::{ffi, fs, io};
|
||||
|
||||
pub struct MicroBenchmark {
|
||||
name: String,
|
||||
@@ -20,8 +20,16 @@ fn bench_cpython_code(group: &mut BenchmarkGroup<WallTime>, bench: &MicroBenchma
|
||||
let gil = cpython::Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
|
||||
let bench_func = |(code, globals, locals)| {
|
||||
let res = cpy_run_code(py, &code, &globals, &locals);
|
||||
let setup_code = ffi::CString::new(&*bench.setup).unwrap();
|
||||
let setup_name = ffi::CString::new(format!("{}_setup", bench.name)).unwrap();
|
||||
let setup_code = cpy_compile_code(py, &setup_code, &setup_name).unwrap();
|
||||
|
||||
let code = ffi::CString::new(&*bench.code).unwrap();
|
||||
let name = ffi::CString::new(&*bench.name).unwrap();
|
||||
let code = cpy_compile_code(py, &code, &name).unwrap();
|
||||
|
||||
let bench_func = |(globals, locals): &mut (cpython::PyDict, cpython::PyDict)| {
|
||||
let res = cpy_run_code(py, &code, globals, locals);
|
||||
if let Err(e) = res {
|
||||
e.print(py);
|
||||
panic!("Error running microbenchmark")
|
||||
@@ -30,36 +38,36 @@ fn bench_cpython_code(group: &mut BenchmarkGroup<WallTime>, bench: &MicroBenchma
|
||||
|
||||
let bench_setup = |iterations| {
|
||||
let globals = cpython::PyDict::new(py);
|
||||
// setup the __builtins__ attribute - no other way to do this (other than manually) as far
|
||||
// as I can tell
|
||||
let _ = py.run("", Some(&globals), None);
|
||||
let locals = cpython::PyDict::new(py);
|
||||
if let Some(idx) = iterations {
|
||||
globals.set_item(py, "ITERATIONS", idx).unwrap();
|
||||
}
|
||||
|
||||
let res = py.run(&bench.setup, Some(&globals), Some(&locals));
|
||||
let res = cpy_run_code(py, &setup_code, &globals, &locals);
|
||||
if let Err(e) = res {
|
||||
e.print(py);
|
||||
panic!("Error running microbenchmark setup code")
|
||||
}
|
||||
let code = std::ffi::CString::new(&*bench.code).unwrap();
|
||||
let name = std::ffi::CString::new(&*bench.name).unwrap();
|
||||
let code = cpy_compile_code(py, &code, &name).unwrap();
|
||||
(code, globals, locals)
|
||||
(globals, locals)
|
||||
};
|
||||
|
||||
if bench.iterate {
|
||||
for idx in (100..=1_000).step_by(200) {
|
||||
group.throughput(Throughput::Elements(idx as u64));
|
||||
group.bench_with_input(BenchmarkId::new("cpython", &bench.name), &idx, |b, idx| {
|
||||
b.iter_batched(
|
||||
b.iter_batched_ref(
|
||||
|| bench_setup(Some(*idx)),
|
||||
bench_func,
|
||||
BatchSize::PerIteration,
|
||||
BatchSize::LargeInput,
|
||||
);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
group.bench_function(BenchmarkId::new("cpython", &bench.name), move |b| {
|
||||
b.iter_batched(|| bench_setup(None), bench_func, BatchSize::PerIteration);
|
||||
b.iter_batched_ref(|| bench_setup(None), bench_func, BatchSize::LargeInput);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -73,8 +81,8 @@ unsafe fn cpy_res(
|
||||
|
||||
fn cpy_compile_code(
|
||||
py: cpython::Python<'_>,
|
||||
s: &std::ffi::CStr,
|
||||
fname: &std::ffi::CStr,
|
||||
s: &ffi::CStr,
|
||||
fname: &ffi::CStr,
|
||||
) -> cpython::PyResult<cpython::PyObject> {
|
||||
unsafe {
|
||||
let res =
|
||||
@@ -114,8 +122,8 @@ fn bench_rustpy_code(group: &mut BenchmarkGroup<WallTime>, bench: &MicroBenchmar
|
||||
.compile(&bench.code, Mode::Exec, bench.name.to_owned())
|
||||
.expect("Error compiling bench code");
|
||||
|
||||
let bench_func = |(scope, bench_code)| {
|
||||
let res: PyResult = vm.run_code_obj(bench_code, scope);
|
||||
let bench_func = |scope| {
|
||||
let res: PyResult = vm.run_code_obj(bench_code.clone(), scope);
|
||||
vm.unwrap_pyresult(res);
|
||||
};
|
||||
|
||||
@@ -129,7 +137,7 @@ fn bench_rustpy_code(group: &mut BenchmarkGroup<WallTime>, bench: &MicroBenchmar
|
||||
}
|
||||
let setup_result = vm.run_code_obj(setup_code.clone(), scope.clone());
|
||||
vm.unwrap_pyresult(setup_result);
|
||||
(scope, bench_code.clone())
|
||||
scope
|
||||
};
|
||||
|
||||
if bench.iterate {
|
||||
@@ -142,14 +150,14 @@ fn bench_rustpy_code(group: &mut BenchmarkGroup<WallTime>, bench: &MicroBenchmar
|
||||
b.iter_batched(
|
||||
|| bench_setup(Some(*idx)),
|
||||
bench_func,
|
||||
BatchSize::PerIteration,
|
||||
BatchSize::LargeInput,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
} else {
|
||||
group.bench_function(BenchmarkId::new("rustpython", &bench.name), move |b| {
|
||||
b.iter_batched(|| bench_setup(None), bench_func, BatchSize::PerIteration);
|
||||
b.iter_batched(|| bench_setup(None), bench_func, BatchSize::LargeInput);
|
||||
});
|
||||
}
|
||||
})
|
||||
|
||||
@@ -11,7 +11,7 @@ mod _random {
|
||||
use crate::pyobject::{BorrowValue, PyObjectRef, PyRef, PyResult, PyValue, StaticType};
|
||||
use crate::VirtualMachine;
|
||||
use num_bigint::{BigInt, Sign};
|
||||
use num_traits::Signed;
|
||||
use num_traits::{Signed, Zero};
|
||||
use rand::{rngs::StdRng, RngCore, SeedableRng};
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -106,27 +106,45 @@ mod _random {
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn getrandbits(&self, k: usize) -> BigInt {
|
||||
fn getrandbits(&self, k: usize, vm: &VirtualMachine) -> PyResult<BigInt> {
|
||||
if k == 0 {
|
||||
return Err(
|
||||
vm.new_value_error("number of bits must be greater than zero".to_owned())
|
||||
);
|
||||
}
|
||||
|
||||
let mut rng = self.rng.lock();
|
||||
let mut k = k;
|
||||
let mut gen_u32 = |k| rng.next_u32() >> 32usize.wrapping_sub(k) as u32;
|
||||
let mut gen_u32 = |k| {
|
||||
let r = rng.next_u32();
|
||||
if k < 32 {
|
||||
r >> (32 - k)
|
||||
} else {
|
||||
r
|
||||
}
|
||||
};
|
||||
|
||||
if k <= 32 {
|
||||
return gen_u32(k).into();
|
||||
return Ok(gen_u32(k).into());
|
||||
}
|
||||
|
||||
let words = (k - 1) / 8 + 1;
|
||||
let mut wordarray = vec![0u32; words];
|
||||
let words = (k - 1) / 32 + 1;
|
||||
let wordarray = (0..words)
|
||||
.map(|_| {
|
||||
let word = gen_u32(k);
|
||||
k = k.wrapping_sub(32);
|
||||
word
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let it = wordarray.iter_mut();
|
||||
#[cfg(target_endian = "big")]
|
||||
let it = it.rev();
|
||||
for word in it {
|
||||
*word = gen_u32(k);
|
||||
k -= 32;
|
||||
}
|
||||
|
||||
BigInt::from_slice(Sign::NoSign, &wordarray)
|
||||
let uint = num_bigint::BigUint::new(wordarray);
|
||||
// very unlikely but might as well check
|
||||
let sign = if uint.is_zero() {
|
||||
Sign::NoSign
|
||||
} else {
|
||||
Sign::Plus
|
||||
};
|
||||
Ok(BigInt::from_biguint(sign, uint))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user