summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/llvm/ProfileData/InstrProf.h52
-rw-r--r--include/llvm/ProfileData/InstrProfReader.h119
-rw-r--r--lib/CMakeLists.txt1
-rw-r--r--lib/LLVMBuild.txt2
-rw-r--r--lib/Makefile2
-rw-r--r--lib/ProfileData/CMakeLists.txt7
-rw-r--r--lib/ProfileData/InstrProf.cpp56
-rw-r--r--lib/ProfileData/InstrProfReader.cpp84
-rw-r--r--lib/ProfileData/LLVMBuild.txt22
-rw-r--r--lib/ProfileData/Makefile14
-rw-r--r--test/tools/llvm-profdata/errors.test12
-rw-r--r--tools/llvm-profdata/CMakeLists.txt2
-rw-r--r--tools/llvm-profdata/LLVMBuild.txt2
-rw-r--r--tools/llvm-profdata/Makefile2
-rw-r--r--tools/llvm-profdata/llvm-profdata.cpp102
15 files changed, 400 insertions, 79 deletions
diff --git a/include/llvm/ProfileData/InstrProf.h b/include/llvm/ProfileData/InstrProf.h
new file mode 100644
index 0000000000..21cc170065
--- /dev/null
+++ b/include/llvm/ProfileData/InstrProf.h
@@ -0,0 +1,52 @@
+//=-- InstrProf.h - Instrumented profiling format support ---------*- C++ -*-=//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Instrumentation-based profiling data is generated by instrumented
+// binaries through library functions in compiler-rt, and read by the clang
+// frontend to feed PGO.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_PROFILEDATA_INSTRPROF_H__
+#define LLVM_PROFILEDATA_INSTRPROF_H__
+
+#include "llvm/Support/system_error.h"
+
+namespace llvm {
+
+const error_category &instrprof_category();
+
+struct instrprof_error {
+ enum ErrorType {
+ success = 0,
+ eof,
+ bad_magic,
+ unsupported_version,
+ too_large,
+ truncated,
+ malformed,
+ unknown_function
+ };
+ ErrorType V;
+
+ instrprof_error(ErrorType V) : V(V) {}
+ operator ErrorType() const { return V; }
+};
+
+inline error_code make_error_code(instrprof_error E) {
+ return error_code(static_cast<int>(E), instrprof_category());
+}
+
+template <> struct is_error_code_enum<instrprof_error> : std::true_type {};
+template <> struct is_error_code_enum<instrprof_error::ErrorType>
+ : std::true_type {};
+
+} // end namespace llvm
+
+#endif // LLVM_PROFILEDATA_INSTRPROF_H__
diff --git a/include/llvm/ProfileData/InstrProfReader.h b/include/llvm/ProfileData/InstrProfReader.h
new file mode 100644
index 0000000000..a45318b0a9
--- /dev/null
+++ b/include/llvm/ProfileData/InstrProfReader.h
@@ -0,0 +1,119 @@
+//=-- InstrProfReader.h - Instrumented profiling readers ----------*- C++ -*-=//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains support for reading profiling data for instrumentation
+// based PGO and coverage.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_PROFILEDATA_INSTRPROF_READER_H__
+#define LLVM_PROFILEDATA_INSTRPROF_READER_H__
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ProfileData/InstrProf.h"
+#include "llvm/Support/LineIterator.h"
+#include "llvm/Support/MemoryBuffer.h"
+
+#include <iterator>
+
+namespace llvm {
+
+class InstrProfReader;
+
+/// Profiling information for a single function.
+struct InstrProfRecord {
+ StringRef Name;
+ uint64_t Hash;
+ ArrayRef<uint64_t> Counts;
+};
+
+/// A file format agnostic iterator over profiling data.
+class InstrProfIterator : public std::iterator<std::input_iterator_tag,
+ InstrProfRecord> {
+ InstrProfReader *Reader;
+ InstrProfRecord Record;
+
+ void Increment();
+public:
+ InstrProfIterator() : Reader(nullptr) {}
+ InstrProfIterator(InstrProfReader *Reader) : Reader(Reader) { Increment(); }
+
+ InstrProfIterator &operator++() { Increment(); return *this; }
+ bool operator==(const InstrProfIterator &RHS) { return Reader == RHS.Reader; }
+ bool operator!=(const InstrProfIterator &RHS) { return Reader != RHS.Reader; }
+ InstrProfRecord &operator*() { return Record; }
+ InstrProfRecord *operator->() { return &Record; }
+};
+
+/// Base class and interface for reading profiling data of any known instrprof
+/// format. Provides an iterator over InstrProfRecords.
+class InstrProfReader {
+ error_code LastError;
+public:
+ InstrProfReader() : LastError(instrprof_error::success) {}
+ virtual ~InstrProfReader() {}
+
+ /// Read a single record.
+ virtual error_code readNextRecord(InstrProfRecord &Record) = 0;
+ /// Iterator over profile data.
+ InstrProfIterator begin() { return InstrProfIterator(this); }
+ InstrProfIterator end() { return InstrProfIterator(); }
+
+ /// Set the current error_code and return same.
+ error_code error(error_code EC) {
+ LastError = EC;
+ return EC;
+ }
+ /// Clear the current error code and return a successful one.
+ error_code success() { return error(instrprof_error::success); }
+
+ /// Return true if the reader has finished reading the profile data.
+ bool isEOF() { return LastError == instrprof_error::eof; }
+ /// Return true if the reader encountered an error reading profiling data.
+ bool hasError() { return LastError && !isEOF(); }
+ /// Get the current error code.
+ error_code getError() { return LastError; }
+
+ /// Factory method to create an appropriately typed reader for the given
+ /// instrprof file.
+ static error_code create(std::string Path,
+ std::unique_ptr<InstrProfReader> &Result);
+};
+
+/// Reader for the simple text based instrprof format.
+///
+/// This format is a simple text format that's suitable for test data. Records
+/// are separated by one or more blank lines, and record fields are separated by
+/// new lines.
+///
+/// Each record consists of a function name, a function hash, a number of
+/// counters, and then each counter value, in that order.
+class TextInstrProfReader : public InstrProfReader {
+private:
+ /// The profile data file contents.
+ std::unique_ptr<MemoryBuffer> DataBuffer;
+ /// Iterator over the profile data.
+ line_iterator Line;
+ /// The current set of counter values.
+ std::vector<uint64_t> Counts;
+
+ TextInstrProfReader(const TextInstrProfReader &) LLVM_DELETED_FUNCTION;
+ TextInstrProfReader &operator=(const TextInstrProfReader &)
+ LLVM_DELETED_FUNCTION;
+public:
+ TextInstrProfReader(std::unique_ptr<MemoryBuffer> &DataBuffer_)
+ : DataBuffer(DataBuffer_.release()), Line(*DataBuffer, '#') {}
+
+ /// Read a single record.
+ error_code readNextRecord(InstrProfRecord &Record) override;
+};
+
+} // end namespace llvm
+
+#endif // LLVM_PROFILEDATA_INSTRPROF_READER_H__
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index 9367f55313..fab1c8747b 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -16,3 +16,4 @@ add_subdirectory(ExecutionEngine)
add_subdirectory(Target)
add_subdirectory(AsmParser)
add_subdirectory(LineEditor)
+add_subdirectory(ProfileData)
diff --git a/lib/LLVMBuild.txt b/lib/LLVMBuild.txt
index a0984d410c..ad5b22b914 100644
--- a/lib/LLVMBuild.txt
+++ b/lib/LLVMBuild.txt
@@ -16,7 +16,7 @@
;===------------------------------------------------------------------------===;
[common]
-subdirectories = Analysis AsmParser Bitcode CodeGen DebugInfo ExecutionEngine LineEditor Linker IR IRReader LTO MC Object Option Support TableGen Target Transforms
+subdirectories = Analysis AsmParser Bitcode CodeGen DebugInfo ExecutionEngine LineEditor Linker IR IRReader LTO MC Object Option ProfileData Support TableGen Target Transforms
[component_0]
type = Group
diff --git a/lib/Makefile b/lib/Makefile
index a97f71aded..0ddf917599 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -12,6 +12,6 @@ include $(LEVEL)/Makefile.config
PARALLEL_DIRS := IR AsmParser Bitcode Analysis Transforms CodeGen Target \
ExecutionEngine Linker LTO MC Object Option DebugInfo \
- IRReader LineEditor
+ IRReader LineEditor ProfileData
include $(LEVEL)/Makefile.common
diff --git a/lib/ProfileData/CMakeLists.txt b/lib/ProfileData/CMakeLists.txt
new file mode 100644
index 0000000000..cef3a5336b
--- /dev/null
+++ b/lib/ProfileData/CMakeLists.txt
@@ -0,0 +1,7 @@
+add_llvm_library(LLVMProfileData
+ InstrProf.cpp
+ InstrProfReader.cpp
+
+ LINK_LIBS
+ LLVMSupport
+)
diff --git a/lib/ProfileData/InstrProf.cpp b/lib/ProfileData/InstrProf.cpp
new file mode 100644
index 0000000000..329abf84e6
--- /dev/null
+++ b/lib/ProfileData/InstrProf.cpp
@@ -0,0 +1,56 @@
+//=-- InstrProf.cpp - Instrumented profiling format support -----------------=//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains support for clang's instrumentation based PGO and
+// coverage.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ProfileData/InstrProf.h"
+#include "llvm/Support/ErrorHandling.h"
+
+using namespace llvm;
+
+namespace {
+class InstrProfErrorCategoryType : public error_category {
+ const char *name() const override { return "llvm.instrprof"; }
+ std::string message(int IE) const override {
+ instrprof_error::ErrorType E = static_cast<instrprof_error::ErrorType>(IE);
+ switch (E) {
+ case instrprof_error::success:
+ return "Success";
+ case instrprof_error::eof:
+ return "End of File";
+ case instrprof_error::bad_magic:
+ return "Invalid file format (bad magic)";
+ case instrprof_error::unsupported_version:
+ return "Unsupported format version";
+ case instrprof_error::too_large:
+ return "Too much profile data";
+ case instrprof_error::truncated:
+ return "Truncated profile data";
+ case instrprof_error::malformed:
+ return "Malformed profile data";
+ case instrprof_error::unknown_function:
+ return "No profile data available for function";
+ }
+ llvm_unreachable("A value of instrprof_error has no message.");
+ }
+ error_condition default_error_condition(int EV) const {
+ if (EV == instrprof_error::success)
+ return errc::success;
+ return errc::invalid_argument;
+ }
+};
+}
+
+const error_category &llvm::instrprof_category() {
+ static InstrProfErrorCategoryType C;
+ return C;
+}
diff --git a/lib/ProfileData/InstrProfReader.cpp b/lib/ProfileData/InstrProfReader.cpp
new file mode 100644
index 0000000000..8b3600090b
--- /dev/null
+++ b/lib/ProfileData/InstrProfReader.cpp
@@ -0,0 +1,84 @@
+//=-- InstrProfReader.cpp - Instrumented profiling reader -------------------=//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains support for reading profiling data for clang's
+// instrumentation based PGO and coverage.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ProfileData/InstrProfReader.h"
+#include "llvm/ProfileData/InstrProf.h"
+#include "llvm/Support/Endian.h"
+
+#include <cassert>
+
+using namespace llvm;
+
+error_code InstrProfReader::create(std::string Path,
+ std::unique_ptr<InstrProfReader> &Result) {
+ std::unique_ptr<MemoryBuffer> Buffer;
+ if (error_code EC = MemoryBuffer::getFileOrSTDIN(Path, Buffer))
+ return EC;
+
+ // Sanity check the file.
+ if (Buffer->getBufferSize() > std::numeric_limits<unsigned>::max())
+ return instrprof_error::too_large;
+
+ // FIXME: This needs to determine which format the file is and construct the
+ // correct subclass.
+ Result.reset(new TextInstrProfReader(Buffer));
+
+ return instrprof_error::success;
+}
+
+void InstrProfIterator::Increment() {
+ if (Reader->readNextRecord(Record))
+ *this = InstrProfIterator();
+}
+
+error_code TextInstrProfReader::readNextRecord(InstrProfRecord &Record) {
+ // Skip empty lines.
+ while (!Line.is_at_end() && Line->empty())
+ ++Line;
+ // If we hit EOF while looking for a name, we're done.
+ if (Line.is_at_end())
+ return error(instrprof_error::eof);
+
+ // Read the function name.
+ Record.Name = *Line++;
+
+ // Read the function hash.
+ if (Line.is_at_end())
+ return error(instrprof_error::truncated);
+ if ((Line++)->getAsInteger(10, Record.Hash))
+ return error(instrprof_error::malformed);
+
+ // Read the number of counters.
+ uint64_t NumCounters;
+ if (Line.is_at_end())
+ return error(instrprof_error::truncated);
+ if ((Line++)->getAsInteger(10, NumCounters))
+ return error(instrprof_error::malformed);
+
+ // Read each counter and fill our internal storage with the values.
+ Counts.clear();
+ Counts.reserve(NumCounters);
+ for (uint64_t I = 0; I < NumCounters; ++I) {
+ if (Line.is_at_end())
+ return error(instrprof_error::truncated);
+ uint64_t Count;
+ if ((Line++)->getAsInteger(10, Count))
+ return error(instrprof_error::malformed);
+ Counts.push_back(Count);
+ }
+ // Give the record a reference to our internal counter storage.
+ Record.Counts = Counts;
+
+ return success();
+}
diff --git a/lib/ProfileData/LLVMBuild.txt b/lib/ProfileData/LLVMBuild.txt
new file mode 100644
index 0000000000..0a8cbe3363
--- /dev/null
+++ b/lib/ProfileData/LLVMBuild.txt
@@ -0,0 +1,22 @@
+;===- ./lib/ProfileData/LLVMBuild.txt --------------------------*- Conf -*--===;
+;
+; The LLVM Compiler Infrastructure
+;
+; This file is distributed under the University of Illinois Open Source
+; License. See LICENSE.TXT for details.
+;
+;===------------------------------------------------------------------------===;
+;
+; This is an LLVMBuild description file for the components in this subdirectory.
+;
+; For more information on the LLVMBuild system, please see:
+;
+; http://llvm.org/docs/LLVMBuild.html
+;
+;===------------------------------------------------------------------------===;
+
+[component_0]
+type = Library
+name = ProfileData
+parent = Libraries
+required_libraries = Support
diff --git a/lib/ProfileData/Makefile b/lib/ProfileData/Makefile
new file mode 100644
index 0000000000..26743612d3
--- /dev/null
+++ b/lib/ProfileData/Makefile
@@ -0,0 +1,14 @@
+##===- lib/ProfileData/Makefile ----------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LEVEL = ../..
+LIBRARYNAME = LLVMProfileData
+BUILD_ARCHIVE := 1
+
+include $(LEVEL)/Makefile.common
diff --git a/test/tools/llvm-profdata/errors.test b/test/tools/llvm-profdata/errors.test
index 219d88dd41..afac7a4dec 100644
--- a/test/tools/llvm-profdata/errors.test
+++ b/test/tools/llvm-profdata/errors.test
@@ -1,19 +1,19 @@
RUN: not llvm-profdata merge %p/Inputs/empty.profdata %p/Inputs/foo3-1.profdata 2>&1 | FileCheck %s --check-prefix=LENGTH
RUN: not llvm-profdata merge %p/Inputs/foo3-1.profdata %p/Inputs/foo3bar3-1.profdata 2>&1 | FileCheck %s --check-prefix=LENGTH
RUN: not llvm-profdata merge %p/Inputs/foo4-1.profdata %p/Inputs/empty.profdata 2>&1 | FileCheck %s --check-prefix=LENGTH
-LENGTH: error: {{.*}}: truncated file
+LENGTH: error: Number of instrumented functions differ
RUN: not llvm-profdata merge %p/Inputs/foo3-1.profdata %p/Inputs/bar3-1.profdata 2>&1 | FileCheck %s --check-prefix=NAME
-NAME: error: {{.*}}: function name mismatch
+NAME: error: Function name mismatch, foo != bar
RUN: not llvm-profdata merge %p/Inputs/foo3-1.profdata %p/Inputs/foo4-1.profdata 2>&1 | FileCheck %s --check-prefix=HASH
-HASH: error: {{.*}}: function hash mismatch
+HASH: error: Function hash mismatch for foo
RUN: not llvm-profdata merge %p/Inputs/overflow.profdata %p/Inputs/overflow.profdata 2>&1 | FileCheck %s --check-prefix=OVERFLOW
-OVERFLOW: error: {{.*}}: counter overflow
+OVERFLOW: error: Counter overflow for overflow
RUN: not llvm-profdata merge %p/Inputs/invalid-count-later.profdata %p/Inputs/invalid-count-later.profdata 2>&1 | FileCheck %s --check-prefix=INVALID-COUNT-LATER
-INVALID-COUNT-LATER: error: {{.*}}: invalid counter
+INVALID-COUNT-LATER: error: {{.*}}: Malformed profile data
RUN: not llvm-profdata merge %p/Inputs/bad-hash.profdata %p/Inputs/bad-hash.profdata 2>&1 | FileCheck %s --check-prefix=BAD-HASH
-BAD-HASH: error: {{.*}}: bad function hash
+BAD-HASH: error: {{.*}}: Malformed profile data
diff --git a/tools/llvm-profdata/CMakeLists.txt b/tools/llvm-profdata/CMakeLists.txt
index 4b1357d87e..4c64cfa1fa 100644
--- a/tools/llvm-profdata/CMakeLists.txt
+++ b/tools/llvm-profdata/CMakeLists.txt
@@ -1,4 +1,4 @@
-set(LLVM_LINK_COMPONENTS core support )
+set(LLVM_LINK_COMPONENTS core profiledata support )
add_llvm_tool(llvm-profdata
llvm-profdata.cpp
diff --git a/tools/llvm-profdata/LLVMBuild.txt b/tools/llvm-profdata/LLVMBuild.txt
index fc9e469199..bbc1ea6fce 100644
--- a/tools/llvm-profdata/LLVMBuild.txt
+++ b/tools/llvm-profdata/LLVMBuild.txt
@@ -19,4 +19,4 @@
type = Tool
name = llvm-profdata
parent = Tools
-required_libraries = Support
+required_libraries = ProfileData Support
diff --git a/tools/llvm-profdata/Makefile b/tools/llvm-profdata/Makefile
index 9d7ad527b1..4177780d6c 100644
--- a/tools/llvm-profdata/Makefile
+++ b/tools/llvm-profdata/Makefile
@@ -9,7 +9,7 @@
LEVEL := ../..
TOOLNAME := llvm-profdata
-LINK_COMPONENTS := core support
+LINK_COMPONENTS := core profiledata support
# This tool has no plugins, optimize startup time.
TOOL_NO_EXPORTS := 1
diff --git a/tools/llvm-profdata/llvm-profdata.cpp b/tools/llvm-profdata/llvm-profdata.cpp
index 47e2131135..53dcf1602c 100644
--- a/tools/llvm-profdata/llvm-profdata.cpp
+++ b/tools/llvm-profdata/llvm-profdata.cpp
@@ -12,8 +12,8 @@
//===----------------------------------------------------------------------===//
#include "llvm/ADT/StringRef.h"
+#include "llvm/ProfileData/InstrProfReader.h"
#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/LineIterator.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/PrettyStackTrace.h"
@@ -22,12 +22,11 @@
using namespace llvm;
-static void exitWithError(const std::string &Message,
- const std::string &Filename, int64_t Line = -1) {
- errs() << "error: " << Filename;
- if (Line >= 0)
- errs() << ":" << Line;
- errs() << ": " << Message << "\n";
+static void exitWithError(const Twine &Message, StringRef Whence = "") {
+ errs() << "error: ";
+ if (!Whence.empty())
+ errs() << Whence << ": ";
+ errs() << Message << "\n";
::exit(1);
}
@@ -45,11 +44,10 @@ int merge_main(int argc, const char *argv[]) {
cl::ParseCommandLineOptions(argc, argv, "LLVM profile data merger\n");
- std::unique_ptr<MemoryBuffer> File1;
- std::unique_ptr<MemoryBuffer> File2;
- if (error_code ec = MemoryBuffer::getFile(Filename1, File1))
+ std::unique_ptr<InstrProfReader> Reader1, Reader2;
+ if (error_code ec = InstrProfReader::create(Filename1, Reader1))
exitWithError(ec.message(), Filename1);
- if (error_code ec = MemoryBuffer::getFile(Filename2, File2))
+ if (error_code ec = InstrProfReader::create(Filename2, Reader2))
exitWithError(ec.message(), Filename2);
if (OutputFilename.empty())
@@ -60,64 +58,32 @@ int merge_main(int argc, const char *argv[]) {
if (!ErrorInfo.empty())
exitWithError(ErrorInfo, OutputFilename);
- enum {ReadName, ReadHash, ReadCount, ReadCounters} State = ReadName;
- uint64_t N1, N2, NumCounters;
- line_iterator I1(*File1, '#'), I2(*File2, '#');
- for (; !I1.is_at_end() && !I2.is_at_end(); ++I1, ++I2) {
- if (I1->empty()) {
- if (!I2->empty())
- exitWithError("data mismatch", Filename2, I2.line_number());
- Output << "\n";
- continue;
- }
- switch (State) {
- case ReadName:
- if (*I1 != *I2)
- exitWithError("function name mismatch", Filename2, I2.line_number());
- Output << *I1 << "\n";
- State = ReadHash;
- break;
- case ReadHash:
- if (I1->getAsInteger(10, N1))
- exitWithError("bad function hash", Filename1, I1.line_number());
- if (I2->getAsInteger(10, N2))
- exitWithError("bad function hash", Filename2, I2.line_number());
- if (N1 != N2)
- exitWithError("function hash mismatch", Filename2, I2.line_number());
- Output << N1 << "\n";
- State = ReadCount;
- break;
- case ReadCount:
- if (I1->getAsInteger(10, N1))
- exitWithError("bad function count", Filename1, I1.line_number());
- if (I2->getAsInteger(10, N2))
- exitWithError("bad function count", Filename2, I2.line_number());
- if (N1 != N2)
- exitWithError("function count mismatch", Filename2, I2.line_number());
- Output << N1 << "\n";
- NumCounters = N1;
- State = ReadCounters;
- break;
- case ReadCounters:
- if (I1->getAsInteger(10, N1))
- exitWithError("invalid counter", Filename1, I1.line_number());
- if (I2->getAsInteger(10, N2))
- exitWithError("invalid counter", Filename2, I2.line_number());
- uint64_t Sum = N1 + N2;
- if (Sum < N1)
- exitWithError("counter overflow", Filename2, I2.line_number());
- Output << N1 + N2 << "\n";
- if (--NumCounters == 0)
- State = ReadName;
- break;
+ for (InstrProfIterator I1 = Reader1->begin(), E1 = Reader1->end(),
+ I2 = Reader2->begin(), E2 = Reader2->end();
+ I1 != E1 && I2 != E2; ++I1, ++I2) {
+ if (I1->Name != I2->Name)
+ exitWithError("Function name mismatch, " + I1->Name + " != " + I2->Name);
+ if (I1->Hash != I2->Hash)
+ exitWithError("Function hash mismatch for " + I1->Name);
+ if (I1->Counts.size() != I2->Counts.size())
+ exitWithError("Function count mismatch for " + I1->Name);
+
+ Output << I1->Name << "\n" << I1->Hash << "\n" << I1->Counts.size() << "\n";
+
+ for (size_t II = 0, EE = I1->Counts.size(); II < EE; ++II) {
+ uint64_t Sum = I1->Counts[II] + I2->Counts[II];
+ if (Sum < I1->Counts[II])
+ exitWithError("Counter overflow for " + I1->Name);
+ Output << Sum << "\n";
}
+ Output << "\n";
}
- if (!I1.is_at_end())
- exitWithError("truncated file", Filename1, I1.line_number());
- if (!I2.is_at_end())
- exitWithError("truncated file", Filename2, I2.line_number());
- if (State != ReadName)
- exitWithError("truncated file", Filename1, I1.line_number());
+ if (Reader1->hasError())
+ exitWithError(Reader1->getError().message(), Filename1);
+ if (Reader2->hasError())
+ exitWithError(Reader2->getError().message(), Filename2);
+ if (!Reader1->isEOF() || !Reader2->isEOF())
+ exitWithError("Number of instrumented functions differ.");
return 0;
}
@@ -158,6 +124,6 @@ int main(int argc, const char *argv[]) {
else
errs() << ProgName << ": Unknown command!\n";
- errs() << "USAGE: " << ProgName << " <merge|show|generate> [args...]\n";
+ errs() << "USAGE: " << ProgName << " <merge> [args...]\n";
return 1;
}