Skip to content

Commit

Permalink
Merge pull request #107 from sfleischman105/Beta-Branch
Browse files Browse the repository at this point in the history
Prefetching and decrementing of `lazy_static`
  • Loading branch information
sfleischman105 authored Apr 4, 2018
2 parents 63472e7 + 82f041c commit 8cd8116
Show file tree
Hide file tree
Showing 20 changed files with 371 additions and 226 deletions.
6 changes: 2 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,14 @@ The Library aims to have the following features upon completion
- [ ] PGN Parsing

The AI Bot aims to have the following features:
- [x] Alpha-Beta pruning
- [x] Multi-threaded search with rayon.rs
- [x] Multi-threaded search using a shared hash-table
- [x] Queiscience-search
- [x] MVV-LVA sorting
- [x] Iterative Deepening
- [x] Aspiration Windows
- [x] Futility Pruning
- [x] Transposition Tables
- [ ] Null Move Heuristic
- [x] Killer Moves
- [ ] Null Move Heuristic

Standalone Installation and Use
-------
Expand Down
36 changes: 30 additions & 6 deletions pleco/src/board/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use tools::pleco_arc::{Arc,UniqueArc};
use helper::Helper;
use helper::prelude::*;
use tools::prng::PRNG;
use tools::Searcher;
use tools::{Searcher,PreFetchable};
use bot_prelude::AlphaBetaSearcher;

use self::castle_rights::Castling;
Expand Down Expand Up @@ -86,6 +86,14 @@ impl fmt::Debug for FenBuildError {
}
}

struct PreFetchDummy {

}

impl PreFetchable for PreFetchDummy {
fn prefetch(&self, _key: u64) {}
}


