UCI Engine output

Discussion of chess software programming and technical issues.

Moderator: Ras

User avatar
hgm
Posts: 28391
Joined: Fri Mar 10, 2006 10:06 am
Location: Amsterdam
Full name: H G Muller

Re: UCI Engine output

Post by hgm »

WinBoard has a separate input thread for each engine, and it simply waits there in a blocking read call untill the engine produces anything. When it does, it gets it instantly, processes it, and starts reading again.

Note that on most OS the buffer associated with a pipe is quite limited, and when you flood it with output when the reader is not paying attention at the other end, it will fill up, and the writer will block in the write call that would make the buffer overflow. Thus very verbose engines might see their processes suspended when the GUI is tardy in reading their output, effectively using much less time than they were granted (when the output thread is also the search thread, which usually is the case).
Dave_N
Posts: 153
Joined: Fri Sep 30, 2011 7:48 am

Re: UCI Engine output

Post by Dave_N »

hgm wrote:WinBoard has a separate input thread for each engine, and it simply waits there in a blocking read call untill the engine produces anything. When it does, it gets it instantly, processes it, and starts reading again.

Note that on most OS the buffer associated with a pipe is quite limited, and when you flood it with output when the reader is not paying attention at the other end, it will fill up, and the writer will block in the write call that would make the buffer overflow. Thus very verbose engines might see their processes suspended when the GUI is tardy in reading their output, effectively using much less time than they were granted (when the output thread is also the search thread, which usually is the case).
I like the sound of the blocking read call that waits for input, that's what I am trying to work out how to do with the UCI protocol, although I will probably support Winboard next. I think I read somewhere that memset(), strings and other array processing functions can waste a lot of cpu time, so I am trying to leave more time for the engines.

I suppose the pipe buffer info could be obtained from the OS (windows,linux,mac) ?
Last edited by Dave_N on Fri Oct 07, 2011 1:23 pm, edited 1 time in total.
Dave_N
Posts: 153
Joined: Fri Sep 30, 2011 7:48 am

Re: UCI Engine output

Post by Dave_N »

ilari wrote:
Dave_N wrote:I suppose the time to look for input could depend on the clock increment ... If I have a time increment of 1/10th of a second then the engine will play optimally if I look every 1/20th of a second.
The better, simpler, more reliable and more efficient method is to forget about polling for input completely and use synchronized reads in a separate thread. That way you'll get any input instantly.
Working on this, thanks for the information =)
User avatar
hgm
Posts: 28391
Joined: Fri Mar 10, 2006 10:06 am
Location: Amsterdam
Full name: H G Muller

Re: UCI Engine output

Post by hgm »

Dave_N wrote:I like the sound of the blocking read call that waits for input, that's what I am trying to work out how to do with the UCI protocol, although I will probably support Winboard next.
The protocol you use would not make the slightest difference for how you read. Itonly starts playing a role after you read something, to decode what it means.
Dave_N
Posts: 153
Joined: Fri Sep 30, 2011 7:48 am

Re: UCI Engine output

Post by Dave_N »

So for example in windows I would use PeekNamedPipe() then read when something is available?
I am quite interested in the special case of waiting until output has completed and sent "bestmove" after a call like "go depth 18", however perhaps PeekNamedPipe() will reply that data is available all the time from the moment the first line is sent from the engine since there is data in the stdin.
Dave_N
Posts: 153
Joined: Fri Sep 30, 2011 7:48 am

Re: UCI Engine output

Post by Dave_N »

Of course if the pipe is going to overflow I need to parse quite often
User avatar
hgm
Posts: 28391
Joined: Fri Mar 10, 2006 10:06 am
Location: Amsterdam
Full name: H G Muller

Re: UCI Engine output

Post by hgm »

Dave_N wrote:So for example in windows I would use PeekNamedPipe() then read when something is available?
I am quite interested in the special case of waiting until output has completed and sent "bestmove" after a call like "go depth 18", however perhaps PeekNamedPipe() will reply that data is available all the time from the moment the first line is sent from the engine since there is data in the stdin.
Indeed. The engine will produce PV lines before its bestmove, they will fill up the buffer (there could be a lot of them, especially in multi-PV mode), the engine process will be stalled by the OS, and the bestmove command would never come.

Further more, becareful with PeekNamedPipe. There seems to be some hidden buffering that makes PeekNamedPipe say there is no input, while you have not read everything there is yet, when using getchar(). Bettertouse a separate thread, and have it hang waiting for input.
tpetzke
Posts: 686
Joined: Thu Mar 03, 2011 4:57 pm
Location: Germany

Re: UCI Engine output

Post by tpetzke »

...and I have also seen the other case where PeekNamedPipe said there is input (although there was none) and when you then try to read the non existing input your program hangs until real input appears.

Thomas...
User avatar
ilari
Posts: 750
Joined: Mon Mar 27, 2006 7:45 pm
Location: Finland

Re: UCI Engine output

Post by ilari »

tpetzke wrote:...and I have also seen the other case where PeekNamedPipe said there is input (although there was none) and when you then try to read the non existing input your program hangs until real input appears.

Thomas...
If you read input in a separate thread with a blocking ReadFile() call you don't have to (and shouldn't) use PeekNamedPipe() anywhere. Please take a look at Cute Chess' PipeReader class to see how it can be done:
header and source
Note that you need some synchronization between the main thread and the input-reading thread. Semaphores are the most natural and portable way to do it.
Dave_N
Posts: 153
Joined: Fri Sep 30, 2011 7:48 am

Re: UCI Engine output

Post by Dave_N »

The code seems to suggest that the "isready" command is occasionally sent to "avoid signal spam" unless I am misinterpreting this:-

Code: Select all

// To avoid signal spam, send the 'readyRead' signal only
 120                 // if we have a whole line of new data
 121                 if (m_lastNewLine <= int(dwRead))
 122                         emit readyRead();