fix: 共享 harness 缓存并限制 runner VM 池

This commit is contained in:
爱特每羊队
2026-06-15 15:26:57 +08:00
parent fdaedc060b
commit 469e37658d
+20 -18
View File
@@ -7,7 +7,7 @@ use serde::Deserialize;
use std::collections::HashMap; use std::collections::HashMap;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc; use std::sync::{Arc, OnceLock, RwLock};
use std::time::Duration; use std::time::Duration;
use walkdir::WalkDir; use walkdir::WalkDir;
@@ -194,6 +194,8 @@ impl HarnessSources {
} }
} }
static HARNESS: OnceLock<HarnessSources> = OnceLock::new();
fn is_blacklisted_harness(name: &str) -> bool { fn is_blacklisted_harness(name: &str) -> bool {
matches!( matches!(
name, name,
@@ -264,15 +266,18 @@ fn build_harness_source(meta: &TestMeta, harness: &HarnessSources) -> Result<Str
} }
fn get_harness_prefix( fn get_harness_prefix(
meta: &TestMeta, harness: &HarnessSources, cache: &mut HarnessPrefixCache, meta: &TestMeta, harness: &HarnessSources, cache: &Arc<RwLock<HarnessPrefixCache>>,
) -> Result<String, String> { ) -> Result<String, String> {
let key = harness_key(meta); let key = harness_key(meta);
if let Some(prefix) = cache.get(&key) { {
return Ok(prefix.clone()); let guard = cache.read().unwrap();
if let Some(prefix) = guard.get(&key) {
return Ok(prefix.clone());
}
} }
let source = build_harness_source(meta, harness)?; let source = build_harness_source(meta, harness)?;
cache.insert(key, source.clone()); cache.write().unwrap().insert(key, source.clone());
Ok(source) Ok(source)
} }
@@ -386,7 +391,7 @@ fn is_skipped(meta: &TestMeta) -> Option<String> {
fn run_test( fn run_test(
path: &Path, source: &str, meta: &TestMeta, kernel: &Arc<KernelCore>, harness: &HarnessSources, path: &Path, source: &str, meta: &TestMeta, kernel: &Arc<KernelCore>, harness: &HarnessSources,
harness_cache: &mut HarnessPrefixCache, no_skip: bool, harness_cache: &Arc<RwLock<HarnessPrefixCache>>, no_skip: bool,
) -> TestResult { ) -> TestResult {
let start = std::time::Instant::now(); let start = std::time::Instant::now();
@@ -405,7 +410,7 @@ fn run_test(
fn run_test_inner( fn run_test_inner(
path: &Path, source: &str, meta: &TestMeta, kernel: &Arc<KernelCore>, harness: &HarnessSources, path: &Path, source: &str, meta: &TestMeta, kernel: &Arc<KernelCore>, harness: &HarnessSources,
harness_cache: &mut HarnessPrefixCache, no_skip: bool, harness_cache: &Arc<RwLock<HarnessPrefixCache>>, no_skip: bool,
) -> TestResult { ) -> TestResult {
let start = std::time::Instant::now(); let start = std::time::Instant::now();
@@ -527,7 +532,7 @@ fn discover_tests(test262_root: &Path) -> Vec<PathBuf> {
/// `harness_cache`) never crosses a thread boundary. /// `harness_cache`) never crosses a thread boundary.
fn process_path( fn process_path(
path: &Path, filter: &Option<String>, no_skip: bool, kernel: &Arc<KernelCore>, harness_sources: &HarnessSources, path: &Path, filter: &Option<String>, no_skip: bool, kernel: &Arc<KernelCore>, harness_sources: &HarnessSources,
harness_cache: &mut HarnessPrefixCache, harness_cache: &Arc<RwLock<HarnessPrefixCache>>,
) -> TestResult { ) -> TestResult {
let source = match std::fs::read_to_string(path) { let source = match std::fs::read_to_string(path) {
Ok(s) => s, Ok(s) => s,
@@ -589,6 +594,8 @@ fn build_runner_kernel() -> Arc<KernelCore> {
// Keep test262 recursion tests from reaching Rust's native stack before the // Keep test262 recursion tests from reaching Rust's native stack before the
// VM converts deep JS calls into a catchable RangeError. // VM converts deep JS calls into a catchable RangeError.
kernel_config.max_call_depth = 256; kernel_config.max_call_depth = 256;
kernel_config.min_pool_size = 1;
kernel_config.max_pool_size = Some(1);
KernelCore::new(kernel_config) KernelCore::new(kernel_config)
} }
@@ -745,6 +752,7 @@ fn run_tests() -> bool {
let filter = &filter; let filter = &filter;
let no_skip = config.no_skip; let no_skip = config.no_skip;
let paths_ref = &paths; let paths_ref = &paths;
let harness_cache = Arc::new(RwLock::new(HarnessPrefixCache::new()));
// Each worker returns its partial stats plus (index, result) pairs so the // Each worker returns its partial stats plus (index, result) pairs so the
// final results vector can be restored to discovery order for stable output. // final results vector can be restored to discovery order for stable output.
@@ -753,14 +761,14 @@ fn run_tests() -> bool {
.map(|_| { .map(|_| {
let cursor = &cursor; let cursor = &cursor;
let progress = &progress; let progress = &progress;
let harness_cache = Arc::clone(&harness_cache);
// Match main()'s 16MB stack: the VM recurses on deeply nested // Match main()'s 16MB stack: the VM recurses on deeply nested
// test programs and would overflow the default worker stack. // test programs and would overflow the default worker stack.
std::thread::Builder::new() std::thread::Builder::new()
.stack_size(16 * 1024 * 1024) .stack_size(16 * 1024 * 1024)
.spawn_scoped(scope, move || { .spawn_scoped(scope, move || {
let kernel = build_runner_kernel(); let kernel = build_runner_kernel();
let harness_sources = HarnessSources::new(); let harness_sources = HARNESS.get_or_init(HarnessSources::new);
let mut harness_cache = HarnessPrefixCache::new();
let mut stats = RunStats::default(); let mut stats = RunStats::default();
let mut out: Vec<(usize, TestResult)> = Vec::new(); let mut out: Vec<(usize, TestResult)> = Vec::new();
@@ -779,14 +787,8 @@ fn run_tests() -> bool {
eprintln!(" [{tid:?}] running: {path_str}"); eprintln!(" [{tid:?}] running: {path_str}");
} }
let result = process_path( let result =
&paths_ref[i], process_path(&paths_ref[i], filter, no_skip, &kernel, harness_sources, &harness_cache);
filter,
no_skip,
&kernel,
&harness_sources,
&mut harness_cache,
);
stats.record(&result); stats.record(&result);
out.push((i, result)); out.push((i, result));