aboutsummaryrefslogtreecommitdiffstats
path: root/lib/ProfileData
diff options
context:
space:
mode:
authorStephen Hines <srhines@google.com>2014-04-23 16:57:46 -0700
committerStephen Hines <srhines@google.com>2014-04-24 15:53:16 -0700
commit36b56886974eae4f9c5ebc96befd3e7bfe5de338 (patch)
treee6cfb69fbbd937f450eeb83bfb83b9da3b01275a /lib/ProfileData
parent69a8640022b04415ae9fac62f8ab090601d8f889 (diff)
downloadexternal_llvm-36b56886974eae4f9c5ebc96befd3e7bfe5de338.zip
external_llvm-36b56886974eae4f9c5ebc96befd3e7bfe5de338.tar.gz
external_llvm-36b56886974eae4f9c5ebc96befd3e7bfe5de338.tar.bz2
Update to LLVM 3.5a.
Change-Id: Ifadecab779f128e62e430c2b4f6ddd84953ed617
Diffstat (limited to 'lib/ProfileData')
-rw-r--r--lib/ProfileData/CMakeLists.txt5
-rw-r--r--lib/ProfileData/InstrProf.cpp64
-rw-r--r--lib/ProfileData/InstrProfReader.cpp212
-rw-r--r--lib/ProfileData/InstrProfWriter.cpp60
-rw-r--r--lib/ProfileData/LLVMBuild.txt22
-rw-r--r--lib/ProfileData/Makefile14
6 files changed, 377 insertions, 0 deletions
diff --git a/lib/ProfileData/CMakeLists.txt b/lib/ProfileData/CMakeLists.txt
new file mode 100644
index 0000000..aefb16c
--- /dev/null
+++ b/lib/ProfileData/CMakeLists.txt
@@ -0,0 +1,5 @@
+add_llvm_library(LLVMProfileData
+ InstrProf.cpp
+ InstrProfReader.cpp
+ InstrProfWriter.cpp
+ )
diff --git a/lib/ProfileData/InstrProf.cpp b/lib/ProfileData/InstrProf.cpp
new file mode 100644
index 0000000..850f613
--- /dev/null
+++ b/lib/ProfileData/InstrProf.cpp
@@ -0,0 +1,64 @@
+//=-- 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::bad_header:
+ return "Invalid header";
+ 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";
+ case instrprof_error::hash_mismatch:
+ return "Function hash mismatch";
+ case instrprof_error::count_mismatch:
+ return "Function count mismatch";
+ case instrprof_error::counter_overflow:
+ return "Counter overflow";
+ }
+ 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 0000000..b07f402
--- /dev/null
+++ b/lib/ProfileData/InstrProfReader.cpp
@@ -0,0 +1,212 @@
+//=-- 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 <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;
+
+ // Create the reader.
+ if (RawInstrProfReader64::hasFormat(*Buffer))
+ Result.reset(new RawInstrProfReader64(std::move(Buffer)));
+ else if (RawInstrProfReader32::hasFormat(*Buffer))
+ Result.reset(new RawInstrProfReader32(std::move(Buffer)));
+ else
+ Result.reset(new TextInstrProfReader(std::move(Buffer)));
+
+ // Read the header and return the result.
+ return Result->readHeader();
+}
+
+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();
+}
+
+template <class IntPtrT>
+static uint64_t getRawMagic();
+
+template <>
+uint64_t getRawMagic<uint64_t>() {
+ return
+ uint64_t(255) << 56 |
+ uint64_t('l') << 48 |
+ uint64_t('p') << 40 |
+ uint64_t('r') << 32 |
+ uint64_t('o') << 24 |
+ uint64_t('f') << 16 |
+ uint64_t('r') << 8 |
+ uint64_t(129);
+}
+
+template <>
+uint64_t getRawMagic<uint32_t>() {
+ return
+ uint64_t(255) << 56 |
+ uint64_t('l') << 48 |
+ uint64_t('p') << 40 |
+ uint64_t('r') << 32 |
+ uint64_t('o') << 24 |
+ uint64_t('f') << 16 |
+ uint64_t('R') << 8 |
+ uint64_t(129);
+}
+
+template <class IntPtrT>
+bool RawInstrProfReader<IntPtrT>::hasFormat(const MemoryBuffer &DataBuffer) {
+ if (DataBuffer.getBufferSize() < sizeof(uint64_t))
+ return false;
+ uint64_t Magic =
+ *reinterpret_cast<const uint64_t *>(DataBuffer.getBufferStart());
+ return getRawMagic<IntPtrT>() == Magic ||
+ sys::SwapByteOrder(getRawMagic<IntPtrT>()) == Magic;
+}
+
+template <class IntPtrT>
+error_code RawInstrProfReader<IntPtrT>::readHeader() {
+ if (!hasFormat(*DataBuffer))
+ return error(instrprof_error::bad_magic);
+ if (DataBuffer->getBufferSize() < sizeof(RawHeader))
+ return error(instrprof_error::bad_header);
+ auto *Header =
+ reinterpret_cast<const RawHeader *>(DataBuffer->getBufferStart());
+ ShouldSwapBytes = Header->Magic != getRawMagic<IntPtrT>();
+ return readHeader(*Header);
+}
+
+static uint64_t getRawVersion() {
+ return 1;
+}
+
+template <class IntPtrT>
+error_code RawInstrProfReader<IntPtrT>::readHeader(const RawHeader &Header) {
+ if (swap(Header.Version) != getRawVersion())
+ return error(instrprof_error::unsupported_version);
+
+ CountersDelta = swap(Header.CountersDelta);
+ NamesDelta = swap(Header.NamesDelta);
+ auto DataSize = swap(Header.DataSize);
+ auto CountersSize = swap(Header.CountersSize);
+ auto NamesSize = swap(Header.NamesSize);
+
+ ptrdiff_t DataOffset = sizeof(RawHeader);
+ ptrdiff_t CountersOffset = DataOffset + sizeof(ProfileData) * DataSize;
+ ptrdiff_t NamesOffset = CountersOffset + sizeof(uint64_t) * CountersSize;
+ size_t FileSize = NamesOffset + sizeof(char) * NamesSize;
+
+ if (FileSize != DataBuffer->getBufferSize())
+ return error(instrprof_error::bad_header);
+
+ const char *Start = DataBuffer->getBufferStart();
+ Data = reinterpret_cast<const ProfileData *>(Start + DataOffset);
+ DataEnd = Data + DataSize;
+ CountersStart = reinterpret_cast<const uint64_t *>(Start + CountersOffset);
+ NamesStart = Start + NamesOffset;
+
+ return success();
+}
+
+template <class IntPtrT>
+error_code
+RawInstrProfReader<IntPtrT>::readNextRecord(InstrProfRecord &Record) {
+ if (Data == DataEnd)
+ return error(instrprof_error::eof);
+
+ // Get the raw data.
+ StringRef RawName(getName(Data->NamePtr), swap(Data->NameSize));
+ auto RawCounts = makeArrayRef(getCounter(Data->CounterPtr),
+ swap(Data->NumCounters));
+
+ // Check bounds.
+ auto *NamesStartAsCounter = reinterpret_cast<const uint64_t *>(NamesStart);
+ if (RawName.data() < NamesStart ||
+ RawName.data() + RawName.size() > DataBuffer->getBufferEnd() ||
+ RawCounts.data() < CountersStart ||
+ RawCounts.data() + RawCounts.size() > NamesStartAsCounter)
+ return error(instrprof_error::malformed);
+
+ // Store the data in Record, byte-swapping as necessary.
+ Record.Hash = swap(Data->FuncHash);
+ Record.Name = RawName;
+ if (ShouldSwapBytes) {
+ Counts.clear();
+ Counts.reserve(RawCounts.size());
+ for (uint64_t Count : RawCounts)
+ Counts.push_back(swap(Count));
+ Record.Counts = Counts;
+ } else
+ Record.Counts = RawCounts;
+
+ // Iterate.
+ ++Data;
+ return success();
+}
+
+namespace llvm {
+template class RawInstrProfReader<uint32_t>;
+template class RawInstrProfReader<uint64_t>;
+}
diff --git a/lib/ProfileData/InstrProfWriter.cpp b/lib/ProfileData/InstrProfWriter.cpp
new file mode 100644
index 0000000..3024f96
--- /dev/null
+++ b/lib/ProfileData/InstrProfWriter.cpp
@@ -0,0 +1,60 @@
+//=-- InstrProfWriter.cpp - Instrumented profiling writer -------------------=//
+//
+// 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 writing profiling data for clang's
+// instrumentation based PGO and coverage.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ProfileData/InstrProfWriter.h"
+#include "llvm/Support/Endian.h"
+
+using namespace llvm;
+
+error_code InstrProfWriter::addFunctionCounts(StringRef FunctionName,
+ uint64_t FunctionHash,
+ ArrayRef<uint64_t> Counters) {
+ auto Where = FunctionData.find(FunctionName);
+ if (Where == FunctionData.end()) {
+ // If this is the first time we've seen this function, just add it.
+ auto &Data = FunctionData[FunctionName];
+ Data.Hash = FunctionHash;
+ Data.Counts = Counters;
+ return instrprof_error::success;;
+ }
+
+ auto &Data = Where->getValue();
+ // We can only add to existing functions if they match, so we check the hash
+ // and number of counters.
+ if (Data.Hash != FunctionHash)
+ return instrprof_error::hash_mismatch;
+ if (Data.Counts.size() != Counters.size())
+ return instrprof_error::count_mismatch;
+ // These match, add up the counters.
+ for (size_t I = 0, E = Counters.size(); I < E; ++I) {
+ if (Data.Counts[I] + Counters[I] < Data.Counts[I])
+ return instrprof_error::counter_overflow;
+ Data.Counts[I] += Counters[I];
+ }
+ return instrprof_error::success;
+}
+
+void InstrProfWriter::write(raw_ostream &OS) {
+ // Write out the counts for each function.
+ for (const auto &I : FunctionData) {
+ StringRef Name = I.getKey();
+ uint64_t Hash = I.getValue().Hash;
+ const std::vector<uint64_t> &Counts = I.getValue().Counts;
+
+ OS << Name << "\n" << Hash << "\n" << Counts.size() << "\n";
+ for (uint64_t Count : Counts)
+ OS << Count << "\n";
+ OS << "\n";
+ }
+}
diff --git a/lib/ProfileData/LLVMBuild.txt b/lib/ProfileData/LLVMBuild.txt
new file mode 100644
index 0000000..0a8cbe3
--- /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 0000000..2674361
--- /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