gpt4 book ai didi

rust - SIMD 代码在 Debug 中有效,但在 Release 中无效

转载 作者:行者123 更新时间:2023-11-29 07:44:29 24 4
gpt4 key购买 nike

此代码在 Debug模式下工作,但在 Release模式下会因为断言而崩溃。

use std::arch::x86_64::*;

fn main() {
unsafe {
let a = vec![2.0f32, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0];
let b = -1.0f32;

let ar = _mm256_loadu_ps(a.as_ptr());
println!("ar: {:?}", ar);

let br = _mm256_set1_ps(b);
println!("br: {:?}", br);

let mut abr = _mm256_setzero_ps();
println!("abr: {:?}", abr);

abr = _mm256_fmadd_ps(ar, br, abr);
println!("abr: {:?}", abr);

let mut ab = [0.0; 8];
_mm256_storeu_ps(ab.as_mut_ptr(), abr);
println!("ab: {:?}", ab);

assert_eq!(ab[0], -2.0f32);
}
}

( Playground )

最佳答案

我确实可以确认这段代码会导致断言在 Release模式下失败:

$ cargo run --release
Finished release [optimized] target(s) in 0.00s
Running `target/release/so53831502`
ar: __m256(2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
br: __m256(-1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0)
abr: __m256(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
abr: __m256(-1.0, -1.0, -1.0, -1.0, 0.0, 0.0, 0.0, 0.0)
ab: [-1.0, -1.0, -1.0, -1.0, 0.0, 0.0, 0.0, 0.0]
thread 'main' panicked at 'assertion failed: `(left == right)`
left: `-1.0`,
right: `-2.0`', src/main.rs:24:9

这似乎是一个编译器错误,请参阅 herehere .特别是,您正在调用类似 _mm256_set1_ps 的例程和 _mm256_fmadd_ps ,这需要 CPU 功能 avxfma分别,但您的代码和编译命令均未向编译器指示应使用此类功能。

解决这个问题的一种方法是告诉编译器用 avx 编译整个程序。和 fma启用的功能,如下所示:

$ RUSTFLAGS="-C target-feature=+avx,+fma" cargo run --release
Compiling so53831502 v0.1.0 (/tmp/so53831502)
Finished release [optimized] target(s) in 0.36s
Running `target/release/so53831502`
ar: __m256(2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
br: __m256(-1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0)
abr: __m256(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
abr: __m256(-2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
ab: [-2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]

另一种实现相同结果的方法是告诉编译器使用您的 CPU 上所有可用的 CPU 功能:

$ RUSTFLAGS="-C target-cpu=native" cargo run --release
Compiling so53831502 v0.1.0 (/tmp/so53831502)
Finished release [optimized] target(s) in 0.34s
Running `target/release/so53831502`
ar: __m256(2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
br: __m256(-1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0)
abr: __m256(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
abr: __m256(-2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
ab: [-2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]

但是,这两个编译命令生成的二进制文件只能在支持 avx 的 CPU 上运行和 fma特征。如果这对您来说不是问题,那么这是一个很好的解决方案。如果您想构建可移植的二进制文件,那么您可以在运行时执行 CPU 功能检测,并在启用特定 CPU 功能的情况下编译某些功能。然后,您有责任保证仅在启用并可用相应的 CPU 功能时才调用上述函数。此过程记录为 dynamic CPU feature detection 的一部分节std::arch文档。

这是一个使用运行时 CPU 特征检测的示例:

use std::arch::x86_64::*;
use std::process;

fn main() {
if is_x86_feature_detected!("avx") && is_x86_feature_detected!("fma") {
// SAFETY: This is safe because we're guaranteed to support the
// necessary CPU features.
unsafe { doit(); }
} else {
eprintln!("unsupported CPU");
process::exit(1);
}
}

#[target_feature(enable = "avx,fma")]
unsafe fn doit() {
let a = vec![2.0f32, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0];
let b = -1.0f32;

let ar = _mm256_loadu_ps(a.as_ptr());
println!("ar: {:?}", ar);

let br = _mm256_set1_ps(b);
println!("br: {:?}", br);

let mut abr = _mm256_setzero_ps();
println!("abr: {:?}", abr);

abr = _mm256_fmadd_ps(ar, br, abr);
println!("abr: {:?}", abr);

let mut ab = [0.0; 8];
_mm256_storeu_ps(ab.as_mut_ptr(), abr);
println!("ab: {:?}", ab);

assert_eq!(ab[0], -2.0f32);
}

要运行它,您不再需要设置任何编译标志:

$ cargo run --release
Compiling so53831502 v0.1.0 (/tmp/so53831502)
Finished release [optimized] target(s) in 0.29s
Running `target/release/so53831502`
ar: __m256(2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
br: __m256(-1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0)
abr: __m256(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
abr: __m256(-2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
ab: [-2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]

如果您在不支持 avx 的 CPU 上运行生成的二进制文件或 fma , 然后程序应该退出并显示一条错误消息:unsupported CPU .

一般来说,我认为 std::arch 的文档可以改进。特别是,您需要拆分代码的关键边界取决于您的向量类型是否出现在您的函数签名中。即 doit routine 不需要标准 x86(或 x86_64)函数 ABI 之外的任何东西来调用,因此可以安全地从不支持 avx 的函数调用或 fma .但是,在内部,已告知该函数使用基于给定 CPU 功能的附加指令集扩展来编译其代码。这是通过 target_feature 实现的属性。例如,如果您提供了不正确的目标特征:

#[target_feature(enable = "ssse3")]
unsafe fn doit() {
// ...
}

然后该程序表现出与您的初始程序相同的行为。

关于rust - SIMD 代码在 Debug 中有效,但在 Release 中无效,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53831502/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com