C++ 与自定义迭代器的性能差异

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,它也大约

我试图在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,它也大约是2.4s。迭代器包含对图像和三个字段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 (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指令

编译器优化