Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Reducing memory usage (substantial perf increase)
Instead of passing a variation down through the negamax recursion tree,
we instead build it up on the way back out. This allows us to preserve
both overall memory and allocations, since we were cloning the variation
many times.

In order to accommodate this, we also now store merely the
"remaining" portion of a variation in our memory bank; now instead of a
map from (WorldState -> (full variation, depth-of-finding, score)), we instead
maintain a map of ((WorldState, depth-of-finding) -> (remaining variation, score)).

So in addition to saving various allocations & memory on the stack,
we're saving memory in our cache! which hopefully means we get more
cache hits since we have to evict less often.

Running time for `./leafline --correspond --depth 5 --from 'rnbqkbnr/pp1p1ppp/2p5/4P3/2P5/8/PP2PPPP/RNBQKBNR b KQkq - 0 3'`
has decreased from approximately 19s to approximately 13s, which is sort
of unbelievable. the regular benchmarks show a more modest but also
consistent improvement in the 5-10% range.

Running the same with depth 6 shows the astonishing time drop of 282s ->
156s. PLEASE double check these results; I find them hard to believe.
  • Loading branch information
Alexander Corwin authored and Alexander Corwin committed Apr 18, 2019
1 parent c863da0 commit 8cbc985
Showing 1 changed file with 32 additions and 35 deletions.
67 changes: 32 additions & 35 deletions src/mind.rs
Expand Up @@ -204,48 +204,47 @@ impl fmt::Debug for Lodestar {
}
}


#[derive(Clone)]
pub struct Souvenir {
soundness: u8,
lodestar: Lodestar,
#[derive(Eq,PartialEq,Hash)]
pub struct SpaceTime {
world_state: WorldState,
instant: i8,
}

impl Souvenir {
fn new(lodestar: Lodestar, field_depth: u8) -> Self {
let soundness = lodestar.variation.len() as u8 - field_depth;
Self { soundness, lodestar }

impl SpaceTime {
fn new(world_state: WorldState, instant: i8) -> Self {
Self { world_state, instant }
}
}


#[allow(too_many_arguments)]
pub fn α_β_negamax_search(
world: WorldState, depth: i8, mut α: f32, β: f32, variation: Variation,
memory_bank: Arc<parking_lot::Mutex<LruCache<WorldState, Souvenir,
world: WorldState, depth: i8, mut α: f32, β: f32,
memory_bank: Arc<parking_lot::Mutex<LruCache<SpaceTime, Lodestar,
BuildHasherDefault<XxHash>>>>,
intuition_bank: Arc<parking_lot::Mutex<HashMap<Patch, u32>>>,
quiet: Option<u8>)
-> Lodestar {

let mut premonitions = world.reckless_lookahead();
let mut optimum = NEG_INFINITY;
let mut optimand = variation.clone();
let mut optimand = vec![];
if depth <= 0 || premonitions.is_empty() {
let potential_score = orientation(world.initiative) * score(world);
match quiet {
None => {
return Lodestar::new(potential_score, variation);
return Lodestar::new(potential_score, vec![]);
},
Some(extension) => {
if depth.abs() >= extension as i8 {
return Lodestar::new(potential_score, variation);
return Lodestar::new(potential_score, vec![]);
}
premonitions = premonitions.into_iter()
.filter(|c| c.hospitalization.is_some())
.collect::<Vec<_>>();
if premonitions.is_empty() {
return Lodestar::new(potential_score, variation)
return Lodestar::new(potential_score, vec![])
} else {
optimum = potential_score;
}
Expand All @@ -260,21 +259,17 @@ pub fn α_β_negamax_search(
}
for premonition in premonitions {
let mut value = NEG_INFINITY; // can't hurt to be pessimistic
let mut extended_variation = variation.clone();
extended_variation.push(premonition.patch);
let mut variation: Variation = vec![premonition.patch];
let cached: bool;
let space_time = SpaceTime::new(premonition.tree, depth);
{
let mut open_vault = memory_bank.lock();
let souvenir_maybe = open_vault.get_mut(&premonition.tree);
match souvenir_maybe {
Some(souvenir) => {
if souvenir.soundness as i8 >= depth {
cached = true;
value = souvenir.lodestar.score;
extended_variation = souvenir.lodestar.variation.clone();
} else {
cached = false;
}
let remembered_lodestar_maybe = open_vault.get_mut(&space_time);
match remembered_lodestar_maybe {
Some(remembered_lodestar) => {
cached = true;
value = remembered_lodestar.score;
variation.extend(remembered_lodestar.variation.clone());
}
None => { cached = false; }
};
Expand All @@ -283,22 +278,22 @@ pub fn α_β_negamax_search(
if !cached {
let mut lodestar = α_β_negamax_search(
premonition.tree, depth - 1,
,, extended_variation.clone(),
,,
memory_bank.clone(), intuition_bank.clone(),
quiet
);
lodestar.score *= -1.; // nega-
value = lodestar.score;
extended_variation = lodestar.variation.clone();
variation.extend(lodestar.variation.clone());
memory_bank.lock().insert(
premonition.tree,
Souvenir::new(lodestar, extended_variation.len() as u8)
space_time,
lodestar,
);
}

if value > optimum {
optimum = value;
optimand = extended_variation;
optimand = variation;
}
if value > α {
α = value;
Expand Down Expand Up @@ -331,7 +326,7 @@ pub fn potentially_timebound_kickoff(
intuition_bank: Arc<parking_lot::Mutex<HashMap<Patch, u32>>>,
déjà_vu_bound: f32)
-> Option<Vec<(Commit, f32, Variation)>> {
let déjà_vu_table: LruCache<WorldState, Souvenir,
let déjà_vu_table: LruCache<SpaceTime, Lodestar,
BuildHasherDefault<XxHash>> =
LruCache::with_hash_state(déjà_vu_table_size_bound(déjà_vu_bound),
Default::default());
Expand All @@ -357,7 +352,7 @@ pub fn potentially_timebound_kickoff(
thread::spawn(move || {
let search_hit: Lodestar = α_β_negamax_search(
premonition.tree, (depth - 1) as i8,
NEG_INFINITY, INFINITY, vec![premonition.patch],
NEG_INFINITY, INFINITY,
travel_memory_bank, travel_intuition_bank,
extension_maybe
);
Expand All @@ -375,7 +370,9 @@ pub fn potentially_timebound_kickoff(
let premonition = time_radios[i].0;
if let Ok(search_hit) = time_radios[i].1.try_recv() {
let value = -search_hit.score;
forecasts.push((premonition, value, search_hit.variation));
let mut full_variation = vec![premonition.patch];
full_variation.extend(search_hit.variation);
forecasts.push((premonition, value, full_variation));
time_radios.swap_remove(i);
}
}
Expand Down

0 comments on commit 8cbc985

Please sign in to comment.