Don't use plain "ret" instructions at targets of jump instructions,

since the branch caches on at least Athlon XP through Athlon 64 CPU's
don't understand such instructions and guarantee a cache miss taking
at least 10 cycles.  Use the documented workaround "ret $0" instead
("nop; ret" also works, but "ret $0" is probably faster on old CPUs).

Normal code (even asm code) doesn't branch to "ret", since there is
usually some cleanup to do, but the __mcount, .mcount and .mexitcount
entry points were optimized too well to have the minimum number of
instructions (3 instructions each if profiling is not enabled) and
they did this.  I didn't see a significant number of cache misses for
.mexitcount, but for the shared "ret" for __mcount and .mcount I
observed cache misses costing 26 cycles each.  For a send(2) syscall
that makes about 70 function calls, the cost of these cache misses
alone increased the syscall time from about 4000 cycles to about 7000
cycles.  4000 is for a profiling (GUPROF) kernel with profiling disabled;
after this fix, configuring profiling only costs about 600 cycles in the
4000, which is consistent with almost perfect branch prediction in the
mcounting calls.
This commit is contained in:
Bruce Evans 2007-11-29 02:01:21 +00:00
parent 7e7c8806bf
commit d5c90663b2
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=174067
2 changed files with 4 additions and 4 deletions

View file

@ -135,7 +135,7 @@ __mcount: \n\
popq %rdx \n\
popq %rax \n\
.mcount_exit: \n\
ret \n\
ret $0 \n\
");
#else /* !__GNUCLIKE_ASM */
#error "this file needs to be ported to your compiler"
@ -187,7 +187,7 @@ GMON_PROF_HIRES = 4 \n\
popq %rdx \n\
popq %rax \n\
.mexitcount_exit: \n\
ret \n\
ret $0 \n\
");
#endif /* __GNUCLIKE_ASM */

View file

@ -113,7 +113,7 @@ __mcount: \n\
addl $8,%esp \n\
popfl \n\
.mcount_exit: \n\
ret \n\
ret $0 \n\
");
#else /* !__GNUCLIKE_ASM */
#error "this file needs to be ported to your compiler"
@ -157,7 +157,7 @@ GMON_PROF_HIRES = 4 \n\
popl %eax \n\
popl %edx \n\
.mexitcount_exit: \n\
ret \n\
ret $0 \n\
");
#endif /* __GNUCLIKE_ASM */