Betrachten Sie den folgenden Code ein:Warum ist die Inlined-Funktion langsamer als der Funktionszeiger?
typedef void (*Fn)();
volatile long sum = 0;
inline void accu() {
sum+=4;
}
static const Fn map[4] = {&accu, &accu, &accu, &accu};
int main(int argc, char** argv) {
static const long N = 10000000L;
if (argc == 1)
{
for (long i = 0; i < N; i++)
{
accu();
accu();
accu();
accu();
}
}
else
{
for (long i = 0; i < N; i++)
{
for (int j = 0; j < 4; j++)
(*map[j])();
}
}
}
Als ich es kompiliert mit:
g++ -O3 test.cpp
Ich bin der erste Zweig erwartet, schneller zu laufen, da der Compiler den Funktionsaufruf zu accu Inline könnte. Und der zweite Zweig kann nicht inline sein, weil der Akku über den in einem Array gespeicherten Funktionszeiger aufgerufen wird.
Aber die Ergebnisse überrascht mich:
time ./a.out
real 0m0.108s
user 0m0.104s
sys 0m0.000s
time ./a.out 1
real 0m0.095s
user 0m0.088s
sys 0m0.004s
Ich verstehe nicht, warum, so habe ich eine objdump:
objdump -DStTrR a.out > a.s
und die Demontage scheint nicht das Leistungsergebnis zu erklären I bekam:
8048300 <main>:
8048300: 55 push %ebp
8048301: 89 e5 mov %esp,%ebp
8048303: 53 push %ebx
8048304: bb 80 96 98 00 mov $0x989680,%ebx
8048309: 83 e4 f0 and $0xfffffff0,%esp
804830c: 83 7d 08 01 cmpl $0x1,0x8(%ebp)
8048310: 74 27 je 8048339 <main+0x39>
8048312: 8d b6 00 00 00 00 lea 0x0(%esi),%esi
8048318: e8 23 01 00 00 call 8048440 <_Z4accuv>
804831d: e8 1e 01 00 00 call 8048440 <_Z4accuv>
8048322: e8 19 01 00 00 call 8048440 <_Z4accuv>
8048327: e8 14 01 00 00 call 8048440 <_Z4accuv>
804832c: 83 eb 01 sub $0x1,%ebx
804832f: 90 nop
8048330: 75 e6 jne 8048318 <main+0x18>
8048332: 31 c0 xor %eax,%eax
8048334: 8b 5d fc mov -0x4(%ebp),%ebx
8048337: c9 leave
8048338: c3 ret
8048339: b8 80 96 98 00 mov $0x989680,%eax
804833e: 66 90 xchg %ax,%ax
8048340: 8b 15 18 a0 04 08 mov 0x804a018,%edx
8048346: 83 c2 04 add $0x4,%edx
8048349: 89 15 18 a0 04 08 mov %edx,0x804a018
804834f: 8b 15 18 a0 04 08 mov 0x804a018,%edx
8048355: 83 c2 04 add $0x4,%edx
8048358: 89 15 18 a0 04 08 mov %edx,0x804a018
804835e: 8b 15 18 a0 04 08 mov 0x804a018,%edx
8048364: 83 c2 04 add $0x4,%edx
8048367: 89 15 18 a0 04 08 mov %edx,0x804a018
804836d: 8b 15 18 a0 04 08 mov 0x804a018,%edx
8048373: 83 c2 04 add $0x4,%edx
8048376: 83 e8 01 sub $0x1,%eax
8048379: 89 15 18 a0 04 08 mov %edx,0x804a018
804837f: 75 bf jne 8048340 <main+0x40>
8048381: eb af jmp 8048332 <main+0x32>
8048383: 90 nop
...
8048440 <_Z4accuv>:
8048440: a1 18 a0 04 08 mov 0x804a018,%eax
8048445: 83 c0 04 add $0x4,%eax
8048448: a3 18 a0 04 08 mov %eax,0x804a018
804844d: c3 ret
804844e: 90 nop
804844f: 90 nop
Es scheint der direkte Anruf Zweig ist definitiv weniger als die Funktion Poin ter Zweig. Aber warum läuft der Funktionszeigerzweig schneller als der direkte Aufruf?
Und beachten Sie, dass ich nur "Zeit" für die Messung der Zeit verwendet habe. Ich habe clock_gettime verwendet, um die Messung durchzuführen, und ähnliche Ergebnisse erhalten.
für Format Es ist leider ‚root @ ubuntu:/cm/gt # g ++ haha. CPP -o za.exx -O3 root @ ubuntu:/cm/gt # Zeit ./za.exx reale \t 0m0.092s Benutzer \t 0m0.084s sys \t 0m0.004s root @ ubuntu:/cm/gt # Zeit./za.exx 1 echte \t 0m0.146s Benutzer \t 0m0.072s sys \t 0m0.000s' –
Beide Codes auf gcc in der gleichen Zeit laufen 4.7. – mfontanini