我正在尝试优化一些矩阵计算,我想知道是否有可能在编译时检测SSE/SSE2/AVX/AVX2/AVX-512/AVX-128-FMA/KCVI [1]是否由编译器?理想情况下,对于GCC和Clang,但我只能管理其中一个.
我不确定它是否可能,也许我将使用自己的宏,但我更愿意检测它并要求用户选择它.
[1] "KCVI"代表骑士角矢量指令优化.像FFTW这样的库检测/利用这些较新的指令优化.
我试图找到潜在因子素数的除数(形式n!+ - 1的数量),因为我最近买了Skylake-X工作站,我认为我可以使用AVX512指令加快速度.
算法简单,主要步骤是对同一个除数重复取模.主要是循环大范围的n值.这是用c写的天真的方法(P是素数表):
uint64_t factorial_naive(uint64_t const nmin, uint64_t const nmax, const uint64_t *restrict P)
{
uint64_t n, i, residue;
for (i = 0; i < APP_BUFLEN; i++){
residue = 2;
for (n=3; n <= nmax; n++){
residue *= n;
residue %= P[i];
// Lets check if we found factor
if (nmin <= n){
if( residue == 1){
report_factor(n, -1, P[i]);
}
if(residue == P[i]- 1){
report_factor(n, 1, P[i]);
}
}
}
}
return EXIT_SUCCESS;
}
Run Code Online (Sandbox Code Playgroud)
这里的想法是针对同一组除数检查大范围的n,例如1,000,000 - > 10,000,000.因此,我们将以数百万次对相同的除数进行模数尊重.使用DIV非常慢,因此根据计算范围有几种可能的方法.在我的情况下,n很可能小于10 …
我正在测试台式机和服务器上的内存带宽。
Sklyake desktop 4 cores/8 hardware threads
Skylake server Xeon 8168 dual socket 48 cores (24 per socket) / 96 hardware threads
Run Code Online (Sandbox Code Playgroud)
系统的峰值带宽为
Peak bandwidth desktop = 2-channels*8*2400 = 38.4 GB/s
Peak bandwidth server = 6-channels*2-sockets*8*2666 = 255.94 GB/s
Run Code Online (Sandbox Code Playgroud)
我正在使用自己的STREAM三合一函数来测量带宽(稍后将提供完整代码)
void triad(double *a, double *b, double *c, double scalar, size_t n) {
#pragma omp parallel for
for(int i=0; i<n; i++) a[i] = b[i] + scalar*c[i];
}
Run Code Online (Sandbox Code Playgroud)
这是我得到的结果
Bandwidth (GB/s)
threads Desktop Server
1 28 16
2(24) 29 146 …
Run Code Online (Sandbox Code Playgroud) 在尝试使用内在函数和汇编来回答嵌入式广播时,我试图做这样的事情:
__m512 mul_broad(__m512 a, float b) {
int scratch = 0;
asm(
"vbroadcastss %k[scalar], %q[scalar]\n\t" // want vbr.. %xmm0, %zmm0
"vmulps %q[scalar], %[vec], %[vec]\n\t"
// how it's done for integer registers
"movw symbol(%q[inttmp]), %w[inttmp]\n\t" // movw symbol(%rax), %ax
"movsbl %h[inttmp], %k[inttmp]\n\t" // movsx %ah, %eax
: [vec] "+x" (a), [scalar] "+x" (b), [inttmp] "=r" (scratch)
:
:
);
return a;
}
Run Code Online (Sandbox Code Playgroud)
的GNU C 86操作数修饰符文档仅指定到改性剂q
(DI(DoubleInt)尺寸,64位).使用q
一个向量寄存器总会带给它归结为xmm
(从ymm
或zmm
). …
我有一个在支持AVX-512的Intel机器上运行的进程,但是这个进程不直接使用任何AVX-512指令(asm或内在函数)并且编译时-mno-avx512f
使编译器不插入任何AVX-512指令.
然而,它在减少的AVX turbo频率下无限运行.毫无疑问,有一个AVX-512指令在某个地方偷偷摸摸,通过一个库,(非常不可能)系统调用或类似的东西.
而不是尝试"二进制搜索"AVX-512指令来自哪里,有没有什么方法可以立即找到它,例如,捕获这样的指令?
操作系统是Ubuntu 16.04.
我目前正在编写一些针对英特尔即将推出的AVX-512 SIMD指令的代码,该指令支持512位操作.
现在假设有一个由16个SIMD寄存器表示的矩阵,每个寄存器包含16个32位整数(对应一行),如何用纯SIMD指令转置矩阵?
已经有解决方案分别用SSE和AVX2转置4x4或8x8矩阵.但我无法弄清楚如何使用AVX-512将其扩展到16x16.
有任何想法吗?
考虑像一个数组atomic<int32_t> shared_array[]
.如果你想SIMD矢量化for(...) sum += shared_array[i].load(memory_order_relaxed)
怎么办?或者在数组中搜索第一个非零元素,或者将其范围归零?这可能很少见,但考虑一下不允许在元素内撕裂的任何用例,但在元素之间重新排序很好. (也许是寻找CAS候选人的搜索).
我认为 x86对齐的向量加载/存储在实践中可以安全地用于带有mo_relaxed
操作的SIMD ,因为任何撕裂只会发生在当前硬件上最坏的8B边界(因为这是自然对齐的8B访问原子1的原因).不幸的是,英特尔的手册只说:
"可以使用多个存储器访问来实现访问大于四字的数据的x87指令或SSE指令."
无法保证这些组件访问是自然对齐,不重叠或其他任何内容.(有趣的事实:根据Agner Fog,大概是qword + word,fld m80
在Haswell上用2个加载uops和2个ALU uops完成x87 10字节加载.)
如果你想在面向未来的方式,当前的x86手册上说,未来所有的x86 CPU将努力向量化,你可以在8B块与加载/存储movq
/ movhps
.
或者你可以使用vpmaskmovd
带有全真掩码的256b,因为手册的操作部分用多个独立的32位负载来定义它,比如Load_32(mem + 4)
.这是否意味着每个元素都作为一个单独的32位访问,保证该元素内的原子性?
(在实际硬件上,它是Haswell上的1个负载和2个端口5 uops,或者Ryzen上只有1或2个负载+ ALU uops(128/256).我认为这是针对不需要从元素中抑制异常的情况进入一个未映射的页面,因为它可能会更慢(但IDK如果它需要微代码辅助).无论如何,这告诉我们它至少与vmovdqa
Haswell上的正常负载一样原子,但这告诉我们没有关于x86 Deathstation 9000 16B的信息/ 32B向量访问被分解为单字节访问,因此每个元素内可能会有撕裂.
我认为实际上可以安全地假设你不会在16,32或64位元素中撕裂任何真正的x86 CPU上的对齐矢量加载/存储,因为这对于已经有效的实现是没有意义的必须保持自然对齐的64位标量存储原子,但知道手册中的保证到底有多远是有趣的.)
收集(AVX2,AVX512)/ Scatter(AVX512)
类似vpgatherdd
的指令显然由多个独立的32b或64b访问组成.AVX2表格被记录为多次执行,FETCH_32BITS(DATA_ADDR);
因此可能会被通常的原子性保证所覆盖,并且如果它不跨越边界,则每个元素将以原子方式收集.
AVX512褶裥都记录在英特尔公司的PDF的insn参考手册作为
DEST[i+31:i] <- MEM[BASE_ADDR + SignExtend(VINDEX[i+31:i]) * …
我的CPU是AMD Ryzen 7 7840H,支持AVX-512指令集。当我运行.NET8程序时, 的值为Vector512.IsHardwareAccelerated
true。但System.Numerics.Vector<T>
仍然是256位,并没有达到512位。Vector<T>
为什么类型长度没有达到 512 位?目前是否不支持,或者我需要调整配置吗?
示例代码:
TextWriter writer = Console.Out;
writer.WriteLine(string.Format("Vector512.IsHardwareAccelerated:\t{0}", Vector512.IsHardwareAccelerated));
writer.WriteLine(string.Format("Vector.IsHardwareAccelerated:\t{0}", Vector.IsHardwareAccelerated));
writer.WriteLine(string.Format("Vector<byte>.Count:\t{0}\t# {1}bit", Vector<byte>.Count, Vector<byte>.Count * 8));
Run Code Online (Sandbox Code Playgroud)
检测结果:
Vector512.IsHardwareAccelerated: True
Vector.IsHardwareAccelerated: True
Vector<byte>.Count: 32 # 256bit
Run Code Online (Sandbox Code Playgroud) AVX512CD指令系列包括:VPCONFLICT,VPLZCNT和VPBROADCASTM.
AVX-512冲突检测(AVX-512CD)中的指令旨在帮助有效地计算通常无法安全矢量化的循环中元素的无冲突子集.
有哪些例子表明这些指令在向量化循环中有用?如果答案将包括标量循环及其矢量化对应物将会有所帮助.
谢谢!