ProfileData: Introduce the InstrProfReader interface and a text reader
[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/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"
22
23 using namespace llvm;
24
25 static void exitWithError(const Twine &Message, StringRef Whence = "") {
26   errs() << "error: ";
27   if (!Whence.empty())
28     errs() << Whence << ": ";
29   errs() << Message << "\n";
30   ::exit(1);
31 }
32
33 int 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));
44
45   cl::ParseCommandLineOptions(argc, argv, "LLVM profile data merger\n");
46
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);
52
53   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
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);
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";
78     }
79     Output << "\n";
80   }
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.");
87
88   return 0;
89 }
90
91 int main(int argc, const char *argv[]) {
92   // Print a stack trace if we signal out.
93   sys::PrintStackTraceOnErrorSignal();
94   PrettyStackTraceProgram X(argc, argv);
95   llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
96
97   StringRef ProgName(sys::path::filename(argv[0]));
98   if (argc > 1) {
99     int (*func)(int, const char *[]) = 0;
100
101     if (strcmp(argv[1], "merge") == 0)
102       func = merge_main;
103
104     if (func) {
105       std::string Invocation(ProgName.str() + " " + argv[1]);
106       argv[1] = Invocation.c_str();
107       return func(argc - 1, argv + 1);
108     }
109
110     if (strcmp(argv[1], "-h") == 0 ||
111         strcmp(argv[1], "-help") == 0 ||
112         strcmp(argv[1], "--help") == 0) {
113
114       errs() << "OVERVIEW: LLVM profile data tools\n\n"
115              << "USAGE: " << ProgName << " <command> [args...]\n"
116              << "USAGE: " << ProgName << " <command> -help\n\n"
117              << "Available commands: merge\n";
118       return 0;
119     }
120   }
121
122   if (argc < 2)
123     errs() << ProgName << ": No command specified!\n";
124   else
125     errs() << ProgName << ": Unknown command!\n";
126
127   errs() << "USAGE: " << ProgName << " <merge> [args...]\n";
128   return 1;
129 }