Skip to content

Commit

Permalink
core: 支持显示时空限制 (#65)
Browse files Browse the repository at this point in the history
虽然有点丑,但是能用
  • Loading branch information
undefined-moe committed Apr 10, 2021
1 parent d5c5b3f commit 1c89596
Show file tree
Hide file tree
Showing 20 changed files with 84 additions and 59 deletions.
2 changes: 1 addition & 1 deletion packages/hydrojudge/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@hydrooj/hydrojudge",
"bin": "bin/hydrojudge.js",
"version": "2.4.19",
"version": "2.5.0",
"os": [
"linux"
],
Expand Down
14 changes: 7 additions & 7 deletions packages/hydrojudge/src/cases.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,8 @@ async function read0(folder: string, files: string[], checkFile, cfg) {
const config = {
count: 0,
subtasks: [{
time_limit_ms: parseTimeMS(cfg.time || '1s'),
memory_limit_mb: parseMemoryMB(cfg.memory || '256m'),
time: parseTimeMS(cfg.time || '1s'),
memory: parseMemoryMB(cfg.memory || '256m'),
type: 'sum',
cases: [],
score: Math.floor(100 / cases.length),
Expand All @@ -105,8 +105,8 @@ async function read0(folder: string, files: string[], checkFile, cfg) {
}
if (extra < cases.length) {
config.subtasks.push({
time_limit_ms: parseTimeMS(cfg.time || '1s'),
memory_limit_mb: parseMemoryMB(cfg.memory || '256m'),
time: parseTimeMS(cfg.time || '1s'),
memory: parseMemoryMB(cfg.memory || '256m'),
type: 'sum',
cases: [],
score: Math.floor(100 / cases.length) + 1,
Expand Down Expand Up @@ -134,8 +134,8 @@ async function read1(folder: string, files: string[], checkFile, cfg) {
if (fs.existsSync(path.resolve(folder, c.output))) {
if (!subtask[REG.subtask(data)]) {
subtask[REG.subtask(data)] = [{
time_limit_ms: parseTimeMS(cfg.time || '1s'),
memory_limit_mb: parseMemoryMB(cfg.memory || '256m'),
time: parseTimeMS(cfg.time || '1s'),
memory: parseMemoryMB(cfg.memory || '256m'),
type: 'min',
cases: [c],
}];
Expand Down Expand Up @@ -199,7 +199,7 @@ function isValidConfig(config) {
if (config.count > (getConfig('testcases_max') || 100)) {
throw new FormatError('Too many testcases. Cancelled.');
}
const total_time = sum(config.subtasks.map((subtask) => subtask.time_limit_ms * subtask.cases.length));
const total_time = sum(config.subtasks.map((subtask) => subtask.time * subtask.cases.length));
if (total_time > (getConfig('total_time_limit') || 60) * 1000) {
throw new FormatError('Total time limit longer than {0}s. Cancelled.', [+getConfig('total_time_limit') || 60]);
}
Expand Down
8 changes: 4 additions & 4 deletions packages/hydrojudge/src/judge/default.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ function judgeCase(c, sid) {
stderr,
copyIn,
copyOut,
time_limit_ms: ctxSubtask.subtask.time_limit_ms * ctx.execute.time,
memory_limit_mb: ctxSubtask.subtask.memory_limit_mb,
time: ctxSubtask.subtask.time * ctx.execute.time,
memory: ctxSubtask.subtask.memory,
},
);
const { code, time_usage_ms, memory_usage_kb } = res;
Expand All @@ -62,9 +62,9 @@ function judgeCase(c, sid) {
let message: any = '';
let score = 0;
if (status === STATUS.STATUS_ACCEPTED) {
if (time_usage_ms > ctxSubtask.subtask.time_limit_ms * ctx.execute.time) {
if (time_usage_ms > ctxSubtask.subtask.time * ctx.execute.time) {
status = STATUS.STATUS_TIME_LIMIT_EXCEEDED;
} else if (memory_usage_kb > ctxSubtask.subtask.memory_limit_mb * 1024) {
} else if (memory_usage_kb > ctxSubtask.subtask.memory * 1024) {
status = STATUS.STATUS_MEMORY_LIMIT_EXCEEDED;
} else {
[status, score, message] = await check({
Expand Down
4 changes: 2 additions & 2 deletions packages/hydrojudge/src/judge/hack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,8 @@ export const judge = async (ctx) => {
stderr,
copyIn: execute.copyIn,
copyOut,
time_limit_ms: 1000,
memory_limit_mb: 512,
time: 1000,
memory: 512,
},
);
const { code, time_usage_ms, memory_usage_kb } = res;
Expand Down
12 changes: 6 additions & 6 deletions packages/hydrojudge/src/judge/interactive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,21 @@ function judgeCase(c) {
{
execute: ctx.executeUser.execute.replace(/\$\{name\}/g, 'code'),
copyIn: ctx.executeUser.copyIn,
time_limit_ms: ctxSubtask.subtask.time_limit_ms,
memory_limit_mb: ctxSubtask.subtask.memory_limit_mb,
time: ctxSubtask.subtask.time,
memory: ctxSubtask.subtask.memory,
}, {
execute: `${ctx.executeInteractor.execute.replace(/\$\{name\}/g, 'interactor')} /w/in /w/tout`,
copyIn: ctx.executeInteractor.copyIn,
time_limit_ms: ctxSubtask.subtask.time_limit_ms * 2,
memory_limit_mb: ctxSubtask.subtask.memory_limit_mb * 2,
time: ctxSubtask.subtask.time * 2,
memory: ctxSubtask.subtask.memory * 2,
},
]);
let status;
let score = 0;
let message: any = '';
if (time_usage_ms > ctxSubtask.subtask.time_limit_ms) {
if (time_usage_ms > ctxSubtask.subtask.time) {
status = STATUS.STATUS_TIME_LIMIT_EXCEEDED;
} else if (memory_usage_kb > ctxSubtask.subtask.memory_limit_mb * 1024) {
} else if (memory_usage_kb > ctxSubtask.subtask.memory * 1024) {
status = STATUS.STATUS_MEMORY_LIMIT_EXCEEDED;
} else if (code) {
status = STATUS.STATUS_RUNTIME_ERROR;
Expand Down
4 changes: 2 additions & 2 deletions packages/hydrojudge/src/judge/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@ export const judge = async (ctx) => {
stderr,
copyIn,
copyOut,
time_limit_ms: parseTimeMS(ctx.config.time || '1s'),
memory_limit_mb: parseMemoryMB(ctx.config.memory || '128m'),
time: parseTimeMS(ctx.config.time || '1s'),
memory: parseMemoryMB(ctx.config.memory || '128m'),
},
);
const { code, time_usage_ms, memory_usage_kb } = res;
Expand Down
12 changes: 6 additions & 6 deletions packages/hydrojudge/src/sandbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ const statusMap = {

function proc({
execute = '',
time_limit_ms = 16000,
memory_limit_mb = 1024,
time = 16000,
memory = 1024,
process_limit = 32,
stdin = '', copyIn = {}, copyOut = [], copyOutCached = [],
} = {}) {
Expand All @@ -39,9 +39,9 @@ function proc({
{ name: 'stdout', max: 1024 * 1024 * size },
{ name: 'stderr', max: 1024 * 1024 * size },
],
cpuLimit: time_limit_ms * 1000 * 1000,
realCpuLimit: time_limit_ms * 3000 * 1000,
memoryLimit: memory_limit_mb * 1024 * 1024,
cpuLimit: time * 1000 * 1000,
realCpuLimit: time * 3000 * 1000,
memoryLimit: memory * 1024 * 1024,
procLimit: process_limit,
copyIn,
copyOut,
Expand All @@ -58,7 +58,7 @@ async function adaptResult(result, params) {
files: result.files,
code: result.exitStatus,
};
if (ret.time_usage_ms >= (params.time_limit_ms || 16000)) {
if (ret.time_usage_ms >= (params.time || 16000)) {
ret.status = STATUS.STATUS_TIME_LIMIT_EXCEEDED;
}
ret.files = result.files || {};
Expand Down
2 changes: 1 addition & 1 deletion packages/hydrooj/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "hydrooj",
"version": "2.21.19",
"version": "2.22.0",
"bin": "bin/hydrooj.js",
"main": "dist/loader.js",
"typings": "dist/loader.d.ts",
Expand Down
7 changes: 7 additions & 0 deletions packages/hydrooj/src/handler/problem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
import paginate from '../lib/paginate';
import { isPid } from '../lib/validator';
import difficultyAlgorithm from '../lib/difficulty';
import { parseConfig } from '../lib/testdataConfig';
import * as system from '../model/system';
import problem from '../model/problem';
import record from '../model/record';
Expand Down Expand Up @@ -189,6 +190,12 @@ export class ProblemDetailHandler extends ProblemHandler {
// e.g. ![img](a.jpg) will navigate to ![img](./pid/file/a.jpg)
this.response.body.pdoc.content = this.response.body.pdoc.content
.replace(/\(file:\/\//g, `(./${this.pdoc.docId}/file/`);
// Get time and memory limit
try {
this.response.body.pdoc.config = await parseConfig(this.pdoc.config);
} catch (e) {
this.response.body.pdoc.config = `Cannot parse: ${e.message}`;
}
}

@param('pid', Types.UnsignedInt)
Expand Down
1 change: 0 additions & 1 deletion packages/hydrooj/src/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,6 @@ declare module './model/problem' {
data: FileInfo[],
additional_file: FileInfo[],
hidden: boolean,
acMsg?: string,
html?: boolean,
difficulty?: number,
/** @deprecated */
Expand Down
22 changes: 12 additions & 10 deletions packages/hydrooj/src/lib/testdataConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,24 +21,26 @@ export async function parseConfig(config: string | ProblemConfig) {
let cfg: ProblemConfig = {};
if (typeof config === 'string') {
// TODO should validate here?
cfg = readYamlCases(load(config) as Record<string, any>) as ProblemConfig;
cfg = await readYamlCases(load(config) as Record<string, any>) as ProblemConfig;
} else cfg = config;
if (cfg.cases) {
for (const c of cfg.cases) {
result.memoryMax = Math.max(result.memoryMax, c.memory);
result.memoryMin = Math.min(result.memoryMin, c.memory);
result.timeMax = Math.max(result.timeMax, c.time);
result.timeMin = Math.min(result.timeMin, c.time);
result.count++;
}
} else if (cfg.subtasks) {
if (cfg.subtasks.length) {
for (const subtask of cfg.subtasks) {
result.memoryMax = Math.max(result.memoryMax, subtask.memory);
result.memoryMin = Math.min(result.memoryMin, subtask.memory);
result.timeMax = Math.max(result.timeMax, subtask.time);
result.timeMin = Math.min(result.timeMin, subtask.time);
}
} else if (cfg.time || cfg.memory) {
if (cfg.time) result.timeMax = result.timeMin = cfg.time as unknown as number;
if (cfg.memory) result.memoryMax = result.memoryMin = cfg.memory as unknown as number;
}
if (result.memoryMax < result.memoryMin) {
result.memoryMax = result.memoryMin = 256;
}
if (result.timeMax < result.timeMin) {
result.timeMax = result.timeMin = 1000;
}
return result;
}

global.Hydro.lib.testdataConfig = { parseConfig };
4 changes: 1 addition & 3 deletions packages/hydrooj/src/model/problem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,7 @@ export class ProblemModel {

static PROJECTION_PUBLIC: Field[] = [
...ProblemModel.PROJECTION_LIST,
'content', 'html', 'data', 'config', 'acMsg',
'additional_file',
'content', 'html', 'data', 'config', 'additional_file',
];

static extend(getter: Getter) {
Expand Down Expand Up @@ -258,7 +257,6 @@ ProblemModel.extend((docId, pid) => ({
additional_file: [],
hidden: true,
config: '',
acMsg: '',
difficulty: 0,
}));

Expand Down
2 changes: 1 addition & 1 deletion packages/migrate-vijos/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@hydrooj/migrate-vijos",
"version": "1.4.0",
"version": "1.4.1",
"main": "package.json",
"repository": "git@github.com:hydro-dev/Hydro.git",
"author": "undefined <i@undefined.moe>",
Expand Down
1 change: 0 additions & 1 deletion packages/migrate-vijos/script.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ const tasks = {
return res;
},
},
ac_msg: 'acMsg',
parent_doc_id: {
field: 'parentId',
processer: (parentId, doc) => {
Expand Down
2 changes: 1 addition & 1 deletion packages/ui-default/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@hydrooj/ui-default",
"version": "4.5.14",
"version": "4.5.15",
"author": "undefined <i@undefined.moe>",
"license": "AGPL-3.0",
"main": "hydro.js",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,10 +126,6 @@ <h1 class="section__title">{{ _('Information') }}</h1>
{% else %}
{{ _('(None)') }}
{% endif %}
{% if pdoc['acMsg'] and pdoc['psdoc']['status'] == STATUS.STATUS_ACCEPTED %}
<dt>{{ _('AC Message') }}</dt>
<dd>{{ pdoc['acMsg'] }}</dd>
{% endif %}
</dd>
{% endif %}
{% endif %}
Expand Down
22 changes: 21 additions & 1 deletion packages/ui-default/templates/problem_detail.html
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,27 @@
<div class="section">
<div class="problem-content-container"><div class="problem-content" data-marker-enabled>
<div class="section__header non-scratchpad--hide">
<h1>{{ pdoc.title }}</h1>
<h1 class="section__title">
{%- if rdoc -%}
<span class="icon record-status--icon {{ model.builtin.STATUS_CODES[rdoc['status']] }}"></span>
<span class="record-status--text {{ model.builtin.STATUS_CODES[rdoc['status']] }}">
{{ rdoc.score }}
</span>
{%- endif %}
{{ pdoc.title }}
</h1>
</div>
<div class="section__header scratchpad--hide">
{% if rdoc %}
<h1 class="section__title">
<span class="icon record-status--icon {{ model.builtin.STATUS_CODES[rdoc['status']] }}"></span>
<span class="record-status--text {{ model.builtin.STATUS_CODES[rdoc['status']] }}">
{{ rdoc.score }}
</span>
</h1>
{% endif %}
<span class="record-status--text">{{ _('Time Limit') }}: {{ pdoc.config.timeMax if pdoc.config.timeMax == pdoc.config.timeMin else pdoc.config.timeMin+'~'+pdoc.config.timeMax }}ms</span>
<span class="record-status--text">{{ _('Memory Limit') }}: {{ pdoc.config.memoryMax if pdoc.config.memoryMax == pdoc.config.memoryMin else pdoc.config.memoryMin+'~'+pdoc.config.memoryMax }}MiB</span>
</div>
<div class="section__body typo">
{% if tdoc %}
Expand Down
12 changes: 7 additions & 5 deletions packages/utils/lib/cases.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ export default async function readYamlCases(cfg: Record<string, any> = {}, check
} else if (cfg.cases) {
config.subtasks = [{
score: parseInt(cfg.score, 10) || Math.floor(100 / cfg.cases.length),
time_limit_ms: parseTimeMS(cfg.time || '1s'),
memory_limit_mb: parseMemoryMB(cfg.memory || '512m'),
time: parseTimeMS(cfg.time || '1s'),
memory: parseMemoryMB(cfg.memory || '256m'),
cases: [],
type: 'sum',
}];
Expand All @@ -63,11 +63,13 @@ export default async function readYamlCases(cfg: Record<string, any> = {}, check
score: parseInt(subtask.score, 10),
if: subtask.if || [],
cases,
time_limit_ms: parseTimeMS(subtask.time || cfg.time || '1s'),
memory_limit_mb: parseMemoryMB(subtask.memory || cfg.memory || '512m'),
time: parseTimeMS(subtask.time || cfg.time || '1s'),
memory: parseMemoryMB(subtask.memory || cfg.memory || '256m'),
});
}
}
if (cfg.time) config.time = parseTimeMS(cfg.time);
if (cfg.memory) config.memory = parseMemoryMB(cfg.memory);
if (config.type === 'submit_answer' && !cfg.outputs) throw new Error('outputs config not found');
return Object.assign(cfg, config);
}
Expand All @@ -83,7 +85,7 @@ export function convertIniConfig(ini: string) {
cases: [{ input: `input/${input.toLowerCase()}`, output: `output/${output.toLowerCase()}` }],
score: parseInt(score, 10),
time: `${time}s`,
memory: '512m',
memory: '256m',
};
if (!Number.isNaN(parseInt(memory, 10))) cur.memory = `${Math.floor(parseInt(memory, 10) / 1024)}m`;
res.subtasks.push(cur);
Expand Down
6 changes: 4 additions & 2 deletions packages/utils/lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,13 +161,15 @@ const TIME_UNITS = { '': 1000, m: 1, u: 0.001 };
const MEMORY_RE = /^([0-9]+(?:\.[0-9]*)?)([kmg])b?$/i;
const MEMORY_UNITS = { k: 1 / 1024, m: 1, g: 1024 };

export function parseTimeMS(str: string) {
export function parseTimeMS(str: string | number) {
if (typeof str === 'number') return str;
const match = TIME_RE.exec(str);
if (!match) throw new Error(`${str} error parsing time`);
return Math.floor(parseFloat(match[1]) * TIME_UNITS[match[2]]);
}

export function parseMemoryMB(str: string) {
export function parseMemoryMB(str: string | number) {
if (typeof str === 'number') return str;
const match = MEMORY_RE.exec(str);
if (!match) throw new Error(`${str} error parsing memory`);
return Math.ceil(parseFloat(match[1]) * MEMORY_UNITS[match[2]]);
Expand Down
2 changes: 1 addition & 1 deletion packages/utils/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@hydrooj/utils",
"version": "1.0.1",
"version": "1.0.2",
"description": "hydrooj utils",
"main": "package.json",
"repository": "https://github.com/hydro-dev/Hydro.git",
Expand Down

0 comments on commit 1c89596

Please sign in to comment.