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>
MaterialInfoTable* MaterialTable[MAX_THREADS];
PawnInfoTable* PawnTable[MAX_THREADS];
MaterialInfoTable* MaterialTable[MAX_THREADS];
PawnInfoTable* PawnTable[MAX_THREADS];
- // Sizes of pawn and material hash tables
- const int PawnTableSize = 16384;
- const int MaterialTableSize = 1024;
-
// Function prototypes
template<bool HasPopCnt>
Value do_evaluate(const Position& pos, EvalInfo& ei);
// Function prototypes
template<bool HasPopCnt>
Value do_evaluate(const Position& pos, EvalInfo& ei);
+
+/// 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
/// values, an endgame score and a middle game score, and interpolates
/// between them based on the remaining material.
/// evaluate() is the main evaluation function. It always computes two
/// values, an endgame score and a middle game score, and interpolates
/// between them based on the remaining material.
continue;
}
if (!PawnTable[i])
continue;
}
if (!PawnTable[i])
- PawnTable[i] = new PawnInfoTable(PawnTableSize);
+ PawnTable[i] = new PawnInfoTable();
- MaterialTable[i] = new MaterialInfoTable(MaterialTableSize);
+ MaterialTable[i] = new MaterialInfoTable();
Bitboard undefended, b, b1, b2, safe;
bool sente;
Bitboard undefended, b, b1, b2, safe;
bool sente;
- int attackUnits, shelter = 0;
const Square ksq = pos.king_square(Us);
// King shelter
const Square ksq = pos.king_square(Us);
// King shelter
- if (relative_rank(Us, ksq) <= RANK_4)
- {
- shelter = ei.pi->get_king_shelter(pos, Us, ksq);
- ei.value += Sign[Us] * make_score(shelter, 0);
- }
+ ei.value += Sign[Us] * ei.pi->king_shelter(pos, Us, ksq);
// King safety. This is quite complicated, and is almost certainly far
// from optimally tuned.
// King safety. This is quite complicated, and is almost certainly far
// from optimally tuned.
attackUnits = Min(25, (ei.kingAttackersCount[Them] * ei.kingAttackersWeight[Them]) / 2)
+ 3 * (ei.kingAdjacentZoneAttacksCount[Them] + count_1s_max_15<HasPopCnt>(undefended))
+ InitKingDanger[relative_square(Us, ksq)]
attackUnits = Min(25, (ei.kingAttackersCount[Them] * ei.kingAttackersWeight[Them]) / 2)
+ 3 * (ei.kingAdjacentZoneAttacksCount[Them] + count_1s_max_15<HasPopCnt>(undefended))
+ InitKingDanger[relative_square(Us, ksq)]
+ - mg_value(ei.pi->king_shelter(pos, Us, ksq)) / 32;
// Analyse enemy's safe queen contact checks. First find undefended
// squares around the king attacked by enemy queen...
// Analyse enemy's safe queen contact checks. First find undefended
// squares around the king attacked by enemy queen...
const Color Them = (Us == WHITE ? BLACK : WHITE);
Bitboard squaresToQueen, defendedSquares, unsafeSquares, supportingPawns;
const Color Them = (Us == WHITE ? BLACK : WHITE);
Bitboard squaresToQueen, defendedSquares, unsafeSquares, supportingPawns;
- Bitboard b = ei.pi->passed_pawns() & pos.pieces_of_color(Us);
+ Bitboard b = ei.pi->passed_pawns(Us);
#include <sstream>
#include <map>
#include <sstream>
#include <map>
/// 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[size];
+ entries = new MaterialInfo[MaterialTableSize];
funcs = new EndgameFunctions();
if (!entries || !funcs)
{
funcs = new EndgameFunctions();
if (!entries || !funcs)
{
- cerr << "Failed to allocate " << numOfEntries * sizeof(MaterialInfo)
+ cerr << "Failed to allocate " << MaterialTableSize * sizeof(MaterialInfo)
<< " bytes for material hash table." << endl;
Application::exit_with_failure();
}
<< " bytes for material hash table." << endl;
Application::exit_with_failure();
}
MaterialInfo* MaterialInfoTable::get_material_info(const Position& pos) {
Key key = pos.get_material_key();
MaterialInfo* MaterialInfoTable::get_material_info(const Position& pos) {
Key key = pos.get_material_key();
- unsigned index = unsigned(key & (size - 1));
+ unsigned index = unsigned(key & (MaterialTableSize - 1));
MaterialInfo* mi = entries + index;
// If mi->key matches the position's material hash key, it means that we
MaterialInfo* mi = entries + index;
// If mi->key matches the position's material hash key, it means that we
return mi;
// Clear the MaterialInfo object, and set its key
return mi;
// Clear the MaterialInfo object, and set its key
+ memset(mi, 0, sizeof(MaterialInfo));
+ mi->factor[WHITE] = mi->factor[BLACK] = uint8_t(SCALE_FACTOR_NORMAL);
mi->key = key;
// Store game phase
mi->key = key;
// Store game phase
+const int MaterialTableSize = 1024;
+
/// MaterialInfo is a class which contains various information about a
/// material configuration. It contains a material balance evaluation,
/// a function pointer to a special endgame evaluation function (which in
/// MaterialInfo is a class which contains various information about a
/// material configuration. It contains a material balance evaluation,
/// a function pointer to a special endgame evaluation function (which in
friend class MaterialInfoTable;
public:
friend class MaterialInfoTable;
public:
- MaterialInfo() : key(0) { clear(); }
-
Score material_value() const;
ScaleFactor scale_factor(const Position& pos, Color c) const;
int space_weight() const;
Score material_value() const;
ScaleFactor scale_factor(const Position& pos, Color c) const;
int space_weight() const;
Value evaluate(const Position& pos) const;
private:
Value evaluate(const Position& pos) const;
private:
Key key;
int16_t value;
uint8_t factor[2];
Key key;
int16_t value;
uint8_t factor[2];
class MaterialInfoTable {
public:
class MaterialInfoTable {
public:
- MaterialInfoTable(unsigned numOfEntries);
~MaterialInfoTable();
MaterialInfo* get_material_info(const Position& pos);
static Phase game_phase(const Position& pos);
private:
~MaterialInfoTable();
MaterialInfo* get_material_info(const Position& pos);
static Phase game_phase(const Position& pos);
private:
MaterialInfo* entries;
EndgameFunctions* funcs;
};
MaterialInfo* entries;
EndgameFunctions* funcs;
};
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
/// 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
/// 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
/// position in addition to the color, because the scale factor need not
extern int cpu_count();
extern int Bioskey();
extern void prefetch(char* addr);
extern int cpu_count();
extern int Bioskey();
extern void prefetch(char* addr);
+extern void prefetchPawn(Key, int);
/// 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];
- std::cerr << "Failed to allocate " << (numOfEntries * sizeof(PawnInfo))
+ std::cerr << "Failed to allocate " << (PawnTableSize * sizeof(PawnInfo))
<< " bytes for pawn hash table." << std::endl;
Application::exit_with_failure();
}
<< " bytes for pawn hash table." << std::endl;
Application::exit_with_failure();
}
-/// 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
/// 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
/// 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
/// in a hash table, so we don't have to recompute everything when the same
assert(pos.is_ok());
Key key = pos.get_pawn_key();
assert(pos.is_ok());
Key key = pos.get_pawn_key();
- unsigned index = unsigned(key & (size - 1));
+ unsigned index = unsigned(key & (PawnTableSize - 1));
PawnInfo* pi = entries + index;
// If pi->key matches the position's pawn hash key, it means that we
PawnInfo* pi = entries + index;
// If pi->key matches the position's pawn hash key, it means that we
return pi;
// Clear the PawnInfo object, and set the key
return pi;
// Clear the PawnInfo object, and set the key
+ memset(pi, 0, sizeof(PawnInfo));
+ pi->kingSquares[WHITE] = pi->kingSquares[BLACK] = SQ_NONE;
pi->key = key;
// Calculate pawn attacks
pi->key = key;
// Calculate pawn attacks
// Mark the pawn as passed. Pawn will be properly scored in evaluation
// because we need full attack info to evaluate passed pawns.
if (passed)
// Mark the pawn as passed. Pawn will be properly scored in evaluation
// because we need full attack info to evaluate passed pawns.
if (passed)
- set_bit(&(pi->passedPawns), s);
+ set_bit(&(pi->passedPawns[Us]), s);
// Score this pawn
if (isolated)
// Score this pawn
if (isolated)
/// 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.
-int PawnInfo::updateShelter(const Position& pos, Color c, Square ksq) {
+/// only when king square changes, about 20% of total king_shelter() calls.
+Score PawnInfo::updateShelter(const Position& pos, Color c, Square ksq) {
- Bitboard pawns = pos.pieces(PAWN, c) & this_and_neighboring_files_bb(ksq);
- unsigned shelter = 0;
- unsigned r = ksq & (7 << 3);
+ Bitboard pawns;
+ unsigned r, k, shelter = 0;
- for (int i = 1, k = (c ? -8 : 8); i < 4; i++)
+ if (relative_rank(c, ksq) <= RANK_4)
- r += k;
- shelter += BitCount8Bit[(pawns >> r) & 0xFF] * (128 >> i);
+ pawns = pos.pieces(PAWN, c) & this_and_neighboring_files_bb(ksq);
+ r = ksq & (7 << 3);
+ k = (c ? -8 : 8);
+ for (int i = 1; i < 4; i++)
+ {
+ r += k;
+ shelter += BitCount8Bit[(pawns >> r) & 0xFF] * (128 >> i);
+ }
- kingShelters[c] = shelter;
- return shelter;
+ kingShelters[c] = make_score(shelter, 0);
+ return kingShelters[c];
+const int PawnTableSize = 16384;
+
/// PawnInfo is a class which contains various information about a pawn
/// structure. Currently, it only includes a middle game and an end game
/// pawn structure evaluation, and a bitboard of passed pawns. We may want
/// PawnInfo is a class which contains various information about a pawn
/// structure. Currently, it only includes a middle game and an end game
/// pawn structure evaluation, and a bitboard of passed pawns. We may want
friend class PawnInfoTable;
public:
friend class PawnInfoTable;
public:
- PawnInfo() { clear(); }
-
Score pawns_value() const;
Value kingside_storm_value(Color c) const;
Value queenside_storm_value(Color c) const;
Bitboard pawn_attacks(Color c) const;
Score pawns_value() const;
Value kingside_storm_value(Color c) const;
Value queenside_storm_value(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 has_open_file_to_left(Color c, File f) const;
int has_open_file_to_right(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_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);
- void clear();
- int updateShelter(const Position& pos, Color c, Square ksq);
+ Score updateShelter(const Position& pos, Color c, Square ksq);
+ Bitboard passedPawns[2];
Bitboard pawnAttacks[2];
Square kingSquares[2];
Score value;
Bitboard pawnAttacks[2];
Square kingSquares[2];
Score value;
- int16_t ksStormValue[2], qsStormValue[2];
- uint8_t halfOpenFiles[2];
- uint8_t kingShelters[2];
+ int ksStormValue[2];
+ int qsStormValue[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
enum SideType { KingSide, QueenSide };
public:
enum SideType { KingSide, QueenSide };
public:
- PawnInfoTable(unsigned numOfEntries);
~PawnInfoTable();
PawnInfo* get_pawn_info(const Position& pos) const;
~PawnInfoTable();
PawnInfo* get_pawn_info(const Position& pos) const;
+ void prefetch(Key key) const;
private:
template<Color Us>
private:
template<Color Us>
template<Color Us, SideType Side>
int evaluate_pawn_storm(Square s, Rank r, File f, Bitboard theirPawns) const;
template<Color Us, SideType Side>
int evaluate_pawn_storm(Square s, Rank r, File f, Bitboard theirPawns) const;
//// Inline functions
////
//// Inline functions
////
-inline Score PawnInfo::pawns_value() const {
- return value;
+inline void PawnInfoTable::prefetch(Key key) const {
+
+ unsigned index = unsigned(key & (PawnTableSize - 1));
+ PawnInfo* pi = entries + index;
+ ::prefetch((char*) pi);
-inline Bitboard PawnInfo::passed_pawns() const {
- return passedPawns;
+inline Score PawnInfo::pawns_value() const {
+ return value;
}
inline Bitboard PawnInfo::pawn_attacks(Color c) const {
}
inline Bitboard PawnInfo::pawn_attacks(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 {
return (halfOpenFiles[c] & (1 << int(f)));
}
inline int PawnInfo::file_is_half_open(Color c, File f) const {
return (halfOpenFiles[c] & (1 << int(f)));
}
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) {
- return (kingSquares[c] == ksq ? kingShelters[c] : updateShelter(pos, c, ksq));
+inline Score PawnInfo::king_shelter(const Position& pos, Color c, Square ksq) {
+ return kingSquares[c] == ksq ? kingShelters[c] : updateShelter(pos, c, ksq);
}
#endif // !defined(PAWNS_H_INCLUDED)
}
#endif // !defined(PAWNS_H_INCLUDED)
// Reset rule 50 draw counter
st->rule50 = 0;
// Reset rule 50 draw counter
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
if ((to ^ from) == 16)
// Set en passant square, only if moved pawn can be captured
if ((to ^ from) == 16)