Revert "[llvm-profdata] Add support for weighted merge of profile data"
[oota-llvm.git] / tools / llvm-profdata / llvm-profdata.cpp
1 //===- 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
14 #include "llvm/ADT/SmallSet.h"
15 #include "llvm/ADT/StringRef.h"
16 #include "llvm/IR/LLVMContext.h"
17 #include "llvm/ProfileData/InstrProfReader.h"
18 #include "llvm/ProfileData/InstrProfWriter.h"
19 #include "llvm/ProfileData/SampleProfReader.h"
20 #include "llvm/ProfileData/SampleProfWriter.h"
21 #include "llvm/Support/CommandLine.h"
22 #include "llvm/Support/FileSystem.h"
23 #include "llvm/Support/Format.h"
24 #include "llvm/Support/ManagedStatic.h"
25 #include "llvm/Support/MemoryBuffer.h"
26 #include "llvm/Support/Path.h"
27 #include "llvm/Support/PrettyStackTrace.h"
28 #include "llvm/Support/Signals.h"
29 #include "llvm/Support/raw_ostream.h"
30
31 using namespace llvm;
32
33 enum ProfileFormat { PF_None = 0, PF_Text, PF_Binary, PF_GCC };
34
35 static void exitWithError(const Twine &Message,
36                           StringRef Whence = "",
37                           StringRef Hint = "") {
38   errs() << "error: ";
39   if (!Whence.empty())
40     errs() << Whence << ": ";
41   errs() << Message << "\n";
42   if (!Hint.empty())
43     errs() << Hint << "\n";
44   ::exit(1);
45 }
46
47 static void exitWithErrorCode(const std::error_code &Error,
48                               StringRef Whence = "") {
49   if (Error.category() == instrprof_category()) {
50     instrprof_error instrError = static_cast<instrprof_error>(Error.value());
51     if (instrError == instrprof_error::unrecognized_format) {
52       // Hint for common error of forgetting -sample for sample profiles.
53       exitWithError(Error.message(), Whence,
54                     "Perhaps you forgot to use the -sample option?");
55     }
56   }
57   exitWithError(Error.message(), Whence);
58 }
59
60 namespace {
61     enum ProfileKinds { instr, sample };
62 }
63
64 static void handleMergeWriterError(std::error_code &Error,
65                                    StringRef WhenceFile = "",
66                                    StringRef WhenceFunction = "",
67                                    bool ShowHint = true)
68 {
69   if (!WhenceFile.empty())
70     errs() << WhenceFile << ": ";
71   if (!WhenceFunction.empty())
72     errs() << WhenceFunction << ": ";
73   errs() << Error.message() << "\n";
74
75   if (ShowHint) {
76     StringRef Hint = "";
77     if (Error.category() == instrprof_category()) {
78       instrprof_error instrError = static_cast<instrprof_error>(Error.value());
79       switch (instrError) {
80       case instrprof_error::hash_mismatch:
81       case instrprof_error::count_mismatch:
82       case instrprof_error::value_site_count_mismatch:
83         Hint = "Make sure that all profile data to be merged is generated " \
84                "from the same binary.";
85         break;
86       default:
87         break;
88       }
89     }
90
91     if (!Hint.empty())
92       errs() << Hint << "\n";
93   }
94 }
95
96 static void mergeInstrProfile(const cl::list<std::string> &Inputs,
97                               StringRef OutputFilename,
98                               ProfileFormat OutputFormat) {
99   if (OutputFilename.compare("-") == 0)
100     exitWithError("Cannot write indexed profdata format to stdout.");
101
102   if (OutputFormat != PF_Binary && OutputFormat != PF_Text)
103     exitWithError("Unknown format is specified.");
104
105   std::error_code EC;
106   raw_fd_ostream Output(OutputFilename.data(), EC, sys::fs::F_None);
107   if (EC)
108     exitWithErrorCode(EC, OutputFilename);
109
110   InstrProfWriter Writer;
111   SmallSet<std::error_code, 4> WriterErrorCodes;
112   for (const auto &Filename : Inputs) {
113     auto ReaderOrErr = InstrProfReader::create(Filename);
114     if (std::error_code ec = ReaderOrErr.getError())
115       exitWithErrorCode(ec, Filename);
116
117     auto Reader = std::move(ReaderOrErr.get());
118     for (auto &I : *Reader) {
119       if (std::error_code EC = Writer.addRecord(std::move(I))) {
120         // Only show hint the first time an error occurs.
121         bool firstTime = WriterErrorCodes.insert(EC).second;
122         handleMergeWriterError(EC, Filename, I.Name, firstTime);
123       }
124     }
125     if (Reader->hasError())
126       exitWithErrorCode(Reader->getError(), Filename);
127   }
128   if (OutputFormat == PF_Text)
129     Writer.writeText(Output);
130   else
131     Writer.write(Output);
132 }
133
134 static sampleprof::SampleProfileFormat FormatMap[] = {
135     sampleprof::SPF_None, sampleprof::SPF_Text, sampleprof::SPF_Binary,
136     sampleprof::SPF_GCC};
137
138 static void mergeSampleProfile(const cl::list<std::string> &Inputs,
139                                StringRef OutputFilename,
140                                ProfileFormat OutputFormat) {
141   using namespace sampleprof;
142   auto WriterOrErr =
143       SampleProfileWriter::create(OutputFilename, FormatMap[OutputFormat]);
144   if (std::error_code EC = WriterOrErr.getError())
145     exitWithErrorCode(EC, OutputFilename);
146
147   auto Writer = std::move(WriterOrErr.get());
148   StringMap<FunctionSamples> ProfileMap;
149   SmallVector<std::unique_ptr<sampleprof::SampleProfileReader>, 5> Readers;
150   for (const auto &Filename : Inputs) {
151     auto ReaderOrErr =
152         SampleProfileReader::create(Filename, getGlobalContext());
153     if (std::error_code EC = ReaderOrErr.getError())
154       exitWithErrorCode(EC, Filename);
155
156     // We need to keep the readers around until after all the files are
157     // read so that we do not lose the function names stored in each
158     // reader's memory. The function names are needed to write out the
159     // merged profile map.
160     Readers.push_back(std::move(ReaderOrErr.get()));
161     const auto Reader = Readers.back().get();
162     if (std::error_code EC = Reader->read())
163       exitWithErrorCode(EC, Filename);
164
165     StringMap<FunctionSamples> &Profiles = Reader->getProfiles();
166     for (StringMap<FunctionSamples>::iterator I = Profiles.begin(),
167                                               E = Profiles.end();
168          I != E; ++I) {
169       StringRef FName = I->first();
170       FunctionSamples &Samples = I->second;
171       ProfileMap[FName].merge(Samples);
172     }
173   }
174   Writer->write(ProfileMap);
175 }
176
177 static int merge_main(int argc, const char *argv[]) {
178   cl::list<std::string> Inputs(cl::Positional, cl::Required, cl::OneOrMore,
179                                cl::desc("<filenames...>"));
180
181   cl::opt<std::string> OutputFilename("output", cl::value_desc("output"),
182                                       cl::init("-"), cl::Required,
183                                       cl::desc("Output file"));
184   cl::alias OutputFilenameA("o", cl::desc("Alias for --output"),
185                             cl::aliasopt(OutputFilename));
186   cl::opt<ProfileKinds> ProfileKind(
187       cl::desc("Profile kind:"), cl::init(instr),
188       cl::values(clEnumVal(instr, "Instrumentation profile (default)"),
189                  clEnumVal(sample, "Sample profile"), clEnumValEnd));
190
191   cl::opt<ProfileFormat> OutputFormat(
192       cl::desc("Format of output profile"), cl::init(PF_Binary),
193       cl::values(clEnumValN(PF_Binary, "binary", "Binary encoding (default)"),
194                  clEnumValN(PF_Text, "text", "Text encoding"),
195                  clEnumValN(PF_GCC, "gcc",
196                             "GCC encoding (only meaningful for -sample)"),
197                  clEnumValEnd));
198
199   cl::ParseCommandLineOptions(argc, argv, "LLVM profile data merger\n");
200
201   if (ProfileKind == instr)
202     mergeInstrProfile(Inputs, OutputFilename, OutputFormat);
203   else
204     mergeSampleProfile(Inputs, OutputFilename, OutputFormat);
205
206   return 0;
207 }
208
209 static int showInstrProfile(std::string Filename, bool ShowCounts,
210                             bool ShowIndirectCallTargets, bool ShowAllFunctions,
211                             std::string ShowFunction, bool TextFormat,
212                             raw_fd_ostream &OS) {
213   auto ReaderOrErr = InstrProfReader::create(Filename);
214   if (std::error_code EC = ReaderOrErr.getError())
215     exitWithErrorCode(EC, Filename);
216
217   auto Reader = std::move(ReaderOrErr.get());
218   uint64_t MaxFunctionCount = 0, MaxBlockCount = 0;
219   size_t ShownFunctions = 0, TotalFunctions = 0;
220   for (const auto &Func : *Reader) {
221     bool Show =
222         ShowAllFunctions || (!ShowFunction.empty() &&
223                              Func.Name.find(ShowFunction) != Func.Name.npos);
224
225     bool doTextFormatDump = (Show && ShowCounts && TextFormat);
226
227     if (doTextFormatDump) {
228       InstrProfWriter::writeRecordInText(Func, OS);
229       continue;
230     }
231
232     ++TotalFunctions;
233     assert(Func.Counts.size() > 0 && "function missing entry counter");
234     if (Func.Counts[0] > MaxFunctionCount)
235       MaxFunctionCount = Func.Counts[0];
236
237     for (size_t I = 1, E = Func.Counts.size(); I < E; ++I) {
238       if (Func.Counts[I] > MaxBlockCount)
239         MaxBlockCount = Func.Counts[I];
240     }
241
242     if (Show) {
243
244       if (!ShownFunctions)
245         OS << "Counters:\n";
246
247       ++ShownFunctions;
248
249       OS << "  " << Func.Name << ":\n"
250          << "    Hash: " << format("0x%016" PRIx64, Func.Hash) << "\n"
251          << "    Counters: " << Func.Counts.size() << "\n"
252          << "    Function count: " << Func.Counts[0] << "\n";
253
254       if (ShowIndirectCallTargets)
255         OS << "    Indirect Call Site Count: "
256            << Func.getNumValueSites(IPVK_IndirectCallTarget) << "\n";
257
258       if (ShowCounts) {
259         OS << "    Block counts: [";
260         for (size_t I = 1, E = Func.Counts.size(); I < E; ++I) {
261           OS << (I == 1 ? "" : ", ") << Func.Counts[I];
262         }
263         OS << "]\n";
264       }
265
266       if (ShowIndirectCallTargets) {
267         uint32_t NS = Func.getNumValueSites(IPVK_IndirectCallTarget);
268         OS << "    Indirect Target Results: \n";
269         for (size_t I = 0; I < NS; ++I) {
270           uint32_t NV = Func.getNumValueDataForSite(IPVK_IndirectCallTarget, I);
271           std::unique_ptr<InstrProfValueData[]> VD =
272               Func.getValueForSite(IPVK_IndirectCallTarget, I);
273           for (uint32_t V = 0; V < NV; V++) {
274             OS << "\t[ " << I << ", ";
275             OS << (const char *)VD[V].Value << ", " << VD[V].Count << " ]\n";
276           }
277         }
278       }
279     }
280   }
281
282   if (Reader->hasError())
283     exitWithErrorCode(Reader->getError(), Filename);
284
285   if (ShowCounts && TextFormat)
286     return 0;
287
288   if (ShowAllFunctions || !ShowFunction.empty())
289     OS << "Functions shown: " << ShownFunctions << "\n";
290   OS << "Total functions: " << TotalFunctions << "\n";
291   OS << "Maximum function count: " << MaxFunctionCount << "\n";
292   OS << "Maximum internal block count: " << MaxBlockCount << "\n";
293   return 0;
294 }
295
296 static int showSampleProfile(std::string Filename, bool ShowCounts,
297                              bool ShowAllFunctions, std::string ShowFunction,
298                              raw_fd_ostream &OS) {
299   using namespace sampleprof;
300   auto ReaderOrErr = SampleProfileReader::create(Filename, getGlobalContext());
301   if (std::error_code EC = ReaderOrErr.getError())
302     exitWithErrorCode(EC, Filename);
303
304   auto Reader = std::move(ReaderOrErr.get());
305   if (std::error_code EC = Reader->read())
306     exitWithErrorCode(EC, Filename);
307
308   if (ShowAllFunctions || ShowFunction.empty())
309     Reader->dump(OS);
310   else
311     Reader->dumpFunctionProfile(ShowFunction, OS);
312
313   return 0;
314 }
315
316 static int show_main(int argc, const char *argv[]) {
317   cl::opt<std::string> Filename(cl::Positional, cl::Required,
318                                 cl::desc("<profdata-file>"));
319
320   cl::opt<bool> ShowCounts("counts", cl::init(false),
321                            cl::desc("Show counter values for shown functions"));
322   cl::opt<bool> TextFormat(
323       "text", cl::init(false),
324       cl::desc("Show instr profile data in text dump format"));
325   cl::opt<bool> ShowIndirectCallTargets(
326       "ic-targets", cl::init(false),
327       cl::desc("Show indirect call site target values for shown functions"));
328   cl::opt<bool> ShowAllFunctions("all-functions", cl::init(false),
329                                  cl::desc("Details for every function"));
330   cl::opt<std::string> ShowFunction("function",
331                                     cl::desc("Details for matching functions"));
332
333   cl::opt<std::string> OutputFilename("output", cl::value_desc("output"),
334                                       cl::init("-"), cl::desc("Output file"));
335   cl::alias OutputFilenameA("o", cl::desc("Alias for --output"),
336                             cl::aliasopt(OutputFilename));
337   cl::opt<ProfileKinds> ProfileKind(
338       cl::desc("Profile kind:"), cl::init(instr),
339       cl::values(clEnumVal(instr, "Instrumentation profile (default)"),
340                  clEnumVal(sample, "Sample profile"), clEnumValEnd));
341
342   cl::ParseCommandLineOptions(argc, argv, "LLVM profile data summary\n");
343
344   if (OutputFilename.empty())
345     OutputFilename = "-";
346
347   std::error_code EC;
348   raw_fd_ostream OS(OutputFilename.data(), EC, sys::fs::F_Text);
349   if (EC)
350     exitWithErrorCode(EC, OutputFilename);
351
352   if (ShowAllFunctions && !ShowFunction.empty())
353     errs() << "warning: -function argument ignored: showing all functions\n";
354
355   if (ProfileKind == instr)
356     return showInstrProfile(Filename, ShowCounts, ShowIndirectCallTargets,
357                             ShowAllFunctions, ShowFunction, TextFormat, OS);
358   else
359     return showSampleProfile(Filename, ShowCounts, ShowAllFunctions,
360                              ShowFunction, OS);
361 }
362
363 int main(int argc, const char *argv[]) {
364   // Print a stack trace if we signal out.
365   sys::PrintStackTraceOnErrorSignal();
366   PrettyStackTraceProgram X(argc, argv);
367   llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
368
369   StringRef ProgName(sys::path::filename(argv[0]));
370   if (argc > 1) {
371     int (*func)(int, const char *[]) = nullptr;
372
373     if (strcmp(argv[1], "merge") == 0)
374       func = merge_main;
375     else if (strcmp(argv[1], "show") == 0)
376       func = show_main;
377
378     if (func) {
379       std::string Invocation(ProgName.str() + " " + argv[1]);
380       argv[1] = Invocation.c_str();
381       return func(argc - 1, argv + 1);
382     }
383
384     if (strcmp(argv[1], "-h") == 0 ||
385         strcmp(argv[1], "-help") == 0 ||
386         strcmp(argv[1], "--help") == 0) {
387
388       errs() << "OVERVIEW: LLVM profile data tools\n\n"
389              << "USAGE: " << ProgName << " <command> [args...]\n"
390              << "USAGE: " << ProgName << " <command> -help\n\n"
391              << "Available commands: merge, show\n";
392       return 0;
393     }
394   }
395
396   if (argc < 2)
397     errs() << ProgName << ": No command specified!\n";
398   else
399     errs() << ProgName << ": Unknown command!\n";
400
401   errs() << "USAGE: " << ProgName << " <merge|show> [args...]\n";
402   return 1;
403 }