[llvm-dev] RFC: Getting ProfileSummaryInfo and BlockFrequencyInfo from various types of passes under the new pass manager
Fedor Sergeev via llvm-dev
llvm-dev at lists.llvm.org
Mon Mar 4 14:05:20 PST 2019
On 3/4/19 10:49 PM, Hiroshi Yamauchi wrote:
>
>
> On Mon, Mar 4, 2019 at 10:55 AM Hiroshi Yamauchi <yamauchi at google.com
> <mailto:yamauchi at google.com>> wrote:
>
>
>
> On Sat, Mar 2, 2019 at 12:58 AM Fedor Sergeev
> <fedor.sergeev at azul.com <mailto:fedor.sergeev at azul.com>> wrote:
>
>
>
> On 3/2/19 2:38 AM, Hiroshi Yamauchi wrote:
>> Here's a sketch of the proposed approach for just one
>> pass(but imagine more)
>>
>> https://reviews.llvm.org/D58845
>>
>> On Fri, Mar 1, 2019 at 12:54 PM Fedor Sergeev via llvm-dev
>> <llvm-dev at lists.llvm.org <mailto:llvm-dev at lists.llvm.org>> wrote:
>>
>> On 2/28/19 12:47 AM, Hiroshi Yamauchi via llvm-dev wrote:
>>> Hi all,
>>>
>>> To implement more profile-guided optimizations, we’d
>>> like to use ProfileSummaryInfo (PSI) and
>>> BlockFrequencyInfo (BFI) from more passes of various
>>> types, under the new pass manager.
>>>
>>> The following is what we came up with. Would appreciate
>>> feedback. Thanks.
>>>
>>> Issue
>>>
>>> It’s not obvious (to me) how to best do this, given that
>>> we cannot request an outer-scope analysis result from an
>>> inner-scope pass through analysis managers [1] and that
>>> we might unnecessarily running some analyses unless we
>>> conditionally build pass pipelines for PGO cases.
>> Indeed, this is an intentional restriction in new pass
>> manager, which is more or less a reflection of a
>> fundamental property of outer-inner IRUnit relationship
>> and transformations/analyses run on those units. The main
>> intent for having those inner IRUnits (e.g. Loops) is to
>> run local transformations and save compile time
>> on being local to a particular small piece of IR. Loop
>> Pass manager allows you to run a whole pipeline of
>> different transformations still locally, amplifying the save.
>> As soon as you run function-level analysis from within
>> the loop pipeline you essentially break this pipelining.
>> Say, as you run your loop transformation it modifies the
>> loop (and the function) and potentially invalidates the
>> analysis,
>> so you have to rerun your analysis again and again. Hence
>> instead of saving on compile time it ends up increasing it.
>>
>>
>> Exactly.
>>
>>
>> I have hit this issue somewhat recently with dependency
>> of loop passes on BranchProbabilityInfo.
>> (some loop passes, like IRCE can use it for profitability
>> analysis).
>>
>> The only solution that appears to be reasonable there is
>> to teach all the loops passes that need to be pipelined
>> to preserve BPI (or any other module/function-level
>> analyses) similar to how they preserve DominatorTree and
>> other "LoopStandard" analyses.
>>
>>
>> Is this implemented - do the loop passes preserve BPI?
> Nope, not implemented right now.
> One of the problems is that even loop canonicalization passes
> run at the start of loop pass manager dont preserve it
> (and at least LoopSimplifyCFG does change control flow).
>>
>> In buildFunctionSimplificationPipeline
>> (where LoopFullUnrollPass is added as in the sketch),
>> LateLoopOptimizationsEPCallbacks
>> and LoopOptimizerEndEPCallbacks seem to allow some arbitrary
>> loop passes to be inserted into the pipelines (via flags)?
>>
>> I wonder how hard it'd be to teach all the relevant loop
>> passes to preserve BFI(or BPI)..
> Well, each time you restructure control flow around the loops
> you will have to update those extra analyses,
> pretty much the same way as DT is being updated through
> DomTreeUpdater.
> The trick is to design a proper update interface (and then
> implement it ;) ).
> And I have not spent enough time on this issue to get a good
> idea of what that interface would be.
>
>
> Hm, sounds non-trivial :) noting BFI depends on BPI.
>
>
> To step back, it looks like:
>
> want to use profiles from more passes -> need to get BFI (from loop
> passes) -> need all the loop passes to preserve BFI.
>
> I wonder if there's no way around this.
Indeed. I believe this is a general consensus here.
regards,
Fedor.
>
>
>
> regards,
> Fedor.
>
>>
>>> It seems that for different types of passes to be able
>>> to get PSI and BFI, we’d need to ensure PSI is cached
>>> for a non-module pass, and PSI, BFI and the
>>> ModuleAnalysisManager proxy are cached for a loop pass
>>> in the pass pipelines. This may mean potentially needing
>>> to insert BFI/PSI in front of many passes [2]. It seems
>>> not obvious how to conditionally insert BFI for PGO
>>> pipelines because there isn’t always a good flag to
>>> detect PGO cases [3] or we tend to build pass pipelines
>>> before examining the code (or without propagating enough
>>> info down) [4].
>>>
>>> Proposed approach
>>>
>>> - Cache PSI right after the profile summary in the IR is
>>> written in the pass pipeline [5]. This would avoid the
>>> need to insert RequiredAnalysisPass for PSI before each
>>> non-module pass that needs it. PSI can be technically
>>> invalidated but unlikely. If it does, we insert another
>>> RequiredAnalysisPass[6].
>>>
>>> - Conditionally insert RequireAnalysisPass for BFI, if
>>> PGO, right before each loop pass that needs it. This
>>> doesn't seem avoidable because BFI can be invalidated
>>> whenever the CFG changes. We detect PGO based on the
>>> command line flags and/or whether the module has the
>>> profile summary info (we may need to pass the module to
>>> more functions.)
>>>
>>> - Add a new proxy ModuleAnalysisManagerLoopProxy for a
>>> loop pass to be able to get to the ModuleAnalysisManager
>>> in one step and PSI through it.
>>>
>>> Alternative approaches
>>>
>>> Dropping BFI and use PSI only
>>> We could consider not using BFI and solely relying on
>>> PSI and function-level profiles only (as opposed to
>>> block-level), but profile precision would suffer.
>>>
>>> Computing BFI in-place
>>> We could consider computing BFI “in-place” by directly
>>> running BFI outside of the pass manager [7]. This would
>>> let us avoid using the analysis manager constraints but
>>> it would still involve running an outer-scope analysis
>>> from an inner-scope pass and potentially cause problems
>>> in terms of pass pipelining and concurrency. Moreover, a
>>> potential downside of running analyses in-place is that
>>> it won’t take advantage of cached analysis results
>>> provided by the pass manager.
>>>
>>> Adding inner-scope versions of PSI and BFI
>>> We could consider adding a function-level and loop-level
>>> PSI and loop-level BFI, which internally act like their
>>> outer-scope versions but provide inner-scope results
>>> only. This way, we could always call getResult for PSI
>>> and BFI. However, this would still involve running an
>>> outer-scope analysis from an inner-scope pass.
>>>
>>> Caching the FAM and the MAM proxies
>>> We could consider caching the FunctionalAnalysisManager
>>> and the ModuleAnalysisManager proxies once early on
>>> instead of adding a new proxy. But it seems to not
>>> likely work well because the analysis cache key type
>>> includes the function or the module and some pass may
>>> add a new function for which the proxy wouldn’t be
>>> cached. We’d need to write and insert a pass in select
>>> locations to just fill the cache. Adding the new proxy
>>> would take care of these with a three-line change.
>>>
>>> Conditional BFI
>>> We could consider adding a conditional BFI analysis that
>>> is a wrapper around BFI and computes BFI only if
>>> profiles are available (either checking the module has
>>> profile summary or depend on the PSI.) With this, we
>>> wouldn’t need to conditionally build pass pipelines and
>>> may work for the new pass manager. But a similar
>>> wouldn’t work for the old pass manager because we cannot
>>> conditionally depend on an analysis under it.
>> There is LazyBlockFrequencyInfo.
>> Not sure how well it fits this idea.
>>
>>
>> Good point. LazyBlockFrequencyInfo seems usable with the old
>> pass manager (save unnecessary BFI/BPI) and would work for
>> function passes. I think the restriction still applies - a
>> loop pass cannot still request (outer-scope) BFI, lazy or
>> not, new or old (pass manager). Another assumption is that
>> it'd be cheap and safe to unconditionally depend on PSI or
>> check the module's profile summary.
>>
>>
>> regards,
>> Fedor.
>>
>>>
>>>
>>> [1] We cannot call AnalysisManager::getResult for an
>>> outer scope but only getCachedResult. Probably because
>>> of potential pipelining or concurrency issues.
>>> [2] For example, potentially breaking up multiple
>>> pipelined loop passes and insert
>>> RequireAnalysisPass<BlockFrequencyAnalysis> in front of
>>> each of them.
>>> [3] For example, -fprofile-instr-use and
>>> -fprofile-sample-use aren’t present in ThinLTO post link
>>> builds.
>>> [4] For example, we could check whether the module has
>>> the profile summary metadata annotated when building
>>> pass pipelines but we don’t always pass the module down
>>> to the place where we build pass pipelines.
>>> [5] By inserting RequireAnalysisPass<ProfileSummaryInfo>
>>> after the PGOInstrumentationUse and the
>>> SampleProfileLoaderPass passes (and around the
>>> PGOIndirectCallPromotion pass for the Thin LTO post link
>>> pipeline.)
>>> [6] For example, the context-sensitive PGO.
>>> [7] Directly calling its constructor along with the
>>> dependent analyses results, eg. the jump threading pass.
>>>
>>> _______________________________________________
>>> LLVM Developers mailing list
>>> llvm-dev at lists.llvm.org <mailto:llvm-dev at lists.llvm.org>
>>> https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
>>
>> _______________________________________________
>> LLVM Developers mailing list
>> llvm-dev at lists.llvm.org <mailto:llvm-dev at lists.llvm.org>
>> https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20190305/054eda98/attachment.html>
More information about the llvm-dev
mailing list