<div dir="ltr">Hi Nick,<div><br></div><div>Your points make a lot of sense. However:</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<span style="font-family:arial,sans-serif;font-size:13px">I have a strong problem with global metrics. Things like "only allow X% code size growth" mean that whether I inline this callsite can depend on seemingly unrelated factors like how many other functions are in the same module, even outside the call stack at hand. Similarly for other things like cutoffs about how many inlinings are to be performed (now it depends on traversal order, and if you provide the inliner with a more complete program then it may chose to not inline calls it otherwise would have). I don't like spooky action at a distance, it's hard to predict and hard to debug.</span></blockquote>
<div><span style="font-family:arial,sans-serif;font-size:13px"><br></span></div><div><font face="arial, sans-serif">Doesn't this all depend on the confidence that your algorithm has about inlining a particular callsite? I'd agree if the global cutoffs were stopping you from performing an inlining decision where your heuristics tell you it is definitely worthwhile. But not all decisions are so clear, right? We surely end up with a bunch of "speculative" inlining decisions where the win/no-win is not clear static-ahead-of-time. If the global cutoff was setting a limit on the number of speculative inlining decisions made, I don't see that as an issue because you're limiting code growth and yet still allowing for a non-conservative heuristic.</font></div>
<div><font face="arial, sans-serif"><br></font></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><span style="font-family:arial,sans-serif;font-size:13px">In the past I've seem them used for their ability to game benchmarks (that's my side of the story, not theirs). You provide an inliner with tweakable knobs that have really messy complicated interactions all across the inliner depending on all sorts of things, then you select the numbers that happen to give you a 20% speed up on SPEC for no good reason, and call it success. Attribute the success to the flexibility provided by the design.</span></blockquote>
<div><span style="font-family:arial,sans-serif;font-size:13px"><br></span></div><div><span style="font-family:arial,sans-serif;font-size:13px">Yes, I can see that is a serious problem. It is difficult to avoid however - if (unlike Google and Apple) we don't have a clear defined set of programs we want to make faster (you have your internal Google code which is what you care about, Apple has a similar ecosystem of programs), we rely wholly on benchmarks to provide a decent scope for evaluation. Agreed, the current benchmark sets are limited, but we have to play with what we have to an extent!</span></div>
<div><span style="font-family:arial,sans-serif;font-size:13px"><br></span></div><div><span style="font-family:arial,sans-serif;font-size:13px">Cheers,</span></div><div><span style="font-family:arial,sans-serif;font-size:13px"><br>
</span></div><div><span style="font-family:arial,sans-serif;font-size:13px">James</span></div></div><div class="gmail_extra"><br><br><div class="gmail_quote">On 6 August 2014 10:12, Nick Lewycky <span dir="ltr"><<a href="mailto:nicholas@mxc.ca" target="_blank">nicholas@mxc.ca</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="">James Molloy wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Hi Nick,<br>
<br>
I'm not an expert on inlining algorithms so please excuse my naivite.<br>
But usually these "top-down versus bottom-up" arguments (in other<br>
domains, at least), come to the obvious conclusion that both have merits<br>
so let's create a hybrid. Why is this not the case here too?<br>
</blockquote>
<br></div>
It is. Our current bottom-up inliner is already a hybrid, we sometimes decide to inline the caller into the callee instead of inlining the callee into the caller.<div class=""><br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
As far as I can tell, Yin's pass simply provides a method to add global<br>
context to local decisions.<br>
</blockquote>
<br></div>
I have a strong problem with global metrics. Things like "only allow X% code size growth" mean that whether I inline this callsite can depend on seemingly unrelated factors like how many other functions are in the same module, even outside the call stack at hand. Similarly for other things like cutoffs about how many inlinings are to be performed (now it depends on traversal order, and if you provide the inliner with a more complete program then it may chose to not inline calls it otherwise would have). I don't like spooky action at a distance, it's hard to predict and hard to debug.<br>

<br>
We *do* want more context in the inliner, that's the largest known deficiency of our current one. Again, the pass manager rewrite is taking place to allow the inliner to call into function analysis passes so that we can have more context available when making our inlining decision. It's just a long, slow path to getting what we want.<div class="">
<br>
<br>
 Algorithms such as a bottom-up inliner<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
analyze a callsite and assign it a value. This could be bottom-up or<br>
top-down, it doesn't really matter. What matters is that eventually, all<br>
(rational) callsites end up in the same sorted datastructure and are<br>
addressed in order.<br>
<br>
Am I missing something?<br>
</blockquote>
<br></div>
The current inliner doesn't assign values across the whole call graph then decide where to inline.<br>
<br>
Firstly, the local decision (looking at a single caller-callee pair through a particular call site) works by attempting to determine how much of the callee will be live given the values known at the caller. For instance, we will resolve a switch statement to its destination block, and potentially eliminate other callees. These simplifications would still be possible even if we calculated everything up front.<br>

