//! The Neural Engine is reported only once its rail is proved live. //! //! On macOS 27.0.1 an unprivileged reader's `ANE0` holds through real Neural //! Engine work: no advance in 25 sample intervals over 3 s of Core ML //! inference on the ANE, while root `powermetrics` read 0.47 J of ANE energy //! over the same span. A figure from it would read 0 J for that work. This //! runs in a process of its own, so the once-per-process proof starts unproved. #![cfg(target_os = "macos")] use std::time::Duration; use jcp_energy::{npu_rail_liveness, npu_rail_liveness_cached, CounterStatus, Fabric, FabricMeter}; #[test] fn the_neural_engine_is_reported_only_once_its_rail_is_proved_live() { let meter = FabricMeter::detect(); assert_eq!(npu_rail_liveness_cached(), None, "nothing has probed the ANE rail yet"); let readable = meter.readable(); assert!(!readable.iter().any(|(f, _)| *f == Fabric::Npu), "an unproved ANE rail was listed readable: {readable:?}"); let ((), readings) = meter.measure(|| std::thread::sleep(Duration::from_millis(50))); assert!(!readings.iter().any(|r| r.fabric == Fabric::Npu), "an unproved ANE rail gave a figure: {readings:?}"); // A load that never touches the Neural Engine cannot prove its rail live // on this host (macOS 27.0.1, unprivileged), whatever the rail does. let status = npu_rail_liveness(|| std::thread::sleep(Duration::from_millis(25))); eprintln!("npu rail liveness under a load that never touches the ANE: {status:?}; readable {readable:?}"); assert_ne!(status, CounterStatus::Live, "the ANE rail was proved live by a load that never touched the ANE"); assert_eq!(npu_rail_liveness_cached(), Some(status), "the proof was not cached"); assert!(!meter.readable().iter().any(|(f, _)| *f == Fabric::Npu)); }