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