Subversion Repositories Games.Chess Giants

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
112 pmbaty 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
}