From 4adf05c50b20f7184dfacf92fc58ba3dd75f069c Mon Sep 17 00:00:00 2001 From: undefined Date: Fri, 24 Feb 2023 19:26:41 +0800 Subject: [PATCH] core&judge: allow performance mode --- packages/hydrojudge/src/config.ts | 1 + packages/hydrojudge/src/hosts/hydro.ts | 8 +++- packages/hydrojudge/src/task.ts | 3 +- packages/hydrooj/src/handler/judge.ts | 58 +++++++++++++------------- packages/hydrooj/src/interface.ts | 3 +- 5 files changed, 41 insertions(+), 32 deletions(-) diff --git a/packages/hydrojudge/src/config.ts b/packages/hydrojudge/src/config.ts index 25eb82065..a9d1fd2fe 100644 --- a/packages/hydrojudge/src/config.ts +++ b/packages/hydrojudge/src/config.ts @@ -26,6 +26,7 @@ const JudgeSettings = Schema.object({ secret: Schema.string().description('Judge Token Secret').default(String.random(32)), disable: Schema.boolean().description('Disable builtin judge').default(false), detail: Schema.boolean().description('Show diff detail').default(true), + performance: Schema.boolean().description('Performance mode').default(false), }); const oldPath = path.resolve(os.homedir(), '.config', 'hydro', 'judge.yaml'); diff --git a/packages/hydrojudge/src/hosts/hydro.ts b/packages/hydrojudge/src/hosts/hydro.ts index 0495f118f..0ea5b6a29 100644 --- a/packages/hydrojudge/src/hosts/hydro.ts +++ b/packages/hydrojudge/src/hosts/hydro.ts @@ -155,13 +155,19 @@ export default class Hydro { getNext(t: JudgeTask) { return (data: Partial) => { log.debug('Next: %o', data); - this.send(t.request.rid, 'next', data); + if (getConfig('performance') && data.case && !data.compilerText && !data.message) { + t.callbackCache ||= []; + t.callbackCache.push(data.case); + } else { + this.send(t.request.rid, 'next', data); + } }; } getEnd(t: JudgeTask) { return (data: Partial) => { log.info('End: %o', data); + if (t.callbackCache) data.cases = t.callbackCache; this.send(t.request.rid, 'end', data); }; } diff --git a/packages/hydrojudge/src/task.ts b/packages/hydrojudge/src/task.ts index 06a85a327..76599ea14 100644 --- a/packages/hydrojudge/src/task.ts +++ b/packages/hydrojudge/src/task.ts @@ -2,7 +2,7 @@ import fs from 'fs-extra'; import { LangConfig } from '@hydrooj/utils/lib/lang'; import { STATUS } from '@hydrooj/utils/lib/status'; import type { - FileInfo, JudgeMeta, JudgeRequest, JudgeResultBody, + FileInfo, JudgeMeta, JudgeRequest, JudgeResultBody, TestCase, } from 'hydrooj'; import readCases from './cases'; import { getConfig } from './config'; @@ -40,6 +40,7 @@ export class JudgeTask { next: (data: Partial) => void; end: (data: Partial) => void; env: Record; + callbackCache?: TestCase[]; constructor(public session: Session, public request: JudgeRequest) { this.stat = {}; diff --git a/packages/hydrooj/src/handler/judge.ts b/packages/hydrooj/src/handler/judge.ts index 6a5d35858..ed3b9d205 100644 --- a/packages/hydrooj/src/handler/judge.ts +++ b/packages/hydrooj/src/handler/judge.ts @@ -24,20 +24,25 @@ import { sleep } from '../utils'; const logger = new Logger('judge'); -export async function next(body: Partial) { - body.rid = new ObjectID(body.rid); - let rdoc = await record.get(body.rid); - if (!rdoc) return; +function parseCaseResult(body: TestCase): Required { + return { + ...body, + id: body.id || 0, + subtaskId: body.subtaskId || 0, + score: body.score || 0, + message: body.message || '', + }; +} + +function processPayload(rdoc: RecordDoc, body: Partial) { const $set: Partial = {}; const $push: any = {}; - if (body.case) { - const c: Required = { - ...body.case, - id: body.case.id || 0, - subtaskId: body.case.subtaskId || 0, - score: body.case.score || 0, - message: body.case.message || '', - }; + if (body.cases?.length) { + const c = body.cases.map(parseCaseResult); + rdoc.testCases.push(...c); + $push.testCases = { $each: c }; + } else if (body.case) { + const c = parseCaseResult(body.case); rdoc.testCases.push(c); $push.testCases = c; } @@ -50,10 +55,18 @@ export async function next(body: Partial) { $push.compilerTexts = body.compilerText; } if (body.status) $set.status = body.status; - if (body.score !== undefined) $set.score = body.score; - if (body.time !== undefined) $set.time = body.time; - if (body.memory !== undefined) $set.memory = body.memory; + if (Number.isFinite(body.score)) $set.score = Math.floor(body.score * 100) / 100; + if (Number.isFinite(body.time)) $set.time = body.time; + if (Number.isFinite(body.memory)) $set.memory = body.memory; if (body.progress !== undefined) $set.progress = body.progress; + return { $set, $push }; +} + +export async function next(body: Partial) { + body.rid = new ObjectID(body.rid); + let rdoc = await record.get(body.rid); + if (!rdoc) return; + const { $set, $push } = processPayload(rdoc, body); rdoc = await record.update(rdoc.domainId, body.rid, $set, $push, {}, body.addProgress ? { progress: body.addProgress } : {}); bus.broadcast('record/change', rdoc!, $set, $push); } @@ -118,21 +131,8 @@ export async function end(body: Partial) { body.rid &&= new ObjectID(body.rid); let rdoc = await record.get(body.rid); if (!rdoc) return; - const $set: Partial = {}; - const $push: any = {}; + const { $set, $push } = processPayload(rdoc, body); const $unset: any = { progress: '' }; - if (body.message) { - rdoc.judgeTexts.push(body.message); - $push.judgeTexts = body.message; - } - if (body.compilerText) { - rdoc.compilerTexts.push(body.compilerText); - $push.compilerTexts = body.compilerText; - } - if (body.status) $set.status = body.status; - if (Number.isFinite(body.score)) $set.score = Math.floor(body.score * 100) / 100; - if (Number.isFinite(body.time)) $set.time = body.time; - if (Number.isFinite(body.memory)) $set.memory = body.memory; $set.judgeAt = new Date(); $set.judger = body.judger ?? 1; await sleep(100); // Make sure that all 'next' event already triggered diff --git a/packages/hydrooj/src/interface.ts b/packages/hydrooj/src/interface.ts index cf73cd5a9..3b1af5fb3 100644 --- a/packages/hydrooj/src/interface.ts +++ b/packages/hydrooj/src/interface.ts @@ -567,7 +567,8 @@ export interface JudgeResultBody { judger?: number; progress?: number; addProgress?: number; - case?: TestCase, + case?: TestCase; + cases?: TestCase[]; status?: number; score?: number; /** in miliseconds */