Skip to content

Commit

Permalink
Optimize table
Browse files Browse the repository at this point in the history
  • Loading branch information
primenumber committed Nov 11, 2023
1 parent 218abf2 commit ebde7c1
Show file tree
Hide file tree
Showing 11 changed files with 72 additions and 62 deletions.
35 changes: 27 additions & 8 deletions src/book.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use crate::engine::board::*;
use crate::engine::eval::*;
use crate::engine::hand::*;
use crate::engine::search::*;
use crate::engine::table::*;
use crate::engine::think::*;
use crate::record::*;
use crate::setup::*;
Expand Down Expand Up @@ -169,14 +170,17 @@ impl Book {
}
}

fn search(board: Board, think_time_limit: u128, solve_obj: &SolveObj, rt: &Runtime, sub_solver: &Arc<SubSolver>) -> Hand {
solve_obj.eval_cache.inc_gen();
fn search(
board: Board,
think_time_limit: u128,
solve_obj: &mut SolveObj,
rt: &Runtime,
sub_solver: &Arc<SubSolver>,
) -> Hand {
solve_obj.cache_gen += 1;
if board.empty().count_ones() <= 18 {
solve_obj.res_cache.inc_gen();
let mut solve_obj = solve_obj.clone();
rt.block_on(async move {
solve_with_move(board, &mut solve_obj, &sub_solver.clone()).await
})
rt.block_on(async move { solve_with_move(board, &mut solve_obj, &sub_solver.clone()).await })
} else {
let start = Instant::now();
let timer = Timer {
Expand All @@ -188,6 +192,7 @@ fn search(board: Board, think_time_limit: u128, solve_obj: &SolveObj, rt: &Runti
cache: solve_obj.eval_cache.clone(),
timer: Some(timer),
node_count: 0,
cache_gen: solve_obj.cache_gen,
};
let (_score, hand, _depth) = searcher.iterative_think(board, EVAL_SCORE_MIN, EVAL_SCORE_MAX, false);
hand
Expand All @@ -210,7 +215,7 @@ fn gen_opening(rng: &mut SmallRng) -> (Board, Vec<Hand>) {
fn play_with_book(
book: Arc<Mutex<Book>>,
think_time_limit: u128,
solve_obj: &SolveObj,
solve_obj: &mut SolveObj,
rt: &Runtime,
rng: &mut SmallRng,
sub_solver: &Arc<SubSolver>,
Expand Down Expand Up @@ -249,7 +254,21 @@ fn grow_book(in_book_path: &Path, out_book_path: &Path, repeat: usize) -> Result
let mut rng = SmallRng::seed_from_u64(0xbeefbeef + i as u64);
let think_time_limit = 1 << rng.gen_range(7..=9);
eprintln!("i={}, tl={}", i, think_time_limit);
play_with_book(book.clone(), think_time_limit, &solve_obj, &rt, &mut rng, &sub_solver.clone());
let mut solve_obj = SolveObj::new(
Arc::new(ResCacheTable::new(256, 4096)),
Arc::new(EvalCacheTable::new(256, 4096)),
solve_obj.evaluator.clone(),
solve_obj.params.clone(),
0,
);
play_with_book(
book.clone(),
think_time_limit,
&mut solve_obj,
&rt,
&mut rng,
&sub_solver.clone(),
);
});
book.lock().unwrap().export(out_book_path)?;
Ok(())
Expand Down
2 changes: 2 additions & 0 deletions src/engine/endgame.rs
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ pub fn solve_inner(
let (res, stat) = fastest_first(solve_obj, board, (alpha, beta), passed);
update_table(
solve_obj.res_cache.clone(),
solve_obj.cache_gen,
board,
res,
None,
Expand All @@ -217,6 +218,7 @@ pub fn solve_inner(
if rem >= solve_obj.params.res_cache_limit {
update_table(
solve_obj.res_cache.clone(),
solve_obj.cache_gen,
board,
res,
best,
Expand Down
1 change: 1 addition & 0 deletions src/engine/midgame.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ where
if rem >= solve_obj.params.res_cache_limit {
update_table(
solve_obj.res_cache.clone(),
solve_obj.cache_gen,
board,
res,
best,
Expand Down
4 changes: 4 additions & 0 deletions src/engine/search.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ pub struct SolveObj {
pub evaluator: Arc<Evaluator>,
pub last_cache: Arc<LastCache>,
pub params: SearchParams,
pub cache_gen: u8,
}

impl SolveObj {
Expand All @@ -63,13 +64,15 @@ impl SolveObj {
eval_cache: Arc<EvalCacheTable>,
evaluator: Arc<Evaluator>,
params: SearchParams,
cache_gen: u8,
) -> SolveObj {
SolveObj {
res_cache,
eval_cache,
evaluator,
last_cache: Arc::new(LastCache::new()),
params,
cache_gen,
}
}
}
Expand Down Expand Up @@ -237,6 +240,7 @@ pub fn move_ordering_impl(solve_obj: &mut SolveObj, board: Board, _old_best: Opt
cache: solve_obj.eval_cache.clone(),
timer: None,
node_count: 0,
cache_gen: solve_obj.cache_gen,
};
let score = searcher
.think(
Expand Down
49 changes: 17 additions & 32 deletions src/engine/table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,20 @@ use crate::engine::hand::*;
use crc64::Crc64;
use spin::Mutex;
use std::io::Write;
use std::sync::atomic::{AtomicU16, Ordering};
use std::sync::Arc;

pub trait CacheElement: Clone + Default {
fn has_key(&self, board: Board) -> bool;
fn get_key(&self) -> Board;
fn update(&mut self, that: &Self, gen: u16);
fn update(&mut self, that: &Self);
}

#[derive(Clone)]
pub struct EvalCache {
pub board: Board,
pub lower: i16,
pub upper: i16,
pub gen: u16,
pub gen: u8,
pub best: Option<Hand>,
pub depth: i32,
}
Expand Down Expand Up @@ -48,7 +47,7 @@ impl CacheElement for EvalCache {
self.board
}

fn update(&mut self, that: &Self, gen: u16) {
fn update(&mut self, that: &Self) {
if that.board == self.board {
if that.depth >= self.depth {
if that.depth == self.depth {
Expand All @@ -60,14 +59,14 @@ impl CacheElement for EvalCache {
} else {
*self = that.clone();
}
self.gen = gen;
self.gen = that.gen;
}
} else {
let empty_self = popcnt(self.board.empty());
let empty_that = popcnt(that.board.empty());
if empty_that >= empty_self || gen > self.gen {
if empty_that >= empty_self || that.gen > self.gen {
*self = that.clone();
self.gen = gen;
self.gen = that.gen;
}
}
}
Expand All @@ -78,7 +77,7 @@ pub struct ResCache {
pub board: Board,
pub lower: i8,
pub upper: i8,
pub gen: u16,
pub gen: u8,
pub best: Option<Hand>,
}

Expand Down Expand Up @@ -106,20 +105,20 @@ impl CacheElement for ResCache {
self.board
}

fn update(&mut self, that: &Self, gen: u16) {
fn update(&mut self, that: &Self) {
if that.board == self.board {
let lower = self.lower.max(that.lower);
let upper = self.upper.min(that.upper);
*self = that.clone();
self.lower = lower;
self.upper = upper;
self.gen = gen;
self.gen = that.gen;
} else {
let empty_self = popcnt(self.board.empty());
let empty_that = popcnt(that.board.empty());
if empty_that >= empty_self || gen > self.gen {
if empty_that >= empty_self || that.gen > self.gen {
*self = that.clone();
self.gen = gen;
self.gen = that.gen;
}
}
}
Expand Down Expand Up @@ -149,17 +148,16 @@ impl<T: CacheElement> CacheArray<T> {
}
}

fn update(&mut self, new_elem: &T, hash: u64, gen: u16) {
fn update(&mut self, new_elem: &T, hash: u64) {
let index = (hash % self.cycle) as usize;
let elem = &mut self.ary[index];
elem.update(new_elem, gen);
elem.update(new_elem);
}
}

pub struct CacheTable<T: CacheElement> {
arrays: Vec<Mutex<CacheArray<T>>>,
buckets: u64,
pub gen: AtomicU16,
}

impl<T: CacheElement> CacheTable<T> {
Expand All @@ -171,7 +169,6 @@ impl<T: CacheElement> CacheTable<T> {
CacheTable::<T> {
arrays: vec,
buckets: buckets as u64,
gen: 1.into(),
}
}

Expand All @@ -193,21 +190,15 @@ impl<T: CacheElement> CacheTable<T> {
let hash = crc64.get();
let bucket_id = (hash % self.buckets) as usize;
let bucket_hash = hash / self.buckets;
self.arrays[bucket_id]
.lock()
.update(&cache, bucket_hash, self.gen.load(Ordering::SeqCst));
}

pub fn inc_gen(&self) {
self.gen.fetch_add(1, Ordering::SeqCst);
self.arrays[bucket_id].lock().update(&cache, bucket_hash);
}
}

pub type EvalCacheTable = CacheTable<EvalCache>;
pub type ResCacheTable = CacheTable<ResCache>;

fn make_record(
gen: u16,
gen: u8,
board: Board,
mut res: i8,
best: Option<Hand>,
Expand All @@ -233,19 +224,13 @@ fn make_record(

pub fn update_table(
res_cache: Arc<ResCacheTable>,
cache_gen: u8,
board: Board,
res: i8,
best: Option<Hand>,
(alpha, beta): (i8, i8),
range: (i8, i8),
) {
let record = make_record(
res_cache.gen.load(Ordering::SeqCst),
board,
res,
best,
(alpha, beta),
range,
);
let record = make_record(cache_gen, board, res, best, (alpha, beta), range);
res_cache.update(record);
}
7 changes: 4 additions & 3 deletions src/engine/think.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ pub struct Searcher {
pub cache: Arc<EvalCacheTable>,
pub timer: Option<Timer>,
pub node_count: usize,
pub cache_gen: u8,
}

pub const DEPTH_SCALE: i32 = 256;
Expand Down Expand Up @@ -233,7 +234,7 @@ impl Searcher {
board,
lower: range.0,
upper: range.1,
gen: self.cache.gen.load(std::sync::atomic::Ordering::SeqCst),
gen: self.cache_gen,
best: Some(best),
depth,
};
Expand Down Expand Up @@ -280,6 +281,7 @@ impl Searcher {

pub fn iterative_think(&mut self, board: Board, alpha: i16, beta: i16, passed: bool) -> (i16, Hand, i8) {
let min_depth = 3;
let max_depth = 60;
let mut current_depth = min_depth;

let (mut score, mut hand) = self
Expand All @@ -290,8 +292,7 @@ impl Searcher {
return (score, hand, current_depth as i8);
}

for depth in (min_depth + 1).. {
self.cache.inc_gen();
for depth in (min_depth + 1)..=max_depth {
let t = match self.think_with_move(board, alpha, beta, passed, depth * DEPTH_SCALE) {
Some(t) => t,
_ => return (score, hand, current_depth as i8),
Expand Down
3 changes: 1 addition & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,7 @@ fn solve_ffo(name: &str, index: &mut usize, solve_obj: &mut SolveObj, workers: &
end.subsec_millis(),
nodes_per_sec / 1_000_000
);
solve_obj.eval_cache.inc_gen();
solve_obj.res_cache.inc_gen();
solve_obj.cache_gen += 1;
stats.push(Stat {
nodes: stat.node_count,
elapsed: end.as_secs_f64(),
Expand Down
Loading

0 comments on commit ebde7c1

Please sign in to comment.