kbhit() taking huge CPU??

Discussion of chess software programming and technical issues.

Moderators: hgm, Rebel, chrisw

JVMerlino
Posts: 1357
Joined: Wed Mar 08, 2006 10:15 pm
Location: San Francisco, California

kbhit() taking huge CPU??

Post by JVMerlino »

(cross-posting from main forum -- sorry about that).

It figures this would happen around April 1st.

Still working on Myrddin, I was perplexed by how much slower the engine appeared to be in console mode compared to being run inside a GUI.

After spending quite a bit of time with various MSVC compiler options, Task Manager, and Intel's VTUNE (which I highly recommend, by the way), I have discovered that it is the call to kbhit() that is taking an average of 30% of the CPU, as sometimes as much as 50%.

Task Manager shows the program CSRSS.EXE as hogging the CPU.

VTUNE shows kbhit() calling the Windows Kernel function GetNumberOfConsoleInputEvents(), which then calls the NTDLL function CsrClientCallServer() function. It is this last function that appears to be the culprit.

Here's all of the relevant code:

Code: Select all

/*======================================================================== 
** InitializeInput -- Open the stdin pipe for reading 
**======================================================================== 
*/ 
void InitializeInput(void) 
{ 
   DWORD   dw; 

   input_handle = GetStdHandle(STD_INPUT_HANDLE); 
   is_pipe = !GetConsoleMode(input_handle, &dw); 

   setbuf(stdout, NULL); 
} 

/*======================================================================== 
** IsInputAvailable -- Check the stdin pipe for input 
**======================================================================== 
*/ 
int IsInputAvailable(void) 
{ 
   DWORD   nchars; 

   if (stdin->_cnt > 0) 
      return 1; 

   if (is_pipe) 
   { 
      if (!PeekNamedPipe(input_handle, NULL, 0, NULL, &nchars, NULL)) 
         return 1; 

      return (nchars); 
   } 
   else 
      return(_kbhit()); 
} 

/*======================================================================== 
** CheckForInput - Check for user input 
**======================================================================== 
*/ 
BOOL   CheckForInput(BOOL bWaitForInput) 
{ 
   if (bWaitForInput == FALSE) 
   { 
      if (!IsInputAvailable()) 
         return(FALSE); 
   } 

   if (!fgets(line, 256, stdin)) 
      return(-1);   // shouldn't ever happen 

   if (line[0] == '\n') 
      return(FALSE); 

#if LOGFILE 
   fprintf(logfile, "> Received %s", line); 
#endif 
   sscanf(line, "%s", command); 

   return(TRUE); 
} 


Most engine programmers will recognize this as very similar to the code from Crafty (which I also found with slight variations in many other engines).

I call CheckForInput() about once every 8K nodes. Changing how often I call it does not seem to have an appreciable effect (which is also very bizarre). Running Myrddin from inside the compiler (for both the release and the debug versions) is no different from running it manually from Windows.

I've compiled Crafty with the same settings, and Greko as well. Neither of the resulting programs show the same behavior as with Myrddin. As a last result, I have even copied the equivalent code from Crafty, with the same poor results.

Clearly, I'm missing something, which I hope that somebody out there has had to deal with before. Any recommendations would be most welcome. This is not how I expected to spend my time working on Alpha 2.

jm
bob
Posts: 20943
Joined: Mon Feb 27, 2006 7:30 pm
Location: Birmingham, AL

Re: kbhit() taking huge CPU??

Post by bob »

JVMerlino wrote:(cross-posting from main forum -- sorry about that).

It figures this would happen around April 1st.

Still working on Myrddin, I was perplexed by how much slower the engine appeared to be in console mode compared to being run inside a GUI.

After spending quite a bit of time with various MSVC compiler options, Task Manager, and Intel's VTUNE (which I highly recommend, by the way), I have discovered that it is the call to kbhit() that is taking an average of 30% of the CPU, as sometimes as much as 50%.

Task Manager shows the program CSRSS.EXE as hogging the CPU.

VTUNE shows kbhit() calling the Windows Kernel function GetNumberOfConsoleInputEvents(), which then calls the NTDLL function CsrClientCallServer() function. It is this last function that appears to be the culprit.

Here's all of the relevant code:

Code: Select all

/*======================================================================== 
** InitializeInput -- Open the stdin pipe for reading 
**======================================================================== 
*/ 
void InitializeInput(void) 
{ 
   DWORD   dw; 

   input_handle = GetStdHandle(STD_INPUT_HANDLE); 
   is_pipe = !GetConsoleMode(input_handle, &dw); 

   setbuf(stdout, NULL); 
} 

/*======================================================================== 
** IsInputAvailable -- Check the stdin pipe for input 
**======================================================================== 
*/ 
int IsInputAvailable(void) 
{ 
   DWORD   nchars; 

   if (stdin->_cnt > 0) 
      return 1; 

   if (is_pipe) 
   { 
      if (!PeekNamedPipe(input_handle, NULL, 0, NULL, &nchars, NULL)) 
         return 1; 

      return (nchars); 
   } 
   else 
      return(_kbhit()); 
} 

