xref: /llvm-project/clang-tools-extra/clang-tidy/ClangTidyProfiling.cpp (revision 46a08ce83262767b3aae5c9828fabcd13f2e8a96)
112152511SRoman Lebedev //===--- ClangTidyProfiling.cpp - clang-tidy --------------------*- C++ -*-===//
212152511SRoman Lebedev //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
612152511SRoman Lebedev //
712152511SRoman Lebedev //===----------------------------------------------------------------------===//
812152511SRoman Lebedev 
912152511SRoman Lebedev #include "ClangTidyProfiling.h"
10a87f1d04SRoman Lebedev #include "llvm/ADT/SmallString.h"
11a87f1d04SRoman Lebedev #include "llvm/Support/FileSystem.h"
12a87f1d04SRoman Lebedev #include "llvm/Support/Path.h"
13a87f1d04SRoman Lebedev #include "llvm/Support/raw_ostream.h"
142c675be9SKazu Hirata #include <optional>
15a87f1d04SRoman Lebedev #include <system_error>
16a87f1d04SRoman Lebedev #include <utility>
1712152511SRoman Lebedev 
1812152511SRoman Lebedev #define DEBUG_TYPE "clang-tidy-profiling"
1912152511SRoman Lebedev 
207d2ea6c4SCarlos Galvez namespace clang::tidy {
2112152511SRoman Lebedev 
22a87f1d04SRoman Lebedev ClangTidyProfiling::StorageParams::StorageParams(llvm::StringRef ProfilePrefix,
23a87f1d04SRoman Lebedev                                                  llvm::StringRef SourceFile)
24a87f1d04SRoman Lebedev     : Timestamp(std::chrono::system_clock::now()), SourceFilename(SourceFile) {
25a87f1d04SRoman Lebedev   llvm::SmallString<32> TimestampStr;
26a87f1d04SRoman Lebedev   llvm::raw_svector_ostream OS(TimestampStr);
27a87f1d04SRoman Lebedev   llvm::format_provider<decltype(Timestamp)>::format(Timestamp, OS,
28a87f1d04SRoman Lebedev                                                      "%Y%m%d%H%M%S%N");
2912152511SRoman Lebedev 
30a87f1d04SRoman Lebedev   llvm::SmallString<256> FinalPrefix(ProfilePrefix);
31a87f1d04SRoman Lebedev   llvm::sys::path::append(FinalPrefix, TimestampStr);
32a87f1d04SRoman Lebedev 
33a87f1d04SRoman Lebedev   // So the full output name is: /ProfilePrefix/timestamp-inputfilename.json
34a87f1d04SRoman Lebedev   StoreFilename = llvm::Twine(FinalPrefix + "-" +
35a87f1d04SRoman Lebedev                               llvm::sys::path::filename(SourceFile) + ".json")
36a87f1d04SRoman Lebedev                       .str();
3712152511SRoman Lebedev }
3812152511SRoman Lebedev 
39*46a08ce8SCongcong Cai void ClangTidyProfiling::printUserFriendlyTable(llvm::raw_ostream &OS,
40*46a08ce8SCongcong Cai                                                 llvm::TimerGroup &TG) {
41*46a08ce8SCongcong Cai   TG.print(OS);
4212152511SRoman Lebedev   OS.flush();
4312152511SRoman Lebedev }
4412152511SRoman Lebedev 
45*46a08ce8SCongcong Cai void ClangTidyProfiling::printAsJSON(llvm::raw_ostream &OS,
46*46a08ce8SCongcong Cai                                      llvm::TimerGroup &TG) {
47a87f1d04SRoman Lebedev   OS << "{\n";
489c857f21SPiotr Zegar   OS << R"("file": ")" << Storage->SourceFilename << "\",\n";
499c857f21SPiotr Zegar   OS << R"("timestamp": ")" << Storage->Timestamp << "\",\n";
50a87f1d04SRoman Lebedev   OS << "\"profile\": {\n";
51*46a08ce8SCongcong Cai   TG.printJSONValues(OS, "");
52a87f1d04SRoman Lebedev   OS << "\n}\n";
53a87f1d04SRoman Lebedev   OS << "}\n";
54a87f1d04SRoman Lebedev   OS.flush();
55a87f1d04SRoman Lebedev }
56a87f1d04SRoman Lebedev 
57*46a08ce8SCongcong Cai void ClangTidyProfiling::storeProfileData(llvm::TimerGroup &TG) {
585413bf1bSKazu Hirata   assert(Storage && "We should have a filename.");
59a87f1d04SRoman Lebedev 
60a87f1d04SRoman Lebedev   llvm::SmallString<256> OutputDirectory(Storage->StoreFilename);
61a87f1d04SRoman Lebedev   llvm::sys::path::remove_filename(OutputDirectory);
62a87f1d04SRoman Lebedev   if (std::error_code EC = llvm::sys::fs::create_directories(OutputDirectory)) {
63a87f1d04SRoman Lebedev     llvm::errs() << "Unable to create output directory '" << OutputDirectory
64a87f1d04SRoman Lebedev                  << "': " << EC.message() << "\n";
65a87f1d04SRoman Lebedev     return;
66a87f1d04SRoman Lebedev   }
67a87f1d04SRoman Lebedev 
68a87f1d04SRoman Lebedev   std::error_code EC;
69d9b948b6SFangrui Song   llvm::raw_fd_ostream OS(Storage->StoreFilename, EC, llvm::sys::fs::OF_None);
70a87f1d04SRoman Lebedev   if (EC) {
71a87f1d04SRoman Lebedev     llvm::errs() << "Error opening output file '" << Storage->StoreFilename
72a87f1d04SRoman Lebedev                  << "': " << EC.message() << "\n";
73a87f1d04SRoman Lebedev     return;
74a87f1d04SRoman Lebedev   }
75a87f1d04SRoman Lebedev 
76*46a08ce8SCongcong Cai   printAsJSON(OS, TG);
77a87f1d04SRoman Lebedev }
78a87f1d04SRoman Lebedev 
792c675be9SKazu Hirata ClangTidyProfiling::ClangTidyProfiling(std::optional<StorageParams> Storage)
80a87f1d04SRoman Lebedev     : Storage(std::move(Storage)) {}
81a87f1d04SRoman Lebedev 
8212152511SRoman Lebedev ClangTidyProfiling::~ClangTidyProfiling() {
83*46a08ce8SCongcong Cai   llvm::TimerGroup TG{"clang-tidy", "clang-tidy checks profiling", Records};
845413bf1bSKazu Hirata   if (!Storage)
85*46a08ce8SCongcong Cai     printUserFriendlyTable(llvm::errs(), TG);
86a87f1d04SRoman Lebedev   else
87*46a08ce8SCongcong Cai     storeProfileData(TG);
8812152511SRoman Lebedev }
8912152511SRoman Lebedev 
907d2ea6c4SCarlos Galvez } // namespace clang::tidy
91