cdani wrote:mar wrote:lucasart wrote:I've got some lazy SMP working, and it gives me this kind of repeated and shuffled output (eg. with 8 threads):
I didn't bother with this, I simply don't output anything for helpers and (if a helper finished first) I echo score/pv again at the end of the iteration.
As I ignore the threads > 0, I only show the info of the thread 0. I even do not collect the pv for other threads as it is not necessary.
I suppose you can do that. It's not very correct though, as it means you may show completed iterations later than they actually happen (what if thread #2 finished an iteration 10 sec before thread 0?).
I opted for a more proper solution, although it requires a bit more work:
* a PV per thread (backed-up recursively through the stack using VLA for compactness).
* a global structure that contains at any time the depth/score/nodes/PV of the highest depth completed so far (by at least one thread).
* only the timer thread (not search threads) writes to std::cout, which alleviates the need for locking std::cout, and allows me to print the "info depth score nodes pv" line in strictly increasing depth order.
Code: Select all
/* declaration (uci.h) */
class Info {
Move _pv[MAX_PLY + 1];
int _depth, _score, _nodes;
mutable bool updated;
mutable std::mutex m;
public:
Info();
void update(int depth, int score, int nodes, Move *pv);
void print() const;
};
/* implementation (uci.cc) */
Info::Info() : _depth(0), updated(false)
{
_pv[0].clear();
}
void Info::update(int depth, int score, int nodes, Move *pv)
{
std::lock_guard<std::mutex> lk(m);
if (depth > _depth) {
_depth = depth;
_score = score;
_nodes = nodes;
for (int i = 0; ; i++)
if ((_pv[i] = pv[i]).null())
break;
updated = true;
}
}
// print info line, only if it has been updated since last print()
void Info::print() const
{
std::lock_guard<std::mutex> lk(m);
if (updated) {
std::ostringstream os;
os << "info depth " << _depth << " score " << _score
<< " nodes " << _nodes << " pv";
for (int i = 0; !_pv[i].null(); i++)
os << ' ' << _pv[i].to_string();
std::cout << os.str() << std::endl;
updated = false;
}
}
* Any search threads call Info::update() whenever it completes an iteration. Info will only be updated if the depth is strictly larger than the highest completed depth so far, and will set updated = true in that case.
* Timer thread (which loops in 5ms resolution) calls Info::print(), which only prints if updated = true, which means that a higher depth was completed (by at least one thread) since last Info::print() actually printed something.
Theory and practice sometimes clash. And when that happens, theory loses. Every single time.