/*======================================================================== 
** CheckForInput - Check for user input 
**======================================================================== 
*/ 
BOOL   CheckForInput(BOOL bWaitForInput) 
{ 
   if (bWaitForInput == FALSE) 
   { 
      if (!IsInputAvailable()) 
         return(FALSE); 
   } 

   if (!fgets(line, 256, stdin)) 
      return(-1);   // shouldn't ever happen 

   if (line[0] == '\n') 
      return(FALSE); 

#if LOGFILE 
   fprintf(logfile, "> Received %s", line); 
#endif 
   sscanf(line, "%s", command); 

   return(TRUE); 
} 


Most engine programmers will recognize this as very similar to the code from Crafty (which I also found with slight variations in many other engines).

I call CheckForInput() about once every 8K nodes. Changing how often I call it does not seem to have an appreciable effect (which is also very bizarre). Running Myrddin from inside the compiler (for both the release and the debug versions) is no different from running it manually from Windows.

I've compiled Crafty with the same settings, and Greko as well. Neither of the resulting programs show the same behavior as with Myrddin. As a last result, I have even copied the equivalent code from Crafty, with the same poor results.

Clearly, I'm missing something, which I hope that somebody out there has had to deal with before. Any recommendations would be most welcome. This is not how I expected to spend my time working on Alpha 2.

jm
Here's a first cut at figuring this out. I assume you can dump your tree as it is searched? If so, turn this "dump" on and in the routine where you check for keyboard input, print a message and then exit(1). Look at the dump and make sure you are actually searching that many nodes before the first call. If so, then remove the exit and try again. Make sure you search that many nodes before the second, the third, etc calls. I once broke this in Cray Blitz by not resetting the node counter to the starting value, which made me check for input (or system time as well) every node which ran overhead way up.

I'd bet that is what is wrong, you are just calling it too often, as in every node, which will hurt.
JVMerlino
Posts: 1357
Joined: Wed Mar 08, 2006 10:15 pm
Location: San Francisco, California

Re: kbhit() taking huge CPU??

Post by JVMerlino »

bob wrote: Here's a first cut at figuring this out. I assume you can dump your tree as it is searched? If so, turn this "dump" on and in the routine where you check for keyboard input, print a message and then exit(1). Look at the dump and make sure you are actually searching that many nodes before the first call. If so, then remove the exit and try again. Make sure you search that many nodes before the second, the third, etc calls. I once broke this in Cray Blitz by not resetting the node counter to the starting value, which made me check for input (or system time as well) every node which ran overhead way up.

I'd bet that is what is wrong, you are just calling it too often, as in every node, which will hurt.
You're a genius, and I'm an idiot. Thanks so much, Bob! :D

...I knew it would be something stupid...

jm
bob
Posts: 20943
Joined: Mon Feb 27, 2006 7:30 pm
Location: Birmingham, AL

Re: kbhit() taking huge CPU??

Post by bob »

JVMerlino wrote:
bob wrote: Here's a first cut at figuring this out. I assume you can dump your tree as it is searched? If so, turn this "dump" on and in the routine where you check for keyboard input, print a message and then exit(1). Look at the dump and make sure you are actually searching that many nodes before the first call. If so, then remove the exit and try again. Make sure you search that many nodes before the second, the third, etc calls. I once broke this in Cray Blitz by not resetting the node counter to the starting value, which made me check for input (or system time as well) every node which ran overhead way up.

I'd bet that is what is wrong, you are just calling it too often, as in every node, which will hurt.
You're a genius, and I'm an idiot. Thanks so much, Bob! :D

...I knew it would be something stupid...

jm
Not a genius. Just "experienced". As in "been there, done that, got the T-shirt."

:)
JVMerlino
Posts: 1357
Joined: Wed Mar 08, 2006 10:15 pm
Location: San Francisco, California

Re: kbhit() taking huge CPU??

Post by JVMerlino »

bob wrote:
JVMerlino wrote:
bob wrote: Here's a first cut at figuring this out. I assume you can dump your tree as it is searched? If so, turn this "dump" on and in the routine where you check for keyboard input, print a message and then exit(1). Look at the dump and make sure you are actually searching that many nodes before the first call. If so, then remove the exit and try again. Make sure you search that many nodes before the second, the third, etc calls. I once broke this in Cray Blitz by not resetting the node counter to the starting value, which made me check for input (or system time as well) every node which ran overhead way up.

I'd bet that is what is wrong, you are just calling it too often, as in every node, which will hurt.
You're a genius, and I'm an idiot. Thanks so much, Bob! :D

...I knew it would be something stupid...

jm
Not a genius. Just "experienced". As in "been there, done that, got the T-shirt."

:)
I am recalling some quote about 5% inspiration and 95% perspiration, or something like that. :wink:

As it turns out, I was calling the function every other node. Pretty ugly.

jm