improve benchmarks and marginal perf improvements
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
use criterion::{criterion_group, criterion_main, Criterion};
|
||||
use std::hint::black_box;
|
||||
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion, Throughput};
|
||||
use std::time::Duration;
|
||||
|
||||
// use crate::future_move::FutureMove;
|
||||
use othello::{board::Board, future_moves::FutureMoves, piece::Piece};
|
||||
@@ -15,10 +15,17 @@ fn future_move_bench(depth: usize, expire: usize) {
|
||||
}
|
||||
|
||||
fn criterion_benchmark(c: &mut Criterion) {
|
||||
c.bench_function("depth 6 expire 4", |b| {
|
||||
b.iter(|| future_move_bench(black_box(6), black_box(4)))
|
||||
let mut group = c.benchmark_group("future_move (expire 4)");
|
||||
group.measurement_time(Duration::from_secs(60));
|
||||
|
||||
for (depth, expire) in [(2, 4), (3, 4), (4, 4), (5, 4), (6, 4)].iter() {
|
||||
group.throughput(Throughput::Elements(*depth as u64));
|
||||
group.bench_with_input(BenchmarkId::from_parameter(depth), depth, |b, depth| {
|
||||
b.iter(|| future_move_bench(*depth, *expire));
|
||||
});
|
||||
}
|
||||
group.finish();
|
||||
}
|
||||
|
||||
criterion_group!(benches, criterion_benchmark);
|
||||
criterion_main!(benches);
|
||||
|
||||
11
src/board.rs
11
src/board.rs
@@ -166,7 +166,7 @@ impl Board {
|
||||
}
|
||||
|
||||
/// Get a reference to a backing [`BitBoard`]
|
||||
pub fn board(&self, color: Piece) -> &BitBoard {
|
||||
pub const fn board(&self, color: Piece) -> &BitBoard {
|
||||
match color {
|
||||
Piece::Black => &self.black_board,
|
||||
Piece::White => &self.white_board,
|
||||
@@ -174,7 +174,7 @@ impl Board {
|
||||
}
|
||||
|
||||
/// Get a mutable reference to a backing [`BitBoard`]
|
||||
pub fn board_mut(&mut self, color: Piece) -> &mut BitBoard {
|
||||
pub const fn board_mut(&mut self, color: Piece) -> &mut BitBoard {
|
||||
match color {
|
||||
Piece::Black => &mut self.black_board,
|
||||
Piece::White => &mut self.white_board,
|
||||
@@ -225,12 +225,13 @@ impl Board {
|
||||
}
|
||||
|
||||
pub fn place(&mut self, i: usize, j: usize, piece: Piece) -> Result<(), &'static str> {
|
||||
if let Some(what_if_result) = self.what_if(i, j, piece) {
|
||||
let what_if_result = self
|
||||
.what_if(i, j, piece)
|
||||
.ok_or("move would not propegate")?;
|
||||
|
||||
*self = what_if_result;
|
||||
return Ok(());
|
||||
}
|
||||
Err("move would not propegate")
|
||||
}
|
||||
|
||||
/// Propegate the board and captures starting from a specific position
|
||||
fn propegate_from(&mut self, i: usize, j: usize) -> usize {
|
||||
|
||||
@@ -152,23 +152,24 @@ impl FutureMoves {
|
||||
parent_idx: usize,
|
||||
lazy_children: bool,
|
||||
) -> Option<impl Iterator<Item = usize>> {
|
||||
let parent = &self.arena[parent_idx];
|
||||
|
||||
// early-exit if a winner for the parent already exists
|
||||
if self.arena[parent_idx].winner != Winner::None {
|
||||
if parent.winner != Winner::None {
|
||||
return None;
|
||||
}
|
||||
|
||||
let new_color = !self.arena[parent_idx].color;
|
||||
let parent_lazy = self.arena[parent_idx].lazy_children;
|
||||
let new_color = !parent.color;
|
||||
let mut new: Vec<Move> =
|
||||
// use [`Board::all_positions`] here instead of [`Board::possible_moves`]
|
||||
// because we use [`Board::what_if`] later and we want to reduce calls to [`Board::propegate_from_dry`]
|
||||
Board::all_positions()
|
||||
.flat_map(|(i, j)| self.arena[parent_idx].board.what_if(i, j, new_color).map(|x| (i, j, x)))
|
||||
.flat_map(|(i, j)| parent.board.what_if(i, j, new_color).map(move |x| (i, j, x)))
|
||||
.map(|(i, j, new_board)| Move {
|
||||
i,
|
||||
j,
|
||||
board: new_board,
|
||||
winner: new_board.game_winner(!self.arena[parent_idx].color),
|
||||
winner: new_board.game_winner(new_color),
|
||||
parent: Some(parent_idx),
|
||||
children: Vec::new(),
|
||||
value: 0,
|
||||
@@ -188,7 +189,7 @@ impl FutureMoves {
|
||||
}
|
||||
|
||||
let start_idx = self.arena.len();
|
||||
if parent_lazy && !lazy_children {
|
||||
if parent.lazy_children && !lazy_children {
|
||||
self.arena[parent_idx].lazy_children = false;
|
||||
// this move's children are being regenerated after lazy child expiration, don't append first node
|
||||
if new.len() > 1 {
|
||||
@@ -234,15 +235,15 @@ impl FutureMoves {
|
||||
|
||||
for (depth, nodes) in by_depth.into_iter().enumerate().rev() {
|
||||
for idx in nodes {
|
||||
let self_value =
|
||||
self.arena[idx].compute_self_value(self.agent_color) / (depth + 1) as i64;
|
||||
let node = &self.arena[idx];
|
||||
let self_value = node.compute_self_value(self.agent_color) / (depth + 1) as i64;
|
||||
|
||||
let children_value = self.arena[idx]
|
||||
let children_value = node
|
||||
.children
|
||||
.iter()
|
||||
.map(|&child| self.arena[child].value)
|
||||
.sum::<i64>()
|
||||
.checked_div(self.arena[idx].children.len() as i64)
|
||||
.checked_div(node.children.len() as i64)
|
||||
.unwrap_or(0);
|
||||
|
||||
self.arena[idx].value = self_value + children_value;
|
||||
@@ -309,8 +310,7 @@ impl FutureMoves {
|
||||
.find(|(_, node)| {
|
||||
node.parent == self.current_root
|
||||
&& self.current_root.is_some()
|
||||
&& node.i == i
|
||||
&& node.j == j
|
||||
&& node.coords() == (i, j)
|
||||
})
|
||||
.map(|x| x.0)
|
||||
.inspect(|&root| self.update_root_idx(root))
|
||||
|
||||
Reference in New Issue
Block a user