mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-20 01:38:19 +08:00
judge: optimize
This commit is contained in:
3 files changed
+36
-96
No files matched your search
@@ -1,14 +1,11 @@
|
|||||||
import { STATUS } from '@hydrooj/utils/lib/status';
|
import { STATUS } from '@hydrooj/utils/lib/status';
|
||||||
import checkers from '../checkers';
|
import checkers from '../checkers';
|
||||||
import { runFlow } from '../flow';
|
import { runFlow } from '../flow';
|
||||||
import { Logger } from '../log';
|
|
||||||
import { del, runQueued } from '../sandbox';
|
import { del, runQueued } from '../sandbox';
|
||||||
import signals from '../signals';
|
import signals from '../signals';
|
||||||
import { NormalizedCase } from '../utils';
|
import { NormalizedCase } from '../utils';
|
||||||
import { Context, ContextSubTask } from './interface';
|
import { Context, ContextSubTask } from './interface';
|
||||||
|
|
||||||
const logger = new Logger('judge/default');
|
|
||||||
|
|
||||||
function judgeCase(c: NormalizedCase) {
|
function judgeCase(c: NormalizedCase) {
|
||||||
return async (ctx: Context, ctxSubtask: ContextSubTask, runner?: Function) => {
|
return async (ctx: Context, ctxSubtask: ContextSubTask, runner?: Function) => {
|
||||||
const { address_space_limit, process_limit } = ctx.session.getLang(ctx.lang);
|
const { address_space_limit, process_limit } = ctx.session.getLang(ctx.lang);
|
||||||
@@ -58,31 +55,9 @@ function judgeCase(c: NormalizedCase) {
|
|||||||
ctx.rerun--;
|
ctx.rerun--;
|
||||||
return await runner(ctx, ctxSubtask);
|
return await runner(ctx, ctxSubtask);
|
||||||
}
|
}
|
||||||
if (!ctx.request.rejudged && [STATUS.STATUS_WRONG_ANSWER, STATUS.STATUS_RUNTIME_ERROR].includes(status)) {
|
if (!ctx.request.rejudged && !ctx.analysis && [STATUS.STATUS_WRONG_ANSWER, STATUS.STATUS_RUNTIME_ERROR].includes(status)) {
|
||||||
const langConfig = ctx.session.getLang(ctx.lang);
|
|
||||||
if (langConfig.analysis && !ctx.analysis) {
|
|
||||||
ctx.analysis = true;
|
ctx.analysis = true;
|
||||||
try {
|
await ctx.runAnalysis(ctx.execute, { src: ctx.input });
|
||||||
const r = await runQueued(langConfig.analysis, {
|
|
||||||
copyIn: {
|
|
||||||
...ctx.execute.copyIn,
|
|
||||||
input: { src: c.input },
|
|
||||||
[langConfig.code_file || 'foo']: ctx.code,
|
|
||||||
compile: { content: langConfig.compile || '' },
|
|
||||||
execute: { content: langConfig.execute || '' },
|
|
||||||
},
|
|
||||||
time: 5000,
|
|
||||||
memory: 256,
|
|
||||||
env: ctx.env,
|
|
||||||
});
|
|
||||||
const out = r.stdout.toString();
|
|
||||||
if (out.length) ctx.next({ compilerText: out.substring(0, 1024) });
|
|
||||||
if (process.env.DEV) console.log(r);
|
|
||||||
} catch (e) {
|
|
||||||
logger.info('Failed to run analysis');
|
|
||||||
logger.error(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
id: c.id,
|
id: c.id,
|
||||||
|
|||||||
@@ -1,49 +1,16 @@
|
|||||||
import { STATUS } from '@hydrooj/utils/lib/status';
|
import { STATUS } from '@hydrooj/utils/lib/status';
|
||||||
import { CompileError } from '../error';
|
|
||||||
import { Execute } from '../interface';
|
|
||||||
import { Logger } from '../log';
|
import { Logger } from '../log';
|
||||||
import { runQueued } from '../sandbox';
|
import { runQueued } from '../sandbox';
|
||||||
import signals from '../signals';
|
import signals from '../signals';
|
||||||
import { JudgeTask } from '../task';
|
import { JudgeTask } from '../task';
|
||||||
import { compilerText, parseMemoryMB, parseTimeMS } from '../utils';
|
import { parseMemoryMB, parseTimeMS } from '../utils';
|
||||||
|
|
||||||
const failure = (status: number, message?: string) => ({
|
|
||||||
status,
|
|
||||||
score: 0,
|
|
||||||
time: 0,
|
|
||||||
memory: 0,
|
|
||||||
message,
|
|
||||||
});
|
|
||||||
|
|
||||||
const logger = new Logger('judge/run');
|
const logger = new Logger('judge/run');
|
||||||
|
|
||||||
export const judge = async (ctx: JudgeTask) => {
|
export const judge = async (ctx: JudgeTask) => {
|
||||||
ctx.stat.judge = new Date();
|
ctx.stat.judge = new Date();
|
||||||
ctx.next({ status: STATUS.STATUS_COMPILING });
|
ctx.next({ status: STATUS.STATUS_COMPILING });
|
||||||
let execute: Execute;
|
const execute = await ctx.compile(ctx.lang, ctx.code);
|
||||||
try {
|
|
||||||
execute = await ctx.compile(
|
|
||||||
ctx.lang, ctx.code,
|
|
||||||
Object.fromEntries(
|
|
||||||
(ctx.config.user_extra_files || []).map((i) => [i.split('/').pop(), { src: i }]),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
} catch (e) {
|
|
||||||
if (e instanceof CompileError) {
|
|
||||||
ctx.next({
|
|
||||||
status: STATUS.STATUS_COMPILE_ERROR,
|
|
||||||
case: failure(STATUS.STATUS_COMPILE_ERROR, compilerText(e.stdout, e.stderr)),
|
|
||||||
});
|
|
||||||
ctx.end(failure(STATUS.STATUS_COMPILE_ERROR));
|
|
||||||
} else {
|
|
||||||
ctx.next({
|
|
||||||
status: STATUS.STATUS_SYSTEM_ERROR,
|
|
||||||
case: failure(STATUS.STATUS_SYSTEM_ERROR, `${e.message}\n${JSON.stringify(e.params)}`),
|
|
||||||
});
|
|
||||||
ctx.end(failure(STATUS.STATUS_SYSTEM_ERROR));
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ctx.next({ status: STATUS.STATUS_JUDGING, progress: 0 });
|
ctx.next({ status: STATUS.STATUS_JUDGING, progress: 0 });
|
||||||
const { address_space_limit, process_limit } = ctx.session.getLang(ctx.lang);
|
const { address_space_limit, process_limit } = ctx.session.getLang(ctx.lang);
|
||||||
const res = await runQueued(
|
const res = await runQueued(
|
||||||
@@ -76,6 +43,9 @@ export const judge = async (ctx: JudgeTask) => {
|
|||||||
message.push(res.stdout, res.stderr);
|
message.push(res.stdout, res.stderr);
|
||||||
ctx.next({
|
ctx.next({
|
||||||
status,
|
status,
|
||||||
|
time: Math.floor(time * 1000000) / 1000000,
|
||||||
|
memory,
|
||||||
|
score: status === STATUS.STATUS_ACCEPTED ? 100 : 0,
|
||||||
case: {
|
case: {
|
||||||
subtaskId: 0,
|
subtaskId: 0,
|
||||||
status,
|
status,
|
||||||
@@ -86,39 +56,9 @@ export const judge = async (ctx: JudgeTask) => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
if ([STATUS.STATUS_WRONG_ANSWER, STATUS.STATUS_RUNTIME_ERROR].includes(status)) {
|
if ([STATUS.STATUS_WRONG_ANSWER, STATUS.STATUS_RUNTIME_ERROR].includes(status)) {
|
||||||
const langConfig = ctx.session.getLang(ctx.lang);
|
await ctx.runAnalysis(execute, { content: ctx.input });
|
||||||
if (langConfig.analysis) {
|
|
||||||
try {
|
|
||||||
const r = await runQueued(langConfig.analysis, {
|
|
||||||
copyIn: {
|
|
||||||
...execute.copyIn,
|
|
||||||
input: { content: ctx.input },
|
|
||||||
[langConfig.code_file || 'foo']: ctx.code,
|
|
||||||
compile: { content: langConfig.compile || '' },
|
|
||||||
execute: { content: langConfig.execute || '' },
|
|
||||||
},
|
|
||||||
env: {
|
|
||||||
...ctx.env,
|
|
||||||
HYDRO_PRETEST: 'true',
|
|
||||||
},
|
|
||||||
time: 5000,
|
|
||||||
memory: 256,
|
|
||||||
});
|
|
||||||
const out = r.stdout.toString();
|
|
||||||
if (out.length) ctx.next({ compilerText: out.substring(0, 1024) });
|
|
||||||
if (process.env.DEV) console.log(r);
|
|
||||||
} catch (e) {
|
|
||||||
logger.info('Failed to run analysis');
|
|
||||||
logger.error(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ctx.stat.done = new Date();
|
ctx.stat.done = new Date();
|
||||||
if (process.env.DEV) ctx.next({ message: JSON.stringify(ctx.stat) });
|
if (process.env.DEV) ctx.next({ message: JSON.stringify(ctx.stat) });
|
||||||
ctx.end({
|
ctx.end({ status });
|
||||||
status,
|
|
||||||
score: status === STATUS.STATUS_ACCEPTED ? 100 : 0,
|
|
||||||
time: Math.floor(time * 1000000) / 1000000,
|
|
||||||
memory,
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
@@ -10,10 +10,10 @@ import checkers from './checkers';
|
|||||||
import compile, { compileWithTestlib } from './compile';
|
import compile, { compileWithTestlib } from './compile';
|
||||||
import { getConfig } from './config';
|
import { getConfig } from './config';
|
||||||
import { CompileError, FormatError } from './error';
|
import { CompileError, FormatError } from './error';
|
||||||
import { NextFunction, ParsedConfig } from './interface';
|
import { Execute, NextFunction, ParsedConfig } from './interface';
|
||||||
import judge from './judge';
|
import judge from './judge';
|
||||||
import { Logger } from './log';
|
import { Logger } from './log';
|
||||||
import { CopyIn, CopyInFile } from './sandbox';
|
import { CopyIn, CopyInFile, runQueued } from './sandbox';
|
||||||
import { compilerText, md5 } from './utils';
|
import { compilerText, md5 } from './utils';
|
||||||
|
|
||||||
interface Session {
|
interface Session {
|
||||||
@@ -156,4 +156,29 @@ export class JudgeTask {
|
|||||||
this.clean.push(result.clean);
|
this.clean.push(result.clean);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async runAnalysis(execute: Execute, input: CopyInFile) {
|
||||||
|
const langConfig = this.session.getLang(this.lang);
|
||||||
|
if (!langConfig.analysis) return;
|
||||||
|
try {
|
||||||
|
const r = await runQueued(langConfig.analysis, {
|
||||||
|
copyIn: {
|
||||||
|
...execute.copyIn,
|
||||||
|
input,
|
||||||
|
[langConfig.code_file || 'foo']: this.code,
|
||||||
|
compile: { content: langConfig.compile || '' },
|
||||||
|
execute: { content: langConfig.execute || '' },
|
||||||
|
},
|
||||||
|
env: this.env,
|
||||||
|
time: 5000,
|
||||||
|
memory: 256,
|
||||||
|
});
|
||||||
|
const out = r.stdout.toString();
|
||||||
|
if (out.length) this.next({ compilerText: out.substring(0, 1024) });
|
||||||
|
if (process.env.DEV) console.log(r);
|
||||||
|
} catch (e) {
|
||||||
|
logger.info('Failed to run analysis');
|
||||||
|
logger.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user