我希望优化这段代码。 BitSetPattern
的大小为512,而BitSetOut
的长度为2048位。
基本上这个代码的作用是,需要4个BitSetPatterns并通过连接它们来创建BitSetOut。复制一位需要太多时间。
我认为OR与SHIFT一起解决了这种情况,但运算符只采用相同长度的位集。也没有办法用较小的一个初始化一个bitset,并用零填充剩余的位。
unsigned outputIter = 0;
BitSetPattern output(0);
for (int i = 3; i >= 0; i--)
{
BitSetOut currentInput = this->input[ i ]->getOutput();
for (unsigned j = 0; j < currentInput.size(); j++)
{
output[ outputIter ] = currentInput[ j ];
outputIter++;
}
}
return output;
我已经对代码进行了分析,这是一种花费太多时间的方法。
答案 0 :(得分:2)
这是一个非常 UNSAFE 的解决方案,你应该 不 使用:
assert (sizeof(output) == output.size() / 8);
assert ((output.size() / 8) == 0);
int offset = 0;
for (int i = 3; i >= 0; --i)
{
auto const sz = input[i].size();
assert ((sz % 8) == 0);
assert (offset + (sz / 8) <= output.size());
memcpy (((char*)&(output)) + offset, (char*)&(input[i]), sz / 8);
offset += sz / 8;
}
基本上,这会尝试安全,并确保除了位(没有填充,对齐,可能是大小甚至压缩位)之外的位集中没有其他内容。然后将它们作为一个整体复制。
标准(AFAIK)中没有任何内容可以保证这一点有效。它甚至可能不适用于现有的实现,但我相信它“应该”适用于简单的std::bitset
实现。
可能可以更快地加速复制部分。由于您知道数据的大小,并且它非常小,因此您可以直接编写SSE甚至AVX内在函数,将源地址的512位复制到目标地址。
还有三件事要尝试:
如果您完全确定您的大小保持不变(例如2048和512位),请使用常量值并删除算术和断言。这个可能有所帮助,具体取决于编译器如何处理memcpy
(某些编译器在某些情况下优化它的地狱,例如,如果大小是常量和字大小的倍数等)
确保您的位缓冲区分配的地址是缓存行大小的倍数(例如64字节)。这是为了确保您不会触及超过必要的缓存行。)
< / LI>您可以通过在每次迭代时触摸 next 输入缓冲区来尝试帮助内存“prefetcher”。例如:
char * output_ptr = (char *)&output;
char * input_ptrs [4] = {(char*)&(input[0]), (char*)&(input[1]), ...};
volatile char dummy = 0;
dummy += input_ptrs[2][0]; // prefetch the next one
memcpy (output_ptr + 0, input_ptrs[3], 64); // copy
dummy += input_ptrs[1][0]; // prefetch the next one
memcpy (output_ptr + 64, input_ptrs[2], 64); // copy
dummy += input_ptrs[0][0]; // prefetch the next one
memcpy (output_ptr + 128, input_ptrs[1], 64); // copy
memcpy (output_ptr + 192, input_ptrs[0], 64); // copy