Engines lose time (not only) under ChessGUI.

Discussion of anything and everything relating to chess playing software and machines.

Moderators: hgm, Rebel, chrisw

User avatar
Matthias Gemuh
Posts: 3245
Joined: Thu Mar 09, 2006 9:10 am

Re: Engines lose time (not only) under ChessGUI.

Post by Matthias Gemuh »

bob wrote:
Matthias Gemuh wrote: Engine authors, don't tell me to use unbuffered output, or to flush buffers.
That's easy on the engine side only.

Cheers,
Matthias.
That is easy on _both_ sides. My testing referee program uses read()/write() and has no problems playing games that last .01 seconds in total...
That sounds mysterious.

I don't see how I can write() to the standard inputs of 2 different child processes under Windows.
CreateProcess() expects file handles of a type that can be used by the evil ReadFile()/WriteFile() but not by read()/write().

If your referee is not unix-only, can you please reveal how he write() to the standard inputs of 2 different child processes ?

Matthias.
My engine was quite strong till I added knowledge to it.
http://www.chess.hylogic.de
User avatar
hgm
Posts: 27809
Joined: Fri Mar 10, 2006 10:06 am
Location: Amsterdam
Full name: H G Muller

Re: Engines lose time (not only) under ChessGUI.

Post by hgm »

Of course it is Unix-only! :wink:
User avatar
Matthias Gemuh
Posts: 3245
Joined: Thu Mar 09, 2006 9:10 am

Re: Engines lose time (not only) under ChessGUI.

Post by Matthias Gemuh »

hgm wrote:Of course it is Unix-only! :wink:
Unix/Linux seems to be a nice OS but I hate to see that no file format can be identified by file name extention (exe, txt, jpg, etc.).
My engine was quite strong till I added knowledge to it.
http://www.chess.hylogic.de
bob
Posts: 20943
Joined: Mon Feb 27, 2006 7:30 pm
Location: Birmingham, AL

Re: Engines lose time (not only) under ChessGUI.

Post by bob »

Matthias Gemuh wrote:
bob wrote:
Matthias Gemuh wrote: Engine authors, don't tell me to use unbuffered output, or to flush buffers.
That's easy on the engine side only.

Cheers,
Matthias.
That is easy on _both_ sides. My testing referee program uses read()/write() and has no problems playing games that last .01 seconds in total...
That sounds mysterious.

I don't see how I can write() to the standard inputs of 2 different child processes under Windows.
CreateProcess() expects file handles of a type that can be used by the evil ReadFile()/WriteFile() but not by read()/write().

If your referee is not unix-only, can you please reveal how he write() to the standard inputs of 2 different child processes ?

Matthias.
There's your first problem. I use linux and this works perfectly there. :)
bob
Posts: 20943
Joined: Mon Feb 27, 2006 7:30 pm
Location: Birmingham, AL

Re: Engines lose time (not only) under ChessGUI.

Post by bob »

Matthias Gemuh wrote:
hgm wrote:Of course it is Unix-only! :wink:
Unix/Linux seems to be a nice OS but I hate to see that no file format can be identified by file name extention (exe, txt, jpg, etc.).
You can do that if you insist, but you are not forced to call your executables something.exe if you don't want to.
Sven
Posts: 4052
Joined: Thu May 15, 2008 9:57 pm
Location: Berlin, Germany
Full name: Sven Schüle

Re: Engines lose time (not only) under ChessGUI.

Post by Sven »

Matthias Gemuh wrote:
bob wrote:
Matthias Gemuh wrote: Engine authors, don't tell me to use unbuffered output, or to flush buffers.
That's easy on the engine side only.

Cheers,
Matthias.
That is easy on _both_ sides. My testing referee program uses read()/write() and has no problems playing games that last .01 seconds in total...
That sounds mysterious.

I don't see how I can write() to the standard inputs of 2 different child processes under Windows.
CreateProcess() expects file handles of a type that can be used by the evil ReadFile()/WriteFile() but not by read()/write().

If your referee is not unix-only, can you please reveal how he write() to the standard inputs of 2 different child processes ?

Matthias.
If this were impossible under Windows then we would not have WinBoard. The key concept is the pipe, which is originally a UNIX concept but which has been ported to Windows. WinBoard creates both engines as child processes and maintains two pipes per engine, one for writing and one for reading. So both engines, when reading their standard input, are actually reading what WinBoard has written into the pipe.

Sven
User avatar
Matthias Gemuh
Posts: 3245
Joined: Thu Mar 09, 2006 9:10 am

Re: Engines lose time (not only) under ChessGUI.

Post by Matthias Gemuh »

Sven Schüle wrote: If this were impossible under Windows then we would not have WinBoard. The key concept is the pipe, which is originally a UNIX concept but which has been ported to Windows. WinBoard creates both engines as child processes and maintains two pipes per engine, one for writing and one for reading. So both engines, when reading their standard input, are actually reading what WinBoard has written into the pipe.

Sven
You haven't understood the problem.

That pipe works with or without a buffer.

1) Without a buffer, the GUI routine writing into that pipe cannot return till engine has read the data. If engine crashes, GUI crashes too.

