在我的代码中,以下几行目前是热点部分:
int table1[256] = /*...*/;
int table2[512] = /*...*/;
int table3[512] = /*...*/;
int* result = /*...*/;
for(int r = 0; r < r_end; ++r)
{
std::uint64_t bits = bit_reader.value(); // 64 bits, no assumption regarding bits.
// The get_ functions are table lookups from the highest word of the bits variable.
struct entry
{
int sign_offset : 5;
int r_offset : 4;
int x : 7;
};
// NOTE: We are only interested in the highest word in the bits variable.
entry e;
if(is_in_table1(bits)) // branch prediction should work well here since table1 will be hit more often than 2 or 3, and 2 more often than 3.
e = reinterpret_cast<const entry&>(table1[get_table1_index(bits)]);
else if(is_in_table2(bits))
e = reinterpret_cast<const entry&>(table2[get_table2_index(bits)]);
else
e = reinterpret_cast<const entry&>(table3[get_table3_index(bits)]);
r += e.r_offset; // r is 18 bits, top 14 bits are always 0.
int x = e.x; // x is 14 bits, top 18 bits are always 0.
int sign_offset = e.sign_offset;
assert(sign_offset <= 16 && sign_offset > 0);
// The following is the hotspot.
int sign = 1 - (bits >> (63 - sign_offset) & 0x2);
(*result++) = ((x << 18) * sign) | r; // 32 bits
// End of hotspot
bit_reader.skip(sign_offset); // sign_offset is the last bit used.
}
虽然我还没有想出如何进一步优化这个过程,但也许从按位操作的内部函数、__shiftleft128
或 _rot
中提取一些东西可能会有用吗?
请注意,我还在处理GPU上的结果数据,所以重要的是将一些东西放入result
,使GPU能够计算正确的结果。
有什么建议吗?
编辑:
添加了表格查找。
编辑:
int sign = 1 - (bits >> (63 - e.sign_offset) & 0x2);
000000013FD6B893 and ecx,1Fh
000000013FD6B896 mov eax,3Fh
000000013FD6B89B sub eax,ecx
000000013FD6B89D movzx ecx,al
000000013FD6B8A0 shr r8,cl
000000013FD6B8A3 and r8d,2
000000013FD6B8A7 mov r14d,1
000000013FD6B8AD sub r14d,r8d
x
和r
不是从位(bit)计算得出的意义上),那么结果((x << 18) * sign) | r
中唯一的变量就是符号(sign),如果你现在能够将'1'左移,以便可以直接与bits
进行&
运算,使用它来在循环之前预先计算(x << 18) | r
和-(x << 18) | r
的值,然后根据bits
的值选择这两个值之间的一个。" - Tony Delroyx
和r
是从位计算的。对于我的含糊不清,我很抱歉,我会更新我的示例。 - ronag