我需要尽可能优化程序。现在我遇到了这个问题:我有一个一维数组,它以像素数据的形式表示纹理。我现在需要处理这些数据。通过以下函数访问该数组:
(y * width) + x
具有 x,y 坐标。现在的问题是,这个功能最优化的方式是什么,我考虑了以下两种可能:
内联:
inline int Coords(x,y) { return (y * width) + x); }
宏:
#define COORDS(X,Y) ((Y)*width)+(X)
哪一个是这里使用的最佳实践,或者有没有办法获得我不知道的更优化的变体?
最佳答案
我编写了一个小测试程序来查看这两种方法之间的区别。
这里是:
#include <cstdint>
#include <algorithm>
#include <iterator>
#include <iostream>
using namespace std;
static constexpr int width = 100;
inline int Coords(int x, int y) { return (y * width) + x; }
#define COORDS(X,Y) ((Y)*width)+(X)
void fill1(uint8_t* bytes, int height)
{
for (int x = 0 ; x < width ; ++x) {
for (int y = 0 ; y < height ; ++y) {
bytes[Coords(x,y)] = 0;
}
}
}
void fill2(uint8_t* bytes, int height)
{
for (int x = 0 ; x < width ; ++x) {
for (int y = 0 ; y < height ; ++y) {
bytes[COORDS(x,y)] = 0;
}
}
}
auto main() -> int
{
uint8_t buf1[100 * 100];
uint8_t buf2[100 * 100];
fill1(buf1, 100);
fill2(buf2, 100);
// these are here to prevent the compiler from optimising away all the above code.
copy(begin(buf1), end(buf1), ostream_iterator<char>(cout));
copy(begin(buf2), end(buf2), ostream_iterator<char>(cout));
return 0;
}
我是这样编译的:
c++ -S -o intent.s -std=c++1y -O3 intent.cpp
然后查看源代码,看看编译器会做什么。
正如预期的那样,编译器完全忽略了程序员的所有优化尝试,而是只查看表达的意图、副作用和别名的可能性。然后它为两个函数发出完全相同的代码(当然是内联的)。
程序集的相关部分:
.globl _main
.align 4, 0x90
_main: ## @main
.cfi_startproc
## BB#0:
pushq %rbp
Ltmp16:
.cfi_def_cfa_offset 16
Ltmp17:
.cfi_offset %rbp, -16
movq %rsp, %rbp
Ltmp18:
.cfi_def_cfa_register %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $20024, %rsp ## imm = 0x4E38
Ltmp19:
.cfi_offset %rbx, -56
Ltmp20:
.cfi_offset %r12, -48
Ltmp21:
.cfi_offset %r13, -40
Ltmp22:
.cfi_offset %r14, -32
Ltmp23:
.cfi_offset %r15, -24
movq ___stack_chk_guard@GOTPCREL(%rip), %r15
movq (%r15), %r15
movq %r15, -48(%rbp)
xorl %eax, %eax
xorl %ecx, %ecx
.align 4, 0x90
LBB2_1: ## %.lr.ph.us.i
## =>This Loop Header: Depth=1
## Child Loop BB2_2 Depth 2
leaq -10048(%rbp,%rcx), %rdx
movl $400, %esi ## imm = 0x190
.align 4, 0x90
LBB2_2: ## Parent Loop BB2_1 Depth=1
## => This Inner Loop Header: Depth=2
movb $0, -400(%rdx,%rsi)
movb $0, -300(%rdx,%rsi)
movb $0, -200(%rdx,%rsi)
movb $0, -100(%rdx,%rsi)
movb $0, (%rdx,%rsi)
addq $500, %rsi ## imm = 0x1F4
cmpq $10400, %rsi ## imm = 0x28A0
jne LBB2_2
## BB#3: ## in Loop: Header=BB2_1 Depth=1
incq %rcx
cmpq $100, %rcx
jne LBB2_1
## BB#4:
xorl %r13d, %r13d
.align 4, 0x90
LBB2_5: ## %.lr.ph.us.i10
## =>This Loop Header: Depth=1
## Child Loop BB2_6 Depth 2
leaq -20048(%rbp,%rax), %rcx
movl $400, %edx ## imm = 0x190
.align 4, 0x90
LBB2_6: ## Parent Loop BB2_5 Depth=1
## => This Inner Loop Header: Depth=2
movb $0, -400(%rcx,%rdx)
movb $0, -300(%rcx,%rdx)
movb $0, -200(%rcx,%rdx)
movb $0, -100(%rcx,%rdx)
movb $0, (%rcx,%rdx)
addq $500, %rdx ## imm = 0x1F4
cmpq $10400, %rdx ## imm = 0x28A0
jne LBB2_6
## BB#7: ## in Loop: Header=BB2_5 Depth=1
incq %rax
cmpq $100, %rax
jne LBB2_5
## BB#8:
movq __ZNSt3__14coutE@GOTPCREL(%rip), %r14
leaq -20049(%rbp), %r12
xorl %ebx, %ebx
.align 4, 0x90
LBB2_9: ## %_ZNSt3__116ostream_iteratorIccNS_11char_traitsIcEEEaSERKc.exit.us.i.i13
## =>This Inner Loop Header: Depth=1
movb -10048(%rbp,%r13), %al
movb %al, -20049(%rbp)
movl $1, %edx
movq %r14, %rdi
movq %r12, %rsi
callq __ZNSt3__124__put_character_sequenceIcNS_11char_traitsIcEEEERNS_13basic_ostreamIT_T0_EES7_PKS4_m
incq %r13
cmpq $10000, %r13 ## imm = 0x2710
jne LBB2_9
## BB#10:
movq __ZNSt3__14coutE@GOTPCREL(%rip), %r14
leaq -20049(%rbp), %r12
.align 4, 0x90
LBB2_11: ## %_ZNSt3__116ostream_iteratorIccNS_11char_traitsIcEEEaSERKc.exit.us.i.i
## =>This Inner Loop Header: Depth=1
movb -20048(%rbp,%rbx), %al
movb %al, -20049(%rbp)
movl $1, %edx
movq %r14, %rdi
movq %r12, %rsi
callq __ZNSt3__124__put_character_sequenceIcNS_11char_traitsIcEEEERNS_13basic_ostreamIT_T0_EES7_PKS4_m
incq %rbx
cmpq $10000, %rbx ## imm = 0x2710
jne LBB2_11
## BB#12: ## %_ZNSt3__14copyIPhNS_16ostream_iteratorIccNS_11char_traitsIcEEEEEET0_T_S7_S6_.exit
cmpq -48(%rbp), %r15
jne LBB2_14
## BB#13: ## %_ZNSt3__14copyIPhNS_16ostream_iteratorIccNS_11char_traitsIcEEEEEET0_T_S7_S6_.exit
xorl %eax, %eax
addq $20024, %rsp ## imm = 0x4E38
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
请注意,如果没有对 copy(..., ostream_iterator...) 的两次调用,编译器会推测该程序的总效果为零,并拒绝发出任何代码,除了从 main()
返回 0
故事的寓意:停止尝试做编译器的工作。继续你的。
您的工作是尽可能优雅地表达意图。就这样。
关于c++ - 优化 : Inline or Macrofunction?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33627765/