feat(wc): enhance debug output for SIMD hardware support limitations

Add new localization strings and logic to provide detailed debug information when SIMD support is limited by GLIBC_TUNABLES, including lists of disabled and enabled features. Refactor SIMD allowance check for better accuracy in detecting runtime support.
This commit is contained in:
mattsu 2025-12-21 22:52:56 +09:00
parent a61c191b68
commit a640e0dbe5
5 changed files with 91 additions and 31 deletions

View file

@ -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 })

View file

@ -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 })

View file

@ -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<io::Error>) {
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),

View file

@ -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<HardwareFeature> {
policy
.iter_features()
.filter(is_wc_simd_runtime_feature)
.collect()
}
fn wc_simd_disabled_features(policy: &SimdPolicy) -> Vec<HardwareFeature> {
policy
.disabled_features()
.into_iter()
.filter(is_wc_simd_debug_feature)
.collect()
}
fn wc_simd_disabled_runtime_features(policy: &SimdPolicy) -> Vec<HardwareFeature> {
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(", ")
)
),
}
}

View file

@ -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<HardwareFeature> {