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