[clang] [llvm] [clang] Implement JSON formatted -ftime-report (PR #137737)
Alan Zhao via cfe-commits
cfe-commits at lists.llvm.org
Wed Apr 30 13:42:56 PDT 2025
https://github.com/alanzhao1 updated https://github.com/llvm/llvm-project/pull/137737
>From 1f0529aa5fbf9c4c1b3f0e58eaf5e527dc1605f2 Mon Sep 17 00:00:00 2001
From: Alan Zhao <ayzhao at google.com>
Date: Mon, 28 Apr 2025 16:21:29 -0700
Subject: [PATCH 1/3] [clang] Implement JSON formatted -ftime-report
This patch adds a new flag, -ftime-report-json, which outputs the same
information as -ftime-report but as JSON instead of -ftime-report's
pretty printed format.
---
clang/include/clang/Basic/CodeGenOptions.def | 3 ++-
clang/include/clang/Driver/Options.td | 5 +++++
clang/lib/Driver/ToolChains/Clang.cpp | 1 +
clang/lib/Frontend/CompilerInvocation.cpp | 13 ++++++++++---
clang/test/Misc/time-passes.c | 8 ++++++++
clang/tools/driver/cc1_main.cpp | 9 ++++++++-
llvm/lib/Support/Timer.cpp | 4 ----
7 files changed, 34 insertions(+), 9 deletions(-)
diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def
index c5990fb248689..927972015c3dc 100644
--- a/clang/include/clang/Basic/CodeGenOptions.def
+++ b/clang/include/clang/Basic/CodeGenOptions.def
@@ -318,8 +318,9 @@ CODEGENOPT(SpeculativeLoadHardening, 1, 0) ///< Enable speculative load hardenin
CODEGENOPT(FineGrainedBitfieldAccesses, 1, 0) ///< Enable fine-grained bitfield accesses.
CODEGENOPT(StrictEnums , 1, 0) ///< Optimize based on strict enum definition.
CODEGENOPT(StrictVTablePointers, 1, 0) ///< Optimize based on the strict vtable pointers
-CODEGENOPT(TimePasses , 1, 0) ///< Set when -ftime-report or -ftime-report= is enabled.
+CODEGENOPT(TimePasses , 1, 0) ///< Set when -ftime-report or -ftime-report= or -ftime-report-json is enabled.
CODEGENOPT(TimePassesPerRun , 1, 0) ///< Set when -ftime-report=per-pass-run is enabled.
+CODEGENOPT(TimePassesJson , 1, 0) ///< Set when -ftime-report-json is enabled.
CODEGENOPT(TimeTrace , 1, 0) ///< Set when -ftime-trace is enabled.
VALUE_CODEGENOPT(TimeTraceGranularity, 32, 500) ///< 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 a9f4083920663..c822736e5d585 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -4083,6 +4083,11 @@ defm ms_tls_guards : BoolFOption<"ms-tls-guards",
def ftime_report : Flag<["-"], "ftime-report">, Group<f_Group>,
Visibility<[ClangOption, CC1Option, FlangOption, FC1Option]>,
MarshallingInfoFlag<CodeGenOpts<"TimePasses">>;
+def ftime_report_json
+ : Flag<["-"], "ftime-report-json">,
+ Group<f_Group>,
+ Visibility<[ClangOption, CC1Option, FlangOption, FC1Option]>,
+ MarshallingInfoFlag<CodeGenOpts<"TimePassesJson">>;
def ftime_report_EQ: Joined<["-"], "ftime-report=">, Group<f_Group>,
Visibility<[ClangOption, CC1Option]>, Values<"per-pass,per-pass-run">,
MarshallingInfoFlag<CodeGenOpts<"TimePassesPerRun">>,
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 762f8af886920..a2462b8f7a63b 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -7011,6 +7011,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_parseable_fixits);
Args.AddLastArg(CmdArgs, options::OPT_ftime_report);
Args.AddLastArg(CmdArgs, options::OPT_ftime_report_EQ);
+ Args.AddLastArg(CmdArgs, options::OPT_ftime_report_json);
Args.AddLastArg(CmdArgs, options::OPT_ftrapv);
Args.AddLastArg(CmdArgs, options::OPT_malign_double);
Args.AddLastArg(CmdArgs, options::OPT_fno_temp_file);
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index 8ff62ae2552c3..c7d11e6027ccf 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -1699,6 +1699,9 @@ void CompilerInvocationBase::GenerateCodeGenArgs(const CodeGenOptions &Opts,
GenerateArg(Consumer, OPT_ftime_report_EQ, "per-pass-run");
else
GenerateArg(Consumer, OPT_ftime_report);
+
+ if (Opts.TimePassesJson)
+ GenerateArg(Consumer, OPT_ftime_report_json);
}
if (Opts.PrepareForLTO && !Opts.PrepareForThinLTO)
@@ -2000,12 +2003,13 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
: llvm::codegenoptions::DebugTemplateNamesKind::Mangled);
}
- if (const Arg *A = Args.getLastArg(OPT_ftime_report, OPT_ftime_report_EQ)) {
+ if (const Arg *A = Args.getLastArg(OPT_ftime_report, OPT_ftime_report_EQ,
+ OPT_ftime_report_json)) {
Opts.TimePasses = true;
// -ftime-report= is only for new pass manager.
- if (A->getOption().getID() == OPT_ftime_report_EQ) {
- StringRef Val = A->getValue();
+ if (const Arg *EQ = Args.getLastArg(OPT_ftime_report_EQ)) {
+ StringRef Val = EQ->getValue();
if (Val == "per-pass")
Opts.TimePassesPerRun = false;
else if (Val == "per-pass-run")
@@ -2014,6 +2018,9 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
Diags.Report(diag::err_drv_invalid_value)
<< A->getAsString(Args) << A->getValue();
}
+
+ if (Args.getLastArg(OPT_ftime_report_json))
+ Opts.TimePassesJson = true;
}
Opts.PrepareForLTO = false;
diff --git a/clang/test/Misc/time-passes.c b/clang/test/Misc/time-passes.c
index c1669826b2268..35b5e1634ee73 100644
--- a/clang/test/Misc/time-passes.c
+++ b/clang/test/Misc/time-passes.c
@@ -8,6 +8,9 @@
// RUN: %clang_cc1 -emit-obj -O1 \
// RUN: -ftime-report=per-pass-run %s -o /dev/null 2>&1 | \
// RUN: FileCheck %s --check-prefixes=TIME,NPM-PER-INVOKE
+// RUN: %clang_cc1 -emit-obj -O1 \
+// RUN: -ftime-report-json %s -o /dev/null 2>&1 | \
+// RUN: FileCheck %s --check-prefixes=JSON
// TIME: Pass execution timing report
// TIME: Total Execution Time:
@@ -19,5 +22,10 @@
// NPM: InstCombinePass{{$}}
// NPM-NOT: InstCombinePass #
// TIME: Total{{$}}
+// JSON:{
+// JSON: "time.pass.InstCombinePass.wall": {{.*}},
+// JSON: "time.pass.InstCombinePass.user": {{.*}},
+// JSON: "time.pass.InstCombinePass.sys": {{.*}},
+// JSON:}
int foo(int x, int y) { return x + y; }
diff --git a/clang/tools/driver/cc1_main.cpp b/clang/tools/driver/cc1_main.cpp
index 341520c6a6f73..a2fc8fc465d8e 100644
--- a/clang/tools/driver/cc1_main.cpp
+++ b/clang/tools/driver/cc1_main.cpp
@@ -296,7 +296,14 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
// If any timers were active but haven't been destroyed yet, print their
// results now. This happens in -disable-free mode.
- llvm::TimerGroup::printAll(llvm::errs());
+ // llvm::TimerGroup::printAll(llvm::errs());
+ if (Clang->getCodeGenOpts().TimePassesJson) {
+ llvm::errs() << "{\n";
+ llvm::TimerGroup::printAllJSONValues(llvm::errs(), "");
+ llvm::errs() << "\n}\n";
+ } else {
+ llvm::TimerGroup::printAll(llvm::errs());
+ }
llvm::TimerGroup::clearAll();
if (llvm::timeTraceProfilerEnabled()) {
diff --git a/llvm/lib/Support/Timer.cpp b/llvm/lib/Support/Timer.cpp
index 69a1846fec29b..22811d7b4af0a 100644
--- a/llvm/lib/Support/Timer.cpp
+++ b/llvm/lib/Support/Timer.cpp
@@ -442,10 +442,6 @@ void TimerGroup::clearAll() {
void TimerGroup::printJSONValue(raw_ostream &OS, const PrintRecord &R,
const char *suffix, double Value) {
- assert(yaml::needsQuotes(Name) == yaml::QuotingType::None &&
- "TimerGroup name should not need quotes");
- assert(yaml::needsQuotes(R.Name) == yaml::QuotingType::None &&
- "Timer name should not need quotes");
constexpr auto max_digits10 = std::numeric_limits<double>::max_digits10;
OS << "\t\"time." << Name << '.' << R.Name << suffix
<< "\": " << format("%.*e", max_digits10 - 1, Value);
>From 287d106e974c75075c0ffdd66c7bf4fbef42b8ee Mon Sep 17 00:00:00 2001
From: Alan Zhao <ayzhao at google.com>
Date: Tue, 29 Apr 2025 16:28:23 -0700
Subject: [PATCH 2/3] remove leftover commented out code
---
clang/tools/driver/cc1_main.cpp | 1 -
1 file changed, 1 deletion(-)
diff --git a/clang/tools/driver/cc1_main.cpp b/clang/tools/driver/cc1_main.cpp
index a2fc8fc465d8e..1e79e78fdea62 100644
--- a/clang/tools/driver/cc1_main.cpp
+++ b/clang/tools/driver/cc1_main.cpp
@@ -296,7 +296,6 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
// If any timers were active but haven't been destroyed yet, print their
// results now. This happens in -disable-free mode.
- // llvm::TimerGroup::printAll(llvm::errs());
if (Clang->getCodeGenOpts().TimePassesJson) {
llvm::errs() << "{\n";
llvm::TimerGroup::printAllJSONValues(llvm::errs(), "");
>From 57094b42f4956afbf7665cab008d325afc3a6786 Mon Sep 17 00:00:00 2001
From: Alan Zhao <ayzhao at google.com>
Date: Wed, 30 Apr 2025 13:37:40 -0700
Subject: [PATCH 3/3] update clang ReleaseNotes.rst
---
clang/docs/ReleaseNotes.rst | 2 ++
1 file changed, 2 insertions(+)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 3105d8b481560..da3c48e4a1836 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -221,6 +221,8 @@ New Compiler Flags
The feature has `existed <https://clang.llvm.org/docs/SourceBasedCodeCoverage.html#running-the-instrumented-program>`_)
for a while and this is just a user facing option.
+- New option ``-ftime-report-json`` added which outputs the same timing data as `-ftime-report` but formatted as JSON.
+
Deprecated Compiler Flags
-------------------------
More information about the cfe-commits
mailing list