对于GCC CFLAGS选项:-msse,-msse2,-mssse3,-msse4,-msse4.1,-msse4.2.它们是独家使用还是可以一起使用?
我的理解是,选择要设置的位置取决于程序将运行的目标拱,是否支持,这是正确的吗?
如果是这样,我怎么知道我的目标拱支持什么?在Linux中,我是cat/proc/cpuinfo,但是如果是mac还是Windows呢?
谢谢!
浮点值除法有_mm_div_ps,整数乘法有_mm_mullo_epi16.但是有什么整数除法(16位值)?我怎么进行这种划分?
我正在考虑更改一些目前需要16字节对齐数组的代码高性能代码,并用于_mm_load_ps放宽对齐约束和使用_mm_loadu_ps.关于SSE指令的内存对齐的性能影响有很多神话,所以我做了一个小的测试用例,它应该是一个内存带宽限制的循环.使用对齐或未对齐的加载内在函数,它通过大型数组运行100次迭代,使用SSE内在函数对元素求和.源代码在这里.https://gist.github.com/rmcgibbo/7689820
带有Sandy Bridge Core i5的64位Macbook Pro的结果如下.数字越小表示性能越快.当我阅读结果时,我发现在未对齐的内存上使用_mm_loadu_ps基本上没有性能损失.
我觉得这很令人惊讶.这是一个公平的测试/合理的结论吗?在哪些硬件平台上有区别?
$ gcc -O3 -msse aligned_vs_unaligned_load.c && ./a.out 200000000
Array Size: 762.939 MB
Trial 1
_mm_load_ps with aligned memory: 0.175311
_mm_loadu_ps with aligned memory: 0.169709
_mm_loadu_ps with unaligned memory: 0.169904
Trial 2
_mm_load_ps with aligned memory: 0.169025
_mm_loadu_ps with aligned memory: 0.191656
_mm_loadu_ps with unaligned memory: 0.177688
Trial 3
_mm_load_ps with aligned memory: 0.182507
_mm_loadu_ps with aligned memory: 0.175914
_mm_loadu_ps with unaligned memory: 0.173419
Trial 4
_mm_load_ps with aligned …Run Code Online (Sandbox Code Playgroud) 问题
我正在学习HPC和代码优化.我试图在Goto的开创性矩阵乘法论文(http://www.cs.utexas.edu/users/pingali/CS378/2008sp/papers/gotoPaper.pdf)中复制结果.尽管我付出了最大努力,但我无法超过理论CPU最高性能的50%.
背景
请参阅此处的相关问题(优化的2x2矩阵乘法:慢速装配与快速SIMD),包括有关我的硬件的信息
我尝试过的
这篇相关论文(http://www.cs.utexas.edu/users/flame/pubs/blis3_ipdps14.pdf)很好地描述了Goto的算法结构.我在下面提供了我的源代码.
我的问题
我要求一般帮助.我一直在研究这个问题太久了,已经尝试了很多不同的算法,内联汇编,各种尺寸的内核(2x2,4x4,2x8,...,mxn m和n大),但我似乎无法打破50%CPU Gflops.这纯粹是出于教育目的,而不是作业.
源代码
希望是可以理解的.如果没有请问.我设置了宏结构(for循环),如上面第2篇文章中所述.我按照两篇论文中的讨论打包矩阵,并在图11中以图形方式显示(http://www.cs.utexas.edu/users/flame/pubs/BLISTOMSrev2.pdf).我的内核计算2x8块,因为这似乎是Nehalem架构的最佳计算(参见GotoBLAS源代码 - 内核).内核基于计算排名1更新的概念,如此处所述(http://code.google.com/p/blis/source/browse/config/template/kernels/3/bli_gemm_opt_mxn.c)
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>
#include <x86intrin.h>
#include <math.h>
#include <omp.h>
#include <stdint.h>
// define some prefetch functions
#define PREFETCHNTA(addr,nrOfBytesAhead) \
_mm_prefetch(((char *)(addr))+nrOfBytesAhead,_MM_HINT_NTA)
#define PREFETCHT0(addr,nrOfBytesAhead) \
_mm_prefetch(((char *)(addr))+nrOfBytesAhead,_MM_HINT_T0)
#define PREFETCHT1(addr,nrOfBytesAhead) \
_mm_prefetch(((char *)(addr))+nrOfBytesAhead,_MM_HINT_T1)
#define PREFETCHT2(addr,nrOfBytesAhead) \
_mm_prefetch(((char *)(addr))+nrOfBytesAhead,_MM_HINT_T2)
// define a min function
#ifndef min
#define min( a, b ) ( …Run Code Online (Sandbox Code Playgroud) 我在哪里可以找到有关常见SIMD技巧的信息?我有一个指令集,知道如何编写非棘手的SIMD代码,但我知道,SIMD现在功能更强大.它可以保存复杂的条件无分支代码.
例如(ARMv6),以下指令序列将Rd的每个字节设置为等于Ra和Rb的相应字节的无符号最小值:
USUB8 Rd, Ra, Rb
SEL Rd, Rb, Ra
Run Code Online (Sandbox Code Playgroud)
教程/非常见SIMD技术的链接也很好:) ARMv6对我来说是最有趣的,但x86(SSE,...)/ Neon(在ARMv7中)/其他也很好.
我最近以内在函数的形式使用了x86 SIMD指令(SSE1234).我发现令人沮丧的是,SSE ISA有几个简单的指令,只能用于浮点数或仅用于整数,但理论上它们应该同样适用于两者.例如,float和double向量都有指令从地址(movhps,movhpd)加载更高的64位128位向量,但是没有这样的整数向量指令.
我的问题:
在整数向量上使用浮点指令时是否有任何理由期望性能受到影响,例如使用movhps将数据加载到整数向量?
我写了几个测试来检查,但我认为他们的结果不可信.编写一个正确的测试来探索这些事情的所有极端情况真的很难,特别是在这里可能涉及指令调度时.
相关问题:
其他平凡相似的东西也有几个基本相同的指令.例如,我可以使用por,orps或orpd按位OR .任何人都可以解释这些附加说明的目的是什么?我想这可能与应用于每条指令的不同调度算法有关.
我想添加一个SSE寄存器的四个组件来获得一个浮点数.这是我现在这样做的方式:
float a[4];
_mm_storeu_ps(a, foo128);
float x = a[0] + a[1] + a[2] + a[3];
Run Code Online (Sandbox Code Playgroud)
是否有直接实现此目的的SSE指令?
我目前正在开发一个开源的3D应用程序框架的C++(用C++ 11).我自己的数学库的设计类似于XNA数学库,同时考虑了SIMD.但目前它并不是很快,而且它在内存中存在问题,但在另一个问题上更多.
几天前我问自己为什么要编写自己的SSE代码.编译器还可以在启用优化时生成高优化代码.我也可以使用GCC的" 向量扩展 " .但这一切都不是真正的便携式.
我知道当我使用自己的SSE代码时,我有更多的控制权,但通常这种控制是不公平的.
SSE的一个大问题是使用动态内存,这在内存池和面向数据的设计的帮助下,尽可能地受到限制.
现在问我的问题:
我应该使用裸SSE吗?也许是封装的.
__m128 v1 = _mm_set_ps(0.5f, 2, 4, 0.25f);
__m128 v2 = _mm_set_ps(2, 0.5f, 0.25f, 4);
__m128 res = _mm_mul_ps(v1, v2);
Run Code Online (Sandbox Code Playgroud)或者编译器应该做脏工作吗?
float v1 = {0.5f, 2, 4, 0.25f};
float v2 = {2, 0.5f, 0.25f, 4};
float res[4];
res[0] = v1[0]*v2[0];
res[1] = v1[1]*v2[1];
res[2] = v1[2]*v2[2];
res[3] = v1[3]*v2[3];
Run Code Online (Sandbox Code Playgroud)或者我应该使用SIMD和其他代码吗?就像具有SIMD操作的动态容器类一样,需要额外的load和store指令.
Pear3D::Vector4f* v1 = new Pear3D::Vector4f(0.5f, …Run Code Online (Sandbox Code Playgroud)许多SSE"mov"指令指定它们正在移动浮点值.例如:
为什么这些指令只是说它们移动32位或64位值?如果它们只是移动位,为什么指令指定它们是浮点值?当然,无论你是否将这些位解释为浮点,它们都能工作吗?
(注意:虽然这个问题是关于"存储"的,但"加载"情况具有相同的问题并且是完全对称的.)
SSE内在函数提供_mm_storeu_pd具有以下签名的函数:
void _mm_storeu_pd (double *p, __m128d a);
Run Code Online (Sandbox Code Playgroud)
所以,如果我有两个双精度矢量,并且我想将它存储到两个双精度数组中,我可以使用这个内在函数.
但是,我的矢量不是两个双打; 它是两个64位整数,我想将它存储到两个64位整数的数组中.也就是说,我想要一个具有以下签名的函数:
void _mm_storeu_epi64 (int64_t *p, __m128i a);
Run Code Online (Sandbox Code Playgroud)
但内在函数没有提供这样的功能.他们最接近的是_mm_storeu_si128:
void _mm_storeu_si128 (__m128i *p, __m128i a);
Run Code Online (Sandbox Code Playgroud)
问题是这个函数需要一个指针__m128i,而我的数组是一个数组int64_t.通过错误类型的指针写入对象违反了严格的别名,并且肯定是未定义的行为.我担心我的编译器现在或将来会重新排序或以其他方式优化存储,从而以奇怪的方式破坏我的程序.
要清楚,我想要的是一个我可以这样调用的函数:
__m128i v = _mm_set_epi64x(2,1);
int64_t ra[2];
_mm_storeu_epi64(&ra[0], v); // does not exist, so I want to implement it
Run Code Online (Sandbox Code Playgroud)
以下是创建此类功能的六次尝试.
void _mm_storeu_epi64(int64_t *p, __m128i a) {
_mm_storeu_si128(reinterpret_cast<__m128i *>(p), a);
}
Run Code Online (Sandbox Code Playgroud)
这似乎有我担心的严格别名问题.
void _mm_storeu_epi64(int64_t *p, __m128i a) {
_mm_storeu_si128(static_cast<__m128i *>(static_cast<void *>(p)), a);
}
Run Code Online (Sandbox Code Playgroud)