[clang-tools-extra] [llvm] [clang-tidy] Restructure JSON profile structure to be parsable (PR #86821)

Paul Kirth via cfe-commits cfe-commits at lists.llvm.org
Wed Mar 27 08:55:14 PDT 2024


https://github.com/ilovepi created https://github.com/llvm/llvm-project/pull/86821

The existing JSON output from `--enable-profile` uses the check names as
keys in the object. This limits the machine readability of the output,
as each key is unique, forcing consumers to split and parse the
substrings of the key itself to organize and extract information.

This change adapts the existing code to output more structured JSON. The
profile is now an array of 'checks', which each have a name that can be
queried and individual times for each of 'wall', 'user', 'sys', 'mem',
and 'instr'. We also make 'mem' and 'sys' non optional, since this makes
parsing uniform. Future patches can triage any inconsistency in the
numeric representation for 'mem' and 'sys', e.g. by using NAN, `0` or
another well defined sentinel value for JSON numbers.


>From eebffcd379bd4dabb8a8cd442916925822aa87bb Mon Sep 17 00:00:00 2001
From: Paul Kirth <paulkirth at google.com>
Date: Wed, 27 Mar 2024 08:54:54 -0700
Subject: [PATCH] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20initia?=
 =?UTF-8?q?l=20version?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Created using spr 1.3.4
---
 .../clang-tidy/ClangTidyProfiling.cpp         |  4 +--
 .../clang-tidy-store-check-profile-one-tu.cpp | 29 ++++++++++++-------
 llvm/lib/Support/Timer.cpp                    | 28 +++++++++---------
 3 files changed, 35 insertions(+), 26 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/ClangTidyProfiling.cpp b/clang-tools-extra/clang-tidy/ClangTidyProfiling.cpp
index 07ab34a07cd31d..aa1e4b45a2f34c 100644
--- a/clang-tools-extra/clang-tidy/ClangTidyProfiling.cpp
+++ b/clang-tools-extra/clang-tidy/ClangTidyProfiling.cpp
@@ -45,9 +45,9 @@ void ClangTidyProfiling::printAsJSON(llvm::raw_ostream &OS) {
   OS << "{\n";
   OS << R"("file": ")" << Storage->SourceFilename << "\",\n";
   OS << R"("timestamp": ")" << Storage->Timestamp << "\",\n";
-  OS << "\"profile\": {\n";
+  OS << "\"profile\": [\n";
   TG->printJSONValues(OS, "");
-  OS << "\n}\n";
+  OS << "\n]\n";
   OS << "}\n";
   OS.flush();
 }
diff --git a/clang-tools-extra/test/clang-tidy/infrastructure/clang-tidy-store-check-profile-one-tu.cpp b/clang-tools-extra/test/clang-tidy/infrastructure/clang-tidy-store-check-profile-one-tu.cpp
index f0939f71edc073..17f6a21db30cf3 100644
--- a/clang-tools-extra/test/clang-tidy/infrastructure/clang-tidy-store-check-profile-one-tu.cpp
+++ b/clang-tools-extra/test/clang-tidy/infrastructure/clang-tidy-store-check-profile-one-tu.cpp
@@ -14,22 +14,31 @@
 // CHECK-FILE: {
 // CHECK-FILE-NEXT:"file": "{{.*}}clang-tidy-store-check-profile-one-tu.cpp",
 // CHECK-FILE-NEXT:"timestamp": "{{[0-9]+}}-{{[0-9]+}}-{{[0-9]+}} {{[0-9]+}}:{{[0-9]+}}:{{[0-9]+}}.{{[0-9]+}}",
-// CHECK-FILE-NEXT:"profile": {
-// CHECK-FILE-NEXT:	"time.clang-tidy.readability-function-size.wall": {{.*}}{{[0-9]}}.{{[0-9]+}}e{{[-+]}}{{[0-9]}}{{[0-9]}},
-// CHECK-FILE-NEXT:	"time.clang-tidy.readability-function-size.user": {{.*}}{{[0-9]}}.{{[0-9]+}}e{{[-+]}}{{[0-9]}}{{[0-9]}},
-// CHECK-FILE-NEXT:	"time.clang-tidy.readability-function-size.sys": {{.*}}{{[0-9]}}.{{[0-9]+}}e{{[-+]}}{{[0-9]}}{{[0-9]}}{{,?}}
-// If available on the platform, we also have a "time.clang-tidy.readability-function-size.instr" entry
-// CHECK-FILE: }
+// CHECK-FILE-NEXT:"profile": [
+// CHECK-FILE-NEXT:  "check": {
+// CHECK-FILE-NEXT:	"name": "clang-tidy.readability-function-size",
+// CHECK-FILE-NEXT:     "wall": {{.*}}{{[0-9]}}.{{[0-9]+}}e{{[-+]}}{{[0-9]}}{{[0-9]}},
+// CHECK-FILE-NEXT:	"user": {{.*}}{{[0-9]}}.{{[0-9]+}}e{{[-+]}}{{[0-9]}}{{[0-9]}},
+// CHECK-FILE-NEXT:	"sys": {{.*}}{{[0-9]}}.{{[0-9]+}}e{{[-+]}}{{[0-9]}}{{[0-9]}}{{,?}}
+// CHECK-FILE-NEXT:	"mem": {{.*}}{{[0-9]}}.{{[0-9]+}}e{{[-+]}}{{[0-9]}}{{[0-9]}},
+// CHECK-FILE-NEXT:	"instr": {{.*}}{{[0-9]}}.{{[0-9]+}}e{{[-+]}}{{[0-9]}}{{[0-9]}}
+// CHECK-FILE-NEXT:  }
+// CHECK-FILE: ]
 // CHECK-FILE-NEXT: }
 
 // CHECK-FILE-NOT: {
 // CHECK-FILE-NOT: "file": {{.*}}clang-tidy-store-check-profile-one-tu.cpp{{.*}},
 // CHECK-FILE-NOT: "timestamp": "{{[0-9]+}}-{{[0-9]+}}-{{[0-9]+}} {{[0-9]+}}:{{[0-9]+}}:{{[0-9]+}}.{{[0-9]+}}",
