Skip to content

Commit

Permalink
Improve memory management
Browse files Browse the repository at this point in the history
Put the whole engine in a single worker, then terminate the worker when done. This should activate JavaScript's garbage collector to collect the WASM instances.
  • Loading branch information
Hakorr committed Oct 2, 2024
1 parent 272491b commit e88510b
Show file tree
Hide file tree
Showing 8 changed files with 121 additions and 1,137 deletions.
103 changes: 59 additions & 44 deletions assets/js/acas-backend-instance.js
Original file line number Diff line number Diff line change
Expand Up @@ -466,8 +466,7 @@ class BackendInstance {

this.pV[profile].lc0WeightName = weightName;

if(this.getEngine(profile)?.setZeroWeights)
this.getEngine(profile).setZeroWeights(await loadFileAsUint8Array(`/A.C.A.S/assets/lc0-weights/${weightName}`));
this.contactEngine('setZeroWeights', [await loadFileAsUint8Array(`/A.C.A.S/assets/lc0-weights/${weightName}`)], profile);
}

disableEngineElo(profile) {
Expand Down Expand Up @@ -900,8 +899,8 @@ class BackendInstance {
return this.engines[i ? i : this.engines.length - 1];
}

getEngine(i) {
return this.getEngineAcasObj(i)['engine'];
contactEngine(method, args, i) {
return this.getEngineAcasObj(i)['engine'](method, args);
}

sendMsgToEngine(msg, i) {
Expand Down Expand Up @@ -942,7 +941,7 @@ class BackendInstance {
const oldestUnfinishedCalcRequestObj = this.pV[profile].pendingCalculations.find(x => !x.finished);
const isMessageForCurrentFen = oldestUnfinishedCalcRequestObj?.fen === this.currentFen;

if(!data?.currmovenumber) console.warn(msg, `(FOR FEN: ${oldestUnfinishedCalcRequestObj?.fen})`);
if(!data?.currmovenumber) console.warn(`${profile} ->`, msg, `\n(Message is for FEN -> ${oldestUnfinishedCalcRequestObj?.fen})`);

if(msg.includes('option name UCI_Variant type combo')) {
const chessVariants = extractVariantNames(msg);
Expand Down Expand Up @@ -1065,8 +1064,6 @@ class BackendInstance {
{
toast.error(`FATAL ERROR: COI failed to enable SharedArrayBuffer, report issue to GitHub!`, 1e9);
} else {
this.killExtraEngines();

const msgHandler = msg => {
try {
this.engineMessageHandler(msg, profile);
Expand All @@ -1079,41 +1076,69 @@ class BackendInstance {

switch(profileChessEngine) {
case 'lc0':
const waitForZeroFish = setInterval(async () => {
if(typeof zerofish !== 'undefined') {
clearInterval(waitForZeroFish);
const lc0 = new Worker('assets/libraries/zerofish/zerofishWorker.js', { type: 'module' });
let lc0_loaded = false;

lc0.onmessage = async e => {
if(e.data === true) {
lc0_loaded = true;

this.engines.push({
'type': profileChessEngine,
'engine': await zerofish(),
'sendMsg': msg => this.getEngine(profile).zero(msg),
'engine': (method, a) => lc0.postMessage({ method: method, args: [...a] }),
'sendMsg': msg => lc0.postMessage({ method: 'zero', args: [msg] }),
'worker': lc0,
profile
});

const ZeroFish = this.getEngine(profile);

ZeroFish.listenZero = msgHandler;

await this.setEngineWeight(this.pV[profile].lc0WeightName, profile);

this.engineStartNewGame('chess', profile);
} else if (e.data) {
msgHandler(e.data);
}
};

const waitLc0 = setInterval(() => {
if(lc0_loaded) {
clearInterval(waitLc0);
return;
}

lc0.postMessage({ method: 'acas_check_loaded' });
}, 100);
break;

default: // Fairy Stockfish NNUE WASM
this.engines.push({
'type': profileChessEngine,
'engine': await Stockfish(),
'sendMsg': msg => this.getEngine(profile).postMessage(msg),
profile
});
const stockfish = new Worker('assets/libraries/fairy-stockfish-nnue.wasm/stockfishWorker.js');
let stockfish_loaded = false;

stockfish.onmessage = async e => {
if(e.data === true) {
stockfish_loaded = true;

const FairyStockfish = this.getEngine(profile);
this.engines.push({
'type': profileChessEngine,
'engine': (method, a) => stockfish.postMessage({ method: method, args: [...a] }),
'sendMsg': msg => stockfish.postMessage({ method: 'postMessage', args: [msg] }),
'worker': stockfish,
profile
});

this.engineStartNewGame(formatVariant(this.pV[profile].chessVariant), profile);
} else if (e.data) {
msgHandler(e.data);
}
};

FairyStockfish.addMessageListener(msgHandler);
const waitStockfish = setInterval(() => {
if(stockfish_loaded) {
clearInterval(waitStockfish);
return;
}

this.engineStartNewGame(formatVariant(this.pV[profile].chessVariant), profile);
stockfish.postMessage({ method: 'acas_check_loaded' });
}, 100);
break;
}
}
Expand Down Expand Up @@ -1391,13 +1416,14 @@ class BackendInstance {
killEngine(i) {
console.warn('Killing engine', i);

let engine = null;
let worker = null;

if(typeof i === 'string') {
const engineIndex = this.engines.findIndex(obj => obj.profile === i);

if(engineIndex !== -1) {
engine = this.engines[engineIndex].engine;
worker = this.engines[engineIndex].worker;

this.engines.splice(engineIndex, 1);

if(this.pV[i]) {
Expand All @@ -1410,10 +1436,9 @@ class BackendInstance {
if(i >= 0 && i < this.engines.length) {
const profileName = this.engines[i].profile;

engine = this.engines[i].engine;
worker = this.engines[i].worker;

this.engines.splice(i, 1);

console.warn(profileName, engine);

if(this.pV[profileName]) {
this.Interface.boardUtils.removeMarkings(profileName);
Expand All @@ -1425,19 +1450,9 @@ class BackendInstance {

this.sendMsgToEngine('quit', i);

const freeFunction = engine?.['_free'];

if(freeFunction)
engine?._free();
}

killExtraEngines() {
/* No implementation needed yet
for(let i = 0; i < this.engines.length; i++) {
if(this.engines.length - 1 !== i) {
this.killEngine(i);
}
}*/
setTimeout(() => {
worker.terminate();
}, 1000);
}

killEngines() {
Expand Down
2 changes: 1 addition & 1 deletion assets/libraries/fairy-stockfish-nnue.wasm/stockfish.js

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

16 changes: 1 addition & 15 deletions assets/libraries/fairy-stockfish-nnue.wasm/stockfish.worker.js

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

28 changes: 28 additions & 0 deletions assets/libraries/fairy-stockfish-nnue.wasm/stockfishWorker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
importScripts('/A.C.A.S/assets/libraries/fairy-stockfish-nnue.wasm/stockfish.js');

let engine = null;

(async () => {
engine = await Stockfish();
})();

onmessage = e => {
const { method, args } = e.data;

if (!engine) {
postMessage(false);
return;
}

if(engine && method === 'acas_check_loaded') {
postMessage(true);

engine.addMessageListener(postMessage);

return;
}

if (engine[method] && typeof engine[method] === 'function') {
engine[method](...args);
}
};
Loading

0 comments on commit e88510b

Please sign in to comment.