1
0
Fork 0
mirror of https://github.com/sockspls/badfish synced 2025-04-29 08:13:08 +00:00

Prefetch pawn hash key

Plus a bunch of other minor optimizations.

With this power pack we have an increase
of a whopping 1.4%  :-)

...and it took 3 good hours of profiling + hacking to get it out !

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
This commit is contained in:
Marco Costalba 2010-08-21 19:57:52 +02:00
parent b6ba5f7fe4
commit 7b721b3663
7 changed files with 75 additions and 85 deletions

View file

@ -229,10 +229,6 @@ namespace {
MaterialInfoTable* MaterialTable[MAX_THREADS]; MaterialInfoTable* MaterialTable[MAX_THREADS];
PawnInfoTable* PawnTable[MAX_THREADS]; PawnInfoTable* PawnTable[MAX_THREADS];
// Sizes of pawn and material hash tables
const int PawnTableSize = 16384;
const int MaterialTableSize = 1024;
// Function prototypes // Function prototypes
template<bool HasPopCnt> template<bool HasPopCnt>
Value do_evaluate(const Position& pos, EvalInfo& ei); Value do_evaluate(const Position& pos, EvalInfo& ei);
@ -268,6 +264,14 @@ namespace {
//// Functions //// Functions
//// ////
/// Prefetches in pawn hash tables
void prefetchPawn(Key key, int threadID) {
PawnTable[threadID]->prefetch(key);
}
/// evaluate() is the main evaluation function. It always computes two /// evaluate() is the main evaluation function. It always computes two
/// values, an endgame score and a middle game score, and interpolates /// values, an endgame score and a middle game score, and interpolates
/// between them based on the remaining material. /// between them based on the remaining material.
@ -412,9 +416,9 @@ void init_eval(int threads) {
continue; continue;
} }
if (!PawnTable[i]) if (!PawnTable[i])
PawnTable[i] = new PawnInfoTable(PawnTableSize); PawnTable[i] = new PawnInfoTable();
if (!MaterialTable[i]) if (!MaterialTable[i])
MaterialTable[i] = new MaterialInfoTable(MaterialTableSize); MaterialTable[i] = new MaterialInfoTable();
} }
} }
@ -682,15 +686,11 @@ namespace {
Bitboard undefended, b, b1, b2, safe; Bitboard undefended, b, b1, b2, safe;
bool sente; bool sente;
int attackUnits, shelter = 0; int attackUnits;
const Square ksq = pos.king_square(Us); const Square ksq = pos.king_square(Us);
// King shelter // King shelter
if (relative_rank(Us, ksq) <= RANK_4) ei.value += Sign[Us] * ei.pi->king_shelter(pos, Us, ksq);
{
shelter = ei.pi->get_king_shelter(pos, Us, ksq);
ei.value += Sign[Us] * make_score(shelter, 0);
}
// King safety. This is quite complicated, and is almost certainly far // King safety. This is quite complicated, and is almost certainly far
// from optimally tuned. // from optimally tuned.
@ -717,7 +717,7 @@ namespace {
attackUnits = Min(25, (ei.kingAttackersCount[Them] * ei.kingAttackersWeight[Them]) / 2) attackUnits = Min(25, (ei.kingAttackersCount[Them] * ei.kingAttackersWeight[Them]) / 2)
+ 3 * (ei.kingAdjacentZoneAttacksCount[Them] + count_1s_max_15<HasPopCnt>(undefended)) + 3 * (ei.kingAdjacentZoneAttacksCount[Them] + count_1s_max_15<HasPopCnt>(undefended))
+ InitKingDanger[relative_square(Us, ksq)] + InitKingDanger[relative_square(Us, ksq)]
- shelter / 32; - mg_value(ei.pi->king_shelter(pos, Us, ksq)) / 32;
// Analyse enemy's safe queen contact checks. First find undefended // Analyse enemy's safe queen contact checks. First find undefended
// squares around the king attacked by enemy queen... // squares around the king attacked by enemy queen...
@ -779,7 +779,7 @@ namespace {
const Color Them = (Us == WHITE ? BLACK : WHITE); const Color Them = (Us == WHITE ? BLACK : WHITE);
Bitboard squaresToQueen, defendedSquares, unsafeSquares, supportingPawns; Bitboard squaresToQueen, defendedSquares, unsafeSquares, supportingPawns;
Bitboard b = ei.pi->passed_pawns() & pos.pieces_of_color(Us); Bitboard b = ei.pi->passed_pawns(Us);
while (b) while (b)
{ {

View file

@ -23,6 +23,7 @@
//// ////
#include <cassert> #include <cassert>
#include <cstring>
#include <sstream> #include <sstream>
#include <map> #include <map>
@ -134,15 +135,14 @@ template<> const SFMap& EndgameFunctions::get<SF>() const { return maps.second;
/// MaterialInfoTable c'tor and d'tor, called once by each thread /// MaterialInfoTable c'tor and d'tor, called once by each thread
MaterialInfoTable::MaterialInfoTable(unsigned int numOfEntries) { MaterialInfoTable::MaterialInfoTable() {
size = numOfEntries; entries = new MaterialInfo[MaterialTableSize];
entries = new MaterialInfo[size];
funcs = new EndgameFunctions(); funcs = new EndgameFunctions();
if (!entries || !funcs) if (!entries || !funcs)
{ {
cerr << "Failed to allocate " << numOfEntries * sizeof(MaterialInfo) cerr << "Failed to allocate " << MaterialTableSize * sizeof(MaterialInfo)
<< " bytes for material hash table." << endl; << " bytes for material hash table." << endl;
Application::exit_with_failure(); Application::exit_with_failure();
} }
@ -181,7 +181,7 @@ Phase MaterialInfoTable::game_phase(const Position& pos) {
MaterialInfo* MaterialInfoTable::get_material_info(const Position& pos) { MaterialInfo* MaterialInfoTable::get_material_info(const Position& pos) {
Key key = pos.get_material_key(); Key key = pos.get_material_key();
unsigned index = unsigned(key & (size - 1)); unsigned index = unsigned(key & (MaterialTableSize - 1));
MaterialInfo* mi = entries + index; MaterialInfo* mi = entries + index;
// If mi->key matches the position's material hash key, it means that we // If mi->key matches the position's material hash key, it means that we
@ -191,7 +191,8 @@ MaterialInfo* MaterialInfoTable::get_material_info(const Position& pos) {
return mi; return mi;
// Clear the MaterialInfo object, and set its key // Clear the MaterialInfo object, and set its key
mi->clear(); memset(mi, 0, sizeof(MaterialInfo));
mi->factor[WHITE] = mi->factor[BLACK] = uint8_t(SCALE_FACTOR_NORMAL);
mi->key = key; mi->key = key;
// Store game phase // Store game phase

View file

@ -33,6 +33,8 @@
//// Types //// Types
//// ////
const int MaterialTableSize = 1024;
/// MaterialInfo is a class which contains various information about a /// MaterialInfo is a class which contains various information about a
/// material configuration. It contains a material balance evaluation, /// material configuration. It contains a material balance evaluation,
/// a function pointer to a special endgame evaluation function (which in /// a function pointer to a special endgame evaluation function (which in
@ -48,8 +50,6 @@ class MaterialInfo {
friend class MaterialInfoTable; friend class MaterialInfoTable;
public: public:
MaterialInfo() : key(0) { clear(); }
Score material_value() const; Score material_value() const;
ScaleFactor scale_factor(const Position& pos, Color c) const; ScaleFactor scale_factor(const Position& pos, Color c) const;
int space_weight() const; int space_weight() const;
@ -58,8 +58,6 @@ public:
Value evaluate(const Position& pos) const; Value evaluate(const Position& pos) const;
private: private:
inline void clear();
Key key; Key key;
int16_t value; int16_t value;
uint8_t factor[2]; uint8_t factor[2];
@ -78,14 +76,13 @@ class EndgameFunctions;
class MaterialInfoTable { class MaterialInfoTable {
public: public:
MaterialInfoTable(unsigned numOfEntries); MaterialInfoTable();
~MaterialInfoTable(); ~MaterialInfoTable();
MaterialInfo* get_material_info(const Position& pos); MaterialInfo* get_material_info(const Position& pos);
static Phase game_phase(const Position& pos); static Phase game_phase(const Position& pos);
private: private:
unsigned size;
MaterialInfo* entries; MaterialInfo* entries;
EndgameFunctions* funcs; EndgameFunctions* funcs;
}; };
@ -104,20 +101,6 @@ inline Score MaterialInfo::material_value() const {
return make_score(value, value); return make_score(value, value);
} }
/// MaterialInfo::clear() resets a MaterialInfo object to an empty state,
/// with all slots at their default values but the key.
inline void MaterialInfo::clear() {
value = 0;
factor[WHITE] = factor[BLACK] = uint8_t(SCALE_FACTOR_NORMAL);
evaluationFunction = NULL;
scalingFunction[WHITE] = scalingFunction[BLACK] = NULL;
spaceWeight = 0;
}
/// MaterialInfo::scale_factor takes a position and a color as input, and /// MaterialInfo::scale_factor takes a position and a color as input, and
/// returns a scale factor for the given color. We have to provide the /// returns a scale factor for the given color. We have to provide the
/// position in addition to the color, because the scale factor need not /// position in addition to the color, because the scale factor need not

View file

@ -56,6 +56,7 @@ extern int get_system_time();
extern int cpu_count(); extern int cpu_count();
extern int Bioskey(); extern int Bioskey();
extern void prefetch(char* addr); extern void prefetch(char* addr);
extern void prefetchPawn(Key, int);
//// ////

View file

@ -110,12 +110,13 @@ namespace {
/// PawnInfoTable c'tor and d'tor instantiated one each thread /// PawnInfoTable c'tor and d'tor instantiated one each thread
PawnInfoTable::PawnInfoTable(unsigned numOfEntries) : size(numOfEntries) { PawnInfoTable::PawnInfoTable() {
entries = new PawnInfo[PawnTableSize];
entries = new PawnInfo[size];
if (!entries) if (!entries)
{ {
std::cerr << "Failed to allocate " << (numOfEntries * sizeof(PawnInfo)) std::cerr << "Failed to allocate " << (PawnTableSize * sizeof(PawnInfo))
<< " bytes for pawn hash table." << std::endl; << " bytes for pawn hash table." << std::endl;
Application::exit_with_failure(); Application::exit_with_failure();
} }
@ -128,16 +129,6 @@ PawnInfoTable::~PawnInfoTable() {
} }
/// PawnInfo::clear() resets to zero the PawnInfo entry. Note that
/// kingSquares[] is initialized to SQ_NONE instead.
void PawnInfo::clear() {
memset(this, 0, sizeof(PawnInfo));
kingSquares[WHITE] = kingSquares[BLACK] = SQ_NONE;
}
/// PawnInfoTable::get_pawn_info() takes a position object as input, computes /// PawnInfoTable::get_pawn_info() takes a position object as input, computes
/// a PawnInfo object, and returns a pointer to it. The result is also stored /// a PawnInfo object, and returns a pointer to it. The result is also stored
/// in a hash table, so we don't have to recompute everything when the same /// in a hash table, so we don't have to recompute everything when the same
@ -148,7 +139,7 @@ PawnInfo* PawnInfoTable::get_pawn_info(const Position& pos) const {
assert(pos.is_ok()); assert(pos.is_ok());
Key key = pos.get_pawn_key(); Key key = pos.get_pawn_key();
unsigned index = unsigned(key & (size - 1)); unsigned index = unsigned(key & (PawnTableSize - 1));
PawnInfo* pi = entries + index; PawnInfo* pi = entries + index;
// If pi->key matches the position's pawn hash key, it means that we // If pi->key matches the position's pawn hash key, it means that we
@ -158,7 +149,8 @@ PawnInfo* PawnInfoTable::get_pawn_info(const Position& pos) const {
return pi; return pi;
// Clear the PawnInfo object, and set the key // Clear the PawnInfo object, and set the key
pi->clear(); memset(pi, 0, sizeof(PawnInfo));
pi->kingSquares[WHITE] = pi->kingSquares[BLACK] = SQ_NONE;
pi->key = key; pi->key = key;
// Calculate pawn attacks // Calculate pawn attacks
@ -268,7 +260,7 @@ Score PawnInfoTable::evaluate_pawns(const Position& pos, Bitboard ourPawns,
// Mark the pawn as passed. Pawn will be properly scored in evaluation // Mark the pawn as passed. Pawn will be properly scored in evaluation
// because we need full attack info to evaluate passed pawns. // because we need full attack info to evaluate passed pawns.
if (passed) if (passed)
set_bit(&(pi->passedPawns), s); set_bit(&(pi->passedPawns[Us]), s);
// Score this pawn // Score this pawn
if (isolated) if (isolated)
@ -331,19 +323,24 @@ int PawnInfoTable::evaluate_pawn_storm(Square s, Rank r, File f, Bitboard theirP
/// PawnInfo::updateShelter calculates and caches king shelter. It is called /// PawnInfo::updateShelter calculates and caches king shelter. It is called
/// only when king square changes, about 20% of total get_king_shelter() calls. /// only when king square changes, about 20% of total king_shelter() calls.
int PawnInfo::updateShelter(const Position& pos, Color c, Square ksq) { Score PawnInfo::updateShelter(const Position& pos, Color c, Square ksq) {
Bitboard pawns = pos.pieces(PAWN, c) & this_and_neighboring_files_bb(ksq); Bitboard pawns;
unsigned shelter = 0; unsigned r, k, shelter = 0;
unsigned r = ksq & (7 << 3);
for (int i = 1, k = (c ? -8 : 8); i < 4; i++) if (relative_rank(c, ksq) <= RANK_4)
{ {
r += k; pawns = pos.pieces(PAWN, c) & this_and_neighboring_files_bb(ksq);
shelter += BitCount8Bit[(pawns >> r) & 0xFF] * (128 >> i); r = ksq & (7 << 3);
k = (c ? -8 : 8);
for (int i = 1; i < 4; i++)
{
r += k;
shelter += BitCount8Bit[(pawns >> r) & 0xFF] * (128 >> i);
}
} }
kingSquares[c] = ksq; kingSquares[c] = ksq;
kingShelters[c] = shelter; kingShelters[c] = make_score(shelter, 0);
return shelter; return kingShelters[c];
} }

View file

@ -32,6 +32,8 @@
//// Types //// Types
//// ////
const int PawnTableSize = 16384;
/// PawnInfo is a class which contains various information about a pawn /// PawnInfo is a class which contains various information about a pawn
/// structure. Currently, it only includes a middle game and an end game /// structure. Currently, it only includes a middle game and an end game
/// pawn structure evaluation, and a bitboard of passed pawns. We may want /// pawn structure evaluation, and a bitboard of passed pawns. We may want
@ -45,30 +47,28 @@ class PawnInfo {
friend class PawnInfoTable; friend class PawnInfoTable;
public: public:
PawnInfo() { clear(); }
Score pawns_value() const; Score pawns_value() const;
Value kingside_storm_value(Color c) const; Value kingside_storm_value(Color c) const;
Value queenside_storm_value(Color c) const; Value queenside_storm_value(Color c) const;
Bitboard pawn_attacks(Color c) const; Bitboard pawn_attacks(Color c) const;
Bitboard passed_pawns() const; Bitboard passed_pawns(Color c) const;
int file_is_half_open(Color c, File f) const; int file_is_half_open(Color c, File f) const;
int has_open_file_to_left(Color c, File f) const; int has_open_file_to_left(Color c, File f) const;
int has_open_file_to_right(Color c, File f) const; int has_open_file_to_right(Color c, File f) const;
int get_king_shelter(const Position& pos, Color c, Square ksq); Score king_shelter(const Position& pos, Color c, Square ksq);
private: private:
void clear(); Score updateShelter(const Position& pos, Color c, Square ksq);
int updateShelter(const Position& pos, Color c, Square ksq);
Key key; Key key;
Bitboard passedPawns; Bitboard passedPawns[2];
Bitboard pawnAttacks[2]; Bitboard pawnAttacks[2];
Square kingSquares[2]; Square kingSquares[2];
Score value; Score value;
int16_t ksStormValue[2], qsStormValue[2]; int ksStormValue[2];
uint8_t halfOpenFiles[2]; int qsStormValue[2];
uint8_t kingShelters[2]; int halfOpenFiles[2];
Score kingShelters[2];
}; };
/// The PawnInfoTable class represents a pawn hash table. It is basically /// The PawnInfoTable class represents a pawn hash table. It is basically
@ -81,9 +81,10 @@ class PawnInfoTable {
enum SideType { KingSide, QueenSide }; enum SideType { KingSide, QueenSide };
public: public:
PawnInfoTable(unsigned numOfEntries); PawnInfoTable();
~PawnInfoTable(); ~PawnInfoTable();
PawnInfo* get_pawn_info(const Position& pos) const; PawnInfo* get_pawn_info(const Position& pos) const;
void prefetch(Key key) const;
private: private:
template<Color Us> template<Color Us>
@ -92,7 +93,6 @@ private:
template<Color Us, SideType Side> template<Color Us, SideType Side>
int evaluate_pawn_storm(Square s, Rank r, File f, Bitboard theirPawns) const; int evaluate_pawn_storm(Square s, Rank r, File f, Bitboard theirPawns) const;
unsigned size;
PawnInfo* entries; PawnInfo* entries;
}; };
@ -101,12 +101,15 @@ private:
//// Inline functions //// Inline functions
//// ////
inline Score PawnInfo::pawns_value() const { inline void PawnInfoTable::prefetch(Key key) const {
return value;
unsigned index = unsigned(key & (PawnTableSize - 1));
PawnInfo* pi = entries + index;
::prefetch((char*) pi);
} }
inline Bitboard PawnInfo::passed_pawns() const { inline Score PawnInfo::pawns_value() const {
return passedPawns; return value;
} }
inline Bitboard PawnInfo::pawn_attacks(Color c) const { inline Bitboard PawnInfo::pawn_attacks(Color c) const {
@ -121,6 +124,10 @@ inline Value PawnInfo::queenside_storm_value(Color c) const {
return Value(qsStormValue[c]); return Value(qsStormValue[c]);
} }
inline Bitboard PawnInfo::passed_pawns(Color c) const {
return passedPawns[c];
}
inline int PawnInfo::file_is_half_open(Color c, File f) const { inline int PawnInfo::file_is_half_open(Color c, File f) const {
return (halfOpenFiles[c] & (1 << int(f))); return (halfOpenFiles[c] & (1 << int(f)));
} }
@ -133,8 +140,8 @@ inline int PawnInfo::has_open_file_to_right(Color c, File f) const {
return halfOpenFiles[c] & ~((1 << int(f+1)) - 1); return halfOpenFiles[c] & ~((1 << int(f+1)) - 1);
} }
inline int PawnInfo::get_king_shelter(const Position& pos, Color c, Square ksq) { inline Score PawnInfo::king_shelter(const Position& pos, Color c, Square ksq) {
return (kingSquares[c] == ksq ? kingShelters[c] : updateShelter(pos, c, ksq)); return kingSquares[c] == ksq ? kingShelters[c] : updateShelter(pos, c, ksq);
} }
#endif // !defined(PAWNS_H_INCLUDED) #endif // !defined(PAWNS_H_INCLUDED)

View file

@ -845,8 +845,9 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI
// Reset rule 50 draw counter // Reset rule 50 draw counter
st->rule50 = 0; st->rule50 = 0;
// Update pawn hash key // Update pawn hash key and prefetch in L1/L2 cache
st->pawnKey ^= zobrist[us][PAWN][from] ^ zobrist[us][PAWN][to]; st->pawnKey ^= zobrist[us][PAWN][from] ^ zobrist[us][PAWN][to];
prefetchPawn(st->pawnKey, threadID);
// Set en passant square, only if moved pawn can be captured // Set en passant square, only if moved pawn can be captured
if ((to ^ from) == 16) if ((to ^ from) == 16)