Subversion Repositories Games.Chess Giants

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.     Protector -- a UCI chess engine
  3.  
  4.     Copyright (C) 2009-2010 Raimund Heid (Raimund_Heid@yahoo.com)
  5.  
  6.     This program is free software: you can redistribute it and/or modify
  7.     it under the terms of the GNU General Public License as published by
  8.     the Free Software Foundation, either version 3 of the License, or
  9.     (at your option) any later version.
  10.  
  11.     This program is distributed in the hope that it will be useful,
  12.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.     GNU General Public License for more details.
  15.  
  16.     You should have received a copy of the GNU General Public License
  17.     along with this program.  If not, see <http://www.gnu.org/licenses/>.
  18.  
  19. */
  20.  
  21. #include "coordination.h"
  22. #include "protector.h"
  23. #include "search.h"
  24. #include "matesearch.h"
  25. #include "io.h"
  26. #include "hash.h"
  27. #include <stdio.h>
  28. #include <assert.h>
  29. #ifndef _MSC_VER
  30. #include <pthread.h>
  31. #else // _MSC_VER
  32. #include <process.h> // Pierre-Marie Baty -- Win32 threads support
  33. __declspec(dllimport) void __stdcall Sleep (unsigned long Timeout); // Pierre-Marie Baty -- for Sleep()
  34. #endif // !_MSC_VER
  35. #include <time.h>
  36.  
  37. /* #define DEBUG_COORDINATION */
  38.  
  39. #ifndef _MSC_VER
  40. #define THREAD_RETURN_TYPE void * // Pierre-Marie Baty -- multiplatform threads support
  41. #define INVALID_THREAD_ID 0 // Pierre-Marie Baty -- multiplatform threads support
  42. pthread_t searchThread[MAX_THREADS];
  43. pthread_t timer;
  44. static pthread_mutex_t guiSearchMutex = PTHREAD_MUTEX_INITIALIZER;
  45. #else // _MSC_VER
  46. #define THREAD_RETURN_TYPE unsigned int // Pierre-Marie Baty -- Win32 threads support
  47. #define INVALID_THREAD_ID -1 // Pierre-Marie Baty -- Win32 threads support
  48. uintptr_t searchThread[MAX_THREADS]; // Pierre-Marie Baty -- Win32 threads support
  49. uintptr_t timer; // Pierre-Marie Baty -- Win32 threads support
  50. static bool guiSearchMutex = false; // Pierre-Marie Baty -- Win32 threads support
  51. bool terminate_timer = false; // Pierre-Marie Baty -- Win32 threads support
  52. #endif // !_MSC_VER
  53. long searchThreadId[MAX_THREADS];
  54.  
  55. static int numThreads = 1;
  56. static SearchTask dummyTask;
  57. static SearchTask *currentTask = &dummyTask;
  58. static Variation variations[MAX_THREADS];
  59. static Hashtable sharedHashtable;
  60. static PawnHashInfo pawnHashtable[MAX_THREADS][PAWN_HASHTABLE_SIZE];
  61.  
  62. Hashtable *getSharedHashtable()
  63. {
  64.    return &sharedHashtable;
  65. }
  66.  
  67. int setNumberOfThreads(int _numThreads)
  68. {
  69.    numThreads = max(1, min(MAX_THREADS, _numThreads));
  70.  
  71.    return numThreads;
  72. }
  73.  
  74. int getNumberOfThreads()
  75. {
  76.    return numThreads;
  77. }
  78.  
  79. UINT64 getNodeCount(void)
  80. {
  81.    int threadCount;
  82.    UINT64 sum = 0;
  83.  
  84.    for (threadCount = 0; threadCount < numThreads; threadCount++)
  85.    {
  86.       sum += variations[threadCount].nodes;
  87.    }
  88.  
  89.    return sum;
  90. }
  91.  
  92. Variation *getCurrentVariation()
  93. {
  94.    return &variations[0];
  95. }
  96.  
  97. void getGuiSearchMutex(void)
  98. {
  99. #ifdef DEBUG_COORDINATION
  100.    logDebug("aquiring search lock...\n");
  101. #endif
  102.  
  103. #ifndef _MSC_VER
  104.    pthread_mutex_lock(&guiSearchMutex);
  105. #else // _MSC_VER
  106.    while (guiSearchMutex)
  107.       Sleep (10); // allow context switching
  108.    guiSearchMutex = true; // Pierre-Marie Baty -- mutex support on Win32
  109. #endif // !_MSC_VER
  110.  
  111. #ifdef DEBUG_COORDINATION
  112.    logDebug("search lock aquired...\n");
  113. #endif
  114. }
  115.  
  116. void releaseGuiSearchMutex(void)
  117. {
  118. #ifndef _MSC_VER
  119.    pthread_mutex_unlock(&guiSearchMutex);
  120. #else // _MSC_VER
  121.    guiSearchMutex = false; // Pierre-Marie Baty -- mutex support on Win32
  122. #endif // !_MSC_VER
  123.  
  124. #ifdef DEBUG_COORDINATION
  125.    logDebug("search lock released...\n");
  126. #endif
  127. }
  128.  
  129. static int startSearch(Variation * currentVariation)
  130. {
  131.    currentVariation->searchStatus = SEARCH_STATUS_RUNNING;
  132.  
  133. #ifdef DEBUG_COORDINATION
  134.    logDebug("Search with thread #%d started.\n",
  135.             currentVariation->threadNumber);
  136. #endif
  137.  
  138.    switch (currentTask->type)
  139.    {
  140.    case TASKTYPE_BEST_MOVE:
  141.       currentTask->bestMove = search(currentVariation, NULL);
  142.       break;
  143.  
  144.    case TASKTYPE_TEST_BEST_MOVE:
  145.       currentTask->bestMove =
  146.          search(currentVariation, &currentTask->solutions);
  147.       break;
  148.  
  149.    case TASKTYPE_MATE_IN_N:
  150.       searchForMate(currentVariation,
  151.                     &currentTask->calculatedSolutions,
  152.                     currentTask->numberOfMoves);
  153.       break;
  154.  
  155.    case TASKTYPE_TEST_MATE_IN_N:
  156.       searchForMate(currentVariation,
  157.                     &currentTask->calculatedSolutions,
  158.                     currentTask->numberOfMoves);
  159.       break;
  160.  
  161.    default:
  162.       break;
  163.    }
  164.  
  165.    currentTask->nodes = getNodeCount();
  166.  
  167.    if (currentVariation->threadNumber == 0)
  168.    {
  169.       int threadCount;
  170.  
  171.       for (threadCount = 1; threadCount < numThreads; threadCount++)
  172.       {
  173.          variations[threadCount].terminate = TRUE;
  174.       }
  175.  
  176. #ifndef _MSC_VER
  177.       pthread_cancel(timer);
  178. #else // _MSC_VER
  179.       terminate_timer = true; // Pierre-Marie Baty -- Win32 threads support
  180. #endif // !_MSC_VER
  181.    }
  182.  
  183. #ifdef DEBUG_COORDINATION
  184.    logDebug("Search thread #%d terminated.\n",
  185.             currentVariation->threadNumber);
  186. #endif
  187.  
  188.    currentVariation->searchStatus = SEARCH_STATUS_FINISHED;
  189.  
  190.    return 0;
  191. }
  192.  
  193. long getElapsedTime()
  194. {
  195.    return getTimestamp() - variations[0].startTime;
  196. }
  197.  
  198. static THREAD_RETURN_TYPE executeSearch(void *arg)
  199. {
  200.    Variation *currentVariation = arg;
  201.  
  202. #ifdef _MSC_VER
  203.    currentVariation->finished = false; // Pierre-Marie Baty -- Win32 thread control
  204. #endif // _MSC_VER
  205.  
  206.    startSearch(currentVariation);
  207.  
  208. #ifdef _MSC_VER
  209.    currentVariation->finished = true; // Pierre-Marie Baty -- Win32 thread control
  210. #endif // _MSC_VER
  211.    return 0;
  212. }
  213.  
  214. static THREAD_RETURN_TYPE watchTime(void *arg)
  215. {
  216.    Variation *currentVariation = arg;
  217.    long timeLimit = currentVariation->timeLimit;
  218.    struct timespec requested;// , remaining; // Pierre-Marie Baty -- unused variable
  219.    int result;
  220.  
  221.    requested.tv_sec = timeLimit / 1000;
  222.    requested.tv_nsec = 1000000 * (timeLimit - 1000 * (long)requested.tv_sec); // Pierre-Marie Baty -- added type cast
  223.  
  224.    /* logReport("### Timer thread working sec=%ld nsec=%ld ###\n",
  225.       requested.tv_sec, requested.tv_nsec); */
  226. #ifndef _MSC_VER
  227.    result = nanosleep(&requested, &remaining);
  228.    if (result != -1)
  229. #else // _MSC_VER
  230.    result = (clock () * 1000 / CLOCKS_PER_SEC); // in milliseconds
  231.    while (!terminate_timer && ((clock () * 1000 / CLOCKS_PER_SEC) < result + timeLimit))
  232.       Sleep (10); // allow context switching if necessary
  233.    if (!terminate_timer)
  234. #endif // !_MSC_VER
  235.    {
  236.       getGuiSearchMutex();
  237.       prepareSearchAbort();
  238.       releaseGuiSearchMutex();
  239.    }
  240.  
  241.    return 0;
  242. }
  243.  
  244. void startTimerThread(SearchTask * task)
  245. {
  246.    if (task->variation->timeLimit > 0 && task->variation->ponderMode == FALSE)
  247.    {
  248. #ifndef _MSC_VER
  249.       if (pthread_create(&timer, NULL, &watchTime, task->variation) == 0)
  250. #else // _MSC_VER
  251.       terminate_timer = false; // Pierre-Marie Baty -- Win32 threads support
  252.       if ((timer = _beginthread (watchTime, 0, task->variation)) != -1) // Pierre-Marie Baty -- Win32 threads support
  253. #endif // !_MSC_VER
  254.       {
  255. #ifdef DEBUG_COORDINATION
  256.          logDebug("Timer thread started.\n");
  257. #endif
  258.       }
  259.       else
  260.       {
  261.          logDebug("### Timer thread could not be started. ###\n");
  262.  
  263.          exit(EXIT_FAILURE);
  264.       }
  265.    }
  266. }
  267.  
  268. void scheduleTask(SearchTask * task)
  269. {
  270.    const unsigned long startTime = getTimestamp();
  271.    int threadCount;
  272.  
  273.    sharedHashtable.entriesUsed = 0;
  274.  
  275.    startTimerThread(task);
  276.  
  277.    for (threadCount = 0; threadCount < numThreads; threadCount++)
  278.    {
  279.       Variation *currentVariation = &variations[threadCount];
  280.  
  281.       currentTask = task;
  282.       *currentVariation = *(currentTask->variation);
  283.       currentVariation->searchStatus = SEARCH_STATUS_TERMINATE;
  284.       currentVariation->bestBaseMove = NO_MOVE;
  285.       currentVariation->terminate = FALSE;
  286.       currentVariation->pawnHashtable = &(pawnHashtable[threadCount][0]);
  287.       currentVariation->kingsafetyHashtable =
  288.          &(kingSafetyHashtable[threadCount][0]);
  289.       currentVariation->threadNumber = threadCount;
  290.       currentVariation->startTime = startTime;
  291.  
  292. #ifndef _MSC_VER
  293.       if (pthread_create(&searchThread[threadCount], NULL,
  294.                          &executeSearch, currentVariation) == 0)
  295. #else // _MSC_VER
  296.       if ((searchThread[threadCount] = _beginthread(executeSearch, 0, currentVariation)) != -1) // Pierre-Marie Baty -- Win32 threads support
  297. #endif // !_MSC_VER
  298.       {
  299. #ifdef DEBUG_COORDINATION
  300.          logDebug("Search thread #%d created.\n", threadCount);
  301. #endif
  302.       }
  303.       else
  304.       {
  305.          logDebug("### Search thread #%d could not be started. ###\n",
  306.                   threadCount);
  307.  
  308.          exit(EXIT_FAILURE);
  309.       }
  310.    }
  311. }
  312.  
  313. void waitForSearchTermination(void)
  314. {
  315.    int threadCount;
  316.    bool finished;
  317.    int count = 0;
  318.  
  319.    do
  320.    {
  321.       finished = TRUE;
  322.  
  323.       if (count > 1000)
  324.       {
  325.          logDebug("waiting for search termination.\n");
  326.          count = 0;
  327.       }
  328.  
  329.       for (threadCount = 0; threadCount < numThreads; threadCount++)
  330.       {
  331.          Variation *currentVariation = &variations[threadCount];
  332.  
  333.          if (currentVariation->searchStatus != SEARCH_STATUS_FINISHED)
  334.          {
  335.             if (searchThread[threadCount] != INVALID_THREAD_ID)
  336.             {
  337. #ifndef _MSC_VER
  338.                const int result = pthread_join (searchThread[threadCount], 0);
  339.  
  340.                if (result == 0)
  341.                {
  342.                   searchThread[threadCount] = INVALID_THREAD_ID;
  343.                }
  344.                else
  345.                {
  346.                   finished = FALSE;
  347.                }
  348. #else // _MSC_VER
  349.                while (!currentVariation->finished)
  350.                   Sleep (10); // allow context switching
  351.  
  352.                searchThread[threadCount] = INVALID_THREAD_ID;
  353. #endif // !_MSC_VER
  354.             }
  355.          }
  356.          else
  357.          {
  358.             searchThread[threadCount] = INVALID_THREAD_ID;
  359.          }
  360.  
  361. #ifdef DEBUG_COORDINATION
  362.          logDebug("Task %d finished.\n", threadCount);
  363. #endif
  364.       }
  365.  
  366.       count++;
  367.    }
  368.    while (finished == FALSE);
  369. }
  370.  
  371. void completeTask(SearchTask * task)
  372. {
  373.    scheduleTask(task);
  374.  
  375. #ifdef DEBUG_COORDINATION
  376.    logDebug("Task scheduled. Waiting for completion.\n");
  377. #endif
  378.  
  379.    waitForSearchTermination();
  380. }
  381.  
  382. void prepareSearchAbort(void)
  383. {
  384.    int threadCount;
  385.  
  386.    for (threadCount = 0; threadCount < numThreads; threadCount++)
  387.    {
  388.       variations[threadCount].terminate = TRUE;
  389.    }
  390. }
  391.  
  392. void unsetPonderMode(void)
  393. {
  394.    int threadCount;
  395.  
  396.    for (threadCount = 0; threadCount < numThreads; threadCount++)
  397.    {
  398.       Variation *currentVariation = &variations[threadCount];
  399.  
  400.       currentVariation->ponderMode = FALSE;
  401.    }
  402. }
  403.  
  404. /*void setTimeLimit(unsigned long timeTarget, unsigned long timeLimit)
  405. {
  406.    int threadCount;
  407.  
  408.    for (threadCount = 0; threadCount < numThreads; threadCount++)
  409.    {
  410.       Variation *currentVariation = &variations[threadCount];
  411.  
  412.       currentVariation->timeTarget = timeTarget;
  413.       currentVariation->timeLimit = timeLimit;
  414.    }
  415. }*/ // Pierre-Marie Baty -- unused function?
  416.  
  417. void setHashtableSizeInMb(unsigned int size)
  418. {
  419.    UINT64 tablesize = 1024 * 1024 * (UINT64) size;
  420.  
  421.    setHashtableSize(&sharedHashtable, tablesize);
  422.    resetHashtable(&sharedHashtable);
  423. }
  424.  
  425. int initializeModuleCoordination()
  426. {
  427.    int threadCount;
  428.  
  429.    initializeHashtable(&sharedHashtable);
  430.    setHashtableSize(&sharedHashtable, 16 * 1024 * 1024);
  431.    resetHashtable(&sharedHashtable);
  432.  
  433.    for (threadCount = 0; threadCount < MAX_THREADS; threadCount++)
  434.    {
  435.       Variation *currentVariation = &variations[threadCount];
  436.  
  437.       currentVariation->searchStatus = SEARCH_STATUS_FINISHED;
  438.    }
  439.  
  440.    return 0;
  441. }
  442.  
  443. int testModuleCoordination()
  444. {
  445.    return 0;
  446. }
  447.