比特流优化

时间:2014-02-14 09:27:47

标签: c++ bit-manipulation

我有一个程序从比特流中读取大量数据。我这样做的方式并不高效,因为在进行性能测试时,大部分时间都花在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());
}

4 个答案:

答案 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