feat : add user input engineWorkersNb
This commit is contained in:
@@ -18,35 +18,42 @@ export const STRONGEST_ENGINE: EngineName = EngineName.Stockfish17;
|
||||
|
||||
export const ENGINE_LABELS: Record<
|
||||
EngineName,
|
||||
{ small: string; full: string }
|
||||
{ small: string; full: string; sizeMb: number }
|
||||
> = {
|
||||
[EngineName.Stockfish17]: {
|
||||
full: "Stockfish 17 (75MB)",
|
||||
small: "Stockfish 17",
|
||||
sizeMb: 75,
|
||||
},
|
||||
[EngineName.Stockfish17Lite]: {
|
||||
full: "Stockfish 17 Lite (6MB)",
|
||||
small: "Stockfish 17 Lite",
|
||||
sizeMb: 6,
|
||||
},
|
||||
[EngineName.Stockfish16_1]: {
|
||||
full: "Stockfish 16.1 (64MB)",
|
||||
small: "Stockfish 16.1",
|
||||
sizeMb: 64,
|
||||
},
|
||||
[EngineName.Stockfish16_1Lite]: {
|
||||
full: "Stockfish 16.1 Lite (6MB)",
|
||||
small: "Stockfish 16.1 Lite",
|
||||
sizeMb: 6,
|
||||
},
|
||||
[EngineName.Stockfish16NNUE]: {
|
||||
full: "Stockfish 16 (40MB)",
|
||||
small: "Stockfish 16",
|
||||
sizeMb: 40,
|
||||
},
|
||||
[EngineName.Stockfish16]: {
|
||||
full: "Stockfish 16 Lite (HCE)",
|
||||
small: "Stockfish 16 Lite",
|
||||
sizeMb: 2,
|
||||
},
|
||||
[EngineName.Stockfish11]: {
|
||||
full: "Stockfish 11 (HCE)",
|
||||
small: "Stockfish 11",
|
||||
sizeMb: 2,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -12,12 +12,17 @@ export const isWasmSupported = () =>
|
||||
|
||||
export const isMultiThreadSupported = () => {
|
||||
try {
|
||||
return SharedArrayBuffer !== undefined;
|
||||
return SharedArrayBuffer !== undefined && !isIosDevice();
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
export const isIosDevice = () => /iPhone|iPad|iPod/i.test(navigator.userAgent);
|
||||
|
||||
export const isMobileDevice = () =>
|
||||
isIosDevice() || /Android|Opera Mini/i.test(navigator.userAgent);
|
||||
|
||||
export const isEngineSupported = (name: EngineName): boolean => {
|
||||
switch (name) {
|
||||
case EngineName.Stockfish17:
|
||||
|
||||
@@ -49,7 +49,6 @@ export class UciEngine {
|
||||
await engine.addNewWorker();
|
||||
engine.isReady = true;
|
||||
|
||||
console.log(`${engineName} initialized`);
|
||||
return engine;
|
||||
}
|
||||
|
||||
@@ -138,11 +137,11 @@ export class UciEngine {
|
||||
for (const worker of this.workers) {
|
||||
this.terminateWorker(worker);
|
||||
}
|
||||
|
||||
console.log(`${this.name} shutdown`);
|
||||
this.workers = [];
|
||||
}
|
||||
|
||||
private terminateWorker(worker: EngineWorker) {
|
||||
console.log(`Terminating worker from ${this.enginePath}`);
|
||||
worker.uci("quit");
|
||||
worker.terminate?.();
|
||||
worker.isReady = false;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { EngineWorker } from "@/types/engine";
|
||||
import { isIosDevice, isMobileDevice } from "./shared";
|
||||
|
||||
export const getEngineWorker = (enginePath: string): EngineWorker => {
|
||||
console.log(`Creating worker from ${enginePath}`);
|
||||
@@ -47,7 +48,7 @@ export const getRecommendedWorkersNb = (): number => {
|
||||
const maxWorkersNbFromThreads = Math.max(
|
||||
1,
|
||||
navigator.hardwareConcurrency - 4,
|
||||
Math.ceil((navigator.hardwareConcurrency * 2) / 3)
|
||||
Math.floor((navigator.hardwareConcurrency * 2) / 3)
|
||||
);
|
||||
|
||||
const maxWorkersNbFromMemory =
|
||||
@@ -55,5 +56,11 @@ export const getRecommendedWorkersNb = (): number => {
|
||||
? navigator.deviceMemory
|
||||
: 4;
|
||||
|
||||
return Math.min(maxWorkersNbFromThreads, maxWorkersNbFromMemory, 10);
|
||||
const maxWorkersNbFromDevice = isIosDevice() ? 2 : isMobileDevice() ? 4 : 10;
|
||||
|
||||
return Math.min(
|
||||
maxWorkersNbFromThreads,
|
||||
maxWorkersNbFromMemory,
|
||||
maxWorkersNbFromDevice
|
||||
);
|
||||
};
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
engineDepthAtom,
|
||||
engineMultiPvAtom,
|
||||
engineNameAtom,
|
||||
engineWorkersNbAtom,
|
||||
evaluationProgressAtom,
|
||||
gameAtom,
|
||||
gameEvalAtom,
|
||||
@@ -19,12 +20,12 @@ import { useEffect, useCallback } from "react";
|
||||
import { usePlayersData } from "@/hooks/usePlayersData";
|
||||
import { Typography } from "@mui/material";
|
||||
import { useCurrentPosition } from "../hooks/useCurrentPosition";
|
||||
import { getRecommendedWorkersNb } from "@/lib/engine/worker";
|
||||
|
||||
export default function AnalyzeButton() {
|
||||
const engineName = useAtomValue(engineNameAtom);
|
||||
const engine = useEngine(engineName);
|
||||
useCurrentPosition(engine);
|
||||
const engineWorkersNb = useAtomValue(engineWorkersNbAtom);
|
||||
const [evaluationProgress, setEvaluationProgress] = useAtom(
|
||||
evaluationProgressAtom
|
||||
);
|
||||
@@ -58,7 +59,7 @@ export default function AnalyzeButton() {
|
||||
white: white?.rating,
|
||||
black: black?.rating,
|
||||
},
|
||||
workersNb: getRecommendedWorkersNb(),
|
||||
workersNb: engineWorkersNb,
|
||||
});
|
||||
|
||||
setEval(newGameEval);
|
||||
@@ -86,6 +87,7 @@ export default function AnalyzeButton() {
|
||||
}, [
|
||||
engine,
|
||||
engineName,
|
||||
engineWorkersNb,
|
||||
game,
|
||||
engineDepth,
|
||||
engineMultiPv,
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { DEFAULT_ENGINE } from "@/constants";
|
||||
import { getRecommendedWorkersNb } from "@/lib/engine/worker";
|
||||
import { EngineName } from "@/types/enums";
|
||||
import { CurrentPosition, GameEval, SavedEvals } from "@/types/eval";
|
||||
import { Chess } from "chess.js";
|
||||
import { atom } from "jotai";
|
||||
import { atomWithStorage } from "jotai/utils";
|
||||
|
||||
export const gameEvalAtom = atom<GameEval | undefined>(undefined);
|
||||
export const gameAtom = atom(new Chess());
|
||||
@@ -16,6 +18,10 @@ export const showPlayerMoveIconAtom = atom(true);
|
||||
export const engineNameAtom = atom<EngineName>(DEFAULT_ENGINE);
|
||||
export const engineDepthAtom = atom(14);
|
||||
export const engineMultiPvAtom = atom(3);
|
||||
export const engineWorkersNbAtom = atomWithStorage(
|
||||
"engineWorkersNb",
|
||||
getRecommendedWorkersNb()
|
||||
);
|
||||
export const evaluationProgressAtom = atom(0);
|
||||
|
||||
export const savedEvalsAtom = atom<SavedEvals>({});
|
||||
|
||||
@@ -20,6 +20,7 @@ import {
|
||||
engineNameAtom,
|
||||
engineDepthAtom,
|
||||
engineMultiPvAtom,
|
||||
engineWorkersNbAtom,
|
||||
} from "../analysis/states";
|
||||
import ArrowOptions from "./arrowOptions";
|
||||
import { useAtomLocalStorage } from "@/hooks/useAtomLocalStorage";
|
||||
@@ -35,6 +36,7 @@ import {
|
||||
PIECE_SETS,
|
||||
STRONGEST_ENGINE,
|
||||
} from "@/constants";
|
||||
import { getRecommendedWorkersNb } from "@/lib/engine/worker";
|
||||
|
||||
interface Props {
|
||||
open: boolean;
|
||||
@@ -56,6 +58,7 @@ export default function EngineSettingsDialog({ open, onClose }: Props) {
|
||||
);
|
||||
const [boardHue, setBoardHue] = useAtom(boardHueAtom);
|
||||
const [pieceSet, setPieceSet] = useAtom(pieceSetAtom);
|
||||
const [engineWorkersNb, setEngineWorkersNb] = useAtom(engineWorkersNbAtom);
|
||||
|
||||
const theme = useTheme();
|
||||
const isDarkMode = theme.palette.mode === "dark";
|
||||
@@ -72,12 +75,15 @@ export default function EngineSettingsDialog({ open, onClose }: Props) {
|
||||
|
||||
return (
|
||||
<Dialog open={open} onClose={onClose} maxWidth="md" fullWidth>
|
||||
<DialogTitle variant="h5">Settings</DialogTitle>
|
||||
<DialogTitle variant="h5" sx={{ paddingBottom: 1 }}>
|
||||
Settings
|
||||
</DialogTitle>
|
||||
<DialogContent sx={{ paddingBottom: 0 }}>
|
||||
<Grid
|
||||
container
|
||||
justifyContent="center"
|
||||
alignItems="center"
|
||||
paddingTop={1}
|
||||
spacing={3}
|
||||
size={12}
|
||||
>
|
||||
@@ -86,12 +92,14 @@ export default function EngineSettingsDialog({ open, onClose }: Props) {
|
||||
justifyContent="center"
|
||||
size={{ xs: 12, sm: 7, md: 8 }}
|
||||
>
|
||||
<Typography>
|
||||
<Typography variant="body2">
|
||||
{ENGINE_LABELS[DEFAULT_ENGINE].small} is the default engine if
|
||||
your device support its requirements. It offers the best balance
|
||||
between speed and strength.{" "}
|
||||
{ENGINE_LABELS[STRONGEST_ENGINE].small} is the strongest engine
|
||||
available, note that it requires a one time download of 75MB.
|
||||
available, note that it requires a one time download of{" "}
|
||||
{ENGINE_LABELS[STRONGEST_ENGINE].sizeMb}MB and is much more
|
||||
compute intensive.
|
||||
</Typography>
|
||||
</Grid>
|
||||
|
||||
@@ -162,6 +170,7 @@ export default function EngineSettingsDialog({ open, onClose }: Props) {
|
||||
<Grid
|
||||
container
|
||||
justifyContent="center"
|
||||
alignItems="center"
|
||||
size={{ xs: 12, sm: 4, md: 3 }}
|
||||
>
|
||||
<FormControl variant="outlined">
|
||||
@@ -194,6 +203,26 @@ export default function EngineSettingsDialog({ open, onClose }: Props) {
|
||||
</Select>
|
||||
</FormControl>
|
||||
</Grid>
|
||||
|
||||
<Grid container justifyContent="center" size={{ xs: 12, sm: 7 }}>
|
||||
<Slider
|
||||
label="Number of threads"
|
||||
value={engineWorkersNb}
|
||||
setValue={setEngineWorkersNb}
|
||||
min={1}
|
||||
max={10}
|
||||
marksFilter={1}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
<Grid container justifyContent="center" size={{ xs: 12, sm: 5 }}>
|
||||
<Typography variant="body2">
|
||||
More threads means quicker analysis but only if your device can
|
||||
handle them, otherwise it may have the opposite effect. The
|
||||
estimated best value for your device is{" "}
|
||||
{getRecommendedWorkersNb()}.
|
||||
</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</DialogContent>
|
||||
<DialogActions sx={{ m: 1 }}>
|
||||
|
||||
@@ -2,8 +2,7 @@ export interface EngineWorker {
|
||||
isReady: boolean;
|
||||
uci(command: string): void;
|
||||
listen: (data: string) => void;
|
||||
terminate?: () => void;
|
||||
setNnueBuffer?: (data: Uint8Array, index?: number) => void;
|
||||
terminate: () => void;
|
||||
}
|
||||
|
||||
export interface WorkerJob {
|
||||
|
||||
Reference in New Issue
Block a user