【发布时间】:2023-03-30 20:49:01
【问题描述】:
我正在尝试将数组元素与 SIMD 并行求和。 为了避免锁定,我使用了可组合的本地线程,它并不总是在 16 个字节上对齐 因为 _mm_add_epi32 抛出异常
concurrency::combinable<__m128i> sum_combine;
int length = 40; // multiple of 8
concurrency::parallel_for(0, length , 8, [&](int it)
{
__m128i v1 = _mm_load_si128(reinterpret_cast<__m128i*>(input_arr + it));
__m128i v2 = _mm_load_si128(reinterpret_cast<__m128i*>(input_arr + it + sizeof(uint32_t)));
auto temp = _mm_add_epi32(v1, v2);
auto &sum = sum_combine.local(); // here is the problem
TRACE(L"%d\n", it);
TRACE(L"add %x\n", &sum);
ASSERT(((unsigned long)&sum & 15) == 0);
sum = _mm_add_epi32(temp, sum);
}
);
这里是来自 ppl.h 的组合的定义
template<typename _Ty>
class combinable
{
private:
// Disable warning C4324: structure was padded due to __declspec(align())
// This padding is expected and necessary.
#pragma warning(push)
#pragma warning(disable: 4324)
__declspec(align(64))
struct _Node
{
unsigned long _M_key;
_Ty _M_value; // this might not be aligned on 16 bytes
_Node* _M_chain;
_Node(unsigned long _Key, _Ty _InitialValue)
: _M_key(_Key), _M_value(_InitialValue), _M_chain(NULL)
{
}
};
有时对齐没问题,代码工作正常,但大多数时候它不工作
我尝试过使用以下,但这不能编译
union combine
{
unsigned short x[sizeof(__m128i) / sizeof(unsigned int)];
__m128i y;
};
concurrency::combinable<combine> sum_combine;
then auto &sum = sum_combine.local().y;
任何纠正对齐问题的建议,仍然使用combinable。
在 x64 上它可以正常工作,因为默认的 16 字节对齐。在 x86 上,有时存在对齐问题。
【问题讨论】:
-
您是否尝试过在结构定义中使用
#pragma pack(push, 1)和#pragma pack(pop)指令?编译器可以用 0 填充你的结构,除非你明确告诉它不要这样做。 -
@mike on whcih struct 我应该使用#pragma pack(push, 1)
-
未对齐的负载可以吗?您可能会损失一些性能,尤其是在旧处理器(例如 Core2)上
-
@harold 但是 input_arr 已经对齐了,它将如何影响总和对齐,是否存在 _mm_addu_epi32
-
@PaulR 我刚刚使用了 4 而不是 sizeof(uint32_t)