我正在使用C++编写一个简单的卷积函数,从基本的"滑动窗口"卷积开始,使用常规产品(目前没有FFT内容),直到SEE,AVX和可能的OpenCL.我遇到了SSE的问题.我的代码看起来像这样:
for (x = 0; x < SIZEX - KSIZEX + 1; ++x)
{
for (y = 0; y < SIZEY - KSIZEY + 1; ++y)
{
tmp = 0.0f;
float fDPtmp = 0.0f;
float *Kp = &K[0];
for (xi = 0; xi < KSIZEX; ++xi, Kp=Kp+4)
{
float *Cp = &C[(x+xi)*SIZEY + y];
__m128 *KpSSE = reinterpret_cast<__m128*>(&K);
__m128 *CpSSE = reinterpret_cast<__m128*>(&C[(x + xi)*SIZEY + y]);
__m128 DPtmp = _mm_dp_ps(*KpSSE, *CpSSE, 0xFF);
_mm_store_ss(&fDPtmp, DPtmp);
tmp += fDPtmp;
}
R[k] = tmp;
++k;
}
}
Run Code Online (Sandbox Code Playgroud)
必要的矩阵是这样初始化的(这些的大小是合理的,因为更简单的实现工作得很好):
__declspec(align(16)) float *C = ReadMatrix("E:\\Code\\conv\\C.bin");
__declspec(align(16)) float *K = ReadMatrix("E:\\Code\\conv\\K.bin");
__declspec(align(16)) float *R = new float[CSIZEX*CSIZEY];
Run Code Online (Sandbox Code Playgroud)
代码在y = 1时崩溃,所以我觉得我处理指针的方式可能有误.有趣的是,如果我用_mm_set_ps替换reinterpret_casts,即
__m128 KpSSE = _mm_set_ps(Kp[0], Kp[1], Kp[2], Kp[3]);
__m128 CpSSE = _mm_set_ps(Cp[0], Cp[1], Cp[2], Cp[3]);
__m128 DPtmp = _mm_dp_ps(KpSSE, CpSSE, 0xFF);
_mm_store_ss(&fDPtmp, DPtmp);
Run Code Online (Sandbox Code Playgroud)
整个事情虽然速度慢但效果很好,我责备所有的复制操作.
请问有谁可以指出我在这里做错了什么?
非常感谢你
拍
更新:好的,正如Paul所指出的,问题在于ReadMatrix(或者另一种解决方案是使用_mm_loadu_ps).对于ReadMatrix(),它看起来像这样:
__declspec(align(16)) float* ReadMatrix(string path)
{
streampos size;
ifstream file(path, ios::in | ios::binary | ios::ate);
if (file.is_open())
{
size = file.tellg();
__declspec(align(16)) float *C = new float[size];
file.seekg(0, ios::beg);
file.read(reinterpret_cast<char*>(&C[0]), size);
file.close();
return C;
}
else cout << "Unable to open file" << endl;
}
Run Code Online (Sandbox Code Playgroud)
它没有做到这一点.有没有其他方法可以优雅地执行此操作,而不是被迫逐个读取文件并执行memcpy,我认为应该可以工作?!
更新:
似乎仍然不想工作
__declspec(align(16)) float* ReadMatrix(string path)
{
streampos size;
ifstream file(path, ios::in | ios::binary | ios::ate);
if (file.is_open())
{
size = file.tellg();
__declspec(align(16)) float *C = static_cast<__declspec(align(16)) float*>(_aligned_malloc(size * sizeof(*C), 16));
file.seekg(0, ios::beg);
file.read(reinterpret_cast<char*>(&C[0]), size);
file.close();
return C;
}
else cout << "Unable to open file" << endl;
}
Run Code Online (Sandbox Code Playgroud)
我在那里添加了static_cast,因为看起来有必要编译Paul的代码(即_aligned_malloc返回一个void指针).我接近只是用fread读取文件的块并将它们memcpy到一个alligned数组中.:/我再次发现自己在寻求建议.非常感谢你们.
拍
PS:非SSE代码适用于这些数据结构._mm_loadu_ps比使用非SSE代码慢.
这不符合你的想法:
__declspec(align(16)) float *C = ReadMatrix("E:\\Code\\conv\\C.bin");
Run Code Online (Sandbox Code Playgroud)
对齐指令在此处实现的所有内容是将指针本身(即C)对齐到16字节边界,而不是指针的内容.
你需要修复ReadMatrix它以便返回适当对齐的数据,或者_mm_loadu_ps像其他人已经建议的那样使用它.
不要使用,_mm_set_ps因为这会产生很多指令,不像_mm_loadu_ps是映射到单个指令.
UPDATE
您在ReadMatrix中重复了同样的错误:
__declspec(align(16)) float *C = new float[size];
Run Code Online (Sandbox Code Playgroud)
再次,这不保证数据的对齐,只保证指针C本身的对齐.要修复此分配,您可以使用_mm_malloc或_aligned_malloc:
float *C = _mm_malloc(size * sizeof(*C), 16);
Run Code Online (Sandbox Code Playgroud)
要么
float *C = _aligned_malloc(size * sizeof(*C), 16);
Run Code Online (Sandbox Code Playgroud)