blob: d8abafc33c20f7937adb35ef42b137394a7c011f [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"
15#include "llvm/Support/CommandLine.h"
Justin Bogner38fff862014-03-19 02:20:42 +000016#include "llvm/Support/LineIterator.h"
Duncan P. N. Exon Smith846a6272014-02-17 23:22:49 +000017#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
Duncan P. N. Exon Smith846a6272014-02-17 23:22:49 +000025static void exitWithError(const std::string &Message,
26 const std::string &Filename, int64_t Line = -1) {
27 errs() << "error: " << Filename;
28 if (Line >= 0)
29 errs() << ":" << Line;
30 errs() << ": " << Message << "\n";
31 ::exit(1);
32}
33
Justin Bognerec49f982014-03-12 22:00:57 +000034//===----------------------------------------------------------------------===//
Justin Bogner618bcea2014-03-19 02:20:46 +000035int merge_main(int argc, const char *argv[]) {
36 cl::opt<std::string> Filename1(cl::Positional, cl::Required,
37 cl::desc("file1"));
38 cl::opt<std::string> Filename2(cl::Positional, cl::Required,
39 cl::desc("file2"));
40
41 cl::opt<std::string> OutputFilename("output", cl::value_desc("output"),
42 cl::init("-"),
43 cl::desc("Output file"));
44 cl::alias OutputFilenameA("o", cl::desc("Alias for --output"),
45 cl::aliasopt(OutputFilename));
Justin Bognerbfee8d42014-03-12 20:14:17 +000046
Justin Bognerec49f982014-03-12 22:00:57 +000047 cl::ParseCommandLineOptions(argc, argv, "LLVM profile data merger\n");
Justin Bognerbfee8d42014-03-12 20:14:17 +000048
Justin Bognerec49f982014-03-12 22:00:57 +000049 std::unique_ptr<MemoryBuffer> File1;
50 std::unique_ptr<MemoryBuffer> File2;
51 if (error_code ec = MemoryBuffer::getFile(Filename1, File1))
52 exitWithError(ec.message(), Filename1);
53 if (error_code ec = MemoryBuffer::getFile(Filename2, File2))
54 exitWithError(ec.message(), Filename2);
Justin Bognerbfee8d42014-03-12 20:14:17 +000055
Justin Bognerec49f982014-03-12 22:00:57 +000056 if (OutputFilename.empty())
57 OutputFilename = "-";
58
59 std::string ErrorInfo;
60 raw_fd_ostream Output(OutputFilename.data(), ErrorInfo, sys::fs::F_Text);
61 if (!ErrorInfo.empty())
62 exitWithError(ErrorInfo, OutputFilename);
63
Justin Bogner38fff862014-03-19 02:20:42 +000064 enum {ReadName, ReadHash, ReadCount, ReadCounters} State = ReadName;
65 uint64_t N1, N2, NumCounters;
66 line_iterator I1(*File1, '#'), I2(*File2, '#');
67 for (; !I1.is_at_end() && !I2.is_at_end(); ++I1, ++I2) {
68 if (I1->empty()) {
69 if (!I2->empty())
70 exitWithError("data mismatch", Filename2, I2.line_number());
Justin Bognerec49f982014-03-12 22:00:57 +000071 Output << "\n";
72 continue;
Justin Bognerbfee8d42014-03-12 20:14:17 +000073 }
Justin Bogner38fff862014-03-19 02:20:42 +000074 switch (State) {
75 case ReadName:
76 if (*I1 != *I2)
77 exitWithError("function name mismatch", Filename2, I2.line_number());
78 Output << *I1 << "\n";
79 State = ReadHash;
80 break;
81 case ReadHash:
82 if (I1->getAsInteger(10, N1))
83 exitWithError("bad function hash", Filename1, I1.line_number());
84 if (I2->getAsInteger(10, N2))
85 exitWithError("bad function hash", Filename2, I2.line_number());
Justin Bognerec49f982014-03-12 22:00:57 +000086 if (N1 != N2)
Justin Bogner38fff862014-03-19 02:20:42 +000087 exitWithError("function hash mismatch", Filename2, I2.line_number());
88 Output << N1 << "\n";
89 State = ReadCount;
90 break;
91 case ReadCount:
92 if (I1->getAsInteger(10, N1))
93 exitWithError("bad function count", Filename1, I1.line_number());
94 if (I2->getAsInteger(10, N2))
95 exitWithError("bad function count", Filename2, I2.line_number());
96 if (N1 != N2)
97 exitWithError("function count mismatch", Filename2, I2.line_number());
98 Output << N1 << "\n";
99 NumCounters = N1;
100 State = ReadCounters;
101 break;
102 case ReadCounters:
103 if (I1->getAsInteger(10, N1))
104 exitWithError("invalid counter", Filename1, I1.line_number());
105 if (I2->getAsInteger(10, N2))
106 exitWithError("invalid counter", Filename2, I2.line_number());
107 uint64_t Sum = N1 + N2;
108 if (Sum < N1)
109 exitWithError("counter overflow", Filename2, I2.line_number());
110 Output << N1 + N2 << "\n";
111 if (--NumCounters == 0)
112 State = ReadName;
113 break;
Justin Bognerbfee8d42014-03-12 20:14:17 +0000114 }
115 }
Justin Bogner38fff862014-03-19 02:20:42 +0000116 if (!I1.is_at_end())
117 exitWithError("truncated file", Filename1, I1.line_number());
118 if (!I2.is_at_end())
119 exitWithError("truncated file", Filename2, I2.line_number());
120 if (State != ReadName)
121 exitWithError("truncated file", Filename1, I1.line_number());
Justin Bognerbfee8d42014-03-12 20:14:17 +0000122
Justin Bognerec49f982014-03-12 22:00:57 +0000123 return 0;
Justin Bognerbfee8d42014-03-12 20:14:17 +0000124}
Justin Bogner618bcea2014-03-19 02:20:46 +0000125
126int main(int argc, const char *argv[]) {
127 // Print a stack trace if we signal out.
128 sys::PrintStackTraceOnErrorSignal();
129 PrettyStackTraceProgram X(argc, argv);
130 llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
131
132 StringRef ProgName(sys::path::filename(argv[0]));
133 if (argc > 1) {
134 int (*func)(int, const char *[]) = 0;
135
136 if (strcmp(argv[1], "merge") == 0)
137 func = merge_main;
138
139 if (func) {
140 std::string Invocation(ProgName.str() + " " + argv[1]);
141 argv[1] = Invocation.c_str();
142 return func(argc - 1, argv + 1);
143 }
144
145 if (strcmp(argv[1], "-h") == 0 ||
146 strcmp(argv[1], "-help") == 0 ||
147 strcmp(argv[1], "--help") == 0) {
148
149 errs() << "OVERVIEW: LLVM profile data tools\n\n"
150 << "USAGE: " << ProgName << " <command> [args...]\n"
151 << "USAGE: " << ProgName << " <command> -help\n\n"
152 << "Available commands: merge\n";
153 return 0;
154 }
155 }
156
157 if (argc < 2)
158 errs() << ProgName << ": No command specified!\n";
159 else
160 errs() << ProgName << ": Unknown command!\n";
161
162 errs() << "USAGE: " << ProgName << " <merge|show|generate> [args...]\n";
163 return 1;
164}