Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 20 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ jobs:
- uses: actions/checkout@v7
with:
submodules: true
- id: engine_hashes
shell: bash
run: |
echo "official=$(git -C Stockfish rev-parse --short=12 HEAD)" >> "$GITHUB_OUTPUT"
echo "fairy=$(git -C Fairy-Stockfish rev-parse --short=12 HEAD)" >> "$GITHUB_OUTPUT"
- uses: docker/setup-qemu-action@v4
with:
platforms: arm64
Expand All @@ -46,6 +51,9 @@ jobs:
cache-from: type=gha
cache-to: type=gha,mode=max,ignore-error=true
load: true
build-args: |
OFFICIAL_STOCKFISH_HASH=${{ steps.engine_hashes.outputs.official }}
FAIRY_STOCKFISH_HASH=${{ steps.engine_hashes.outputs.fairy }}
- uses: docker/build-push-action@v7
id: docker_build_arm64
with:
Expand All @@ -54,6 +62,9 @@ jobs:
cache-from: type=gha
cache-to: type=gha,mode=max,ignore-error=true
load: true
build-args: |
OFFICIAL_STOCKFISH_HASH=${{ steps.engine_hashes.outputs.official }}
FAIRY_STOCKFISH_HASH=${{ steps.engine_hashes.outputs.fairy }}
- uses: docker/login-action@v4
with:
username: ${{ vars.DOCKERHUB_USERNAME }}
Expand All @@ -79,6 +90,9 @@ jobs:
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
OFFICIAL_STOCKFISH_HASH=${{ steps.engine_hashes.outputs.official }}
FAIRY_STOCKFISH_HASH=${{ steps.engine_hashes.outputs.fairy }}
if: github.event_name == 'push'
- run: docker cp "$(docker create ${{ steps.docker_build_amd64.outputs.imageid }}):/fishnet" fishnet-x86_64-unknown-linux-musl
- run: docker cp "$(docker create ${{ steps.docker_build_arm64.outputs.imageid }}):/fishnet" fishnet-aarch64-unknown-linux-musl
Expand Down Expand Up @@ -106,10 +120,14 @@ jobs:
with:
msystem: mingw64
update: true
install: mingw-w64-x86_64-sccache mingw-w64-x86_64-gcc mingw-w64-x86_64-rust mingw-w64-x86_64-make tar
install: git mingw-w64-x86_64-sccache mingw-w64-x86_64-gcc mingw-w64-x86_64-rust mingw-w64-x86_64-make tar
- uses: actions/checkout@v7
with:
submodules: true
- id: engine_hashes
run: |
echo "official=$(git -C Stockfish rev-parse --short=12 HEAD)" >> "$GITHUB_OUTPUT"
echo "fairy=$(git -C Fairy-Stockfish rev-parse --short=12 HEAD)" >> "$GITHUB_OUTPUT"
- uses: actions/cache@v6
with:
path: ${{ runner.temp }}/sccache
Expand All @@ -128,7 +146,7 @@ jobs:
continue-on-error: true
- run: tar xf intel-sde/sde-external-9.0.0-2021-11-07-win.tar.xz && echo SDE_PATH=$(cygpath -u $GITHUB_WORKSPACE)/sde-external-9.0.0-2021-11-07-win/sde.exe | tee $GITHUB_ENV
if: steps.sde.outcome == 'success'
- run: cargo build --release --target x86_64-pc-windows-gnu -vv
- run: OFFICIAL_STOCKFISH_HASH=${{ steps.engine_hashes.outputs.official }} FAIRY_STOCKFISH_HASH=${{ steps.engine_hashes.outputs.fairy }} cargo build --release --target x86_64-pc-windows-gnu -vv
- run: mv target/x86_64-pc-windows-gnu/release/fishnet.exe fishnet-x86_64-pc-windows-gnu-unsigned.exe
- uses: actions/upload-artifact@v7
id: upload-unsigned-artifact
Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ ENV RUSTC_WRAPPER=/usr/bin/sccache
ENV SCCACHE_DIR=/sccache
ENV SCCACHE_CACHE_SIZE=250M
WORKDIR /fishnet
ARG OFFICIAL_STOCKFISH_HASH
ARG FAIRY_STOCKFISH_HASH
ENV OFFICIAL_STOCKFISH_HASH=$OFFICIAL_STOCKFISH_HASH
ENV FAIRY_STOCKFISH_HASH=$FAIRY_STOCKFISH_HASH
COPY . .
RUN --mount=type=cache,target=/sccache sccache --show-stats && cargo auditable build --release -vv && sccache --show-stats

