diff options
author | Stephen Hines <srhines@google.com> | 2014-04-23 16:57:46 -0700 |
---|---|---|
committer | Stephen Hines <srhines@google.com> | 2014-04-24 15:53:16 -0700 |
commit | 36b56886974eae4f9c5ebc96befd3e7bfe5de338 (patch) | |
tree | e6cfb69fbbd937f450eeb83bfb83b9da3b01275a /lib/ProfileData | |
parent | 69a8640022b04415ae9fac62f8ab090601d8f889 (diff) | |
download | external_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.txt | 5 | ||||
-rw-r--r-- | lib/ProfileData/InstrProf.cpp | 64 | ||||
-rw-r--r-- | lib/ProfileData/InstrProfReader.cpp | 212 | ||||
-rw-r--r-- | lib/ProfileData/InstrProfWriter.cpp | 60 | ||||
-rw-r--r-- | lib/ProfileData/LLVMBuild.txt | 22 | ||||
-rw-r--r-- | lib/ProfileData/Makefile | 14 |
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 |