alphaBeta2Parallel.cc
Go to the documentation of this file.
00001 /* alphaBeta2Parallel.cc
00002  */
00003 #ifdef OSL_SMP
00004 
00005 #include "osl/search/alphaBeta2Parallel.h"
00006 #include "osl/search/simpleHashTable.h"
00007 #include "osl/search/usiReporter.h"
00008 #include "osl/misc/nonBlockDelete.h"
00009 #include <iostream>
00010 #include <bitset>
00011 #ifdef _WIN32
00012 # include <malloc.h>
00013 #endif
00014 
00015 #define DEBUG_SMP 0
00016 #define ONLY_HELP_DESCENDANT
00017 // #define OSL_BUSY_WAIT
00018 
00019 /* ------------------------------------------------------------------------- */
00020 struct osl::search::AlphaBeta2ParallelCommon::LivingThreadLock
00021 {
00022   AlphaBeta2ParallelCommon *shared;
00023   LivingThreadLock(AlphaBeta2ParallelCommon *s) : shared(s)
00024   {
00025     boost::mutex::scoped_lock lk(shared->living_threads_lock);
00026     shared->living_threads += 1;
00027     shared->living_threads_condition.notify_one();
00028   }
00029   ~LivingThreadLock()
00030   {
00031     boost::mutex::scoped_lock lk(shared->living_threads_lock);
00032     shared->living_threads -= 1;
00033     shared->living_threads_condition.notify_one();
00034   }
00035 };
00036 
00037 /* ------------------------------------------------------------------------- */
00038 template <class EvalT>
00039 osl::search::AlphaBeta2Parallel<EvalT>::
00040 Worker::Worker(int tid, AlphaBeta2Parallel *s) : shared(s), thread_id(tid)
00041 {
00042 }
00043 
00044 template <class EvalT>
00045 void
00046 #ifdef __GNUC__
00047 #  ifdef _WIN32
00048 __attribute__((noinline))
00049 __attribute__((force_align_arg_pointer)) 
00050 #  endif
00051 #endif
00052 osl::search::AlphaBeta2Parallel<EvalT>::Worker::operator()()
00053 {
00054 #if DEBUG_SMP > 1
00055   {
00056     boost::mutex::scoped_lock lk(OslConfig::lock_io);
00057     std::cerr << "thread " << thread_id << " started\n";
00058   }
00059 #endif
00060   try {
00061     AlphaBeta2ParallelCommon::LivingThreadLock lk(shared);
00062     shared->threadWait(thread_id, -1);
00063   }
00064   catch (std::exception& e) {
00065     std::cerr << "warning caught exception in thread root " << e.what() << "\n";
00066   }
00067   catch (...) {
00068     std::cerr << "warning caught unknown exception in thread root\n";
00069   }
00070 }
00071 
00072 /* ------------------------------------------------------------------------- */
00073 
00074 static osl::misc::AtomicCounter parallel_counter;
00075 
00076 osl::search::AlphaBeta2ParallelCommon::
00077 AlphaBeta2ParallelCommon() 
00078   : smp_idle(0), quit(false), 
00079     parallel_splits(0), max_split_depth(0), descendant_reject(0), descendant_test(0),
00080     living_threads(0), max_threads(OslConfig::numCPUs()), max_thread_group(5),
00081     split_min_limit(400), my_id(parallel_counter.valueAndinc()), started(false)
00082 {
00083   job.fill(0);
00084   info[0].thread_id = 0;
00085   info[0].used = true;
00086   info[0].parent = -1;
00087   waiting.fill(0);
00088   
00089   threads.fill(0);
00090   checkmate.fill(0);
00091   for (int i=1; i<max_threads; ++i) {
00092     threads[i] = 0;
00093     checkmate[i] = 0;
00094   }
00095 }
00096 
00097 osl::search::AlphaBeta2ParallelCommon::
00098 ~AlphaBeta2ParallelCommon() 
00099 {
00100   waitAll();
00101   for (int i=1; i<max_threads; ++i) {
00102     delete checkmate[i];
00103   }  
00104 #if DEBUG_SMP > 1
00105   std::cerr << "<= AlphaBeta2Parallel " << my_id << "\n";
00106 #endif
00107 #if DEBUG_SMP > 2
00108   std::cerr << "descendant_reject " << descendant_reject 
00109             << " / " << descendant_test << " = " << (double)descendant_reject/descendant_test << "\n";
00110   std::cerr << "max_split_depth " << max_split_depth << "\n";
00111 #endif
00112 }
00113 
00114 void osl::search::
00115 AlphaBeta2ParallelCommon::waitAll() {
00116 #ifndef OSL_BUSY_WAIT
00117   {
00118   boost::mutex::scoped_lock lk(lock_smp);
00119 #endif      
00120   quit = true;
00121   started = false;
00122 #ifndef OSL_BUSY_WAIT
00123   condition_smp.notify_all();
00124   }
00125 #endif
00126   boost::mutex::scoped_lock lk(living_threads_lock);
00127   while (living_threads != (quit ? 0 : smp_idle)) {
00128     living_threads_condition.wait(lk);
00129   }
00130   for (int i=1; i<max_threads; ++i) {
00131     delete threads[i];
00132     threads[i] = 0;
00133   }  
00134 }
00135 
00136 bool osl::search::AlphaBeta2ParallelCommon::isDescendant(int elder, int younger)
00137 {
00138 #ifndef ONLY_HELP_DESCENDANT
00139   return true;
00140 #else
00141   ++descendant_test;
00142   if (elder < 0)
00143     return true;
00144   while (younger >= 0) {
00145     if (elder == younger)
00146       return true;
00147     younger = info[younger].parent;
00148   } 
00149   ++descendant_reject;
00150   return false;
00151 #endif
00152 }
00153 
00154 /* ------------------------------------------------------------------------- */
00155 
00156 template <class EvalT>
00157 osl::search::AlphaBeta2Parallel<EvalT>::
00158 AlphaBeta2Parallel(AlphaBeta2Tree<EvalT> *m) 
00159   : AlphaBeta2ParallelCommon(), master(m)
00160 {
00161 #if DEBUG_SMP > 0
00162   std::cerr << "=> AlphaBeta2Parallel " << max_threads << " threads ";
00163 # if DEBUG_SMP > 1
00164   std::cerr << " id " << my_id;
00165 # endif
00166   std::cerr << "\n";
00167 #endif
00168   tree.fill(0);
00169   tree[0] = master;
00170   checkmate[0] = checkmateSearcher(*master);
00171 }
00172 
00173 template <class EvalT>
00174 osl::search::AlphaBeta2Parallel<EvalT>::
00175 ~AlphaBeta2Parallel() 
00176 {
00177 }
00178 
00179 template <class EvalT>
00180 void osl::search::AlphaBeta2Parallel<EvalT>::
00181 threadStart()
00182 {
00183   if (started)
00184     return;
00185   started = true;
00186   quit = false;
00187   int i=1;
00188   for (; i<max_threads; ++i) {
00189     int j=0, max_retry=4;
00190     for (; j<max_retry; ++j) {
00191       try 
00192       {
00193         if (! checkmate[i])
00194           checkmate[i] = new checkmate_t(master->checkmateSearcher());
00195         threads[i] = new boost::thread(Worker(i, this));
00196         break;
00197       } 
00198       catch (std::exception& e)
00199       {
00200         std::cerr << e.what() << "\n";
00201       }
00202       std::cerr << "wait for thread " << i << " started\n";
00203       const int microseconds = (j+1)*100000;
00204 #ifdef _WIN32
00205       boost::this_thread::sleep(boost::posix_time::microseconds(microseconds));
00206 #else
00207       usleep(microseconds);
00208 #endif
00209       NonBlockDelete::deleteAll();
00210     }
00211     if (j == max_retry)
00212       break;
00213   }
00214   if (i < max_threads) 
00215   {
00216     std::cerr << "error in start thread #" << i << "\n";
00217     for (int j=i; j<max_threads; ++j) {
00218       delete checkmate[j];
00219       checkmate[j] = 0;
00220     }
00221     max_threads = i;
00222   }
00223   boost::mutex::scoped_lock lk(living_threads_lock);
00224   while (living_threads+1 != max_threads) {
00225     living_threads_condition.wait(lk);
00226   }
00227 }
00228 
00229 template <class EvalT>
00230 void osl::search::AlphaBeta2Parallel<EvalT>::
00231 search(int tree_id)
00232 {
00233   TreeInfo *info = &this->info[tree_id];
00234   assert(tree[tree_id]);
00235   if (info->is_root)
00236     tree[tree_id]->examineMovesRootPar(tree_id);
00237   else
00238     tree[tree_id]->examineMovesOther(tree_id);
00239 }
00240 
00241 template <class EvalT>
00242 int osl::search::
00243 AlphaBeta2Parallel<EvalT>::treeId(AlphaBeta2Tree<EvalT> *t) 
00244 {
00245   if (t == master)
00246     return 0;
00247   for (size_t i=1; i<tree.size(); ++i)
00248     if (t == tree[i])
00249       return i;
00250   assert(0);
00251   abort();
00252 }
00253 
00254 template <class EvalT>
00255 void osl::search::AlphaBeta2Parallel<EvalT>::
00256 threadWait(int thread_id, int waiting)
00257 {
00258 #if DEBUG_SMP > 2
00259   {
00260     boost::mutex::scoped_lock lk(OslConfig::lock_io);
00261     std::cerr << "thread " << thread_id << " ready, waiting " << waiting << "\n";
00262   }
00263 #endif
00264   while (1) {
00265     this->waiting[thread_id] = waiting;
00266     {
00267       boost::mutex::scoped_lock lk(lock_smp);
00268       smp_idle++;
00269     }
00270   {
00271 #ifndef OSL_BUSY_WAIT
00272     boost::mutex::scoped_lock lk(lock_smp);
00273 #endif      
00274     while (! job[thread_id] 
00275            && ! quit 
00276            && (waiting < 0 || info[waiting].nprocs))
00277     {
00278 #ifndef OSL_BUSY_WAIT
00279       condition_smp.wait(lk);
00280 #endif      
00281     }
00282     
00283     if (quit) {
00284       {
00285 #ifdef OSL_BUSY_WAIT
00286         boost::mutex::scoped_lock lk(lock_smp);
00287 #endif
00288         --smp_idle;
00289       }
00290 #if DEBUG_SMP > 1
00291       boost::mutex::scoped_lock lk(OslConfig::lock_io);
00292       std::cerr << "thread " << thread_id << " exiting\n";
00293 #endif
00294       return;
00295     }
00296     {
00297 #ifdef OSL_BUSY_WAIT
00298       boost::mutex::scoped_lock lk(lock_smp);
00299 #endif
00300       if (! job[thread_id])
00301         job[thread_id] = waiting;
00302       --smp_idle;
00303     }
00304   }
00305 
00306     if (job[thread_id] == waiting) {
00307 #ifndef NDEBUG
00308       if (waiting >= 0) {
00309         for (int i=0; i<max_threads; ++i) {
00310           assert(info[waiting].siblings[i] == 0);
00311         }
00312         assert(info[waiting].nprocs == 0);
00313       }
00314 #endif
00315 #if DEBUG_SMP > 3
00316       boost::mutex::scoped_lock lk(OslConfig::lock_io);
00317       std::cerr << "thread " << thread_id << " go up " 
00318                 << waiting << " " << info[job[thread_id]].best_move << "\n";
00319 #endif
00320       return;
00321     }
00322 
00323     if (quit || job[thread_id] == -1) {
00324       return;
00325     }
00326     int my_job = job[thread_id];
00327 #if DEBUG_SMP > 3
00328     {
00329       boost::mutex::scoped_lock lk(OslConfig::lock_io);
00330       std::cerr << "thread " << thread_id << " go to job " << my_job << " waiting " << waiting << "\n";
00331       if (! tree[my_job]) {
00332         std::cerr << "thread " << thread_id << " null job " << my_job << " waiting " << waiting << "\n";
00333       }
00334     }
00335 #endif
00336 
00337     assert(tree[my_job]);
00338     search(my_job);
00339 
00340     int parent = info[my_job].parent;
00341     boost::mutex::scoped_lock lk(lock_smp);
00342     {
00343       SCOPED_LOCK(lk,info[parent].lock);
00344       copyToParent(parent, my_job);
00345       info[parent].nprocs--;
00346       info[parent].siblings[thread_id] = 0;
00347 #ifndef OSL_BUSY_WAIT
00348       if (info[parent].nprocs == 0)
00349         condition_smp.notify_all();
00350 #endif
00351     }
00352     job[thread_id] = 0;
00353     delete tree[my_job];
00354     tree[my_job] = 0;
00355 #if DEBUG_SMP > 3
00356     {
00357       boost::mutex::scoped_lock lk(OslConfig::lock_io);
00358       std::cerr << "thread " << thread_id << " back from job " << my_job << " waiting " << waiting;
00359       if (waiting >= 0)
00360         std::cerr << " rest " << info[waiting].nprocs;
00361       std::cerr << "\n";
00362     }
00363 #endif
00364   }
00365 }
00366 
00367 template <class EvalT>
00368 bool osl::search::AlphaBeta2Parallel<EvalT>::
00369 split(AlphaBeta2Tree<EvalT> *tree, int tree_id, int thread_id, int max_split)
00370 {
00371   TreeInfo *pinfo = &info[tree_id];
00372 #if DEBUG_SMP > 2
00373   {
00374     unsigned int depth = 0;
00375     int parent = pinfo->parent;
00376     while (parent >= 0)
00377       ++depth, parent = info[parent].parent;;
00378     max_split_depth = std::max(depth, max_split_depth);
00379   }
00380   for (int i=0; i<max_threads; ++i) {
00381     assert(pinfo->siblings[i] == 0);
00382   }
00383 #endif
00384   assert(tree == master || tree == this->tree[tree_id]);
00385   {
00386     boost::mutex::scoped_lock lk(lock_smp);
00387     {
00388       int tid=0;
00389       for (; tid<max_threads && job[tid]; ++tid)
00390         ;
00391       if (tid == max_threads || tree->stop_tree)
00392         return false;
00393     }
00394   
00395     parallel_splits++;  
00396     job[pinfo->thread_id] = 0;
00397     pinfo->nprocs = 0;
00398 
00399     int nblocks = 0;
00400     if (const int child_id = copyToChild(tree_id, thread_id))
00401     {
00402       // first, assgin job to splitting thread
00403       nblocks++;
00404       pinfo->siblings[thread_id] = child_id;
00405       info[child_id].thread_id = thread_id;
00406       info[child_id].parent = tree_id;
00407       pinfo->nprocs++;
00408     }
00409     if (max_split <= 0)
00410       max_split = std::max(max_threads/2, max_thread_group);
00411     else
00412       max_split = std::min(max_split, std::max(max_threads/2, max_thread_group));
00413     for (int tid = 0;
00414          tid < max_threads && nblocks < max_split;
00415          ++tid) {    
00416       assert(pinfo->siblings[tid] == 0 || tid == thread_id);
00417       if (job[tid] || tid == thread_id)         // he is working
00418         continue;
00419       if (! isDescendant(waiting[tid], pinfo->parent))
00420         continue;
00421       int child_id = copyToChild(tree_id, tid);
00422       if (!child_id)
00423         continue;
00424 #if DEBUG_SMP > 3
00425       {
00426         boost::mutex::scoped_lock lk(OslConfig::lock_io);
00427         std::cerr << "split " << tree_id << " in " << thread_id << " => " << child_id << " in " << tid << "\n";
00428       }
00429 #endif
00430       nblocks++;
00431       pinfo->siblings[tid] = child_id;
00432       info[child_id].thread_id = tid;
00433       info[child_id].parent = tree_id;
00434       pinfo->nprocs++;
00435     }  
00436     pinfo->search_value = pinfo->value;
00437   
00438     if (!nblocks) {    
00439       job[pinfo->thread_id] = tree_id;
00440       return false;
00441     }
00442   
00443     for (int tid=0; tid< max_threads; ++tid)
00444       if (pinfo->siblings[tid])
00445         job[tid] = pinfo->siblings[tid];  
00446   }
00447 #ifndef OSL_BUSY_WAIT
00448   condition_smp.notify_all();
00449 #endif
00450   threadWait(pinfo->thread_id, tree_id);
00451   
00452   return true;
00453 }
00454 
00455 template <class EvalT>
00456 void osl::search::
00457 AlphaBeta2Parallel<EvalT>::stopThread(int tree_id)
00458 {
00459   TreeInfo *info = &this->info[tree_id];
00460   AlphaBeta2Tree<EvalT> *tree = this->tree[tree_id];
00461   SCOPED_LOCK(lk,info->lock);
00462   tree->stop_tree = true;
00463   for (int tid = 0; tid<max_threads; tid++)
00464     if (info->siblings[tid])
00465       stopThread(info->siblings[tid]);
00466 }
00467 
00468 template <class EvalT>
00469 void osl::search::
00470 AlphaBeta2Parallel<EvalT>::copyToParent(int parent, int child) 
00471 {
00472   TreeInfo *c = &info[child];
00473   AlphaBeta2Tree<EvalT> *cc = tree[child], *pp = tree[parent];
00474   c->used = 0;    
00475   pp->node_count += cc->nodeCount();
00476   pp->mpn.merge(cc->mpn);
00477   pp->mpn_cut.merge(cc->mpn_cut);
00478   pp->alpha_update.merge(cc->alpha_update);
00479   pp->last_alpha_update.merge(cc->last_alpha_update);
00480   pp->ext.merge(cc->ext);
00481   pp->ext_limit.merge(cc->ext_limit);
00482 }
00483 
00484 template <class EvalT>
00485 int osl::search::
00486 AlphaBeta2Parallel<EvalT>::copyToChild(int parent, int thread_id)
00487 {  
00488   static int warnings = 0;  
00489   int first = thread_id * MaxBlocksPerCpu + 1;  
00490   int last = first + MaxBlocksPerCpu;
00491   int maxb = max_threads * MaxBlocksPerCpu + 1;
00492 
00493   int cid=first;
00494   for (; cid < last && info[cid].used; cid++)
00495     ;
00496   
00497   if (cid >= last) {    
00498     if (++warnings < 6) {
00499       boost::mutex::scoped_lock lk(OslConfig::lock_io);
00500       std::cerr << "WARNING.  optimal SMP block cannot be allocated, thread "
00501                 << thread_id << "\n";
00502     }
00503     for (cid=1; cid<maxb && info[cid].used; cid++)
00504       ;    
00505     if (cid >= maxb) {
00506       if (warnings < 6) {
00507         boost::mutex::scoped_lock lk(OslConfig::lock_io);
00508         std::cerr << "ERROR.  no SMP block can be allocated\n";
00509       }
00510       return 0;      
00511     }    
00512   }
00513 
00514   TreeInfo *c = &info[cid], *p = &info[parent];
00515   try 
00516   {
00517     assert(tree[cid] == 0);
00518     tree[cid] = new AlphaBeta2Tree<EvalT>(*tree[parent], this);
00519   }
00520   catch (std::bad_alloc&)
00521   {
00522     boost::mutex::scoped_lock lk(OslConfig::lock_io);
00523     std::cerr << "ERROR.  split failed due to bad_alloc\n";
00524     return 0;
00525   }
00526   c->set(*p, max_threads);
00527   tree[cid]->setCheckmateSearcher(checkmate[thread_id]);
00528 
00529   return cid;
00530 }
00531 
00532 template <class EvalT>
00533 const std::pair<osl::MoveLogProb,size_t> osl::search::
00534 AlphaBeta2Parallel<EvalT>::nextMove(int tree_id)
00535 {
00536   int parent = info[tree_id].parent;
00537   TreeInfo *info = &this->info[parent];
00538   SCOPED_LOCK(lk,info->lock);
00539   const size_t old_index = info->move_index;
00540   if (tree[parent]->stop_tree)
00541     return std::make_pair(MoveLogProb(), old_index);
00542   if (info->is_root) {
00543     if (old_index < info->moves.size()) {
00544       ++(info->move_index);
00545       return std::make_pair(info->moves[old_index], old_index);
00546     }
00547     return std::make_pair(MoveLogProb(), old_index);
00548   }
00549   else {
00550     MoveLogProb m = (info->turn == BLACK) 
00551       ? tree[parent]->template nextMove<BLACK>() 
00552       : tree[parent]->template nextMove<WHITE>();
00553     if (m.validMove()) {
00554       assert(m.player() == info->turn);
00555       ++(info->move_index);
00556     }
00557     return std::make_pair(m, old_index);
00558   }
00559 }
00560 
00561 template <class EvalT>
00562 size_t osl::search::
00563 AlphaBeta2Parallel<EvalT>::checkmateCount() const
00564 {
00565   return master->checkmateSearcher().totalNodeCount();
00566 }
00567 
00568 template <class EvalT>
00569 size_t osl::search::
00570 AlphaBeta2Parallel<EvalT>::mainCheckmateCount() const
00571 {
00572   size_t result = master->checkmateSearcher().mainNodeCount();
00573 #ifndef NEW_DFPN
00574   for (int i=1; i<max_threads; ++i)
00575     result += checkmate[i]->mainNodeCount();
00576 #endif
00577   return result;
00578 }
00579 
00580 /* ------------------------------------------------------------------------- */
00581 
00582 template <class EvalT>
00583 template <osl::Player P>
00584 void osl::search::
00585 AlphaBeta2Tree<EvalT>::testMoveRoot(int tree_id, const MoveLogProb& m)
00586 {
00587   if (stop_tree) {
00588     std::cerr << "root tree stop\n";
00589     return;
00590   }
00591   
00592   Window w;
00593   AlphaBeta2ParallelCommon::TreeInfo *parent = shared->parent(tree_id);
00594   {
00595     SCOPED_LOCK(lk,parent->lock);
00596     w = parent->window;
00597     assert(w.isConsistent());
00598   }
00599   assert(P == m.player());
00600 #ifndef GPSONE
00601   if (this->multi_pv) {
00602     int width = this->multi_pv*this->eval.captureValue(newPtypeO(P, PAWN))/200;
00603     if (width % 2 == 0) 
00604       width -= EvalTraits<P>::delta;
00605     w.alpha(P) = parent->search_value + width;
00606   }
00607 #endif
00608   const int result = alphaBetaSearch<P>(m, w, false);
00609 
00610   if (eval::betterThan(P, result, parent->search_value)) {
00611     makePV(m.move());
00612     if (eval::betterThan(P, result, w.beta(P))) {
00613       {
00614         boost::mutex::scoped_lock lk_smp(shared->lock_smp);
00615         SCOPED_LOCK(lk,parent->lock);
00616         if (! stop_tree) {
00617 #if DEBUG_SMP > 2
00618           std::cerr << "beta cut root " << tree_id << "\n";
00619 #endif
00620           for (int tid=0; tid<shared->max_threads; tid++)
00621             if (parent->siblings[tid] && tid != shared->info[tree_id].thread_id)
00622               shared->stopThread(parent->siblings[tid]);
00623         }
00624       }
00625       shared->parallel_abort.inc();
00626     }
00627     SCOPED_LOCK(lk,parent->lock);
00628     if (! stopping()
00629         && (eval::betterThan(P, result, parent->search_value))) {
00630       assert(parent->window.isConsistent());
00631       parent->window.alpha(P) = result + EvalTraits<P>::delta;
00632       parent->best_move = m;
00633       parent->search_value = result;
00634       updateRootPV(P, std::cerr, result, m.move());
00635       assert(parent->window.isConsistent());
00636       shared->tree[shared->parentID(tree_id)]->pv[0] = pv[0];
00637     }
00638   }  
00639 #ifndef GPSONE
00640   else if (this->multi_pv && !stopping() 
00641            && eval::betterThan(P, result, w.alpha(P)))
00642     addMultiPV(P, result, m.move());
00643 #endif
00644 }
00645 
00646 template <class EvalT>
00647 template <osl::Player P>
00648 void osl::search::AlphaBeta2Tree<EvalT>::
00649 examineMovesRootPar(const MoveLogProbVector& moves, size_t start, Window window,
00650                     MoveLogProb& best_move, int& best_value)
00651 {
00652   const int id = shared->treeId(this);
00653 #if DEBUG_SMP > 3
00654   {
00655     boost::mutex::scoped_lock lk(OslConfig::lock_io);
00656     std::cerr << "start split root " << id << " turn " << P << " parent " << shared->info[id].parent << "\n";
00657     history().dump();
00658   }
00659 #endif
00660   AlphaBeta2ParallelCommon::TreeInfo *info = &shared->info[id];
00661   info->window = window;
00662   info->is_root = true;
00663   info->in_pv = false;
00664   info->value = best_value;
00665   info->moves = moves;
00666   info->move_index = start;
00667   info->turn = P;
00668   info->best_move = best_move;
00669   if (! shared->split(this, id, info->thread_id, -1)) {
00670     shared->cancelled_splits.inc();
00671     throw AlphaBeta2ParallelCommon::SplitFailed();
00672   }
00673   SCOPED_LOCK(lk,info->lock);
00674   best_value = info->search_value;
00675   best_move = info->best_move;
00676 }
00677 
00678 template <class EvalT>
00679 void osl::search::AlphaBeta2Tree<EvalT>::
00680 examineMovesRootPar(int tree_id)
00681 {
00682   AlphaBeta2ParallelCommon::TreeInfo *info = &shared->info[tree_id];
00683   const Player my_turn = info->turn;
00684   for (MoveLogProb m = shared->nextMove(tree_id).first; 
00685        m.validMove() && ! stopping();
00686        m = shared->nextMove(tree_id).first) {
00687 #ifndef GPSONE
00688     if (OslConfig::usiMode()) {
00689       boost::mutex::scoped_lock lk(OslConfig::lock_io);      
00690       UsiReporter::rootMove(m.move());
00691     }
00692 #endif
00693     try {
00694       if (my_turn == BLACK)
00695         testMoveRoot<BLACK>(tree_id, m);
00696       else
00697         testMoveRoot<WHITE>(tree_id, m);
00698       if (this->root_limit >= 1600)
00699         this->checkmate_searcher->runGC(this->table->isVerbose(),
00700                                         lastMemoryUseRatio1000());
00701     }
00702     catch (BetaCut& e) {
00703       std::cerr << "caught BetaCut at root " << info->thread_id << "\n";
00704       assert(stop_tree);
00705       break;
00706     }
00707     catch (std::runtime_error&) {
00708       stop_tree = true;
00709       this->stopNow();
00710       break;
00711     }
00712     catch (std::exception& e) {
00713 #if DEBUG_SMP > 0
00714       boost::mutex::scoped_lock lk(OslConfig::lock_io);
00715       std::cerr << "caught " << e.what() << " at root " << info->thread_id << "\n";
00716 #endif
00717       stop_tree = true;
00718       this->stopNow();
00719       break;
00720     }
00721     catch (...) {
00722       boost::mutex::scoped_lock lk(OslConfig::lock_io);
00723       std::cerr << "caught something at root " << info->thread_id << "\n";
00724       stop_tree = true;
00725       this->stopNow();
00726       break;
00727     }
00728   }
00729   // cut or no more moves to search
00730 }
00731 
00732 template <class EvalT>
00733 template <osl::Player P>
00734 bool osl::search::
00735 AlphaBeta2Tree<EvalT>::testMoveOther(int tree_id, const MoveLogProb& m, size_t index,
00736                               bool in_pv)
00737 {
00738   if (stopping())
00739     return false;
00740 
00741   Window w;
00742   AlphaBeta2ParallelCommon::TreeInfo *parent = shared->parent(tree_id);
00743   {
00744     SCOPED_LOCK(lk,parent->lock);
00745     w = parent->window;
00746     assert(w.isConsistent() || stop_tree);
00747   }
00748   if (stopping())
00749     return false;
00750   assert(P == m.player());
00751   const int result = alphaBetaSearch<P>(m, w, in_pv);
00752   if (stopping())
00753     return false;
00754 
00755   bool cut = false;
00756   int parent_search_value;
00757   {
00758 #ifdef OSL_USE_RACE_DETECTOR
00759     SCOPED_LOCK(lk,parent->lock);
00760 #endif
00761     parent_search_value = parent->search_value;
00762   }
00763   if (eval::betterThan(P, result, parent_search_value)) {
00764     makePV(m.move());
00765     if (eval::betterThan(P, result, w.beta(P))) {
00766       cut = true;
00767       {
00768         boost::mutex::scoped_lock lk_smp(shared->lock_smp);
00769         SCOPED_LOCK(lk,parent->lock);
00770         if (! stop_tree) {
00771 #if DEBUG_SMP > 2
00772           std::cerr << "beta cut " << tree_id << "\n";
00773 #endif
00774           for (int tid=0; tid<shared->max_threads; tid++)
00775             if (parent->siblings[tid] && tid != shared->info[tree_id].thread_id)
00776               shared->stopThread(parent->siblings[tid]);
00777         }
00778       }
00779       shared->parallel_abort.inc();
00780     }
00781     SCOPED_LOCK(lk,parent->lock);
00782     if (! stopping() && eval::betterThan(P, result, parent->search_value)) {
00783       parent->window.alpha(P) = result + EvalTraits<P>::delta;
00784       parent->best_move = m;
00785       parent->search_value = result;
00786       parent->alpha_update++;
00787       parent->last_alpha_update = index;
00788       assert(cut || shared->tree[shared->info[tree_id].parent]->stop_tree
00789              || parent->window.isConsistent());
00790       AlphaBeta2Tree *pp = shared->tree[shared->parentID(tree_id)];
00791       pp->pv[pp->curDepth()] = pv[curDepth()];
00792       if (cut)
00793         return true;
00794     }
00795   }  
00796   return false;
00797 }
00798 
00799 template <class EvalT>
00800 template <osl::Player P>
00801 bool osl::search::AlphaBeta2Tree<EvalT>::
00802 examineMovesOther(Window& w, MoveLogProb& best_move, int& best_value, 
00803                   int& tried_moves, int& alpha_update, int& last_alpha_update)
00804 {
00805   assert(w.isConsistent());
00806 
00807   const int id = shared->treeId(this);
00808 #if DEBUG_SMP > 3
00809   {
00810     boost::mutex::scoped_lock lk(OslConfig::lock_io);
00811     std::cerr << "start split at " << curLimit() << " " << id << " turn " << P 
00812               << " move " << tried_moves 
00813               << " parent " << shared->info[id].parent << "\n";
00814     history().dump();
00815   }
00816 #endif
00817   AlphaBeta2ParallelCommon::TreeInfo *info = &shared->info[id];
00818   info->window = w;
00819   info->is_root = false;
00820   info->in_pv = (! w.null()) && (! best_move.validMove());
00821   info->value = best_value;
00822   info->move_index = tried_moves;
00823   info->turn = P;
00824   info->best_move = best_move;
00825   info->alpha_update = alpha_update;
00826   info->last_alpha_update = last_alpha_update;
00827   if (! shared->split(this, id, info->thread_id, shared->max_thread_group)) {
00828 #if DEBUG_SMP > 2
00829     boost::mutex::scoped_lock lk(OslConfig::lock_io);
00830     std::cerr << "failed split " << id << " turn " << P << "\n";
00831     for (int i=0; i<shared->max_threads; ++i) {
00832       std::cerr << "  " << i << " " << shared->job[i] << "\n";
00833     }
00834 #endif
00835     shared->cancelled_splits.inc();
00836     throw AlphaBeta2ParallelCommon::SplitFailed();
00837   }
00838   SCOPED_LOCK(lk,info->lock);
00839   best_value = info->search_value;
00840   best_move = info->best_move;
00841   w = info->window;
00842   tried_moves = info->move_index;
00843   alpha_update += info->alpha_update;
00844   last_alpha_update = info->last_alpha_update;
00845 #if DEBUG_SMP > 3
00846   {
00847     boost::mutex::scoped_lock lk(OslConfig::lock_io);
00848     std::cerr << "back from split at " << curLimit() << " " << id << " turn " << P << " parent " << shared->info[id].parent << "\n";
00849   }
00850 #endif
00851   testStop();
00852   return EvalTraits<P>::betterThan(best_value, w.beta(P));
00853 }
00854 
00855 template <class EvalT>
00856 void osl::search::AlphaBeta2Tree<EvalT>::
00857 examineMovesOther(int tree_id)
00858 {
00859   bool cut = false;
00860   AlphaBeta2ParallelCommon::TreeInfo *parent = shared->parent(tree_id);
00861   for (std::pair<MoveLogProb,size_t> m = shared->nextMove(tree_id); m.first.validMove() && !stopping(); 
00862        m = shared->nextMove(tree_id)) {
00863     bool in_pv = parent->in_pv;
00864     if (in_pv) {
00865       in_pv = ! parent->best_move.validMove();
00866     }
00867     assert(parent->turn == m.first.player());
00868     try {
00869       const bool cut_by_move =
00870         (parent->turn == BLACK)
00871         ? testMoveOther<BLACK>(tree_id, m.first, m.second, in_pv)
00872         : testMoveOther<WHITE>(tree_id, m.first, m.second, in_pv);
00873       if (cut_by_move) {
00874         cut = true;
00875         break;
00876       }
00877       testStop();
00878     }
00879     catch (BetaCut&) {
00880       assert(stop_tree);
00881     }
00882     catch (TableFull&) {
00883       stop_tree = true;
00884       this->stopNow();
00885       break;
00886     }
00887     catch (misc::NoMoreTime&) {
00888       stop_tree = true;
00889       this->stopNow();
00890 #if DEBUG_SMP > 2
00891       boost::mutex::scoped_lock lk(OslConfig::lock_io);
00892       std::cerr << "caught timeout in tree " << tree_id << " thread " << shared->info[tree_id].thread_id << "\n";
00893 #endif
00894       break;
00895     }
00896     catch (NoMoreMemory&) {
00897       stop_tree = true;
00898       this->stopNow();
00899 #if DEBUG_SMP > 2
00900       boost::mutex::scoped_lock lk(OslConfig::lock_io);
00901       std::cerr << "caught memory full in tree " << tree_id << " thread " << shared->info[tree_id].thread_id << "\n";
00902 #endif
00903       break;
00904     }
00905     catch (std::exception& e) {
00906       this->stopNow();
00907       stop_tree = true;
00908       boost::mutex::scoped_lock lk(OslConfig::lock_io);
00909       std::cerr << "caught exception at " << tree_id << " " << e.what() << "\n";
00910       break;
00911     }
00912     catch (...) {
00913       boost::mutex::scoped_lock lk(OslConfig::lock_io);
00914       std::cerr << "caught unknown exception at " << tree_id << "\n";
00915       throw;
00916     }
00917   }
00918   // cut or no more moves to search
00919 }
00920 
00921 namespace osl
00922 {
00923   namespace search
00924   {
00925 #ifndef MINIMAL
00926     template struct AlphaBeta2Parallel<eval::ProgressEval>;
00927 
00928     template 
00929     bool AlphaBeta2Tree<eval::ProgressEval>::examineMovesOther<BLACK>(Window&, MoveLogProb&, int&, int&, int&, int&);
00930     template 
00931     bool AlphaBeta2Tree<eval::ProgressEval>::examineMovesOther<WHITE>(Window&, MoveLogProb&, int&, int&, int&, int&);
00932 
00933     template
00934     void AlphaBeta2Tree<eval::ProgressEval>::examineMovesRootPar<BLACK>(const MoveLogProbVector&, size_t, Window, MoveLogProb&, int&);
00935     template
00936     void AlphaBeta2Tree<eval::ProgressEval>::examineMovesRootPar<WHITE>(const MoveLogProbVector&, size_t, Window, MoveLogProb&, int&);
00937 #endif
00938     template struct AlphaBeta2Parallel<eval::ml::OpenMidEndingEval>;
00939 
00940     template 
00941     bool AlphaBeta2Tree<eval::ml::OpenMidEndingEval>::examineMovesOther<BLACK>(Window&, MoveLogProb&, int&, int&, int&, int&);
00942     template 
00943     bool AlphaBeta2Tree<eval::ml::OpenMidEndingEval>::examineMovesOther<WHITE>(Window&, MoveLogProb&, int&, int&, int&, int&);
00944 
00945     template
00946     void AlphaBeta2Tree<eval::ml::OpenMidEndingEval>::examineMovesRootPar<BLACK>(const MoveLogProbVector&, size_t, Window, MoveLogProb&, int&);
00947     template
00948     void AlphaBeta2Tree<eval::ml::OpenMidEndingEval>::examineMovesRootPar<WHITE>(const MoveLogProbVector&, size_t, Window, MoveLogProb&, int&);
00949   }
00950 }
00951 
00952 #endif /* OSL_SMP */
00953 /* ------------------------------------------------------------------------- */
00954 // ;;; Local Variables:
00955 // ;;; mode:c++
00956 // ;;; c-basic-offset:2
00957 // ;;; End:
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines