feat(phase21.5): MirBuilder optimization prep + crate EXE infrastructure
Phase 21.5 optimization readiness - C-level performance target: - MirBuilder: JsonFrag purify toggle (HAKO_MIR_BUILDER_JSONFRAG_PURIFY=1) - Normalizer: extended f64 canonicalization + dedupe improvements - loop_opts_adapter: JsonFrag path refinement for crate EXE compatibility Infrastructure improvements: - provider_registry: add diagnostics + ring-1 providers (array/console/map/path) - mir_interpreter: add normalization/purify feature gates - tools/selfhost_exe_stageb.sh: new end-to-end Stage-B→crate EXE pipeline - tools/perf/microbench.sh: performance measurement tooling Smoke tests (phase2100): - Extend timeout 15s→120s for heavy crate EXE builds - Add stageb_loop_jsonfrag_crate_exe_canary_vm.sh (target test) - Add s3_backend_selector_crate_exe_vm_parity_return42_canary_vm.sh Documentation: - ENV_VARS.md: add Phase 21.5 optimization toggles - README updates: clarify crate backend strategy - phase215-optimization.md: new optimization roadmap This commit sets the stage for Phase 21.5 critical optimization: achieving C-level performance to decide hakorune's future viability.
This commit is contained in:
28
src/runner/modes/common_util/diag.rs
Normal file
28
src/runner/modes/common_util/diag.rs
Normal file
@ -0,0 +1,28 @@
|
||||
//! Common diagnostics helpers (concise, centralized)
|
||||
|
||||
/// Whether provider logs should be emitted under current policy.
|
||||
/// quiet_pipe usually reflects NYASH_JSON_ONLY; allowing override with HAKO_PROVIDER_TRACE=1.
|
||||
pub fn provider_log_enabled(quiet_pipe: bool) -> bool {
|
||||
!quiet_pipe || std::env::var("HAKO_PROVIDER_TRACE").as_deref() == Ok("1")
|
||||
}
|
||||
|
||||
/// Emit a consistent provider-registry info line.
|
||||
pub fn provider_log_info(msg: &str) {
|
||||
eprintln!("[provider-registry] {}", msg);
|
||||
}
|
||||
|
||||
/// Emit the provider selection tag in a stable shape.
|
||||
pub fn provider_log_select(box_name: &str, ring: &str, source: &str, caps: Option<&str>) {
|
||||
match caps {
|
||||
Some(c) if !c.is_empty() => {
|
||||
eprintln!("[provider/select:{} ring={} src={} caps={}]", box_name, ring, source, c);
|
||||
}
|
||||
_ => {
|
||||
eprintln!("[provider/select:{} ring={} src={}]", box_name, ring, source);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Emit a Fail-Fast tag for provider fallback/selection errors.
|
||||
pub fn failfast_provider(reason: &str) { eprintln!("[failfast/provider/{}]", reason); }
|
||||
|
||||
@ -14,3 +14,4 @@ pub mod core_bridge;
|
||||
pub mod hako;
|
||||
pub mod plugin_guard;
|
||||
pub mod provider_registry;
|
||||
pub mod diag;
|
||||
|
||||
@ -1,26 +1,21 @@
|
||||
//! Provider registry: selects concrete providers for core resources (e.g. FileBox).
|
||||
//! SSOT (Single Source of Truth) for provider selection via ProviderFactory registration.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::sync::{Arc, Mutex, OnceLock};
|
||||
|
||||
use crate::boxes::file::provider::FileIo;
|
||||
use crate::boxes::file::core_ro::CoreRoFileIo;
|
||||
use crate::boxes::file::provider::FileIo;
|
||||
use crate::config::provider_env::{self, ProviderPolicy};
|
||||
use crate::runner::modes::common_util::diag;
|
||||
|
||||
/// Provider selection policy (global). Applied when mode=Auto.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
enum ProviderPolicy {
|
||||
/// Current default: prefer plugin/dynamic providers by priority; use ring-1 as fallback
|
||||
StrictPluginFirst,
|
||||
/// Prefer ring-1 (static/core-ro) for stability/CI; fall back to plugin if unavailable
|
||||
SafeCoreFirst,
|
||||
/// Alias to SafeCoreFirst for future extension
|
||||
StaticPreferred,
|
||||
}
|
||||
// Policy/Mode are provided by config::provider_env (centralized)
|
||||
pub use crate::config::provider_env::FileBoxMode;
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub enum FileBoxMode { Auto, CoreRo, PluginOnly }
|
||||
|
||||
/// Factory for creating FileIo providers
|
||||
/// Factory for creating providers for a specific Box type.
|
||||
/// Note: Currently specialized for FileBox via `FileIo`.
|
||||
/// The registry is structured as BoxName → [Factory], enabling future
|
||||
/// extension to other Box kinds without changing the selection policy surface.
|
||||
pub trait ProviderFactory: Send + Sync {
|
||||
fn box_name(&self) -> &str;
|
||||
fn create_provider(&self) -> Arc<dyn FileIo>;
|
||||
@ -30,13 +25,17 @@ pub trait ProviderFactory: Send + Sync {
|
||||
}
|
||||
}
|
||||
|
||||
/// Global registry of provider factories
|
||||
static PROVIDER_FACTORIES: OnceLock<Mutex<Vec<Arc<dyn ProviderFactory>>>> = OnceLock::new();
|
||||
/// Global registry of provider factories, grouped by Box name
|
||||
static PROVIDER_FACTORIES: OnceLock<Mutex<HashMap<String, Vec<Arc<dyn ProviderFactory>>>>> =
|
||||
OnceLock::new();
|
||||
|
||||
/// Register a provider factory (called by builtin/dynamic loaders)
|
||||
pub fn register_provider_factory(factory: Arc<dyn ProviderFactory>) {
|
||||
let registry = PROVIDER_FACTORIES.get_or_init(|| Mutex::new(Vec::new()));
|
||||
registry.lock().unwrap().push(factory);
|
||||
let registry = PROVIDER_FACTORIES
|
||||
.get_or_init(|| Mutex::new(HashMap::new()));
|
||||
let mut guard = registry.lock().unwrap();
|
||||
let key = factory.box_name().to_string();
|
||||
guard.entry(key).or_default().push(factory);
|
||||
}
|
||||
|
||||
/// Built‑in ring‑1 FileBox provider (core‑ro) — always available, lowest priority
|
||||
@ -51,37 +50,20 @@ impl ProviderFactory for CoreRoFileProviderFactory {
|
||||
|
||||
/// Ensure ring‑1 (core‑ro) provider is present in the registry
|
||||
fn ensure_builtin_file_provider_registered() {
|
||||
let reg = PROVIDER_FACTORIES.get_or_init(|| Mutex::new(Vec::new()));
|
||||
let reg = PROVIDER_FACTORIES
|
||||
.get_or_init(|| Mutex::new(HashMap::new()));
|
||||
let mut guard = reg.lock().unwrap();
|
||||
// If at least one FileBox provider exists, we still keep ring‑1 present for safety; avoid duplicates by checking any core‑ro present by priority
|
||||
let has_core_ro = guard.iter().any(|f| f.box_name() == "FileBox" && f.priority() <= -100);
|
||||
let list = guard.entry("FileBox".to_string()).or_default();
|
||||
// keep ring‑1 present for safety; avoid duplicates by checking any core‑ro present by priority
|
||||
let has_core_ro = list.iter().any(|f| f.priority() <= -100);
|
||||
if !has_core_ro {
|
||||
guard.push(Arc::new(CoreRoFileProviderFactory));
|
||||
list.push(Arc::new(CoreRoFileProviderFactory));
|
||||
}
|
||||
}
|
||||
|
||||
/// Read global provider policy (affects Auto mode only)
|
||||
fn read_provider_policy_from_env() -> ProviderPolicy {
|
||||
match std::env::var("HAKO_PROVIDER_POLICY").unwrap_or_else(|_| "strict-plugin-first".to_string()).as_str() {
|
||||
"safe-core-first" => ProviderPolicy::SafeCoreFirst,
|
||||
"static-preferred" => ProviderPolicy::StaticPreferred,
|
||||
_ => ProviderPolicy::StrictPluginFirst,
|
||||
}
|
||||
}
|
||||
|
||||
/// Read FileBox mode from environment variables
|
||||
/// Backward-compat public readers for existing callers (if any)
|
||||
#[allow(dead_code)]
|
||||
pub fn read_filebox_mode_from_env() -> FileBoxMode {
|
||||
match std::env::var("NYASH_FILEBOX_MODE").unwrap_or_else(|_| "auto".to_string()).as_str() {
|
||||
"core-ro" => FileBoxMode::CoreRo,
|
||||
"plugin-only" => FileBoxMode::PluginOnly,
|
||||
_ => {
|
||||
if std::env::var("NYASH_DISABLE_PLUGINS").as_deref() == Ok("1") {
|
||||
FileBoxMode::CoreRo
|
||||
} else { FileBoxMode::Auto }
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn read_filebox_mode_from_env() -> FileBoxMode { provider_env::filebox_mode_from_env() }
|
||||
|
||||
/// Select provider based on mode and registered factories (SSOT)
|
||||
#[allow(dead_code)]
|
||||
@ -94,13 +76,14 @@ pub fn select_file_provider(mode: FileBoxMode) -> Arc<dyn FileIo> {
|
||||
match mode {
|
||||
FileBoxMode::Auto => {
|
||||
// Selection by global policy
|
||||
let policy = read_provider_policy_from_env();
|
||||
let policy = provider_env::provider_policy_from_env();
|
||||
if let Some(reg) = registry {
|
||||
let mut factories: Vec<_> = reg.lock().unwrap()
|
||||
.iter()
|
||||
.filter(|f| f.box_name() == "FileBox" && f.is_available())
|
||||
.cloned()
|
||||
.collect();
|
||||
let mut factories: Vec<_> = reg
|
||||
.lock()
|
||||
.unwrap()
|
||||
.get("FileBox")
|
||||
.map(|v| v.iter().filter(|f| f.is_available()).cloned().collect())
|
||||
.unwrap_or_else(|| Vec::new());
|
||||
|
||||
// Sort by priority (descending); plugin providers should rank higher than ring-1 (priority -100)
|
||||
factories.sort_by(|a, b| b.priority().cmp(&a.priority()));
|
||||
@ -109,9 +92,9 @@ pub fn select_file_provider(mode: FileBoxMode) -> Arc<dyn FileIo> {
|
||||
match policy {
|
||||
ProviderPolicy::StrictPluginFirst => {
|
||||
if let Some(factory) = factories.first() {
|
||||
if !quiet_pipe || std::env::var("HAKO_PROVIDER_TRACE").as_deref() == Ok("1") {
|
||||
eprintln!("[provider-registry] FileBox: using registered provider (priority={})", factory.priority());
|
||||
eprintln!("[provider/select:FileBox ring=plugin src=dynamic]");
|
||||
if diag::provider_log_enabled(quiet_pipe) {
|
||||
diag::provider_log_info(&format!("FileBox: using registered provider (priority={})", factory.priority()));
|
||||
diag::provider_log_select("FileBox", "plugin", "dynamic", None);
|
||||
}
|
||||
return factory.create_provider();
|
||||
}
|
||||
@ -119,17 +102,17 @@ pub fn select_file_provider(mode: FileBoxMode) -> Arc<dyn FileIo> {
|
||||
ProviderPolicy::SafeCoreFirst | ProviderPolicy::StaticPreferred => {
|
||||
// Prefer ring-1 (priority <= -100)
|
||||
if let Some(core_ro) = factories.iter().find(|f| f.priority() <= -100) {
|
||||
if !quiet_pipe || std::env::var("HAKO_PROVIDER_TRACE").as_deref() == Ok("1") {
|
||||
eprintln!("[provider-registry] FileBox: using core-ro (policy)");
|
||||
eprintln!("[provider/select:FileBox ring=1 src=static caps=[read]]");
|
||||
if diag::provider_log_enabled(quiet_pipe) {
|
||||
diag::provider_log_info("FileBox: using core-ro (policy)");
|
||||
diag::provider_log_select("FileBox", "1", "static", Some("[read]"));
|
||||
}
|
||||
return core_ro.create_provider();
|
||||
}
|
||||
// Fallback to first available (plugin)
|
||||
if let Some(factory) = factories.first() {
|
||||
if !quiet_pipe || std::env::var("HAKO_PROVIDER_TRACE").as_deref() == Ok("1") {
|
||||
eprintln!("[provider-registry] FileBox: using registered provider (priority={})", factory.priority());
|
||||
eprintln!("[provider/select:FileBox ring=plugin src=dynamic]");
|
||||
if diag::provider_log_enabled(quiet_pipe) {
|
||||
diag::provider_log_info(&format!("FileBox: using registered provider (priority={})", factory.priority()));
|
||||
diag::provider_log_select("FileBox", "plugin", "dynamic", None);
|
||||
}
|
||||
return factory.create_provider();
|
||||
}
|
||||
@ -142,20 +125,18 @@ pub fn select_file_provider(mode: FileBoxMode) -> Arc<dyn FileIo> {
|
||||
// - When JSON‑only pipeline is active (quiet structured I/O), or
|
||||
// - When NYASH_FILEBOX_ALLOW_FALLBACK=1 is set,
|
||||
// always use core‑ro provider even if Fail‑Fast is ON.
|
||||
let allow_fb_override =
|
||||
crate::config::env::env_bool("NYASH_JSON_ONLY") ||
|
||||
crate::config::env::env_bool("NYASH_FILEBOX_ALLOW_FALLBACK");
|
||||
let allow_fb_override = provider_env::allow_filebox_fallback_override(quiet_pipe);
|
||||
|
||||
if crate::config::env::fail_fast() && !allow_fb_override {
|
||||
eprintln!("[failfast/provider/filebox:auto-fallback-blocked]");
|
||||
diag::failfast_provider("filebox:auto-fallback-blocked");
|
||||
panic!("Fail-Fast: FileBox provider fallback is disabled (NYASH_FAIL_FAST=0 or NYASH_FILEBOX_ALLOW_FALLBACK=1 to override)");
|
||||
} else {
|
||||
if !quiet_pipe || std::env::var("HAKO_PROVIDER_TRACE").as_deref() == Ok("1") {
|
||||
eprintln!(
|
||||
"[provider-registry] FileBox: using core-ro fallback{}",
|
||||
if diag::provider_log_enabled(quiet_pipe) {
|
||||
diag::provider_log_info(&format!(
|
||||
"FileBox: using core-ro fallback{}",
|
||||
if allow_fb_override { " (override)" } else { "" }
|
||||
);
|
||||
eprintln!("[provider/select:FileBox ring=1 src=static caps=[read]]");
|
||||
));
|
||||
diag::provider_log_select("FileBox", "1", "static", Some("[read]"));
|
||||
}
|
||||
Arc::new(CoreRoFileIo::new())
|
||||
}
|
||||
@ -163,18 +144,19 @@ pub fn select_file_provider(mode: FileBoxMode) -> Arc<dyn FileIo> {
|
||||
FileBoxMode::PluginOnly => {
|
||||
// Try only registered providers, Fail-Fast if none available
|
||||
if let Some(reg) = registry {
|
||||
let mut factories: Vec<_> = reg.lock().unwrap()
|
||||
.iter()
|
||||
.filter(|f| f.box_name() == "FileBox" && f.is_available())
|
||||
.cloned()
|
||||
.collect();
|
||||
let mut factories: Vec<_> = reg
|
||||
.lock()
|
||||
.unwrap()
|
||||
.get("FileBox")
|
||||
.map(|v| v.iter().filter(|f| f.is_available()).cloned().collect())
|
||||
.unwrap_or_else(|| Vec::new());
|
||||
|
||||
factories.sort_by(|a, b| b.priority().cmp(&a.priority()));
|
||||
|
||||
if let Some(factory) = factories.first() {
|
||||
if !quiet_pipe || std::env::var("HAKO_PROVIDER_TRACE").as_deref() == Ok("1") {
|
||||
eprintln!("[provider-registry] FileBox: using plugin-only provider (priority={})", factory.priority());
|
||||
eprintln!("[provider/select:FileBox ring=plugin src=dynamic]");
|
||||
if diag::provider_log_enabled(quiet_pipe) {
|
||||
diag::provider_log_info(&format!("FileBox: using plugin-only provider (priority={})", factory.priority()));
|
||||
diag::provider_log_select("FileBox", "plugin", "dynamic", None);
|
||||
}
|
||||
return factory.create_provider();
|
||||
}
|
||||
@ -184,9 +166,9 @@ pub fn select_file_provider(mode: FileBoxMode) -> Arc<dyn FileIo> {
|
||||
}
|
||||
FileBoxMode::CoreRo => {
|
||||
// Always use core-ro, ignore registry
|
||||
if !quiet_pipe || std::env::var("HAKO_PROVIDER_TRACE").as_deref() == Ok("1") {
|
||||
eprintln!("[provider-registry] FileBox: using core-ro (forced)");
|
||||
eprintln!("[provider/select:FileBox ring=1 src=static caps=[read]]");
|
||||
if diag::provider_log_enabled(quiet_pipe) {
|
||||
diag::provider_log_info("FileBox: using core-ro (forced)");
|
||||
diag::provider_log_select("FileBox", "1", "static", Some("[read]"));
|
||||
}
|
||||
Arc::new(CoreRoFileIo::new())
|
||||
}
|
||||
|
||||
@ -429,6 +429,12 @@ impl NyashRunner {
|
||||
0
|
||||
};
|
||||
|
||||
// Optional: print lightweight VM counters for diagnostics
|
||||
if crate::config::env::env_bool("NYASH_VM_STATS") {
|
||||
let (inst, br, cmp) = vm.stats_counters();
|
||||
eprintln!("[vm/stats] inst={} compare={} branch={}", inst, cmp, br);
|
||||
}
|
||||
|
||||
// Quiet mode: suppress "RC:" output for JSON-only pipelines
|
||||
if !quiet_pipe {
|
||||
println!("RC: {}", exit_code);
|
||||
|
||||
Reference in New Issue
Block a user