CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
159 lines
5.9 KiB
Rust
159 lines
5.9 KiB
Rust
//! Emulator registry primitives.
|
|
//!
|
|
//! Every emulator backend lives in its own crate and registers itself
|
|
//! into a global registry via [`inventory`] (see
|
|
//! [`crate::emulator::EmulatorBackendDef`]). This module assembles that
|
|
//! registry into a list of [`EmulatorInfo`] — each backend's static
|
|
//! [`EmulatorDescription`] plus its live runtime status (installed /
|
|
//! supported) — and provides the generic [`find`] / [`default_emulator`]
|
|
//! / [`make_def`] helpers that operate over a supplied slice of them.
|
|
//!
|
|
//! No backend is named here: the list is whatever set of backend
|
|
//! crates was compiled into the binary, so disabling a backend's
|
|
//! feature simply drops it from the registry.
|
|
//!
|
|
//! Named hardware agents ([`crate::agent::AgentDef`]) and system
|
|
//! topologies ([`crate::topology::TopologyDef`]) live in the
|
|
//! `mirage_builtin` crate; the on-disk store policy for them lives in
|
|
//! [`crate::agent::store`] / [`crate::topology::store`].
|
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
use crate::common::{MaybeRef, SimpleMap};
|
|
use crate::config::OptionDef;
|
|
use crate::emulator::{EmulatorBackendDef, EmulatorDef, EmulatorKind, ExecMode, SupportStatus};
|
|
use crate::topology::TopologyDef;
|
|
|
|
/// The canonical name of the built-in pass-through emulator. Only used
|
|
/// as a tie-breaker so [`default_emulator`] never picks the no-op
|
|
/// backend when a real one is available; the `noop` backend itself
|
|
/// lives in the `mirage_noop` crate.
|
|
pub const NOOP_NAME: &str = "noop";
|
|
|
|
/// A registry entry: a backend's static [`EmulatorDescription`]
|
|
/// flattened together with its live runtime status on this host.
|
|
///
|
|
/// [`EmulatorDescription`]: crate::emulator::EmulatorDescription
|
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
|
pub struct EmulatorInfo {
|
|
/// Canonical name of the backend (also its [`EmulatorKind`]).
|
|
pub name: String,
|
|
pub version: String,
|
|
pub description: String,
|
|
/// Schema of the options this backend accepts (empty when none).
|
|
pub options_schema: Vec<OptionDef>,
|
|
/// Plugin names this backend discovered on the current host.
|
|
pub plugins: Vec<String>,
|
|
/// `true` if this backend's runtime is present on this machine.
|
|
pub installed: bool,
|
|
/// Whether this host's hardware/environment can run the backend.
|
|
pub support: SupportStatus,
|
|
}
|
|
|
|
/// Build the full emulator registry by probing every backend that was
|
|
/// compiled into the binary. Each backend (registered via
|
|
/// [`inventory`]) contributes its description plus a live install /
|
|
/// support probe. Entries are returned sorted by name so the order is
|
|
/// deterministic regardless of link order.
|
|
pub fn registry() -> Vec<EmulatorInfo> {
|
|
let mut out: Vec<EmulatorInfo> = inventory::iter::<EmulatorBackendDef>
|
|
.into_iter()
|
|
.map(|def| {
|
|
let d = def.backend.description();
|
|
let mut plugins: Vec<String> = def
|
|
.backend
|
|
.discover_plugins()
|
|
.into_iter()
|
|
.flat_map(|selection| selection.into_keys())
|
|
.collect();
|
|
plugins.sort();
|
|
plugins.dedup();
|
|
EmulatorInfo {
|
|
name: d.name,
|
|
version: d.version,
|
|
description: d.description,
|
|
options_schema: d.options_schema,
|
|
plugins,
|
|
installed: def.backend.installed(),
|
|
support: def.backend.supported(),
|
|
}
|
|
})
|
|
.collect();
|
|
out.sort_by(|a, b| a.name.cmp(&b.name));
|
|
out
|
|
}
|
|
|
|
/// Lookup an emulator by its canonical name within `specs`.
|
|
pub fn find<'a>(specs: &'a [EmulatorInfo], name: &str) -> Option<&'a EmulatorInfo> {
|
|
specs.iter().find(|e| e.name == name)
|
|
}
|
|
|
|
/// The default emulator for new profiles when the user doesn't pick
|
|
/// one explicitly. Picks the first installed, non-noop entry in name
|
|
/// order, falling back to the `noop` entry (or the first entry if
|
|
/// `noop` is somehow absent).
|
|
pub fn default_emulator(specs: &[EmulatorInfo]) -> &EmulatorInfo {
|
|
specs
|
|
.iter()
|
|
.find(|e| e.name != NOOP_NAME && e.installed)
|
|
.or_else(|| specs.iter().find(|e| e.name == NOOP_NAME))
|
|
.or_else(|| specs.first())
|
|
.expect("emulator registry must not be empty")
|
|
}
|
|
|
|
/// Build an [`EmulatorDef`] for the given registry entry, using the
|
|
/// supplied system topology.
|
|
pub fn make_def(spec: &EmulatorInfo, topology: TopologyDef) -> EmulatorDef {
|
|
EmulatorDef {
|
|
emulator: EmulatorKind::from(spec.name.clone()),
|
|
plugins: Default::default(),
|
|
exec_mode: ExecMode::default(),
|
|
options: SimpleMap::default(),
|
|
topology: MaybeRef::Owned(topology),
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
fn info(name: &str, installed: bool) -> EmulatorInfo {
|
|
EmulatorInfo {
|
|
name: name.to_string(),
|
|
version: "0".to_string(),
|
|
description: String::new(),
|
|
options_schema: Vec::new(),
|
|
plugins: Vec::new(),
|
|
installed,
|
|
support: SupportStatus::supported("test"),
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn find_locates_by_name() {
|
|
let specs = [info("noop", true)];
|
|
assert_eq!(find(&specs, "noop").map(|e| e.name.as_str()), Some("noop"));
|
|
assert!(find(&specs, "bogus").is_none());
|
|
}
|
|
|
|
#[test]
|
|
fn default_prefers_installed_non_noop() {
|
|
let specs = [info("noop", true), info("rocjitsu", true)];
|
|
assert_eq!(default_emulator(&specs).name, "rocjitsu");
|
|
}
|
|
|
|
#[test]
|
|
fn default_falls_back_to_noop() {
|
|
let specs = [info("noop", true), info("hotswap", false)];
|
|
assert_eq!(default_emulator(&specs).name, "noop");
|
|
}
|
|
|
|
#[test]
|
|
fn registry_serializes_discovered_plugins() {
|
|
let mut emulator = info("rocjitsu", true);
|
|
emulator.plugins = vec!["logging".to_string(), "race".to_string()];
|
|
let json = serde_json::to_value(&emulator).unwrap();
|
|
assert_eq!(json["plugins"], serde_json::json!(["logging", "race"]));
|
|
}
|
|
}
|