gpt4 book ai didi

c++ - SSE:reinterpret_cast<__m128*> 而不是 _mm_load_ps

转载 作者:太空狗 更新时间:2023-10-29 20:26:06 29 4
gpt4 key购买 nike

我正在用 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;
}
}

必要的矩阵是这样初始化的(这些矩阵的大小被认为是可以的,因为更简单的实现工作得很好):

__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];

代码在 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);

虽然速度较慢,但​​整个过程运行良好,我将其归咎于所有复制操作。

谁能指出我到底做错了什么?

非常感谢

帕特

更新:好的,正如 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;
}

它并没有起到作用。有没有其他方法可以优雅地执行此操作,而不是被迫逐个读取文件并执行我认为应该有效的 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;
}

我在那里添加了 static_cast,因为它似乎有必要让 Paul 的代码编译(即 _aligned_malloc 返回一个空指针)。我快要用 fread 读取文件 block 并将它们 memcpy 到一个对齐的数组中。 :/我又一次发现自己在寻求建议。非常感谢大家。

帕特

PS:非 SSE 代码可以很好地处理这些数据结构。 _mm_loadu_ps 比使用非 SSE 代码慢。

最佳答案

这并不像你想象的那样:

__declspec(align(16)) float *C = ReadMatrix("E:\\Code\\conv\\C.bin");

此处对齐指令的作用是将指针本身(即 C)对齐到 16 字节边界,而不是指针的内容

您要么需要修复 ReadMatrix 以便它返回适当对齐的数据,要么使用 _mm_loadu_ps,正如其他人已经建议的那样。

不要使用 _mm_set_ps,因为这会在后台生成大量指令,这与映射到单个指令的 _mm_loadu_ps 不同。

更新

你在 ReadMatrix 中重复了同样的错误:

__declspec(align(16)) float *C = new float[size];

同样,这不能保证数据的对齐,只能保证指针 C 本身的对齐。要修复此分配,您可以使用 _mm_malloc_aligned_malloc:

float *C = _mm_malloc(size * sizeof(*C), 16); 

float *C = _aligned_malloc(size * sizeof(*C), 16); 

关于c++ - SSE:reinterpret_cast<__m128*> 而不是 _mm_load_ps,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21328985/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com