C++ 与自定义迭代器的性能差异
我试图在3D图像的像素上实现一个迭代器。图像存储在一个向量中,我进行索引映射,从(x,y,z)到向量索引。这样做的目的是能够根据图像进行范围测量 当然,使用向量迭代器对像素进行迭代非常快(在我的例子中是0.6秒),但是我没有访问索引的权限 三重C++ 与自定义迭代器的性能差异,c++,performance,gcc,C++,Performance,Gcc,我试图在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),即使使用VS2015,它也大约
for
循环(z、y、x按内存顺序排列)在VS2015上速度一样快,但在gcc或clang(gcc 5.2、clang 3.9以及旧版本)上速度要慢得多(2.4s)
我编写了一个迭代器,它返回一个元组(x,y,z,value),即使使用VS2015,它也大约是2.4s。迭代器包含对图像和三个字段x、y和z的引用,通过使用与三重循环相同的pixel_at(x、y、z)
来获得像素值
因此,我有两个问题:
- 为什么VS2015比GCC和Clang快得多?(以编辑方式回答)
- 如何在仍然可以访问x、y、z的情况下实现更快的时间
_x++;
if (_x == _im.width())
{
_x = 0;
_y++;
if (_y == _im.height())
{
_y = 0;
_z++;
}
}
for (const auto& c : im.indexes())
sum += std::get<3>(c);
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
测量的回路如下所示:
三重,用于循环:
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);
使用自定义迭代器进行迭代:
_x++;
if (_x == _im.width())
{
_x = 0;
_y++;
if (_y == _im.height())
{
_y = 0;
_z++;
}
}
for (const auto& c : im.indexes())
sum += std::get<3>(c);
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
向量上的迭代:
for (unsigned char c : im.pixels())
sum += c;
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>
推送%r14
推送%r13
推送%r12
推送%rbp
推送%rdi
推送%rsi
推送%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
和$0xf,%ebp
子%r12,%rdi
shr%rbp
shr%rdi
负%rbp
lea 0x1(%rdi),%r11
和$0x7,%ebp
cmp%r11,%rbp
cmova%r11,%rbp
异或%eax,%eax
xchg%ax,%ax
nopw%cs:0x0(%rax,%rax,1)
cmp%r8,%r10
je 1004012dc
cmp$0xa,%r11
移动%r11,%rcx
ja 1004012f0
movswl(%r8),%edx
添加%edx,%eax
cmp$0x1,%rcx
je 100401300
movswl 0x2(%r8),%edx
添加%edx,%eax
cmp$0x2,%rcx
lea 0x4(%r8),%rdx
je 1004011ed
movswl 0x4(%r8),%edx
添加%edx,%eax
cmp$0x3,%rcx
lea 0x6(%r8),%rdx
je 1004011ed
movswl 0x6(%r8),%edx
添加%edx,%eax
cmp$0x4,%rcx
lea 0x8(%r8),%rdx
je 1004011ed
movswl 0x8(%r8),%edx
添加%edx,%eax
cmp$0x5,%rcx
lea 0xa(%r8),%rdx
je 1004011ed
movswl 0xa(%r8),%edx
添加%edx,%eax
cmp$0x6,%rcx
lea 0xc(%r8),%rdx
je 1004011ed
movswl 0xc(%r8),%edx
添加%edx,%eax
cmp$0x7,%rcx
lea 0xe(%r8),%rdx
je 1004011ed
movswl 0xe(%r8),%edx
添加%edx,%eax
cmp$0x8,%rcx
lea 0x10(%r8),%rdx
je 1004011ed
movswl 0x10(%r8),%edx
添加%edx,%eax
cmp$0xa,%rcx
lea 0x12(%r8),%rdx
jne 1004011ed
movswl 0x12(%r8),%edx
添加%edx,%eax
lea 0x14(%r8),%rdx
cmp%rcx,%r11
je 1004012dc
变动%r11,%rsi
移动%rdi,%r14
低于%rcx,%rsi
低于%rcx,%r14
lea-0x8(%rsi),%r9
shr$0x3,%r9
添加$0x1,%r9
cmp$0x6,%r14
lea 0x0(,%r9,8),%r13
jbe 10040127d
pxor%xmm0,%xmm0
lea(%r8,%rcx,2),%r14
异或%ecx,%ecx
movdqa(%r14),%xmm1
添加$0x1,%rcx
movdqa%xmm4,%xmm2
添加$0x10,%r14
movdqa%xmm1,%xmm3
cmp%rcx,%r9
pcmpgtw%xmm1,%xmm2
punpcklwd%xmm2,%xmm3
punpckhwd%xmm2,%xmm1
填充%xmm3,%xmm0
填充%xmm1,%xmm0
ja 100401226
movdqa%xmm0,%xmm1
lea(%rdx,%r13,2),%rdx
psrldq$0x8,%xmm1
填充%xmm1,%xmm0
movdqa%xmm0,%xmm1
psrldq$0x4,%xmm1
填充%xmm1,%xmm0
movd%xmm0,%ecx
添加%ecx,%eax
cmp%r13,%rsi
je 1004012dc
movswl(%rdx),%ecx
添加%ecx,%eax
lea 0x2(%rdx),%rcx
cmp%rcx,%r10
je 1004012dc
movswl 0x2(%rdx),%ecx
添加%ecx,%eax
lea 0x4(%rdx),%rcx
cmp%rcx,%r10
je 1004012dc
movswl 0x4(%rdx),%ecx
添加%ecx,%eax
lea 0x6(%rdx),%rcx
cmp%rcx,%r10
je 1004012dc
movswl 0x6(%rdx),%ecx
添加%ecx,%eax
lea 0x8(%rdx),%rcx
cmp%rcx,%r10
je 1004012dc
movswl 0x8(%rdx),%ecx
添加%ecx,%eax
lea 0xa(%rdx),%rcx
cmp%rcx,%r10
je 1004012dc
movswl 0xa(%rdx),%ecx
添加%ecx,%eax
lea 0xc(%rdx),%rcx
cmp%rcx,%r10
je 1004012dc
movswl 0xc(%rdx),%edx
添加%edx,%eax
子$0x1,%ebx
jne 100401130
弹出%rbx
波普%rsi
pop%rdi
弹出%rbp
弹出%r12
弹出%r13
弹出%r14
retq
测试%rbp,%rbp
jne 100401308
异或%ecx,%ecx
mov%r8,%rdx
jmpq 1004011f6
不
mov%r12,%rdx
jmpq 1004011ed
mov%rbp,%rcx
jmpq 100401146
自定义迭代器:
_x++;
if (_x == _im.width())
{
_x = 0;
_y++;
if (_y == _im.height())
{
_y = 0;
_z++;
}
}
for (const auto& c : im.indexes())
sum += std::get<3>(c);
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
推送%r14
推送%rbp
推送%rdi
推送%rsi
推送%rbx
低于$0x30,%rsp
mov(%rcx),%r10d
mov$0x64,%ebp
异或%ebx,%ebx
移动%rcx,%rdi
mov 0x4(%rcx),%ecx
异或%edx,%edx
mov 0x8(%rdi),%esi
不
异或%r9d,%r9d
异或%r11d,%r11d
异或%r8d,%r8d
nopl 0x0(%rax)
cmp%r9d,%esi
je 1004017b0
mov%ecx,%eax
mov 0x10(%rdi),%r14
添加%r9d,%edx
imul%r9d,%eax
添加%r11d,%eax
imul%r10d,%eax
添加%r8d,%eax
添加$0x1,%r8d
cltq
movswl(%r14,%rax,2),%eax
添加%eax,%ebx
凸轮轴位置%r10d,%r8d
jne 100401760
添加$0x1,%r11d
异或%r8d,%r8d
cmp%r11d,%ecx
jne 100401760
添加$0x1,%r9d
异或%r11d,%r11d
cmp%r9d,%esi
jne 100401765
nopw%cs:0x0(%rax,%rax,1)
测试%r11d,%r11d
jne 100401765
测试%r8d,%r8d
jne 100401765
低于$0x1,%ebp
jne 100401750
mov 0x28ea(%rip),%rcx#1004040b0
callq 100401828
lea 0x2f(%rsp),%rdx
mov$0x1,%r8d
移动百分比rax,%rcx
movb$0xa,0x2f(%rsp)
callq 100401800
mov%ebx,%eax
添加$0x30,%rsp
弹出%rbx
波普%rsi
pop%rdi
弹出%rbp
弹出%r14
retq
因此,前两个工作台似乎有循环展开,但定制迭代器没有
编辑:我也尝试过使用boost::asio::coroutine
s,但它比我的解决方案慢。为什么慢
正如您在反汇编中所展示的,编译器为不同的循环生成了截然不同的代码。为自定义迭代器生成的机器代码的主要缺点是,它不使用SIMD指令
编译器优化