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