mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
fix: 简化显示纯耗时, 修复 pipefail/BOA源/JerryScript编译/录入值
- 输出移除 X.Xx 倍率, 只显示耗时对比 - set -o pipefail 避免 cargo 编译失败被 pipe 吞掉 - BOA 改用 boa/ dev 源码 (兼容 Rust 1.96+) - build.sh 修复 IFS='|' 分隔, 解决多词参数被拆碎 - 加入 pkg-config/cmake/nodejs 依赖, 支持 BOA/JerryScript/V8 - test262 各引擎全部改为录入值, 仅 OxideJS 现场跑 (cherry picked from commit d64c6577e768195687b182a3ccb6ef36d318e905)
This commit is contained in:
+17
-17
@@ -1,7 +1,7 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# OxideJS Benchmark Suite — 一键构建
|
# OxideJS Benchmark Suite — 一键构建
|
||||||
# 兼容: Debian/Ubuntu, RHEL/Fedora, Arch, Alpine, openSUSE
|
# 兼容: Debian/Ubuntu, RHEL/Fedora, Arch, Alpine, openSUSE
|
||||||
set -e
|
set -eo pipefail
|
||||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
REPO_ROOT="$(dirname "$SCRIPT_DIR")"
|
REPO_ROOT="$(dirname "$SCRIPT_DIR")"
|
||||||
|
|
||||||
@@ -13,23 +13,23 @@ step() { echo -e "\n${BOLD}${CYAN}═══ $* ═══${NC}"; }
|
|||||||
|
|
||||||
# ── 包管理器检测 ─────────────────────────────────────────────────────
|
# ── 包管理器检测 ─────────────────────────────────────────────────────
|
||||||
detect_pm() {
|
detect_pm() {
|
||||||
if command -v apt-get &>/dev/null; then echo "apt" "apt-get install -y" "apt-get update -qq"
|
if command -v apt-get &>/dev/null; then echo "apt|apt-get install -y|apt-get update -qq"
|
||||||
elif command -v dnf &>/dev/null; then echo "dnf" "dnf install -y" "dnf check-update 2>/dev/null || true"
|
elif command -v dnf &>/dev/null; then echo "dnf|dnf install -y|dnf check-update 2>/dev/null || true"
|
||||||
elif command -v yum &>/dev/null; then echo "yum" "yum install -y" "yum check-update 2>/dev/null || true"
|
elif command -v yum &>/dev/null; then echo "yum|yum install -y|yum check-update 2>/dev/null || true"
|
||||||
elif command -v pacman &>/dev/null; then echo "pacman" "pacman -S --noconfirm" "pacman -Sy --noconfirm"
|
elif command -v pacman &>/dev/null; then echo "pacman|pacman -S --noconfirm|pacman -Sy --noconfirm"
|
||||||
elif command -v apk &>/dev/null; then echo "apk" "apk add --no-cache" "apk update"
|
elif command -v apk &>/dev/null; then echo "apk|apk add --no-cache|apk update"
|
||||||
elif command -v zypper &>/dev/null; then echo "zypper" "zypper install -y" "zypper refresh"
|
elif command -v zypper &>/dev/null; then echo "zypper|zypper install -y|zypper refresh"
|
||||||
else echo "unknown" "" ""
|
else echo "unknown||"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
map_pkgs() {
|
map_pkgs() {
|
||||||
case "$1" in
|
case "$1" in
|
||||||
apt) echo "gcc make git python3 python3-pip curl pkg-config cmake";;
|
apt) echo "gcc make git python3 python3-pip curl pkg-config cmake nodejs";;
|
||||||
dnf|yum) echo "gcc make git python3 python3-pip curl pkgconfig cmake";;
|
dnf|yum) echo "gcc make git python3 python3-pip curl pkgconfig cmake nodejs";;
|
||||||
pacman) echo "gcc make git python python-pip curl pkgconf cmake";;
|
pacman) echo "gcc make git python python-pip curl pkgconf cmake nodejs";;
|
||||||
apk) echo "gcc make git python3 py3-pip curl pkgconfig cmake";;
|
apk) echo "gcc make git python3 py3-pip curl pkgconfig cmake nodejs";;
|
||||||
zypper) echo "gcc make git python3 python3-pip curl pkg-config cmake";;
|
zypper) echo "gcc make git python3 python3-pip curl pkg-config cmake nodejs";;
|
||||||
*) echo "gcc make git python3 curl";;
|
*) echo "gcc make git python3 curl";;
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
@@ -103,10 +103,10 @@ build_quickjs() {
|
|||||||
|
|
||||||
# ── BOA ──────────────────────────────────────────────────────────────────
|
# ── BOA ──────────────────────────────────────────────────────────────────
|
||||||
build_boa() {
|
build_boa() {
|
||||||
step "BOA (baseline v0.21)"
|
step "BOA (dev)"
|
||||||
local boa_dir="$REPO_ROOT/baseline-boa"
|
local boa_dir="$REPO_ROOT/boa"
|
||||||
if [ ! -d "$boa_dir" ]; then
|
if [ ! -d "$boa_dir" ]; then
|
||||||
warn "baseline-boa/ 不存在,跳过"
|
warn "boa/ 不存在,跳过"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
if [ -f "$boa_dir/target/release/boa" ]; then
|
if [ -f "$boa_dir/target/release/boa" ]; then
|
||||||
@@ -188,7 +188,7 @@ echo -e "${BOLD}${CYAN}╚══════════════════
|
|||||||
step "检测环境"
|
step "检测环境"
|
||||||
echo " OS: $(uname -a 2>/dev/null | cut -d' ' -f1-3)"
|
echo " OS: $(uname -a 2>/dev/null | cut -d' ' -f1-3)"
|
||||||
echo " CPU: $(nproc 2>/dev/null || echo '?') cores"
|
echo " CPU: $(nproc 2>/dev/null || echo '?') cores"
|
||||||
read pm icmd ucmd <<< $(detect_pm)
|
IFS='|' read pm icmd ucmd <<< $(detect_pm)
|
||||||
info "包管理器: $pm"
|
info "包管理器: $pm"
|
||||||
|
|
||||||
install_deps "$pm" "$icmd" "$ucmd" $(map_pkgs "$pm")
|
install_deps "$pm" "$icmd" "$ucmd" $(map_pkgs "$pm")
|
||||||
|
|||||||
+21
-72
@@ -31,18 +31,12 @@ RESULTS_DIR = REPO_ROOT / "benchmark" / "results"
|
|||||||
class Engine:
|
class Engine:
|
||||||
"""A JS engine available for benchmarking."""
|
"""A JS engine available for benchmarking."""
|
||||||
|
|
||||||
def __init__(self, key, name, exe, run_cmd, *,
|
def __init__(self, key, name, exe, run_cmd, *, test262_rate=None):
|
||||||
test262_exe=None, test262_rate=None,
|
|
||||||
test262_runner_is_conf=False, test262_conf=None, test262_cwd=None):
|
|
||||||
self.key = key
|
self.key = key
|
||||||
self.name = name
|
self.name = name
|
||||||
self.exe = Path(exe) if isinstance(exe, str) else exe
|
self.exe = Path(exe) if isinstance(exe, str) else exe
|
||||||
self._run_cmd = run_cmd # list of str, {exe} and {file} placeholders
|
self._run_cmd = run_cmd # list of str, {exe} and {file} placeholders
|
||||||
self.test262_exe = Path(test262_exe) if test262_exe else None
|
|
||||||
self.test262_rate = test262_rate # pre-recorded pass rate or None
|
self.test262_rate = test262_rate # pre-recorded pass rate or None
|
||||||
self.test262_runner_is_conf = test262_runner_is_conf
|
|
||||||
self.test262_conf = test262_conf
|
|
||||||
self.test262_cwd = test262_cwd
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def available(self):
|
def available(self):
|
||||||
@@ -58,7 +52,7 @@ class Engine:
|
|||||||
f.write(js); tmp = f.name
|
f.write(js); tmp = f.name
|
||||||
try:
|
try:
|
||||||
if self.key == "v8":
|
if self.key == "v8":
|
||||||
rc, out, err, t = run(["node", "-p", js], timeout=timeout)
|
rc, out, err, t = run(["node", tmp], timeout=timeout)
|
||||||
else:
|
else:
|
||||||
cmd = [str(self.exe) if p == "{exe}" else (tmp if p == "{file}" else p) for p in self._run_cmd]
|
cmd = [str(self.exe) if p == "{exe}" else (tmp if p == "{file}" else p) for p in self._run_cmd]
|
||||||
rc, out, err, t = run(cmd, timeout=timeout)
|
rc, out, err, t = run(cmd, timeout=timeout)
|
||||||
@@ -73,65 +67,35 @@ class Engine:
|
|||||||
cmd = [str(self.exe) if p == "{exe}" else (str(file_path) if p == "{file}" else p) for p in self._run_cmd]
|
cmd = [str(self.exe) if p == "{exe}" else (str(file_path) if p == "{file}" else p) for p in self._run_cmd]
|
||||||
return run(cmd, timeout=timeout)
|
return run(cmd, timeout=timeout)
|
||||||
|
|
||||||
def run_test262(self, timeout=7200):
|
|
||||||
"""Run test262 suite. Returns (pass, fail, skip, total, elapsed_sec) or None."""
|
|
||||||
if self.test262_rate is not None:
|
|
||||||
return None # pre-recorded, no runner
|
|
||||||
if not self.test262_exe or not self.test262_exe.exists():
|
|
||||||
return None
|
|
||||||
if self.test262_runner_is_conf:
|
|
||||||
cwd = self.test262_cwd or self.exe.parent
|
|
||||||
rc, out, err, _ = run([str(self.test262_exe), "-c", str(self.test262_conf)],
|
|
||||||
timeout=timeout, cwd=cwd)
|
|
||||||
else:
|
|
||||||
rc, out, err, _ = run([str(self.test262_exe), "--supervise", str(TEST262_DIR)],
|
|
||||||
timeout=timeout)
|
|
||||||
summary = {"pass": 0, "fail": 0, "skip": 0, "total": 0}
|
|
||||||
for line in (out + err).split('\n'):
|
|
||||||
for k in ("pass", "fail", "skip", "total"):
|
|
||||||
m = re.search(rf'{k}\s*:\s*(\d+)', line, re.IGNORECASE)
|
|
||||||
if m: summary[k] = max(summary[k], int(m.group(1)))
|
|
||||||
if summary["total"] == 0:
|
|
||||||
return None
|
|
||||||
return summary
|
|
||||||
|
|
||||||
|
|
||||||
# ── Engine registry ─────────────────────────────────────────────────────
|
# ── Engine registry ─────────────────────────────────────────────────────
|
||||||
|
|
||||||
# QuickJS (全平台, make 编译)
|
# QuickJS (全平台, make 编译) — test262 98.8% (ES2020 full, minus Annex B)
|
||||||
QJS_DIR = REPO_ROOT / "baseline-quickjs"
|
|
||||||
QUICKJS = Engine("quickjs", "QuickJS",
|
QUICKJS = Engine("quickjs", "QuickJS",
|
||||||
exe=QJS_DIR / "qjs",
|
exe=REPO_ROOT / "baseline-quickjs" / "qjs",
|
||||||
run_cmd=["{exe}", "{file}"],
|
run_cmd=["{exe}", "{file}"],
|
||||||
test262_exe=QJS_DIR / "run-test262",
|
|
||||||
test262_runner_is_conf=True,
|
|
||||||
test262_conf="test262.conf",
|
|
||||||
test262_cwd=QJS_DIR,
|
|
||||||
test262_rate=94.5)
|
test262_rate=94.5)
|
||||||
|
|
||||||
# BOA (全平台, cargo build)
|
# BOA (全平台, cargo build) — test262 ~85% (ES2020)
|
||||||
BOA_DIR = REPO_ROOT / "baseline-boa"
|
|
||||||
BOA = Engine("boa", "BOA",
|
BOA = Engine("boa", "BOA",
|
||||||
exe=BOA_DIR / "target" / "release" / "boa",
|
exe=REPO_ROOT / "boa" / "target" / "release" / "boa",
|
||||||
run_cmd=["{exe}", "--strict", "{file}"],
|
run_cmd=["{exe}", "--strict", "{file}"],
|
||||||
test262_rate=85.0)
|
test262_rate=85.0)
|
||||||
|
|
||||||
# JerryScript (全平台, cmake + make)
|
# JerryScript (全平台, cmake+make) — test262 ~98% (ES5.1 + partial ES6)
|
||||||
JERRY_DIR = REPO_ROOT / "baseline-jerryscript"
|
|
||||||
JERRY = Engine("jerry", "JerryScript",
|
JERRY = Engine("jerry", "JerryScript",
|
||||||
exe=JERRY_DIR / "build" / "bin" / "MinSizeRel" / "jerry",
|
exe=REPO_ROOT / "baseline-jerryscript" / "build" / "bin" / "MinSizeRel" / "jerry",
|
||||||
run_cmd=["{exe}", "{file}"],
|
run_cmd=["{exe}", "{file}"],
|
||||||
test262_rate=98.0)
|
test262_rate=98.0)
|
||||||
|
|
||||||
# V8 via node (主流平台可选)
|
# V8 via node (主流平台可选) — test262 ~99.9%
|
||||||
V8 = Engine("v8", "V8(node)",
|
V8 = Engine("v8", "V8(node)",
|
||||||
exe=Path("node"), # resolved via shutil_which
|
exe=Path("node"),
|
||||||
run_cmd=["node", "-p"],
|
run_cmd=["node", "-p"],
|
||||||
test262_rate=99.9)
|
test262_rate=99.9)
|
||||||
|
|
||||||
# Hermes (主流平台可选)
|
# Hermes (主流平台可选) — test262 ~90%
|
||||||
HERMES = Engine("hermes", "Hermes",
|
HERMES = Engine("hermes", "Hermes",
|
||||||
exe=Path("hermes"), # resolved via shutil_which
|
exe=Path("hermes"),
|
||||||
run_cmd=["{exe}", "{file}"],
|
run_cmd=["{exe}", "{file}"],
|
||||||
test262_rate=90.0)
|
test262_rate=90.0)
|
||||||
|
|
||||||
@@ -219,7 +183,7 @@ def bench_timing():
|
|||||||
if avg and avg != float('inf'):
|
if avg and avg != float('inf'):
|
||||||
ratio = ox_avg / avg
|
ratio = ox_avg / avg
|
||||||
row[f"{eng.key}_ratio"] = round(ratio, 1)
|
row[f"{eng.key}_ratio"] = round(ratio, 1)
|
||||||
parts.append(f" {eng.name} {avg:.3f}ms {ratio:.1f}x")
|
parts.append(f" {eng.name} {avg:.3f}ms")
|
||||||
else:
|
else:
|
||||||
row[f"{eng.key}_ratio"] = 0
|
row[f"{eng.key}_ratio"] = 0
|
||||||
parts.append(f" {eng.name} N/A")
|
parts.append(f" {eng.name} N/A")
|
||||||
@@ -255,7 +219,7 @@ def bench_stress():
|
|||||||
if val and val != float('inf'):
|
if val and val != float('inf'):
|
||||||
ratio = ox / val
|
ratio = ox / val
|
||||||
row[f"{eng.key}_ratio"] = round(ratio, 1)
|
row[f"{eng.key}_ratio"] = round(ratio, 1)
|
||||||
parts.append(f" {eng.name} {val:.1f}ms {ratio:.1f}x")
|
parts.append(f" {eng.name} {val:.1f}ms")
|
||||||
else:
|
else:
|
||||||
row[f"{eng.key}_ratio"] = 0
|
row[f"{eng.key}_ratio"] = 0
|
||||||
parts.append(f" {eng.name} N/A")
|
parts.append(f" {eng.name} N/A")
|
||||||
@@ -296,28 +260,11 @@ def bench_test262_oxide():
|
|||||||
return summary
|
return summary
|
||||||
|
|
||||||
def bench_test262_baselines():
|
def bench_test262_baselines():
|
||||||
"""各引擎 test262 成绩汇总 — 运行 runner 或使用已知通过率"""
|
"""各引擎 test262 成绩 — 全部使用已知通过率,不实际跑"""
|
||||||
print("\n" + "=" * 60)
|
|
||||||
print(" 3b. Test262 — 各引擎")
|
|
||||||
print("=" * 60)
|
|
||||||
results = {}
|
results = {}
|
||||||
for eng in ALL_ENGINES:
|
for eng in ALL_ENGINES:
|
||||||
if eng.test262_rate is not None:
|
if eng.test262_rate is not None:
|
||||||
results[eng.key] = {"rate": eng.test262_rate, "note": f"{eng.name} 录入值"}
|
results[eng.key] = {"rate": eng.test262_rate, "note": f"{eng.name} 录入值"}
|
||||||
print(f" {eng.name:15s} {eng.test262_rate:.1f}% (录入值)")
|
|
||||||
elif eng.available:
|
|
||||||
s = eng.run_test262()
|
|
||||||
if s:
|
|
||||||
ran = s['pass'] + s['fail']
|
|
||||||
rate = s['pass'] / ran * 100 if ran else 0
|
|
||||||
results[eng.key] = {"rate": round(rate, 1), "raw": s}
|
|
||||||
print(f" {eng.name:15s} {rate:.1f}%")
|
|
||||||
else:
|
|
||||||
results[eng.key] = {"rate": 0, "note": "runner 不可用"}
|
|
||||||
print(f" {eng.name:15s} 无法运行")
|
|
||||||
else:
|
|
||||||
results[eng.key] = {"rate": 0, "note": "引擎不可用"}
|
|
||||||
print(f" {eng.name:15s} N/A")
|
|
||||||
return results
|
return results
|
||||||
|
|
||||||
def parse_jsonl(path):
|
def parse_jsonl(path):
|
||||||
@@ -504,20 +451,22 @@ def report(all_data):
|
|||||||
timing = all_data.get("timing", [])
|
timing = all_data.get("timing", [])
|
||||||
if timing:
|
if timing:
|
||||||
w("## Single JS Execution\n")
|
w("## Single JS Execution\n")
|
||||||
w("| Scenario | OxideJS | QuickJS | Ratio |")
|
w("| Scenario | OxideJS | QuickJS ")
|
||||||
w("|------|---------|---------|------|")
|
w("|------|---------|---------|------|")
|
||||||
for r in timing:
|
for r in timing:
|
||||||
w(f"| {r['name']} | {r['ox_ms']:.3f}ms | {r['qjs_ms']:.3f}ms | {r['ratio']:.1f}x |")
|
qjs_v = r.get('quickjs_ms', 0); qjs_r = r.get('quickjs_ratio', 0)
|
||||||
|
w(f"| {r['name']} | {r['ox_ms']:.3f}ms | {qjs_v:.3f}ms |")
|
||||||
w("")
|
w("")
|
||||||
|
|
||||||
# Stress
|
# Stress
|
||||||
stress = all_data.get("stress", [])
|
stress = all_data.get("stress", [])
|
||||||
if stress:
|
if stress:
|
||||||
w("## Stress Benchmarks\n")
|
w("## Stress Benchmarks\n")
|
||||||
w("| Test | OxideJS | QuickJS | Ratio |")
|
w("| Test | OxideJS | QuickJS ")
|
||||||
w("|------|---------|---------|------|")
|
w("|------|---------|---------|------|")
|
||||||
for r in stress:
|
for r in stress:
|
||||||
w(f"| {r['test']} | {r['ox_ms']:.1f}ms | {r['qjs_ms']:.1f}ms | {r['ratio']:.1f}x |")
|
qjs_v = r.get('quickjs_ms', 0); qjs_r = r.get('quickjs_ratio', 0)
|
||||||
|
w(f"| {r['test']} | {r['ox_ms']:.1f}ms | {qjs_v:.1f}ms |")
|
||||||
w("")
|
w("")
|
||||||
|
|
||||||
# Startup
|
# Startup
|
||||||
|
|||||||
Reference in New Issue
Block a user