blob: fcc54042f404599a3f5faece3e7777a5a0b30875 [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 Bognerbfee8d42014-03-12 20:14:17 +000015#include "llvm/Profile/ProfileDataReader.h"
16#include "llvm/Profile/ProfileDataWriter.h"
Duncan P. N. Exon Smith846a6272014-02-17 23:22:49 +000017#include "llvm/Support/CommandLine.h"
Justin Bognerbfee8d42014-03-12 20:14:17 +000018#include "llvm/Support/LineIterator.h"
Duncan P. N. Exon Smith846a6272014-02-17 23:22:49 +000019#include "llvm/Support/ManagedStatic.h"
20#include "llvm/Support/MemoryBuffer.h"
21#include "llvm/Support/PrettyStackTrace.h"
22#include "llvm/Support/Signals.h"
23#include "llvm/Support/raw_ostream.h"
24
25using namespace llvm;
26
Duncan P. N. Exon Smith846a6272014-02-17 23:22:49 +000027static void exitWithError(const std::string &Message,
28 const std::string &Filename, int64_t Line = -1) {
29 errs() << "error: " << Filename;
30 if (Line >= 0)
31 errs() << ":" << Line;
32 errs() << ": " << Message << "\n";
33 ::exit(1);
34}
35
Justin Bognerbfee8d42014-03-12 20:14:17 +000036int merge_main(int argc, const char *argv[]) {
37 cl::opt<std::string> Filename1(cl::Positional, cl::Required,
38 cl::desc("file1"));
39 cl::opt<std::string> Filename2(cl::Positional, cl::Required,
40 cl::desc("file2"));
41
42 cl::opt<std::string> OutputFilename("output", cl::value_desc("output"),
43 cl::init("-"),
44 cl::desc("Output file"));
45 cl::alias OutputFilenameA("o", cl::desc("Alias for --output"),
46 cl::aliasopt(OutputFilename));
Duncan P. N. Exon Smith846a6272014-02-17 23:22:49 +000047
48 cl::ParseCommandLineOptions(argc, argv, "LLVM profile data merger\n");
49
Justin Bognerbfee8d42014-03-12 20:14:17 +000050 std::unique_ptr<ProfileDataReader> Reader1, Reader2;
51 if (error_code EC = ProfileDataReader::create(Filename1, Reader1))
52 exitWithError(EC.message(), Filename1);
53 if (error_code EC = ProfileDataReader::create(Filename2, Reader2))
54 exitWithError(EC.message(), Filename2);
Duncan P. N. Exon Smith846a6272014-02-17 23:22:49 +000055
56 if (OutputFilename.empty())
57 OutputFilename = "-";
58
59 std::string ErrorInfo;
Rafael Espindola90c7f1c2014-02-24 18:20:12 +000060 raw_fd_ostream Output(OutputFilename.data(), ErrorInfo, sys::fs::F_Text);
Duncan P. N. Exon Smith846a6272014-02-17 23:22:49 +000061 if (!ErrorInfo.empty())
62 exitWithError(ErrorInfo, OutputFilename);
63
Justin Bognerbfee8d42014-03-12 20:14:17 +000064 if (Output.is_displayed())
65 exitWithError("Refusing to write a binary file to stdout", OutputFilename);
Duncan P. N. Exon Smith846a6272014-02-17 23:22:49 +000066
Justin Bognerbfee8d42014-03-12 20:14:17 +000067 StringRef Name1, Name2;
68 std::vector<uint64_t> Counts1, Counts2, NewCounts;
69 uint64_t Hash1, Hash2;
70 ProfileDataWriter Writer;
71 ProfileDataReader::name_iterator I1 = Reader1->begin(),
72 E1 = Reader1->end(),
73 I2 = Reader2->begin(),
74 E2 = Reader2->end();
75 for (; I1 != E1 && I2 != E2; ++I1, ++I2) {
76 Name1 = *I1;
77 Name2 = *I2;
78 if (Name1 != Name2)
79 exitWithError("Function name mismatch", Filename2); // ???
Duncan P. N. Exon Smith846a6272014-02-17 23:22:49 +000080
Justin Bognerbfee8d42014-03-12 20:14:17 +000081 if (error_code EC = Reader1->getFunctionCounts(Name1, Hash1, Counts1))
82 exitWithError(EC.message(), Filename1);
83 if (error_code EC = Reader2->getFunctionCounts(Name2, Hash2, Counts2))
84 exitWithError(EC.message(), Filename2);
Duncan P. N. Exon Smith846a6272014-02-17 23:22:49 +000085
Justin Bognerbfee8d42014-03-12 20:14:17 +000086 if (Counts1.size() != Counts2.size())
87 exitWithError("Function count mismatch", Filename2); // ???
88 if (Hash1 != Hash2)
89 exitWithError("Function hash mismatch", Filename2); // ???
Duncan P. N. Exon Smith846a6272014-02-17 23:22:49 +000090
Justin Bognerbfee8d42014-03-12 20:14:17 +000091 for (size_t II = 0, EE = Counts1.size(); II < EE; ++II) {
92 uint64_t Sum = Counts1[II] + Counts2[II];
93 if (Sum < Counts1[II])
94 exitWithError("Counter overflow", Filename2); // ???
95 NewCounts.push_back(Sum);
Duncan P. N. Exon Smith846a6272014-02-17 23:22:49 +000096 }
97
Justin Bognerbfee8d42014-03-12 20:14:17 +000098 Writer.addFunctionCounts(Name1, Hash1, NewCounts.size(), NewCounts.data());
Duncan P. N. Exon Smith846a6272014-02-17 23:22:49 +000099
Justin Bognerbfee8d42014-03-12 20:14:17 +0000100 Counts1.clear();
101 Counts2.clear();
102 NewCounts.clear();
Duncan P. N. Exon Smith846a6272014-02-17 23:22:49 +0000103 }
Justin Bognerbfee8d42014-03-12 20:14:17 +0000104 if (I1 != E1 || I2 != E2)
105 exitWithError("Truncated file", Filename2);
106
107 Writer.write(Output);
Duncan P. N. Exon Smith846a6272014-02-17 23:22:49 +0000108
109 return 0;
110}
Justin Bognerbfee8d42014-03-12 20:14:17 +0000111
112struct HashPrinter {
113 uint64_t Hash;
114 HashPrinter(uint64_t Hash) : Hash(Hash) {}
115 void print(raw_ostream &OS) const {
116 char Buf[18], *Cur = Buf;
117 *Cur++ = '0'; *Cur++ = 'x';
118 for (unsigned I = 16; I;) {
119 char Digit = 0xF & (Hash >> (--I * 4));
120 *Cur++ = (Digit < 10 ? '0' + Digit : 'A' + Digit - 10);
121 }
122 OS.write(Buf, 18);
123 }
124};
125static raw_ostream &operator<<(raw_ostream &OS, const HashPrinter &Hash) {
126 Hash.print(OS);
127 return OS;
128}
129
130struct FreqPrinter {
131 double Freq;
132 FreqPrinter(double Freq) : Freq(Freq) {}
133 void print(raw_ostream &OS) const {
134 OS << (unsigned)(Freq * 100) << "." << ((unsigned)(Freq * 1000) % 10)
135 << ((unsigned)(Freq * 10000) % 10) << "%";
136 }
137};
138static raw_ostream &operator<<(raw_ostream &OS, const FreqPrinter &Freq) {
139 Freq.print(OS);
140 return OS;
141}
142
143int show_main(int argc, const char *argv[]) {
144 cl::opt<std::string> Filename(cl::Positional, cl::Required,
145 cl::desc("<profdata-file>"));
146
147 cl::opt<bool> ShowCounts("counts", cl::init(false));
148 cl::opt<bool> ShowAllFunctions("all-functions", cl::init(false));
149 cl::opt<std::string> ShowFunction("function");
150
151 cl::opt<std::string> OutputFilename("output", cl::value_desc("output"),
152 cl::init("-"),
153 cl::desc("Output file"));
154 cl::alias OutputFilenameA("o", cl::desc("Alias for --output"),
155 cl::aliasopt(OutputFilename));
156
157 cl::ParseCommandLineOptions(argc, argv, "LLVM profile data summary\n");
158
159 std::unique_ptr<ProfileDataReader> Reader;
160 if (error_code EC = ProfileDataReader::create(Filename, Reader))
161 exitWithError(EC.message(), Filename);
162
163 if (OutputFilename.empty())
164 OutputFilename = "-";
165
166 std::string ErrorInfo;
167 raw_fd_ostream OS(OutputFilename.data(), ErrorInfo, sys::fs::F_Text);
168 if (!ErrorInfo.empty())
169 exitWithError(ErrorInfo, OutputFilename);
170
171 if (ShowAllFunctions && !ShowFunction.empty())
172 errs() << "warning: -function argument ignored: showing all functions\n";
173
174 uint64_t MaxBlockCount = 0, MaxFunctionCount = 0;
175 uint64_t Hash;
176 double CallFreq;
177 size_t ShownFunctions = false;
178 std::vector<uint64_t> Counts;
179 for (const auto &Name : *Reader) {
180 bool Show = ShowAllFunctions || Name.find(ShowFunction) != Name.npos;
181 if (error_code EC = Reader->getFunctionCounts(Name, Hash, Counts))
182 exitWithError(EC.message(), Filename);
183 if (error_code EC = Reader->getCallFrequency(Name, Hash, CallFreq))
184 exitWithError(EC.message(), Filename);
185 if (Show) {
186 if (!ShownFunctions)
187 OS << "Counters:\n";
188 ++ShownFunctions;
189 OS << " " << Name << ":\n"
190 << " Hash: " << HashPrinter(Hash) << "\n"
191 << " Relative call frequency: " << FreqPrinter(CallFreq) << "\n"
192 << " Counters: " << Counts.size() << "\n"
193 << " Function count: " << Counts[0] << "\n";
194 }
195
196 if (Counts[0] > MaxFunctionCount)
197 MaxFunctionCount = Counts[0];
198
199 if (Show && ShowCounts)
200 OS << " Block counts: [";
201 for (size_t I = 1, E = Counts.size(); I < E; ++I) {
202 if (Counts[I] > MaxBlockCount)
203 MaxBlockCount = Counts[I];
204 if (Show && ShowCounts)
205 OS << (I == 1 ? "" : ", ") << Counts[I];
206 }
207 if (Show && ShowCounts)
208 OS << "]\n";
209
210 Counts.clear();
211 }
212
213 if (ShowAllFunctions || !ShowFunction.empty())
214 OS << "Functions shown: " << ShownFunctions << "\n";
215 OS << "Total functions: " << Reader->numProfiledFunctions() << "\n";
216 OS << "Maximum function count: " << MaxFunctionCount << "\n";
217 OS << "Maximum internal block count: " << MaxBlockCount << "\n";
218 return 0;
219}
220
221int generate_main(int argc, const char *argv[]) {
222 cl::opt<std::string> InputName(cl::Positional, cl::Required,
223 cl::desc("<input-file>"));
224
225 cl::opt<std::string> OutputFilename("output", cl::value_desc("output"),
226 cl::init("-"),
227 cl::desc("Output file"));
228 cl::alias OutputFilenameA("o", cl::desc("Alias for --output"),
229 cl::aliasopt(OutputFilename));
230
231 cl::ParseCommandLineOptions(argc, argv, "LLVM profile data generator\n");
232
233 if (OutputFilename.empty())
234 OutputFilename = "-";
235
236 std::string ErrorInfo;
237 raw_fd_ostream Output(OutputFilename.data(), ErrorInfo, sys::fs::F_Text);
238 if (!ErrorInfo.empty())
239 exitWithError(ErrorInfo, OutputFilename);
240
241 if (Output.is_displayed())
242 exitWithError("Refusing to write a binary file to stdout", OutputFilename);
243
244 std::unique_ptr<MemoryBuffer> Buffer;
245 if (error_code EC = MemoryBuffer::getFile(InputName, Buffer))
246 exitWithError(EC.message(), InputName);
247
248 ProfileDataWriter Writer;
249 StringRef Name;
250 uint64_t Hash, NumCounters;
251 std::vector<uint64_t> Counters;
252 for (line_iterator I(*Buffer, '#'); !I.is_at_end(); ++I) {
253 if (I->empty())
254 continue;
255 Name = *I;
256 if ((++I).is_at_end())
257 exitWithError("Truncated file", InputName, I.line_number());
258 if (I->getAsInteger(10, Hash))
259 exitWithError("Failed to read hash", InputName, I.line_number());
260 if ((++I).is_at_end())
261 exitWithError("Truncated file", InputName, I.line_number());
262 if (I->getAsInteger(10, NumCounters))
263 exitWithError("Failed to read num counters", InputName, I.line_number());
264 for (uint64_t CurCounter = 0; CurCounter < NumCounters; ++CurCounter) {
265 uint64_t Counter;
266 if ((++I).is_at_end())
267 exitWithError("Truncated file", InputName, I.line_number());
268 if (I->getAsInteger(10, Counter))
269 exitWithError("Failed to read counter", InputName, I.line_number());
270 Counters.push_back(Counter);
271 }
272 Writer.addFunctionCounts(Name, Hash, NumCounters, Counters.data());
273 Counters.clear();
274 }
275
276 Writer.write(Output);
277
278 return 0;
279}
280
281int main(int argc, const char *argv[]) {
282 // Print a stack trace if we signal out.
283 sys::PrintStackTraceOnErrorSignal();
284 PrettyStackTraceProgram X(argc, argv);
285 llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
286
287 StringRef ProgName(sys::path::filename(argv[0]));
288 if (argc > 1) {
289 int (*func)(int, const char *[]) = 0;
290
291 if (strcmp(argv[1], "merge") == 0)
292 func = merge_main;
293 else if (strcmp(argv[1], "show") == 0)
294 func = show_main;
295 else if (strcmp(argv[1], "generate") == 0)
296 func = generate_main;
297
298 if (func) {
299 std::string Invocation(ProgName.str() + " " + argv[1]);
300 argv[1] = Invocation.c_str();
301 return func(argc - 1, argv + 1);
302 }
303
304 if (strcmp(argv[1], "-h") == 0 ||
305 strcmp(argv[1], "-help") == 0 ||
306 strcmp(argv[1], "--help") == 0) {
307
308 errs() << "OVERVIEW: LLVM profile data tools\n\n"
309 << "USAGE: " << ProgName << " <command> [args...]\n"
310 << "USAGE: " << ProgName << " <command> -help\n\n"
311 << "Available commands: merge, show, generate\n";
312 return 0;
313 }
314 }
315
316 if (argc < 2)
317 errs() << ProgName << ": No command specified!\n";
318 else
319 errs() << ProgName << ": Unknown command!\n";
320
321 errs() << "USAGE: " << ProgName << " <merge|show|generate> [args...]\n";
322 return 1;
323}