Expand Down
29 changes: 29 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ fn main() {
"cargo:rustc-env=FISHNET_TARGET={}",
env::var("TARGET").unwrap()
);
set_engine_hashes();

// Build Stockfish and Fairy-Stockfish and archive them
// (along with eval files).
Expand All @@ -76,6 +77,34 @@ fn main() {
add_favicon();
}

fn set_engine_hashes() {
println!(
"cargo:rustc-env=OFFICIAL_STOCKFISH_HASH={}",
env::var("OFFICIAL_STOCKFISH_HASH")
.unwrap_or_else(|_| git("Stockfish", ["rev-parse", "--short=12", "HEAD"]))
);
println!(
"cargo:rustc-env=FAIRY_STOCKFISH_HASH={}",
env::var("FAIRY_STOCKFISH_HASH")
.unwrap_or_else(|_| git("Fairy-Stockfish", ["rev-parse", "--short=12", "HEAD"]))
);
}

fn git<const N: usize>(dir: &str, args: [&str; N]) -> String {
let output = Command::new("git")
.arg("-C")
.arg(dir)
.args(args)
.output()
.unwrap_or_else(|err| panic!("Could not inspect {dir}: {err}"));
assert!(
output.status.success(),
"Could not inspect engine revision in {dir}: {}",
String::from_utf8_lossy(&output.stderr)
);
String::from_utf8(output.stdout).unwrap().trim().to_owned()
}

fn has_target_feature(feature: &str) -> bool {
env::var("CARGO_CFG_TARGET_FEATURE")
.unwrap()
Expand Down
6 changes: 5 additions & 1 deletion src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ pub struct VoidRequestBody {}
#[derive(Debug, Serialize)]
struct Stockfish {
flavor: EvalFlavor,
version: &'static str,
}

#[derive(Debug, Serialize)]
Expand Down Expand Up @@ -681,7 +682,10 @@ impl ApiActor {
slow: false,
})
.json(&AnalysisRequestBody {
stockfish: Stockfish { flavor },
stockfish: Stockfish {
flavor,
version: flavor.engine_version(),
},
analysis,
})
.send()
Expand Down
35 changes: 35 additions & 0 deletions src/assets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use std::{
io,
path::{Path, PathBuf},
str,
sync::OnceLock,
};

use ar::Archive;
Expand Down Expand Up @@ -147,13 +148,40 @@ pub enum EngineFlavor {
MultiVariant,
}

static OFFICIAL_STOCKFISH_VERSION: OnceLock<String> = OnceLock::new();
static FAIRY_STOCKFISH_VERSION: OnceLock<String> = OnceLock::new();

impl EngineFlavor {
pub fn eval_flavor(self) -> EvalFlavor {
match self {
EngineFlavor::Official => EvalFlavor::Nnue,
EngineFlavor::MultiVariant => EvalFlavor::Hce,
}
}

pub fn set_version(self, version: String) {
let version_slot = match self {
EngineFlavor::Official => &OFFICIAL_STOCKFISH_VERSION,
EngineFlavor::MultiVariant => &FAIRY_STOCKFISH_VERSION,
};
version_slot.get_or_init(|| match self {
EngineFlavor::Official => format!(
"OfficialStockfish/{version}/{}",
env!("OFFICIAL_STOCKFISH_HASH")
),
EngineFlavor::MultiVariant => {
format!("FairyStockfish/{version}/{}", env!("FAIRY_STOCKFISH_HASH"))
}
});
}

pub fn version(self) -> &'static str {
let version_slot = match self {
EngineFlavor::Official => &OFFICIAL_STOCKFISH_VERSION,
EngineFlavor::MultiVariant => &FAIRY_STOCKFISH_VERSION,
};
version_slot.get().expect("engine UCI initialized").as_str()
}
}

