-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
fix(wc):GNU wc-cpu.sh #9144
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(wc):GNU wc-cpu.sh #9144
Changes from all commits
5a6f263
15eacb6
a61c191
a640e0d
62673fc
39615a3
b0ededa
7465137
b2fe861
3f2bb5f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -29,9 +29,10 @@ use uucore::translate; | |
| use uucore::{ | ||
| error::{FromIo, UError, UResult}, | ||
| format_usage, | ||
| hardware::{HardwareFeature, HasHardwareFeatures as _, SimdPolicy}, | ||
| parser::shortcut_value_parser::ShortcutValueParser, | ||
| quoting_style::{self, QuotingStyle}, | ||
| show, | ||
| show, show_error, | ||
| }; | ||
|
|
||
| use crate::{ | ||
|
|
@@ -49,6 +50,7 @@ struct Settings<'a> { | |
| show_lines: bool, | ||
| show_words: bool, | ||
| show_max_line_length: bool, | ||
| debug: bool, | ||
| files0_from: Option<Input<'a>>, | ||
| total_when: TotalWhen, | ||
| } | ||
|
|
@@ -62,6 +64,7 @@ impl Default for Settings<'_> { | |
| show_lines: true, | ||
| show_words: true, | ||
| show_max_line_length: false, | ||
| debug: false, | ||
| files0_from: None, | ||
| total_when: TotalWhen::default(), | ||
| } | ||
|
|
@@ -85,6 +88,7 @@ impl<'a> Settings<'a> { | |
| show_lines: matches.get_flag(options::LINES), | ||
| show_words: matches.get_flag(options::WORDS), | ||
| show_max_line_length: matches.get_flag(options::MAX_LINE_LENGTH), | ||
| debug: matches.get_flag(options::DEBUG), | ||
| files0_from, | ||
| total_when, | ||
| }; | ||
|
|
@@ -95,6 +99,7 @@ impl<'a> Settings<'a> { | |
| Self { | ||
| files0_from: settings.files0_from, | ||
| total_when, | ||
| debug: settings.debug, | ||
| ..Default::default() | ||
| } | ||
| } | ||
|
|
@@ -122,6 +127,7 @@ mod options { | |
| pub static MAX_LINE_LENGTH: &str = "max-line-length"; | ||
| pub static TOTAL: &str = "total"; | ||
| pub static WORDS: &str = "words"; | ||
| pub static DEBUG: &str = "debug"; | ||
| } | ||
| static ARG_FILES: &str = "files"; | ||
| static STDIN_REPR: &str = "-"; | ||
|
|
@@ -445,6 +451,12 @@ pub fn uu_app() -> Command { | |
| .help(translate!("wc-help-words")) | ||
| .action(ArgAction::SetTrue), | ||
| ) | ||
| .arg( | ||
| Arg::new(options::DEBUG) | ||
| .long(options::DEBUG) | ||
| .action(ArgAction::SetTrue) | ||
| .hide(true), | ||
| ) | ||
| .arg( | ||
| Arg::new(ARG_FILES) | ||
| .action(ArgAction::Append) | ||
|
|
@@ -805,6 +817,74 @@ fn escape_name_wrapper(name: &OsStr) -> String { | |
| .expect("All escaped names with the escaping option return valid strings.") | ||
| } | ||
|
|
||
| fn hardware_feature_label(feature: HardwareFeature) -> &'static str { | ||
| match feature { | ||
| HardwareFeature::Avx512 => "AVX512F", | ||
| HardwareFeature::Avx2 => "AVX2", | ||
| HardwareFeature::PclMul => "PCLMUL", | ||
| HardwareFeature::Vmull => "VMULL", | ||
| HardwareFeature::Sse2 => "SSE2", | ||
| HardwareFeature::Asimd => "ASIMD", | ||
| } | ||
| } | ||
|
|
||
| fn is_simd_runtime_feature(feature: &HardwareFeature) -> bool { | ||
| matches!( | ||
| feature, | ||
| HardwareFeature::Avx2 | HardwareFeature::Sse2 | HardwareFeature::Asimd | ||
| ) | ||
| } | ||
|
|
||
| fn is_simd_debug_feature(feature: &HardwareFeature) -> bool { | ||
| matches!( | ||
| feature, | ||
| HardwareFeature::Avx512 | ||
| | HardwareFeature::Avx2 | ||
| | HardwareFeature::Sse2 | ||
| | HardwareFeature::Asimd | ||
| ) | ||
| } | ||
|
|
||
| struct WcSimdFeatures { | ||
| enabled: Vec<HardwareFeature>, | ||
| disabled: Vec<HardwareFeature>, | ||
| disabled_runtime: Vec<HardwareFeature>, | ||
| } | ||
|
|
||
| fn wc_simd_features(policy: &SimdPolicy) -> WcSimdFeatures { | ||
| let enabled = policy | ||
| .iter_features() | ||
| .filter(is_simd_runtime_feature) | ||
| .collect(); | ||
|
|
||
| let mut disabled = Vec::new(); | ||
| let mut disabled_runtime = Vec::new(); | ||
| for feature in policy.disabled_features() { | ||
| if is_simd_debug_feature(&feature) { | ||
| disabled.push(feature); | ||
| } | ||
| if is_simd_runtime_feature(&feature) { | ||
| disabled_runtime.push(feature); | ||
| } | ||
| } | ||
|
|
||
| WcSimdFeatures { | ||
| enabled, | ||
| disabled, | ||
| disabled_runtime, | ||
| } | ||
| } | ||
|
|
||
| pub(crate) fn wc_simd_allowed(policy: &SimdPolicy) -> bool { | ||
| let disabled_features = policy.disabled_features(); | ||
| if disabled_features.iter().any(is_simd_runtime_feature) { | ||
| return false; | ||
| } | ||
| policy | ||
| .iter_features() | ||
| .any(|feature| is_simd_runtime_feature(&feature)) | ||
| } | ||
|
|
||
| fn wc(inputs: &Inputs, settings: &Settings) -> UResult<()> { | ||
| let mut total_word_count = WordCount::default(); | ||
| let mut num_inputs: usize = 0; | ||
|
|
@@ -814,6 +894,51 @@ fn wc(inputs: &Inputs, settings: &Settings) -> UResult<()> { | |
| _ => (compute_number_width(inputs, settings), true), | ||
| }; | ||
|
|
||
| if settings.debug { | ||
| let policy = SimdPolicy::detect(); | ||
| let features = wc_simd_features(policy); | ||
|
|
||
| let enabled: Vec<&'static str> = features | ||
| .enabled | ||
| .iter() | ||
| .copied() | ||
| .map(hardware_feature_label) | ||
| .collect(); | ||
| let disabled: Vec<&'static str> = features | ||
| .disabled | ||
| .iter() | ||
| .copied() | ||
| .map(hardware_feature_label) | ||
| .collect(); | ||
|
Comment on lines
+901
to
+912
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why these two ?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. enabled is derived from policy.iter_features() (hardware minus GLIBC_TUNABLES‑disabled), while disabled is the subset explicitly disabled by GLIBC_TUNABLES for debug output. They’re intentionally different sets, so you can have both when some SIMD features are available and others are disabled |
||
|
|
||
| let enabled_empty = enabled.is_empty(); | ||
| let disabled_empty = disabled.is_empty(); | ||
|
Comment on lines
+914
to
+915
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same |
||
| let runtime_disabled = !features.disabled_runtime.is_empty(); | ||
|
|
||
| if enabled_empty && !runtime_disabled { | ||
| show_error!("{}", translate!("wc-debug-hw-unavailable")); | ||
| } else if runtime_disabled { | ||
| show_error!( | ||
| "{}", | ||
| translate!("wc-debug-hw-disabled-glibc", "features" => disabled.join(", ")) | ||
| ); | ||
| } else if !enabled_empty && disabled_empty { | ||
| show_error!( | ||
| "{}", | ||
| translate!("wc-debug-hw-using", "features" => enabled.join(", ")) | ||
| ); | ||
| } else { | ||
| show_error!( | ||
| "{}", | ||
| translate!( | ||
| "wc-debug-hw-limited-glibc", | ||
| "disabled" => disabled.join(", "), | ||
| "enabled" => enabled.join(", ") | ||
| ) | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| for maybe_input in inputs.try_iter(settings)? { | ||
| num_inputs += 1; | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should we cache this ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since it's already cached elsewhere, it's a tough call whether to cache it here.