official-stockfish / Stockfish

A free and strong UCI chess engine
https://stockfishchess.org/
GNU General Public License v3.0
11.55k stars 2.27k forks source link

Setting Skill Level option < 20 causing Segmentation fault #1268

Closed Dayjo closed 7 years ago

Dayjo commented 7 years ago

Hello there,

I'm trying to write a shell script that will allow me to just pass a FEN to it and it do a bunch of stockfish stuff. So far I have it working fine, but as soon as I add the setoption Skill Level line to the script, I get a Segmentation fault.

OS: Ubuntu 16.04.3 LTS

My script (stockfish.sh);

#!/bin/bash
/home/ubuntu/stockfish-8-linux/Linux/stockfish_8_x64 << EOF
setoption name Hash value 1024
setoption name threads value 2
position fen $1
go depth 20
EOF

Then running;

stockfish.sh "r1bqkbnr/pp1ppppp/2n5/2p5/3PP3/5N2/PPP2PPP/RNBQKB1R b KQkq - 0 3"

This works great and I get the response;

Stockfish 8 64 by T. Romstad, M. Costalba, J. Kiiski, G. Linscott
bestmove c5c4

but as soon as I add the skill level option like so;

#!/bin/bash
/home/ubuntu/stockfish-8-linux/Linux/stockfish_8_x64 << EOF
setoption name Skill Level value 1
setoption name Hash value 1024
setoption name threads value 2
position fen $1
go depth 20
EOF

I get an error;

stockfish.sh: line 8: 14888 Segmentation fault      (core dumped)

If I remove the go line, I do not get this error, but obviously, it then doesn't try and calculate the move. I've tried using go movetime instead of depth, but the same issue occurs. Without the Skill Level it works fine, and with the Skill Level the go commands get this segmentation fault.

I noticed also if I set the Skill Level to anything below 20 it errors, but anything 20 or above works fine (Though I don't think it's really doing anything). If you need anymore information please let me know

MichaelB7 commented 7 years ago

This may not be the fix - but when using skill level , do not set threads higher than 1 - there is no point.

Sent from my iPhone

On Oct 9, 2017, at 8:25 AM, Joel notifications@github.com wrote:

Hello there,

I'm trying to write a shell script that will allow me to just pass a FEN to it and it do a bunch of stockfish stuff. So far I have it working fine, but as soon as I add the setoption Skill Level line to the script, I get a Segmentation fault.

OS: Ubuntu 16.04.3 LTS

My script (stockfish.sh);

!/bin/bash

/home/ubuntu/stockfish-8-linux/Linux/stockfish_8_x64 << EOF setoption name Hash value 1024 setoption name threads value 2 position fen $1 go depth 20 EOF Then running;

stockfish.sh "r1bqkbnr/pp1ppppp/2n5/2p5/3PP3/5N2/PPP2PPP/RNBQKB1R b KQkq - 0 3" This works great and I get the response;

Stockfish 8 64 by T. Romstad, M. Costalba, J. Kiiski, G. Linscott bestmove c5c4 but as soon as I add the skill level option like so;

!/bin/bash

/home/ubuntu/stockfish-8-linux/Linux/stockfish_8_x64 << EOF setoption name Skill Level value 1 setoption name Hash value 1024 setoption name threads value 2 position fen $1 go depth 20 EOF I get an error;

stockfish.sh: line 8: 14888 Segmentation fault (core dumped) If I remove the go line, I do not get this error, but obviously, it then doesn't try and calculate the move. I've tried using go movetime instead of depth, but the same issue occurs. Without the Skill Level it works fine, and with the Skill Level the go commands get this segmentation fault.

I noticed also if I set the Skill Level to anything below 20 it errors, but anything 20 or above works fine (Though I don't think it's really doing anything)

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub, or mute the thread.

Dayjo commented 7 years ago

Hi @MichaelB7

Thanks for your response! That's interesting, could you elaborate as to why? I did try ONLY setting the skill level value, and it still errors.

setoption name Skill Level value 1
position fen $1
go infinite

Gets the same result.

But this works (setting it to > 20)

Also tried doing position startpos in case it was a problem with the (multiple) FENs I've been trying.

Additionally, I've tried the same commands directly in the binary and they seem to work ok i.e;

MichaelB7 commented 7 years ago

Generally speaking , you would use skill level to reduce playing strength and increase threads to increase playing strength- why would you do both?

Sent from my iPhone

On Oct 9, 2017, at 12:04 PM, Joel notifications@github.com wrote:

Hi @MichaelB7

Thanks for your response! That's interesting, could you elaborate as to why? I did try ONLY setting the skill level value, and it still errors.

setoption name Skill Level value 1 position fen $1 go infinite Gets the same result.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or mute the thread.

joergoster commented 7 years ago

@Dayjo Please update to a current dev build, for example from here http://chess.ultimaiq.net/stockfish.html. There were some patches applied in the meantime which should have fixed this problem.

Dayjo commented 7 years ago

@MichaelB7, I guess I wouldn't? But I've not been able to find any documentation that describes the relationship between these variable as you have :)

@joergoster I would, unfortunately, it looks like that page is windows only. I'm running on Linux, however I shall look to build it myself. I did however find one here; http://abrok.eu/stockfish/ and try that but ended up with the same error.

Dayjo commented 7 years ago

For some additional information:

I've also run the binary in PHP with proc_open and fwrite to write the commands, but I get the exact same problem.

Other issues are that without the skill level option and everything working, it seems like it's way too quick to be paying attention to the options I'm using. For instance, I can run the following;

