<div dir="ltr">Apologies for the cross-post, this effects both clang and llvm.<br><br>I was looking into the startup time of clang on small files<br>(<a href="http://lists.cs.uiuc.edu/pipermail/cfe-commits/Week-of-Mon-20080818/007171.html" target="_blank">http://lists.cs.uiuc.edu/pipermail/cfe-commits/Week-of-Mon-20080818/007171.html</a>)<br>
and discovered that a significant amount of our startup time was being<br>spent in the linker resolving weak symbols. At least on Darwin, this was<br>actually the dominant factor in our startup time. Our use of C++ means<br>
that by default we tend to have quite a few weak symbols in our binaries.<br><br>There are two ways to reduce this startup cost, one start is to use <br>-fvisibility-inlines-hidden for compilers which support it (GCC). This marks<br>
inline member functions as hidden which means they do not appear as<br>weak external symbols in the final linked image.<br><br>The second is to use an explicit list of exports which is provided to the<br>linker. For applications like llvm-as which do no loading of plugins the<br>
export list is simply "_main" which is easy to specify.<br><br>Here are some timing results on Darwin of versions of clang, llc, and llvm-as <br>for each option. The -cur command is the way the current executable is build, -vih<br>
is the executable compiled with -visibility-inlines-hidden, and -export is the<br>executable built with an export list of "_main" only (this subsumes <br>-fvisibility-inlines-hidden). <br><br>These are all Release builds. empty.ll is in fact empty, empty.bc is the resultant <br>
.bc, and empty.c has one int variable. runN is a program which simply fork-execs<br>the given program N times (1000 in this case).<br><br>=====<br><br># For a baseline:<br>ddunbar@ddunbar2:rt$ time runN 1000 `which true`<br>
real 0m1.561s<br>user 0m0.303s<br>sys 0m1.136s<br><br>--- clang ---<br># 4152 weak external & defined symbols<br><br>ddunbar@ddunbar2:rt$ time runN 1000 ./clang-cur empty.c <br>real 0m8.398s<br>user 0m4.708s<br>
sys 0m3.299s<br><br># 1937 weak external & defined symbols<br>ddunbar@ddunbar2:rt$ time runN 1000 ./clang-vih empty.c <br>real 0m6.732s<br>user 0m3.250s<br>sys 0m3.124s<br><br># 0 weak external & defined symbols<br>
ddunbar@ddunbar2:rt$ time runN 1000 ./clang-export empty.c <br>real 0m4.998s<br>user 0m1.781s<br>sys 0m2.923s<br><br>--- llc ---<br><br># 3914 weak external & defined symbols<br>ddunbar@ddunbar2:rt$ time runN 1000 ./llc-cur -f -fast -regalloc=local empty.bc <br>
real 0m8.958s<br>user 0m4.331s<br>sys 0m4.170s<br><br># 2037 weak external & defined symbols<br>ddunbar@ddunbar2:rt$ time runN 1000 ./llc-vih -f -fast -regalloc=local empty.bc <br>real 0m7.482s<br>user 0m3.056s<br>
sys 0m3.932s<br><br># 0 weak external & defined symbols<br>ddunbar@ddunbar2:rt$ time runN 1000 ./llc-export -f -fast -regalloc=local empty.bc <br>real 0m6.123s<br>user 0m1.919s<br>sys 0m3.775s<br><br>--- llvm-as ---<br>
<br># 1370 weak external & defined symbols<br>ddunbar@ddunbar2:rt$ time runN 1000 ./llvm-as-cur -f empty.ll<br>real 0m4.683s<br>user 0m2.036s<br>sys 0m2.362s<br><br># 725 weak external & defined symbols<br>
ddunbar@ddunbar2:rt$ time runN 1000 ./llvm-as-vih -f empty.ll<br>real 0m4.141s<br>user 0m1.606s<br>sys 0m2.288s<br><br># 0 weak external & defined symbols<br>ddunbar@ddunbar2:rt$ time runN 1000 ./llvm-as-export -f empty.ll<br>
real 0m3.376s<br>user 0m0.969s<br>sys 0m2.180s<br><br>====<br><br>The performance difference is rather large for these small files. My suggestion based on <br>these results is that we enable -fvisibility-inlines-hidden by default for platforms which <br>
support it, and add a Makefile flag which allows individual programs to specify their export <br>list (probably just as a list of symbols). For simple tools which have no exports we<br>would set this to _main.<br><br>Seems reasonable?<br>
<br> - Daniel<br><br></div>