This is an archive of the discontinued LLVM Phabricator instance.

[IR] Reimplement time tracing of NewPassManager by PassInstrumentation framework
ClosedPublic

Authored by dongjunduo on Aug 16 2022, 5:55 AM.

Details

Summary

This patch is a enhancement of D74516.

The previous implementation of time tracing in NewPassManager is direct but messive.

The key codes are like the demo below:

 /// Runs the function pass across every function in the module.
 PreservedAnalyses run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM,
                       LazyCallGraph &CG, CGSCCUpdateResult &UR) {
     /// ...
     PreservedAnalyses PassPA;
     {
       TimeTraceScope TimeScope(Pass.name());
       PassPA = Pass.run(F, FAM);
     }
     /// ...
}

It can be bothered to judge where should we add the tracing codes by hands.

With the PassInstrumentation framework, we can easily add Before/After callback
functions to add time tracing codes.

Thus, the implementation of that can be clearer than before by this mechanism.

Further more, we need not to add time tracing codes by hands when new types of PassManager are added.

Through this improved method, the time tracing results of pass execution time now are approximately equal to the previous one.

Demo:

{   // ... (Previous)
    "dur": 31,
    "name": "Total AnnotationRemarksPass",
    // ...
},
{
    // ... (Now)
    "dur": 50,
    "name": "Total AnnotationRemarksPass",
    // ...
},
{
    // ... (Previous)
    "dur": 840,
    "name": "Total AlwaysInlinerPass",
    // ...
},
{
    // ... (Now)
    "dur": 725,
    "name": "Total AlwaysInlinerPass",
    // ...
}

Diff Detail

Event Timeline

dongjunduo created this revision.Aug 16 2022, 5:55 AM
Herald added a project: Restricted Project. · View Herald TranscriptAug 16 2022, 5:55 AM
dongjunduo requested review of this revision.Aug 16 2022, 5:55 AM
Herald added a project: Restricted Project. · View Herald TranscriptAug 16 2022, 5:55 AM
dongjunduo edited the summary of this revision. (Show Details)Aug 16 2022, 5:56 AM
dongjunduo added reviewers: jamieschmeiser, Whitney.
dongjunduo edited the summary of this revision. (Show Details)Aug 16 2022, 6:00 AM
dongjunduo edited the summary of this revision. (Show Details)
dongjunduo edited the summary of this revision. (Show Details)
dongjunduo edited the summary of this revision. (Show Details)Aug 16 2022, 6:22 AM
myhsu added a reviewer: myhsu.Aug 16 2022, 9:03 AM
myhsu added a subscriber: myhsu.

I don't think this is Clang-specific, could you update the title?

jamieschmeiser added inline comments.Aug 17 2022, 8:13 AM
llvm/lib/IR/PassTimeProfiling.cpp
42 ↗(On Diff #452973)

This looks like it is copied with changes from Passes/StandardInstructions.cpp. You should almost never replicate code for several reasons. 1) If there is a bug in the code, it probably won't be fixed in all the copies; 2) code bloat 3) It is confusing because it is unexpected. If there are only minor changes, it is difficult to recognize the changes. I see that the loop case is different. Perhaps a parameter to control what happens for a loop? Why not put the new functionality in Passes/StandardInstructions.cpp?

Considering that getIRName is only used for identifying the IR, do you even need the change?

dongjunduo retitled this revision from [Clang] Reimplement time tracing of NewPassManager by PassInstrumentation framework to [WIP] [IR] Reimplement time tracing of NewPassManager by PassInstrumentation framework.Aug 22 2022, 7:47 AM

Move class PassTimeProfiling to StandardInstrumentation.cpp

You want the timing extensions to be the last ones called before the pass and the first ones at the end of the pass so that the overhead of the other callbacks is not included in the timings. Does PassInstrumentationCallbacks have the ability to specify that the pass be registered as the first callback? If not, add a bool parameter that allows it to be placed at the front with a default of false, and then put all timing extensions at the end, with the parameter being set to true for the registering of the atEnd callback (to put them as the first ones called). Also, add a comment that the timing ones should be last for this reason.

llvm/lib/Passes/StandardInstrumentations.cpp
1165

Rather than testing if the option is set before and after each pass, test in registerCallBacks and only register when getTimeTraceProfilerInstance() returns a pointer.

Adjust the location of TimeProfiler's start and end functions

dongjunduo retitled this revision from [WIP] [IR] Reimplement time tracing of NewPassManager by PassInstrumentation framework to [IR] Reimplement time tracing of NewPassManager by PassInstrumentation framework.Aug 30 2022, 5:39 AM
dongjunduo edited the summary of this revision. (Show Details)
myhsu added inline comments.Sep 3 2022, 2:28 PM
llvm/include/llvm/Passes/StandardInstrumentations.h
409

Could we use /// here to get better doxygen appearances?

413

nit: can we move private members here (or using struct instead)

llvm/lib/Passes/StandardInstrumentations.cpp
1151

nit: personally I would simply rename the local PIC rather than spelling out this

1175

ditto the one above

dongjunduo updated this revision to Diff 457964.Sep 5 2022, 6:10 AM

Restyle the callback registration and related comment

dongjunduo marked an inline comment as done.Sep 5 2022, 6:17 AM
dongjunduo added inline comments.
llvm/include/llvm/Passes/StandardInstrumentations.h
413

