From: Steinar H. Gunderson Date: Sat, 8 Aug 2020 14:40:07 +0000 (+0200) Subject: Merge remote-tracking branch 'upstream/master' into HEAD X-Git-Url: https://git.sesse.net/?p=stockfish;a=commitdiff_plain;h=4004bcf3a48c47450344e93fcf186e3eb5d32165;hp=-c Merge remote-tracking branch 'upstream/master' into HEAD --- 4004bcf3a48c47450344e93fcf186e3eb5d32165 diff --combined src/Makefile index 9b10a195,4741e722..59179812 --- a/src/Makefile +++ b/src/Makefile @@@ -39,13 -39,11 +39,14 @@@ PGOBENCH = ./$(EXE) benc SRCS = benchmark.cpp bitbase.cpp bitboard.cpp endgame.cpp evaluate.cpp main.cpp \ material.cpp misc.cpp movegen.cpp movepick.cpp pawns.cpp position.cpp psqt.cpp \ search.cpp thread.cpp timeman.cpp tt.cpp uci.cpp ucioption.cpp tune.cpp syzygy/tbprobe.cpp \ - nnue/evaluate_nnue.cpp nnue/features/half_kp.cpp ++ nnue/evaluate_nnue.cpp nnue/features/half_kp.cpp \ + hashprobe.grpc.pb.cc hashprobe.pb.cc +CLISRCS = client.cpp hashprobe.grpc.pb.cc hashprobe.pb.cc uci.cpp OBJS = $(notdir $(SRCS:.cpp=.o)) +CLIOBJS = $(notdir $(CLISRCS:.cpp=.o)) - VPATH = syzygy + VPATH = syzygy:nnue:nnue/features ### Establish the operating system name KERNEL = $(shell uname -s) @@@ -70,7 -68,14 +71,14 @@@ endi # prefetch = yes/no --- -DUSE_PREFETCH --- Use prefetch asm-instruction # popcnt = yes/no --- -DUSE_POPCNT --- Use popcnt asm-instruction # sse = yes/no --- -msse --- Use Intel Streaming SIMD Extensions + # sse3 = yes/no --- -msse3 --- Use Intel Streaming SIMD Extensions 3 + # ssse3 = yes/no --- -mssse3 --- Use Intel Supplemental Streaming SIMD Extensions 3 + # sse41 = yes/no --- -msse4.1 --- Use Intel Streaming SIMD Extensions 4.1 + # sse42 = yes/no --- -msse4.2 --- Use Intel Streaming SIMD Extensions 4.2 + # avx2 = yes/no --- -mavx2 --- Use Intel Advanced Vector Extensions 2 # pext = yes/no --- -DUSE_PEXT --- Use pext x86_64 asm-instruction + # avx512 = yes/no --- -mavx512bw --- Use Intel Advanced Vector Extensions 512 + # neon = yes/no --- -DUSE_NEON --- Use ARM SIMD architecture # # Note that Makefile is space sensitive, so when adding new architectures # or modifying existing flags, you have to make sure there are no extra spaces @@@ -84,7 -89,15 +92,15 @@@ bits = 6 prefetch = no popcnt = no sse = no + sse3 = no + ssse3 = no + sse41 = no + sse42 = no + avx2 = no pext = no + avx512 = no + neon = no + ARCH = x86-64-modern ### 2.2 Architecture specific ifeq ($(ARCH),general-32) @@@ -114,11 -127,70 +130,70 @@@ ifeq ($(ARCH),x86-64 sse = yes endif + ifeq ($(ARCH),x86-64-sse3) + arch = x86_64 + prefetch = yes + sse = yes + sse3 = yes + endif + + ifeq ($(ARCH),x86-64-sse3-popcnt) + arch = x86_64 + prefetch = yes + sse = yes + sse3 = yes + popcnt = yes + endif + + ifeq ($(ARCH),x86-64-ssse3) + arch = x86_64 + prefetch = yes + sse = yes + sse3 = yes + ssse3 = yes + endif + + ifeq ($(ARCH),x86-64-sse41) + arch = x86_64 + prefetch = yes + popcnt = yes + sse = yes + sse3 = yes + ssse3 = yes + sse41 = yes + endif + ifeq ($(ARCH),x86-64-modern) arch = x86_64 prefetch = yes popcnt = yes sse = yes + sse3 = yes + ssse3 = yes + sse41 = yes + endif + + ifeq ($(ARCH),x86-64-sse42) + arch = x86_64 + prefetch = yes + popcnt = yes + sse = yes + sse3 = yes + ssse3 = yes + sse41 = yes + sse42 = yes + endif + + ifeq ($(ARCH),x86-64-avx2) + arch = x86_64 + prefetch = yes + popcnt = yes + sse = yes + sse3 = yes + ssse3 = yes + sse41 = yes + sse42 = yes + avx2 = yes endif ifeq ($(ARCH),x86-64-bmi2) @@@ -126,9 -198,28 +201,28 @@@ prefetch = yes popcnt = yes sse = yes + sse3 = yes + ssse3 = yes + sse41 = yes + sse42 = yes + avx2 = yes pext = yes endif + ifeq ($(ARCH),x86-64-avx512) + arch = x86_64 + prefetch = yes + popcnt = yes + sse = yes + sse3 = yes + ssse3 = yes + sse41 = yes + sse42 = yes + avx2 = yes + pext = yes + avx512 = yes + endif + ifeq ($(ARCH),armv7) arch = armv7 prefetch = yes @@@ -139,6 -230,14 +233,14 @@@ ifeq ($(ARCH),armv8 arch = armv8-a prefetch = yes popcnt = yes + neon = yes + endif + + ifeq ($(ARCH),apple-silicon) + arch = arm64 + prefetch = yes + popcnt = yes + neon = yes endif ifeq ($(ARCH),ppc-32) @@@ -157,8 -256,8 +259,8 @@@ endi ### ========================================================================== ### 3.1 Selecting compiler (default = gcc) - CXXFLAGS += -Wall -Wcast-qual -fno-exceptions -std=c++11 $(EXTRACXXFLAGS) - DEPENDFLAGS += -std=c++11 + CXXFLAGS += -Wall -Wcast-qual -fno-exceptions -std=c++17 $(EXTRACXXFLAGS) + DEPENDFLAGS += -std=c++17 LDFLAGS += $(EXTRALDFLAGS) ifeq ($(COMP),) @@@ -168,7 -267,7 +270,7 @@@ endi ifeq ($(COMP),gcc) comp=gcc CXX=g++ - CXXFLAGS += -pedantic -Wextra -Wshadow + CXXFLAGS += -pedantic -Wextra ifeq ($(ARCH),$(filter $(ARCH),armv7 armv8)) ifeq ($(OS),Android) @@@ -252,8 -351,8 +354,8 @@@ endi endif ifeq ($(KERNEL),Darwin) - CXXFLAGS += -arch $(arch) -mmacosx-version-min=10.9 - LDFLAGS += -arch $(arch) -mmacosx-version-min=10.9 + CXXFLAGS += -arch $(arch) -mmacosx-version-min=10.15 + LDFLAGS += -arch $(arch) -mmacosx-version-min=10.15 endif ### Travis CI script uses COMPILER to overwrite CXX @@@ -286,14 -385,14 +388,14 @@@ endi ### 3.2.2 Debugging with undefined behavior sanitizers ifneq ($(sanitize),no) - CXXFLAGS += -g3 -fsanitize=$(sanitize) -fuse-ld=gold - LDFLAGS += -fsanitize=$(sanitize) -fuse-ld=gold + CXXFLAGS += -g3 -fsanitize=$(sanitize) + LDFLAGS += -fsanitize=$(sanitize) endif ### 3.3 Optimization ifeq ($(optimize),yes) - CXXFLAGS += -O3 + CXXFLAGS += -O3 -g ifeq ($(comp),gcc) ifeq ($(OS), Android) @@@ -325,7 -424,7 +427,7 @@@ endi ### 3.6 popcnt ifeq ($(popcnt),yes) - ifeq ($(arch),$(filter $(arch),ppc64 armv8-a)) + ifeq ($(arch),$(filter $(arch),ppc64 armv8-a arm64)) CXXFLAGS += -DUSE_POPCNT else ifeq ($(comp),icc) CXXFLAGS += -msse3 -DUSE_POPCNT @@@ -334,11 -433,61 +436,61 @@@ endif endif + ifeq ($(avx2),yes) + CXXFLAGS += -DUSE_AVX2 + ifeq ($(comp),$(filter $(comp),gcc clang mingw)) + CXXFLAGS += -mavx2 + endif + endif + + ifeq ($(avx512),yes) + CXXFLAGS += -DUSE_AVX512 + ifeq ($(comp),$(filter $(comp),gcc clang mingw)) + CXXFLAGS += -mavx512bw + endif + endif + + ifeq ($(sse42),yes) + CXXFLAGS += -DUSE_SSE42 + ifeq ($(comp),$(filter $(comp),gcc clang mingw)) + CXXFLAGS += -msse4.2 + endif + endif + + ifeq ($(sse41),yes) + CXXFLAGS += -DUSE_SSE41 + ifeq ($(comp),$(filter $(comp),gcc clang mingw)) + CXXFLAGS += -msse4.1 + endif + endif + + ifeq ($(ssse3),yes) + CXXFLAGS += -DUSE_SSSE3 + ifeq ($(comp),$(filter $(comp),gcc clang mingw)) + CXXFLAGS += -mssse3 + endif + endif + + ifeq ($(sse3),yes) + CXXFLAGS += -DUSE_SSE3 + ifeq ($(comp),$(filter $(comp),gcc clang mingw)) + CXXFLAGS += -msse3 + endif + endif + + ifeq ($(neon),yes) + CXXFLAGS += -DUSE_NEON + endif + + ifeq ($(arch),x86_64) + CXXFLAGS += -DUSE_SSE2 + endif + ### 3.7 pext ifeq ($(pext),yes) CXXFLAGS += -DUSE_PEXT ifeq ($(comp),$(filter $(comp),gcc clang mingw)) - CXXFLAGS += -msse4 -mbmi2 + CXXFLAGS += -mbmi2 endif endif @@@ -384,15 -533,23 +536,23 @@@ help @echo "Supported targets:" @echo "" @echo "build > Standard build" - @echo "profile-build > PGO build" + @echo "profile-build > Standard build with PGO" @echo "strip > Strip executable" @echo "install > Install executable" @echo "clean > Clean up" + @echo "net > Download the default nnue net" @echo "" @echo "Supported archs:" @echo "" - @echo "x86-64-bmi2 > x86 64-bit with pext support (also enables SSE4)" - @echo "x86-64-modern > x86 64-bit with popcnt support (also enables SSE3)" + @echo "x86-64-avx512 > x86 64-bit with avx512 support" + @echo "x86-64-bmi2 > x86 64-bit with bmi2 support" + @echo "x86-64-avx2 > x86 64-bit with avx2 support" + @echo "x86-64-sse42 > x86 64-bit with sse42 support" + @echo "x86-64-modern > x86 64-bit with sse41 support (x86-64-sse41)" + @echo "x86-64-sse41 > x86 64-bit with sse41 support" + @echo "x86-64-ssse3 > x86 64-bit with ssse3 support" + @echo "x86-64-sse3-popcnt > x86 64-bit with sse3 and popcnt support" + @echo "x86-64-sse3 > x86 64-bit with sse3 support" @echo "x86-64 > x86 64-bit generic" @echo "x86-32 > x86 32-bit (also enables SSE)" @echo "x86-32-old > x86 32-bit fall back for old hardware" @@@ -400,6 -557,7 +560,7 @@@ @echo "ppc-32 > PPC 32-bit" @echo "armv7 > ARMv7 32-bit" @echo "armv8 > ARMv8 64-bit" + @echo "apple-silicon > Apple silicon ARM64" @echo "general-64 > unspecified 64-bit" @echo "general-32 > unspecified 32-bit" @echo "" @@@ -412,17 -570,20 +573,20 @@@ @echo "" @echo "Simple examples. If you don't know what to do, you likely want to run: " @echo "" - @echo "make build ARCH=x86-64 (This is for 64-bit systems)" - @echo "make build ARCH=x86-32 (This is for 32-bit systems)" + @echo "make -j build ARCH=x86-64 (This is for 64-bit systems)" + @echo "make -j build ARCH=x86-32 (This is for 32-bit systems)" @echo "" @echo "Advanced examples, for experienced users: " @echo "" - @echo "make build ARCH=x86-64 COMP=clang" - @echo "make profile-build ARCH=x86-64-bmi2 COMP=gcc COMPCXX=g++-4.8" + @echo "make -j build ARCH=x86-64-modern COMP=clang" + @echo "make -j profile-build ARCH=x86-64-bmi2 COMP=gcc COMPCXX=g++-4.8" @echo "" + @echo "The selected architecture $(ARCH) enables the following configuration: " + @echo "" + @$(MAKE) ARCH=$(ARCH) COMP=$(COMP) config-sanity - .PHONY: help build profile-build strip install clean objclean profileclean \ + .PHONY: help build profile-build strip install clean net objclean profileclean \ config-sanity icc-profile-use icc-profile-make gcc-profile-use gcc-profile-make \ clang-profile-use clang-profile-make @@@ -456,14 -617,21 +620,21 @@@ install clean: objclean profileclean @rm -f .depend *~ core + net: + $(eval nnuenet := $(shell grep EvalFile ucioption.cpp | grep Option | sed 's/.*\(nn-[a-z0-9]\{12\}.nnue\).*/\1/')) + @echo "Default net: $(nnuenet)" + $(eval nnuedownloadurl := https://tests.stockfishchess.org/api/nn/$(nnuenet)) + $(eval curl_or_wget := $(shell if hash curl 2>/dev/null; then echo "curl -sL"; elif hash wget 2>/dev/null; then echo "wget -qO-"; fi)) + @if test -f "$(nnuenet)"; then echo "Already available."; else echo "Downloading $(nnuedownloadurl)"; $(curl_or_wget) $(nnuedownloadurl) > $(nnuenet); fi + # clean binaries and objects objclean: - @rm -f $(EXE) *.o ./syzygy/*.o + @rm -f $(EXE) *.o ./syzygy/*.o ./nnue/*.o ./nnue/features/*.o # clean auxiliary profiling files profileclean: @rm -rf profdir - @rm -f bench.txt *.gcda *.gcno + @rm -f bench.txt *.gcda *.gcno ./syzygy/*.gcda ./nnue/*.gcda ./nnue/features/*.gcda @rm -f stockfish.profdata *.profraw default: @@@ -473,7 -641,7 +644,7 @@@ ### Section 5. Private Targets ### ========================================================================== -all: $(EXE) .depend +all: $(EXE) client .depend config-sanity: @echo "" @@@ -488,7 -656,14 +659,14 @@@ @echo "prefetch: '$(prefetch)'" @echo "popcnt: '$(popcnt)'" @echo "sse: '$(sse)'" + @echo "sse3: '$(sse3)'" + @echo "ssse3: '$(ssse3)'" + @echo "sse41: '$(sse41)'" + @echo "sse42: '$(sse42)'" + @echo "avx2: '$(avx2)'" @echo "pext: '$(pext)'" + @echo "avx512: '$(avx512)'" + @echo "neon: '$(neon)'" @echo "" @echo "Flags:" @echo "CXX: $(CXX)" @@@ -502,12 -677,19 +680,19 @@@ @test "$(optimize)" = "yes" || test "$(optimize)" = "no" @test "$(arch)" = "any" || test "$(arch)" = "x86_64" || test "$(arch)" = "i386" || \ test "$(arch)" = "ppc64" || test "$(arch)" = "ppc" || \ - test "$(arch)" = "armv7" || test "$(arch)" = "armv8-a" + test "$(arch)" = "armv7" || test "$(arch)" = "armv8-a" || test "$(arch)" = "arm64" @test "$(bits)" = "32" || test "$(bits)" = "64" @test "$(prefetch)" = "yes" || test "$(prefetch)" = "no" @test "$(popcnt)" = "yes" || test "$(popcnt)" = "no" @test "$(sse)" = "yes" || test "$(sse)" = "no" + @test "$(sse3)" = "yes" || test "$(sse3)" = "no" + @test "$(ssse3)" = "yes" || test "$(ssse3)" = "no" + @test "$(sse41)" = "yes" || test "$(sse41)" = "no" + @test "$(sse42)" = "yes" || test "$(sse42)" = "no" + @test "$(avx2)" = "yes" || test "$(avx2)" = "no" @test "$(pext)" = "yes" || test "$(pext)" = "no" + @test "$(avx512)" = "yes" || test "$(avx512)" = "no" + @test "$(neon)" = "yes" || test "$(neon)" = "no" @test "$(comp)" = "gcc" || test "$(comp)" = "icc" || test "$(comp)" = "mingw" || test "$(comp)" = "clang" $(EXE): $(OBJS) @@@ -549,32 -731,6 +734,32 @@@ icc-profile-use EXTRACXXFLAGS='-prof_use -prof_dir ./profdir' \ all +### GRPC + +PROTOS_PATH = . +PROTOC = protoc +GRPC_CPP_PLUGIN = grpc_cpp_plugin +GRPC_CPP_PLUGIN_PATH ?= `which $(GRPC_CPP_PLUGIN)` + +%.grpc.pb.h %.grpc.pb.cc: %.proto + $(PROTOC) -I $(PROTOS_PATH) --grpc_out=. --plugin=protoc-gen-grpc=$(GRPC_CPP_PLUGIN_PATH) $< + +# oh my +%.cpp: %.cc + cp $< $@ + +%.pb.h %.pb.cc: %.proto + $(PROTOC) -I $(PROTOS_PATH) --cpp_out=. $< + +#LDFLAGS += -Wl,-Bstatic -Wl,-\( -lprotobuf -lgrpc++_unsecure -lgrpc_unsecure -lgrpc -lz -Wl,-\) -Wl,-Bdynamic -ldl +LDFLAGS += /usr/lib/x86_64-linux-gnu/libprotobuf.a /usr/lib/x86_64-linux-gnu/libgrpc++_unsecure.a /usr/lib/x86_64-linux-gnu/libgrpc_unsecure.a /usr/lib/x86_64-linux-gnu/libgrpc.a /usr/lib/x86_64-linux-gnu/libcares.a -ldl -lz +#LDFLAGS += /usr/lib/x86_64-linux-gnu/libprotobuf.a /usr/lib/libgrpc++_unsecure.a /usr/lib/libgrpc_unsecure.a /usr/lib/libgrpc.a /usr/lib/x86_64-linux-gnu/libcares.a -ldl -lz + +client: $(CLIOBJS) + $(CXX) -o $@ $(CLIOBJS) $(LDFLAGS) + +# Other stuff + .depend: -@$(CXX) $(DEPENDFLAGS) -MM $(SRCS) > $@ 2> /dev/null diff --combined src/main.cpp index 98cbfc97,fbad6622..25d8f415 --- a/src/main.cpp +++ b/src/main.cpp @@@ -1,8 -1,6 +1,6 @@@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2008 Tord Romstad (Glaurung author) - Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad - Copyright (C) 2015-2020 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad + Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@@ -18,10 -16,7 +16,10 @@@ along with this program. If not, see . */ +#include #include +#include +#include #include "bitboard.h" #include "endgame.h" @@@ -32,197 -27,6 +30,197 @@@ #include "uci.h" #include "syzygy/tbprobe.h" +#include +#include +#include +#include "hashprobe.h" +#include "hashprobe.grpc.pb.h" +#include "tt.h" + +using grpc::Server; +using grpc::ServerBuilder; +using grpc::ServerContext; +using grpc::Status; +using grpc::StatusCode; +using namespace hashprobe; + +Status HashProbeImpl::Probe(ServerContext* context, + const HashProbeRequest* request, + HashProbeResponse *response) { + Position pos; + StateInfo st; + pos.set(request->fen(), /*isChess960=*/false, &st, Threads.main()); + if (!pos.pos_is_ok()) { + return Status(StatusCode::INVALID_ARGUMENT, "Invalid FEN"); + } + + bool invert = (pos.side_to_move() == BLACK); + StateListPtr setup_states = StateListPtr(new std::deque(1)); + + ProbeMove(&pos, setup_states.get(), invert, response->mutable_root()); + + MoveList moves(pos); + for (const ExtMove* em = moves.begin(); em != moves.end(); ++em) { + HashProbeLine *line = response->add_line(); + FillMove(&pos, em->move, line->mutable_move()); + setup_states->push_back(StateInfo()); + pos.do_move(em->move, setup_states->back()); + ProbeMove(&pos, setup_states.get(), !invert, line); + pos.undo_move(em->move); + } + + return Status::OK; +} + +void HashProbeImpl::FillMove(Position *pos, Move move, HashProbeMove* decoded) { + if (!is_ok(move)) return; + + Square from = from_sq(move); + Square to = to_sq(move); + + if (type_of(move) == CASTLING) { + to = make_square(to > from ? FILE_G : FILE_C, rank_of(from)); + } + + Piece moved_piece = pos->moved_piece(move); + std::string pretty; + if (type_of(move) == CASTLING) { + if (to > from) { + pretty = "O-O"; + } else { + pretty = "O-O-O"; + } + } else if (type_of(moved_piece) == PAWN) { + if (type_of(move) == ENPASSANT || pos->piece_on(to) != NO_PIECE) { + // Capture. + pretty = char('a' + file_of(from)); + pretty += "x"; + } + pretty += UCI::square(to); + if (type_of(move) == PROMOTION) { + pretty += "="; + pretty += " PNBRQK"[promotion_type(move)]; + } + } else { + pretty = " PNBRQK"[type_of(moved_piece)]; + Bitboard attackers = pos->attackers_to(to) & pos->pieces(color_of(moved_piece), type_of(moved_piece)); + if (more_than_one(attackers)) { + // Remove all illegal moves to disambiguate. + Bitboard att_copy = attackers; + while (att_copy) { + Square s = pop_lsb(&att_copy); + Move m = make_move(s, to); + if (!pos->pseudo_legal(m) || !pos->legal(m)) { + attackers &= ~SquareBB[s]; + } + } + } + if (more_than_one(attackers)) { + // Disambiguate by file if possible. + Bitboard attackers_this_file = attackers & file_bb(file_of(from)); + if (attackers != attackers_this_file) { + pretty += char('a' + file_of(from)); + attackers = attackers_this_file; + } + if (more_than_one(attackers)) { + // Still ambiguous, so need to disambiguate by rank. + pretty += char('1' + rank_of(from)); + } + } + + if (type_of(move) == ENPASSANT || pos->piece_on(to) != NO_PIECE) { + pretty += "x"; + } + + pretty += UCI::square(to); + } + + if (pos->gives_check(move)) { + // Check if mate. + StateInfo si; + pos->do_move(move, si, true); + if (MoveList(*pos).size() > 0) { + pretty += "+"; + } else { + pretty += "#"; + } + pos->undo_move(move); + } + + decoded->set_pretty(pretty); +} + +void HashProbeImpl::ProbeMove(Position* pos, std::deque* setup_states, bool invert, HashProbeLine* response) { + bool found; + TTEntry *entry = TT.probe(pos->key(), found); + response->set_found(found); + if (found) { + Value value = entry->value(); + Value eval = entry->eval(); + Bound bound = entry->bound(); + + if (invert) { + value = -value; + eval = -eval; + if (bound == BOUND_UPPER) { + bound = BOUND_LOWER; + } else if (bound == BOUND_LOWER) { + bound = BOUND_UPPER; + } + } + + response->set_depth(entry->depth()); + FillValue(eval, response->mutable_eval()); + if (entry->depth() > DEPTH_NONE) { + FillValue(value, response->mutable_value()); + } + response->set_bound(HashProbeLine::ValueBound(bound)); + + // Follow the PV until we hit an illegal move. + std::stack pv; + std::set seen; + while (found && is_ok(entry->move()) && + pos->pseudo_legal(entry->move()) && + pos->legal(entry->move())) { + FillMove(pos, entry->move(), response->add_pv()); + if (seen.count(pos->key())) break; + pv.push(entry->move()); + seen.insert(pos->key()); + setup_states->push_back(StateInfo()); + pos->do_move(entry->move(), setup_states->back()); + entry = TT.probe(pos->key(), found); + } + + // Unroll the PV back again, so the Position object remains unchanged. + while (!pv.empty()) { + pos->undo_move(pv.top()); + pv.pop(); + } + } +} + +void HashProbeImpl::FillValue(Value value, HashProbeScore* score) { + if (abs(value) < VALUE_MATE - MAX_PLY) { + score->set_score_type(HashProbeScore::SCORE_CP); + score->set_score_cp(value * 100 / PawnValueEg); + } else { + score->set_score_type(HashProbeScore::SCORE_MATE); + score->set_score_mate((value > 0 ? VALUE_MATE - value + 1 : -VALUE_MATE - value) / 2); + } +} + +HashProbeThread::HashProbeThread(const std::string &server_address) { + builder.AddListeningPort(server_address, grpc::InsecureServerCredentials()); + builder.RegisterService(&service); + server = std::move(builder.BuildAndStart()); + std::cout << "Server listening on " << server_address << std::endl; + std::thread([this]{ server->Wait(); }).detach(); +} + +void HashProbeThread::Shutdown() { + server->Shutdown(); +} + namespace PSQT { void init(); } @@@ -240,6 -44,7 +238,7 @@@ int main(int argc, char* argv[]) Endgames::init(); Threads.set(size_t(Options["Threads"])); Search::clear(); // After threads are up + Eval::init_NNUE(); UCI::loop(argc, argv); diff --combined src/misc.cpp index d9c0679b,3d7c75e5..4ff52f48 --- a/src/misc.cpp +++ b/src/misc.cpp @@@ -1,8 -1,6 +1,6 @@@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2008 Tord Romstad (Glaurung author) - Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad - Copyright (C) 2015-2020 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad + Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@@ -46,6 -44,7 +44,7 @@@ typedef bool(*fun3_t)(HANDLE, CONST GRO #include #include #include + #include #if defined(__linux__) && !defined(__ANDROID__) #include @@@ -145,13 -144,10 +144,11 @@@ const string engine_info(bool to_uci) { date >> month >> day >> year; ss << setw(2) << day << setw(2) << (1 + months.find(month) / 4) << year.substr(2); + ss << "-asn"; } - ss << (Is64Bit ? " 64" : "") - << (HasPext ? " BMI2" : (HasPopCnt ? " POPCNT" : "")) - << (to_uci ? "\nid author ": " by ") - << "T. Romstad, M. Costalba, J. Kiiski, G. Linscott"; + ss << (to_uci ? "\nid author ": " by ") + << "the Stockfish developers (see AUTHORS file)"; return ss.str(); } @@@ -216,7 -212,33 +213,33 @@@ const std::string compiler_info() compiler += " on unknown system"; #endif - compiler += "\n __VERSION__ macro expands to: "; + compiler += "\nCompilation settings include: "; + compiler += (Is64Bit ? " 64bit" : " 32bit"); + #if defined(USE_AVX512) + compiler += " AVX512"; + #endif + #if defined(USE_AVX2) + compiler += " AVX2"; + #endif + #if defined(USE_SSE42) + compiler += " SSE42"; + #endif + #if defined(USE_SSE41) + compiler += " SSE41"; + #endif + #if defined(USE_SSSE3) + compiler += " SSSE3"; + #endif + #if defined(USE_SSE3) + compiler += " SSE3"; + #endif + compiler += (HasPext ? " BMI2" : ""); + compiler += (HasPopCnt ? " POPCNT" : ""); + #if !defined(NDEBUG) + compiler += " DEBUG"; + #endif + + compiler += "\n__VERSION__ macro expands to: "; #ifdef __VERSION__ compiler += __VERSION__; #else @@@ -294,6 -316,29 +317,29 @@@ void prefetch(void* addr) #endif + /// Wrappers for systems where the c++17 implementation doesn't guarantee the availability of aligned_alloc. + /// Memory allocated with std_aligned_alloc must be freed with std_aligned_free. + /// + + void* std_aligned_alloc(size_t alignment, size_t size) { + #if defined(__APPLE__) + return aligned_alloc(alignment, size); + #elif defined(_WIN32) + return _mm_malloc(size, alignment); + #else + return std::aligned_alloc(alignment, size); + #endif + } + + void std_aligned_free(void* ptr) { + #if defined(__APPLE__) + free(ptr); + #elif defined(_WIN32) + _mm_free(ptr); + #else + free(ptr); + #endif + } /// aligned_ttmem_alloc() will return suitably aligned memory, and if possible use large pages. /// The returned pointer is the aligned one, while the mem argument is the one that needs diff --combined src/position.cpp index 57f731d4,46e5d78b..7b01172f --- a/src/position.cpp +++ b/src/position.cpp @@@ -1,8 -1,6 +1,6 @@@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2008 Tord Romstad (Glaurung author) - Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad - Copyright (C) 2015-2020 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad + Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@@ -200,6 -198,9 +198,9 @@@ Position& Position::set(const string& f std::fill_n(&pieceList[0][0], sizeof(pieceList) / sizeof(Square), SQ_NONE); st = si; + // Each piece on board gets a unique ID used to track the piece later + PieceId piece_id, next_piece_id = PIECE_ID_ZERO; + ss >> std::noskipws; // 1. Piece placement @@@ -213,7 -214,19 +214,19 @@@ else if ((idx = PieceToChar.find(token)) != string::npos) { - put_piece(Piece(idx), sq); + auto pc = Piece(idx); + put_piece(pc, sq); + + if (Eval::useNNUE) + { + // Kings get a fixed ID, other pieces get ID in order of placement + piece_id = + (idx == W_KING) ? PIECE_ID_WKING : + (idx == B_KING) ? PIECE_ID_BKING : + next_piece_id++; + evalList.put_piece(piece_id, sq, pc); + } + ++sq; } } @@@ -283,6 -296,8 +296,6 @@@ thisThread = th; set_state(st); - assert(pos_is_ok()); - return *this; } @@@ -703,6 -718,14 +716,14 @@@ void Position::do_move(Move m, StateInf ++st->rule50; ++st->pliesFromNull; + // Used by NNUE + st->accumulator.computed_accumulation = false; + st->accumulator.computed_score = false; + PieceId dp0 = PIECE_ID_NONE; + PieceId dp1 = PIECE_ID_NONE; + auto& dp = st->dirtyPiece; + dp.dirty_num = 1; + Color us = sideToMove; Color them = ~us; Square from = from_sq(m); @@@ -750,6 -773,16 +771,16 @@@ else st->nonPawnMaterial[them] -= PieceValue[MG][captured]; + if (Eval::useNNUE) + { + dp.dirty_num = 2; // 2 pieces moved + dp1 = piece_id_on(capsq); + dp.pieceId[1] = dp1; + dp.old_piece[1] = evalList.piece_with_id(dp1); + evalList.put_piece(dp1, capsq, NO_PIECE); + dp.new_piece[1] = evalList.piece_with_id(dp1); + } + // Update board and piece lists remove_piece(capsq); @@@ -785,7 -818,18 +816,18 @@@ // Move the piece. The tricky Chess960 castling is handled earlier if (type_of(m) != CASTLING) + { + if (Eval::useNNUE) + { + dp0 = piece_id_on(from); + dp.pieceId[0] = dp0; + dp.old_piece[0] = evalList.piece_with_id(dp0); + evalList.put_piece(dp0, to, pc); + dp.new_piece[0] = evalList.piece_with_id(dp0); + } + move_piece(from, to); + } // If the moving piece is a pawn do some special extra work if (type_of(pc) == PAWN) @@@ -808,6 -852,13 +850,13 @@@ remove_piece(to); put_piece(promotion, to); + if (Eval::useNNUE) + { + dp0 = piece_id_on(to); + evalList.put_piece(dp0, to, promotion); + dp.new_piece[0] = evalList.piece_with_id(dp0); + } + // Update hash keys k ^= Zobrist::psq[pc][to] ^ Zobrist::psq[promotion][to]; st->pawnKey ^= Zobrist::psq[pc][to]; @@@ -899,6 -950,12 +948,12 @@@ void Position::undo_move(Move m) { move_piece(to, from); // Put the piece back at the source square + if (Eval::useNNUE) + { + PieceId dp0 = st->dirtyPiece.pieceId[0]; + evalList.put_piece(dp0, from, pc); + } + if (st->capturedPiece) { Square capsq = to; @@@ -915,6 -972,14 +970,14 @@@ } put_piece(st->capturedPiece, capsq); // Restore the captured piece + + if (Eval::useNNUE) + { + PieceId dp1 = st->dirtyPiece.pieceId[1]; + assert(evalList.piece_with_id(dp1).from[WHITE] == PS_NONE); + assert(evalList.piece_with_id(dp1).from[BLACK] == PS_NONE); + evalList.put_piece(dp1, capsq, st->capturedPiece); + } } } @@@ -936,6 -1001,34 +999,34 @@@ void Position::do_castling(Color us, Sq rto = relative_square(us, kingSide ? SQ_F1 : SQ_D1); to = relative_square(us, kingSide ? SQ_G1 : SQ_C1); + if (Eval::useNNUE) + { + PieceId dp0, dp1; + auto& dp = st->dirtyPiece; + dp.dirty_num = 2; // 2 pieces moved + + if (Do) + { + dp0 = piece_id_on(from); + dp1 = piece_id_on(rfrom); + dp.pieceId[0] = dp0; + dp.old_piece[0] = evalList.piece_with_id(dp0); + evalList.put_piece(dp0, to, make_piece(us, KING)); + dp.new_piece[0] = evalList.piece_with_id(dp0); + dp.pieceId[1] = dp1; + dp.old_piece[1] = evalList.piece_with_id(dp1); + evalList.put_piece(dp1, rto, make_piece(us, ROOK)); + dp.new_piece[1] = evalList.piece_with_id(dp1); + } + else + { + dp0 = piece_id_on(to); + dp1 = piece_id_on(rto); + evalList.put_piece(dp0, from, make_piece(us, KING)); + evalList.put_piece(dp1, rfrom, make_piece(us, ROOK)); + } + } + // Remove both pieces first since squares could overlap in Chess960 remove_piece(Do ? from : to); remove_piece(Do ? rfrom : rto); @@@ -953,7 -1046,14 +1044,14 @@@ void Position::do_null_move(StateInfo& assert(!checkers()); assert(&newSt != st); - std::memcpy(&newSt, st, sizeof(StateInfo)); + if (Eval::useNNUE) + { + std::memcpy(&newSt, st, sizeof(StateInfo)); + st->accumulator.computed_score = false; + } + else + std::memcpy(&newSt, st, offsetof(StateInfo, accumulator)); + newSt.previous = st; st = &newSt; diff --combined src/syzygy/tbprobe.cpp index 764574f7,20215b96..61ba8121 --- a/src/syzygy/tbprobe.cpp +++ b/src/syzygy/tbprobe.cpp @@@ -1,7 -1,6 +1,6 @@@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (c) 2013 Ronald de Man - Copyright (C) 2016-2020 Marco Costalba, Lucas Braesch + Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@@ -75,7 -74,7 +74,7 @@@ int MapB1H1H7[SQUARE_NB] int MapA1D1D4[SQUARE_NB]; int MapKK[10][SQUARE_NB]; // [MapA1D1D4][SQUARE_NB] -int Binomial[6][SQUARE_NB]; // [k][n] k elements from a set of n elements +int Binomial[7][SQUARE_NB]; // [k][n] k elements from a set of n elements int LeadPawnIdx[6][SQUARE_NB]; // [leadPawnsCnt][SQUARE_NB] int LeadPawnsSize[6][4]; // [leadPawnsCnt][FILE_A..FILE_D] @@@ -1320,7 -1319,7 +1319,7 @@@ void Tablebases::init(const std::string Binomial[0][0] = 1; for (int n = 1; n < 64; n++) // Squares - for (int k = 0; k < 6 && k <= n; ++k) // Pieces + for (int k = 0; k < 7 && k <= n; ++k) // Pieces Binomial[k][n] = (k > 0 ? Binomial[k - 1][n - 1] : 0) + (k < n ? Binomial[k ][n - 1] : 0); diff --combined src/ucioption.cpp index 5982f26a,faeb78ae..79a2385a --- a/src/ucioption.cpp +++ b/src/ucioption.cpp @@@ -1,8 -1,6 +1,6 @@@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2008 Tord Romstad (Glaurung author) - Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad - Copyright (C) 2015-2020 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad + Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@@ -28,13 -26,11 +26,13 @@@ #include "thread.h" #include "tt.h" #include "uci.h" +#include "hashprobe.h" #include "syzygy/tbprobe.h" using std::string; UCI::OptionsMap Options; // Global object +std::unique_ptr hash_probe_thread; namespace UCI { @@@ -44,13 -40,8 +42,15 @@@ void on_hash_size(const Option& o) { TT void on_logger(const Option& o) { start_logger(o); } void on_threads(const Option& o) { Threads.set(size_t(o)); } void on_tb_path(const Option& o) { Tablebases::init(o); } + void on_use_NNUE(const Option& ) { Eval::init_NNUE(); } + void on_eval_file(const Option& ) { Eval::init_NNUE(); } +void on_rpc_server_address(const Option& o) { + if (hash_probe_thread) { + hash_probe_thread->Shutdown(); + } + std::string addr = o; + hash_probe_thread.reset(new HashProbeThread(addr)); +} /// Our case insensitive less() function as required by UCI protocol bool CaseInsensitiveLess::operator() (const string& s1, const string& s2) const { @@@ -87,7 -78,8 +87,9 @@@ void init(OptionsMap& o) o["SyzygyProbeDepth"] << Option(1, 1, 100); o["Syzygy50MoveRule"] << Option(true); o["SyzygyProbeLimit"] << Option(7, 0, 7); + o["Use NNUE"] << Option(false, on_use_NNUE); + o["EvalFile"] << Option("nn-9931db908a9b.nnue", on_eval_file); + o["RPCServerAddress"] << Option("", on_rpc_server_address); }