【发布时间】:2016-05-17 17:07:55
【问题描述】:
我试图在 3D 图像的像素上实现迭代器。图像存储在单个向量中,我进行索引映射以从 (x, y, z) 到向量索引。这个想法是能够对图像进行基于范围的处理。
当然,使用向量迭代器对像素进行迭代非常快(在我的情况下为 0.6 秒),但我无法访问索引。
三重for 循环(z、y、x 以内存顺序排列)在 VS2015 上同样快,但使用 gcc 或 clang(gcc 5.2、clang 3.9 以及旧版本)要慢得多(2.4s) )。
我写了一个迭代器,它返回一个元组 (x, y, z, value),而且它也在 2.4s 左右,即使是 VS2015。迭代器中包含了对图片的引用,以及x、y、z这三个字段,像素的值是通过和三重循环一样的pixel_at(x, y, z)得到的。
所以,我有两个问题:
为什么 VS2015 比 GCC 和 Clang 快那么多? (在编辑中回答)
如何在仍然可以访问 x、y、z 的同时获得更快的时间?
这是 x/y/z 迭代器的增量:
_x++;
if (_x == _im.width())
{
_x = 0;
_y++;
if (_y == _im.height())
{
_y = 0;
_z++;
}
}
测量的循环如下:
三重for-loop:
for (int k = 0; k < im.depth(); ++k)
for (int j = 0; j < im.height(); ++j)
for (int i = 0; i < im.width(); ++i)
sum += im.pixel_at(i, j, k);
遍历向量:
for (unsigned char c : im.pixels())
sum += c;
使用自定义迭代器进行迭代:
for (const auto& c : im.indexes())
sum += std::get<3>(c);
使用单个索引实现的迭代器为我提供了良好的性能(0.6 秒),但是我无法访问 x、y、z,并且动态计算它们太慢(6 秒)。在迭代器中拥有 x、y、z 和索引也无济于事(2.4 秒)。
基准是对图像进行 100 次传递,同时对像素值求和,随机初始化。对于我也有索引的情况,我确保读取索引的值(例如,z 坐标的总和),以便编译器不会优化它们。它不会改变任何东西,除了我动态计算索引的情况,在这种情况下计算被优化掉了。
完整的代码可以在这里找到:https://github.com/nitnelave/3DIterator
谢谢!
编辑: 启用链接时间优化 (-flto) 后,三重 for 循环在 g++ 上的速度与矢量迭代器 (0.18s) 一样快 (0.19s),但自定义迭代器仍然慢 6 倍(1.2 秒)。这已经比我为 for 循环和迭代器获得的 3.2 秒要好得多,但我们还没有完全做到。
编辑:我隔离了我禁止 gcc 内联的函数内部的循环,以隔离汇编代码,这里是:
三重for循环:
push %r15
push %r14
push %r13
push %r12
push %rbp
push %rdi
push %rsi
push %rbx
sub $0x78,%rsp
mov 0x8(%rcx),%eax
pxor %xmm4,%xmm4
mov %rcx,%r12
movl $0x64,0x5c(%rsp)
xor %r13d,%r13d
xor %r14d,%r14d
mov %eax,0x58(%rsp)
mov 0x58(%rsp),%edx
test %edx,%edx
jle 10040163a <_Z17bench_triple_loopRK7Image3D.constprop.5+0x2fa>
mov 0x4(%r12),%eax
movl $0x0,0x54(%rsp)
movl $0x0,0x2c(%rsp)
mov %eax,0x48(%rsp)
nopl 0x0(%rax,%rax,1)
nopw %cs:0x0(%rax,%rax,1)
mov 0x48(%rsp),%eax
test %eax,%eax
jle 10040161f <_Z17bench_triple_loopRK7Image3D.constprop.5+0x2df>
movslq (%r12),%rax
mov 0x54(%rsp),%r10d
mov 0x2c(%rsp),%ebx
mov %rax,%rcx
mov %rax,0x40(%rsp)
add %rax,%rax
mov %rax,0x38(%rsp)
lea -0x1(%rcx),%eax
imul %ecx,%r10d
imul %eax,%ebx
mov %eax,0x50(%rsp)
movslq %r10d,%rsi
lea (%rsi,%rsi,1),%r9
mov %ebx,0x4c(%rsp)
xor %ebx,%ebx
xchg %ax,%ax
nopw %cs:0x0(%rax,%rax,1)
test %ecx,%ecx
jle 100401605 <_Z17bench_triple_loopRK7Image3D.constprop.5+0x2c5>
mov 0x10(%r12),%rdx
lea (%rdx,%r9,1),%r8
mov %r8,%rax
and $0xf,%eax
shr %rax
neg %rax
and $0x7,%eax
cmp %ecx,%eax
cmova %ecx,%eax
cmp $0xa,%ecx
cmovbe %ecx,%eax
test %eax,%eax
je 100401690 <_Z17bench_triple_loopRK7Image3D.constprop.5+0x350>
movswl (%r8),%r8d
add %r8d,%r14d
cmp $0x1,%eax
je 100401720 <_Z17bench_triple_loopRK7Image3D.constprop.5+0x3e0>
movswl 0x2(%rdx,%r9,1),%r8d
add %r8d,%r14d
cmp $0x2,%eax
je 100401710 <_Z17bench_triple_loopRK7Image3D.constprop.5+0x3d0>
movswl 0x4(%rdx,%r9,1),%r8d
add %r8d,%r14d
cmp $0x3,%eax
je 100401700 <_Z17bench_triple_loopRK7Image3D.constprop.5+0x3c0>
movswl 0x6(%rdx,%r9,1),%r8d
add %r8d,%r14d
cmp $0x4,%eax
je 1004016f0 <_Z17bench_triple_loopRK7Image3D.constprop.5+0x3b0>
movswl 0x8(%rdx,%r9,1),%r8d
add %r8d,%r14d
cmp $0x5,%eax
je 1004016e0 <_Z17bench_triple_loopRK7Image3D.constprop.5+0x3a0>
movswl 0xa(%rdx,%r9,1),%r8d
add %r8d,%r14d
cmp $0x6,%eax
je 1004016d0 <_Z17bench_triple_loopRK7Image3D.constprop.5+0x390>
movswl 0xc(%rdx,%r9,1),%r8d
add %r8d,%r14d
cmp $0x7,%eax
je 1004016c0 <_Z17bench_triple_loopRK7Image3D.constprop.5+0x380>
movswl 0xe(%rdx,%r9,1),%r8d
add %r8d,%r14d
cmp $0x8,%eax
je 1004016b0 <_Z17bench_triple_loopRK7Image3D.constprop.5+0x370>
movswl 0x10(%rdx,%r9,1),%r8d
add %r8d,%r14d
cmp $0xa,%eax
jne 1004016a0 <_Z17bench_triple_loopRK7Image3D.constprop.5+0x360>
movswl 0x12(%rdx,%r9,1),%r8d
add %r8d,%r14d
mov $0xa,%r8d
cmp %ecx,%eax
je 1004015fb <_Z17bench_triple_loopRK7Image3D.constprop.5+0x2bb>
mov %eax,%r15d
mov %ecx,%edi
sub %eax,%edi
mov %r15,0x30(%rsp)
mov 0x50(%rsp),%r15d
lea -0x8(%rdi),%r11d
sub %eax,%r15d
shr $0x3,%r11d
add $0x1,%r11d
cmp $0x6,%r15d
lea 0x0(,%r11,8),%ebp
jbe 100401573 <_Z17bench_triple_loopRK7Image3D.constprop.5+0x233>
mov 0x30(%rsp),%r15
pxor %xmm0,%xmm0
xor %eax,%eax
add %rsi,%r15
lea (%rdx,%r15,2),%r15
movdqa (%r15),%xmm1
movdqa %xmm4,%xmm3
add $0x1,%eax
add $0x10,%r15
pcmpgtw %xmm1,%xmm3
movdqa %xmm1,%xmm2
cmp %eax,%r11d
punpcklwd %xmm3,%xmm2
punpckhwd %xmm3,%xmm1
paddd %xmm2,%xmm0
paddd %xmm1,%xmm0
ja 10040151a <_Z17bench_triple_loopRK7Image3D.constprop.5+0x1da>
movdqa %xmm0,%xmm1
add %ebp,%r8d
psrldq $0x8,%xmm1
paddd %xmm1,%xmm0
movdqa %xmm0,%xmm1
psrldq $0x4,%xmm1
paddd %xmm1,%xmm0
movd %xmm0,%eax
add %eax,%r14d
cmp %ebp,%edi
je 1004015fb <_Z17bench_triple_loopRK7Image3D.constprop.5+0x2bb
lea (%r10,%r8,1),%eax
cltq
movswl (%rdx,%rax,2),%eax
add %eax,%r14d
lea 0x1(%r8),%eax
cmp %eax,%ecx
jle 1004015fb <_Z17bench_triple_loopRK7Image3D.constprop.5+0x2bb
add %r10d,%eax
cltq
movswl (%rdx,%rax,2),%eax
add %eax,%r14d
lea 0x2(%r8),%eax
cmp %eax,%ecx
jle 1004015fb <_Z17bench_triple_loopRK7Image3D.constprop.5+0x2bb
add %r10d,%eax
cltq
movswl (%rdx,%rax,2),%eax
add %eax,%r14d
lea 0x3(%r8),%eax
cmp %eax,%ecx
jle 1004015fb <_Z17bench_triple_loopRK7Image3D.constprop.5+0x2bb
add %r10d,%eax
cltq
movswl (%rdx,%rax,2),%eax
add %eax,%r14d
lea 0x4(%r8),%eax
cmp %eax,%ecx
jle 1004015fb <_Z17bench_triple_loopRK7Image3D.constprop.5+0x2bb
add %r10d,%eax
cltq
movswl (%rdx,%rax,2),%eax
add %eax,%r14d
lea 0x5(%r8),%eax
cmp %eax,%ecx
jle 1004015fb <_Z17bench_triple_loopRK7Image3D.constprop.5+0x2bb
add %r10d,%eax
add $0x6,%r8d
cltq
movswl (%rdx,%rax,2),%eax
add %eax,%r14d
cmp %r8d,%ecx
jle 1004015fb <_Z17bench_triple_loopRK7Image3D.constprop.5+0x2bb
add %r10d,%r8d
movslq %r8d,%r8
movswl (%rdx,%r8,2),%eax
add %eax,%r14d
add 0x2c(%rsp),%r13d
add 0x4c(%rsp),%r13d
add $0x1,%ebx
add 0x38(%rsp),%r9
add 0x40(%rsp),%rsi
add %ecx,%r10d
cmp %ebx,0x48(%rsp)
jne 1004013f0 <_Z17bench_triple_loopRK7Image3D.constprop.5+0xb0>
addl $0x1,0x2c(%rsp)
mov 0x48(%rsp),%ebx
mov 0x2c(%rsp),%eax
add %ebx,0x54(%rsp)
cmp 0x58(%rsp),%eax
jne 1004013a0 <_Z17bench_triple_loopRK7Image3D.constprop.5+0x60>
subl $0x1,0x5c(%rsp)
jne 10040136c <_Z17bench_triple_loopRK7Image3D.constprop.5+0x2c>
mov 0x2a64(%rip),%rcx # 1004040b0 <__fu0__ZSt4cout>
mov %r13d,%eax
mov %r14d,%r13d
mov %eax,%edx
callq 100401828 <_ZNSolsEi>
lea 0x6f(%rsp),%rdx
mov $0x1,%r8d
mov %rax,%rcx
movb $0xa,0x6f(%rsp)
callq 100401800 <_ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l>
mov %r13d,%eax
add $0x78,%rsp
pop %rbx
pop %rsi
pop %rdi
pop %rbp
pop %r12
pop %r13
pop %r14
pop %r15
retq
nop
nopw %cs:0x0(%rax,%rax,1)
xor %r8d,%r8d
jmpq 1004014da <_Z17bench_triple_loopRK7Image3D.constprop.5+0x19a>
nopl 0x0(%rax,%rax,1)
mov $0x9,%r8d
jmpq 1004014d2 <_Z17bench_triple_loopRK7Image3D.constprop.5+0x192>
nopl 0x0(%rax,%rax,1)
mov $0x8,%r8d
jmpq 1004014d2 <_Z17bench_triple_loopRK7Image3D.constprop.5+0x192>
nopl 0x0(%rax,%rax,1)
mov $0x7,%r8d
jmpq 1004014d2 <_Z17bench_triple_loopRK7Image3D.constprop.5+0x192>
nopl 0x0(%rax,%rax,1)
mov $0x6,%r8d
jmpq 1004014d2 <_Z17bench_triple_loopRK7Image3D.constprop.5+0x192>
nopl 0x0(%rax,%rax,1)
mov $0x5,%r8d
jmpq 1004014d2 <_Z17bench_triple_loopRK7Image3D.constprop.5+0x192>
nopl 0x0(%rax,%rax,1)
mov $0x4,%r8d
jmpq 1004014d2 <_Z17bench_triple_loopRK7Image3D.constprop.5+0x192>
nopl 0x0(%rax,%rax,1)
mov $0x3,%r8d
jmpq 1004014d2 <_Z17bench_triple_loopRK7Image3D.constprop.5+0x192>
nopl 0x0(%rax,%rax,1)
mov $0x2,%r8d
jmpq 1004014d2 <_Z17bench_triple_loopRK7Image3D.constprop.5+0x192>
nopl 0x0(%rax,%rax,1)
mov $0x1,%r8d
jmpq 1004014d2 <_Z17bench_triple_loopRK7Image3D.constprop.5+0x192>
nopl 0x0(%rax,%rax,1)
对向量的迭代:
push %r14
push %r13
push %r12
push %rbp
push %rdi
push %rsi
push %rbx
mov 0x10(%rcx),%r8
mov 0x18(%rcx),%r10
mov $0x64,%ebx
pxor %xmm4,%xmm4
lea 0x2(%r8),%r12
mov %r10,%rdi
mov %r8,%rbp
and $0xf,%ebp
sub %r12,%rdi
shr %rbp
shr %rdi
neg %rbp
lea 0x1(%rdi),%r11
and $0x7,%ebp
cmp %r11,%rbp
cmova %r11,%rbp
xor %eax,%eax
xchg %ax,%ax
nopw %cs:0x0(%rax,%rax,1)
cmp %r8,%r10
je 1004012dc <_Z10bench_iterRK7Image3D.constprop.4+0x1fc>
cmp $0xa,%r11
mov %r11,%rcx
ja 1004012f0 <_Z10bench_iterRK7Image3D.constprop.4+0x210>
movswl (%r8),%edx
add %edx,%eax
cmp $0x1,%rcx
je 100401300 <_Z10bench_iterRK7Image3D.constprop.4+0x220>
movswl 0x2(%r8),%edx
add %edx,%eax
cmp $0x2,%rcx
lea 0x4(%r8),%rdx
je 1004011ed <_Z10bench_iterRK7Image3D.constprop.4+0x10d>
movswl 0x4(%r8),%edx
add %edx,%eax
cmp $0x3,%rcx
lea 0x6(%r8),%rdx
je 1004011ed <_Z10bench_iterRK7Image3D.constprop.4+0x10d>
movswl 0x6(%r8),%edx
add %edx,%eax
cmp $0x4,%rcx
lea 0x8(%r8),%rdx
je 1004011ed <_Z10bench_iterRK7Image3D.constprop.4+0x10d>
movswl 0x8(%r8),%edx
add %edx,%eax
cmp $0x5,%rcx
lea 0xa(%r8),%rdx
je 1004011ed <_Z10bench_iterRK7Image3D.constprop.4+0x10d>
movswl 0xa(%r8),%edx
add %edx,%eax
cmp $0x6,%rcx
lea 0xc(%r8),%rdx
je 1004011ed <_Z10bench_iterRK7Image3D.constprop.4+0x10d>
movswl 0xc(%r8),%edx
add %edx,%eax
cmp $0x7,%rcx
lea 0xe(%r8),%rdx
je 1004011ed <_Z10bench_iterRK7Image3D.constprop.4+0x10d>
movswl 0xe(%r8),%edx
add %edx,%eax
cmp $0x8,%rcx
lea 0x10(%r8),%rdx
je 1004011ed <_Z10bench_iterRK7Image3D.constprop.4+0x10d>
movswl 0x10(%r8),%edx
add %edx,%eax
cmp $0xa,%rcx
lea 0x12(%r8),%rdx
jne 1004011ed <_Z10bench_iterRK7Image3D.constprop.4+0x10d>
movswl 0x12(%r8),%edx
add %edx,%eax
lea 0x14(%r8),%rdx
cmp %rcx,%r11
je 1004012dc <_Z10bench_iterRK7Image3D.constprop.4+0x1fc>
mov %r11,%rsi
mov %rdi,%r14
sub %rcx,%rsi
sub %rcx,%r14
lea -0x8(%rsi),%r9
shr $0x3,%r9
add $0x1,%r9
cmp $0x6,%r14
lea 0x0(,%r9,8),%r13
jbe 10040127d <_Z10bench_iterRK7Image3D.constprop.4+0x19d>
pxor %xmm0,%xmm0
lea (%r8,%rcx,2),%r14
xor %ecx,%ecx
movdqa (%r14),%xmm1
add $0x1,%rcx
movdqa %xmm4,%xmm2
add $0x10,%r14
movdqa %xmm1,%xmm3
cmp %rcx,%r9
pcmpgtw %xmm1,%xmm2
punpcklwd %xmm2,%xmm3
punpckhwd %xmm2,%xmm1
paddd %xmm3,%xmm0
paddd %xmm1,%xmm0
ja 100401226 <_Z10bench_iterRK7Image3D.constprop.4+0x146>
movdqa %xmm0,%xmm1
lea (%rdx,%r13,2),%rdx
psrldq $0x8,%xmm1
paddd %xmm1,%xmm0
movdqa %xmm0,%xmm1
psrldq $0x4,%xmm1
paddd %xmm1,%xmm0
movd %xmm0,%ecx
add %ecx,%eax
cmp %r13,%rsi
je 1004012dc <_Z10bench_iterRK7Image3D.constprop.4+0x1fc>
movswl (%rdx),%ecx
add %ecx,%eax
lea 0x2(%rdx),%rcx
cmp %rcx,%r10
je 1004012dc <_Z10bench_iterRK7Image3D.constprop.4+0x1fc>
movswl 0x2(%rdx),%ecx
add %ecx,%eax
lea 0x4(%rdx),%rcx
cmp %rcx,%r10
je 1004012dc <_Z10bench_iterRK7Image3D.constprop.4+0x1fc>
movswl 0x4(%rdx),%ecx
add %ecx,%eax
lea 0x6(%rdx),%rcx
cmp %rcx,%r10
je 1004012dc <_Z10bench_iterRK7Image3D.constprop.4+0x1fc>
movswl 0x6(%rdx),%ecx
add %ecx,%eax
lea 0x8(%rdx),%rcx
cmp %rcx,%r10
je 1004012dc <_Z10bench_iterRK7Image3D.constprop.4+0x1fc>
movswl 0x8(%rdx),%ecx
add %ecx,%eax
lea 0xa(%rdx),%rcx
cmp %rcx,%r10
je 1004012dc <_Z10bench_iterRK7Image3D.constprop.4+0x1fc>
movswl 0xa(%rdx),%ecx
add %ecx,%eax
lea 0xc(%rdx),%rcx
cmp %rcx,%r10
je 1004012dc <_Z10bench_iterRK7Image3D.constprop.4+0x1fc>
movswl 0xc(%rdx),%edx
add %edx,%eax
sub $0x1,%ebx
jne 100401130 <_Z10bench_iterRK7Image3D.constprop.4+0x50>
pop %rbx
pop %rsi
pop %rdi
pop %rbp
pop %r12
pop %r13
pop %r14
retq
test %rbp,%rbp
jne 100401308 <_Z10bench_iterRK7Image3D.constprop.4+0x228>
xor %ecx,%ecx
mov %r8,%rdx
jmpq 1004011f6 <_Z10bench_iterRK7Image3D.constprop.4+0x116>
nop
mov %r12,%rdx
jmpq 1004011ed <_Z10bench_iterRK7Image3D.constprop.4+0x10d>
mov %rbp,%rcx
jmpq 100401146 <_Z10bench_iterRK7Image3D.constprop.4+0x66>
自定义迭代器:
push %r14
push %rbp
push %rdi
push %rsi
push %rbx
sub $0x30,%rsp
mov (%rcx),%r10d
mov $0x64,%ebp
xor %ebx,%ebx
mov %rcx,%rdi
mov 0x4(%rcx),%ecx
xor %edx,%edx
mov 0x8(%rdi),%esi
nop
xor %r9d,%r9d
xor %r11d,%r11d
xor %r8d,%r8d
nopl 0x0(%rax)
cmp %r9d,%esi
je 1004017b0 <_Z16bench_index_iterRK7Image3D.constprop.0+0x80>
mov %ecx,%eax
mov 0x10(%rdi),%r14
add %r9d,%edx
imul %r9d,%eax
add %r11d,%eax
imul %r10d,%eax
add %r8d,%eax
add $0x1,%r8d
cltq
movswl (%r14,%rax,2),%eax
add %eax,%ebx
cmp %r10d,%r8d
jne 100401760 <_Z16bench_index_iterRK7Image3D.constprop.0+0x30>
add $0x1,%r11d
xor %r8d,%r8d
cmp %r11d,%ecx
jne 100401760 <_Z16bench_index_iterRK7Image3D.constprop.0+0x30>
add $0x1,%r9d
xor %r11d,%r11d
cmp %r9d,%esi
jne 100401765 <_Z16bench_index_iterRK7Image3D.constprop.0+0x35>
nopw %cs:0x0(%rax,%rax,1)
test %r11d,%r11d
jne 100401765 <_Z16bench_index_iterRK7Image3D.constprop.0+0x35>
test %r8d,%r8d
jne 100401765 <_Z16bench_index_iterRK7Image3D.constprop.0+0x35>
sub $0x1,%ebp
jne 100401750 <_Z16bench_index_iterRK7Image3D.constprop.0+0x20>
mov 0x28ea(%rip),%rcx # 1004040b0 <__fu0__ZSt4cout>
callq 100401828 <_ZNSolsEi>
lea 0x2f(%rsp),%rdx
mov $0x1,%r8d
mov %rax,%rcx
movb $0xa,0x2f(%rsp)
callq 100401800 <_ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l>
mov %ebx,%eax
add $0x30,%rsp
pop %rbx
pop %rsi
pop %rdi
pop %rbp
pop %r14
retq
因此,前 2 个工作台似乎有循环展开,但自定义迭代器没有。
编辑:我也尝试使用boost::asio::coroutines,但它比我的解决方案慢。
【问题讨论】:
-
您要求我们解释您未向我们展示的不同版本代码之间的时间差异...
-
我不想展示太多代码,因为我的最短代码分布在 7 个文件中:/ 但如果您认为有必要,我可以将其上传到某个地方。编辑:我添加了代码链接。
-
您的整个问题涉及不同的循环对和迭代器增量。向我们展示了那些循环结构(忘记主体)及其相应的迭代器增量。这是几个简短的 sn-ps,不需要整个文件。
-
@Cameron 我更新了帖子并添加了循环。
-
为什么你认为即时计算
x/y/z太慢了?在您的示例代码中,您不使用x/y/z(operator!=除外,它可以轻松地使用索引。
标签: c++ performance gcc