{"id":212,"date":"2009-09-19T16:45:53","date_gmt":"2009-09-19T23:45:53","guid":{"rendered":"http:\/\/gameangst.com\/?p=212"},"modified":"2009-09-19T16:45:49","modified_gmt":"2009-09-19T23:45:49","slug":"minimizing-code-bloat-excessive-inlining","status":"publish","type":"post","link":"http:\/\/gameangst.com\/?p=212","title":{"rendered":"Minimizing Code Bloat: Excessive Inlining"},"content":{"rendered":"<p><em>This article is a continuation of <a href=\"http:\/\/gameangst.com\/?p=46\">Minimizing Code Bloat for Faster Builds and Smaller Executables<\/a>.<\/em><\/p>\n<p>When a function is inlined its code is, from the perspective of the compiler, replicated to every place where the function is called. \u00a0For very simple functions the inlined code can be smaller than the out-of-line function call, and the result is a net reduction in code size. \u00a0For most functions, however, the function code is larger than the function call and inlining will increase executable size.<\/p>\n<p>Code bloat from excessive inlining usually isn&#8217;t a problem if you&#8217;re smart enough to trust your compiler. \u00a0Compilers apply a set of heuristics to decide whether the performance benefits of inlining a function justify the costs. \u00a0If the cost isn&#8217;t justified, the compiler won&#8217;t inline. \u00a0Additionally, most compilers err on the side of not inlining. \u00a0Unless you&#8217;ve overridden the default compiler behavior with a <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/z8y1yy88.aspx\" target=\"_blank\">__forceinline<\/a> directive, you can safely assume that any code bloat that comes from inlining is justified by improved performance.<\/p>\n<p>Still, you can never be too careful, so it&#8217;s worth checking to see how much\u00a0inlining\u00a0is costing you.<\/p>\n<p>One technique for measuring the cost of inlining is compiling your engine with inlining enabled and again with inlining disabled, and comparing the size of the resulting executables. \u00a0If the executable without inlining is a lot smaller, you&#8217;re probably\u00a0inlining\u00a0too much. \u00a0Even if your executable isn&#8217;t significantly smaller with inlining disabled, you may still be suffering from excessive\u00a0inlining. \u00a0In some cases inlining a function can result in reduced code size because the inlined code opens up optimization opportunities that were otherwise invisible to the compiler. \u00a0Code size reductions from well inlined functions can offset code size increases from poorly inlined functions, making quick executable size comparisons unreliable.<\/p>\n<p>A better way to identify excessive\u00a0inlining\u00a0is to use DumpBin on the .obj files of your application. \u00a0Even with inlining enabled, inline functions will be instantiated into every object file in which they are used. \u00a0All those duplicate instantiations are merged or removed at link time, but if you run DumpBin on the .lib or .obj files you can measure how many object files the inlined functions are being replicated into. \u00a0This is similar to the technique I proposed to measure the compile-time cost of <a href=\"http:\/\/gameangst.com\/?p=226\">template overspecialization<\/a>. \u00a0Sort the database of symbols extracted from DumpBin by <em>symbol_size<\/em> * <em>symbol_count<\/em>, where <em>symbol_count<\/em> is the number of object files in which a particular symbol appears,\u00a0and skim through the top 100. \u00a0 This isn&#8217;t a perfect measure of code bloat from function inlining, but it can usually catch the worst offenders.<\/p>\n<p>You can improve the report I described above by discarding symbols with sizes below some threshold. \u00a0These will be functions whose inlined code is smaller than an out-of-line function call and are consequently not a factor in code bloat. \u00a0Likewise, if you haven&#8217;t been abusing the <em>__forceinline <\/em>directive, you can discard symbols with sizes above some threshold. \u00a0Very large functions will never automatically be inlined by the compiler, so they don&#8217;t increase the size of the executable. \u00a0They do, however, contribute unfavorably to compile and link times, but I&#8217;ll talk more about that later.<\/p>\n<p>One last thing&#8211;be sure to review the source for any function you&#8217;re considering deinlining. \u00a0Consider carefully how the compiler sees the function in isolation and in the context in which it is inlined. \u00a0Are the function parameter values typically known at compile time at the call site? \u00a0Is the ratio of the number of times the function is executed in a frame to the number of times the function is called in the source very large? \u00a0If the answer to either of these questions is yes, the function may be a good candidate for inlining regardless of what the symbol analysis says.<\/p>\n<p>Next I&#8217;ll be looking at <a href=\"http:\/\/gameangst.com\/?p=222\">static allocations<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This article is a continuation of Minimizing Code Bloat for Faster Builds and Smaller Executables. When a function is inlined its code is, from the perspective of the compiler, replicated to every place where the function is called. \u00a0For very simple functions the inlined code can be smaller than the out-of-line function call, and the [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[1],"tags":[8,14,7],"_links":{"self":[{"href":"http:\/\/gameangst.com\/index.php?rest_route=\/wp\/v2\/posts\/212"}],"collection":[{"href":"http:\/\/gameangst.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/gameangst.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/gameangst.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/gameangst.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=212"}],"version-history":[{"count":19,"href":"http:\/\/gameangst.com\/index.php?rest_route=\/wp\/v2\/posts\/212\/revisions"}],"predecessor-version":[{"id":308,"href":"http:\/\/gameangst.com\/index.php?rest_route=\/wp\/v2\/posts\/212\/revisions\/308"}],"wp:attachment":[{"href":"http:\/\/gameangst.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=212"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/gameangst.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=212"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/gameangst.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=212"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}