我必须使用SSE扩展来优化一段代码.我的目标平台是Windows和Linux,因此我使用MS编译器(VStudio)和GCC编译器构建我的应用程序.
SSE涉及哪些方法?我可以找到很多关于如何在GCC中使用SSE的例子,但它们似乎与MS编译器不兼容.是否存在milti-platform SSE方法?
如果我有一个x86的指令缓冲区,有一种简单的方法来检查一条指令是否是SSE指令而不必检查操作码是否在SSE指令的范围内?我的意思是有一个可以检查的公共指令前缀或处理器状态(例如寄存器)吗?
我总结两个数组并输出第三个数组(不是减少).像这样:
void add_scalar(float* result, const float* a, const float* b, const int N) {
for(int i = 0; i<N; i++) {
result[i] = a[i] + b[i];
}
}
Run Code Online (Sandbox Code Playgroud)
我想以最大吞吐量来做这件事.使用SSE和四个内核,我天真地期望加速16倍(SSE为4,四个内核为4).我用SSE(和AVX)实现了代码.Visual Studio 2012具有自动矢量化功能,但通过"展开循环"我获得了更好的结果.我运行我的代码用于阵列(具有32字节对齐),具有四种大小:小于32KB,小于256KB,小于8MB,以及对L1,L2,L3高速缓存和主存储器的应对大于8 MB.对于L1,我使用我的展开的SSE代码(使用AVX的5-6)看到大约4倍的加速.这和我期望的一样多.之后,每个缓存级别的效率都会下降.然后我使用OpenMP在每个核心上运行.我在主循环上面放了"#pragma omp parallel for"数组.但是,我获得的最佳加速比是SSE + OpenMP的5-6倍.有没有人知道为什么我没有看到16倍的加速?也许这是由于阵列从系统内存到缓存的一些"上传"时间?我意识到我应该对代码进行分析,但这本身就是我必须要学习的另一种冒险.
#define ROUND_DOWN(x, s) ((x) & ~((s)-1))
void add_vector(float* result, const float* a, const float* b, const int N) {
__m128 a4;
__m128 b4;
__m128 sum;
int i = 0;
for(; i < ROUND_DOWN(N, 8); i+=8) {
a4 = _mm_load_ps(a + i);
b4 = …Run Code Online (Sandbox Code Playgroud) 我是C++的新手(从Java转移到我的科学应用程序的性能),我对SSE一无所知.不过,我需要改进以下非常简单的代码:
int myMax=INT_MAX;
int size=18000003;
vector<int> nodeCost(size);
/* init part */
for (int k=0;k<size;k++){
nodeCost[k]=myMax;
}
Run Code Online (Sandbox Code Playgroud)
我已经测量了初始化部分的时间,它需要13ms,这对于我的科学应用来说太大了(整个算法在22ms运行,这意味着初始化占总时间的1/2).请记住,初始化部分将针对同一向量重复多次.
如您所见,向量的大小不会除以4.有没有办法加速SSE的初始化?你能建议怎么样?我是否需要使用数组或SSE也可以与向量一起使用?
请,因为我需要你的帮助,所以我们都避免a)"你是如何衡量时间"或b)"过早优化是所有邪恶的根源",这对你来说是合理的,但a)测量的时间是正确的b我同意,但我别无选择.我不想将代码与OpenMP并行化,因此SSE是唯一的后备.
谢谢你的帮助
我只是尝试使用SSE扩展,我开始使用简单的矢量点乘法.所以我写了下面的代码:
void SSE_vectormult(double * A, double * B)
{
__m128d a;
__m128d b;
a = _mm_load_pd(A);
b = _mm_load_pd(B);
const int mask = 0xf1;
__m128d res = _mm_dp_pd(a,b,mask);
A = res;
}
Run Code Online (Sandbox Code Playgroud)
用A和B相同长度的矢量.现在,我必须将结果转换__m128d回来double.有没有简单的方法(或转换功能)?
谢谢!
我正在阅读以下有关如何使用Intel Westmere和AMD Bulldozer中引入的PCLMULQDQ指令有效实现CRC32的文章:
V. Gopal等."使用PCLMULQDQ指令对通用多项式进行快速CRC计算." 2009. http://www.intel.com/content/dam/www/public/us/en/documents/white-papers/fast-crc-computation-generic-polynomials-pclmulqdq-paper.pdf
我理解算法,但我不确定的一件事是如何计算常数$ k_i $.例如,它们为IEEE 802.3多项式提供常量值:
等等.我可以使用这些常量,因为我只需要支持一个多项式,但我很感兴趣:他们是如何计算这些数字的?我不能只使用典型的bignum实现(例如Python提供的实现),因为算法必须在GF(2)中进行.
我已经写了一些AVX2代码在Haswell i7处理器上运行.相同的代码库也用于非Haswell处理器,其中相同的代码应替换为其SSE等效代码.我想知道有没有办法让编译器忽略非Haswell处理器上的AVX2指令.我需要这样的东西:
public void useSSEorAVX(...){
IF (compiler directive detected AVX2)
AVX2 code (this part is ready)
ELSE
SSE code (this part is also ready)
}
}
Run Code Online (Sandbox Code Playgroud)
现在我在编译之前评论相关代码,但必须有一些更有效的方法来做到这一点.我正在使用Ubuntu和gcc.谢谢你的帮助.
我正在尝试找到一种O(n?log(n))排序方法来同时对多个数组进行排序,以便多值数组中的元素将表示来自4个不同单值数组的元素,并且排序方法将对多值元素进行排序.
例如:
对于一个给定4个单值阵列An,Bn,Cn和Dn,我会设置一个新的数组Qn
,使得Q? = [ A? B? C? D? ].
Q?可以在该过程中改变,使得Q? = [ Aa? Bb? Cc? Dd? ]
其中a?,b?,c?和d?是索引列表
,当然这Q? ? Q??? = [ Aa??? Bb??? Cc??? Dd??? ]使得Aa? ? Aa???,Bb? ? Bb???等等.当然,动机是使用SIMD intructions从这个结构中受益,以分别对4个数组进行排序.
我尝试使用SIMD比较器(_mm_cmplt_ps例如)和掩码交换(_mm_blendv_ps例如)来制作传统排序算法的修改版本(快速排序,堆排序,合并排序等)但我总是遇到理论上出现的问题成为O(n?log(n))决策树中的步骤.因此,决定是否设置枢轴(快速排序)或者是否要将父项与其中一个子项交换(堆排序)对于所有整个4个组件同时是不正确的(并且因此,下一步 - 向右或向左 - 是不正确的).
现在我只有O(n²)方法工作.
有任何想法吗?
我有一个8位无符号8位数的向量,范围为0 .. 12 in xmm0.我想对e向量中的每个元素执行以下转换:
if (e != 12)
e = 11 - e;
Run Code Online (Sandbox Code Playgroud)
也就是说,数字0,1,...,11被改变为11,10,...,0而12保持不变.其他值不会发生,我不在乎它们会发生什么.
如何使用SSE4指令集有效地实现此操作?
在sse内在函数中有两种实现累积的方法。但是其中之一得到了错误的结果。
#include <smmintrin.h>
int main(int argc, const char * argv[]) {
int32_t A[4] = {10, 20, 30, 40};
int32_t B[8] = {-1, 2, -3, -4, -5, -6, -7, -8};
int32_t C[4] = {0, 0, 0, 0};
int32_t D[4] = {0, 0, 0, 0};
__m128i lv = _mm_load_si128((__m128i *)A);
__m128i rv = _mm_load_si128((__m128i *)B);
// way 1 unexpected
rv += lv;
_mm_store_si128((__m128i *)C, rv);
// way 2 expected
rv = _mm_load_si128((__m128i *)B);
rv = _mm_add_epi32(lv, rv);
_mm_store_si128((__m128i *)D, rv);
return 0; …Run Code Online (Sandbox Code Playgroud)