<br>
Secondly, we iterate with the function passes optimizing the new function after each inlining is performed. This may eliminate dead code (potentially removing call graph edges) and can resolve loads (potentially creating new call graph edges as indirect calls are resolved to direct calls). Handling the CFG updates is one of the more interesting and difficult parts of the inliner, and it's very important for getting C++ virtual calls right. This sort of thing can't be calculated up front.<br>

<br>
Nick<br>
<br>
PS. You may have guessed that I'm just plain prejudiced against top-down inliners. I am, and I should call that out before going too far down into the discussion.<br>
<br>
In the past I've seem them used for their ability to game benchmarks (that's my side of the story, not theirs). You provide an inliner with tweakable knobs that have really messy complicated interactions all across the inliner depending on all sorts of things, then you select the numbers that happen to give you a 20% speed up on SPEC for no good reason, and call it success. Attribute the success to the flexibility provided by the design.<br>

<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="">
On 6 August 2014 08:54, Nick Lewycky <<a href="mailto:nicholas@mxc.ca" target="_blank">nicholas@mxc.ca</a><br></div><div class="">
<mailto:<a href="mailto:nicholas@mxc.ca" target="_blank">nicholas@mxc.ca</a>>> wrote:<br>
<br>
    Hal Finkel wrote:<br>
<br>
        I'd like you to elaborate on your assertion here, however, that<br>
        a "topdown inliner is going to work best when you have the whole<br>
        program." It seems to me that, whole program or not, a top-down<br>
        inlining approach is exactly what you want to avoid the<br></div>
        vector-push_back-cold-path- inlining problem (because, from the<div><div class="h5"><br>
        caller, you see many calls to push_back, which is small --<br>
        because the hot path is small and the cold path has not (yet)<br>
        been inlined -- and inlines them all, at which point it can make<br>
        a sensible decision about the cold-path calls).<br>
<br>
<br>
    I don't see that. You get the same information when looking at a<br>
    pair of functions and deciding whether to inline. With the bottom-up<br>
    walk, we analyze the caller and callee in their entirety before<br>
    deciding whether to inline. I assume a top-down inliner would do the<br>
    same.<br>
<br>
    If you have a top-down traversal and you don't have the whole<br>
    program, the first problem you have is a whole ton of starting<br>
    points. At first blush bottom up seems to have the same problem,<br>
    except that they are generally very straight-forward leaf functions<br>
    -- setters and getters or little loops to test for a property. Top<br>
    down you don't yet know what you've got, and it has lots of calls<br>
    that may access arbitrary memory. In either case, you apply your<br>
    metric to inline or not. Then you run the function-level passes to<br>
    perform simplification. Bottom up, you're much more likely to get<br>
    meaningful simplifications -- your getter/setter melts away. Top<br>
    down you may remove some redundant loads or dead stores, but you<br>
    still don't know what's going on because you have these opaque<br>
    not-yet-analyzed callees in the way. If you couldn't analyze the<br>
    memory before, inlining one level away hasn't helped you, and the<br>
    function size has grown. You don't get the simplifications until you<br>
    go all the way down the call stack to the setters and getters etc.<br>
<br>
    There's a fix for this, and that's to perform a sort of symbolic<br>
    execution and just keep track of what the program has done so far<br>
    (ie. what values registers have taken on so far, which pointers have<br>
    escaped etc.), and make each inlining decision in program execution<br>
    order. But that fix doesn't get you very far if you haven't got a<br>
    significant chunk of program to work with.<br>
<br>
<br>
    Nick<br>
    ______________________________ _________________<br>
    llvm-commits mailing list<br></div></div>
    <a href="mailto:llvm-commits@cs.uiuc.edu" target="_blank">llvm-commits@cs.uiuc.edu</a> <mailto:<a href="mailto:llvm-commits@cs.uiuc.edu" target="_blank">llvm-commits@cs.uiuc.<u></u>edu</a>><br>
    <a href="http://lists.cs.uiuc.edu/" target="_blank">http://lists.cs.uiuc.edu/</a> mailman/listinfo/llvm-commits<br>
    <<a href="http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits" target="_blank">http://lists.cs.uiuc.edu/<u></u>mailman/listinfo/llvm-commits</a>><br>
<br>
<br>
</blockquote>
<br>
</blockquote></div><br></div>