#[derive(Debug, Default)]
Expand Down Expand Up @@ -194,6 +222,13 @@ impl EvalFlavor {
pub fn is_hce(self) -> bool {
matches!(self, EvalFlavor::Hce)
}

pub fn engine_version(self) -> &'static str {
match self {
EvalFlavor::Hce => EngineFlavor::MultiVariant.version(),
EvalFlavor::Nnue => EngineFlavor::Official.version(),
}
}
}

#[derive(Debug)]
Expand Down
52 changes: 27 additions & 25 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -273,33 +273,35 @@ async fn worker(i: usize, assets: Arc<Assets>, tx: mpsc::Sender<Pull>, logger: L
// Ensure engine process is ready.
let flavor = chunk.flavor;
let context = ProgressAt::from(&chunk);
let (mut sf, join_handle) = if let Some((sf, join_handle)) =
engine.get_mut(flavor).take()
{
(sf, join_handle)
} else {
// Backoff before starting engine.
let backoff = engine_backoff.next();
if backoff >= Duration::from_secs(5) {
logger.info(&format!(
"Waiting {backoff:?} before attempting to start engine"
));
let (mut sf, join_handle) =
if let Some((sf, join_handle)) = engine.get_mut(flavor).take() {
(sf, join_handle)
} else {
logger.debug(&format!(
"Waiting {backoff:?} before attempting to start engine"
));
}
tokio::select! {
_ = tx.closed() => break,
_ = sleep(engine_backoff.next()) => (),
}
// Backoff before starting engine.
let backoff = engine_backoff.next();
if backoff >= Duration::from_secs(5) {
logger.info(&format!(
"Waiting {backoff:?} before attempting to start engine"
));
} else {
logger.debug(&format!(
"Waiting {backoff:?} before attempting to start engine"
));
}
tokio::select! {
_ = tx.closed() => break,
_ = sleep(engine_backoff.next()) => (),
}

// Start engine and spawn actor.
let (sf, sf_actor) =
stockfish::channel(assets.stockfish.get(flavor).path.clone(), logger.clone());
let join_handle = tokio::spawn(sf_actor.run());
(sf, join_handle)
};
// Start engine and spawn actor.
let (sf, sf_actor) = stockfish::channel(
flavor,
assets.stockfish.get(flavor).path.clone(),
logger.clone(),
);
let join_handle = tokio::spawn(sf_actor.run());
(sf, join_handle)
};

// Analyse or play.
let batch_id = chunk.work.id();
Expand Down
23 changes: 22 additions & 1 deletion src/stockfish.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,17 @@ use crate::{
util::NevermindExt as _,
};

pub fn channel(exe: PathBuf, logger: Logger) -> (StockfishStub, StockfishActor) {
pub fn channel(
flavor: EngineFlavor,
exe: PathBuf,
logger: Logger,
) -> (StockfishStub, StockfishActor) {
let (tx, rx) = mpsc::channel(1);
(
StockfishStub { tx },
StockfishActor {
rx,
flavor,
exe,
initialized: false,
logger,
Expand Down Expand Up @@ -49,6 +54,7 @@ impl StockfishStub {

pub struct StockfishActor {
rx: mpsc::Receiver<StockfishMessage>,
flavor: EngineFlavor,
exe: PathBuf,
initialized: bool,
logger: Logger,
Expand Down Expand Up @@ -211,6 +217,21 @@ impl StockfishActor {

async fn init(&mut self, stdout: &mut Stdout, stdin: &mut Stdin) -> io::Result<()> {
if !mem::replace(&mut self.initialized, true) {
stdin.write_line("uci").await?;
stdin.flush().await?;

let mut version = "unknown".to_owned();
loop {
let line = stdout.read_line().await?;
if let Some(name) = line.strip_prefix("id name ") {
version = name.to_owned();
}
if line.trim_end() == "uciok" {
break;
}
}
self.flavor.set_version(version.replace('/', "_"));

stdin
.write_line("setoption name UCI_Chess960 value true")
.await?;
Expand Down
Loading