judge: remove useless suffix

This commit is contained in:
undefined committed 2022-09-06 13:02:46 +08:00
1 parent 805c8e4cd3
commit 7f967060cd
12 files changed
+61 -60

No files matched your search

+14 -3
View File
@@ -1,10 +1,21 @@
/* eslint-disable no-template-curly-in-string */ /* eslint-disable no-template-curly-in-string */
import { STATUS } from '@hydrooj/utils/lib/status'; import { STATUS } from '@hydrooj/utils/lib/status';
import { FormatError, SystemError } from './error'; import { FormatError, SystemError } from './error';
import { CheckConfig } from './interface'; import { CopyInFile, run } from './sandbox';
import { run } from './sandbox';
import { parse } from './testlib'; import { parse } from './testlib';
export interface CheckConfig {
execute: string;
input: CopyInFile;
output: CopyInFile;
user_stdout: CopyInFile;
user_stderr: CopyInFile;
copyIn: Record<string, CopyInFile>;
score: number;
detail: boolean;
env?: Record<string, string>;
}
type Checker = (config: CheckConfig) => Promise<{ type Checker = (config: CheckConfig) => Promise<{
status: number, status: number,
score: number, score: number,
@@ -202,4 +213,4 @@ const checkers: Record<string, Checker> = new Proxy({
}, },
}); });
export = checkers; export default checkers;
+4 -4
View File
@@ -71,8 +71,8 @@ export const runFlow = async (ctx: Context, task: Task) => {
const tasks = []; const tasks = [];
ctx.total_status = 0; ctx.total_status = 0;
ctx.total_score = 0; ctx.total_score = 0;
ctx.total_memory_usage_kb = 0; ctx.total_memory = 0;
ctx.total_time_usage_ms = 0; ctx.total_time = 0;
ctx.rerun = getConfig('rerun') || 0; ctx.rerun = getConfig('rerun') || 0;
ctx.queue = new Queue({ concurrency: getConfig('singleTaskParallelism') }); ctx.queue = new Queue({ concurrency: getConfig('singleTaskParallelism') });
ctx.failed = {}; ctx.failed = {};
@@ -90,7 +90,7 @@ export const runFlow = async (ctx: Context, task: Task) => {
ctx.end({ ctx.end({
status: ctx.total_status, status: ctx.total_status,
score: ctx.total_score, score: ctx.total_score,
time: Math.floor(ctx.total_time_usage_ms * 1000000) / 1000000, time: Math.floor(ctx.total_time * 1000000) / 1000000,
memory: ctx.total_memory_usage_kb, memory: ctx.total_memory,
}); });
}; };
+1 -1
View File
@@ -19,7 +19,7 @@ const logger = new Logger('judge');
const session = { const session = {
config: { detail: system.get('hydrojudge.detail') }, config: { detail: system.get('hydrojudge.detail') },
async fetchCodeFile(name: string) { async fetchFile(name: string) {
const target = path.join('/tmp/hydro/judge', name.replace(/\//g, '_')); const target = path.join('/tmp/hydro/judge', name.replace(/\//g, '_'));
await storage.get(`submission/${name}`, target); await storage.get(`submission/${name}`, target);
return target; return target;
+1 -1
View File
@@ -105,7 +105,7 @@ export default class Hydro {
return filePath; return filePath;
} }
async fetchCodeFile(name: string) { async fetchFile(name: string) {
const res = await this.axios.post('judge/code', { id: name }); const res = await this.axios.post('judge/code', { id: name });
const f = await this.axios.get(res.data.url, { responseType: 'stream' }) const f = await this.axios.get(res.data.url, { responseType: 'stream' })
.catch((e) => new Error(`DownloadFail(${name}): ${e.message}`)); .catch((e) => new Error(`DownloadFail(${name}): ${e.message}`));
-12
View File
@@ -6,15 +6,3 @@ export interface Execute {
copyIn: Record<string, CopyInFile>; copyIn: Record<string, CopyInFile>;
time?: number; time?: number;
} }
export interface CheckConfig {
execute: string;
input: CopyInFile;
output: CopyInFile;
user_stdout: CopyInFile;
user_stderr: CopyInFile;
copyIn: Record<string, CopyInFile>;
score: number;
detail: boolean;
env?: Record<string, string>;
}
+9 -9
View File
@@ -23,7 +23,7 @@ function judgeCase(c: NormalizedCase, sid: string) {
const copyIn = { ...ctx.execute.copyIn }; const copyIn = { ...ctx.execute.copyIn };
if (filename) copyIn[`${filename}.in`] = c.input ? { src: c.input } : { content: '' }; if (filename) copyIn[`${filename}.in`] = c.input ? { src: c.input } : { content: '' };
const copyOutCached = filename ? [`${filename}.out?`] : []; const copyOutCached = filename ? [`${filename}.out?`] : [];
const stdin = filename ? null : c.input; const stdin = filename ? null : { src: c.input };
const res = await run( const res = await run(
ctx.execute.execute, ctx.execute.execute,
{ {
@@ -35,7 +35,7 @@ function judgeCase(c: NormalizedCase, sid: string) {
cacheStdoutAndStderr: true, cacheStdoutAndStderr: true,
}, },
); );
const { code, time_usage_ms, memory_usage_kb } = res; const { code, time, memory } = res;
let { status } = res; let { status } = res;
let stdout: CmdFile = { fileId: res.fileIds[filename ? `${filename}.out` : 'stdout'] }; let stdout: CmdFile = { fileId: res.fileIds[filename ? `${filename}.out` : 'stdout'] };
const stderr = { fileId: res.fileIds['stderr'] }; const stderr = { fileId: res.fileIds['stderr'] };
@@ -43,9 +43,9 @@ function judgeCase(c: NormalizedCase, sid: string) {
let message: any = ''; let message: any = '';
let score = 0; let score = 0;
if (status === STATUS.STATUS_ACCEPTED) { if (status === STATUS.STATUS_ACCEPTED) {
if (time_usage_ms > c.time * ctx.execute.time) { if (time > c.time * ctx.execute.time) {
status = STATUS.STATUS_TIME_LIMIT_EXCEEDED; status = STATUS.STATUS_TIME_LIMIT_EXCEEDED;
} else if (memory_usage_kb > c.memory * 1024) { } else if (memory > c.memory * 1024) {
status = STATUS.STATUS_MEMORY_LIMIT_EXCEEDED; status = STATUS.STATUS_MEMORY_LIMIT_EXCEEDED;
} else { } else {
({ status, score, message } = await checkers[ctx.config.checker_type]({ ({ status, score, message } = await checkers[ctx.config.checker_type]({
@@ -75,16 +75,16 @@ function judgeCase(c: NormalizedCase, sid: string) {
ctxSubtask.score = Score[ctxSubtask.subtask.type](ctxSubtask.score, score); ctxSubtask.score = Score[ctxSubtask.subtask.type](ctxSubtask.score, score);
ctxSubtask.status = Math.max(ctxSubtask.status, status); ctxSubtask.status = Math.max(ctxSubtask.status, status);
if (ctxSubtask.status > STATUS.STATUS_ACCEPTED) ctx.failed[sid] = true; if (ctxSubtask.status > STATUS.STATUS_ACCEPTED) ctx.failed[sid] = true;
ctx.total_time_usage_ms += time_usage_ms; ctx.total_time += time;
ctx.total_memory_usage_kb = Math.max(ctx.total_memory_usage_kb, memory_usage_kb); ctx.total_memory = Math.max(ctx.total_memory, memory);
ctx.next({ ctx.next({
case: { case: {
id: c.id, id: c.id,
subtaskId: ctxSubtask.subtask.id, subtaskId: ctxSubtask.subtask.id,
status, status,
score, score,
time: time_usage_ms, time,
memory: memory_usage_kb, memory,
message, message,
}, },
addProgress: 100 / ctx.config.count, addProgress: 100 / ctx.config.count,
@@ -98,7 +98,7 @@ function judgeCase(c: NormalizedCase, sid: string) {
const r = await run(langConfig.analysis, { const r = await run(langConfig.analysis, {
copyIn: { copyIn: {
...copyIn, ...copyIn,
input: stdin ? { src: stdin } : { content: '' }, input: stdin || { content: '' },
[langConfig.code_file || 'foo']: ctx.code, [langConfig.code_file || 'foo']: ctx.code,
compile: { content: langConfig.compile || '' }, compile: { content: langConfig.compile || '' },
execute: { content: langConfig.execute || '' }, execute: { content: langConfig.execute || '' },
+7 -7
View File
@@ -19,7 +19,7 @@ function judgeCase(c: NormalizedCase) {
return async (ctx: Context, ctxSubtask: ContextSubTask) => { return async (ctx: Context, ctxSubtask: ContextSubTask) => {
ctx.executeInteractor.copyIn.in = c.input ? { src: c.input } : { content: '' }; ctx.executeInteractor.copyIn.in = c.input ? { src: c.input } : { content: '' };
ctx.executeInteractor.copyIn.out = c.output ? { src: c.output } : { content: '' }; ctx.executeInteractor.copyIn.out = c.output ? { src: c.output } : { content: '' };
const [{ code, time_usage_ms, memory_usage_kb }, resInteractor] = await runPiped( const [{ code, time, memory }, resInteractor] = await runPiped(
{ {
execute: ctx.executeUser.execute, execute: ctx.executeUser.execute,
copyIn: ctx.executeUser.copyIn, copyIn: ctx.executeUser.copyIn,
@@ -39,9 +39,9 @@ function judgeCase(c: NormalizedCase) {
let status: number; let status: number;
let score = 0; let score = 0;
let message: any = ''; let message: any = '';
if (time_usage_ms > c.time * ctx.executeUser.time) { if (time > c.time * ctx.executeUser.time) {
status = STATUS.STATUS_TIME_LIMIT_EXCEEDED; status = STATUS.STATUS_TIME_LIMIT_EXCEEDED;
} else if (memory_usage_kb > c.memory * 1024) { } else if (memory > c.memory * 1024) {
status = STATUS.STATUS_MEMORY_LIMIT_EXCEEDED; status = STATUS.STATUS_MEMORY_LIMIT_EXCEEDED;
} else if ((code && code !== 13/* Broken Pipe */) || (code === 13 && !resInteractor.code)) { } else if ((code && code !== 13/* Broken Pipe */) || (code === 13 && !resInteractor.code)) {
status = STATUS.STATUS_RUNTIME_ERROR; status = STATUS.STATUS_RUNTIME_ERROR;
@@ -56,8 +56,8 @@ function judgeCase(c: NormalizedCase) {
} }
ctxSubtask.score = Score[ctxSubtask.subtask.type](ctxSubtask.score, score); ctxSubtask.score = Score[ctxSubtask.subtask.type](ctxSubtask.score, score);
ctxSubtask.status = Math.max(ctxSubtask.status, status); ctxSubtask.status = Math.max(ctxSubtask.status, status);
ctx.total_time_usage_ms += time_usage_ms; ctx.total_time += time;
ctx.total_memory_usage_kb = Math.max(ctx.total_memory_usage_kb, memory_usage_kb); ctx.total_memory = Math.max(ctx.total_memory, memory);
ctx.next({ ctx.next({
status: STATUS.STATUS_JUDGING, status: STATUS.STATUS_JUDGING,
case: { case: {
@@ -65,8 +65,8 @@ function judgeCase(c: NormalizedCase) {
subtaskId: ctxSubtask.subtask.id, subtaskId: ctxSubtask.subtask.id,
status, status,
score, score,
time: time_usage_ms, time,
memory: memory_usage_kb, memory,
message, message,
}, },
addProgress: 100 / ctx.config.count, addProgress: 100 / ctx.config.count,
+2 -2
View File
@@ -8,8 +8,8 @@ export type Context = JudgeTask & RuntimeContext;
export interface RuntimeContext { export interface RuntimeContext {
total_score?: number; total_score?: number;
total_status?: number; total_status?: number;
total_time_usage_ms?: number; total_time?: number;
total_memory_usage_kb?: number; total_memory?: number;
queue?: PQueue; queue?: PQueue;
errored?: boolean; errored?: boolean;
+9 -11
View File
@@ -52,14 +52,12 @@ export const judge = async (ctx: Context) => {
const { filename } = ctx.config; const { filename } = ctx.config;
if (filename) copyIn[`${filename}.in`] = { content: ctx.input }; if (filename) copyIn[`${filename}.in`] = { content: ctx.input };
const copyOut = filename ? [`${filename}.out?`] : []; const copyOut = filename ? [`${filename}.out?`] : [];
const stdin = path.resolve(ctx.tmpdir, '0.in');
await fs.writeFile(stdin, ctx.input || '');
const stdout = path.resolve(ctx.tmpdir, '0.out'); const stdout = path.resolve(ctx.tmpdir, '0.out');
const stderr = path.resolve(ctx.tmpdir, '0.err'); const stderr = path.resolve(ctx.tmpdir, '0.err');
const res = await run( const res = await run(
ctx.execute.execute, ctx.execute.execute,
{ {
stdin: filename ? null : stdin, stdin: filename ? null : { content: ctx.input },
stdout: filename ? null : stdout, stdout: filename ? null : stdout,
stderr, stderr,
copyIn, copyIn,
@@ -68,14 +66,14 @@ export const judge = async (ctx: Context) => {
memory: parseMemoryMB(ctx.config.memory || '128m'), memory: parseMemoryMB(ctx.config.memory || '128m'),
}, },
); );
const { code, time_usage_ms, memory_usage_kb } = res; const { code, time, memory } = res;
let { status } = res; let { status } = res;
if (!fs.existsSync(stdout)) fs.writeFileSync(stdout, ''); if (!fs.existsSync(stdout)) fs.writeFileSync(stdout, '');
const message: string[] = []; const message: string[] = [];
if (status === STATUS.STATUS_ACCEPTED) { if (status === STATUS.STATUS_ACCEPTED) {
if (time_usage_ms > parseTimeMS(ctx.config.time || '1s') * ctx.execute.time) { if (time > parseTimeMS(ctx.config.time || '1s') * ctx.execute.time) {
status = STATUS.STATUS_TIME_LIMIT_EXCEEDED; status = STATUS.STATUS_TIME_LIMIT_EXCEEDED;
} else if (memory_usage_kb > parseMemoryMB(ctx.config.memory || '128m') * 1024) { } else if (memory > parseMemoryMB(ctx.config.memory || '128m') * 1024) {
status = STATUS.STATUS_MEMORY_LIMIT_EXCEEDED; status = STATUS.STATUS_MEMORY_LIMIT_EXCEEDED;
} }
} else if (code) { } else if (code) {
@@ -91,8 +89,8 @@ export const judge = async (ctx: Context) => {
subtaskId: 0, subtaskId: 0,
status, status,
score: 100, score: 100,
time: time_usage_ms, time,
memory: memory_usage_kb, memory,
message: message.join('\n').substring(0, 102400), message: message.join('\n').substring(0, 102400),
}, },
}); });
@@ -104,7 +102,7 @@ export const judge = async (ctx: Context) => {
const r = await run(langConfig.analysis, { const r = await run(langConfig.analysis, {
copyIn: { copyIn: {
...copyIn, ...copyIn,
input: { src: stdin }, input: { content: ctx.input },
[langConfig.code_file || 'foo']: ctx.code, [langConfig.code_file || 'foo']: ctx.code,
compile: { content: langConfig.compile || '' }, compile: { content: langConfig.compile || '' },
execute: { content: langConfig.execute || '' }, execute: { content: langConfig.execute || '' },
@@ -130,7 +128,7 @@ export const judge = async (ctx: Context) => {
ctx.end({ ctx.end({
status, status,
score: status === STATUS.STATUS_ACCEPTED ? 100 : 0, score: status === STATUS.STATUS_ACCEPTED ? 100 : 0,
time: Math.floor(time_usage_ms * 1000000) / 1000000, time: Math.floor(time * 1000000) / 1000000,
memory: memory_usage_kb, memory,
}); });
}; };
+10 -8
View File
@@ -30,7 +30,7 @@ const statusMap: Map<SandboxStatus, number> = new Map([
interface Parameter { interface Parameter {
time?: number; time?: number;
stdin?: string; stdin?: CopyInFile;
stdout?: string; stdout?: string;
stderr?: string; stderr?: string;
execute?: string; execute?: string;
@@ -46,8 +46,10 @@ interface Parameter {
interface SandboxAdaptedResult { interface SandboxAdaptedResult {
status: number; status: number;
code: number; code: number;
time_usage_ms: number; /** in miliseconds */
memory_usage_kb?: number; time: number;
/** in kilobytes */
memory?: number;
files: Record<string, string>; files: Record<string, string>;
fileIds?: Record<string, string>; fileIds?: Record<string, string>;
stdout?: string; stdout?: string;
@@ -72,7 +74,7 @@ function proc({
time = 16000, time = 16000,
memory = parseMemoryMB(getConfig('memoryMax')), memory = parseMemoryMB(getConfig('memoryMax')),
processLimit = getConfig('processLimit'), processLimit = getConfig('processLimit'),
stdin = '', copyIn = {}, copyOut = [], copyOutCached = [], stdin = { content: '' }, copyIn = {}, copyOut = [], copyOutCached = [],
cacheStdoutAndStderr = false, cacheStdoutAndStderr = false,
env = {}, env = {},
}: Parameter = {}): Cmd { }: Parameter = {}): Cmd {
@@ -89,7 +91,7 @@ function proc({
args: parseArgs(execute), args: parseArgs(execute),
env: [...getConfig('env').split('\n'), ...Object.keys(env).map((i) => `${i}=${env[i].replace(/=/g, '\\=')}`)], env: [...getConfig('env').split('\n'), ...Object.keys(env).map((i) => `${i}=${env[i].replace(/=/g, '\\=')}`)],
files: [ files: [
stdin ? { src: stdin } : { content: '' }, stdin,
{ name: 'stdout', max: Math.floor(1024 * 1024 * size) }, { name: 'stdout', max: Math.floor(1024 * 1024 * size) },
{ name: 'stderr', max: Math.floor(1024 * 1024 * size) }, { name: 'stderr', max: Math.floor(1024 * 1024 * size) },
], ],
@@ -110,12 +112,12 @@ async function adaptResult(result: SandboxResult, params: Parameter): Promise<Sa
// FIXME: Signalled? // FIXME: Signalled?
const ret: SandboxAdaptedResult = { const ret: SandboxAdaptedResult = {
status: statusMap.get(result.status) || STATUS.STATUS_ACCEPTED, status: statusMap.get(result.status) || STATUS.STATUS_ACCEPTED,
time_usage_ms: result.time / 1000000 / rate, time: result.time / 1000000 / rate,
memory_usage_kb: result.memory / 1024, memory: result.memory / 1024,
files: result.files, files: result.files,
code: result.exitStatus, code: result.exitStatus,
}; };
if (ret.time_usage_ms >= (params.time || 16000)) { if (ret.time >= (params.time || 16000)) {
ret.status = STATUS.STATUS_TIME_LIMIT_EXCEEDED; ret.status = STATUS.STATUS_TIME_LIMIT_EXCEEDED;
} }
ret.files = result.files || {}; ret.files = result.files || {};
+2 -2
View File
@@ -19,7 +19,7 @@ interface Session {
getNext: (task: JudgeTask) => NextFunction; getNext: (task: JudgeTask) => NextFunction;
getEnd: (task: JudgeTask) => NextFunction; getEnd: (task: JudgeTask) => NextFunction;
cacheOpen: (source: string, files: any[], next?: NextFunction) => Promise<string>; cacheOpen: (source: string, files: any[], next?: NextFunction) => Promise<string>;
fetchCodeFile: (target: string) => Promise<string>; fetchFile: (target: string) => Promise<string>;
config: { detail: boolean, host?: string }; config: { detail: boolean, host?: string };
} }
@@ -110,7 +110,7 @@ export class JudgeTask {
if ((this.code as any).content.startsWith('@@hydro_submission_file@@')) { if ((this.code as any).content.startsWith('@@hydro_submission_file@@')) {
const id = (this.code as any).content.split('@@hydro_submission_file@@')[1]?.split('#')?.[0]; const id = (this.code as any).content.split('@@hydro_submission_file@@')[1]?.split('#')?.[0];
if (!id) throw new SystemError('Submission File Not Found'); if (!id) throw new SystemError('Submission File Not Found');
const target = await this.session.fetchCodeFile(id); const target = await this.session.fetchFile(id);
this.code = { src: target }; this.code = { src: target };
this.clean.push(() => fs.remove(target)); this.clean.push(() => fs.remove(target));
} }
+2
View File
@@ -514,7 +514,9 @@ export interface JudgeResultBody {
case?: TestCase, case?: TestCase,
status?: number; status?: number;
score?: number; score?: number;
/** in miliseconds */
time?: number; time?: number;
/** in kilobytes */
memory?: number; memory?: number;
message?: string | JudgeMessage; message?: string | JudgeMessage;
compilerText?: string; compilerText?: string;