From e81823b589ab5c6c944479cad63aed857d65099c Mon Sep 17 00:00:00 2001 From: undefined Date: Wed, 5 Feb 2025 07:43:14 +0800 Subject: [PATCH] judge: add stack size report --- packages/hydrojudge/src/hosts/builtin.ts | 19 +++++++--- packages/hydrojudge/src/hosts/hydro.ts | 37 +++++++++++++------ .../hydrojudge/src/{compiler.ts => info.ts} | 10 +++++ packages/hydrojudge/src/sandbox.ts | 2 +- 4 files changed, 50 insertions(+), 18 deletions(-) rename packages/hydrojudge/src/{compiler.ts => info.ts} (71%) diff --git a/packages/hydrojudge/src/hosts/builtin.ts b/packages/hydrojudge/src/hosts/builtin.ts index 889ce399b..43dc12fc8 100644 --- a/packages/hydrojudge/src/hosts/builtin.ts +++ b/packages/hydrojudge/src/hosts/builtin.ts @@ -8,9 +8,9 @@ import { SettingModel, StorageModel, SystemModel, TaskModel, } from 'hydrooj'; import { langs } from 'hydrooj/src/model/setting'; -import { compilerVersions } from '../compiler'; import { getConfig } from '../config'; import { FormatError, SystemError } from '../error'; +import { compilerVersions, stackSize } from '../info'; import { Context } from '../judge/interface'; import logger from '../log'; import { versionCheck } from '../sandbox'; @@ -96,19 +96,26 @@ export async function postInit(ctx) { }; const parallelism = Math.max(getConfig('parallelism'), 2); const taskConsumer = TaskModel.consume({ type: 'judge' }, handle, true, parallelism); - function collectCompilerInfo() { + async function collectInfo() { const coll = db.collection('status'); - compilerVersions(langs).then((compilers) => coll.updateOne( + const compilers = await compilerVersions(langs); + await coll.updateOne( { mid: info.mid, type: 'server' }, { $set: { compilers } }, { upsert: true }, - )).catch((e) => logger.error(e)); + ); + const size = await stackSize(); + await coll.updateOne( + { mid: info.mid, type: 'server' }, + { $set: { stackSize: size } }, + { upsert: true }, + ); } ctx.on('system/setting', () => { taskConsumer.setConcurrency(Math.max(getConfig('parallelism'), 2)); - collectCompilerInfo(); + collectInfo(); }); - collectCompilerInfo(); + collectInfo(); TaskModel.consume({ type: 'judge', priority: { $gt: -50 } }, handle); TaskModel.consume({ type: 'generate' }, handle); } diff --git a/packages/hydrojudge/src/hosts/hydro.ts b/packages/hydrojudge/src/hosts/hydro.ts index a6eb37851..4d97afaf2 100644 --- a/packages/hydrojudge/src/hosts/hydro.ts +++ b/packages/hydrojudge/src/hosts/hydro.ts @@ -7,9 +7,9 @@ import { fs, pipeRequest } from '@hydrooj/utils'; import { LangConfig } from '@hydrooj/utils/lib/lang'; import * as sysinfo from '@hydrooj/utils/lib/sysinfo'; import type { JudgeResultBody } from 'hydrooj'; -import { compilerVersions } from '../compiler'; import { getConfig } from '../config'; import { FormatError, SystemError } from '../error'; +import { compilerVersions, stackSize as getStackSize } from '../info'; import { Session } from '../interface'; import log from '../log'; import { JudgeTask } from '../task'; @@ -184,7 +184,8 @@ export default class Hydro implements Session { ? JSON.stringify({ key: 'config', ...config }) : '{"key":"ping"}'; let compilers = {}; - let compilerVersionCallback = () => { }; + let sendStatus = () => { }; + let stackSize = 0; this.ws.on('message', (data) => { if (data.toString() === 'ping') { this.ws.send('pong'); @@ -193,9 +194,13 @@ export default class Hydro implements Session { const request = JSON.parse(data.toString()); if (request.language) { this.language = request.language; - compilerVersions(this.language).then((res) => { - compilers = res; - compilerVersionCallback(); + Promise.allSettled([ + compilerVersions(this.language), + getStackSize(), + ]).then(([compiler, stack]) => { + compilers = compiler.status === 'fulfilled' ? compiler.value : {}; + stackSize = stack.status === 'fulfilled' ? stack.value : 0; + sendStatus(); }); } if (request.task) queue.add(() => new JudgeTask(this, request.task).handle().catch((e) => log.error(e))); @@ -214,14 +219,24 @@ export default class Hydro implements Session { this.ws.send('{"key":"start"}'); if (!this.config.noStatus) { const info = await sysinfo.get(); - this.ws.send(JSON.stringify({ key: 'status', info: { ...info } })); - compilerVersionCallback = () => { - this.ws.send(JSON.stringify({ key: 'status', info: { ...info, compilers } })); - }; - setInterval(async () => { + this.ws.send(JSON.stringify({ key: 'status', info: { ...info, stackSize } })); + sendStatus = () => this.ws.send(JSON.stringify({ key: 'status', info: { ...info, compilers, stackSize } })); + const interval = setInterval(async () => { const [mid, inf] = await sysinfo.update(); - this.ws.send(JSON.stringify({ key: 'status', info: { mid, ...inf, compilers } })); + this.ws.send(JSON.stringify({ + key: 'status', + info: { + mid, ...inf, compilers, stackSize, + }, + })); }, 1200000); + let stopped = false; + const stop = () => { + if (!stopped) clearInterval(interval); + stopped = true; + }; + this.ws.on('close', stop); + this.ws.on('error', stop); } resolve(null); }); diff --git a/packages/hydrojudge/src/compiler.ts b/packages/hydrojudge/src/info.ts similarity index 71% rename from packages/hydrojudge/src/compiler.ts rename to packages/hydrojudge/src/info.ts index 36e98e821..a73f268a3 100644 --- a/packages/hydrojudge/src/compiler.ts +++ b/packages/hydrojudge/src/info.ts @@ -16,3 +16,13 @@ export async function compilerVersions(langs: Record) { } return result; } + +export async function stackSize() { + const res = await runQueued('/bin/bash -c "ulimit -s"', { + copyIn: {}, + time: 10000, + memory: 256, + }, 'stackSize', 5); + if (res.stderr) return -1; + return +res.stdout; +} diff --git a/packages/hydrojudge/src/sandbox.ts b/packages/hydrojudge/src/sandbox.ts index 5d7dbd53e..adcffd9fb 100644 --- a/packages/hydrojudge/src/sandbox.ts +++ b/packages/hydrojudge/src/sandbox.ts @@ -220,7 +220,7 @@ export async function versionCheck(reportWarn: (str: string) => void, reportErro const config = await client.config(); sandboxCgroup = config.runnerConfig?.cgroupType || 0; } catch (e) { - if (e?.syscall === 'connect') reportError('Connecting to sandbox failed, please check sandbox_host config and if your sandbox is running.'); + if (e?.code === 'ECONNREFUSED') reportError('Failed to connect to sandbox, please check sandbox_host config and if your sandbox is running.'); else reportError('Your sandbox version is tooooooo low! Please upgrade!'); return false; }