1 //===- llvm-profdata.cpp - LLVM profile data tool -------------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // llvm-profdata merges .profdata files.
12 //===----------------------------------------------------------------------===//
14 #include "llvm/ADT/StringRef.h"
15 #include "llvm/ProfileData/InstrProfReader.h"
16 #include "llvm/Support/CommandLine.h"
17 #include "llvm/Support/ManagedStatic.h"
18 #include "llvm/Support/MemoryBuffer.h"
19 #include "llvm/Support/PrettyStackTrace.h"
20 #include "llvm/Support/Signals.h"
21 #include "llvm/Support/raw_ostream.h"
25 static void exitWithError(const Twine &Message, StringRef Whence = "") {
28 errs() << Whence << ": ";
29 errs() << Message << "\n";
33 int merge_main(int argc, const char *argv[]) {
34 cl::opt<std::string> Filename1(cl::Positional, cl::Required,
36 cl::opt<std::string> Filename2(cl::Positional, cl::Required,
39 cl::opt<std::string> OutputFilename("output", cl::value_desc("output"),
41 cl::desc("Output file"));
42 cl::alias OutputFilenameA("o", cl::desc("Alias for --output"),
43 cl::aliasopt(OutputFilename));
45 cl::ParseCommandLineOptions(argc, argv, "LLVM profile data merger\n");
47 std::unique_ptr<InstrProfReader> Reader1, Reader2;
48 if (error_code ec = InstrProfReader::create(Filename1, Reader1))
49 exitWithError(ec.message(), Filename1);
50 if (error_code ec = InstrProfReader::create(Filename2, Reader2))
51 exitWithError(ec.message(), Filename2);
53 if (OutputFilename.empty())
56 std::string ErrorInfo;
57 raw_fd_ostream Output(OutputFilename.data(), ErrorInfo, sys::fs::F_Text);
58 if (!ErrorInfo.empty())
59 exitWithError(ErrorInfo, OutputFilename);
61 for (InstrProfIterator I1 = Reader1->begin(), E1 = Reader1->end(),
62 I2 = Reader2->begin(), E2 = Reader2->end();
63 I1 != E1 && I2 != E2; ++I1, ++I2) {
64 if (I1->Name != I2->Name)
65 exitWithError("Function name mismatch, " + I1->Name + " != " + I2->Name);
66 if (I1->Hash != I2->Hash)
67 exitWithError("Function hash mismatch for " + I1->Name);
68 if (I1->Counts.size() != I2->Counts.size())
69 exitWithError("Function count mismatch for " + I1->Name);
71 Output << I1->Name << "\n" << I1->Hash << "\n" << I1->Counts.size() << "\n";
73 for (size_t II = 0, EE = I1->Counts.size(); II < EE; ++II) {
74 uint64_t Sum = I1->Counts[II] + I2->Counts[II];
75 if (Sum < I1->Counts[II])
76 exitWithError("Counter overflow for " + I1->Name);
77 Output << Sum << "\n";
81 if (Reader1->hasError())
82 exitWithError(Reader1->getError().message(), Filename1);
83 if (Reader2->hasError())
84 exitWithError(Reader2->getError().message(), Filename2);
85 if (!Reader1->isEOF() || !Reader2->isEOF())
86 exitWithError("Number of instrumented functions differ.");
93 HashPrinter(uint64_t Hash) : Hash(Hash) {}
94 void print(raw_ostream &OS) const {
95 char Buf[18], *Cur = Buf;
96 *Cur++ = '0'; *Cur++ = 'x';
97 for (unsigned I = 16; I;) {
98 char Digit = 0xF & (Hash >> (--I * 4));
99 *Cur++ = (Digit < 10 ? '0' + Digit : 'A' + Digit - 10);
104 static raw_ostream &operator<<(raw_ostream &OS, const HashPrinter &Hash) {
109 int show_main(int argc, const char *argv[]) {
110 cl::opt<std::string> Filename(cl::Positional, cl::Required,
111 cl::desc("<profdata-file>"));
113 cl::opt<bool> ShowCounts("counts", cl::init(false),
114 cl::desc("Show counter values for shown functions"));
115 cl::opt<bool> ShowAllFunctions("all-functions", cl::init(false),
116 cl::desc("Details for every function"));
117 cl::opt<std::string> ShowFunction("function",
118 cl::desc("Details for matching functions"));
120 cl::opt<std::string> OutputFilename("output", cl::value_desc("output"),
122 cl::desc("Output file"));
123 cl::alias OutputFilenameA("o", cl::desc("Alias for --output"),
124 cl::aliasopt(OutputFilename));
126 cl::ParseCommandLineOptions(argc, argv, "LLVM profile data summary\n");
128 std::unique_ptr<InstrProfReader> Reader;
129 if (error_code EC = InstrProfReader::create(Filename, Reader))
130 exitWithError(EC.message(), Filename);
132 if (OutputFilename.empty())
133 OutputFilename = "-";
135 std::string ErrorInfo;
136 raw_fd_ostream OS(OutputFilename.data(), ErrorInfo, sys::fs::F_Text);
137 if (!ErrorInfo.empty())
138 exitWithError(ErrorInfo, OutputFilename);
140 if (ShowAllFunctions && !ShowFunction.empty())
141 errs() << "warning: -function argument ignored: showing all functions\n";
143 uint64_t MaxFunctionCount = 0, MaxBlockCount = 0;
144 size_t ShownFunctions = 0, TotalFunctions = 0;
145 for (const auto &Func : *Reader) {
146 bool Show = ShowAllFunctions ||
147 (!ShowFunction.empty() &&
148 Func.Name.find(ShowFunction) != Func.Name.npos);
151 if (Func.Counts[0] > MaxFunctionCount)
152 MaxFunctionCount = Func.Counts[0];
159 OS << " " << Func.Name << ":\n"
160 << " Hash: " << HashPrinter(Func.Hash) << "\n"
161 << " Counters: " << Func.Counts.size() << "\n"
162 << " Function count: " << Func.Counts[0] << "\n";
165 if (Show && ShowCounts)
166 OS << " Block counts: [";
167 for (size_t I = 1, E = Func.Counts.size(); I < E; ++I) {
168 if (Func.Counts[I] > MaxBlockCount)
169 MaxBlockCount = Func.Counts[I];
170 if (Show && ShowCounts)
171 OS << (I == 1 ? "" : ", ") << Func.Counts[I];
173 if (Show && ShowCounts)
177 if (ShowAllFunctions || !ShowFunction.empty())
178 OS << "Functions shown: " << ShownFunctions << "\n";
179 OS << "Total functions: " << TotalFunctions << "\n";
180 OS << "Maximum function count: " << MaxFunctionCount << "\n";
181 OS << "Maximum internal block count: " << MaxBlockCount << "\n";
185 int main(int argc, const char *argv[]) {
186 // Print a stack trace if we signal out.
187 sys::PrintStackTraceOnErrorSignal();
188 PrettyStackTraceProgram X(argc, argv);
189 llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
191 StringRef ProgName(sys::path::filename(argv[0]));
193 int (*func)(int, const char *[]) = 0;
195 if (strcmp(argv[1], "merge") == 0)
197 else if (strcmp(argv[1], "show") == 0)
201 std::string Invocation(ProgName.str() + " " + argv[1]);
202 argv[1] = Invocation.c_str();
203 return func(argc - 1, argv + 1);
206 if (strcmp(argv[1], "-h") == 0 ||
207 strcmp(argv[1], "-help") == 0 ||
208 strcmp(argv[1], "--help") == 0) {
210 errs() << "OVERVIEW: LLVM profile data tools\n\n"
211 << "USAGE: " << ProgName << " <command> [args...]\n"
212 << "USAGE: " << ProgName << " <command> -help\n\n"
213 << "Available commands: merge, show\n";
219 errs() << ProgName << ": No command specified!\n";
221 errs() << ProgName << ": Unknown command!\n";
223 errs() << "USAGE: " << ProgName << " <merge|show> [args...]\n";