[Time-report] Add a flag -ftime-report={per-pass,per-pass-run} to control the pass timing aggregation

Currently, -ftime-report + new pass manager emits one line of report for each
pass run. This potentially causes huge output text especially with regular LTO
or large single file (Obeserved in private tests and was reported in D51276).
The behaviour of -ftime-report + legacy pass manager is
emitting one line of report for each pass object which has relatively reasonable
text output size. This patch adds a flag `-ftime-report=` to control time report
aggregation for new pass manager.

The flag is for new pass manager only. Using it with legacy pass manager gives
an error. It is a driver and cc1 flag. `per-pass` is the new default so
`-ftime-report` is aliased to `-ftime-report=per-pass`. Before this patch,
functionality-wise `-ftime-report` is aliased to `-ftime-report=per-pass-run`.

* Adds an boolean variable TimePassesHandler::PerRun to control per-pass vs per-pass-run.
* Adds a new clang CodeGen flag CodeGenOptions::TimePassesPerRun to work with the existing CodeGenOptions::TimePasses.
* Remove FrontendOptions::ShowTimers, its uses are replaced by the existing CodeGenOptions::TimePasses.
* Remove FrontendTimesIsEnabled (It was introduced in D45619 which was largely reverted.)

Differential Revision: https://reviews.llvm.org/D92436
This commit is contained in:
Yuanfang Chen 2020-12-02 10:18:18 -08:00
parent c6348e8c95
commit 1821265db6
17 changed files with 167 additions and 69 deletions

View File

@ -252,7 +252,8 @@ CODEGENOPT(SpeculativeLoadHardening, 1, 0) ///< Enable speculative load hardenin
CODEGENOPT(FineGrainedBitfieldAccesses, 1, 0) ///< Enable fine-grained bitfield accesses. CODEGENOPT(FineGrainedBitfieldAccesses, 1, 0) ///< Enable fine-grained bitfield accesses.
CODEGENOPT(StrictEnums , 1, 0) ///< Optimize based on strict enum definition. CODEGENOPT(StrictEnums , 1, 0) ///< Optimize based on strict enum definition.
CODEGENOPT(StrictVTablePointers, 1, 0) ///< Optimize based on the strict vtable pointers CODEGENOPT(StrictVTablePointers, 1, 0) ///< Optimize based on the strict vtable pointers
CODEGENOPT(TimePasses , 1, 0) ///< Set when -ftime-report is enabled. CODEGENOPT(TimePasses , 1, 0) ///< Set when -ftime-report or -ftime-report= is enabled.
CODEGENOPT(TimePassesPerRun , 1, 0) ///< Set when -ftime-report=per-pass-run is enabled.
CODEGENOPT(TimeTrace , 1, 0) ///< Set when -ftime-trace is enabled. CODEGENOPT(TimeTrace , 1, 0) ///< Set when -ftime-trace is enabled.
VALUE_CODEGENOPT(TimeTraceGranularity, 32, 500) ///< Minimum time granularity (in microseconds), VALUE_CODEGENOPT(TimeTraceGranularity, 32, 500) ///< Minimum time granularity (in microseconds),
///< traced by time profiler ///< traced by time profiler

View File