/// Represents a Chessboard through a `Board`.
///
Expand Down Expand Up @@ -544,16 +552,23 @@ impl Board {
/// `Board::generate_moves()`, which guarantees that only Legal moves will be created.
pub fn apply_move(&mut self, bit_move: BitMove) {
let gives_check: bool = self.gives_check(bit_move);
self.apply_unknown_move(bit_move, gives_check);
let pt_d = PreFetchDummy {};
let mt_d = PreFetchDummy {};
self.apply_move_pft_chk::<PreFetchDummy,PreFetchDummy>(bit_move, gives_check, &pt_d, &mt_d);
}

/// Applies a move to the Board. This method is only useful if before a move is applied to
/// a board, the ability of the move to give check is applied. If it is not needed to know
/// if the move gives check or not, consider using `Board::apply_move` instead.
///
/// This method also takes in two generic parameters implementing `PreFetchable`, one of which
/// will prefetch from the A table taking in a pawn key, the other of which pre-fetching
/// from a table utilizing the material key.
///
/// # Safety
///
/// The passed in `BitMove` must be a legal move for the current position.
/// The passed in `BitMove` must be a legal move for the current position, and the gives_check
/// parameter must be correct for the move.
///
/// # Panics
///
Expand All @@ -564,7 +579,9 @@ impl Board {
/// The second parameter, `gives_check`, must be true if the move gives check, or false
/// if the move doesn't give check. If an incorrect `gives_check` is supplied, undefined
/// behavior will follow.
pub fn apply_unknown_move(&mut self, bit_move: BitMove, gives_check: bool) {
pub fn apply_move_pft_chk<PT, MT>(&mut self, bit_move: BitMove, gives_check: bool,
pawn_table: &PT, material_table: &MT)
where PT: PreFetchable, MT: PreFetchable {

// Check for stupidity
assert_ne!(bit_move.get_src(), bit_move.get_dest());
Expand All @@ -578,9 +595,9 @@ impl Board {
// New Arc for the board to have by making a partial clone of the current state
let mut next_arc_state = UniqueArc::new(self.state.partial_clone());

// Seperate Block to allow derefencing the BoardState
// As there is garunteed only one owner of the Arc, this is allowed
{
// Seperate Block to allow derefencing the BoardState
// As there is garunteed only one owner of the Arc, this is allowed
let new_state: &mut BoardState = &mut *next_arc_state;

// Set the prev state
Expand Down Expand Up @@ -651,9 +668,13 @@ impl Board {
self.remove_piece_c(captured, cap_sq);
}
zob ^= z_square(cap_sq, captured);

// update material key and prefetch access to a Material Table
let cap_count = self.count_piece(them, captured.type_of());
material_key ^= z_square(SQ(cap_count), captured);
material_table.prefetch(material_key);
new_state.psq -= psq(captured, cap_sq);

// Reset Rule 50
new_state.rule_50 = 0;
new_state.captured_piece = captured.type_of();
Expand Down Expand Up @@ -709,7 +730,10 @@ impl Board {
new_state.psq += psq(us_promo,to) - psq(piece, to);
new_state.nonpawn_material[us as usize] += piece_value(us_promo, false);
}

// update pawn key and prefetch access
pawn_key ^= z_square(from, piece) ^ z_square(to, piece);
pawn_table.prefetch2(pawn_key);
new_state.rule_50 = 0;
}

Expand Down
12 changes: 12 additions & 0 deletions pleco/src/tools/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,15 @@ pub trait Searcher {
where
Self: Sized;
}

/// Allows an object to have it's entries pre-fetchable.
pub trait PreFetchable {
/// Pre-fetches a particular key. This means bringing it into the cache for faster access.
fn prefetch(&self, key: u64);

/// Pre-fetches a particular key, alongside the next key.
fn prefetch2(&self, key: u64) {
self.prefetch(key);
self.prefetch(key + 1);
}
}
16 changes: 9 additions & 7 deletions pleco/src/tools/tt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ use std::cell::UnsafeCell;

use prefetch::prefetch::*;

use super::PreFetchable;
use core::piece_move::BitMove;

// TODO: investigate potention for SIMD in key lookup
Expand Down Expand Up @@ -447,22 +448,23 @@ impl TranspositionTable {
(hits * 100.0) / (clusters_scanned * CLUSTER_SIZE as u64) as f64
}
}
}

unsafe impl Sync for TranspositionTable {}

impl PreFetchable for TranspositionTable {
/// Pre-fetches a particular key. This means bringing it into the cache for faster eventual
/// access.
#[inline(always)]
pub fn prefetch(&self, key: u64) {
fn prefetch(&self, key: u64) {
let index: usize = ((self.num_clusters() - 1) as u64 & key) as usize;
unsafe {
let ptr = (*self.clusters.get()).as_ptr().offset(index as isize);
prefetch::<Write, High, Data, Cluster>(ptr);
unsafe {
let ptr = (*self.clusters.get()).as_ptr().offset(index as isize);
prefetch::<Write, High, Data, Cluster>(ptr);
};
}
}

unsafe impl Sync for TranspositionTable {}


impl Drop for TranspositionTable {
fn drop(&mut self) {
unsafe {self.de_alloc();}
Expand Down
10 changes: 3 additions & 7 deletions pleco_engine/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -71,15 +71,10 @@ pleco = { path = "../pleco", version = "0.4.0" }
clippy = {version = "0.0.191", optional = true}
chrono = "0.4.1"
rand = "0.4.2"
rayon = "1.0.1"
num_cpus = "1.8.0"
prefetch = "0.2.0"
crossbeam-utils = "0.3.2"

[dependencies.lazy_static]
version = "1.0.0"
features = ["nightly"]


[features]
default = []
dev = ["clippy"]
Expand All @@ -91,7 +86,8 @@ test = false
doc = false

[dev-dependencies]
criterion = { version = '0.2.2', default-features = false, features=['real_blackbox'] }
criterion = { version = '0.2.2', default-features = false, features=['real_blackbox'] }
lazy_static = {version = "1.0.0", features = ["nightly"]}

[[bench]]
name = "bench_engine_main"
Expand Down
17 changes: 10 additions & 7 deletions pleco_engine/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,23 +22,26 @@ Planned & Implemented features


The AI aims to have the following features:
- [x] Alpha-Beta pruning
- [x] Multi-threaded search with rayon.rs
- [ ] Queiscience-search
- [x] MVV-LVA sorting
- [x] Multi-threaded search using a shared hash-table
- [x] Queiscience-search
- [x] Iterative Deepening
- [x] Aspiration Windows
- [x] Futility Pruning
- [x] Transposition Tables
- [ ] Null Move Heuristic
- [x] Killer Moves
- [ ] Null Move Heuristic

Standalone Installation and Use
-------

Currently, Pleco's use as a standalone program is limited in functionality. A UCI client is needed to properly interact with the program. As a recommendation, check out [Arena](http://www.playwitharena.com/).
Currently, Pleco's use as a standalone program is limited in functionality. A UCI client is needed to properly interact with the program.
As a recommendation, check out [Arena](http://www.playwitharena.com/).

The easiest way to use the engine would be to check out the "releases" tab,
[here](https://github.com/sfleischman105/Pleco/releases).

Firstly, clone the repo and navigate into the created folder with the following commands:
If you would rather build it yourself (for a specific architecture, or otherwise), clone the repo
and navigate into the created folder with the following commands:

```
$ git clone https://github.com/sfleischman105/Pleco --branch master
Expand Down
12 changes: 8 additions & 4 deletions pleco_engine/benches/bench_engine_main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,21 @@ trait DepthLimit {
fn depth() -> u16;
}

struct Depth3 {}
struct Depth4 {}


struct Depth5 {}
struct Depth6 {}
struct Depth7 {}
struct Depth8 {}
struct Depth9 {}



impl DepthLimit for Depth3 { fn depth() -> u16 {3} }
impl DepthLimit for Depth4 { fn depth() -> u16 {4} }
impl DepthLimit for Depth5 { fn depth() -> u16 {5} }
impl DepthLimit for Depth6 { fn depth() -> u16 {6} }
impl DepthLimit for Depth7 { fn depth() -> u16 {7} }
impl DepthLimit for Depth8 { fn depth() -> u16 {8} }
impl DepthLimit for Depth9 { fn depth() -> u16 {9} }

criterion_main!{
eval_benches::eval_benches,
Expand Down
10 changes: 5 additions & 5 deletions pleco_engine/benches/eval_benches.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use pleco_engine::search::eval::Evaluation;
fn bench_100_pawn_evals(b: &mut Bencher, boards: &Vec<Board>) {

b.iter_with_setup(|| {
PawnTable::new(1 << 10)
PawnTable::new()
}, |mut t| {
#[allow(unused_variables)]
let mut score: i64 = 0;
Expand All @@ -27,7 +27,7 @@ fn bench_100_pawn_evals(b: &mut Bencher, boards: &Vec<Board>) {

fn bench_100_pawn_king_evals(b: &mut Bencher, boards: &Vec<Board>) {
b.iter_with_setup(|| {
PawnTable::new(1 << 10)
PawnTable::new()
}, |mut t| {
#[allow(unused_variables)]
let mut score: i64 = 0;
Expand All @@ -42,7 +42,7 @@ fn bench_100_pawn_king_evals(b: &mut Bencher, boards: &Vec<Board>) {

fn bench_100_material_eval(b: &mut Bencher, boards: &Vec<Board>) {
b.iter_with_setup(|| {
Material::new(1 << 11)
Material::new()
}, |mut t| {
#[allow(unused_variables)]
let mut score: i64 = 0;
Expand All @@ -56,8 +56,8 @@ fn bench_100_material_eval(b: &mut Bencher, boards: &Vec<Board>) {

fn bench_100_eval(b: &mut Bencher, boards: &Vec<Board>) {
b.iter_with_setup(|| {
let tp: PawnTable = black_box(PawnTable::new(1 << 10));
let tm: Material = black_box(Material::new(1 << 11));
let tp: PawnTable = black_box(PawnTable::new());
let tm: Material = black_box(Material::new());
(tp, tm)
}, |(mut tp, mut tm)| {
#[allow(unused_variables)]
Expand Down
17 changes: 8 additions & 9 deletions pleco_engine/benches/multimove_benches.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ use pleco::{Board};

use pleco_engine::engine::PlecoSearcher;
use pleco_engine::time::uci_timer::PreLimits;
use pleco_engine::consts::*;
use pleco_engine::threadpool::*;

use super::*;
Expand All @@ -15,12 +14,12 @@ const KIWIPETE: &str = "r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R
fn search_kiwipete_3moves_engine<D: DepthLimit>(b: &mut Bencher) {
let mut pre_limit = PreLimits::blank();
pre_limit.depth = Some(D::depth());
let _searcher = PlecoSearcher::init(false);
let mut searcher = PlecoSearcher::init(false);
let limit = pre_limit.create();
let board_kwi: Board = Board::from_fen(KIWIPETE).unwrap();
b.iter_with_setup(|| {
threadpool().clear_all();
unsafe {TT_TABLE.clear() };
searcher.clear_tt();
board_kwi.shallow_clone()
}, |mut board| {
let mov = black_box(threadpool().search(&board, &limit));
Expand All @@ -34,11 +33,11 @@ fn search_kiwipete_3moves_engine<D: DepthLimit>(b: &mut Bencher) {
fn search_startpos_3moves_engine<D: DepthLimit>(b: &mut Bencher) {
let mut pre_limit = PreLimits::blank();
pre_limit.depth = Some(D::depth());
let _searcher = PlecoSearcher::init(false);
let mut searcher = PlecoSearcher::init(false);
let limit = pre_limit.create();
b.iter_with_setup(|| {
threadpool().clear_all();
unsafe {TT_TABLE.clear() };
searcher.clear_tt();
Board::start_pos()
}, |mut board| {
let mov = black_box(threadpool().search(&board, &limit));
Expand All @@ -50,20 +49,20 @@ fn search_startpos_3moves_engine<D: DepthLimit>(b: &mut Bencher) {
}

fn bench_engine_evaluations(c: &mut Criterion) {
c.bench_function("Search MuliMove Depth 4", search_startpos_3moves_engine::<Depth4>);
c.bench_function("Search MuliMove Depth 5", search_startpos_3moves_engine::<Depth5>);
c.bench_function("Search MuliMove Depth 6", search_startpos_3moves_engine::<Depth6>);
c.bench_function("Search MuliMove Depth 7", search_startpos_3moves_engine::<Depth7>);
c.bench_function("Search KiwiPete MuliMove Depth 4", search_kiwipete_3moves_engine::<Depth4>);
c.bench_function("Search MuliMove Depth 8", search_startpos_3moves_engine::<Depth8>);
c.bench_function("Search KiwiPete MuliMove Depth 5", search_kiwipete_3moves_engine::<Depth5>);
c.bench_function("Search KiwiPete MuliMove Depth 6", search_kiwipete_3moves_engine::<Depth6>);
c.bench_function("Search KiwiPete MuliMove Depth 7", search_kiwipete_3moves_engine::<Depth7>);
c.bench_function("Search KiwiPete MuliMove Depth 8", search_kiwipete_3moves_engine::<Depth8>);
}

criterion_group!(name = search_multimove;
config = Criterion::default()
.sample_size(18)
.warm_up_time(Duration::from_millis(200));
.sample_size(26)
.warm_up_time(Duration::from_millis(100));
targets = bench_engine_evaluations
);

Loading

0 comments on commit 8cd8116

Please sign in to comment.