我正在做一些统计计算.我需要它们快速,所以我重写了大部分内容以使用SSE.我对它很陌生,所以我想知道这里的正确方法是什么:
据我所知,SSE中没有log2或ln功能,至少不能达到4.1,这是我使用的硬件支持的最新版本.
是否更好:
这将是我发布的第一个SO问题!
std::cout << "Hello mighty StackOverflow!" << std::endl;
Run Code Online (Sandbox Code Playgroud)
我正在尝试使用英特尔的SSE4.2和/或AVX内在函数优化立体视觉应用的"块匹配"实现.我正在使用"绝对差异之和"来找到最佳匹配块.在我的情况下blockSize将是一个奇数,如3或5.这是我的C++代码片段:
for (int i = 0; i < rows; ++i) {
for (int j = 0; j < cols; ++j) {
minS = INT_MAX;
for (int k = 0; k <= beta; ++k) {
S = 0;
for (int l = i; l < i + blockSize; ++l) {
for (int m = j; m <= j + blockSize ; ++m) {
// adiff(a,b) === abs(a-b)
S += …Run Code Online (Sandbox Code Playgroud) 我正在尝试加速多核架构上的矩阵乘法.为此,我尝试同时使用线程和SIMD.但我的结果并不好.我通过顺序矩阵乘法测试加速:
void sequentialMatMul(void* params)
{
cout << "SequentialMatMul started.";
int i, j, k;
for (i = 0; i < N; i++)
{
for (k = 0; k < N; k++)
{
for (j = 0; j < N; j++)
{
X[i][j] += A[i][k] * B[k][j];
}
}
}
cout << "\nSequentialMatMul finished.";
}
Run Code Online (Sandbox Code Playgroud)
我尝试将线程和SIMD添加到矩阵乘法中,如下所示:
void threadedSIMDMatMul(void* params)
{
bounds *args = (bounds*)params;
int lowerBound = args->lowerBound;
int upperBound = args->upperBound;
int idx = args->idx;
int i, j, k;
for (i …Run Code Online (Sandbox Code Playgroud) 我正在尝试使用System.Numerics.Vector(T)来矢量化算法并利用CPU的SIMD操作.但是,我的矢量实现比我原来的实现要慢得多.有没有使用可能没有记录的Vector的技巧?这里的具体用途是尝试加速数据的kb.
不幸的是,我在其上找到的几乎所有文档都基于RyuJIT的预发布版本,我不知道有多少这些材料可以移植到.NET Native.
当我在Vector xor操作期间检查反汇编时,它显示:
00007FFB040A9C10 xor eax,eax
00007FFB040A9C12 mov qword ptr [rcx],rax
00007FFB040A9C15 mov qword ptr [rcx+8],rax
00007FFB040A9C19 mov rax,qword ptr [r8]
00007FFB040A9C1C xor rax,qword ptr [rdx]
00007FFB040A9C1F mov qword ptr [rcx],rax
00007FFB040A9C22 mov rax,qword ptr [r8+8]
00007FFB040A9C26 xor rax,qword ptr [rdx+8]
00007FFB040A9C2A mov qword ptr [rcx+8],rax
00007FFB040A9C2E mov rax,rcx
Run Code Online (Sandbox Code Playgroud)
为什么不使用xmm寄存器和SIMD指令呢?同样奇怪的是,SIMD指令是针对此代码的一个版本生成的,我没有明确地向量化,但它们从未被执行,有利于常规寄存器和指令.
我确保我在Release,x64,Optimize代码启用的情况下运行.我看到了x86编译的类似行为.我在机器级别的东西上有点新手,所以它可能只是在这里发生了一些我不能正确理解的东西.
Framework版本为4.6,Vector.IsHardwareAccelerated在运行时为false.
更新: "使用.NET Native工具链编译"是罪魁祸首.启用它会导致Vector.IsHardwareAccelerated == false; 禁用它会导致Vector.IsHardwareAccelerated == true.我已经确认,当禁用.NET Native时,编译器会使用ymm寄存器生成AVX指令.这导致了一个问题......为什么在.NET Native中没有启用SIMD?有什么办法可以改变吗?
更新Tangent:我发现自动SSE矢量化数组代码未被执行的原因是因为编译器插入了一条指令,该指令查看数组的起始位置是否低于最后一个元素之一的地址数组,如果是,只使用普通寄存器.我认为这必定是编译器中的一个错误,因为按照惯例,数组的开头应始终位于比其最后一个元素低的地址.它是测试每个操作数数组的内存地址的一组指令的一部分,我想确保它们不重叠.我已为此提交了Microsoft Connect错误报告:https://connect.microsoft.com/VisualStudio/feedback/details/1831117
我有一些适用于__m128值的代码.我在这些值上使用x86-64 SSE内在函数,我发现如果值在内存中未对齐,我会崩溃.这是由于我的编译器(在此实例中为clang)仅生成对齐的加载指令.
我是否可以指示我的编译器生成未对齐的加载,无论是全局加载还是某些值(可能带有某种注释)?
我首先得到未对齐值的原因是我试图节省内存.我有一个struct大致如下:
#pragma pack(push, 4)
struct Foobar {
__m128 a;
__m128 b;
int c;
};
#pragma pack(pop)
Run Code Online (Sandbox Code Playgroud)
然后我创建了这些结构的数组.数组中的第二个元素从36个字节开始,这不是16的倍数.
我知道我可以切换到数组表示的结构,或者删除打包编译指示(代价是将结构的大小从36增加到48字节); 但我也知道,未对齐的载荷现在并不那么昂贵,并且想先尝试一下.
更新以回答以下一些评论:
我的实际代码更接近于此:
struct Vector4 {
__m128 data;
Vector4(__m128 v) : data(v) {}
};
struct Foobar {
Vector4 a;
Vector4 b;
int c;
}
Run Code Online (Sandbox Code Playgroud)
然后我有一些实用功能,例如:
inline Vector4 add( const Vector4& a, const Vector4 &b ) {
return Vector4(_mm_add_ps(a.data, b.data));
}
inline Vector4 subtract( const Vector4& a, const Vector4& b ) {
return Vector4(_mm_sub_ps(a.data, b.data));
} …Run Code Online (Sandbox Code Playgroud) 这是我的想象力,还是PNOTSSE和AVX失踪的指令?也就是说,翻转向量中的每一位的指令.
如果是,是否有比PXOR使用所有1的向量更好的模拟方法?非常烦人,因为我需要设置所有1的向量来使用该方法.
我想用JavaScript编写需要大量数值计算的应用程序.但是,我对客户端JavaScript中有效的线性代数式计算的状态非常困惑.似乎有很多方法,但没有明确表明他们的准备情况.它们中的大多数似乎都限制了允许计算的向量和矩阵的大小.
显然允许GPU上的矢量和矩阵计算,但我不清楚其局限性.围绕此库尝试的 包装器似乎限制了矩阵和向量的大小.这是一个实际的限制(浏览器不支持其他任何东西)或只是开发限制(有人需要编写代码)?
WebCL是OpenCL的一个提议的浏览器级实现,但似乎停留在开发中.
Apple最近提出了一种名为WebGPU的 WebCL替代方案.到目前为止,有一个原型和演示,但我不清楚这是否会被广泛采用.
Mozilla已经推出了一个用于SIMD操作的API,但它只有实验支持.
JavaScript支持浏览器端的矢量化计算吗?
笔记:
我的问题不是"JavaScript中的数值计算有什么好的库",而是"JavaScrpt中的矢量化操作是否可行?" 可接受的答案将链接到在非实验性浏览器中工作的矢量化计算的演示.
我可能会对SIMD,矢量化和GPU计算感到困惑.我认为在这种情况下同义地使用它们是可以的,因为它们都允许通过使用专门的计算机硬件进行涉及高维向量的有效计算.
此代码在调试模式下工作,但由于在释放模式下断言而导致混乱.
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);
}
}
Run Code Online (Sandbox Code Playgroud)
(游乐场)
我有一个有趣的问题,想不出用矢量化代码解决的有效方法。
我有一个ymm包含 8 个 32 位整数的寄存器,其中每个整数由以下部分组成:
8x 个3bit“个体”值8位包含一个单 3位值,“无关”这个问题,但最好我会保持这个值不变,而不会影响3位值。我可以3自由地在前 8 位内移动那个位值,但我想理想地保留在那里的某个地方......我想要做的是找到一种方法来“转置”3 位值,以便(显示前 3 个元素):
Legend:
z -> 8 Top-level bits I'd like to keep in place/don't care about)
a..x -> groups of 3-bit values I'd like to transpose over the ymm register
vvvv Source vvvv
-----------------
|MSB LSB|MSB LSB|MSB LSB|...
|zzzzzzzz...............cccbbbaaa|zzzzzzzz...............kkkjjjiii|zzzzzzzz...............sssrrrqqq|...
|zzzzzzzz...............qqqiiiaaa|zzzzzzzz...............rrrjjjbbb|zzzzzzzz...............ssskkkccc|...
-----------------
^^^^ Dest ^^^^
Run Code Online (Sandbox Code Playgroud)
我可以执行 8x( extract+ pdep+ …
假设我们想快速找到数组中第一个非零元素的索引,效果如下
fn leading_zeros(arr: &[u32]) -> Option<usize> {
arr.iter().position(|&x| x != 0)
}
Run Code Online (Sandbox Code Playgroud)
但是,这会被编译为逐一检查,rustc如下所示。u128通过使用如下类型检查单词 4 by 4,可以稍微加快速度。这使我的机器的速度提高了大约 3 倍。
fn leading_zeros_wide(arr: &[u32]) -> Option<usize> {
let (beg, mid, _) = unsafe { arr.align_to::<u128>() };
beg.iter().position(|&x| x != 0).or_else(|| {
let left = beg.len() + 4 * mid.iter().position(|&x| x != 0).unwrap_or(mid.len());
arr[left..].iter().position(|&x| x != 0).map(|p| p + left)
})
}
Run Code Online (Sandbox Code Playgroud)
有没有办法让它更快?
这是我用来确定 3 倍加速的基准:
#![feature(test)]
extern crate test;
fn v() -> Box<[u32]> {
std::iter::repeat(0).take(1000).collect()
}
// …Run Code Online (Sandbox Code Playgroud) simd ×10
sse ×5
c ×3
avx ×2
c++ ×2
rust ×2
.net ×1
.net-native ×1
assembly ×1
avx2 ×1
intrinsics ×1
javascript ×1
logarithm ×1
matrix ×1
optimization ×1
performance ×1
uwp ×1
vector ×1
x86 ×1
x86-64 ×1