sys.exit()
我认为// 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
}
}
}
指令是and
操作,所以它是否会如此昂贵?
PS:FLAG是0x2所以我猜编译器做了一些优化来为&
生成一个指令。我用Vtune来描述。
答案 0 :(得分: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;
}
}
}
答案 1 :(得分:1)
你能描述这个变种(没有分支)并发布结果吗?我好奇......(可能会慢一点,如果你很少将这些255写入pTex,因为这段代码会用or
触及每个pTex字节。)
#include <string>
#define IJ_REF(_i, _j) ((_j)*nx_+(_i))
#define HAS_BIT(_v, _bit) (((_v) & (_bit)) == (_bit))
int main()
{
constexpr uint32_t ny_ = 350, nx_ = 350;
constexpr uint8_t FLAG = 2;
uint8_t image_[ny_*nx_];
uint8_t pTex[ny_*nx_*4];
// let access pTex by uint32_t directly
uint32_t *pTex32bPtr = reinterpret_cast<uint32_t *>(pTex);
// debug input
image_[IJ_REF(nx_-2, ny_-1)] = FLAG;
image_[IJ_REF(nx_-1, ny_-1)] = ~FLAG;
pTex32bPtr[IJ_REF(nx_-2, ny_-1)] = 0x12345678;
pTex32bPtr[IJ_REF(nx_-1, ny_-1)] = 0x12345678;
// prepare for loop
const uint32_t endOfs = ny_*nx_;
constexpr uint32_t pTexORValue[2] = {0, 0xFFFFFFFF};
// loop trough all [x,y] values
for (uint32_t srcOfs = 0; srcOfs < endOfs; ++srcOfs) {
unsigned ORindex = !HAS_BIT(image_[srcOfs], FLAG);
// if you know FLAG is always 2, it can be:
// ORindex = image_[srcOfs]&2; with pTexORValue array:
// [3] = {0xFFFFFFFF, 0, 0};
pTex32bPtr[srcOfs] |= pTexORValue[ORindex];
}
// debug output
for (size_t i = IJ_REF(nx_-2, ny_-1) * 4; i < IJ_REF(nx_, ny_-1)*4; ++i) {
printf(" %02x", pTex[i]);
}
}
另外,我有点想知道,为什么你的编译器会movzx edx
+ and edx
,而它可以做test byte ptr [eax+ecx],2
。什么是FLAG
的类型?哦,现在我明白了,因为你的HAS_BIT
宏了。实际上&#34; has_all_bits&#34;测试
如果你打算只测试一个比特,或任何比特是好的,你应该尝试(这应该允许test
使用):
#define HAS_SOME_BIT(_v, _bits) (((_v) & (_bits)) != 0)
即使我上面发布的代码更好地进行优化也可能有所帮助。
在FLAG固定为2的装配中,甚至可以将OR值计算为:
mov ebx,image_offset
loop:
movzx eax,Image_[ebx]
; copy bit 0x02 to all 32 bits
shl eax,30
sar eax,31
not eax ; flip it to "not HAS_BIT"
or pTex[ebx*4],eax
...