nit: can we move private members here (or using struct instead)

413

That class is designed following the class PrintIRInstrumentation(ref)

I think it's best to keep the class structure consistent. : )

llvm/lib/Passes/StandardInstrumentations.cpp
1151

dtto the one above.

dongjunduo added inline comments.Sep 5 2022, 6:19 AM
llvm/lib/Passes/StandardInstrumentations.cpp
1151

@jamieschmeiser
The callback functions of TimeProfiler can be registered if and only if "-ftime-trace" is given. : )

dongjunduo updated this revision to Diff 458072.Sep 5 2022, 6:02 PM

Restyle codes

jamieschmeiser requested changes to this revision.Sep 6 2022, 5:17 AM
jamieschmeiser added inline comments.
llvm/include/llvm/Passes/StandardInstrumentations.h
422

Why are you saving PIC as a member? You do not refer to it other than initializing it. Please remove it.

This revision now requires changes to proceed.Sep 6 2022, 5:17 AM
jamieschmeiser added inline comments.Sep 6 2022, 5:27 AM
llvm/lib/Passes/StandardInstrumentations.cpp
1151
1153

This is unnecessary (see comment in header)

dongjunduo updated this revision to Diff 458157.Sep 6 2022, 6:44 AM

Remove the useless code

dongjunduo marked 2 inline comments as done.Sep 6 2022, 6:45 AM
jamieschmeiser added inline comments.Sep 6 2022, 11:58 AM
llvm/lib/Passes/StandardInstrumentations.cpp
2093

This comment should be expanded to indicate why it must be the last instrumentation (ie, so that it is the last instrumentation before the pass and that this also ensures that the after routines are truly put at the front so that other instrumentations are not included in the timing).

dongjunduo updated this revision to Diff 458345.Sep 6 2022, 7:13 PM

Add more comments

dongjunduo marked an inline comment as done.Sep 6 2022, 7:14 PM
jamieschmeiser accepted this revision.Sep 7 2022, 6:39 AM

A couple of nits left: small edits to comments and the change of "...() == nullptr" to "!...()" and it is good to go.
LGTM.

llvm/lib/Passes/StandardInstrumentations.cpp
2095
2096
This revision is now accepted and ready to land.Sep 7 2022, 6:39 AM
dongjunduo updated this revision to Diff 458446.Sep 7 2022, 7:04 AM

Restyle codes and comments

dongjunduo marked 3 inline comments as done.Sep 7 2022, 7:06 AM

As discussed, change your code to use the name of the loop or call getIRName and add a FIXME comment to resolve the 2 pieces of code. https://reviews.llvm.org/D133587 has been created to fix the generation of the loop names and fix the lit tests.

I have delivered https://reviews.llvm.org/D133587 so you should be good to go without the FIXME or changes.

aeubanks accepted this revision.Sep 9 2022, 12:28 PM

nice cleanup, one nit

llvm/lib/Passes/StandardInstrumentations.cpp
1159

I'd rename the param to InsertAtFront and here it should be /*InsertAtFront=*/ true. We do this for params where we pass constants to make it harder to mess up if we add more bool params in the future, and just for reading clarity.

(sorry to post here, not sure where else to post this in regards to the gsoc project I just learned about) somebody had brought up the idea of noting which passes don't make any changes to the IR. if we could somehow filter by passes that haven't made any changes that could be insightful

@aeubanks Not sure what you mean... something like print-changed=no-change? That would different from this work but we can continue the discussion.

or do you mean noting which passes don't make changes and calculating the time spent in those passes? That would combine this work with the print-changed type filters...

aeubanks added a comment.EditedSep 9 2022, 1:24 PM

@aeubanks Not sure what you mean... something like print-changed=no-change? That would different from this work but we can continue the discussion.

Nothing to do with printing, I meant somehow augmenting TimeTrace filter out passes that actually transform the IR (since they're actually doing something) and only report passes that made no change (wasting compile time). That could be useful for investigating if there's any way to avoid running passes.

and yeah I'm not asking for any work here, just a random thought if you have time

@aeubanks An interesting idea. I'll give it some thought... it should be doable by combining this with the logic in the change printers but I'd be concerned that the detection of the changes would become a hotspot itself. Perhaps a double run, the first to determine which passes make changes and then a recompile to time those passes that are then known to make changes.

@aeubanks An interesting idea. I'll give it some thought... it should be doable by combining this with the logic in the change printers but I'd be concerned that the detection of the changes would become a hotspot itself. Perhaps a double run, the first to determine which passes make changes and then a recompile to time those passes that are then known to make changes.

Ideally we'd have some sort of hashing mechanism to hash functions rather than relying on printing the IR. But printing seems like a fine first step.
If we can augment the time trace to have some way to mark the last data point with some flag, we can stop the timer, determine if IR changed, then mark the data point accordingly and we shouldn't need two runs. Two runs seems like too much hassle.

I agree. We could time the pass, figure out whether it changed anything (outside of the timing) and then decide how to save the timing info for the pass.

this actually slightly improved compile times, probably by not calculating pass names when we aren't using time tracing. thanks again!

https://llvm-compile-time-tracker.com/compare.php?from=69d9bb2aade39c76de9d6da9e2383377852e4d73&to=6975ab71260c79ddc7a616814678913e67ea417c&stat=instructions