2) With a buffer (on GUI end), Windows does not flush that buffer into pipe immediately. GUI can force a flush but at the price in 1) above.
My engine was quite strong till I added knowledge to it.
http://www.chess.hylogic.de
User avatar
hgm
Posts: 27809
Joined: Fri Mar 10, 2006 10:06 am
Location: Amsterdam
Full name: H G Muller

Re: Engines lose time (not only) under ChessGUI.

Post by hgm »

Matthias Gemuh wrote:1) Without a buffer, the GUI routine writing into that pipe cannot return till engine has read the data. If engine crashes, GUI crashes too.
This should not be true! I can't believe Windows would implement pipes that poorly. A pipe is supposed to have its own buffer in the OS, (even the very earliest Unix systems could buffer 4KB there), and the writing program is not supposed to block unless it overflows that buffer. You definitely should not have to wait until the progam reads it.
2) With a buffer (on GUI end), Windows does not flush that buffer into pipe immediately. GUI can force a flush but at the price in 1) above.
Except for that I think (1) has no price, this is true. Buffering is not recommended.

If you have this problem, I think it is because you are sending too much at once, clogging the pipe.
User avatar
Matthias Gemuh
Posts: 3245
Joined: Thu Mar 09, 2006 9:10 am

Re: Engines lose time (not only) under ChessGUI.

Post by Matthias Gemuh »

hgm wrote:
Matthias Gemuh wrote:1) Without a buffer, the GUI routine writing into that pipe cannot return till engine has read the data. If engine crashes, GUI crashes too.
This should not be true! I can't believe Windows would implement pipes that poorly. A pipe is supposed to have its own buffer in the OS, (even the very earliest Unix systems could buffer 4KB there), and the writing program is not supposed to block unless it overflows that buffer. You definitely should not have to wait until the progam reads it.
2) With a buffer (on GUI end), Windows does not flush that buffer into pipe immediately. GUI can force a flush but at the price in 1) above.
Except for that I think (1) has no price, this is true. Buffering is not recommended.

If you have this problem, I think it is because you are sending too much at once, clogging the pipe.
One last trial to explain it.

Windows offers only WriteFile() to write into a pipe.
(Obselete write functions do exist that work like WriteFile())
WriteFile() has an internal buffer that makes WriteFile() non-blocking.
Windows flushes that buffer depending on how full it is or how long data has been standing in it. This efficiency decision effectively steals time from any engine waiting at the other end of the pipe.
The internal WriteFile() buffer can be forcefully flushed with FlushFileBuffers() to eliminate delays, but that is blocking.
My engine was quite strong till I added knowledge to it.
http://www.chess.hylogic.de
User avatar
hgm
Posts: 27809
Joined: Fri Mar 10, 2006 10:06 am
Location: Amsterdam
Full name: H G Muller

Re: Engines lose time (not only) under ChessGUI.

Post by hgm »

What you say is either not correct,or you are using confusing terminology.

WriteFile has _no_ buffer associated with it. It gets its data handed to it in an array that is called a buffer. But there is no way to 'flush' that. In a sense, flushing it is exactly what the WriteFile call does, namely copying the data in the buffer to system memory space.

If you use WriteFile on a pipe, that pipe has a buffer associated with it. There is no way to flush that buffer, it is completely outside the control of the sending program, not even in its memory space. You cannot request the pipe not to have a buffer by using unbuffered I/O.

This is what MicroSoft sys about it (emphasis mine):
The WriteFile function returns when one of the following conditions occur:

* The number of bytes requested is written.
* A read operation releases buffer space on the read end of the pipe (if the write was blocked). For more information, see the Pipes section.
* An asynchronous handle is being used and the write is occurring asynchronously.
* An error occurs.
The blocking only occurs conditionally, because the pipe buffer in the OS is full, which usually will not be the case, unless you continue to dump vast amounts of data in it that no one is reading.
Pipes
If an anonymous pipe is being used and the read handle has been closed, when WriteFile attempts to write using the pipe's corresponding write handle, the function returns FALSE and GetLastError returns ERROR_BROKEN_PIPE.

If the pipe buffer is full when an application uses the WriteFile function to write to a pipe, the write operation may not finish immediately. The write operation will be completed when a read operation (using the ReadFile function) makes more system buffer space available for the pipe.

When writing to a nonblocking, byte-mode pipe handle with insufficient buffer space, WriteFile returns TRUE with *lpNumberOfBytesWritten < nNumberOfBytesToWrite.

For more information about pipes, see Pipes.
The write operation may not finish immediately if the pipe buffer is full. I.e., normally, a write on a pipe will finish immediately, as the pipe buffer will not be full, and this is mentioned as a necessary condition for not finishing immediately (i.e. blocking).

The problem you sketch simply does not occur in GUI->engine traffic. A GUI would never send more data than fits in the pipe buffer. It would send at most a modest amount, and then start waiting until the engine replies. And usually such a reply would only come afte the engine has read all the data it was sent.

E.g., you send a UCI engine a position and a go command. These are not nearly enough to fill the pipe buffer, if the game was not 1000 moves long. Now you will be waiting for a bestmove reply. You will not recieve it before the engine will have read the newline following the go command. Which is indeed the last thing you sent it. So at that point the pipe buffer will be empty. Only then you will start sending the engine the next position command, which will thus go into an empty buffer, and not be able to fill it by itself. The WriteFile call will thus not block, and return instantly.