我需要arm和x86之间的跨平台SIMD指令。因此,我找到了一个名为libsimdpp的库,并运行了这个example。
我做了一些更改,以将其与添加两个数组的标准cpp方法进行比较,但libSimd示例的效果总是较差。
结果
我使用库的方式或构建方式有问题吗?
我对示例所做的更改。
#define SIMDPP_ARCH_X86_SSE4_1 true
#include <simdpp/simd.h>
#include <iostream>
#include <chrono>
//example where i got this from
//https://github.com/p12tic/libsimdpp/tree/2e5c0464a8069310d7eb3048e1afa0e96e08f344
// Initializes vector to store values
void init_vector(float* a, float* b, size_t size) {
for (int i=0; i<size; i++) {
a[i] = i * 1.0;
b[i] = (size * 1.0) - i - 1;
}
}
using namespace simdpp;
int main() {
//1048576
const unsigned long SIZE = 4 * 150000;
float vec_a[SIZE];
float vec_b[SIZE];
float result[SIZE];
///////////////////////////*/
//LibSIMDpp
//*
auto t1 = std::chrono::high_resolution_clock::now();
init_vector(vec_a, vec_b, SIZE);
for (int i=0; i<SIZE; i+=4) {
float32<4> xmmA = load(vec_a + i); //loads 4 floats into xmmA
float32<4> xmmB = load(vec_b + i); //loads 4 floats into xmmB
float32<4> xmmC = add(xmmA, xmmB); //Vector add of xmmA and xmmB
store(result + i, xmmC); //Store result into the vector
}
auto t2 = std::chrono::high_resolution_clock::now();
std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(t2-t1).count()
<< " milliseconds\n";
//*/
///////////////////////////*/
//standard
//*
init_vector(vec_a, vec_b, SIZE);
t1 = std::chrono::high_resolution_clock::now();
for (auto i = 0; i < SIZE; i++) {
result[i] = vec_a[i] + vec_b[i];
}
t2 = std::chrono::high_resolution_clock::now();
std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(t2-t1).count()
<< " milliseconds\n";
//*/
int i = 0;
return 0;
}
答案 0 :(得分:1)
即使直接使用_mm_add_ps
内部函数,调试构建也会减慢手动矢量化代码的速度,而不是减慢标量的速度。 (通常是因为您倾向于使用更多单独的语句,并且调试代码生成器分别编译每个语句。)
您正在使用C ++包装器库,因此在调试模式下,这是重要的额外一层,不会会优化,因为您告诉编译器不要这样做。因此毫不奇怪地将其减慢得比标量更糟。
例如,请参见Why is this C++ wrapper class not being inlined away?。 (即使__attribute__((always_inline))
也不会对性能有很大帮助;传递args仍会导致重新加载/存储以制作另一个副本)。
没有基准调试版本,它没有用,并且告诉您非常
-O3
性能。(根据您的使用情况,您可能还想使用-O3 -march=native -ffast-math
。)