From e2d3c163cbdd98de6f0399db358be964d014d313 Mon Sep 17 00:00:00 2001 From: protonspring Date: Tue, 1 Jan 2019 05:35:53 -0700 Subject: [PATCH 1/9] Remove as useless micro-optimization in pawns generation (#1915) The extra condition is used as a shortcut to skip the following 3 assignments: ```C++ Bitboard b1 = shift(pawnsOn7) & enemies; Bitboard b2 = shift(pawnsOn7) & enemies; Bitboard b3 = shift(pawnsOn7) & emptySquares; ``` In case of EVASION with no target on 8th rank (the common case), we end up performing the 3 statements for nothing because b1 = b2 = b3 = 0. But this is just a small micro-optimization and the condition is quite confusing, so just remove it and prefer a readable code instead. STC LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 78020 W: 16978 L: 16967 D: 44075 http://tests.stockfishchess.org/tests/view/5c27b4fe0ebc5902ba135bb0 No functional change. --- src/movegen.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/movegen.cpp b/src/movegen.cpp index 76a27d9f4..e7678979f 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -96,7 +96,6 @@ namespace { // Compute our parametrized parameters at compile time, named according to // the point of view of white side. constexpr Color Them = (Us == WHITE ? BLACK : WHITE); - constexpr Bitboard TRank8BB = (Us == WHITE ? Rank8BB : Rank1BB); constexpr Bitboard TRank7BB = (Us == WHITE ? Rank7BB : Rank2BB); constexpr Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB); constexpr Direction Up = (Us == WHITE ? NORTH : SOUTH); @@ -161,7 +160,7 @@ namespace { } // Promotions and underpromotions - if (pawnsOn7 && (Type != EVASIONS || (target & TRank8BB))) + if (pawnsOn7) { if (Type == CAPTURES) emptySquares = ~pos.pieces(); From 7accf07c0b9cb3e2b932da5dd11b7d321745895e Mon Sep 17 00:00:00 2001 From: protonspring Date: Tue, 1 Jan 2019 05:36:56 -0700 Subject: [PATCH 2/9] Remove "Any" predicate filter (#1914) This custom predicate filter creates an unnecessary abstraction layer, but doesn't make the code any more readable. The code is clear enough without it. No functional change. --- src/movepick.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/movepick.cpp b/src/movepick.cpp index 883135d49..d8ab68e76 100644 --- a/src/movepick.cpp +++ b/src/movepick.cpp @@ -31,9 +31,6 @@ namespace { QSEARCH_TT, QCAPTURE_INIT, QCAPTURE, QCHECK_INIT, QCHECK }; - // Helper filter used with select() - const auto Any = [](){ return true; }; - // partial_insertion_sort() sorts moves in descending order up to and including // a given limit. The order of moves smaller than the limit is left unspecified. void partial_insertion_sort(ExtMove* begin, ExtMove* end, int limit) { @@ -225,7 +222,7 @@ top: /* fallthrough */ case BAD_CAPTURE: - return select(Any); + return select([](){ return true; }); case EVASION_INIT: cur = moves; @@ -236,7 +233,7 @@ top: /* fallthrough */ case EVASION: - return select(Any); + return select([](){ return true; }); case PROBCUT: return select([&](){ return pos.see_ge(move, threshold); }); @@ -261,7 +258,7 @@ top: /* fallthrough */ case QCHECK: - return select(Any); + return select([](){ return true; }); } assert(false); From 79c97625a42c131708af953839900aff31102454 Mon Sep 17 00:00:00 2001 From: protonspring Date: Tue, 1 Jan 2019 05:38:09 -0700 Subject: [PATCH 3/9] Remove openFiles in pawns. (#1917) A single popcount in evaluate.cpp replaces all openFiles stuff in pawns. It doesn't seem to affect performance at all. STC LLR: 2.96 (-2.94,2.94) [-3.00,1.00] Total: 28103 W: 6134 L: 6025 D: 15944 http://tests.stockfishchess.org/tests/view/5b7d70a20ebc5902bdbb1999 No functional change. --- src/evaluate.cpp | 3 ++- src/pawns.cpp | 1 - src/pawns.h | 2 -- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 53a54006a..0a7d0af9a 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -717,7 +717,8 @@ namespace { behind |= (Us == WHITE ? behind >> 16 : behind << 16); int bonus = popcount(safe) + popcount(behind & safe); - int weight = pos.count(Us) - 2 * pe->open_files(); + int weight = pos.count(Us) + - 2 * popcount(pe->semiopenFiles[WHITE] & pe->semiopenFiles[BLACK]); Score score = make_score(bonus * weight * weight / 16, 0); diff --git a/src/pawns.cpp b/src/pawns.cpp index edd670b84..a9fc92b25 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -185,7 +185,6 @@ Entry* probe(const Position& pos) { e->key = key; e->scores[WHITE] = evaluate(pos, e); e->scores[BLACK] = evaluate(pos, e); - e->openFiles = popcount(e->semiopenFiles[WHITE] & e->semiopenFiles[BLACK]); e->asymmetry = popcount( (e->passedPawns[WHITE] | e->passedPawns[BLACK]) | (e->semiopenFiles[WHITE] ^ e->semiopenFiles[BLACK])); diff --git a/src/pawns.h b/src/pawns.h index df220eabb..67f966ada 100644 --- a/src/pawns.h +++ b/src/pawns.h @@ -39,7 +39,6 @@ struct Entry { Bitboard pawn_attacks_span(Color c) const { return pawnAttacksSpan[c]; } int weak_unopposed(Color c) const { return weakUnopposed[c]; } int pawn_asymmetry() const { return asymmetry; } - int open_files() const { return openFiles; } int semiopen_file(Color c, File f) const { return semiopenFiles[c] & (1 << f); @@ -73,7 +72,6 @@ struct Entry { int semiopenFiles[COLOR_NB]; int pawnsOnSquares[COLOR_NB][COLOR_NB]; // [color][light/dark squares] int asymmetry; - int openFiles; }; typedef HashTable Table; From eb6d7f537d214c4dc8bde7d4fdc2aaead47dd3c3 Mon Sep 17 00:00:00 2001 From: Marco Costalba Date: Tue, 1 Jan 2019 14:10:26 +0100 Subject: [PATCH 4/9] Assorted trivial cleanups (#1894) To address https://github.com/official-stockfish/Stockfish/issues/1862 No functional change. --- src/bitboard.cpp | 4 ++-- src/endgame.cpp | 5 +++- src/evaluate.cpp | 8 +++---- src/movegen.cpp | 8 +++---- src/movepick.h | 4 ++-- src/pawns.cpp | 2 +- src/position.cpp | 10 ++++---- src/psqt.cpp | 18 +++++++------- src/search.cpp | 62 ++++++++++++++++++++++++------------------------ tests/perft.sh | 2 +- 10 files changed, 63 insertions(+), 60 deletions(-) diff --git a/src/bitboard.cpp b/src/bitboard.cpp index 398c6bf77..8079b783b 100644 --- a/src/bitboard.cpp +++ b/src/bitboard.cpp @@ -184,8 +184,8 @@ namespace { // init_magics() computes all rook and bishop attacks at startup. Magic // bitboards are used to look up attacks of sliding pieces. As a reference see - // chessprogramming.wikispaces.com/Magic+Bitboards. In particular, here we - // use the so called "fancy" approach. + // www.chessprogramming.org/Magic_Bitboards. In particular, here we use the so + // called "fancy" approach. void init_magics(Bitboard table[], Magic magics[], Direction directions[]) { diff --git a/src/endgame.cpp b/src/endgame.cpp index 66ee54d84..835173c46 100644 --- a/src/endgame.cpp +++ b/src/endgame.cpp @@ -131,7 +131,7 @@ Value Endgame::operator()(const Position& pos) const { Square loserKSq = pos.square(weakSide); Square bishopSq = pos.square(strongSide); - // If our Bishop does not attack A1/H8, we flip the enemy king square + // If our Bishop does not attack A1/H8, we flip the enemy king square // to drive to opposite corners (A8/H1). Value result = VALUE_KNOWN_WIN @@ -724,6 +724,9 @@ ScaleFactor Endgame::operator()(const Position& pos) const { template<> ScaleFactor Endgame::operator()(const Position& pos) const { + assert(verify_material(pos, strongSide, KnightValueMg, 1)); + assert(verify_material(pos, weakSide, BishopValueMg, 0)); + Square pawnSq = pos.square(strongSide); Square bishopSq = pos.square(weakSide); Square weakKingSq = pos.square(weakSide); diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 0a7d0af9a..725ea49ce 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -213,7 +213,7 @@ namespace { // kingRing[color] are the squares adjacent to the king, plus (only for a // king on its first rank) the squares two ranks in front. For instance, // if black's king is on g8, kingRing[BLACK] is f8, h8, f7, g7, h7, f6, g6 - // and h6. It is set to 0 when king safety evaluation is skipped. + // and h6. Bitboard kingRing[COLOR_NB]; // kingAttackersCount[color] is the number of pieces of the given color @@ -505,7 +505,7 @@ namespace { Score score = SCORE_ZERO; // Non-pawn enemies - nonPawnEnemies = pos.pieces(Them) & ~pos.pieces(Them, PAWN); + nonPawnEnemies = pos.pieces(Them) & ~pos.pieces(PAWN); // Squares strongly protected by the enemy, either because they defend the // square with a pawn, or because they defend the square twice and we don't. @@ -717,8 +717,8 @@ namespace { behind |= (Us == WHITE ? behind >> 16 : behind << 16); int bonus = popcount(safe) + popcount(behind & safe); - int weight = pos.count(Us) - - 2 * popcount(pe->semiopenFiles[WHITE] & pe->semiopenFiles[BLACK]); + int weight = pos.count(Us) + - 2 * popcount(pe->semiopenFiles[WHITE] & pe->semiopenFiles[BLACK]); Score score = make_score(bonus * weight * weight / 16, 0); diff --git a/src/movegen.cpp b/src/movegen.cpp index e7678979f..c3cff08da 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -28,6 +28,7 @@ namespace { template ExtMove* generate_castling(const Position& pos, ExtMove* moveList) { + constexpr Color Them = (Us == WHITE ? BLACK : WHITE); constexpr CastlingRight Cr = Us | Cs; constexpr bool KingSide = (Cs == KING_SIDE); @@ -39,7 +40,7 @@ namespace { Square kfrom = pos.square(Us); Square rfrom = pos.castling_rook_square(Cr); Square kto = relative_square(Us, KingSide ? SQ_G1 : SQ_C1); - Bitboard enemies = pos.pieces(~Us); + Bitboard enemies = pos.pieces(Them); assert(!pos.checkers()); @@ -53,7 +54,7 @@ namespace { // Because we generate only legal castling moves we need to verify that // when moving the castling rook we do not discover some hidden checker. // For instance an enemy queen in SQ_A1 when castling rook is in SQ_B1. - if (Chess960 && (attacks_bb(kto, pos.pieces() ^ rfrom) & pos.pieces(~Us, ROOK, QUEEN))) + if (Chess960 && (attacks_bb(kto, pos.pieces() ^ rfrom) & pos.pieces(Them, ROOK, QUEEN))) return moveList; Move m = make(kfrom, rfrom); @@ -93,8 +94,7 @@ namespace { template ExtMove* generate_pawn_moves(const Position& pos, ExtMove* moveList, Bitboard target) { - // Compute our parametrized parameters at compile time, named according to - // the point of view of white side. + // Compute some compile time parameters relative to the white side constexpr Color Them = (Us == WHITE ? BLACK : WHITE); constexpr Bitboard TRank7BB = (Us == WHITE ? Rank7BB : Rank2BB); constexpr Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB); diff --git a/src/movepick.h b/src/movepick.h index 7a55e21c6..d9ecba99d 100644 --- a/src/movepick.h +++ b/src/movepick.h @@ -85,11 +85,11 @@ enum StatsParams { NOT_USED = 0 }; /// ButterflyHistory records how often quiet moves have been successful or /// unsuccessful during the current search, and is used for reduction and move /// ordering decisions. It uses 2 tables (one for each color) indexed by -/// the move's from and to squares, see chessprogramming.wikispaces.com/Butterfly+Boards +/// the move's from and to squares, see www.chessprogramming.org/Butterfly_Boards typedef Stats ButterflyHistory; /// CounterMoveHistory stores counter moves indexed by [piece][to] of the previous -/// move, see chessprogramming.wikispaces.com/Countermove+Heuristic +/// move, see www.chessprogramming.org/Countermove_Heuristic typedef Stats CounterMoveHistory; /// CapturePieceToHistory is addressed by a move's [piece][to][captured piece type] diff --git a/src/pawns.cpp b/src/pawns.cpp index a9fc92b25..c581c8e72 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -115,7 +115,7 @@ namespace { // not attacked more times than defended. if ( !(stoppers ^ lever ^ leverPush) && popcount(support) >= popcount(lever) - 1 - && popcount(phalanx) >= popcount(leverPush)) + && popcount(phalanx) >= popcount(leverPush)) e->passedPawns[Us] |= s; else if ( stoppers == SquareBB[s + Up] diff --git a/src/position.cpp b/src/position.cpp index bd5daa6dc..0396eb9f5 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -183,7 +183,7 @@ void Position::init() { { std::swap(cuckoo[i], key); std::swap(cuckooMove[i], move); - if (move == 0) // Arrived at empty slot ? + if (move == MOVE_NONE) // Arrived at empty slot? break; i = (i == H1(key)) ? H2(key) : H1(key); // Push victim to alternative slot } @@ -465,16 +465,16 @@ const string Position::fen() const { ss << (sideToMove == WHITE ? " w " : " b "); if (can_castle(WHITE_OO)) - ss << (chess960 ? char('A' + file_of(castling_rook_square(WHITE | KING_SIDE))) : 'K'); + ss << (chess960 ? char('A' + file_of(castling_rook_square(WHITE_OO ))) : 'K'); if (can_castle(WHITE_OOO)) - ss << (chess960 ? char('A' + file_of(castling_rook_square(WHITE | QUEEN_SIDE))) : 'Q'); + ss << (chess960 ? char('A' + file_of(castling_rook_square(WHITE_OOO))) : 'Q'); if (can_castle(BLACK_OO)) - ss << (chess960 ? char('a' + file_of(castling_rook_square(BLACK | KING_SIDE))) : 'k'); + ss << (chess960 ? char('a' + file_of(castling_rook_square(BLACK_OO ))) : 'k'); if (can_castle(BLACK_OOO)) - ss << (chess960 ? char('a' + file_of(castling_rook_square(BLACK | QUEEN_SIDE))) : 'q'); + ss << (chess960 ? char('a' + file_of(castling_rook_square(BLACK_OOO))) : 'q'); if (!can_castle(ANY_CASTLING)) ss << '-'; diff --git a/src/psqt.cpp b/src/psqt.cpp index a4a5e0a04..bc3e53928 100644 --- a/src/psqt.cpp +++ b/src/psqt.cpp @@ -90,15 +90,15 @@ constexpr Score Bonus[][RANK_NB][int(FILE_NB) / 2] = { } }; -constexpr Score PBonus[RANK_NB][FILE_NB] = - { // Pawn - { S( 0, 0), S( 0, 0), S( 0, 0), S( 0, 0), S( 0, 0), S( 0, 0), S( 0, 0), S( 0, 0) }, - { S( 0,-11), S( -3, -4), S( 13, -1), S( 19, -4), S( 16, 17), S( 13, 7), S( 4, 4), S( -4,-13) }, - { S(-16, -8), S(-12, -6), S( 20, -3), S( 21, 0), S( 25,-11), S( 29, 3), S( 0, 0), S(-27, -1) }, - { S(-11, 3), S(-17, 6), S( 11,-10), S( 21, 1), S( 32, -6), S( 19,-11), S( -5, 0), S(-14, -2) }, - { S( 4, 13), S( 6, 7), S( -8, 3), S( 3, -5), S( 8,-15), S( -2, -1), S(-19, 9), S( -5, 13) }, - { S( -5, 25), S(-19, 20), S( 7, 16), S( 8, 12), S( -7, 21), S( -2, 3), S(-10, -4), S(-16, 15) }, - { S(-10, 6), S( 9, -5), S( -7, 16), S(-12, 27), S( -7, 15), S( -8, 11), S( 16, -7), S( -8, 4) } +constexpr Score PBonus[RANK_NB][FILE_NB] = + { // Pawn (asymmetric distribution) + { }, + { S( 0,-11), S( -3,-4), S(13, -1), S( 19, -4), S(16, 17), S(13, 7), S( 4, 4), S( -4,-13) }, + { S(-16, -8), S(-12,-6), S(20, -3), S( 21, 0), S(25,-11), S(29, 3), S( 0, 0), S(-27, -1) }, + { S(-11, 3), S(-17, 6), S(11,-10), S( 21, 1), S(32, -6), S(19,-11), S( -5, 0), S(-14, -2) }, + { S( 4, 13), S( 6, 7), S(-8, 3), S( 3, -5), S( 8,-15), S(-2, -1), S(-19, 9), S( -5, 13) }, + { S( -5, 25), S(-19,20), S( 7, 16), S( 8, 12), S(-7, 21), S(-2, 3), S(-10, -4), S(-16, 15) }, + { S(-10, 6), S( 9,-5), S(-7, 16), S(-12, 27), S(-7, 15), S(-8, 11), S( 16, -7), S( -8, 4) } }; #undef S diff --git a/src/search.cpp b/src/search.cpp index 4a541c5b9..fe9b446e4 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -113,8 +113,8 @@ namespace { Value value_from_tt(Value v, int ply); void update_pv(Move* pv, Move move, Move* childPv); void update_continuation_histories(Stack* ss, Piece pc, Square to, int bonus); - void update_quiet_stats(const Position& pos, Stack* ss, Move move, Move* quiets, int quietsCnt, int bonus); - void update_capture_stats(const Position& pos, Move move, Move* captures, int captureCnt, int bonus); + void update_quiet_stats(const Position& pos, Stack* ss, Move move, Move* quiets, int quietCount, int bonus); + void update_capture_stats(const Position& pos, Move move, Move* captures, int captureCount, int bonus); inline bool gives_check(const Position& pos, Move move) { Color us = pos.side_to_move(); @@ -498,32 +498,32 @@ void Thread::search() { if ( Limits.use_time_management() && !Threads.stop && !Threads.stopOnPonderhit) + { + double fallingEval = (306 + 119 * failedLow + 6 * (mainThread->previousScore - bestValue)) / 581.0; + fallingEval = std::max(0.5, std::min(1.5, fallingEval)); + + // If the bestMove is stable over several iterations, reduce time accordingly + timeReduction = 1.0; + for (int i : {3, 4, 5}) + if (lastBestMoveDepth * i < completedDepth) + timeReduction *= 1.25; + + // Use part of the gained time from a previous stable move for the current move + double bestMoveInstability = 1.0 + mainThread->bestMoveChanges; + bestMoveInstability *= std::pow(mainThread->previousTimeReduction, 0.528) / timeReduction; + + // Stop the search if we have only one legal move, or if available time elapsed + if ( rootMoves.size() == 1 + || Time.elapsed() > Time.optimum() * bestMoveInstability * fallingEval) { - double fallingEval = (306 + 119 * failedLow + 6 * (mainThread->previousScore - bestValue)) / 581.0; - fallingEval = std::max(0.5, std::min(1.5, fallingEval)); - - // If the bestMove is stable over several iterations, reduce time accordingly - timeReduction = 1.0; - for (int i : {3, 4, 5}) - if (lastBestMoveDepth * i < completedDepth) - timeReduction *= 1.25; - - // Use part of the gained time from a previous stable move for the current move - double bestMoveInstability = 1.0 + mainThread->bestMoveChanges; - bestMoveInstability *= std::pow(mainThread->previousTimeReduction, 0.528) / timeReduction; - - // Stop the search if we have only one legal move, or if available time elapsed - if ( rootMoves.size() == 1 - || Time.elapsed() > Time.optimum() * bestMoveInstability * fallingEval) - { - // If we are allowed to ponder do not stop the search now but - // keep pondering until the GUI sends "ponderhit" or "stop". - if (Threads.ponder) - Threads.stopOnPonderhit = true; - else - Threads.stop = true; - } + // If we are allowed to ponder do not stop the search now but + // keep pondering until the GUI sends "ponderhit" or "stop". + if (Threads.ponder) + Threads.stopOnPonderhit = true; + else + Threads.stop = true; } + } } if (!mainThread) @@ -1481,7 +1481,7 @@ moves_loop: // When in check, search starts from here // update_capture_stats() updates move sorting heuristics when a new capture best move is found void update_capture_stats(const Position& pos, Move move, - Move* captures, int captureCnt, int bonus) { + Move* captures, int captureCount, int bonus) { CapturePieceToHistory& captureHistory = pos.this_thread()->captureHistory; Piece moved_piece = pos.moved_piece(move); @@ -1491,7 +1491,7 @@ moves_loop: // When in check, search starts from here captureHistory[moved_piece][to_sq(move)][captured] << bonus; // Decrease all the other played capture moves - for (int i = 0; i < captureCnt; ++i) + for (int i = 0; i < captureCount; ++i) { moved_piece = pos.moved_piece(captures[i]); captured = type_of(pos.piece_on(to_sq(captures[i]))); @@ -1503,7 +1503,7 @@ moves_loop: // When in check, search starts from here // update_quiet_stats() updates move sorting heuristics when a new quiet best move is found void update_quiet_stats(const Position& pos, Stack* ss, Move move, - Move* quiets, int quietsCnt, int bonus) { + Move* quiets, int quietCount, int bonus) { if (ss->killers[0] != move) { @@ -1523,7 +1523,7 @@ moves_loop: // When in check, search starts from here } // Decrease all the other played quiet moves - for (int i = 0; i < quietsCnt; ++i) + for (int i = 0; i < quietCount; ++i) { thisThread->mainHistory[us][from_to(quiets[i])] << -bonus; update_continuation_histories(ss, pos.moved_piece(quiets[i]), to_sq(quiets[i]), -bonus); @@ -1666,7 +1666,7 @@ bool RootMove::extract_ponder_from_tt(Position& pos) { assert(pv.size() == 1); - if (!pv[0]) + if (pv[0] == MOVE_NONE) return false; pos.do_move(pv[0], st); diff --git a/tests/perft.sh b/tests/perft.sh index d40222116..545e750fe 100755 --- a/tests/perft.sh +++ b/tests/perft.sh @@ -1,5 +1,5 @@ #!/bin/bash -# verify perft numbers (positions from https://chessprogramming.wikispaces.com/Perft+Results) +# verify perft numbers (positions from www.chessprogramming.org/Perft_Results) error() { From 3c576efa77f431cf3687881b8fd6a728e87ed97d Mon Sep 17 00:00:00 2001 From: Marco Costalba Date: Wed, 2 Jan 2019 08:31:03 +0100 Subject: [PATCH 5/9] Delay castling legality check Delay legality check of castling moves at search time, just before making the move, as is the standard with all the other move types. This should avoid an useless and not trivial legality check when the castling is then not tried later. For instance due to a previous cut-off. The patch is also a big simplification and allows to entirely remove generate_castling() Bench changes due to a different move sequence out of MovePicker. STC: LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 45073 W: 9918 L: 9843 D: 25312 http://tests.stockfishchess.org/tests/view/5c2f176f0ebc596a450bdfb3 LTC: LLR: 3.15 (-2.94,2.94) [-3.00,1.00] Total: 10156 W: 1707 L: 1560 D: 6889 http://tests.stockfishchess.org/tests/view/5c2e7dfd0ebc596a450bcdf4 Verified with perft both in standard and Chess960 cases. Closes https://github.com/official-stockfish/Stockfish/pull/1929 Bench: 3559104 --- src/movegen.cpp | 63 +++++++----------------------------------------- src/position.cpp | 31 +++++++++++++++++++----- src/position.h | 2 +- src/types.h | 4 ++- 4 files changed, 38 insertions(+), 62 deletions(-) diff --git a/src/movegen.cpp b/src/movegen.cpp index c3cff08da..5ed248933 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -25,48 +25,6 @@ namespace { - template - ExtMove* generate_castling(const Position& pos, ExtMove* moveList) { - - constexpr Color Them = (Us == WHITE ? BLACK : WHITE); - constexpr CastlingRight Cr = Us | Cs; - constexpr bool KingSide = (Cs == KING_SIDE); - - if (pos.castling_impeded(Cr) || !pos.can_castle(Cr)) - return moveList; - - // After castling, the rook and king final positions are the same in Chess960 - // as they would be in standard chess. - Square kfrom = pos.square(Us); - Square rfrom = pos.castling_rook_square(Cr); - Square kto = relative_square(Us, KingSide ? SQ_G1 : SQ_C1); - Bitboard enemies = pos.pieces(Them); - - assert(!pos.checkers()); - - const Direction step = Chess960 ? kto > kfrom ? WEST : EAST - : KingSide ? WEST : EAST; - - for (Square s = kto; s != kfrom; s += step) - if (pos.attackers_to(s) & enemies) - return moveList; - - // Because we generate only legal castling moves we need to verify that - // when moving the castling rook we do not discover some hidden checker. - // For instance an enemy queen in SQ_A1 when castling rook is in SQ_B1. - if (Chess960 && (attacks_bb(kto, pos.pieces() ^ rfrom) & pos.pieces(Them, ROOK, QUEEN))) - return moveList; - - Move m = make(kfrom, rfrom); - - if (Checks && !pos.gives_check(m)) - return moveList; - - *moveList++ = m; - return moveList; - } - - template ExtMove* make_promotions(ExtMove* moveList, Square to, Square ksq) { @@ -261,7 +219,9 @@ namespace { template ExtMove* generate_all(const Position& pos, ExtMove* moveList, Bitboard target) { - constexpr bool Checks = Type == QUIET_CHECKS; + constexpr CastlingRight OO = Us | KING_SIDE; + constexpr CastlingRight OOO = Us | QUEEN_SIDE; + constexpr bool Checks = Type == QUIET_CHECKS; // Reduce template instantations moveList = generate_pawn_moves(pos, moveList, target); moveList = generate_moves(pos, moveList, Us, target); @@ -275,19 +235,14 @@ namespace { Bitboard b = pos.attacks_from(ksq) & target; while (b) *moveList++ = make_move(ksq, pop_lsb(&b)); - } - if (Type != CAPTURES && Type != EVASIONS && pos.castling_rights(Us)) - { - if (pos.is_chess960()) + if (Type != CAPTURES && pos.can_castle(CastlingRight(OO | OOO))) { - moveList = generate_castling(pos, moveList); - moveList = generate_castling(pos, moveList); - } - else - { - moveList = generate_castling(pos, moveList); - moveList = generate_castling(pos, moveList); + if (!pos.castling_impeded(OO) && pos.can_castle(OO)) + *moveList++ = make(ksq, pos.castling_rook_square(OO)); + + if (!pos.castling_impeded(OOO) && pos.can_castle(OOO)) + *moveList++ = make(ksq, pos.castling_rook_square(OOO)); } } diff --git a/src/position.cpp b/src/position.cpp index 0396eb9f5..21eff88c4 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -540,6 +540,7 @@ bool Position::legal(Move m) const { Color us = sideToMove; Square from = from_sq(m); + Square to = to_sq(m); assert(color_of(moved_piece(m)) == us); assert(piece_on(square(us)) == make_piece(us, KING)); @@ -550,7 +551,6 @@ bool Position::legal(Move m) const { if (type_of(m) == ENPASSANT) { Square ksq = square(us); - Square to = to_sq(m); Square capsq = to - pawn_push(us); Bitboard occupied = (pieces() ^ from ^ capsq) | to; @@ -563,16 +563,35 @@ bool Position::legal(Move m) const { && !(attacks_bb(ksq, occupied) & pieces(~us, QUEEN, BISHOP)); } - // If the moving piece is a king, check whether the destination - // square is attacked by the opponent. Castling moves are checked - // for legality during move generation. + // Castling moves generation does not check if the castling path is clear of + // enemy attacks, it is delayed at a later time: now! + if (type_of(m) == CASTLING) + { + // After castling, the rook and king final positions are the same in + // Chess960 as they would be in standard chess. + to = relative_square(us, to > from ? SQ_G1 : SQ_C1); + Direction step = to > from ? WEST : EAST; + + for (Square s = to; s != from; s += step) + if (attackers_to(s) & pieces(~us)) + return false; + + // In case of Chess960, verify that when moving the castling rook we do + // not discover some hidden checker. + // For instance an enemy queen in SQ_A1 when castling rook is in SQ_B1. + return !chess960 + || !(attacks_bb(to, pieces() ^ to_sq(m)) & pieces(~us, ROOK, QUEEN)); + } + + // If the moving piece is a king, check whether the destination square is + // attacked by the opponent. if (type_of(piece_on(from)) == KING) - return type_of(m) == CASTLING || !(attackers_to(to_sq(m)) & pieces(~us)); + return !(attackers_to(to) & pieces(~us)); // A non-king move is legal if and only if it is not pinned or it // is moving along the ray towards or away from the king. return !(blockers_for_king(us) & from) - || aligned(from, to_sq(m), square(us)); + || aligned(from, to, square(us)); } diff --git a/src/position.h b/src/position.h index d94ef185a..74173d03b 100644 --- a/src/position.h +++ b/src/position.h @@ -265,7 +265,7 @@ inline bool Position::can_castle(CastlingRight cr) const { } inline int Position::castling_rights(Color c) const { - return st->castlingRights & ((WHITE_OO | WHITE_OOO) << (2 * c)); + return st->castlingRights & (c == WHITE ? WHITE_CASTLING : BLACK_CASTLING); } inline bool Position::castling_impeded(CastlingRight cr) const { diff --git a/src/types.h b/src/types.h index c4c2752c8..8e27606c1 100644 --- a/src/types.h +++ b/src/types.h @@ -141,7 +141,9 @@ enum CastlingRight { WHITE_OOO = WHITE_OO << 1, BLACK_OO = WHITE_OO << 2, BLACK_OOO = WHITE_OO << 3, - ANY_CASTLING = WHITE_OO | WHITE_OOO | BLACK_OO | BLACK_OOO, + WHITE_CASTLING = WHITE_OO | WHITE_OOO, + BLACK_CASTLING = BLACK_OO | BLACK_OOO, + ANY_CASTLING = WHITE_CASTLING | BLACK_CASTLING, CASTLING_RIGHT_NB = 16 }; From bb843a00c1ef381162dc9c2491b5436b6cf5563f Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Thu, 3 Jan 2019 23:56:11 +0100 Subject: [PATCH 6/9] Check tablebase files This addresses partially issue #1911 in that it documents in our Readme the command that users can use to verifying the md5sum of their downloaded tablebase files. Additionally, a quick check of the file size (the size of each tablebase file modulo 64 is 16 as pointed out by @syzygy1) has been implemented at launch time in Stockfish. Closes https://github.com/official-stockfish/Stockfish/pull/1927 and https://github.com/official-stockfish/Stockfish/issues/1911 No functional change. --- Readme.md | 4 +++- src/syzygy/tbprobe.cpp | 34 ++++++++++++++++++++++++++-------- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/Readme.md b/Readme.md index a68ef560b..bc058dbc9 100644 --- a/Readme.md +++ b/Readme.md @@ -86,7 +86,9 @@ Currently, Stockfish has the following UCI options: Example: `C:\tablebases\wdl345;C:\tablebases\wdl6;D:\tablebases\dtz345;D:\tablebases\dtz6` It is recommended to store .rtbw files on an SSD. There is no loss in storing - the .rtbz files on a regular HD. + the .rtbz files on a regular HD. It is recommended to verify all md5 checksums + of the downloaded tablebase files (`md5sum -c checksum.md5`) as corruption will + lead to engine crashes. * #### SyzygyProbeDepth Minimum remaining search depth for which a position is probed. Set this option diff --git a/src/syzygy/tbprobe.cpp b/src/syzygy/tbprobe.cpp index 57c7d872e..bf6ed4218 100644 --- a/src/syzygy/tbprobe.cpp +++ b/src/syzygy/tbprobe.cpp @@ -214,14 +214,22 @@ public: return *baseAddress = nullptr, nullptr; fstat(fd, &statbuf); + + if (statbuf.st_size % 64 != 16) + { + std::cerr << "Corrupt tablebase file " << fname << std::endl; + exit(EXIT_FAILURE); + } + *mapping = statbuf.st_size; *baseAddress = mmap(nullptr, statbuf.st_size, PROT_READ, MAP_SHARED, fd, 0); madvise(*baseAddress, statbuf.st_size, MADV_RANDOM); ::close(fd); - if (*baseAddress == MAP_FAILED) { + if (*baseAddress == MAP_FAILED) + { std::cerr << "Could not mmap() " << fname << std::endl; - exit(1); + exit(EXIT_FAILURE); } #else // Note FILE_FLAG_RANDOM_ACCESS is only a hint to Windows and as such may get ignored. @@ -233,21 +241,30 @@ public: DWORD size_high; DWORD size_low = GetFileSize(fd, &size_high); + + if (size_low % 64 != 16) + { + std::cerr << "Corrupt tablebase file " << fname << std::endl; + exit(EXIT_FAILURE); + } + HANDLE mmap = CreateFileMapping(fd, nullptr, PAGE_READONLY, size_high, size_low, nullptr); CloseHandle(fd); - if (!mmap) { + if (!mmap) + { std::cerr << "CreateFileMapping() failed" << std::endl; - exit(1); + exit(EXIT_FAILURE); } *mapping = (uint64_t)mmap; *baseAddress = MapViewOfFile(mmap, FILE_MAP_READ, 0, 0, 0); - if (!*baseAddress) { + if (!*baseAddress) + { std::cerr << "MapViewOfFile() failed, name = " << fname << ", error = " << GetLastError() << std::endl; - exit(1); + exit(EXIT_FAILURE); } #endif uint8_t* data = (uint8_t*)*baseAddress; @@ -255,7 +272,8 @@ public: constexpr uint8_t Magics[][4] = { { 0xD7, 0x66, 0x0C, 0xA5 }, { 0x71, 0xE8, 0x23, 0x5D } }; - if (memcmp(data, Magics[type == WDL], 4)) { + if (memcmp(data, Magics[type == WDL], 4)) + { std::cerr << "Corrupted table in file " << fname << std::endl; unmap(*baseAddress, *mapping); return *baseAddress = nullptr, nullptr; @@ -416,7 +434,7 @@ class TBTables { } } std::cerr << "TB hash table size too low!" << std::endl; - exit(1); + exit(EXIT_FAILURE); } public: From f69106f7bb82f97ba07fb06a31395039d08af9f4 Mon Sep 17 00:00:00 2001 From: Miguel Lahoz Date: Sun, 6 Jan 2019 04:53:21 +0800 Subject: [PATCH 7/9] Introduce Multi-Cut This was inspired after reading about [Multi-Cut](https://www.chessprogramming.org/Multi-Cut). We now do non-singular cut node pruning. The idea is to prune when we have a "backup plan" in case our expected fail high node does not fail high on the ttMove. For singular extensions, we do a search on all other moves but the ttMove. If this fails high on our original beta, this means that both the ttMove, as well as at least one other move was proven to fail high on a lower depth search. We then assume that one of these moves will work on a higher depth and prune. STC: LLR: 2.96 (-2.94,2.94) [0.50,4.50] Total: 72952 W: 16104 L: 15583 D: 41265 http://tests.stockfishchess.org/tests/view/5c3119640ebc596a450c0be5 LTC: LLR: 2.95 (-2.94,2.94) [0.00,3.50] Total: 27103 W: 4564 L: 4314 D: 18225 http://tests.stockfishchess.org/tests/view/5c3184c00ebc596a450c1662 Bench: 3145487 --- src/search.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index fe9b446e4..c8e6c8b65 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -943,13 +943,21 @@ moves_loop: // When in check, search starts from here && tte->depth() >= depth - 3 * ONE_PLY && pos.legal(move)) { - Value reducedBeta = std::max(ttValue - 2 * depth / ONE_PLY, -VALUE_MATE); + Value singularBeta = std::max(ttValue - 2 * depth / ONE_PLY, -VALUE_MATE); ss->excludedMove = move; - value = search(pos, ss, reducedBeta - 1, reducedBeta, depth / 2, cutNode); + value = search(pos, ss, singularBeta - 1, singularBeta, depth / 2, cutNode); ss->excludedMove = MOVE_NONE; - if (value < reducedBeta) + if (value < singularBeta) extension = ONE_PLY; + + // Multi-cut pruning + // Our ttMove is assumed to fail high, and now we failed high also on a reduced + // search without the ttMove. So we assume this expected Cut-node is not singular, + // that is multiple moves fail high, and we can prune the whole subtree by returning + // the hard beta bound. + else if (cutNode && singularBeta > beta) + return beta; } else if ( givesCheck // Check extension (~2 Elo) && pos.see_ge(move)) From 70880b8e247c94d0a16a2fb50b41827726e00742 Mon Sep 17 00:00:00 2001 From: MJZ1977 <37274752+MJZ1977@users.noreply.github.com> Date: Wed, 9 Jan 2019 15:05:28 +0100 Subject: [PATCH 8/9] Flag critical search tree in hash table Introducing new concept, saving principal lines into the transposition table to generate a "critical search tree" which we can reuse later for intelligent pruning/extension decisions. For instance in this patch we just reduce reduction for these lines. But a lot of other ideas are possible. To go further : tune some parameters, how to add or remove lines from the critical search tree, how to use these lines in search choices, etc. STC : LLR: 2.94 (-2.94,2.94) [0.50,4.50] Total: 59761 W: 13321 L: 12863 D: 33577 +2.23 ELO http://tests.stockfishchess.org/tests/view/5c34da5d0ebc596a450c53d3 LTC : LLR: 2.96 (-2.94,2.94) [0.00,3.50] Total: 26826 W: 4439 L: 4191 D: 18196 +2.9 ELO http://tests.stockfishchess.org/tests/view/5c35ceb00ebc596a450c65b2 Special thanks to Miguel Lahoz for his help in transposition table in/out. Bench: 3399866 --- src/search.cpp | 26 +++++++++++++++++++------- src/tt.cpp | 12 ++++++------ src/tt.h | 8 +++++--- tests/instrumented.sh | 1 + 4 files changed, 31 insertions(+), 16 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index c8e6c8b65..b7e04fad2 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -577,7 +577,7 @@ namespace { Move ttMove, move, excludedMove, bestMove; Depth extension, newDepth; Value bestValue, value, ttValue, eval, maxValue, pureStaticEval; - bool ttHit, inCheck, givesCheck, improving; + bool ttHit, pvHit, inCheck, givesCheck, improving; bool captureOrPromotion, doFullDepthSearch, moveCountPruning, skipQuiets, ttCapture, pvExact; Piece movedPiece; int moveCount, captureCount, quietCount; @@ -643,6 +643,7 @@ namespace { ttValue = ttHit ? value_from_tt(tte->value(), ss->ply) : VALUE_NONE; ttMove = rootNode ? thisThread->rootMoves[thisThread->pvIdx].pv[0] : ttHit ? tte->move() : MOVE_NONE; + pvHit = ttHit ? tte->pv_hit() : false; // At non-PV nodes we check for an early TT cutoff if ( !PvNode @@ -676,6 +677,11 @@ namespace { return ttValue; } + if ( depth > 6 * ONE_PLY + && !excludedMove + && PvNode) + pvHit = true; + // Step 5. Tablebases probe if (!rootNode && TB::Cardinality) { @@ -709,7 +715,7 @@ namespace { if ( b == BOUND_EXACT || (b == BOUND_LOWER ? value >= beta : value <= alpha)) { - tte->save(posKey, value_to_tt(value, ss->ply), b, + tte->save(posKey, value_to_tt(value, ss->ply), pvHit, b, std::min(DEPTH_MAX - ONE_PLY, depth + 6 * ONE_PLY), MOVE_NONE, VALUE_NONE); @@ -760,7 +766,7 @@ namespace { else ss->staticEval = eval = pureStaticEval = -(ss-1)->staticEval + 2 * Eval::Tempo; - tte->save(posKey, VALUE_NONE, BOUND_NONE, DEPTH_NONE, MOVE_NONE, pureStaticEval); + tte->save(posKey, VALUE_NONE, pvHit, BOUND_NONE, DEPTH_NONE, MOVE_NONE, pureStaticEval); } // Step 7. Razoring (~2 Elo) @@ -875,6 +881,7 @@ namespace { tte = TT.probe(posKey, ttHit); ttValue = ttHit ? value_from_tt(tte->value(), ss->ply) : VALUE_NONE; ttMove = ttHit ? tte->move() : MOVE_NONE; + pvHit = ttHit ? tte->pv_hit() : false; } moves_loop: // When in check, search starts from here @@ -1035,6 +1042,10 @@ moves_loop: // When in check, search starts from here { Depth r = reduction(improving, depth, moveCount); + // Decrease reduction if position is or has been on the PV + if (pvHit && !PvNode) + r -= ONE_PLY; + // Decrease reduction if opponent's move count is high (~10 Elo) if ((ss-1)->moveCount > 15) r -= ONE_PLY; @@ -1217,7 +1228,7 @@ moves_loop: // When in check, search starts from here bestValue = std::min(bestValue, maxValue); if (!excludedMove) - tte->save(posKey, value_to_tt(bestValue, ss->ply), + tte->save(posKey, value_to_tt(bestValue, ss->ply), pvHit, bestValue >= beta ? BOUND_LOWER : PvNode && bestMove ? BOUND_EXACT : BOUND_UPPER, depth, bestMove, pureStaticEval); @@ -1247,7 +1258,7 @@ moves_loop: // When in check, search starts from here Move ttMove, move, bestMove; Depth ttDepth; Value bestValue, value, ttValue, futilityValue, futilityBase, oldAlpha; - bool ttHit, inCheck, givesCheck, evasionPrunable; + bool ttHit, pvHit, inCheck, givesCheck, evasionPrunable; int moveCount; if (PvNode) @@ -1281,6 +1292,7 @@ moves_loop: // When in check, search starts from here tte = TT.probe(posKey, ttHit); ttValue = ttHit ? value_from_tt(tte->value(), ss->ply) : VALUE_NONE; ttMove = ttHit ? tte->move() : MOVE_NONE; + pvHit = ttHit ? tte->pv_hit() : false; if ( !PvNode && ttHit @@ -1318,7 +1330,7 @@ moves_loop: // When in check, search starts from here if (bestValue >= beta) { if (!ttHit) - tte->save(posKey, value_to_tt(bestValue, ss->ply), BOUND_LOWER, + tte->save(posKey, value_to_tt(bestValue, ss->ply), pvHit, BOUND_LOWER, DEPTH_NONE, MOVE_NONE, ss->staticEval); return bestValue; @@ -1429,7 +1441,7 @@ moves_loop: // When in check, search starts from here if (inCheck && bestValue == -VALUE_INFINITE) return mated_in(ss->ply); // Plies to mate from the root - tte->save(posKey, value_to_tt(bestValue, ss->ply), + tte->save(posKey, value_to_tt(bestValue, ss->ply), pvHit, bestValue >= beta ? BOUND_LOWER : PvNode && bestValue > oldAlpha ? BOUND_EXACT : BOUND_UPPER, ttDepth, bestMove, ss->staticEval); diff --git a/src/tt.cpp b/src/tt.cpp index 653d081f8..d05de9163 100644 --- a/src/tt.cpp +++ b/src/tt.cpp @@ -31,7 +31,7 @@ TranspositionTable TT; // Our global transposition table /// TTEntry::save saves a TTEntry -void TTEntry::save(Key k, Value v, Bound b, Depth d, Move m, Value ev) { +void TTEntry::save(Key k, Value v, bool PvNode, Bound b, Depth d, Move m, Value ev) { assert(d / ONE_PLY * ONE_PLY == d); @@ -47,7 +47,7 @@ void TTEntry::save(Key k, Value v, Bound b, Depth d, Move m, Value ev) { key16 = (uint16_t)(k >> 48); value16 = (int16_t)v; eval16 = (int16_t)ev; - genBound8 = (uint8_t)(TT.generation8 | b); + genBound8 = (uint8_t)(TT.generation8 | PvNode << 2 | b); depth8 = (int8_t)(d / ONE_PLY); } } @@ -122,7 +122,7 @@ TTEntry* TranspositionTable::probe(const Key key, bool& found) const { for (int i = 0; i < ClusterSize; ++i) if (!tte[i].key16 || tte[i].key16 == key16) { - tte[i].genBound8 = uint8_t(generation8 | tte[i].bound()); // Refresh + tte[i].genBound8 = uint8_t(generation8 | tte[i].pv_hit() << 2 | tte[i].bound()); // Refresh return found = (bool)tte[i].key16, &tte[i]; } @@ -131,11 +131,11 @@ TTEntry* TranspositionTable::probe(const Key key, bool& found) const { TTEntry* replace = tte; for (int i = 1; i < ClusterSize; ++i) // Due to our packed storage format for generation and its cyclic - // nature we add 259 (256 is the modulus plus 3 to keep the lowest + // nature we add 263 (263 is the modulus plus 7 to keep the lowest // two bound bits from affecting the result) to calculate the entry // age correctly even after generation8 overflows into the next cycle. - if ( replace->depth8 - ((259 + generation8 - replace->genBound8) & 0xFC) * 2 - > tte[i].depth8 - ((259 + generation8 - tte[i].genBound8) & 0xFC) * 2) + if ( replace->depth8 - ((263 + generation8 - replace->genBound8) & 0xF8) + > tte[i].depth8 - ((263 + generation8 - tte[i].genBound8) & 0xF8)) replace = &tte[i]; return found = false, replace; diff --git a/src/tt.h b/src/tt.h index 2cf82f58d..8b98dbd52 100644 --- a/src/tt.h +++ b/src/tt.h @@ -30,7 +30,8 @@ /// move 16 bit /// value 16 bit /// eval value 16 bit -/// generation 6 bit +/// generation 5 bit +/// PvNode 1 bit /// bound type 2 bit /// depth 8 bit @@ -40,8 +41,9 @@ struct TTEntry { Value value() const { return (Value)value16; } Value eval() const { return (Value)eval16; } Depth depth() const { return (Depth)(depth8 * int(ONE_PLY)); } + bool pv_hit() const { return (bool)(genBound8 & 0x4); } Bound bound() const { return (Bound)(genBound8 & 0x3); } - void save(Key k, Value v, Bound b, Depth d, Move m, Value ev); + void save(Key k, Value v, bool PvNode, Bound b, Depth d, Move m, Value ev); private: friend class TranspositionTable; @@ -76,7 +78,7 @@ class TranspositionTable { public: ~TranspositionTable() { free(mem); } - void new_search() { generation8 += 4; } // Lower 2 bits are used by Bound + void new_search() { generation8 += 8; } // Lower 3 bits are used by PV flag and Bound TTEntry* probe(const Key key, bool& found) const; int hashfull() const; void resize(size_t mbSize); diff --git a/tests/instrumented.sh b/tests/instrumented.sh index 137d0e4af..eb70466fc 100755 --- a/tests/instrumented.sh +++ b/tests/instrumented.sh @@ -45,6 +45,7 @@ race:TTEntry::bound race:TTEntry::save race:TTEntry::value race:TTEntry::eval +race:TTEntry::pv_hit race:TranspositionTable::probe race:TranspositionTable::hashfull From d2acdac1012cfbd8563fbe70157b2adbb05b2002 Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Wed, 9 Jan 2019 16:14:34 +0100 Subject: [PATCH 9/9] Small improvements to the CI infrastructure - avoid inlining for the debug testing so that suppressions work - provide more output for triggered errors No functional change. --- .travis.yml | 2 +- tests/instrumented.sh | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index ea5bda1d2..c4f68ae56 100644 --- a/.travis.yml +++ b/.travis.yml @@ -63,7 +63,7 @@ script: # # Valgrind # - - export CXXFLAGS=-O1 + - export CXXFLAGS="-O1 -fno-inline" - if [ -x "$(command -v valgrind )" ]; then make clean && make -j2 ARCH=x86-64 debug=yes optimize=no build > /dev/null && ../tests/instrumented.sh --valgrind; fi - if [ -x "$(command -v valgrind )" ]; then ../tests/instrumented.sh --valgrind-thread; fi # diff --git a/tests/instrumented.sh b/tests/instrumented.sh index eb70466fc..5156e02f4 100755 --- a/tests/instrumented.sh +++ b/tests/instrumented.sh @@ -28,14 +28,14 @@ case $1 in echo "sanitizer-undefined testing started" prefix='!' exeprefix='' - postfix='2>&1 | grep "runtime error:"' + postfix='2>&1 | grep -A50 "runtime error:"' threads="1" ;; --sanitizer-thread) echo "sanitizer-thread testing started" prefix='!' exeprefix='' - postfix='2>&1 | grep "WARNING: ThreadSanitizer:"' + postfix='2>&1 | grep -A50 "WARNING: ThreadSanitizer:"' threads="2" cat << EOF > tsan.supp