blob: d5fa4ac288471b5c244462ff86b1412c16a430b5 [file] [log] [blame]
Duncan P. N. Exon Smith846a6272014-02-17 23:22:49 +00001//===- llvm-profdata.cpp - LLVM profile data tool -------------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// llvm-profdata merges .profdata files.
11//
12//===----------------------------------------------------------------------===//
13
Duncan P. N. Exon Smith846a6272014-02-17 23:22:49 +000014#include "llvm/ADT/StringRef.h"
Justin Bognerf8d79192014-03-21 17:24:48 +000015#include "llvm/ProfileData/InstrProfReader.h"
Duncan P. N. Exon Smith846a6272014-02-17 23:22:49 +000016#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"
22
23using namespace llvm;
24
Justin Bognerf8d79192014-03-21 17:24:48 +000025static void exitWithError(const Twine &Message, StringRef Whence = "") {
26 errs() << "error: ";
27 if (!Whence.empty())
28 errs() << Whence << ": ";
29 errs() << Message << "\n";
Duncan P. N. Exon Smith846a6272014-02-17 23:22:49 +000030 ::exit(1);
31}
32
Justin Bogner618bcea2014-03-19 02:20:46 +000033int merge_main(int argc, const char *argv[]) {
34 cl::opt<std::string> Filename1(cl::Positional, cl::Required,
35 cl::desc("file1"));
36 cl::opt<std::string> Filename2(cl::Positional, cl::Required,
37 cl::desc("file2"));
38
39 cl::opt<std::string> OutputFilename("output", cl::value_desc("output"),
40 cl::init("-"),
41 cl::desc("Output file"));
42 cl::alias OutputFilenameA("o", cl::desc("Alias for --output"),
43 cl::aliasopt(OutputFilename));
Justin Bognerbfee8d42014-03-12 20:14:17 +000044
Justin Bognerec49f982014-03-12 22:00:57 +000045 cl::ParseCommandLineOptions(argc, argv, "LLVM profile data merger\n");
Justin Bognerbfee8d42014-03-12 20:14:17 +000046
Justin Bognerf8d79192014-03-21 17:24:48 +000047 std::unique_ptr<InstrProfReader> Reader1, Reader2;
48 if (error_code ec = InstrProfReader::create(Filename1, Reader1))
Justin Bognerec49f982014-03-12 22:00:57 +000049 exitWithError(ec.message(), Filename1);
Justin Bognerf8d79192014-03-21 17:24:48 +000050 if (error_code ec = InstrProfReader::create(Filename2, Reader2))
Justin Bognerec49f982014-03-12 22:00:57 +000051 exitWithError(ec.message(), Filename2);
Justin Bognerbfee8d42014-03-12 20:14:17 +000052
Justin Bognerec49f982014-03-12 22:00:57 +000053 if (OutputFilename.empty())
54 OutputFilename = "-";
55
56 std::string ErrorInfo;
57 raw_fd_ostream Output(OutputFilename.data(), ErrorInfo, sys::fs::F_Text);
58 if (!ErrorInfo.empty())
59 exitWithError(ErrorInfo, OutputFilename);
60
Justin Bognerf8d79192014-03-21 17:24:48 +000061 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);
70
71 Output << I1->Name << "\n" << I1->Hash << "\n" << I1->Counts.size() << "\n";
72
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";
Justin Bognerbfee8d42014-03-12 20:14:17 +000078 }
Justin Bognerf8d79192014-03-21 17:24:48 +000079 Output << "\n";
Justin Bognerbfee8d42014-03-12 20:14:17 +000080 }
Justin Bognerf8d79192014-03-21 17:24:48 +000081 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.");
Justin Bognerbfee8d42014-03-12 20:14:17 +000087
Justin Bognerec49f982014-03-12 22:00:57 +000088 return 0;
Justin Bognerbfee8d42014-03-12 20:14:17 +000089}
Justin Bogner618bcea2014-03-19 02:20:46 +000090
Justin Bogner9af28ef2014-03-21 17:29:44 +000091struct HashPrinter {
92 uint64_t Hash;
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);
100 }
101 OS.write(Buf, 18);
102 }
103};
104static raw_ostream &operator<<(raw_ostream &OS, const HashPrinter &Hash) {
105 Hash.print(OS);
106 return OS;
107}
108
109int show_main(int argc, const char *argv[]) {
110 cl::opt<std::string> Filename(cl::Positional, cl::Required,
111 cl::desc("<profdata-file>"));
112
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"));
119
120 cl::opt<std::string> OutputFilename("output", cl::value_desc("output"),
121 cl::init("-"),
122 cl::desc("Output file"));
123 cl::alias OutputFilenameA("o", cl::desc("Alias for --output"),
124 cl::aliasopt(OutputFilename));
125
126 cl::ParseCommandLineOptions(argc, argv, "LLVM profile data summary\n");
127
128 std::unique_ptr<InstrProfReader> Reader;
129 if (error_code EC = InstrProfReader::create(Filename, Reader))
130 exitWithError(EC.message(), Filename);
131
132 if (OutputFilename.empty())
133 OutputFilename = "-";
134
135 std::string ErrorInfo;
136 raw_fd_ostream OS(OutputFilename.data(), ErrorInfo, sys::fs::F_Text);
137 if (!ErrorInfo.empty())
138 exitWithError(ErrorInfo, OutputFilename);
139
140 if (ShowAllFunctions && !ShowFunction.empty())
141 errs() << "warning: -function argument ignored: showing all functions\n";
142
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);
149
150 ++TotalFunctions;
151 if (Func.Counts[0] > MaxFunctionCount)
152 MaxFunctionCount = Func.Counts[0];
153
154 if (Show) {
155 if (!ShownFunctions)
156 OS << "Counters:\n";
157 ++ShownFunctions;
158
159 OS << " " << Func.Name << ":\n"
160 << " Hash: " << HashPrinter(Func.Hash) << "\n"
161 << " Counters: " << Func.Counts.size() << "\n"
162 << " Function count: " << Func.Counts[0] << "\n";
163 }
164
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];
172 }
173 if (Show && ShowCounts)
174 OS << "]\n";
175 }
176
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";
182 return 0;
183}
184
Justin Bogner618bcea2014-03-19 02:20:46 +0000185int 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.
190
191 StringRef ProgName(sys::path::filename(argv[0]));
192 if (argc > 1) {
193 int (*func)(int, const char *[]) = 0;
194
195 if (strcmp(argv[1], "merge") == 0)
196 func = merge_main;
Justin Bogner9af28ef2014-03-21 17:29:44 +0000197 else if (strcmp(argv[1], "show") == 0)
198 func = show_main;
Justin Bogner618bcea2014-03-19 02:20:46 +0000199
200 if (func) {
201 std::string Invocation(ProgName.str() + " " + argv[1]);
202 argv[1] = Invocation.c_str();
203 return func(argc - 1, argv + 1);
204 }
205
206 if (strcmp(argv[1], "-h") == 0 ||
207 strcmp(argv[1], "-help") == 0 ||
208 strcmp(argv[1], "--help") == 0) {
209
210 errs() << "OVERVIEW: LLVM profile data tools\n\n"
211 << "USAGE: " << ProgName << " <command> [args...]\n"
212 << "USAGE: " << ProgName << " <command> -help\n\n"
Justin Bogner9af28ef2014-03-21 17:29:44 +0000213 << "Available commands: merge, show\n";
Justin Bogner618bcea2014-03-19 02:20:46 +0000214 return 0;
215 }
216 }
217
218 if (argc < 2)
219 errs() << ProgName << ": No command specified!\n";
220 else
221 errs() << ProgName << ": Unknown command!\n";
222
Justin Bogner9af28ef2014-03-21 17:29:44 +0000223 errs() << "USAGE: " << ProgName << " <merge|show> [args...]\n";
Justin Bogner618bcea2014-03-19 02:20:46 +0000224 return 1;
225}