dsh-eval-guard 0.7.1 → 0.7.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ISSUES.md +235 -0
- package/README.md +46 -18
- package/assets/neural-cifar/workspace.zip +0 -0
- package/assets/neural-cpp/workspace.zip +0 -0
- package/assets/neural-fp32/workspace.zip +0 -0
- package/assets/neural-pendulum/SPEC.md +41 -38
- package/assets/neural-pendulum/TASK.md +146 -32
- package/assets/neural-pendulum/sim.cpp +4 -2
- package/assets/neural-pendulum/sim_eval +0 -0
- package/assets/neural-pendulum/workspace.zip +0 -0
- package/eval/README.md +19 -9
- package/eval/__pycache__/bomberman.cpython-310.pyc +0 -0
- package/eval/__pycache__/commit0.cpython-310.pyc +0 -0
- package/eval/__pycache__/common.cpython-310.pyc +0 -0
- package/eval/__pycache__/ctf.cpython-310.pyc +0 -0
- package/eval/__pycache__/featurebench.cpython-310.pyc +0 -0
- package/eval/__pycache__/land.cpython-310.pyc +0 -0
- package/eval/__pycache__/neural-cifar.cpython-310.pyc +0 -0
- package/eval/__pycache__/neural-cpp.cpython-310.pyc +0 -0
- package/eval/__pycache__/neural-fp32.cpython-310.pyc +0 -0
- package/eval/__pycache__/neural-pendulum.cpython-310.pyc +0 -0
- package/eval/__pycache__/swe-bench-pro.cpython-310.pyc +0 -0
- package/eval/__pycache__/tank.cpython-310.pyc +0 -0
- package/eval/__pycache__/warehouse.cpython-310.pyc +0 -0
- package/eval/bomberman.py +5 -3
- package/eval/commit0.py +10 -3
- package/eval/common.py +169 -5
- package/eval/ctf.py +4 -2
- package/eval/featurebench.py +12 -8
- package/eval/land.py +4 -2
- package/eval/legacy/__pycache__/bomberman.cpython-310.pyc +0 -0
- package/eval/legacy/__pycache__/commit0.cpython-310.pyc +0 -0
- package/eval/legacy/__pycache__/ctf.cpython-310.pyc +0 -0
- package/eval/legacy/__pycache__/featurebench.cpython-310.pyc +0 -0
- package/eval/legacy/__pycache__/land.cpython-310.pyc +0 -0
- package/eval/legacy/__pycache__/swe_bench_pro.cpython-310.pyc +0 -0
- package/eval/legacy/__pycache__/tank.cpython-310.pyc +0 -0
- package/eval/legacy/__pycache__/warehouse.cpython-310.pyc +0 -0
- package/eval/legacy/bomberman.py +5 -2
- package/eval/legacy/ctf.py +5 -2
- package/eval/legacy/featurebench.py +55 -15
- package/eval/legacy/land.py +6 -3
- package/eval/legacy/swe_bench_pro.py +57 -16
- package/eval/legacy/tank.py +2 -2
- package/eval/legacy/warehouse.py +4 -4
- package/eval/neural-cpp.py +9 -6
- package/eval/neural-fp32.py +17 -5
- package/eval/swe-bench-pro.py +11 -7
- package/eval/tank.py +11 -2
- package/eval/warehouse.py +17 -1
- package/lib/client/index.js +73 -46
- package/lib/client/index.js.map +1 -1
- package/lib/index.js +894 -301
- package/native/dsh-eval-supervisor +0 -0
- package/native/supervisor.c +190 -26
- package/neural-cifar-eval/README.md +5 -0
- package/neural-cifar-eval/__pycache__/cifar_cache.cpython-310.pyc +0 -0
- package/neural-cifar-eval/__pycache__/common.cpython-310.pyc +0 -0
- package/neural-cifar-eval/__pycache__/fetch_cifar.cpython-310.pyc +0 -0
- package/neural-cifar-eval/__pycache__/ops_eval.cpython-310.pyc +0 -0
- package/neural-cifar-eval/__pycache__/run_eval.cpython-310.pyc +0 -0
- package/neural-cifar-eval/common.py +13 -0
- package/neural-cifar-eval/ops_eval.py +17 -5
- package/neural-cifar-eval/run_eval.py +42 -32
- package/neural-pendulum-eval/README.md +62 -0
- package/neural-pendulum-eval/__pycache__/ops_eval.cpython-310.pyc +0 -0
- package/neural-pendulum-eval/__pycache__/run_eval.cpython-310.pyc +0 -0
- package/neural-pendulum-eval/ops_eval.py +603 -0
- package/neural-pendulum-eval/run_eval.py +218 -137
- package/neural-pendulum-eval/sim_eval +0 -0
- package/package.json +7 -11
- package/assets/neural-pendulum/hidden/test_infra.cpp +0 -631
- package/assets/neural-pendulum/include/nn/nn.hpp +0 -88
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/eval/legacy/bomberman.py
CHANGED
|
@@ -107,13 +107,16 @@ def main() -> int:
|
|
|
107
107
|
cmd = [sys.executable, "-X", "utf8", str(task / "tournament" / "run.py"), "--output", str(run_dir),
|
|
108
108
|
"--bots", *bots, "--sizes", *sizes, "--seeds", str(seeds), "--workers", str(max(1, args.workers))]
|
|
109
109
|
print("tier=%s sizes=%s seeds=%d bots=%d" % (args.tier, sizes, seeds, len(bots)), flush=True)
|
|
110
|
-
completed = subprocess.run(cmd, capture_output=True, text=True, encoding="utf-8", errors="replace")
|
|
110
|
+
completed = subprocess.run(cmd, capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=3600)
|
|
111
111
|
if completed.returncode != 0:
|
|
112
112
|
print(completed.stdout[-4000:], completed.stderr[-4000:], file=sys.stderr)
|
|
113
113
|
return 2
|
|
114
114
|
ratings_doc = load_json(run_dir / "bt.json") or {}
|
|
115
|
+
if ratings_doc.get("unavailable"):
|
|
116
|
+
print("bomberman rating unavailable: " + str(ratings_doc.get("unavailable")), file=sys.stderr)
|
|
117
|
+
return 2
|
|
115
118
|
ratings = ratings_doc.get("ratings", {})
|
|
116
|
-
prices = load_json(ROOT / "prices.json") or {}
|
|
119
|
+
prices = load_json(ROOT / "bomberman-prices.json") or load_json(ROOT / "prices.json") or {}
|
|
117
120
|
|
|
118
121
|
rows = []
|
|
119
122
|
for name, program in programs.items():
|
package/eval/legacy/ctf.py
CHANGED
|
@@ -123,14 +123,17 @@ def main() -> int:
|
|
|
123
123
|
print("tier=%s sizes=%s maps=%d players=%d" % (args.tier, sizes, maps_per_size, len(players)), flush=True)
|
|
124
124
|
for step in steps:
|
|
125
125
|
completed = subprocess.run([sys.executable, "-X", "utf8", tournament, *step], capture_output=True, text=True,
|
|
126
|
-
encoding="utf-8", errors="replace")
|
|
126
|
+
encoding="utf-8", errors="replace", timeout=1800)
|
|
127
127
|
if completed.returncode != 0:
|
|
128
128
|
print(completed.stdout[-4000:], completed.stderr[-4000:], file=sys.stderr)
|
|
129
129
|
return 2
|
|
130
130
|
scores = load_json(games_dir / "成绩.json") or {}
|
|
131
|
+
if scores.get("unavailable"):
|
|
132
|
+
print("ctf rating unavailable: " + str(scores.get("unavailable")), file=sys.stderr)
|
|
133
|
+
return 2
|
|
131
134
|
raw_ratings = scores.get("ratings", {})
|
|
132
135
|
ratings = {name: (value[0] if isinstance(value, list) and value else value) for name, value in raw_ratings.items()}
|
|
133
|
-
prices = load_json(ROOT / "prices.json") or {}
|
|
136
|
+
prices = load_json(ROOT / "ctf-prices.json") or load_json(ROOT / "prices.json") or {}
|
|
134
137
|
|
|
135
138
|
rows = []
|
|
136
139
|
for name, program in players.items():
|
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
Submission layout:
|
|
5
5
|
submissions/<name>/workspace/ (copy of the agent workspace, including .venv)
|
|
6
6
|
|
|
7
|
-
The hidden feature test file is copied from the plugin asset; scoring
|
|
8
|
-
|
|
7
|
+
The hidden feature test file is copied from the plugin asset; scoring checks the
|
|
8
|
+
fail-to-pass file and every pass-to-pass file explicitly (a skipped or removed
|
|
9
|
+
test does not count as resolved).
|
|
9
10
|
"""
|
|
10
11
|
from __future__ import annotations
|
|
11
12
|
|
|
@@ -23,6 +24,7 @@ ASSET = ROOT.parents[1] / "assets" / "featurebench"
|
|
|
23
24
|
PASSED = re.compile(r"(\d+) passed")
|
|
24
25
|
FAILED = re.compile(r"(\d+) failed")
|
|
25
26
|
ERRORS = re.compile(r"(\d+) error")
|
|
27
|
+
RESULT = re.compile(r"^(PASSED|FAILED|ERROR|SKIPPED|XFAIL|XPASS) (\S+)", re.MULTILINE)
|
|
26
28
|
|
|
27
29
|
|
|
28
30
|
def load_json(path: Path):
|
|
@@ -39,18 +41,29 @@ def find_workspace(directory: Path) -> Path | None:
|
|
|
39
41
|
return None
|
|
40
42
|
|
|
41
43
|
|
|
42
|
-
def install_hidden_test(workspace: Path) ->
|
|
44
|
+
def install_hidden_test(workspace: Path) -> str:
|
|
43
45
|
source = ASSET / "hidden" / "test_regression.py"
|
|
44
|
-
if source.is_file():
|
|
45
|
-
|
|
46
|
+
if not source.is_file():
|
|
47
|
+
return "hidden regression test is missing"
|
|
48
|
+
shutil.copy2(source, workspace / "tests" / "test_regression.py")
|
|
49
|
+
return ""
|
|
46
50
|
|
|
47
51
|
|
|
48
|
-
def
|
|
52
|
+
def matches(node: str, selectors: list[str]) -> bool:
|
|
53
|
+
for selector in selectors:
|
|
54
|
+
if node == selector or node.startswith(selector + "::") or node.startswith(selector + "/"):
|
|
55
|
+
return True
|
|
56
|
+
return False
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def run_tests(workspace: Path, instance: dict) -> tuple[int, int, int, str, dict]:
|
|
49
60
|
venv = workspace / ".venv" / "bin" / "python"
|
|
50
61
|
python = str(venv) if venv.is_file() else "python3"
|
|
51
|
-
|
|
62
|
+
fail_to_pass = list(instance.get("FAIL_TO_PASS", []))
|
|
63
|
+
pass_to_pass = list(instance.get("PASS_TO_PASS", []))
|
|
64
|
+
tests = fail_to_pass + pass_to_pass
|
|
52
65
|
env = {k: v for k, v in __import__("os").environ.items() if k not in {"PYTHONPATH", "PYTHONHOME"}}
|
|
53
|
-
completed = subprocess.run([python, "-m", "pytest", *tests, "-q", "--tb=no"], cwd=workspace,
|
|
66
|
+
completed = subprocess.run([python, "-m", "pytest", *tests, "-q", "--tb=no", "-rA"], cwd=workspace,
|
|
54
67
|
capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=1800, env=env)
|
|
55
68
|
output = (completed.stdout or "") + "\n" + (completed.stderr or "")
|
|
56
69
|
passed = int(PASSED.search(output).group(1)) if PASSED.search(output) else 0
|
|
@@ -58,7 +71,31 @@ def run_tests(workspace: Path, instance: dict) -> tuple[int, int, int, str]:
|
|
|
58
71
|
errors = int(ERRORS.search(output).group(1)) if ERRORS.search(output) else 0
|
|
59
72
|
if completed.returncode != 0 and passed == 0 and failed == 0 and errors == 0:
|
|
60
73
|
errors = 1
|
|
61
|
-
|
|
74
|
+
outcomes = {node: status for status, node in RESULT.findall(output)}
|
|
75
|
+
f2p_total = f2p_passed = 0
|
|
76
|
+
p2p_total = p2p_passed = 0
|
|
77
|
+
for node, status in outcomes.items():
|
|
78
|
+
if matches(node, fail_to_pass):
|
|
79
|
+
f2p_total += 1
|
|
80
|
+
f2p_passed += 1 if status == "PASSED" else 0
|
|
81
|
+
elif matches(node, pass_to_pass):
|
|
82
|
+
p2p_total += 1
|
|
83
|
+
p2p_passed += 1 if status == "PASSED" else 0
|
|
84
|
+
resolved = (
|
|
85
|
+
len(fail_to_pass) > 0
|
|
86
|
+
and f2p_total > 0
|
|
87
|
+
and f2p_passed == f2p_total
|
|
88
|
+
and p2p_total > 0
|
|
89
|
+
and p2p_passed == p2p_total
|
|
90
|
+
and completed.returncode == 0
|
|
91
|
+
)
|
|
92
|
+
return passed, failed, errors, output[-3000:], {
|
|
93
|
+
"resolved": resolved,
|
|
94
|
+
"f2p_total": f2p_total,
|
|
95
|
+
"f2p_passed": f2p_passed,
|
|
96
|
+
"p2p_total": p2p_total,
|
|
97
|
+
"p2p_passed": p2p_passed,
|
|
98
|
+
}
|
|
62
99
|
|
|
63
100
|
|
|
64
101
|
def main() -> int:
|
|
@@ -78,20 +115,23 @@ def main() -> int:
|
|
|
78
115
|
for directory in directories:
|
|
79
116
|
workspace = find_workspace(directory)
|
|
80
117
|
if workspace is None:
|
|
81
|
-
rows.append({"name": directory.name, "status": "missing-workspace", "score": 0.0, "passed": 0, "failed": 0, "errors": 0})
|
|
118
|
+
rows.append({"name": directory.name, "status": "missing-workspace", "score": 0.0, "passed": 0, "failed": 0, "errors": 0, "resolved": False})
|
|
82
119
|
continue
|
|
83
120
|
try:
|
|
84
|
-
install_hidden_test(workspace)
|
|
85
|
-
|
|
121
|
+
hidden_error = install_hidden_test(workspace)
|
|
122
|
+
if hidden_error:
|
|
123
|
+
rows.append({"name": directory.name, "status": "hidden-test-failed", "score": 0.0, "passed": 0, "failed": 0, "errors": 1, "resolved": False, "detail": hidden_error})
|
|
124
|
+
continue
|
|
125
|
+
passed, failed, errors, detail, extra = run_tests(workspace, instance)
|
|
86
126
|
total = passed + failed + errors
|
|
87
127
|
score = 100.0 * passed / total if total else 0.0
|
|
88
|
-
rows.append({"name": directory.name, "status": "ok", "score": round(score, 2), "passed": passed, "failed": failed, "errors": errors, "detail": detail})
|
|
128
|
+
rows.append({"name": directory.name, "status": "ok", "score": round(score, 2), "passed": passed, "failed": failed, "errors": errors, "detail": detail, **extra})
|
|
89
129
|
except Exception as error:
|
|
90
|
-
rows.append({"name": directory.name, "status": "error", "score": 0.0, "passed": 0, "failed": 0, "errors": 1, "detail": str(error)})
|
|
130
|
+
rows.append({"name": directory.name, "status": "error", "score": 0.0, "passed": 0, "failed": 0, "errors": 1, "resolved": False, "detail": str(error)})
|
|
91
131
|
rows.sort(key=lambda row: (-row["score"], row["name"]))
|
|
92
132
|
payload = {"generatedAt": time.strftime("%Y-%m-%dT%H:%M:%S%z"), "benchmark": "featurebench", "instance": instance.get("instance_id"), "results": rows}
|
|
93
133
|
(out / "summary.json").write_text(json.dumps(payload, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
|
|
94
|
-
lines = ["# FeatureBench · 单 feature 排行", "", "- 实例:%s" % instance.get("instance_id", ""), "- 指标:隐藏
|
|
134
|
+
lines = ["# FeatureBench · 单 feature 排行", "", "- 实例:%s" % instance.get("instance_id", ""), "- 指标:隐藏 feature 测试与全部回归文件通过才 resolved", "", "| 名次 | 名称 | 得分 | 通过 | 失败 | 错误 | 状态 |", "|---:|---|---:|---:|---:|---:|---|"]
|
|
95
135
|
for rank, row in enumerate(rows, 1):
|
|
96
136
|
lines.append("| %d | %s | %.1f | %d | %d | %d | %s |" % (rank, row["name"], row["score"], row["passed"], row["failed"], row["errors"], row["status"]))
|
|
97
137
|
(out / "summary.md").write_text("\n".join(lines) + "\n", encoding="utf-8")
|
package/eval/legacy/land.py
CHANGED
|
@@ -112,20 +112,23 @@ def main() -> int:
|
|
|
112
112
|
if melee == 0:
|
|
113
113
|
cmd += ["--only", "duel"]
|
|
114
114
|
print("tier=%s maps=%d melee=%d entries=%d" % (args.tier, maps, melee, len(list(entries.iterdir()))), flush=True)
|
|
115
|
-
completed = subprocess.run(cmd, capture_output=True, text=True, encoding="utf-8", errors="replace")
|
|
115
|
+
completed = subprocess.run(cmd, capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=1800)
|
|
116
116
|
if completed.returncode != 0:
|
|
117
117
|
print(completed.stdout[-4000:], completed.stderr[-4000:], file=sys.stderr)
|
|
118
118
|
return 2
|
|
119
119
|
ratings_prefix = out / "ratings"
|
|
120
120
|
rate = subprocess.run([sys.executable, "-X", "utf8", str(task / "tournament" / "rate.py"), str(results_jsonl),
|
|
121
121
|
"--entries", str(entries), "--out", str(ratings_prefix)], capture_output=True, text=True,
|
|
122
|
-
encoding="utf-8", errors="replace")
|
|
122
|
+
encoding="utf-8", errors="replace", timeout=1800)
|
|
123
123
|
if rate.returncode != 0:
|
|
124
124
|
print(rate.stdout[-4000:], rate.stderr[-4000:], file=sys.stderr)
|
|
125
125
|
return 2
|
|
126
126
|
ratings = load_json(Path(str(ratings_prefix) + ".json")) or {}
|
|
127
|
+
if ratings.get("unavailable"):
|
|
128
|
+
print("land rating unavailable: " + str(ratings.get("unavailable")), file=sys.stderr)
|
|
129
|
+
return 2
|
|
127
130
|
models = ratings.get("models", {})
|
|
128
|
-
prices = load_json(ROOT / "prices.json") or {}
|
|
131
|
+
prices = load_json(ROOT / "land-prices.json") or load_json(ROOT / "prices.json") or {}
|
|
129
132
|
|
|
130
133
|
rows = []
|
|
131
134
|
all_names = list(names) + [name for name in models if name not in names]
|
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
Submission layout:
|
|
5
5
|
submissions/<name>/workspace/ (copy of the agent workspace, including .venv)
|
|
6
6
|
|
|
7
|
-
The hidden test patch is applied from the plugin asset; scoring
|
|
8
|
-
instance's fail-to-pass and pass-to-pass
|
|
7
|
+
The hidden test patch is applied from the plugin asset; scoring checks the
|
|
8
|
+
instance's fail-to-pass and pass-to-pass node ids explicitly (a skipped or
|
|
9
|
+
renamed fail-to-pass test does not count as resolved).
|
|
9
10
|
"""
|
|
10
11
|
from __future__ import annotations
|
|
11
12
|
|
|
@@ -22,6 +23,7 @@ ASSET = ROOT.parents[1] / "assets" / "swe-bench-pro"
|
|
|
22
23
|
PASSED = re.compile(r"(\d+) passed")
|
|
23
24
|
FAILED = re.compile(r"(\d+) failed")
|
|
24
25
|
ERRORS = re.compile(r"(\d+) error")
|
|
26
|
+
RESULT = re.compile(r"^(PASSED|FAILED|ERROR|SKIPPED|XFAIL|XPASS) (\S+)", re.MULTILINE)
|
|
25
27
|
|
|
26
28
|
|
|
27
29
|
def load_json(path: Path):
|
|
@@ -48,22 +50,34 @@ def find_workspace(directory: Path) -> Path | None:
|
|
|
48
50
|
return None
|
|
49
51
|
|
|
50
52
|
|
|
51
|
-
def apply_hidden_tests(workspace: Path) ->
|
|
53
|
+
def apply_hidden_tests(workspace: Path) -> str:
|
|
52
54
|
patch = ASSET / "hidden" / "test.patch"
|
|
53
55
|
if not patch.is_file():
|
|
54
|
-
return
|
|
55
|
-
subprocess.run(["patch", "-p1", "--forward", "-i", str(patch)], cwd=workspace,
|
|
56
|
-
|
|
56
|
+
return "hidden test patch is missing"
|
|
57
|
+
completed = subprocess.run(["patch", "-p1", "--forward", "-i", str(patch)], cwd=workspace,
|
|
58
|
+
capture_output=True, text=True, encoding="utf-8", errors="replace")
|
|
59
|
+
if completed.returncode != 0:
|
|
60
|
+
return "hidden test patch failed to apply: " + (completed.stdout + completed.stderr)[-2000:]
|
|
61
|
+
return ""
|
|
57
62
|
|
|
58
63
|
|
|
59
|
-
def
|
|
64
|
+
def matches(node: str, selectors: list[str]) -> bool:
|
|
65
|
+
for selector in selectors:
|
|
66
|
+
if node == selector or node.startswith(selector + "::") or node.startswith(selector + "/"):
|
|
67
|
+
return True
|
|
68
|
+
return False
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def run_tests(workspace: Path, instance: dict) -> tuple[int, int, int, str, dict]:
|
|
60
72
|
venv = workspace / ".venv" / "bin" / "python"
|
|
61
73
|
python = str(venv) if venv.is_file() else "python3"
|
|
62
|
-
|
|
74
|
+
fail_to_pass = as_list(instance.get("fail_to_pass"))
|
|
75
|
+
pass_to_pass = as_list(instance.get("pass_to_pass"))
|
|
76
|
+
tests = fail_to_pass + pass_to_pass
|
|
63
77
|
if not tests:
|
|
64
78
|
tests = as_list(instance.get("selected_test_files_to_run"))
|
|
65
79
|
env = {k: v for k, v in __import__("os").environ.items() if k not in {"PYTHONPATH", "PYTHONHOME"}}
|
|
66
|
-
completed = subprocess.run([python, "-m", "pytest", *tests, "-q", "--tb=no"], cwd=workspace,
|
|
80
|
+
completed = subprocess.run([python, "-m", "pytest", *tests, "-q", "--tb=no", "-rA"], cwd=workspace,
|
|
67
81
|
capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=1800, env=env)
|
|
68
82
|
output = (completed.stdout or "") + "\n" + (completed.stderr or "")
|
|
69
83
|
passed = int(PASSED.search(output).group(1)) if PASSED.search(output) else 0
|
|
@@ -71,7 +85,31 @@ def run_tests(workspace: Path, instance: dict) -> tuple[int, int, int, str]:
|
|
|
71
85
|
errors = int(ERRORS.search(output).group(1)) if ERRORS.search(output) else 0
|
|
72
86
|
if completed.returncode != 0 and passed == 0 and failed == 0 and errors == 0:
|
|
73
87
|
errors = 1
|
|
74
|
-
|
|
88
|
+
outcomes = {node: status for status, node in RESULT.findall(output)}
|
|
89
|
+
f2p_total = f2p_passed = 0
|
|
90
|
+
p2p_total = p2p_passed = 0
|
|
91
|
+
for node, status in outcomes.items():
|
|
92
|
+
if matches(node, fail_to_pass):
|
|
93
|
+
f2p_total += 1
|
|
94
|
+
f2p_passed += 1 if status == "PASSED" else 0
|
|
95
|
+
elif matches(node, pass_to_pass):
|
|
96
|
+
p2p_total += 1
|
|
97
|
+
p2p_passed += 1 if status == "PASSED" else 0
|
|
98
|
+
resolved = (
|
|
99
|
+
len(fail_to_pass) > 0
|
|
100
|
+
and f2p_total > 0
|
|
101
|
+
and f2p_passed == f2p_total
|
|
102
|
+
and p2p_total > 0
|
|
103
|
+
and p2p_passed == p2p_total
|
|
104
|
+
and completed.returncode == 0
|
|
105
|
+
)
|
|
106
|
+
return passed, failed, errors, output[-3000:], {
|
|
107
|
+
"resolved": resolved,
|
|
108
|
+
"f2p_total": f2p_total,
|
|
109
|
+
"f2p_passed": f2p_passed,
|
|
110
|
+
"p2p_total": p2p_total,
|
|
111
|
+
"p2p_passed": p2p_passed,
|
|
112
|
+
}
|
|
75
113
|
|
|
76
114
|
|
|
77
115
|
def main() -> int:
|
|
@@ -91,20 +129,23 @@ def main() -> int:
|
|
|
91
129
|
for directory in directories:
|
|
92
130
|
workspace = find_workspace(directory)
|
|
93
131
|
if workspace is None:
|
|
94
|
-
rows.append({"name": directory.name, "status": "missing-workspace", "score": 0.0, "passed": 0, "failed": 0, "errors": 0})
|
|
132
|
+
rows.append({"name": directory.name, "status": "missing-workspace", "score": 0.0, "passed": 0, "failed": 0, "errors": 0, "resolved": False})
|
|
95
133
|
continue
|
|
96
134
|
try:
|
|
97
|
-
apply_hidden_tests(workspace)
|
|
98
|
-
|
|
135
|
+
patch_error = apply_hidden_tests(workspace)
|
|
136
|
+
if patch_error:
|
|
137
|
+
rows.append({"name": directory.name, "status": "hidden-test-failed", "score": 0.0, "passed": 0, "failed": 0, "errors": 1, "resolved": False, "detail": patch_error})
|
|
138
|
+
continue
|
|
139
|
+
passed, failed, errors, detail, extra = run_tests(workspace, instance)
|
|
99
140
|
total = passed + failed + errors
|
|
100
141
|
score = 100.0 * passed / total if total else 0.0
|
|
101
|
-
rows.append({"name": directory.name, "status": "ok", "score": round(score, 2), "passed": passed, "failed": failed, "errors": errors, "detail": detail})
|
|
142
|
+
rows.append({"name": directory.name, "status": "ok", "score": round(score, 2), "passed": passed, "failed": failed, "errors": errors, "detail": detail, **extra})
|
|
102
143
|
except Exception as error:
|
|
103
|
-
rows.append({"name": directory.name, "status": "error", "score": 0.0, "passed": 0, "failed": 0, "errors": 1, "detail": str(error)})
|
|
144
|
+
rows.append({"name": directory.name, "status": "error", "score": 0.0, "passed": 0, "failed": 0, "errors": 1, "resolved": False, "detail": str(error)})
|
|
104
145
|
rows.sort(key=lambda row: (-row["score"], row["name"]))
|
|
105
146
|
payload = {"generatedAt": time.strftime("%Y-%m-%dT%H:%M:%S%z"), "benchmark": "swe-bench-pro", "instance": instance.get("instance_id"), "results": rows}
|
|
106
147
|
(out / "summary.json").write_text(json.dumps(payload, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
|
|
107
|
-
lines = ["# SWE-Bench Pro · 单任务排行", "", "- 实例:%s" % instance.get("instance_id", ""), "- 指标:隐藏 fail-to-pass + pass-to-pass
|
|
148
|
+
lines = ["# SWE-Bench Pro · 单任务排行", "", "- 实例:%s" % instance.get("instance_id", ""), "- 指标:隐藏 fail-to-pass + pass-to-pass 节点全部通过才 resolved", "", "| 名次 | 名称 | 得分 | 通过 | 失败 | 错误 | 状态 |", "|---:|---|---:|---:|---:|---:|---|"]
|
|
108
149
|
for rank, row in enumerate(rows, 1):
|
|
109
150
|
lines.append("| %d | %s | %.1f | %d | %d | %d | %s |" % (rank, row["name"], row["score"], row["passed"], row["failed"], row["errors"], row["status"]))
|
|
110
151
|
(out / "summary.md").write_text("\n".join(lines) + "\n", encoding="utf-8")
|
package/eval/legacy/tank.py
CHANGED
|
@@ -258,8 +258,8 @@ def main() -> int:
|
|
|
258
258
|
if not directories:
|
|
259
259
|
print("no submissions found under " + str(submissions_root), file=sys.stderr)
|
|
260
260
|
return 2
|
|
261
|
-
prices_path = ROOT / "prices.json"
|
|
262
|
-
prices = load_json(prices_path) or {}
|
|
261
|
+
prices_path = ROOT / "tank-prices.json"
|
|
262
|
+
prices = load_json(prices_path) or load_json(ROOT / "prices.json") or {}
|
|
263
263
|
|
|
264
264
|
participants: list[Participant] = [Participant("baseline", workspace / "baseline.cpp", "baseline")]
|
|
265
265
|
participants += [load_submission(directory) for directory in directories]
|
package/eval/legacy/warehouse.py
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"""Independent evaluation for dsh-eval-guard warehouse submissions.
|
|
3
3
|
|
|
4
4
|
Reads submissions/<name>/{src/*.cpp,run/,cost.json}, compiles with the fixed
|
|
5
|
-
g++ flags, compares every public workload byte-for-byte
|
|
6
|
-
output, measures CPU time against the baseline, and writes a
|
|
7
|
-
cost/violation/static-scan reports.
|
|
5
|
+
g++ flags, compares every public workload byte-for-byte (CRLF normalized) with
|
|
6
|
+
the expected output, measures CPU time against the baseline, and writes a
|
|
7
|
+
leaderboard plus cost/violation/static-scan reports.
|
|
8
8
|
|
|
9
9
|
The evaluator is independent of the DSH plugin: copy the run/ directory from
|
|
10
10
|
$DSH_HOME/eval-guard/runs/<run-id>/ next to src/.
|
|
@@ -220,7 +220,7 @@ def main() -> int:
|
|
|
220
220
|
out_dir = Path(args.out).resolve() if args.out else ROOT / "results" / time.strftime("%Y%m%d-%H%M%S")
|
|
221
221
|
out_dir.mkdir(parents=True, exist_ok=True)
|
|
222
222
|
build_dir = out_dir / "build"
|
|
223
|
-
prices = load_json(ROOT / "prices.json") or {}
|
|
223
|
+
prices = load_json(ROOT / "warehouse-prices.json") or load_json(ROOT / "prices.json") or {}
|
|
224
224
|
|
|
225
225
|
print("tier=%s workloads=%s repeats=%d" % (args.tier, ",".join(names), repeats))
|
|
226
226
|
baseline = Participant("baseline", baseline_src, "baseline")
|
package/eval/neural-cpp.py
CHANGED
|
@@ -15,15 +15,12 @@ import sys
|
|
|
15
15
|
import tempfile
|
|
16
16
|
from pathlib import Path
|
|
17
17
|
|
|
18
|
-
from common import EVAL_ROOT, clean_copy, emit, fail, parse_workspace
|
|
18
|
+
from common import EVAL_ROOT, child_env, clean_copy, emit, fail, parse_workspace
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
def run(cmd: list[str], cwd: Path, timeout: int = 600) -> subprocess.CompletedProcess[str]:
|
|
22
|
-
env = dict(os.environ)
|
|
23
|
-
env.pop('PYTHONPATH', None)
|
|
24
|
-
env.pop('PYTHONHOME', None)
|
|
25
22
|
return subprocess.run(cmd, cwd=str(cwd), capture_output=True, text=True,
|
|
26
|
-
encoding='utf-8', errors='replace', env=
|
|
23
|
+
encoding='utf-8', errors='replace', env=child_env(), timeout=timeout)
|
|
27
24
|
|
|
28
25
|
|
|
29
26
|
def main() -> int:
|
|
@@ -31,6 +28,9 @@ def main() -> int:
|
|
|
31
28
|
hidden = EVAL_ROOT.parent / 'assets' / 'neural-cpp' / 'hidden' / 'test_neural.cpp'
|
|
32
29
|
if not hidden.is_file():
|
|
33
30
|
return fail({'task': 'neural-cpp', 'ok': False, 'error': 'hidden test missing'})
|
|
31
|
+
# Snapshot the hidden test BEFORE the candidate build runs: an agent-authored
|
|
32
|
+
# CMakeLists can otherwise overwrite the asset and substitute a passing test.
|
|
33
|
+
hidden_source = hidden.read_bytes()
|
|
34
34
|
|
|
35
35
|
with tempfile.TemporaryDirectory(prefix='neural-cpp-eval-') as td:
|
|
36
36
|
root = Path(td)
|
|
@@ -67,9 +67,12 @@ def main() -> int:
|
|
|
67
67
|
if not lib.is_file():
|
|
68
68
|
return fail({'task': 'neural-cpp', 'ok': False, 'error': 'build/libnn.a missing'})
|
|
69
69
|
|
|
70
|
+
# Compile the in-memory snapshot, not the on-disk asset the build could edit.
|
|
71
|
+
hidden_copy = root / 'test_neural.cpp'
|
|
72
|
+
hidden_copy.write_bytes(hidden_source)
|
|
70
73
|
exe = root / 'test_neural'
|
|
71
74
|
cc = run([compiler, '-std=c++17', '-O3', '-pthread',
|
|
72
|
-
'-I', str(source / 'include'), str(
|
|
75
|
+
'-I', str(source / 'include'), str(hidden_copy), str(lib),
|
|
73
76
|
'-lm', '-o', str(exe)], root, 300)
|
|
74
77
|
if cc.returncode != 0:
|
|
75
78
|
return fail({'task': 'neural-cpp', 'ok': False, 'error': 'hidden test compile failed',
|
package/eval/neural-fp32.py
CHANGED
|
@@ -20,7 +20,7 @@ import numpy as np
|
|
|
20
20
|
import torch
|
|
21
21
|
import torch.nn.functional as F
|
|
22
22
|
|
|
23
|
-
from common import EVAL_ROOT, clean_copy, emit, fail, parse_workspace
|
|
23
|
+
from common import EVAL_ROOT, child_env, clean_copy, emit, fail, parse_workspace
|
|
24
24
|
|
|
25
25
|
torch.set_num_threads(1)
|
|
26
26
|
torch.set_float32_matmul_precision('highest')
|
|
@@ -29,6 +29,9 @@ torch.backends.mkldnn.deterministic = True
|
|
|
29
29
|
torch.manual_seed(1234)
|
|
30
30
|
|
|
31
31
|
SEEDS = (11, 22, 33)
|
|
32
|
+
# A single CLI invocation budget and a total budget for the whole oracle run.
|
|
33
|
+
INVOCATION_TIMEOUT_SECONDS = 60
|
|
34
|
+
OPS_DEADLINE_SECONDS = 1800
|
|
32
35
|
|
|
33
36
|
|
|
34
37
|
def write_tensor(path: Path, t: torch.Tensor) -> None:
|
|
@@ -65,11 +68,12 @@ def build_candidate(workspace: Path, root: Path) -> Path:
|
|
|
65
68
|
shutil.rmtree(build, ignore_errors=True)
|
|
66
69
|
build.mkdir(parents=True)
|
|
67
70
|
cfg = subprocess.run(['cmake', '-S', '.', '-B', 'build', '-DCMAKE_BUILD_TYPE=Release'],
|
|
68
|
-
cwd=str(source), capture_output=True, text=True, encoding='utf-8', errors='replace',
|
|
71
|
+
cwd=str(source), capture_output=True, text=True, encoding='utf-8', errors='replace',
|
|
72
|
+
timeout=180, env=child_env())
|
|
69
73
|
if cfg.returncode != 0:
|
|
70
74
|
raise RuntimeError('cmake configure failed\n' + (cfg.stdout + cfg.stderr)[-4000:])
|
|
71
75
|
made = subprocess.run(['cmake', '--build', 'build', '-j4'], cwd=str(source), capture_output=True,
|
|
72
|
-
text=True, encoding='utf-8', errors='replace', timeout=1800)
|
|
76
|
+
text=True, encoding='utf-8', errors='replace', timeout=1800, env=child_env())
|
|
73
77
|
if made.returncode != 0:
|
|
74
78
|
raise RuntimeError('build failed\n' + (made.stdout + made.stderr)[-4000:])
|
|
75
79
|
binary = build / 'nn_task'
|
|
@@ -87,7 +91,8 @@ class Case:
|
|
|
87
91
|
self.flops = flops
|
|
88
92
|
|
|
89
93
|
|
|
90
|
-
def run_operation(name: str, threshold: float, cases: list[Case], binary: Path, root: Path
|
|
94
|
+
def run_operation(name: str, threshold: float, cases: list[Case], binary: Path, root: Path,
|
|
95
|
+
invocation_timeout: float = INVOCATION_TIMEOUT_SECONDS) -> dict:
|
|
91
96
|
op_dir = root / 'ops' / name
|
|
92
97
|
op_dir.mkdir(parents=True, exist_ok=True)
|
|
93
98
|
executable = True
|
|
@@ -111,7 +116,8 @@ def run_operation(name: str, threshold: float, cases: list[Case], binary: Path,
|
|
|
111
116
|
started = time.perf_counter()
|
|
112
117
|
try:
|
|
113
118
|
proc = subprocess.run(cmd, cwd=str(case_dir), capture_output=True, text=True,
|
|
114
|
-
encoding='utf-8', errors='replace', timeout=
|
|
119
|
+
encoding='utf-8', errors='replace', timeout=invocation_timeout,
|
|
120
|
+
env=child_env())
|
|
115
121
|
except subprocess.TimeoutExpired:
|
|
116
122
|
executable = False
|
|
117
123
|
first_error = first_error or 'timeout'
|
|
@@ -459,7 +465,13 @@ def main() -> int:
|
|
|
459
465
|
except Exception as exc:
|
|
460
466
|
return fail({'task': 'neural-fp32', 'ok': False, 'error': str(exc)})
|
|
461
467
|
rows = []
|
|
468
|
+
deadline = time.monotonic() + OPS_DEADLINE_SECONDS
|
|
462
469
|
for name, threshold, builder in OPERATIONS:
|
|
470
|
+
if time.monotonic() > deadline:
|
|
471
|
+
rows.append({'name': name, 'executable': False, 'passed': False,
|
|
472
|
+
'weighted_mean_relative_error': None, 'threshold': threshold,
|
|
473
|
+
'speed_gflops': None, 'error': 'evaluation deadline exceeded'})
|
|
474
|
+
continue
|
|
463
475
|
try:
|
|
464
476
|
cases = builder()
|
|
465
477
|
row = run_operation(name, threshold, cases, binary, root)
|
package/eval/swe-bench-pro.py
CHANGED
|
@@ -3,9 +3,12 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
import os, tempfile
|
|
5
5
|
from pathlib import Path
|
|
6
|
-
from common import EVAL_ROOT, candidate_row, clean_copy, emit, fail, parse_workspace, run_legacy
|
|
6
|
+
from common import EVAL_ROOT, candidate_row, clean_copy, emit, fail, parse_workspace, restore_baseline, run_legacy, verify_venv
|
|
7
7
|
|
|
8
8
|
workspace = parse_workspace()
|
|
9
|
+
problem = verify_venv(workspace)
|
|
10
|
+
if problem is not None:
|
|
11
|
+
raise SystemExit(fail({'task': 'swe-bench-pro', 'ok': False, 'error': problem}))
|
|
9
12
|
with tempfile.TemporaryDirectory(prefix='swe-pro-eval-') as td:
|
|
10
13
|
temp = Path(td)
|
|
11
14
|
candidate = temp / 'candidate' / 'workspace'
|
|
@@ -13,13 +16,14 @@ with tempfile.TemporaryDirectory(prefix='swe-pro-eval-') as td:
|
|
|
13
16
|
clean_copy(workspace, candidate, ignore_venv=True)
|
|
14
17
|
venv = workspace / '.venv'
|
|
15
18
|
if venv.is_dir():
|
|
16
|
-
|
|
19
|
+
try:
|
|
20
|
+
os.symlink(venv, candidate / '.venv')
|
|
21
|
+
except FileExistsError:
|
|
22
|
+
pass
|
|
23
|
+
restore_baseline(candidate)
|
|
17
24
|
result = run_legacy(EVAL_ROOT / 'legacy' / 'swe_bench_pro.py', ['--submissions', str(temp)], temp / 'out')
|
|
18
25
|
if not result.get('ok'):
|
|
19
26
|
raise SystemExit(fail({'task': 'swe-bench-pro', 'ok': False, 'error': result.get('error', 'evaluation failed')}))
|
|
20
27
|
row = candidate_row(result['summary'])
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
errors = row.get('errors', 0)
|
|
24
|
-
resolved = failed == 0 and errors == 0 and passed > 0
|
|
25
|
-
emit({'task': 'swe-bench-pro', 'ok': True, 'score': 100.0 if resolved else 0.0, 'resolved': resolved, 'passRate': row.get('score', 0), 'passed': passed, 'failed': failed, 'errors': errors, 'status': row.get('status')})
|
|
28
|
+
resolved = row.get('resolved') is True
|
|
29
|
+
emit({'task': 'swe-bench-pro', 'ok': True, 'score': 100.0 if resolved else 0.0, 'resolved': resolved, 'passRate': row.get('score', 0), 'passed': row.get('passed', 0), 'failed': row.get('failed', 0), 'errors': row.get('errors', 0), 'f2pPassed': row.get('f2p_passed', 0), 'f2pTotal': row.get('f2p_total', 0), 'status': row.get('status')})
|
package/eval/tank.py
CHANGED
|
@@ -16,5 +16,14 @@ with tempfile.TemporaryDirectory(prefix='tank-eval-') as td:
|
|
|
16
16
|
result = run_legacy(EVAL_ROOT / 'legacy' / 'tank.py', ['--submissions', str(temp), '--arena', str(EVAL_ROOT / 'arena' / 'tank'), '--tier', 'quick'], temp / 'out')
|
|
17
17
|
if not result.get('ok'):
|
|
18
18
|
raise SystemExit(fail({'task': 'tank', 'ok': False, 'error': result.get('error', 'evaluation failed')}))
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
summary = result['summary']
|
|
20
|
+
row = candidate_row(summary)
|
|
21
|
+
if not row:
|
|
22
|
+
raise SystemExit(fail({'task': 'tank', 'ok': False, 'error': 'candidate row missing from evaluator summary'}))
|
|
23
|
+
wins = draws = losses = 0
|
|
24
|
+
for pair in summary.get('pairwise') or []:
|
|
25
|
+
if pair.get('a') == 'candidate':
|
|
26
|
+
wins += int(pair.get('wins', 0)); draws += int(pair.get('draws', 0)); losses += int(pair.get('losses', 0))
|
|
27
|
+
elif pair.get('b') == 'candidate':
|
|
28
|
+
wins += int(pair.get('losses', 0)); draws += int(pair.get('draws', 0)); losses += int(pair.get('wins', 0))
|
|
29
|
+
emit({'task': 'tank', 'ok': True, 'score': row.get('rating', 0), 'rating': row.get('rating', 0), 'wins': wins, 'losses': losses, 'draws': draws, 'games': row.get('games', 0)})
|
package/eval/warehouse.py
CHANGED
|
@@ -17,4 +17,20 @@ with tempfile.TemporaryDirectory(prefix='warehouse-eval-') as td:
|
|
|
17
17
|
if not result.get('ok'):
|
|
18
18
|
raise SystemExit(fail({'task': 'warehouse', 'ok': False, 'error': result.get('error', 'evaluation failed')}))
|
|
19
19
|
row = candidate_row(result['summary'])
|
|
20
|
-
|
|
20
|
+
if not row:
|
|
21
|
+
raise SystemExit(fail({'task': 'warehouse', 'ok': False, 'error': 'candidate row missing from evaluator summary'}))
|
|
22
|
+
compile_error = row.get('compileError') or ''
|
|
23
|
+
correct = row.get('correct', 0)
|
|
24
|
+
total = row.get('total', 0)
|
|
25
|
+
status = 'compile-failed' if compile_error else ('ok' if correct == total and total else 'incorrect')
|
|
26
|
+
emit({
|
|
27
|
+
'task': 'warehouse',
|
|
28
|
+
'ok': True,
|
|
29
|
+
'score': row.get('score', 0),
|
|
30
|
+
'speedup': row.get('geomeanSpeedup', 0),
|
|
31
|
+
'geomeanSpeedup': row.get('geomeanSpeedup', 0),
|
|
32
|
+
'correct': correct,
|
|
33
|
+
'total': total,
|
|
34
|
+
'status': status,
|
|
35
|
+
'error': compile_error,
|
|
36
|
+
})
|