-// CHECK-FILE-NOT: "profile": {
-// CHECK-FILE-NOT:	"time.clang-tidy.readability-function-size.wall": {{.*}}{{[0-9]}}.{{[0-9]+}}e{{[-+]}}{{[0-9]}}{{[0-9]}},
-// CHECK-FILE-NOT:	"time.clang-tidy.readability-function-size.user": {{.*}}{{[0-9]}}.{{[0-9]+}}e{{[-+]}}{{[0-9]}}{{[0-9]}},
-// CHECK-FILE-NOT:	"time.clang-tidy.readability-function-size.sys": {{.*}}{{[0-9]}}.{{[0-9]+}}e{{[-+]}}{{[0-9]}}{{[0-9]}}{{,?}}
+// CHECK-FILE-NOT: "profile": [
+// CHECK-FILE-NOT:  "check": {
+// CHECK-FILE-NOT:	"name": "clang-tidy.readability-function-size",
+// CHECK-FILE-NOT:	"wall": {{.*}}{{[0-9]}}.{{[0-9]+}}e{{[-+]}}{{[0-9]}}{{[0-9]}},
+// CHECK-FILE-NOT:	"user": {{.*}}{{[0-9]}}.{{[0-9]+}}e{{[-+]}}{{[0-9]}}{{[0-9]}},
+// CHECK-FILE-NOT:	"sys": {{.*}}{{[0-9]}}.{{[0-9]+}}e{{[-+]}}{{[0-9]}}{{[0-9]}}{{,?}}
+// CHECK-FILE-NOT:	"mem": {{.*}}{{[0-9]}}.{{[0-9]+}}e{{[-+]}}{{[0-9]}}{{[0-9]}}{{,?}}
+// CHECK-FILE-NOT:	"instr": {{.*}}{{[0-9]}}.{{[0-9]+}}e{{[-+]}}{{[0-9]}}{{[0-9]}}{{,?}}
 // CHECK-FILE-NOT: }
+// CHECK-FILE-NOT: ]
 // CHECK-FILE-NOT: }
 
 class A {
diff --git a/llvm/lib/Support/Timer.cpp b/llvm/lib/Support/Timer.cpp
index c1b0fdbc077bb0..6f79deff97a6ee 100644
--- a/llvm/lib/Support/Timer.cpp
+++ b/llvm/lib/Support/Timer.cpp
@@ -472,21 +472,21 @@ const char *TimerGroup::printJSONValues(raw_ostream &OS, const char *delim) {
   for (const PrintRecord &R : TimersToPrint) {
     OS << delim;
     delim = ",\n";
-
     const TimeRecord &T = R.Time;
-    printJSONValue(OS, R, ".wall", T.getWallTime());
-    OS << delim;
-    printJSONValue(OS, R, ".user", T.getUserTime());
-    OS << delim;
-    printJSONValue(OS, R, ".sys", T.getSystemTime());
-    if (T.getMemUsed()) {
-      OS << delim;
-      printJSONValue(OS, R, ".mem", T.getMemUsed());
-    }
-    if (T.getInstructionsExecuted()) {
-      OS << delim;
-      printJSONValue(OS, R, ".instr", T.getInstructionsExecuted());
-    }
+    constexpr auto max_digits10 = std::numeric_limits<double>::max_digits10;
+    OS << "  \"check\": {\n";
+    OS << "    \"name\": \"" << Name << '.' << R.Name << "\""<< delim;
+    OS << "    \"wall\": " << format("%.*e", max_digits10 - 1, T.getWallTime())
+       << delim;
+    OS << "    \"user\": " << format("%.*e", max_digits10 - 1, T.getUserTime())
+       << delim;
+    OS << "    \"sys\": " << format("%.*e", max_digits10 - 1, T.getSystemTime())
+       << delim;
+    OS << "    \"mem\": " << format("%.*e", max_digits10 - 1, T.getMemUsed())
+       << delim;
+    OS << "    \"instr\": "
+       << format("%.*e", max_digits10 - 1, T.getInstructionsExecuted());
+    OS << "\n  }";
   }
   TimersToPrint.clear();
   return delim;



More information about the cfe-commits mailing list