diff --git a/src/uu/wc/locales/en-US.ftl b/src/uu/wc/locales/en-US.ftl index 52ea93291..ac22b1f1e 100644 --- a/src/uu/wc/locales/en-US.ftl +++ b/src/uu/wc/locales/en-US.ftl @@ -37,3 +37,4 @@ wc-debug-hw-unavailable = wc: debug: hardware support unavailable on this CPU wc-debug-hw-using = wc: debug: using hardware support (features: { $features }) wc-debug-hw-disabled-env = wc: debug: hardware support disabled by environment wc-debug-hw-disabled-glibc = wc: debug: hardware support disabled by GLIBC_TUNABLES ({ $features }) +wc-debug-hw-limited-glibc = wc: debug: hardware support limited by GLIBC_TUNABLES (disabled: { $disabled }; enabled: { $enabled }) diff --git a/src/uu/wc/locales/fr-FR.ftl b/src/uu/wc/locales/fr-FR.ftl index 641e68461..22efab71a 100644 --- a/src/uu/wc/locales/fr-FR.ftl +++ b/src/uu/wc/locales/fr-FR.ftl @@ -37,3 +37,4 @@ wc-debug-hw-unavailable = wc : debug : prise en charge matérielle indisponible wc-debug-hw-using = wc : debug : utilisation de l'accélération matérielle (fonctions : { $features }) wc-debug-hw-disabled-env = wc : debug : prise en charge matérielle désactivée par l'environnement wc-debug-hw-disabled-glibc = wc : debug : prise en charge matérielle désactivée par GLIBC_TUNABLES ({ $features }) +wc-debug-hw-limited-glibc = wc : debug : prise en charge matérielle limitée par GLIBC_TUNABLES (désactivé : { $disabled } ; activé : { $enabled }) diff --git a/src/uu/wc/src/count_fast.rs b/src/uu/wc/src/count_fast.rs index d2715f375..d20c53d4f 100644 --- a/src/uu/wc/src/count_fast.rs +++ b/src/uu/wc/src/count_fast.rs @@ -4,7 +4,7 @@ // file that was distributed with this source code. // cSpell:ignore sysconf -use crate::word_count::WordCount; +use crate::{wc_simd_allowed, word_count::WordCount}; use uucore::hardware::SimdPolicy; use super::WordCountable; @@ -233,7 +233,8 @@ pub(crate) fn count_bytes_chars_and_lines_fast< ) -> (WordCount, Option) { let mut total = WordCount::default(); let buf: &mut [u8] = &mut AlignedBuffer::default().data; - let simd_allowed = SimdPolicy::detect().allows_simd(); + let policy = SimdPolicy::detect(); + let simd_allowed = wc_simd_allowed(policy); loop { match handle.read(buf) { Ok(0) => return (total, None), diff --git a/src/uu/wc/src/wc.rs b/src/uu/wc/src/wc.rs index b7d22dd3a..81c445554 100644 --- a/src/uu/wc/src/wc.rs +++ b/src/uu/wc/src/wc.rs @@ -828,6 +828,55 @@ fn hardware_feature_label(feature: HardwareFeature) -> &'static str { } } +fn is_wc_simd_runtime_feature(feature: &HardwareFeature) -> bool { + matches!( + feature, + HardwareFeature::Avx2 | HardwareFeature::Sse2 | HardwareFeature::Asimd + ) +} + +fn is_wc_simd_debug_feature(feature: &HardwareFeature) -> bool { + matches!( + feature, + HardwareFeature::Avx512 + | HardwareFeature::Avx2 + | HardwareFeature::Sse2 + | HardwareFeature::Asimd + ) +} + +fn wc_simd_enabled_features(policy: &SimdPolicy) -> Vec { + policy + .iter_features() + .filter(is_wc_simd_runtime_feature) + .collect() +} + +fn wc_simd_disabled_features(policy: &SimdPolicy) -> Vec { + policy + .disabled_features() + .into_iter() + .filter(is_wc_simd_debug_feature) + .collect() +} + +fn wc_simd_disabled_runtime_features(policy: &SimdPolicy) -> Vec { + policy + .disabled_features() + .into_iter() + .filter(is_wc_simd_runtime_feature) + .collect() +} + +pub(crate) fn wc_simd_allowed(policy: &SimdPolicy) -> bool { + if !wc_simd_disabled_runtime_features(policy).is_empty() { + return false; + } + policy + .iter_features() + .any(|feature| is_wc_simd_runtime_feature(&feature)) +} + fn wc(inputs: &Inputs, settings: &Settings) -> UResult<()> { let mut total_word_count = WordCount::default(); let mut num_inputs: usize = 0; @@ -839,34 +888,41 @@ fn wc(inputs: &Inputs, settings: &Settings) -> UResult<()> { if settings.debug { let policy = SimdPolicy::detect(); - if policy.allows_simd() { - let enabled: Vec<&'static str> = - policy.iter_features().map(hardware_feature_label).collect(); - if enabled.is_empty() { - eprintln!("{}", translate!("wc-debug-hw-unavailable")); - } else { - eprintln!( - "{}", - translate!("wc-debug-hw-using", "features" => enabled.join(", ")) - ); - } - } else { - let disabled: Vec<&'static str> = policy - .disabled_features() - .into_iter() - .map(hardware_feature_label) - .collect(); - if disabled.is_empty() { - eprintln!("{}", translate!("wc-debug-hw-disabled-env")); - } else { - eprintln!( - "{}", - translate!( - "wc-debug-hw-disabled-glibc", - "features" => disabled.join(", ") - ) - ); - } + let enabled_features = wc_simd_enabled_features(policy); + let disabled_features = wc_simd_disabled_features(policy); + let disabled_runtime_features = wc_simd_disabled_runtime_features(policy); + + let enabled: Vec<&'static str> = enabled_features + .iter() + .copied() + .map(hardware_feature_label) + .collect(); + let disabled: Vec<&'static str> = disabled_features + .iter() + .copied() + .map(hardware_feature_label) + .collect(); + + let runtime_disabled = !disabled_runtime_features.is_empty(); + + match (enabled.is_empty(), runtime_disabled, disabled.is_empty()) { + (true, false, _) => eprintln!("{}", translate!("wc-debug-hw-unavailable")), + (_, true, _) => eprintln!( + "{}", + translate!("wc-debug-hw-disabled-glibc", "features" => disabled.join(", ")) + ), + (false, false, true) => eprintln!( + "{}", + translate!("wc-debug-hw-using", "features" => enabled.join(", ")) + ), + (false, false, false) => eprintln!( + "{}", + translate!( + "wc-debug-hw-limited-glibc", + "disabled" => disabled.join(", "), + "enabled" => enabled.join(", ") + ) + ), } } diff --git a/src/uucore/src/lib/features/hardware.rs b/src/uucore/src/lib/features/hardware.rs index f2fef8030..474990343 100644 --- a/src/uucore/src/lib/features/hardware.rs +++ b/src/uucore/src/lib/features/hardware.rs @@ -214,8 +214,9 @@ impl SimdPolicy { } } + /// Returns true if any SIMD feature remains enabled after applying GLIBC_TUNABLES. pub fn allows_simd(&self) -> bool { - self.disabled_by_env.is_empty() + self.iter_features().next().is_some() } pub fn disabled_features(&self) -> Vec {