diff --git a/lua/cp/runner/execute.lua b/lua/cp/runner/execute.lua index 6d7b712..09cf062 100644 --- a/lua/cp/runner/execute.lua +++ b/lua/cp/runner/execute.lua @@ -63,47 +63,43 @@ function M.compile(language_config, substitutions) return r end -local function parse_and_strip_time_v(output, memory_mb) - local lines = vim.split(output or '', '\n', { plain = true }) - - local timing_idx - for i = #lines, 1, -1 do - if lines[i]:match('^%s*Command being timed:') then - timing_idx = i +local function parse_and_strip_time_v(output) + local s = output or '' + local last_i, from = nil, 1 + while true do + local i = string.find(s, 'Command being timed:', from, true) + if not i then break end + last_i, from = i, i + 1 end - if not timing_idx then - return output or '', 0, false + if not last_i then + return s, 0 end - local start_idx = timing_idx - local k = timing_idx - 1 - while k >= 1 and lines[k]:match('^%s*Command ') do - start_idx = k + local k = last_i - 1 + while k >= 1 do + local ch = s:sub(k, k) + if ch ~= ' ' and ch ~= '\t' then + break + end k = k - 1 end - local peak_mb, mled = 0, false - for j = timing_idx, #lines do - local kb = lines[j]:match('Maximum resident set size %(kbytes%):%s*(%d+)') + local head = s:sub(1, k) + local tail = s:sub(last_i) + + local peak_kb = 0.0 + for line in tail:gmatch('[^\n]+') do + local kb = line:match('Maximum resident set size %(kbytes%):%s*(%d+)') if kb then - peak_mb = tonumber(kb) / 1024.0 - if memory_mb and memory_mb > 0 and peak_mb > memory_mb then - mled = true - end + peak_kb = tonumber(kb) end end - for j = #lines, start_idx, -1 do - table.remove(lines, j) - end - - while #lines > 0 and lines[#lines]:match('^%s*$') do - table.remove(lines, #lines) - end - - return table.concat(lines, '\n'), peak_mb, mled + local peak_mb = peak_kb / 1024.0 + head = head:gsub('\n+$', '') + return head, peak_mb end function M.run(cmd, stdin, timeout_ms, memory_mb) @@ -130,7 +126,7 @@ function M.run(cmd, stdin, timeout_ms, memory_mb) local code = r.code or 0 local raw = r.stdout or '' - local cleaned, peak_mb, mled = parse_and_strip_time_v(raw, memory_mb) + local cleaned, peak_mb = parse_and_strip_time_v(raw) local tled = code == 124 local signal = nil @@ -138,6 +134,16 @@ function M.run(cmd, stdin, timeout_ms, memory_mb) signal = constants.signal_codes[code] end + local lower = (cleaned or ''):lower() + local oom_hint = lower:find('std::bad_alloc', 1, true) + or lower:find('cannot allocate memory', 1, true) + or lower:find('out of memory', 1, true) + or lower:find('oom', 1, true) + or lower:find('enomem', 1, true) + local near_cap = peak_mb >= (0.90 * memory_mb) + + local mled = (peak_mb >= memory_mb) or near_cap or (oom_hint and not tled) + if tled then logger.log(('Execution timed out in %.1fms.'):format(dt)) elseif mled then diff --git a/lua/cp/runner/run.lua b/lua/cp/runner/run.lua index 411769d..b7af68b 100644 --- a/lua/cp/runner/run.lua +++ b/lua/cp/runner/run.lua @@ -122,9 +122,8 @@ local function run_single_test_case(contest_config, cp_config, test_case) local cmd = build_command(language_config, substitutions) local stdin_content = (test_case.input or '') .. '\n' - local timeout_ms = (run_panel_state.constraints and run_panel_state.constraints.timeout_ms) - or 2000 - local memory_mb = run_panel_state.constraints and run_panel_state.constraints.memory_mb or nil + local timeout_ms = (run_panel_state.constraints and run_panel_state.constraints.timeout_ms) or 0 + local memory_mb = run_panel_state.constraints and run_panel_state.constraints.memory_mb or 0 local r = exec.run(cmd, stdin_content, timeout_ms, memory_mb) @@ -184,7 +183,7 @@ local function run_single_test_case(contest_config, cp_config, test_case) signal = signal, tled = r.tled or false, mled = r.mled or false, - rss_mb = r.peak_mb, + rss_mb = r.peak_mb or 0, } end @@ -284,6 +283,7 @@ function M.handle_compilation_failure(output) tc.signal = '' tc.tled = false tc.mled = false + tc.rss_mb = 0 end end diff --git a/lua/cp/runner/run_render.lua b/lua/cp/runner/run_render.lua index 2c05c15..3ac6d5f 100644 --- a/lua/cp/runner/run_render.lua +++ b/lua/cp/runner/run_render.lua @@ -40,7 +40,7 @@ function M.get_status_info(ran_test_case) return { text = 'WA', highlight_group = 'CpTestWA' } end - return { text = '...', highlight_group = 'CpTestPending' } + return { text = 'N/A', highlight_group = 'CpTestPending' } end local function format_exit_code(code)