From 4556056b0f9e24ad21f0bc2303932b977ff7ffb5 Mon Sep 17 00:00:00 2001 From: Alan Zhao Date: Mon, 21 Jul 2025 16:34:33 -0700 Subject: [PATCH 1/2] [clang][timers][stats] Add a flag to enable timers in the stats file As reported in #138173, enabling `-ftime-report` adds pass timing info to the stats file if `-stats-file` is specified. This was determined to be WAI. However, if one intentionally wants to put timer information in the stats file, using `-ftime-report` may lead to a lot of logspam (that can't be removed by directing stderr to `/dev/null` as that would also redirect compiler errors). To address this, this PR adds a flag `-stats-file-timers` that adds timer data to the stats file without outputting to stderr. --- clang/include/clang/Basic/CodeGenOptions.def | 3 ++- clang/include/clang/Driver/Options.td | 3 +++ clang/lib/Frontend/CompilerInvocation.cpp | 7 ++++--- clang/test/Misc/time-passes.c | 4 ++++ clang/tools/driver/cc1_main.cpp | 2 +- 5 files changed, 14 insertions(+), 5 deletions(-) diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def index cfffeb71f09d1..e137738102544 100644 --- a/clang/include/clang/Basic/CodeGenOptions.def +++ b/clang/include/clang/Basic/CodeGenOptions.def @@ -313,9 +313,10 @@ CODEGENOPT(SpeculativeLoadHardening, 1, 0, Benign) ///< Enable speculative load CODEGENOPT(FineGrainedBitfieldAccesses, 1, 0, Benign) ///< Enable fine-grained bitfield accesses. CODEGENOPT(StrictEnums , 1, 0, Benign) ///< Optimize based on strict enum definition. CODEGENOPT(StrictVTablePointers, 1, 0, Benign) ///< Optimize based on the strict vtable pointers -CODEGENOPT(TimePasses , 1, 0, Benign) ///< Set when -ftime-report or -ftime-report= or -ftime-report-json is enabled. +CODEGENOPT(TimePasses , 1, 0, Benign) ///< Set when -ftime-report, -ftime-report=, -ftime-report-json, or -stats-file-timers is enabled. CODEGENOPT(TimePassesPerRun , 1, 0, Benign) ///< Set when -ftime-report=per-pass-run is enabled. CODEGENOPT(TimePassesJson , 1, 0, Benign) ///< Set when -ftime-report-json is enabled. +CODEGENOPT(TimePassesStatsFile , 1, 0, Benign) ///< Set when -stats-file-timers is enabled. CODEGENOPT(TimeTrace , 1, 0, Benign) ///< Set when -ftime-trace is enabled. VALUE_CODEGENOPT(TimeTraceGranularity, 32, 500, Benign) ///< Minimum time granularity (in microseconds), ///< traced by time profiler diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index e30c152cbce2e..20def5dd0eb5e 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -8253,6 +8253,9 @@ def stats_file : Joined<["-"], "stats-file=">, def stats_file_append : Flag<["-"], "stats-file-append">, HelpText<"If stats should be appended to stats-file instead of overwriting it">, MarshallingInfoFlag>; +def stats_file_timers : Flag<["-"], "stats-file-timers">, + HelpText<"If stats should include timers.">, + MarshallingInfoFlag>; def fdump_record_layouts_simple : Flag<["-"], "fdump-record-layouts-simple">, HelpText<"Dump record layout information in a simple form used for testing">, MarshallingInfoFlag>; diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 3a36250da57a3..30bca9e72eae0 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -2013,8 +2013,9 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, : llvm::codegenoptions::DebugTemplateNamesKind::Mangled); } - if (const Arg *A = Args.getLastArg(OPT_ftime_report, OPT_ftime_report_EQ, - OPT_ftime_report_json)) { + if (Args.hasArg(OPT_ftime_report, OPT_ftime_report_EQ, + OPT_ftime_report_json) || + Opts.TimePassesStatsFile) { Opts.TimePasses = true; // -ftime-report= is only for new pass manager. @@ -2026,7 +2027,7 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, Opts.TimePassesPerRun = true; else Diags.Report(diag::err_drv_invalid_value) - << A->getAsString(Args) << A->getValue(); + << EQ->getAsString(Args) << EQ->getValue(); } if (Args.getLastArg(OPT_ftime_report_json)) diff --git a/clang/test/Misc/time-passes.c b/clang/test/Misc/time-passes.c index 370f52e4904fe..2f952d97b5967 100644 --- a/clang/test/Misc/time-passes.c +++ b/clang/test/Misc/time-passes.c @@ -19,6 +19,10 @@ // RUN: -ftime-report-json %s -o /dev/null \ // RUN: -mllvm -info-output-file=%t // RUN: cat %t | FileCheck %s --check-prefixes=JSON +// RUN: %clang_cc1 -emit-obj -O1 \ +// RUN: %s -o /dev/null \ +// RUN: -stats-file=%t -stats-file-timers 2>&1 | count 0 +// RUN: FileCheck %s -input-file=%t -check-prefixes=JSON // TIME: Pass execution timing report // TIME: Total Execution Time: diff --git a/clang/tools/driver/cc1_main.cpp b/clang/tools/driver/cc1_main.cpp index 2c17f28621f5f..9b1e390cb0f34 100644 --- a/clang/tools/driver/cc1_main.cpp +++ b/clang/tools/driver/cc1_main.cpp @@ -304,7 +304,7 @@ int cc1_main(ArrayRef Argv, const char *Argv0, void *MainAddr) { *IOFile << "{\n"; llvm::TimerGroup::printAllJSONValues(*IOFile, ""); *IOFile << "\n}\n"; - } else { + } else if (!Clang->getCodeGenOpts().TimePassesStatsFile) { llvm::TimerGroup::printAll(*IOFile); } llvm::TimerGroup::clearAll(); From 3b995e1d47ec18b0f2c22b16cdb1349cfd213df3 Mon Sep 17 00:00:00 2001 From: Alan Zhao Date: Tue, 22 Jul 2025 14:29:41 -0700 Subject: [PATCH 2/2] code review comments --- clang/lib/Frontend/CompilerInvocation.cpp | 5 ++--- clang/test/Misc/time-passes.c | 2 ++ 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 30bca9e72eae0..ab4384abd7996 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -2013,9 +2013,8 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, : llvm::codegenoptions::DebugTemplateNamesKind::Mangled); } - if (Args.hasArg(OPT_ftime_report, OPT_ftime_report_EQ, - OPT_ftime_report_json) || - Opts.TimePassesStatsFile) { + if (Args.hasArg(OPT_ftime_report, OPT_ftime_report_EQ, OPT_ftime_report_json, + OPT_stats_file_timers)) { Opts.TimePasses = true; // -ftime-report= is only for new pass manager. diff --git a/clang/test/Misc/time-passes.c b/clang/test/Misc/time-passes.c index 2f952d97b5967..6afbcd466378d 100644 --- a/clang/test/Misc/time-passes.c +++ b/clang/test/Misc/time-passes.c @@ -19,6 +19,8 @@ // RUN: -ftime-report-json %s -o /dev/null \ // RUN: -mllvm -info-output-file=%t // RUN: cat %t | FileCheck %s --check-prefixes=JSON +// Check that -stats-file-timers only outputs pass time info in the stats file +// and not stderr. // RUN: %clang_cc1 -emit-obj -O1 \ // RUN: %s -o /dev/null \ // RUN: -stats-file=%t -stats-file-timers 2>&1 | count 0