improve benchmarks and marginal perf improvements

This commit is contained in:
2025-02-18 16:27:04 -05:00
parent 1972707f88
commit 0fea3da31c
3 changed files with 32 additions and 24 deletions

View File

@@ -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,9 +15,16 @@ 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);

View File

@@ -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 {

View File

@@ -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))