按位操作会影响性能

zou*_*yjs 2 c c++ assembly bitwise-operators

// nx_, ny_ is like 350 * 350
#define   IJ_REF(_i, _j) ((_j)*nx_+(_i))
#define HAS_BIT(_v, _bit)     (((_v) & (_bit)) == (_bit))

for (int ix = 0; ix < nx_; ++ix) {              // 0.019s
    for (int iy = 0; iy < ny_; ++iy) {          // 0.716s
        int32 r = IJ_REF(ix, iy);               // 0.548s
        if (!HAS_BIT(image_[r], FLAG)) {        // 3.016s
            int32 k = r * 4;                    // 0.242s
            pTex[k] = pTex[k + 1] = pTex[k + 2] = pTex[k + 3] = 255;  // 1.591s
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

HAS_BIT系列的组装是: 在此输入图像描述

我猜这个and指令是一个&操作,所以它是否会如此昂贵?

PS:FLAG是0x2所以我猜编译器做了一些优化来生成单个指令HAS_BIT.我用Vtune来描述.

das*_*ght 9

命中不是因为你使用的是逐位指令,而是因为指令从内存读取 - 比使用寄存器的偏移计算更昂贵的操作.

代码的问题在于它不会连续读取内存,因为根据IJ_REF您的图像按行存储,但是您按列读取它.

如果交换循环的顺序,则应该能够通过增加缓存命中数来提高性能:

for (int iy = 0; iy < ny_; ++iy) {
    for (int ix = 0; ix < nx_; ++ix) {
        int32 r = IJ_REF(ix, iy);
        if (!HAS_BIT(image_[r], FLAG)) {
            int32 k = r * 4;
            pTex[k] = pTex[k + 1] = pTex[k + 2] = pTex[k + 3] = 255;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 分析器可能正确地测量事物.负载快速启动,但CPU不会等到它完成,直到实际需要该负载的结果.这种情况发生在我们正在加载的寄存器中,在和指令中.这就是为什么在指令级上进行分析在今天几乎没用.您不应该考虑单行代码或指令.时间瓶颈发生在整个大部分代码甚至整个程序上. (3认同)
  • @JasonC我不是100%确定探查器是否正确地将时间归因于此,但你是对的,读取指令在`movzx`行. (2认同)