我有一个程序从比特流中读取大量数据。我这样做的方式并不高效,因为在进行性能测试时,大部分时间都花在read
函数上。
这是我的阅读功能:
uint32_t bitstream::read(bitstream::size_type n) {
uint32_t a = data[pos / 32];
uint32_t b = data[(pos + n - 1) / 32];
uint32_t shift = pos & 31;
a >>= shift;
b <<= 32 - shift;
uint32_t mask = (uint32_t)(((uint64_t)1 << n) - 1);
uint32_t ret = (a | b) & mask;
pos += n;
return ret;
}
如何进一步优化此功能?我的探查器说这个功能的大部分时间花在计算ret上。
修改
关于内部,这是我设置数据的方式:
bitstream::bitstream(const std::string &dat) : size( dat.size()*8 ) {
// data has the type std::vector<uint32_t>
data.resize((dat.size() + 3) / 4 + 1);
memcpy(&data[0], dat.c_str(), dat.size());
}
答案 0 :(得分:1)
您是否总是读取相同的位数,或者它是否有所不同?
如果您是,那么您可以尝试编写一个函数来只读取那么多位:n
保持不变可能允许编译器进行更积极的优化。 (如果n
总是1,那么你可以写一个更简单的读取方法)
答案 1 :(得分:0)
答案主要取决于您使用的CPU架构和编译器,而不是语言。如果你的CPU是&lt; 32位或在右移位和/或编译器的位移子程序上做得不好,天真地实现了,一般来说你运气不好。您可以牺牲大量的程序存储器并明确地写出所有情况(即切换() - 在模32与n的组合上)或者您可以尝试通过使用uint16_t和uint8_t短路移位来完成编译工作联合。
在代码中你可以非常便宜地做的是使用预先计算的类const数组来进行掩码,而不是每次在函数中计算它。
答案 2 :(得分:0)
您可以尝试在uint64_t中保留64位缓冲区,一旦它低于32位就读取另一个32位字。如果您经常读取小于32位的大小,这可能会有所帮助。
答案 3 :(得分:0)
如果pos
可以为0,那么shift
也可以为0.结果b
向左移位32位,有效地将其设置为0并且右移{0}的a
也没有效果。对于这种情况,您应该提前终止,以避免无意义的操作。
此外,您可以尝试使用掩码表来消除一个移位操作,您需要一个只有32个条目的uint32_t
数组。
大多数现代英特尔CPU都有两个ALU单元,要求它们连续执行三个操作,然后通过使用更多ALU操作来计算取决于这些移位结果的结果将限制您的吞吐量。
最后,如果代码将在具有BMI功能的CPU上执行,您可以使用BEXTR指令或内部函数从位置len
开始的src
中提取start
位。
有关位操作指令的详细信息,请参阅http://en.wikipedia.org/wiki/Bit_Manipulation_Instruction_Sets。