setoption name Hash value 1024
setoption name threads value 1
position fen 8/8/8/1p5p/1P4k1/6P1/6K1/8 w - - 1
go depth 56

from within the binary, it goes through all the depths and comes back with a move of bestmove g2f2 ponder g4f5, however when I run this through the script, it always returns g2f1 and it seems like it's running instsantly (way too quickly to be processing all of the moves for a depth of 56)". I'm unsure why it's producing different results when running directly in the binary and running like this.

housecroft commented 7 years ago

@Dayjo Not being a programmer myself but I am following this github page. I tried something similar but ran into the same problem. http://open-chess.org/viewtopic.php?f=5&t=3137

Dayjo commented 7 years ago

@housecroft Thanks for the input, did you manage to get anywhere with it, other than using an older version?

housecroft commented 7 years ago

Unfortunately not. I abandoned my project because I am quite busy anyhow and don't have the time to toy around with this kind of stuff.

Dayjo commented 7 years ago

It's not critical to the current stage of my project, but it certainly would be nice to not have to play against the hardest computer level every time :1st_place_medal:

vondele commented 7 years ago

The problem is related to the fact that your script exists immediately before search has started. You need to keep stdin open till search has finished. It can still be reproduced on master and is fixed with PR #1270

Dayjo commented 7 years ago

@vondele that's interesting, I thought it must be something like this, but thought that would be resolved by using the proc_open technique. I may try building it with your fix in to see if I can get it to work.

mcostalba commented 7 years ago

@Dayjo should be fixed with current master. Could you please verify and confirm? Thanks.

Dayjo commented 7 years ago

@mcostalba Thanks, I'll give this a go later today.

Is it unusual that when I'm running the process like this, that it seems practically instant, and it doesn't do all of the info depth 1 seldepth 1 multipv 1 score cp -29 nodes 26 nps 4333 tbhits 0 time 6 pv f2g2 style lines of output, it just does;

For instance;

$process = proc_open(self::BINARY, $descriptorspec, $pipes, $cwd, $env);

// Set the options and run the go command
            fwrite($pipes[0], "setoption name Skill Level value 20\n");
            fwrite($pipes[0], "setoption name threads value 2\n");
            fwrite($pipes[0], "setoption name Hash value 1024\n");
            fwrite($pipes[0], "position fen $fen\n");
            fwrite($pipes[0], "go depth 300\n");
            fclose($pipes[0]);

I get the response;

Stockfish 8 64 by T. Romstad, M. Costalba, J. Kiiski, G. Linscott\n
    bestmove f2e1\n

But if I start the binary in the terminal and run those commands in the terminal, when I do go depth 300 it goes for a long time and outputs all of the info depth 50 currmove f2e3 currmovenumber 4 style lines.

vondele commented 7 years ago

@Dayjo, as soon as you fclose the pipe, you essentially send a 'quit' to SF. You need to keep the pipe open till you have received the 'bestmove' answer. Anyway, please close the issue if the segfault is gone for you.

Dayjo commented 7 years ago

@vondele Ah yes, I thought i'd moved the fclose after my loop! Whoops. I'll close this once I've rebuilt and tested the binary with the skill level :)

Dayjo commented 7 years ago

This does seem to work with the new version, but also weirdly I got it working with the current version. I think perhaps the problem was that the script was getting exited prematurely as @vondele suggested. (despite it working, it's kinda hard to see the difference in result when changing the skill level).

For anyone interested, this is how i'm using it (I'll likely add more processing for the bestmove line);


public function getStockfishMove(string $fen, $depth = 20, $skill = 20)
     {
         $cwd = '/tmp';
         $env = [];
         $stderr_ouput = [];

         $descriptorspec = [
            0 => ["pipe", "r"],  // stdin is a pipe that the child will read from
            1 => ["pipe", "w"],  // stdout is a pipe that the child will write to
            2 => ["pipe", "w"]   //array("file", "/tmp/error-output.txt", "a") // stderr is a file to write to
         ];

         // Run the stockfish binary
         $process = proc_open(self::BINARY, $descriptorspec, $pipes, $cwd, $env);

         if (is_resource($process)) {
             stream_set_blocking($pipes[1], false);
             stream_set_blocking($pipes[2], false);

             // Set the options and run the go command
             fwrite($pipes[0], "setoption name Skill Level value $skill\n");
             fwrite($pipes[0], "setoption name threads value 1\n");
             fwrite($pipes[0], "setoption name Hash value 1024\n");
             fwrite($pipes[0], "position fen $fen\n");
             fwrite($pipes[0], "go depth $depth\n");

             $status = proc_get_status($process);

             // While the process is running (Might want to add another check here)
             while ($status['running']) {

                 $status = proc_get_status($process);
                 $output[] = fgets($pipes[1]);

                 // If our stderr pipe has data
                 if (!feof($pipes[2])) {

                     // Grab the error line
                     $error_line = fgets($pipes[2]);
                     $stderr_ouput[] = $error_line;

                     if ($error_line) {
                         echo "ERROR: " . $error_line;
                         break;
                     }
                 }

                 // Stop the loop if we found the bestmove line
                 if (strstr($output[count($output)-1], 'bestmove')) {
                     $bestMoveLine = $output[count($output)-1];
                     break;
                 }

                 flush();
             }

             // Close the pipes
             fclose($pipes[0]);
             fclose($pipes[1]);
             fclose($pipes[2]);

             // Close the process
             proc_close($process);
         } else {
             throw Exception("Stockfish binary could not be run.");
         }

         return $bestMoveLine;
     }