有什么方法可以加速这个位列表代码?

时间:2015-04-28 12:10:19

标签: c++ c++11 bit-manipulation

我在列表中存储了可变数量的位。我需要查找[i,j]范围内的位。目前,我将这些位存储在无符号32位整数的向量中。

这就是我查找的方式:

std::uint32_t
Data::findInt3(const std::vector<std::uint32_t>& input, int size, int pos) {
    pos = pos*size;
    int firstc = pos >> 5;
    int ipos = pos & 31;
    int end = ipos+size;
    std::uint64_t t = input[firstc];

    std::uint64_t num = (t << 32) | input[firstc+1];
    std::uint64_t number = num >> (64-end);
    number = number & ((1 << size)-1);

    return number;
}

这段代码被称为很多次。我想只是小加速会非常有益。谁能看到任何可以做得更好的东西?喜欢换东西而不是换东西。或哪个更快?

由于

3 个答案:

答案 0 :(得分:3)

这段代码执行了几件事:

  1. 计算索引
  2. 它使用计算的索引访问一个向量(我猜它是某种查找表)
  3. 使用向量的值
  4. 计算结果

    因此,通过观察它,如果不显示它的使用方式,并且不了解整个算法,它看起来就不会被优化。这些操作已经看起来最佳。

    如果它真的是在一个大循环中执行,那么我会这样做:

    • 尝试预先计算循环外的一些值
    • 尝试不对矢量进行此类随机访问,而是进行串行访问(如果是查找表,则可能无法访问)
    • 尝试向量化访问(使用SIMD或类似功能)
    • 如果没有其他工作,请在汇编中实施

答案 1 :(得分:1)

首先是常见的事情:

  1. 不要猜,测量!在代码周围写一些测量线束,并在下面的建议中添加一些数据。
  2. 我不熟悉你的其余代码,所以我可能会有几度学习。
  3. 注意参数的类型sizepos和内部变量。你肯定这些需要签名整数吗?
  4. 编译器类型和设置可能会对此产生重大影响。以下建议之一是否真的有帮助。
  5. 我实际上看到了一些你可以尝试的事情:

    1. 在前几行中,您基本上将pos参数拆分为其他值firstciposend。我假设您的代码中的这些值以前也作为分隔值存在。将它们作为单独的参数直接传递可能会更好。如果不以此函数的更多参数为代价来获得此计算事件,则可以获得回报。你
    2. 在接下来的两行中,您查找两次32位值并将它们打包到一个64位值。最好从一开始就将值直接存储在std::vector<std::uint64_t>中,这样就可以节省一个&#34;查找&#34;,&#34;或&#34;和#34;位移&#34;。你能改变矢量类型吗?
    3. 此行std::uint64_t number = num >> (64-end);的计算看起来很可疑。是否无法以任何方式预先计算此值?
    4. 可以简化最后一行number = number & ((1 << size)-1);上的屏蔽操作。您需要支持多少种不同的尺寸?我想只有64个。你可以将所有可能的掩码放入(预先计算)std::vector<uint64_t> masks;。通过这种方式,您可以将此行转换为:number &= masks[size];向量查找几乎总是比移位操作更快。
    5. 如果无法进行预先计算(步骤3),请考虑将相同的逻辑(步骤4)扩展到第3步,制作如下内容:std::uint64_t number = num >> shiftvalue[end];这将节省一次减法。
    6. 减少局部变量的数量。编译器已经为你做了很多这方面的工作,但为什么不帮助它。每次调用函数时都需要在堆栈上创建局部变量,并在最后处理掉。如果重新进入和多线程不是这个函数的问题,你可以将它们变成静态或全局变量。

答案 2 :(得分:1)

我尝试过一点优化你的代码,如果不需要,不要获取第二个数组元素。也许,这对小尺寸有帮助:

std::uint32_t
Data::findInt3(const std::vector<std::uint32_t>& input, int size, int pos) {
pos = pos*size;
int firstc = pos >> 5;
int ipos = pos & 31;
int end = ipos+size;

if(end > 32) {
  std::uint64_t t = input[firstc];
  std::uint64_t num = (t << 32) | input[firstc+1];
  return (num >> (64-end)) & ((1L << size)-1);
} else {
  return (input[firstc] >> (32-end)) & ((1 << size)-1);
}

}