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/Support/CommandLine.h" 16 #include "llvm/Support/LineIterator.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 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 34 //===----------------------------------------------------------------------===// 35 int 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)); 46 47 cl::ParseCommandLineOptions(argc, argv, "LLVM profile data merger\n"); 48 49 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); 55 56 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 64 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()); 71 Output << "\n"; 72 continue; 73 } 74 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()); 86 if (N1 != N2) 87 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; 114 } 115 } 116 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()); 122 123 return 0; 124 } 125 126 int 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 } 165