internal static void Warmup() { // Bench 128 4 17 yields: // CheckInfoBroker: 140 (4/32/40/32/32) // EvalInfoBroker: 16 (4/4/4/4) // SwapListBroker: 16 (4/4/4/4) // MovesSearchedBroker: 120 (28/36/28/28) // PositionBroker: 32 (8/8/8/8) // StateInfoArrayBroker: 16 (4/4/4/4) // MListBroker: 20 (4/4/4/4/4) // LoopStackBroker: 32 (8/8/8/8) // MovePickerBroker: 136 (32/40/32/32) // StateInfoBroker: 132 (32/36/32/32) // Specific allocation not to overallocate memory for nothing int i, brokerSize; // Reusing brokers brokerSize = 40; for (i = 0; i < brokerSize; i++) { CheckInfoBroker.GetObject(); } for (i = 0; i < brokerSize; i++) { CheckInfoBroker.Free(); } brokerSize = 4; for (i = 0; i < brokerSize; i++) { EvalInfoBroker.GetObject(); } for (i = 0; i < brokerSize; i++) { EvalInfoBroker.Free(); } brokerSize = 4; for (i = 0; i < brokerSize; i++) { SwapListBroker.GetObject(); } for (i = 0; i < brokerSize; i++) { SwapListBroker.Free(); } brokerSize = 36; for (i = 0; i < brokerSize; i++) { MovesSearchedBroker.GetObject(); } for (i = 0; i < brokerSize; i++) { MovesSearchedBroker.Free(); } brokerSize = 8; for (i = 0; i < brokerSize; i++) { PositionBroker.GetObject(); } for (i = 0; i < brokerSize; i++) { PositionBroker.Free(); } brokerSize = 4; for (i = 0; i < brokerSize; i++) { StateInfoArrayBroker.GetObject(); } for (i = 0; i < brokerSize; i++) { StateInfoArrayBroker.Free(); } brokerSize = 4; for (i = 0; i < brokerSize; i++) { MListBroker.GetObject(); } for (i = 0; i < brokerSize; i++) { MListBroker.Free(); } brokerSize = 36; for (i = 0; i < brokerSize; i++) { StateInfoBroker.GetObject(); } for (i = 0; i < brokerSize; i++) { StateInfoBroker.Free(); } // Recycling brokers brokerSize = 8; LoopStack[] arrLoopStack = new LoopStack[brokerSize]; for (i = 0; i < brokerSize; i++) { arrLoopStack[i] = LoopStackBroker.GetObject(); } for (i = brokerSize - 1; i >= 0; i--) { LoopStackBroker.Free(arrLoopStack[i]); } brokerSize = 40; MovePicker[] arrMovePicker = new MovePicker[brokerSize]; for (i = 0; i < brokerSize; i++) { arrMovePicker[i] = MovePickerBroker.GetObject(); } for (i = brokerSize - 1; i >= 0; i--) { MovePickerBroker.Free(arrMovePicker[i]); } }
internal static void init() { for (int i = 0; i < Constants.BROKER_SLOTS; i++) { _pool[i] = new LoopStack[0]; } }
internal static void Free(LoopStack obj) { obj.Recycle(); #if WINDOWS_RT _cnt[Environment.CurrentManagedThreadId & Constants.BROKER_SLOT_MASK]--; #else _cnt[System.Threading.Thread.CurrentThread.ManagedThreadId & Constants.BROKER_SLOT_MASK]--; #endif }
internal static LoopStack GetObject() { int slotID = System.Threading.Thread.CurrentThread.ManagedThreadId & Constants.BROKER_SLOT_MASK; if (_cnt[slotID] == _pool[slotID].Length) { int poolLength = _pool[slotID].Length; LoopStack[] temp = new LoopStack[poolLength + Constants.BrokerCapacity]; Array.Copy(_pool[slotID], temp, poolLength); for (int i = 0; i < Constants.BrokerCapacity; i++) { temp[poolLength + i] = new LoopStack(); } _pool[slotID] = temp; } return(_pool[slotID][_cnt[slotID]++]); }
internal static LoopStack GetObject() { int slotID = System.Threading.Thread.CurrentThread.ManagedThreadId & Constants.BROKER_SLOT_MASK; if (_cnt[slotID] == _pool[slotID].Length) { int poolLength = _pool[slotID].Length; LoopStack[] temp = new LoopStack[poolLength + Constants.BrokerCapacity]; Array.Copy(_pool[slotID], temp, poolLength); for (int i = 0; i < Constants.BrokerCapacity; i++) { temp[poolLength + i] = new LoopStack(); } _pool[slotID] = temp; } return _pool[slotID][_cnt[slotID]++]; }
internal static void Free(LoopStack obj) { obj.Recycle(); _cnt[System.Threading.Thread.CurrentThread.ManagedThreadId & Constants.BROKER_SLOT_MASK]--; }
/// Thread::idle_loop() is where the thread is parked when it has no work to do. /// The parameter 'master_sp', if non-NULL, is a pointer to an active SplitPoint /// object for which the thread is the master. internal void idle_loop(SplitPoint sp_master, ManualResetEvent initEvent) { if (initEvent != null) { // Signal done initEvent.Set(); } bool use_sleeping_threads = Threads.useSleepingThreads; // If this thread is the master of a split point and all slaves have // finished their work at this split point, return from the idle loop. while ((sp_master == null) || (sp_master.slavesMask != 0)) { // If we are not searching, wait for a condition to be signaled // instead of wasting CPU time polling for work. while (do_sleep || do_exit || (!is_searching && use_sleeping_threads)) { if (do_exit) { Debug.Assert(sp_master == null); return; } // Grab the lock to avoid races with Thread::wake_up() ThreadHelper.lock_grab(sleepLock); // If we are master and all slaves have finished don't go to sleep if ((sp_master != null) && (sp_master.slavesMask == 0)) { ThreadHelper.lock_release(sleepLock); break; } // Do sleep after retesting sleep conditions under lock protection, in // particular we need to avoid a deadlock in case a master thread has, // in the meanwhile, allocated us and sent the wake_up() call before we // had the chance to grab the lock. if (do_sleep || !is_searching) { ThreadHelper.cond_wait(sleepCond, sleepLock); } ThreadHelper.lock_release(sleepLock); } // If this thread has been assigned work, launch a search if (is_searching) { Debug.Assert(!do_sleep && !do_exit); ThreadHelper.lock_grab(Threads.splitLock); Debug.Assert(is_searching); SplitPoint sp = curSplitPoint; ThreadHelper.lock_release(Threads.splitLock); LoopStack ls = LoopStackBroker.GetObject(); Stack[] ss = ls.ss; int ssPos = 0; Position pos = PositionBroker.GetObject(); pos.copy(sp.pos, this); Array.Copy(sp.ss, sp.ssPos - 1, ss, ssPos, 4); ss[ssPos + 1].sp = sp; ThreadHelper.lock_grab(sp.Lock); if (sp.nodeType == NodeTypeC.Root) { Search.search(NodeTypeC.SplitPointRoot, pos, ss, ssPos + 1, sp.alpha, sp.beta, sp.depth); } else if (sp.nodeType == NodeTypeC.PV) { Search.search(NodeTypeC.SplitPointPV, pos, ss, ssPos + 1, sp.alpha, sp.beta, sp.depth); } else if (sp.nodeType == NodeTypeC.NonPV) { Search.search(NodeTypeC.SplitPointNonPV, pos, ss, ssPos + 1, sp.alpha, sp.beta, sp.depth); } else { Debug.Assert(false); } Debug.Assert(is_searching); is_searching = false; #if ACTIVE_REPARENT sp.allSlavesRunning = false; #endif sp.slavesMask &= ~(1UL << idx); sp.nodes += pos.nodes; // Wake up master thread so to allow it to return from the idle loop in // case we are the last slave of the split point. if (use_sleeping_threads && this != sp.master && !sp.master.is_searching) { sp.master.wake_up(); } // After releasing the lock we cannot access anymore any SplitPoint // related data in a safe way becuase it could have been released under // our feet by the sp master. Also accessing other Thread objects is // unsafe because if we are exiting there is a chance are already freed. ThreadHelper.lock_release(sp.Lock); #if ACTIVE_REPARENT // Try to reparent to the first split point, with still all slaves // running, where we are available as a possible slave. for (int i = 0; i < Threads.size(); i++) { Thread th = Threads.threads[i]; int spCnt = th.splitPointsCnt; SplitPoint latest = th.splitPoints[spCnt != 0 ? spCnt - 1 : 0]; if (this.is_available_to(th) && spCnt > 0 && !th.cutoff_occurred() && latest.allSlavesRunning && Utils.more_than_one(latest.slavesMask)) { ThreadHelper.lock_grab(latest.Lock); ThreadHelper.lock_grab(Threads.splitLock); // Retest all under lock protection, we are in the middle // of a race storm here ! if (this.is_available_to(th) && spCnt == th.splitPointsCnt && !th.cutoff_occurred() && latest.allSlavesRunning && Utils.more_than_one(latest.slavesMask)) { latest.slavesMask |= 1UL << idx; curSplitPoint = latest; is_searching = true; } ThreadHelper.lock_release(Threads.splitLock); ThreadHelper.lock_release(latest.Lock); break; // Exit anyhow, only one try (enough in 99% of cases) } } #endif pos.startState = null; pos.st = null; PositionBroker.Free(); LoopStackBroker.Free(ls); } } }