@ -2005,7 +2005,12 @@ def Wframe_larger_than_EQ : Joined<["-"], "Wframe-larger-than=">, Group<f_Group>
def : Flag<["-"], "fterminated-vtables">, Alias<fapple_kext>; def : Flag<["-"], "fterminated-vtables">, Alias<fapple_kext>;
def fthreadsafe_statics : Flag<["-"], "fthreadsafe-statics">, Group<f_Group>; def fthreadsafe_statics : Flag<["-"], "fthreadsafe-statics">, Group<f_Group>;
def ftime_report : Flag<["-"], "ftime-report">, Group<f_Group>, Flags<[CC1Option]>, def ftime_report : Flag<["-"], "ftime-report">, Group<f_Group>, Flags<[CC1Option]>,
MarshallingInfoFlag<"FrontendOpts.ShowTimers">; MarshallingInfoFlag<"CodeGenOpts.TimePasses">;
def ftime_report_EQ: Joined<["-"], "ftime-report=">, Group<f_Group>,
Flags<[CC1Option]>, Values<"per-pass,per-pass-run">,
MarshallingInfoFlag<"CodeGenOpts.TimePassesPerRun">,
HelpText<"(For new pass manager) \"per-pass\": one report for each pass; "
"\"per-pass-run\": one report for each pass invocation">;
def ftime_trace : Flag<["-"], "ftime-trace">, Group<f_Group>, def ftime_trace : Flag<["-"], "ftime-trace">, Group<f_Group>,
HelpText<"Turn on time profiler. Generates JSON file based on output filename.">, HelpText<"Turn on time profiler. Generates JSON file based on output filename.">,
DocBrief<[{ DocBrief<[{

View File

@ -239,9 +239,6 @@ public:
/// Show frontend performance metrics and statistics. /// Show frontend performance metrics and statistics.
unsigned ShowStats : 1; unsigned ShowStats : 1;
/// Show timers for individual actions.
unsigned ShowTimers : 1;
/// print the supported cpus for the current target /// print the supported cpus for the current target
unsigned PrintSupportedCPUs : 1; unsigned PrintSupportedCPUs : 1;
@ -453,15 +450,15 @@ public:
public: public:
FrontendOptions() FrontendOptions()
: DisableFree(false), RelocatablePCH(false), ShowHelp(false), : DisableFree(false), RelocatablePCH(false), ShowHelp(false),
ShowStats(false), ShowTimers(false), TimeTrace(false), ShowStats(false), TimeTrace(false), ShowVersion(false),
ShowVersion(false), FixWhatYouCan(false), FixOnlyWarnings(false), FixWhatYouCan(false), FixOnlyWarnings(false), FixAndRecompile(false),
FixAndRecompile(false), FixToTemporaries(false), FixToTemporaries(false), ARCMTMigrateEmitARCErrors(false),
ARCMTMigrateEmitARCErrors(false), SkipFunctionBodies(false), SkipFunctionBodies(false), UseGlobalModuleIndex(true),
UseGlobalModuleIndex(true), GenerateGlobalModuleIndex(true), GenerateGlobalModuleIndex(true), ASTDumpDecls(false),
ASTDumpDecls(false), ASTDumpLookups(false), ASTDumpLookups(false), BuildingImplicitModule(false),
BuildingImplicitModule(false), ModulesEmbedAllFiles(false), ModulesEmbedAllFiles(false), IncludeTimestamps(true),
IncludeTimestamps(true), UseTemporary(true), UseTemporary(true), AllowPCMWithCompilerErrors(false),
AllowPCMWithCompilerErrors(false), TimeTraceGranularity(500) {} TimeTraceGranularity(500) {}
/// getInputKindForExtension - Return the appropriate input kind for a file /// getInputKindForExtension - Return the appropriate input kind for a file
/// extension. For example, "c" would return Language::C. /// extension. For example, "c" would return Language::C.

View File

@ -227,10 +227,6 @@ std::unique_ptr<CompilerInvocation> createInvocationFromCommandLine(
// Frontend timing utils // Frontend timing utils
/// If the user specifies the -ftime-report argument on an Clang command line
/// then the value of this boolean will be true, otherwise false.
extern bool FrontendTimesIsEnabled;
} // namespace clang } // namespace clang
#endif // LLVM_CLANG_FRONTEND_UTILS_H #endif // LLVM_CLANG_FRONTEND_UTILS_H

View File

@ -907,7 +907,7 @@ bool EmitAssemblyHelper::AddEmitPasses(legacy::PassManager &CodeGenPasses,
void EmitAssemblyHelper::EmitAssembly(BackendAction Action, void EmitAssemblyHelper::EmitAssembly(BackendAction Action,
std::unique_ptr<raw_pwrite_stream> OS) { std::unique_ptr<raw_pwrite_stream> OS) {
TimeRegion Region(FrontendTimesIsEnabled ? &CodeGenerationTime : nullptr); TimeRegion Region(CodeGenOpts.TimePasses ? &CodeGenerationTime : nullptr);
setCommandLineOpts(CodeGenOpts); setCommandLineOpts(CodeGenOpts);
@ -1064,7 +1064,7 @@ static PassBuilder::OptimizationLevel mapToLevel(const CodeGenOptions &Opts) {
/// `EmitAssembly` at some point in the future when the default switches. /// `EmitAssembly` at some point in the future when the default switches.
void EmitAssemblyHelper::EmitAssemblyWithNewPassManager( void EmitAssemblyHelper::EmitAssemblyWithNewPassManager(
BackendAction Action, std::unique_ptr<raw_pwrite_stream> OS) { BackendAction Action, std::unique_ptr<raw_pwrite_stream> OS) {
TimeRegion Region(FrontendTimesIsEnabled ? &CodeGenerationTime : nullptr); TimeRegion Region(CodeGenOpts.TimePasses ? &CodeGenerationTime : nullptr);
setCommandLineOpts(CodeGenOpts); setCommandLineOpts(CodeGenOpts);
bool RequiresCodeGen = (Action != Backend_EmitNothing && bool RequiresCodeGen = (Action != Backend_EmitNothing &&

View File

@ -122,6 +122,8 @@ namespace clang {
/// can happen when Clang plugins trigger additional AST deserialization. /// can happen when Clang plugins trigger additional AST deserialization.
bool IRGenFinished = false; bool IRGenFinished = false;
bool TimerIsEnabled = false;
std::unique_ptr<CodeGenerator> Gen; std::unique_ptr<CodeGenerator> Gen;
SmallVector<LinkModule, 4> LinkModules; SmallVector<LinkModule, 4> LinkModules;
@ -136,8 +138,7 @@ namespace clang {
const PreprocessorOptions &PPOpts, const PreprocessorOptions &PPOpts,
const CodeGenOptions &CodeGenOpts, const CodeGenOptions &CodeGenOpts,
const TargetOptions &TargetOpts, const TargetOptions &TargetOpts,
const LangOptions &LangOpts, bool TimePasses, const LangOptions &LangOpts, const std::string &InFile,
const std::string &InFile,
SmallVector<LinkModule, 4> LinkModules, SmallVector<LinkModule, 4> LinkModules,
std::unique_ptr<raw_pwrite_stream> OS, LLVMContext &C, std::unique_ptr<raw_pwrite_stream> OS, LLVMContext &C,
CoverageSourceInfo *CoverageInfo = nullptr) CoverageSourceInfo *CoverageInfo = nullptr)
@ -149,8 +150,9 @@ namespace clang {
Gen(CreateLLVMCodeGen(Diags, InFile, HeaderSearchOpts, PPOpts, Gen(CreateLLVMCodeGen(Diags, InFile, HeaderSearchOpts, PPOpts,
CodeGenOpts, C, CoverageInfo)), CodeGenOpts, C, CoverageInfo)),
LinkModules(std::move(LinkModules)) { LinkModules(std::move(LinkModules)) {
FrontendTimesIsEnabled = TimePasses; TimerIsEnabled = CodeGenOpts.TimePasses;
llvm::TimePassesIsEnabled = TimePasses; llvm::TimePassesIsEnabled = CodeGenOpts.TimePasses;
llvm::TimePassesPerRun = CodeGenOpts.TimePassesPerRun;
} }
// This constructor is used in installing an empty BackendConsumer // This constructor is used in installing an empty BackendConsumer
@ -161,7 +163,7 @@ namespace clang {
const PreprocessorOptions &PPOpts, const PreprocessorOptions &PPOpts,
const CodeGenOptions &CodeGenOpts, const CodeGenOptions &CodeGenOpts,
const TargetOptions &TargetOpts, const TargetOptions &TargetOpts,
const LangOptions &LangOpts, bool TimePasses, const LangOptions &LangOpts,
SmallVector<LinkModule, 4> LinkModules, LLVMContext &C, SmallVector<LinkModule, 4> LinkModules, LLVMContext &C,
CoverageSourceInfo *CoverageInfo = nullptr) CoverageSourceInfo *CoverageInfo = nullptr)
: Diags(Diags), Action(Action), HeaderSearchOpts(HeaderSearchOpts), : Diags(Diags), Action(Action), HeaderSearchOpts(HeaderSearchOpts),
@ -172,8 +174,9 @@ namespace clang {
Gen(CreateLLVMCodeGen(Diags, "", HeaderSearchOpts, PPOpts, Gen(CreateLLVMCodeGen(Diags, "", HeaderSearchOpts, PPOpts,
CodeGenOpts, C, CoverageInfo)), CodeGenOpts, C, CoverageInfo)),
LinkModules(std::move(LinkModules)) { LinkModules(std::move(LinkModules)) {
FrontendTimesIsEnabled = TimePasses; TimerIsEnabled = CodeGenOpts.TimePasses;
llvm::TimePassesIsEnabled = TimePasses; llvm::TimePassesIsEnabled = CodeGenOpts.TimePasses;
llvm::TimePassesPerRun = CodeGenOpts.TimePassesPerRun;
} }
llvm::Module *getModule() const { return Gen->GetModule(); } llvm::Module *getModule() const { return Gen->GetModule(); }
std::unique_ptr<llvm::Module> takeModule() { std::unique_ptr<llvm::Module> takeModule() {
@ -191,12 +194,12 @@ namespace clang {
Context = &Ctx; Context = &Ctx;
if (FrontendTimesIsEnabled) if (TimerIsEnabled)
LLVMIRGeneration.startTimer(); LLVMIRGeneration.startTimer();
Gen->Initialize(Ctx); Gen->Initialize(Ctx);
if (FrontendTimesIsEnabled) if (TimerIsEnabled)
LLVMIRGeneration.stopTimer(); LLVMIRGeneration.stopTimer();
} }
@ -206,7 +209,7 @@ namespace clang {
"LLVM IR generation of declaration"); "LLVM IR generation of declaration");
// Recurse. // Recurse.
if (FrontendTimesIsEnabled) { if (TimerIsEnabled) {
LLVMIRGenerationRefCount += 1; LLVMIRGenerationRefCount += 1;
if (LLVMIRGenerationRefCount == 1) if (LLVMIRGenerationRefCount == 1)
LLVMIRGeneration.startTimer(); LLVMIRGeneration.startTimer();
@ -214,7 +217,7 @@ namespace clang {
Gen->HandleTopLevelDecl(D); Gen->HandleTopLevelDecl(D);
if (FrontendTimesIsEnabled) { if (TimerIsEnabled) {
LLVMIRGenerationRefCount -= 1; LLVMIRGenerationRefCount -= 1;
if (LLVMIRGenerationRefCount == 0) if (LLVMIRGenerationRefCount == 0)
LLVMIRGeneration.stopTimer(); LLVMIRGeneration.stopTimer();
@ -227,12 +230,12 @@ namespace clang {
PrettyStackTraceDecl CrashInfo(D, SourceLocation(), PrettyStackTraceDecl CrashInfo(D, SourceLocation(),
Context->getSourceManager(), Context->getSourceManager(),
"LLVM IR generation of inline function"); "LLVM IR generation of inline function");
if (FrontendTimesIsEnabled) if (TimerIsEnabled)
LLVMIRGeneration.startTimer(); LLVMIRGeneration.startTimer();
Gen->HandleInlineFunctionDefinition(D); Gen->HandleInlineFunctionDefinition(D);
if (FrontendTimesIsEnabled) if (TimerIsEnabled)
LLVMIRGeneration.stopTimer(); LLVMIRGeneration.stopTimer();
} }
@ -280,7 +283,7 @@ namespace clang {
{ {
llvm::TimeTraceScope TimeScope("Frontend"); llvm::TimeTraceScope TimeScope("Frontend");
PrettyStackTraceString CrashInfo("Per-file LLVM IR generation"); PrettyStackTraceString CrashInfo("Per-file LLVM IR generation");
if (FrontendTimesIsEnabled) { if (TimerIsEnabled) {
LLVMIRGenerationRefCount += 1; LLVMIRGenerationRefCount += 1;
if (LLVMIRGenerationRefCount == 1) if (LLVMIRGenerationRefCount == 1)
LLVMIRGeneration.startTimer(); LLVMIRGeneration.startTimer();
@ -288,7 +291,7 @@ namespace clang {
Gen->HandleTranslationUnit(C); Gen->HandleTranslationUnit(C);
if (FrontendTimesIsEnabled) { if (TimerIsEnabled) {
LLVMIRGenerationRefCount -= 1; LLVMIRGenerationRefCount -= 1;
if (LLVMIRGenerationRefCount == 0) if (LLVMIRGenerationRefCount == 0)
LLVMIRGeneration.stopTimer(); LLVMIRGeneration.stopTimer();
@ -967,8 +970,8 @@ CodeGenAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
std::unique_ptr<BackendConsumer> Result(new BackendConsumer( std::unique_ptr<BackendConsumer> Result(new BackendConsumer(
BA, CI.getDiagnostics(), CI.getHeaderSearchOpts(), BA, CI.getDiagnostics(), CI.getHeaderSearchOpts(),
CI.getPreprocessorOpts(), CI.getCodeGenOpts(), CI.getTargetOpts(), CI.getPreprocessorOpts(), CI.getCodeGenOpts(), CI.getTargetOpts(),
CI.getLangOpts(), CI.getFrontendOpts().ShowTimers, std::string(InFile), CI.getLangOpts(), std::string(InFile), std::move(LinkModules),
std::move(LinkModules), std::move(OS), *VMContext, CoverageInfo)); std::move(OS), *VMContext, CoverageInfo));
BEConsumer = Result.get(); BEConsumer = Result.get();
// Enable generating macro debug info only when debug info is not disabled and // Enable generating macro debug info only when debug info is not disabled and
@ -1115,7 +1118,6 @@ void CodeGenAction::ExecuteAction() {
BackendConsumer Result(BA, CI.getDiagnostics(), CI.getHeaderSearchOpts(), BackendConsumer Result(BA, CI.getDiagnostics(), CI.getHeaderSearchOpts(),
CI.getPreprocessorOpts(), CI.getCodeGenOpts(), CI.getPreprocessorOpts(), CI.getCodeGenOpts(),
CI.getTargetOpts(), CI.getLangOpts(), CI.getTargetOpts(), CI.getLangOpts(),
CI.getFrontendOpts().ShowTimers,
std::move(LinkModules), *VMContext, nullptr); std::move(LinkModules), *VMContext, nullptr);
// PR44896: Force DiscardValueNames as false. DiscardValueNames cannot be // PR44896: Force DiscardValueNames as false. DiscardValueNames cannot be
// true here because the valued names are needed for reading textual IR. // true here because the valued names are needed for reading textual IR.

View File

@ -5501,6 +5501,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_print_source_range_info); Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_print_source_range_info);
Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_parseable_fixits); Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_parseable_fixits);
Args.AddLastArg(CmdArgs, options::OPT_ftime_report); Args.AddLastArg(CmdArgs, options::OPT_ftime_report);
Args.AddLastArg(CmdArgs, options::OPT_ftime_report_EQ);
Args.AddLastArg(CmdArgs, options::OPT_ftime_trace); Args.AddLastArg(CmdArgs, options::OPT_ftime_trace);
Args.AddLastArg(CmdArgs, options::OPT_ftime_trace_granularity_EQ); Args.AddLastArg(CmdArgs, options::OPT_ftime_trace_granularity_EQ);
Args.AddLastArg(CmdArgs, options::OPT_ftrapv); Args.AddLastArg(CmdArgs, options::OPT_ftrapv);

View File

@ -23,7 +23,6 @@ add_clang_library(clangFrontend
FrontendAction.cpp FrontendAction.cpp
FrontendActions.cpp FrontendActions.cpp
FrontendOptions.cpp FrontendOptions.cpp
FrontendTiming.cpp
HeaderIncludeGen.cpp HeaderIncludeGen.cpp
InitHeaderSearch.cpp InitHeaderSearch.cpp
InitPreprocessor.cpp InitPreprocessor.cpp

View File

@ -975,7 +975,7 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) {
<< " based upon " << BACKEND_PACKAGE_STRING << " based upon " << BACKEND_PACKAGE_STRING
<< " default target " << llvm::sys::getDefaultTargetTriple() << "\n"; << " default target " << llvm::sys::getDefaultTargetTriple() << "\n";
if (getFrontendOpts().ShowTimers) if (getCodeGenOpts().TimePasses)
createFrontendTimer(); createFrontendTimer();
if (getFrontendOpts().ShowStats || !getFrontendOpts().StatsFile.empty()) if (getFrontendOpts().ShowStats || !getFrontendOpts().StatsFile.empty())

View File

@ -1046,6 +1046,26 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.setFramePointer(FP); Opts.setFramePointer(FP);
} }
if (const Arg *A = Args.getLastArg(OPT_ftime_report, OPT_ftime_report_EQ)) {
Opts.TimePasses = true;
// -ftime-report= is only for new pass manager.
if (A->getOption().getID() == OPT_ftime_report_EQ) {
if (!Opts.ExperimentalNewPassManager)
Diags.Report(diag::err_drv_argument_only_allowed_with)
<< A->getAsString(Args) << "-fexperimental-new-pass-manager";
StringRef Val = A->getValue();
if (Val == "per-pass")
Opts.TimePassesPerRun = false;
else if (Val == "per-pass-run")
Opts.TimePassesPerRun = true;
else
Diags.Report(diag::err_drv_invalid_value)
<< A->getAsString(Args) << A->getValue();
}
}
Opts.DisableFree = Args.hasArg(OPT_disable_free); Opts.DisableFree = Args.hasArg(OPT_disable_free);
Opts.DiscardValueNames = Args.hasArg(OPT_discard_value_names); Opts.DiscardValueNames = Args.hasArg(OPT_discard_value_names);
Opts.DisableTailCalls = Args.hasArg(OPT_mdisable_tail_calls); Opts.DisableTailCalls = Args.hasArg(OPT_mdisable_tail_calls);

View File

@ -1,19 +0,0 @@
//===- FrontendTiming.cpp - Implements Frontend timing utils -------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file keps implementation of frontend timing utils.
//
//===----------------------------------------------------------------------===//
#include "clang/Frontend/Utils.h"
namespace clang {
bool FrontendTimesIsEnabled = false;
}

View File

@ -0,0 +1,11 @@
// Check that -ftime-report flag is passed to compiler. The value of the flag
// is only diagnosed in the compiler for simplicity since this is a dev option.
// RUN: %clang -### -c -ftime-report %s 2>&1 | FileCheck %s
// RUN: %clang -### -c -ftime-report=per-pass %s 2>&1 | FileCheck %s -check-prefix=PER-PASS
// RUN: %clang -### -c -ftime-report=per-pass-run %s 2>&1 | FileCheck %s -check-prefix=PER-PASS-INVOKE
// RUN: %clang -### -c -ftime-report=unknown %s 2>&1 | FileCheck %s -check-prefix=UNKNOWN
// CHECK: "-ftime-report"
// PER-PASS: "-ftime-report=per-pass"
// PER-PASS-INVOKE: "-ftime-report=per-pass-run"
// UNKNOWN: "-ftime-report=unknown"

View File

@ -0,0 +1,41 @@
// Check that legacy pass manager could only use -ftime-report
// RUN: %clang_cc1 -fno-experimental-new-pass-manager -emit-obj -O1 \
// RUN: -ftime-report %s -o /dev/null 2>&1 | \
// RUN: FileCheck %s --check-prefixes=TIME,LPM
// RUN: not %clang_cc1 -fno-experimental-new-pass-manager -emit-obj -O1 \
// RUN: -ftime-report=per-pass %s -o /dev/null 2>&1 | \
// RUN: FileCheck %s --check-prefixes=ERROR
// RUN: not %clang_cc1 -fno-experimental-new-pass-manager -emit-obj -O1 \
// RUN: -ftime-report=per-pass-run %s -o /dev/null 2>&1 | \
// RUN: FileCheck %s --check-prefixes=ERROR
// Check -ftime-report/-ftime-report= output for the new pass manager
// RUN: %clang_cc1 -emit-obj -O1 -fexperimental-new-pass-manager \
// RUN: -ftime-report %s -o /dev/null 2>&1 | \
// RUN: FileCheck %s --check-prefixes=TIME,NPM
// RUN: %clang_cc1 -emit-obj -O1 -fexperimental-new-pass-manager \
// RUN: -ftime-report=per-pass %s -o /dev/null 2>&1 | \
// RUN: FileCheck %s --check-prefixes=TIME,NPM
// RUN: %clang_cc1 -emit-obj -O1 -fexperimental-new-pass-manager \
// RUN: -ftime-report=per-pass-run %s -o /dev/null 2>&1 | \
// RUN: FileCheck %s --check-prefixes=TIME,NPM-PER-INVOKE
// TIME: Pass execution timing report
// TIME: Total Execution Time:
// TIME: Name
// LPM-DAG: Dominator Tree Construction #
// LPM-DAG: Dominator Tree Construction #
// LPM-DAG: Dominator Tree Construction #
// NPM-PER-INVOKE-DAG: InstCombinePass #
// NPM-PER-INVOKE-DAG: InstCombinePass #
// NPM-PER-INVOKE-DAG: InstCombinePass #
// NPM-NOT: InstCombinePass #
// NPM: InstCombinePass{{$}}
// NPM-NOT: InstCombinePass #
// TIME: Total{{$}}
// LPM-NOT: Pass execution timing report
// NPM: Pass execution timing report
// ERROR: error: invalid argument '-ftime-report={{.*}}' only allowed with '-fexperimental-new-pass-manager'
int foo(int x, int y) { return x + y; }

View File

@ -38,11 +38,6 @@ void reportAndResetTimings(raw_ostream *OutStream = nullptr);
/// Request the timer for this legacy-pass-manager's pass instance. /// Request the timer for this legacy-pass-manager's pass instance.
Timer *getPassTimer(Pass *); Timer *getPassTimer(Pass *);
/// If the user specifies the -time-passes argument on an LLVM tool command line
/// then the value of this boolean will be true, otherwise false.
/// This is the storage for the -time-passes option.
extern bool TimePassesIsEnabled;
/// This class implements -time-passes functionality for new pass manager. /// This class implements -time-passes functionality for new pass manager.
/// It provides the pass-instrumentation callbacks that measure the pass /// It provides the pass-instrumentation callbacks that measure the pass
/// execution time. They collect timing info into individual timers as /// execution time. They collect timing info into individual timers as
@ -70,9 +65,11 @@ class TimePassesHandler {
raw_ostream *OutStream = nullptr; raw_ostream *OutStream = nullptr;
bool Enabled; bool Enabled;
bool PerRun;
public: public:
TimePassesHandler(bool Enabled = TimePassesIsEnabled); TimePassesHandler();
TimePassesHandler(bool Enabled, bool PerRun = false);
/// Destructor handles the print action if it has not been handled before. /// Destructor handles the print action if it has not been handled before.
~TimePassesHandler() { print(); } ~TimePassesHandler() { print(); }

View File

@ -309,6 +309,12 @@ protected:
/// then the value of this boolean will be true, otherwise false. /// then the value of this boolean will be true, otherwise false.
/// This is the storage for the -time-passes option. /// This is the storage for the -time-passes option.
extern bool TimePassesIsEnabled; extern bool TimePassesIsEnabled;
/// If TimePassesPerRun is true, there would be one line of report for
/// each pass invocation.
/// If TimePassesPerRun is false, there would be only one line of
/// report for each pass (even there are more than one pass objects).
/// (For new pass manager only)
extern bool TimePassesPerRun;
} // end namespace llvm } // end namespace llvm

View File

@ -35,11 +35,17 @@ using namespace llvm;
namespace llvm { namespace llvm {
bool TimePassesIsEnabled = false; bool TimePassesIsEnabled = false;
bool TimePassesPerRun = false;
static cl::opt<bool, true> EnableTiming( static cl::opt<bool, true> EnableTiming(
"time-passes", cl::location(TimePassesIsEnabled), cl::Hidden, "time-passes", cl::location(TimePassesIsEnabled), cl::Hidden,
cl::desc("Time each pass, printing elapsed time for each on exit")); cl::desc("Time each pass, printing elapsed time for each on exit"));
static cl::opt<bool, true> EnableTimingPerRun(
"time-passes-per-run", cl::location(TimePassesPerRun), cl::Hidden,
cl::desc("Time each pass run, printing elapsed time for each run on exit"),
cl::callback([](const bool &) { TimePassesIsEnabled = true; }));
namespace { namespace {
namespace legacy { namespace legacy {
@ -165,6 +171,13 @@ void reportAndResetTimings(raw_ostream *OutStream) {
/// Returns the timer for the specified pass invocation of \p PassID. /// Returns the timer for the specified pass invocation of \p PassID.
/// Each time it creates a new timer. /// Each time it creates a new timer.
Timer &TimePassesHandler::getPassTimer(StringRef PassID) { Timer &TimePassesHandler::getPassTimer(StringRef PassID) {
if (!PerRun) {
TimerVector &Timers = TimingData[PassID];
if (Timers.size() == 0)
Timers.emplace_back(new Timer(PassID, PassID, TG));
return *Timers.front();
}
// Take a vector of Timers created for this \p PassID and append // Take a vector of Timers created for this \p PassID and append
// one more timer to it. // one more timer to it.
TimerVector &Timers = TimingData[PassID]; TimerVector &Timers = TimingData[PassID];
@ -179,8 +192,12 @@ Timer &TimePassesHandler::getPassTimer(StringRef PassID) {
return *T; return *T;
} }
TimePassesHandler::TimePassesHandler(bool Enabled) TimePassesHandler::TimePassesHandler(bool Enabled, bool PerRun)
: TG("pass", "... Pass execution timing report ..."), Enabled(Enabled) {} : TG("pass", "... Pass execution timing report ..."), Enabled(Enabled),
PerRun(PerRun) {}
TimePassesHandler::TimePassesHandler()
: TimePassesHandler(TimePassesIsEnabled, TimePassesPerRun) {}
void TimePassesHandler::setOutStream(raw_ostream &Out) { void TimePassesHandler::setOutStream(raw_ostream &Out) {
OutStream = &Out; OutStream = &Out;

View File

@ -1,9 +1,15 @@
; RUN: opt -enable-new-pm=0 < %s -disable-output -instcombine -instcombine -licm -time-passes 2>&1 | FileCheck %s --check-prefix=TIME --check-prefix=TIME-LEGACY ; RUN: opt -enable-new-pm=0 < %s -disable-output -instcombine -instcombine -licm -time-passes 2>&1 | FileCheck %s --check-prefix=TIME --check-prefix=TIME-LEGACY
; RUN: opt -enable-new-pm=0 < %s -disable-output -instcombine -instcombine -licm -licm -time-passes 2>&1 | FileCheck %s --check-prefix=TIME --check-prefix=TIME-LEGACY --check-prefix=TIME-DOUBLE-LICM-LEGACY ; RUN: opt -enable-new-pm=0 < %s -disable-output -instcombine -instcombine -licm -licm -time-passes 2>&1 | FileCheck %s --check-prefix=TIME --check-prefix=TIME-LEGACY --check-prefix=TIME-DOUBLE-LICM-LEGACY
; RUN: opt < %s -disable-output -passes='instcombine,instcombine,loop(licm)' -time-passes 2>&1 | FileCheck %s --check-prefix=TIME --check-prefix=TIME-NEW
; RUN: opt < %s -disable-output -passes='instcombine,loop(licm),instcombine,loop(licm)' -time-passes 2>&1 | FileCheck %s --check-prefix=TIME --check-prefix=TIME-NEW -check-prefix=TIME-DOUBLE-LICM-NEW
; RUN: opt < %s -disable-output -passes='default<O2>' -time-passes 2>&1 | FileCheck %s --check-prefix=TIME ; RUN: opt < %s -disable-output -passes='default<O2>' -time-passes 2>&1 | FileCheck %s --check-prefix=TIME
; ;
; For new pass manager, check that -time-passes-per-run emit one report for each pass run.
; RUN: opt < %s -disable-output -passes='instcombine,instcombine,loop(licm)' -time-passes-per-run 2>&1 | FileCheck %s --check-prefix=TIME --check-prefix=TIME-NEW
; RUN: opt < %s -disable-output -passes='instcombine,loop(licm),instcombine,loop(licm)' -time-passes-per-run 2>&1 | FileCheck %s --check-prefix=TIME --check-prefix=TIME-NEW -check-prefix=TIME-DOUBLE-LICM-NEW
;
; For new pass manager, check that -time-passes emit one report for each pass.
; RUN: opt < %s -disable-output -passes='instcombine,instcombine,loop(licm)' -time-passes 2>&1 | FileCheck %s --check-prefixes=TIME,TIME-NEW-PER-PASS
; RUN: opt < %s -disable-output -passes='instcombine,loop(licm),instcombine,loop(licm)' -time-passes 2>&1 | FileCheck %s --check-prefixes=TIME,TIME-NEW-PER-PASS
;
; The following 4 test runs verify -info-output-file interaction (default goes to stderr, '-' goes to stdout). ; The following 4 test runs verify -info-output-file interaction (default goes to stderr, '-' goes to stdout).
; RUN: opt -enable-new-pm=0 < %s -disable-output -O2 -time-passes -info-output-file='-' 2>/dev/null | FileCheck %s --check-prefix=TIME ; RUN: opt -enable-new-pm=0 < %s -disable-output -O2 -time-passes -info-output-file='-' 2>/dev/null | FileCheck %s --check-prefix=TIME
; RUN: opt < %s -disable-output -passes='default<O2>' -time-passes -info-output-file='-' 2>/dev/null | FileCheck %s --check-prefix=TIME ; RUN: opt < %s -disable-output -passes='default<O2>' -time-passes -info-output-file='-' 2>/dev/null | FileCheck %s --check-prefix=TIME
@ -46,6 +52,24 @@
; TIME-NEW-DAG: VerifierPass ; TIME-NEW-DAG: VerifierPass
; TIME-NEW-DAG: DominatorTreeAnalysis ; TIME-NEW-DAG: DominatorTreeAnalysis
; TIME-NEW-DAG: TargetLibraryAnalysis ; TIME-NEW-DAG: TargetLibraryAnalysis
; TIME-NEW-PER-PASS-DAG: InstCombinePass
; TIME-NEW-PER-PASS-DAG: LICMPass
; TIME-NEW-PER-PASS-DAG: LCSSAPass
; TIME-NEW-PER-PASS-DAG: LoopSimplifyPass
; TIME-NEW-PER-PASS-DAG: ScalarEvolutionAnalysis
; TIME-NEW-PER-PASS-DAG: LoopAnalysis
; TIME-NEW-PER-PASS-DAG: VerifierPass
; TIME-NEW-PER-PASS-DAG: DominatorTreeAnalysis
; TIME-NEW-PER-PASS-DAG: TargetLibraryAnalysis
; TIME-NEW-PER-PASS-NOT: InstCombinePass #
; TIME-NEW-PER-PASS-NOT: LICMPass #
; TIME-NEW-PER-PASS-NOT: LCSSAPass #
; TIME-NEW-PER-PASS-NOT: LoopSimplifyPass #
; TIME-NEW-PER-PASS-NOT: ScalarEvolutionAnalysis #
; TIME-NEW-PER-PASS-NOT: LoopAnalysis #
; TIME-NEW-PER-PASS-NOT: VerifierPass #
; TIME-NEW-PER-PASS-NOT: DominatorTreeAnalysis #
; TIME-NEW-PER-PASS-NOT: TargetLibraryAnalysis #
; TIME: Total{{$}} ; TIME: Total{{$}}
define i32 @foo() { define i32 @foo() {