judge: optimize

master
undefined 11 months ago
parent 2d25eaac0f
commit 0bc6a28457
No known key found for this signature in database

@ -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);
}
}
} }

Loading…
Cancel
Save