"Fossies" - the Fresh Open Source Software Archive

Member "stockfish-11-linux/src/misc.cpp" (18 Jan 2020, 11233 Bytes) of package /linux/privat/stockfish-11-linux.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the last Fossies "Diffs" side-by-side code changes report for "misc.cpp": 9-linux_vs_10-linux.

    1 /*
    2   Stockfish, a UCI chess playing engine derived from Glaurung 2.1
    3   Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
    4   Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
    5   Copyright (C) 2015-2020 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
    6 
    7   Stockfish is free software: you can redistribute it and/or modify
    8   it under the terms of the GNU General Public License as published by
    9   the Free Software Foundation, either version 3 of the License, or
   10   (at your option) any later version.
   11 
   12   Stockfish is distributed in the hope that it will be useful,
   13   but WITHOUT ANY WARRANTY; without even the implied warranty of
   14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   15   GNU General Public License for more details.
   16 
   17   You should have received a copy of the GNU General Public License
   18   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   19 */
   20 
   21 #ifdef _WIN32
   22 #if _WIN32_WINNT < 0x0601
   23 #undef  _WIN32_WINNT
   24 #define _WIN32_WINNT 0x0601 // Force to include needed API prototypes
   25 #endif
   26 
   27 #ifndef NOMINMAX
   28 #define NOMINMAX
   29 #endif
   30 
   31 #include <windows.h>
   32 // The needed Windows API for processor groups could be missed from old Windows
   33 // versions, so instead of calling them directly (forcing the linker to resolve
   34 // the calls at compile time), try to load them at runtime. To do this we need
   35 // first to define the corresponding function pointers.
   36 extern "C" {
   37 typedef bool(*fun1_t)(LOGICAL_PROCESSOR_RELATIONSHIP,
   38                       PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX, PDWORD);
   39 typedef bool(*fun2_t)(USHORT, PGROUP_AFFINITY);
   40 typedef bool(*fun3_t)(HANDLE, CONST GROUP_AFFINITY*, PGROUP_AFFINITY);
   41 }
   42 #endif
   43 
   44 #include <fstream>
   45 #include <iomanip>
   46 #include <iostream>
   47 #include <sstream>
   48 #include <vector>
   49 
   50 #include "misc.h"
   51 #include "thread.h"
   52 
   53 using namespace std;
   54 
   55 namespace {
   56 
   57 /// Version number. If Version is left empty, then compile date in the format
   58 /// DD-MM-YY and show in engine_info.
   59 const string Version = "11";
   60 
   61 /// Our fancy logging facility. The trick here is to replace cin.rdbuf() and
   62 /// cout.rdbuf() with two Tie objects that tie cin and cout to a file stream. We
   63 /// can toggle the logging of std::cout and std:cin at runtime whilst preserving
   64 /// usual I/O functionality, all without changing a single line of code!
   65 /// Idea from http://groups.google.com/group/comp.lang.c++/msg/1d941c0f26ea0d81
   66 
   67 struct Tie: public streambuf { // MSVC requires split streambuf for cin and cout
   68 
   69   Tie(streambuf* b, streambuf* l) : buf(b), logBuf(l) {}
   70 
   71   int sync() override { return logBuf->pubsync(), buf->pubsync(); }
   72   int overflow(int c) override { return log(buf->sputc((char)c), "<< "); }
   73   int underflow() override { return buf->sgetc(); }
   74   int uflow() override { return log(buf->sbumpc(), ">> "); }
   75 
   76   streambuf *buf, *logBuf;
   77 
   78   int log(int c, const char* prefix) {
   79 
   80     static int last = '\n'; // Single log file
   81 
   82     if (last == '\n')
   83         logBuf->sputn(prefix, 3);
   84 
   85     return last = logBuf->sputc((char)c);
   86   }
   87 };
   88 
   89 class Logger {
   90 
   91   Logger() : in(cin.rdbuf(), file.rdbuf()), out(cout.rdbuf(), file.rdbuf()) {}
   92  ~Logger() { start(""); }
   93 
   94   ofstream file;
   95   Tie in, out;
   96 
   97 public:
   98   static void start(const std::string& fname) {
   99 
  100     static Logger l;
  101 
  102     if (!fname.empty() && !l.file.is_open())
  103     {
  104         l.file.open(fname, ifstream::out);
  105 
  106         if (!l.file.is_open())
  107         {
  108             cerr << "Unable to open debug log file " << fname << endl;
  109             exit(EXIT_FAILURE);
  110         }
  111 
  112         cin.rdbuf(&l.in);
  113         cout.rdbuf(&l.out);
  114     }
  115     else if (fname.empty() && l.file.is_open())
  116     {
  117         cout.rdbuf(l.out.buf);
  118         cin.rdbuf(l.in.buf);
  119         l.file.close();
  120     }
  121   }
  122 };
  123 
  124 } // namespace
  125 
  126 /// engine_info() returns the full name of the current Stockfish version. This
  127 /// will be either "Stockfish <Tag> DD-MM-YY" (where DD-MM-YY is the date when
  128 /// the program was compiled) or "Stockfish <Version>", depending on whether
  129 /// Version is empty.
  130 
  131 const string engine_info(bool to_uci) {
  132 
  133   const string months("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec");
  134   string month, day, year;
  135   stringstream ss, date(__DATE__); // From compiler, format is "Sep 21 2008"
  136 
  137   ss << "Stockfish " << Version << setfill('0');
  138 
  139   if (Version.empty())
  140   {
  141       date >> month >> day >> year;
  142       ss << setw(2) << day << setw(2) << (1 + months.find(month) / 4) << year.substr(2);
  143   }
  144 
  145   ss << (Is64Bit ? " 64" : "")
  146      << (HasPext ? " BMI2" : (HasPopCnt ? " POPCNT" : ""))
  147      << (to_uci  ? "\nid author ": " by ")
  148      << "T. Romstad, M. Costalba, J. Kiiski, G. Linscott";
  149 
  150   return ss.str();
  151 }
  152 
  153 
  154 /// compiler_info() returns a string trying to describe the compiler we use
  155 
  156 const std::string compiler_info() {
  157 
  158   #define STRINGIFY2(x) #x
  159   #define STRINGIFY(x) STRINGIFY2(x)
  160   #define VER_STRING(major, minor, patch) STRINGIFY(major) "." STRINGIFY(minor) "." STRINGIFY(patch)
  161 
  162 /// Predefined macros hell:
  163 ///
  164 /// __GNUC__           Compiler is gcc, Clang or Intel on Linux
  165 /// __INTEL_COMPILER   Compiler is Intel
  166 /// _MSC_VER           Compiler is MSVC or Intel on Windows
  167 /// _WIN32             Building on Windows (any)
  168 /// _WIN64             Building on Windows 64 bit
  169 
  170   std::string compiler = "\nCompiled by ";
  171 
  172   #ifdef __clang__
  173      compiler += "clang++ ";
  174      compiler += VER_STRING(__clang_major__, __clang_minor__, __clang_patchlevel__);
  175   #elif __INTEL_COMPILER
  176      compiler += "Intel compiler ";
  177      compiler += "(version ";
  178      compiler += STRINGIFY(__INTEL_COMPILER) " update " STRINGIFY(__INTEL_COMPILER_UPDATE);
  179      compiler += ")";
  180   #elif _MSC_VER
  181      compiler += "MSVC ";
  182      compiler += "(version ";
  183      compiler += STRINGIFY(_MSC_FULL_VER) "." STRINGIFY(_MSC_BUILD);
  184      compiler += ")";
  185   #elif __GNUC__
  186      compiler += "g++ (GNUC) ";
  187      compiler += VER_STRING(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__);
  188   #else
  189      compiler += "Unknown compiler ";
  190      compiler += "(unknown version)";
  191   #endif
  192 
  193   #if defined(__APPLE__) 
  194      compiler += " on Apple";
  195   #elif defined(__CYGWIN__)
  196      compiler += " on Cygwin";
  197   #elif defined(__MINGW64__)
  198      compiler += " on MinGW64";
  199   #elif defined(__MINGW32__)
  200      compiler += " on MinGW32";
  201   #elif defined(__ANDROID__)
  202      compiler += " on Android";
  203   #elif defined(__linux__)
  204      compiler += " on Linux";
  205   #elif defined(_WIN64)
  206      compiler += " on Microsoft Windows 64-bit";
  207   #elif defined(_WIN32)
  208      compiler += " on Microsoft Windows 32-bit";
  209   #else
  210      compiler += " on unknown system";
  211   #endif
  212 
  213   compiler += "\n __VERSION__ macro expands to: ";
  214   #ifdef __VERSION__
  215      compiler += __VERSION__;
  216   #else
  217      compiler += "(undefined macro)";
  218   #endif
  219   compiler += "\n";
  220 
  221   return compiler;
  222 }
  223 
  224 
  225 /// Debug functions used mainly to collect run-time statistics
  226 static std::atomic<int64_t> hits[2], means[2];
  227 
  228 void dbg_hit_on(bool b) { ++hits[0]; if (b) ++hits[1]; }
  229 void dbg_hit_on(bool c, bool b) { if (c) dbg_hit_on(b); }
  230 void dbg_mean_of(int v) { ++means[0]; means[1] += v; }
  231 
  232 void dbg_print() {
  233 
  234   if (hits[0])
  235       cerr << "Total " << hits[0] << " Hits " << hits[1]
  236            << " hit rate (%) " << 100 * hits[1] / hits[0] << endl;
  237 
  238   if (means[0])
  239       cerr << "Total " << means[0] << " Mean "
  240            << (double)means[1] / means[0] << endl;
  241 }
  242 
  243 
  244 /// Used to serialize access to std::cout to avoid multiple threads writing at
  245 /// the same time.
  246 
  247 std::ostream& operator<<(std::ostream& os, SyncCout sc) {
  248 
  249   static std::mutex m;
  250 
  251   if (sc == IO_LOCK)
  252       m.lock();
  253 
  254   if (sc == IO_UNLOCK)
  255       m.unlock();
  256 
  257   return os;
  258 }
  259 
  260 
  261 /// Trampoline helper to avoid moving Logger to misc.h
  262 void start_logger(const std::string& fname) { Logger::start(fname); }
  263 
  264 
  265 /// prefetch() preloads the given address in L1/L2 cache. This is a non-blocking
  266 /// function that doesn't stall the CPU waiting for data to be loaded from memory,
  267 /// which can be quite slow.
  268 #ifdef NO_PREFETCH
  269 
  270 void prefetch(void*) {}
  271 
  272 #else
  273 
  274 void prefetch(void* addr) {
  275 
  276 #  if defined(__INTEL_COMPILER)
  277    // This hack prevents prefetches from being optimized away by
  278    // Intel compiler. Both MSVC and gcc seem not be affected by this.
  279    __asm__ ("");
  280 #  endif
  281 
  282 #  if defined(__INTEL_COMPILER) || defined(_MSC_VER)
  283   _mm_prefetch((char*)addr, _MM_HINT_T0);
  284 #  else
  285   __builtin_prefetch(addr);
  286 #  endif
  287 }
  288 
  289 #endif
  290 
  291 namespace WinProcGroup {
  292 
  293 #ifndef _WIN32
  294 
  295 void bindThisThread(size_t) {}
  296 
  297 #else
  298 
  299 /// best_group() retrieves logical processor information using Windows specific
  300 /// API and returns the best group id for the thread with index idx. Original
  301 /// code from Texel by Peter Ă–sterlund.
  302 
  303 int best_group(size_t idx) {
  304 
  305   int threads = 0;
  306   int nodes = 0;
  307   int cores = 0;
  308   DWORD returnLength = 0;
  309   DWORD byteOffset = 0;
  310 
  311   // Early exit if the needed API is not available at runtime
  312   HMODULE k32 = GetModuleHandle("Kernel32.dll");
  313   auto fun1 = (fun1_t)(void(*)())GetProcAddress(k32, "GetLogicalProcessorInformationEx");
  314   if (!fun1)
  315       return -1;
  316 
  317   // First call to get returnLength. We expect it to fail due to null buffer
  318   if (fun1(RelationAll, nullptr, &returnLength))
  319       return -1;
  320 
  321   // Once we know returnLength, allocate the buffer
  322   SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *buffer, *ptr;
  323   ptr = buffer = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)malloc(returnLength);
  324 
  325   // Second call, now we expect to succeed
  326   if (!fun1(RelationAll, buffer, &returnLength))
  327   {
  328       free(buffer);
  329       return -1;
  330   }
  331 
  332   while (byteOffset < returnLength)
  333   {
  334       if (ptr->Relationship == RelationNumaNode)
  335           nodes++;
  336 
  337       else if (ptr->Relationship == RelationProcessorCore)
  338       {
  339           cores++;
  340           threads += (ptr->Processor.Flags == LTP_PC_SMT) ? 2 : 1;
  341       }
  342 
  343       assert(ptr->Size);
  344       byteOffset += ptr->Size;
  345       ptr = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)(((char*)ptr) + ptr->Size);
  346   }
  347 
  348   free(buffer);
  349 
  350   std::vector<int> groups;
  351 
  352   // Run as many threads as possible on the same node until core limit is
  353   // reached, then move on filling the next node.
  354   for (int n = 0; n < nodes; n++)
  355       for (int i = 0; i < cores / nodes; i++)
  356           groups.push_back(n);
  357 
  358   // In case a core has more than one logical processor (we assume 2) and we
  359   // have still threads to allocate, then spread them evenly across available
  360   // nodes.
  361   for (int t = 0; t < threads - cores; t++)
  362       groups.push_back(t % nodes);
  363 
  364   // If we still have more threads than the total number of logical processors
  365   // then return -1 and let the OS to decide what to do.
  366   return idx < groups.size() ? groups[idx] : -1;
  367 }
  368 
  369 
  370 /// bindThisThread() set the group affinity of the current thread
  371 
  372 void bindThisThread(size_t idx) {
  373 
  374   // Use only local variables to be thread-safe
  375   int group = best_group(idx);
  376 
  377   if (group == -1)
  378       return;
  379 
  380   // Early exit if the needed API are not available at runtime
  381   HMODULE k32 = GetModuleHandle("Kernel32.dll");
  382   auto fun2 = (fun2_t)(void(*)())GetProcAddress(k32, "GetNumaNodeProcessorMaskEx");
  383   auto fun3 = (fun3_t)(void(*)())GetProcAddress(k32, "SetThreadGroupAffinity");
  384 
  385   if (!fun2 || !fun3)
  386       return;
  387 
  388   GROUP_AFFINITY affinity;
  389   if (fun2(group, &affinity))
  390       fun3(GetCurrentThread(), &affinity, nullptr);
  391 }
  392 
  393 #endif
  394 
  395 } // namespace WinProcGroup