diff options
| author | Roman Lebedev <lebedev.ri@gmail.com> | 2018-06-06 15:07:51 +0000 |
|---|---|---|
| committer | Roman Lebedev <lebedev.ri@gmail.com> | 2018-06-06 15:07:51 +0000 |
| commit | a87f1d04cee8168c91d497f9589dc038b3863b14 (patch) | |
| tree | 686d92842969cd48458986ca5e1d2f583df248f4 /clang-tools-extra/clang-tidy/ClangTidyProfiling.cpp | |
| parent | c4b7e0125ffb7ccb66f39c8ebee32145a322c6b0 (diff) | |
| download | bcm5719-llvm-a87f1d04cee8168c91d497f9589dc038b3863b14.tar.gz bcm5719-llvm-a87f1d04cee8168c91d497f9589dc038b3863b14.zip | |
[clang-tidy] Store checks profiling info as JSON files
Summary:
Continuation of D46504.
Example output:
```
$ clang-tidy -enable-check-profile -store-check-profile=. -checks=-*,readability-function-size source.cpp
$ # Note that there won't be timings table printed to the console.
$ cat *.json
{
"file": "/path/to/source.cpp",
"timestamp": "2018-05-16 16:13:18.717446360",
"profile": {
"time.clang-tidy.readability-function-size.wall": 1.0421266555786133e+00,
"time.clang-tidy.readability-function-size.user": 9.2088400000005421e-01,
"time.clang-tidy.readability-function-size.sys": 1.2418899999999974e-01
}
}
```
There are two arguments that control profile storage:
* `-store-check-profile=<prefix>`
By default reports are printed in tabulated format to stderr. When this option
is passed, these per-TU profiles are instead stored as JSON.
If the prefix is not an absolute path, it is considered to be relative to the
directory from where you have run :program:`clang-tidy`. All `.` and `..`
patterns in the path are collapsed, and symlinks are resolved.
Example:
Let's suppose you have a source file named `example.cpp`, located in
`/source` directory.
* If you specify `-store-check-profile=/tmp`, then the profile will be saved
to `/tmp/<timestamp>-example.cpp.json`
* If you run :program:`clang-tidy` from within `/foo` directory, and specify
`-store-check-profile=.`, then the profile will still be saved to
`/foo/<timestamp>-example.cpp.json`
Reviewers: alexfh, sbenza, george.karpenkov, NoQ, aaron.ballman
Reviewed By: alexfh, george.karpenkov, aaron.ballman
Subscribers: Quuxplusone, JonasToth, aaron.ballman, llvm-commits, rja, Eugene.Zelenko, xazax.hun, mgrang, cfe-commits
Tags: #clang-tools-extra
Differential Revision: https://reviews.llvm.org/D46602
llvm-svn: 334101
Diffstat (limited to 'clang-tools-extra/clang-tidy/ClangTidyProfiling.cpp')
| -rw-r--r-- | clang-tools-extra/clang-tidy/ClangTidyProfiling.cpp | 100 |
1 files changed, 64 insertions, 36 deletions
diff --git a/clang-tools-extra/clang-tidy/ClangTidyProfiling.cpp b/clang-tools-extra/clang-tidy/ClangTidyProfiling.cpp index d332942fa24..fc0a9697b94 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyProfiling.cpp +++ b/clang-tools-extra/clang-tidy/ClangTidyProfiling.cpp @@ -9,56 +9,84 @@ #include "ClangTidyProfiling.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/YAMLTraits.h" +#include "llvm/Support/raw_ostream.h" +#include <system_error> +#include <utility> #define DEBUG_TYPE "clang-tidy-profiling" namespace clang { namespace tidy { -void ClangTidyProfiling::preprocess() { - // Convert from a insertion-friendly map to sort-friendly vector. - Timers.clear(); - Timers.reserve(Records.size()); - for (const auto &P : Records) { - Timers.emplace_back(P.getValue(), P.getKey()); - Total += P.getValue(); - } - assert(Timers.size() == Records.size() && "Size mismatch after processing"); +ClangTidyProfiling::StorageParams::StorageParams(llvm::StringRef ProfilePrefix, + llvm::StringRef SourceFile) + : Timestamp(std::chrono::system_clock::now()), SourceFilename(SourceFile) { + llvm::SmallString<32> TimestampStr; + llvm::raw_svector_ostream OS(TimestampStr); + llvm::format_provider<decltype(Timestamp)>::format(Timestamp, OS, + "%Y%m%d%H%M%S%N"); + + llvm::SmallString<256> FinalPrefix(ProfilePrefix); + llvm::sys::path::append(FinalPrefix, TimestampStr); - // We want the measurements to be sorted by decreasing time spent. - llvm::sort(Timers.begin(), Timers.end()); + // So the full output name is: /ProfilePrefix/timestamp-inputfilename.json + StoreFilename = llvm::Twine(FinalPrefix + "-" + + llvm::sys::path::filename(SourceFile) + ".json") + .str(); } -void ClangTidyProfiling::printProfileData(llvm::raw_ostream &OS) const { - std::string Line = "===" + std::string(73, '-') + "===\n"; - OS << Line; - - if (Total.getUserTime()) - OS << " ---User Time---"; - if (Total.getSystemTime()) - OS << " --System Time--"; - if (Total.getProcessTime()) - OS << " --User+System--"; - OS << " ---Wall Time---"; - if (Total.getMemUsed()) - OS << " ---Mem---"; - OS << " --- Name ---\n"; - - // Loop through all of the timing data, printing it out. - for (auto I = Timers.rbegin(), E = Timers.rend(); I != E; ++I) { - I->first.print(Total, OS); - OS << I->second << '\n'; - } +void ClangTidyProfiling::printUserFriendlyTable(llvm::raw_ostream &OS) { + TG->print(OS); + OS.flush(); +} - Total.print(Total, OS); - OS << "Total\n"; - OS << Line << "\n"; +void ClangTidyProfiling::printAsJSON(llvm::raw_ostream &OS) { + OS << "{\n"; + OS << "\"file\": \"" << Storage->SourceFilename << "\",\n"; + OS << "\"timestamp\": \"" << Storage->Timestamp << "\",\n"; + OS << "\"profile\": {\n"; + TG->printJSONValues(OS, ""); + OS << "\n}\n"; + OS << "}\n"; OS.flush(); } +void ClangTidyProfiling::storeProfileData() { + assert(Storage.hasValue() && "We should have a filename."); + + llvm::SmallString<256> OutputDirectory(Storage->StoreFilename); + llvm::sys::path::remove_filename(OutputDirectory); + if (std::error_code EC = llvm::sys::fs::create_directories(OutputDirectory)) { + llvm::errs() << "Unable to create output directory '" << OutputDirectory + << "': " << EC.message() << "\n"; + return; + } + + std::error_code EC; + llvm::raw_fd_ostream OS(Storage->StoreFilename, EC, llvm::sys::fs::F_None); + if (EC) { + llvm::errs() << "Error opening output file '" << Storage->StoreFilename + << "': " << EC.message() << "\n"; + return; + } + + printAsJSON(OS); +} + +ClangTidyProfiling::ClangTidyProfiling(llvm::Optional<StorageParams> Storage) + : Storage(std::move(Storage)) {} + ClangTidyProfiling::~ClangTidyProfiling() { - preprocess(); - printProfileData(llvm::errs()); + TG.emplace("clang-tidy", "clang-tidy checks profiling", Records); + + if (!Storage.hasValue()) + printUserFriendlyTable(llvm::errs()); + else + storeProfileData(); } } // namespace tidy |

