aboutsummaryrefslogtreecommitdiff
path: root/include/llvm/ProfileData
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2015-12-30 11:46:15 +0000
committerDimitry Andric <dim@FreeBSD.org>2015-12-30 11:46:15 +0000
commitdd58ef019b700900793a1eb48b52123db01b654e (patch)
treefcfbb4df56a744f4ddc6122c50521dd3f1c5e196 /include/llvm/ProfileData
parent2fe5752e3a7c345cdb59e869278d36af33c13fa4 (diff)
Notes
Diffstat (limited to 'include/llvm/ProfileData')
-rw-r--r--include/llvm/ProfileData/CoverageMapping.h6
-rw-r--r--include/llvm/ProfileData/InstrProf.h552
-rw-r--r--include/llvm/ProfileData/InstrProfData.inc735
-rw-r--r--include/llvm/ProfileData/InstrProfReader.h175
-rw-r--r--include/llvm/ProfileData/InstrProfWriter.h23
-rw-r--r--include/llvm/ProfileData/SampleProf.h301
-rw-r--r--include/llvm/ProfileData/SampleProfReader.h245
-rw-r--r--include/llvm/ProfileData/SampleProfWriter.h114
8 files changed, 1965 insertions, 186 deletions
diff --git a/include/llvm/ProfileData/CoverageMapping.h b/include/llvm/ProfileData/CoverageMapping.h
index 3488e793d84fb..3790e1358449c 100644
--- a/include/llvm/ProfileData/CoverageMapping.h
+++ b/include/llvm/ProfileData/CoverageMapping.h
@@ -104,7 +104,7 @@ struct CounterExpression {
};
/// \brief A Counter expression builder is used to construct the
-/// counter expressions. It avoids unecessary duplication
+/// counter expressions. It avoids unnecessary duplication
/// and simplifies algebraic expressions.
class CounterExpressionBuilder {
/// \brief A list of all the counter expressions
@@ -236,7 +236,7 @@ class CounterMappingContext {
public:
CounterMappingContext(ArrayRef<CounterExpression> Expressions,
- ArrayRef<uint64_t> CounterValues = ArrayRef<uint64_t>())
+ ArrayRef<uint64_t> CounterValues = None)
: Expressions(Expressions), CounterValues(CounterValues) {}
void setCounts(ArrayRef<uint64_t> Counts) { CounterValues = Counts; }
@@ -443,7 +443,7 @@ public:
/// \brief Get the list of function instantiations in the file.
///
- /// Fucntions that are instantiated more than once, such as C++ template
+ /// Functions that are instantiated more than once, such as C++ template
/// specializations, have distinct coverage records for each instantiation.
std::vector<const FunctionRecord *> getInstantiations(StringRef Filename);
diff --git a/include/llvm/ProfileData/InstrProf.h b/include/llvm/ProfileData/InstrProf.h
index 77055ba872682..4688759a3bd13 100644
--- a/include/llvm/ProfileData/InstrProf.h
+++ b/include/llvm/ProfileData/InstrProf.h
@@ -16,34 +16,310 @@
#ifndef LLVM_PROFILEDATA_INSTRPROF_H_
#define LLVM_PROFILEDATA_INSTRPROF_H_
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/IR/GlobalValue.h"
+#include "llvm/ProfileData/InstrProfData.inc"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/MD5.h"
#include <cstdint>
+#include <list>
#include <system_error>
#include <vector>
+#define INSTR_PROF_INDEX_VERSION 3
namespace llvm {
+
+class Function;
+class GlobalVariable;
+class Module;
+
+/// Return the name of data section containing profile counter variables.
+inline StringRef getInstrProfCountersSectionName(bool AddSegment) {
+ return AddSegment ? "__DATA," INSTR_PROF_CNTS_SECT_NAME_STR
+ : INSTR_PROF_CNTS_SECT_NAME_STR;
+}
+
+/// Return the name of data section containing names of instrumented
+/// functions.
+inline StringRef getInstrProfNameSectionName(bool AddSegment) {
+ return AddSegment ? "__DATA," INSTR_PROF_NAME_SECT_NAME_STR
+ : INSTR_PROF_NAME_SECT_NAME_STR;
+}
+
+/// Return the name of the data section containing per-function control
+/// data.
+inline StringRef getInstrProfDataSectionName(bool AddSegment) {
+ return AddSegment ? "__DATA," INSTR_PROF_DATA_SECT_NAME_STR
+ : INSTR_PROF_DATA_SECT_NAME_STR;
+}
+
+/// Return the name profile runtime entry point to do value profiling
+/// for a given site.
+inline StringRef getInstrProfValueProfFuncName() {
+ return INSTR_PROF_VALUE_PROF_FUNC_STR;
+}
+
+/// Return the name of the section containing function coverage mapping
+/// data.
+inline StringRef getInstrProfCoverageSectionName(bool AddSegment) {
+ return AddSegment ? "__DATA,__llvm_covmap" : "__llvm_covmap";
+}
+
+/// Return the name prefix of variables containing instrumented function names.
+inline StringRef getInstrProfNameVarPrefix() { return "__profn_"; }
+
+/// Return the name prefix of variables containing per-function control data.
+inline StringRef getInstrProfDataVarPrefix() { return "__profd_"; }
+
+/// Return the name prefix of profile counter variables.
+inline StringRef getInstrProfCountersVarPrefix() { return "__profc_"; }
+
+/// Return the name prefix of the COMDAT group for instrumentation variables
+/// associated with a COMDAT function.
+inline StringRef getInstrProfComdatPrefix() { return "__profv_"; }
+
+/// Return the name of a covarage mapping variable (internal linkage)
+/// for each instrumented source module. Such variables are allocated
+/// in the __llvm_covmap section.
+inline StringRef getCoverageMappingVarName() {
+ return "__llvm_coverage_mapping";
+}
+
+/// Return the name of function that registers all the per-function control
+/// data at program startup time by calling __llvm_register_function. This
+/// function has internal linkage and is called by __llvm_profile_init
+/// runtime method. This function is not generated for these platforms:
+/// Darwin, Linux, and FreeBSD.
+inline StringRef getInstrProfRegFuncsName() {
+ return "__llvm_profile_register_functions";
+}
+
+/// Return the name of the runtime interface that registers per-function control
+/// data for one instrumented function.
+inline StringRef getInstrProfRegFuncName() {
+ return "__llvm_profile_register_function";
+}
+
+/// Return the name of the runtime initialization method that is generated by
+/// the compiler. The function calls __llvm_profile_register_functions and
+/// __llvm_profile_override_default_filename functions if needed. This function
+/// has internal linkage and invoked at startup time via init_array.
+inline StringRef getInstrProfInitFuncName() { return "__llvm_profile_init"; }
+
+/// Return the name of the hook variable defined in profile runtime library.
+/// A reference to the variable causes the linker to link in the runtime
+/// initialization module (which defines the hook variable).
+inline StringRef getInstrProfRuntimeHookVarName() {
+ return "__llvm_profile_runtime";
+}
+
+/// Return the name of the compiler generated function that references the
+/// runtime hook variable. The function is a weak global.
+inline StringRef getInstrProfRuntimeHookVarUseFuncName() {
+ return "__llvm_profile_runtime_user";
+}
+
+/// Return the name of the profile runtime interface that overrides the default
+/// profile data file name.
+inline StringRef getInstrProfFileOverriderFuncName() {
+ return "__llvm_profile_override_default_filename";
+}
+
+/// Return the modified name for function \c F suitable to be
+/// used the key for profile lookup.
+std::string getPGOFuncName(const Function &F,
+ uint64_t Version = INSTR_PROF_INDEX_VERSION);
+
+/// Return the modified name for a function suitable to be
+/// used the key for profile lookup. The function's original
+/// name is \c RawFuncName and has linkage of type \c Linkage.
+/// The function is defined in module \c FileName.
+std::string getPGOFuncName(StringRef RawFuncName,
+ GlobalValue::LinkageTypes Linkage,
+ StringRef FileName,
+ uint64_t Version = INSTR_PROF_INDEX_VERSION);
+
+/// Create and return the global variable for function name used in PGO
+/// instrumentation. \c FuncName is the name of the function returned
+/// by \c getPGOFuncName call.
+GlobalVariable *createPGOFuncNameVar(Function &F, StringRef FuncName);
+
+/// Create and return the global variable for function name used in PGO
+/// instrumentation. /// \c FuncName is the name of the function
+/// returned by \c getPGOFuncName call, \c M is the owning module,
+/// and \c Linkage is the linkage of the instrumented function.
+GlobalVariable *createPGOFuncNameVar(Module &M,
+ GlobalValue::LinkageTypes Linkage,
+ StringRef FuncName);
+
+/// Given a PGO function name, remove the filename prefix and return
+/// the original (static) function name.
+StringRef getFuncNameWithoutPrefix(StringRef PGOFuncName, StringRef FileName);
+
const std::error_category &instrprof_category();
enum class instrprof_error {
- success = 0,
- eof,
- bad_magic,
- bad_header,
- unsupported_version,
- unsupported_hash_type,
- too_large,
- truncated,
- malformed,
- unknown_function,
- hash_mismatch,
- count_mismatch,
- counter_overflow
+ success = 0,
+ eof,
+ unrecognized_format,
+ bad_magic,
+ bad_header,
+ unsupported_version,
+ unsupported_hash_type,
+ too_large,
+ truncated,
+ malformed,
+ unknown_function,
+ hash_mismatch,
+ count_mismatch,
+ counter_overflow,
+ value_site_count_mismatch
};
inline std::error_code make_error_code(instrprof_error E) {
return std::error_code(static_cast<int>(E), instrprof_category());
}
+inline instrprof_error MergeResult(instrprof_error &Accumulator,
+ instrprof_error Result) {
+ // Prefer first error encountered as later errors may be secondary effects of
+ // the initial problem.
+ if (Accumulator == instrprof_error::success &&
+ Result != instrprof_error::success)
+ Accumulator = Result;
+ return Accumulator;
+}
+
+enum InstrProfValueKind : uint32_t {
+#define VALUE_PROF_KIND(Enumerator, Value) Enumerator = Value,
+#include "llvm/ProfileData/InstrProfData.inc"
+};
+
+namespace object {
+class SectionRef;
+}
+
+namespace IndexedInstrProf {
+uint64_t ComputeHash(StringRef K);
+}
+
+/// A symbol table used for function PGO name look-up with keys
+/// (such as pointers, md5hash values) to the function. A function's
+/// PGO name or name's md5hash are used in retrieving the profile
+/// data of the function. See \c getPGOFuncName() method for details
+/// on how PGO name is formed.
+class InstrProfSymtab {
+public:
+ typedef std::vector<std::pair<uint64_t, uint64_t>> AddrHashMap;
+
+private:
+ StringRef Data;
+ uint64_t Address;
+ // A map from MD5 hash keys to function name strings.
+ std::vector<std::pair<uint64_t, std::string>> HashNameMap;
+ // A map from function runtime address to function name MD5 hash.
+ // This map is only populated and used by raw instr profile reader.
+ AddrHashMap AddrToMD5Map;
+
+public:
+ InstrProfSymtab() : Data(), Address(0), HashNameMap(), AddrToMD5Map() {}
+
+ /// Create InstrProfSymtab from an object file section which
+ /// contains function PGO names that are uncompressed.
+ /// This interface is used by CoverageMappingReader.
+ std::error_code create(object::SectionRef &Section);
+ /// This interface is used by reader of CoverageMapping test
+ /// format.
+ inline std::error_code create(StringRef D, uint64_t BaseAddr);
+ /// Create InstrProfSymtab from a set of names iteratable from
+ /// \p IterRange. This interface is used by IndexedProfReader.
+ template <typename NameIterRange> void create(const NameIterRange &IterRange);
+ // If the symtab is created by a series of calls to \c addFuncName, \c
+ // finalizeSymtab needs to be called before looking up function names.
+ // This is required because the underlying map is a vector (for space
+ // efficiency) which needs to be sorted.
+ inline void finalizeSymtab();
+ /// Update the symtab by adding \p FuncName to the table. This interface
+ /// is used by the raw and text profile readers.
+ void addFuncName(StringRef FuncName) {
+ HashNameMap.push_back(std::make_pair(
+ IndexedInstrProf::ComputeHash(FuncName), FuncName.str()));
+ }
+ /// Map a function address to its name's MD5 hash. This interface
+ /// is only used by the raw profiler reader.
+ void mapAddress(uint64_t Addr, uint64_t MD5Val) {
+ AddrToMD5Map.push_back(std::make_pair(Addr, MD5Val));
+ }
+ AddrHashMap &getAddrHashMap() { return AddrToMD5Map; }
+ /// Return function's PGO name from the function name's symabol
+ /// address in the object file. If an error occurs, Return
+ /// an empty string.
+ StringRef getFuncName(uint64_t FuncNameAddress, size_t NameSize);
+ /// Return function's PGO name from the name's md5 hash value.
+ /// If not found, return an empty string.
+ inline StringRef getFuncName(uint64_t FuncMD5Hash);
+};
+
+std::error_code InstrProfSymtab::create(StringRef D, uint64_t BaseAddr) {
+ Data = D;
+ Address = BaseAddr;
+ return std::error_code();
+}
+
+template <typename NameIterRange>
+void InstrProfSymtab::create(const NameIterRange &IterRange) {
+ for (auto Name : IterRange)
+ HashNameMap.push_back(
+ std::make_pair(IndexedInstrProf::ComputeHash(Name), Name.str()));
+ finalizeSymtab();
+}
+
+void InstrProfSymtab::finalizeSymtab() {
+ std::sort(HashNameMap.begin(), HashNameMap.end(), less_first());
+ HashNameMap.erase(std::unique(HashNameMap.begin(), HashNameMap.end()),
+ HashNameMap.end());
+ std::sort(AddrToMD5Map.begin(), AddrToMD5Map.end(), less_first());
+ AddrToMD5Map.erase(std::unique(AddrToMD5Map.begin(), AddrToMD5Map.end()),
+ AddrToMD5Map.end());
+}
+
+StringRef InstrProfSymtab::getFuncName(uint64_t FuncMD5Hash) {
+ auto Result =
+ std::lower_bound(HashNameMap.begin(), HashNameMap.end(), FuncMD5Hash,
+ [](const std::pair<uint64_t, std::string> &LHS,
+ uint64_t RHS) { return LHS.first < RHS; });
+ if (Result != HashNameMap.end())
+ return Result->second;
+ return StringRef();
+}
+
+struct InstrProfValueSiteRecord {
+ /// Value profiling data pairs at a given value site.
+ std::list<InstrProfValueData> ValueData;
+
+ InstrProfValueSiteRecord() { ValueData.clear(); }
+ template <class InputIterator>
+ InstrProfValueSiteRecord(InputIterator F, InputIterator L)
+ : ValueData(F, L) {}
+
+ /// Sort ValueData ascending by Value
+ void sortByTargetValues() {
+ ValueData.sort(
+ [](const InstrProfValueData &left, const InstrProfValueData &right) {
+ return left.Value < right.Value;
+ });
+ }
+
+ /// Merge data from another InstrProfValueSiteRecord
+ /// Optionally scale merged counts by \p Weight.
+ instrprof_error mergeValueData(InstrProfValueSiteRecord &Input,
+ uint64_t Weight = 1);
+};
+
/// Profiling information for a single function.
struct InstrProfRecord {
InstrProfRecord() {}
@@ -52,8 +328,258 @@ struct InstrProfRecord {
StringRef Name;
uint64_t Hash;
std::vector<uint64_t> Counts;
+
+ typedef std::vector<std::pair<uint64_t, uint64_t>> ValueMapType;
+
+ /// Return the number of value profile kinds with non-zero number
+ /// of profile sites.
+ inline uint32_t getNumValueKinds() const;
+ /// Return the number of instrumented sites for ValueKind.
+ inline uint32_t getNumValueSites(uint32_t ValueKind) const;
+ /// Return the total number of ValueData for ValueKind.
+ inline uint32_t getNumValueData(uint32_t ValueKind) const;
+ /// Return the number of value data collected for ValueKind at profiling
+ /// site: Site.
+ inline uint32_t getNumValueDataForSite(uint32_t ValueKind,
+ uint32_t Site) const;
+ /// Return the array of profiled values at \p Site.
+ inline std::unique_ptr<InstrProfValueData[]>
+ getValueForSite(uint32_t ValueKind, uint32_t Site,
+ uint64_t (*ValueMapper)(uint32_t, uint64_t) = 0) const;
+ inline void
+ getValueForSite(InstrProfValueData Dest[], uint32_t ValueKind, uint32_t Site,
+ uint64_t (*ValueMapper)(uint32_t, uint64_t) = 0) const;
+ /// Reserve space for NumValueSites sites.
+ inline void reserveSites(uint32_t ValueKind, uint32_t NumValueSites);
+ /// Add ValueData for ValueKind at value Site.
+ void addValueData(uint32_t ValueKind, uint32_t Site,
+ InstrProfValueData *VData, uint32_t N,
+ ValueMapType *ValueMap);
+
+ /// Merge the counts in \p Other into this one.
+ /// Optionally scale merged counts by \p Weight.
+ instrprof_error merge(InstrProfRecord &Other, uint64_t Weight = 1);
+
+ /// Clear value data entries
+ void clearValueData() {
+ for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; ++Kind)
+ getValueSitesForKind(Kind).clear();
+ }
+
+private:
+ std::vector<InstrProfValueSiteRecord> IndirectCallSites;
+ const std::vector<InstrProfValueSiteRecord> &
+ getValueSitesForKind(uint32_t ValueKind) const {
+ switch (ValueKind) {
+ case IPVK_IndirectCallTarget:
+ return IndirectCallSites;
+ default:
+ llvm_unreachable("Unknown value kind!");
+ }
+ return IndirectCallSites;
+ }
+
+ std::vector<InstrProfValueSiteRecord> &
+ getValueSitesForKind(uint32_t ValueKind) {
+ return const_cast<std::vector<InstrProfValueSiteRecord> &>(
+ const_cast<const InstrProfRecord *>(this)
+ ->getValueSitesForKind(ValueKind));
+ }
+
+ // Map indirect call target name hash to name string.
+ uint64_t remapValue(uint64_t Value, uint32_t ValueKind,
+ ValueMapType *HashKeys);
+
+ // Merge Value Profile data from Src record to this record for ValueKind.
+ // Scale merged value counts by \p Weight.
+ instrprof_error mergeValueProfData(uint32_t ValueKind, InstrProfRecord &Src,
+ uint64_t Weight);
+};
+
+uint32_t InstrProfRecord::getNumValueKinds() const {
+ uint32_t NumValueKinds = 0;
+ for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; ++Kind)
+ NumValueKinds += !(getValueSitesForKind(Kind).empty());
+ return NumValueKinds;
+}
+
+uint32_t InstrProfRecord::getNumValueData(uint32_t ValueKind) const {
+ uint32_t N = 0;
+ const std::vector<InstrProfValueSiteRecord> &SiteRecords =
+ getValueSitesForKind(ValueKind);
+ for (auto &SR : SiteRecords) {
+ N += SR.ValueData.size();
+ }
+ return N;
+}
+
+uint32_t InstrProfRecord::getNumValueSites(uint32_t ValueKind) const {
+ return getValueSitesForKind(ValueKind).size();
+}
+
+uint32_t InstrProfRecord::getNumValueDataForSite(uint32_t ValueKind,
+ uint32_t Site) const {
+ return getValueSitesForKind(ValueKind)[Site].ValueData.size();
+}
+
+std::unique_ptr<InstrProfValueData[]> InstrProfRecord::getValueForSite(
+ uint32_t ValueKind, uint32_t Site,
+ uint64_t (*ValueMapper)(uint32_t, uint64_t)) const {
+ uint32_t N = getNumValueDataForSite(ValueKind, Site);
+ if (N == 0)
+ return std::unique_ptr<InstrProfValueData[]>(nullptr);
+
+ auto VD = llvm::make_unique<InstrProfValueData[]>(N);
+ getValueForSite(VD.get(), ValueKind, Site, ValueMapper);
+
+ return VD;
+}
+
+void InstrProfRecord::getValueForSite(InstrProfValueData Dest[],
+ uint32_t ValueKind, uint32_t Site,
+ uint64_t (*ValueMapper)(uint32_t,
+ uint64_t)) const {
+ uint32_t I = 0;
+ for (auto V : getValueSitesForKind(ValueKind)[Site].ValueData) {
+ Dest[I].Value = ValueMapper ? ValueMapper(ValueKind, V.Value) : V.Value;
+ Dest[I].Count = V.Count;
+ I++;
+ }
+}
+
+void InstrProfRecord::reserveSites(uint32_t ValueKind, uint32_t NumValueSites) {
+ std::vector<InstrProfValueSiteRecord> &ValueSites =
+ getValueSitesForKind(ValueKind);
+ ValueSites.reserve(NumValueSites);
+}
+
+inline support::endianness getHostEndianness() {
+ return sys::IsLittleEndianHost ? support::little : support::big;
+}
+
+// Include definitions for value profile data
+#define INSTR_PROF_VALUE_PROF_DATA
+#include "llvm/ProfileData/InstrProfData.inc"
+
+ /*
+ * Initialize the record for runtime value profile data.
+ * Return 0 if the initialization is successful, otherwise
+ * return 1.
+ */
+int initializeValueProfRuntimeRecord(ValueProfRuntimeRecord *RuntimeRecord,
+ const uint16_t *NumValueSites,
+ ValueProfNode **Nodes);
+
+/* Release memory allocated for the runtime record. */
+void finalizeValueProfRuntimeRecord(ValueProfRuntimeRecord *RuntimeRecord);
+
+/* Return the size of ValueProfData structure that can be used to store
+ the value profile data collected at runtime. */
+uint32_t getValueProfDataSizeRT(const ValueProfRuntimeRecord *Record);
+
+/* Return a ValueProfData instance that stores the data collected at runtime. */
+ValueProfData *
+serializeValueProfDataFromRT(const ValueProfRuntimeRecord *Record,
+ ValueProfData *Dst);
+
+namespace IndexedInstrProf {
+
+enum class HashT : uint32_t {
+ MD5,
+
+ Last = MD5
+};
+
+static inline uint64_t MD5Hash(StringRef Str) {
+ MD5 Hash;
+ Hash.update(Str);
+ llvm::MD5::MD5Result Result;
+ Hash.final(Result);
+ // Return the least significant 8 bytes. Our MD5 implementation returns the
+ // result in little endian, so we may need to swap bytes.
+ using namespace llvm::support;
+ return endian::read<uint64_t, little, unaligned>(Result);
+}
+
+inline uint64_t ComputeHash(HashT Type, StringRef K) {
+ switch (Type) {
+ case HashT::MD5:
+ return IndexedInstrProf::MD5Hash(K);
+ }
+ llvm_unreachable("Unhandled hash type");
+}
+
+const uint64_t Magic = 0x8169666f72706cff; // "\xfflprofi\x81"
+const uint64_t Version = INSTR_PROF_INDEX_VERSION;
+const HashT HashType = HashT::MD5;
+
+inline uint64_t ComputeHash(StringRef K) { return ComputeHash(HashType, K); }
+
+// This structure defines the file header of the LLVM profile
+// data file in indexed-format.
+struct Header {
+ uint64_t Magic;
+ uint64_t Version;
+ uint64_t MaxFunctionCount;
+ uint64_t HashType;
+ uint64_t HashOffset;
+};
+
+} // end namespace IndexedInstrProf
+
+namespace RawInstrProf {
+
+const uint64_t Version = INSTR_PROF_RAW_VERSION;
+
+template <class IntPtrT> inline uint64_t getMagic();
+template <> inline uint64_t getMagic<uint64_t>() {
+ return INSTR_PROF_RAW_MAGIC_64;
+}
+
+template <> inline uint64_t getMagic<uint32_t>() {
+ return INSTR_PROF_RAW_MAGIC_32;
+}
+
+// Per-function profile data header/control structure.
+// The definition should match the structure defined in
+// compiler-rt/lib/profile/InstrProfiling.h.
+// It should also match the synthesized type in
+// Transforms/Instrumentation/InstrProfiling.cpp:getOrCreateRegionCounters.
+template <class IntPtrT> struct LLVM_ALIGNAS(8) ProfileData {
+ #define INSTR_PROF_DATA(Type, LLVMType, Name, Init) Type Name;
+ #include "llvm/ProfileData/InstrProfData.inc"
};
+// File header structure of the LLVM profile data in raw format.
+// The definition should match the header referenced in
+// compiler-rt/lib/profile/InstrProfilingFile.c and
+// InstrProfilingBuffer.c.
+struct Header {
+#define INSTR_PROF_RAW_HEADER(Type, Name, Init) const Type Name;
+#include "llvm/ProfileData/InstrProfData.inc"
+};
+
+} // end namespace RawInstrProf
+
+namespace coverage {
+
+// Profile coverage map has the following layout:
+// [CoverageMapFileHeader]
+// [ArrayStart]
+// [CovMapFunctionRecord]
+// [CovMapFunctionRecord]
+// ...
+// [ArrayEnd]
+// [Encoded Region Mapping Data]
+LLVM_PACKED_START
+template <class IntPtrT> struct CovMapFunctionRecord {
+ #define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) Type Name;
+ #include "llvm/ProfileData/InstrProfData.inc"
+};
+LLVM_PACKED_END
+
+}
+
} // end namespace llvm
namespace std {
diff --git a/include/llvm/ProfileData/InstrProfData.inc b/include/llvm/ProfileData/InstrProfData.inc
new file mode 100644
index 0000000000000..48dae506cabb8
--- /dev/null
+++ b/include/llvm/ProfileData/InstrProfData.inc
@@ -0,0 +1,735 @@
+/*===-- InstrProfData.inc - instr profiling runtime structures -----------=== *\
+|*
+|* The LLVM Compiler Infrastructure
+|*
+|* This file is distributed under the University of Illinois Open Source
+|* License. See LICENSE.TXT for details.
+|*
+\*===----------------------------------------------------------------------===*/
+/*
+ * This is the master file that defines all the data structure, signature,
+ * constant literals that are shared across profiling runtime library,
+ * compiler (instrumentation), and host tools (reader/writer). The entities
+ * defined in this file affect the profile runtime ABI, the raw profile format,
+ * or both.
+ *
+ * The file has two identical copies. The master copy lives in LLVM and
+ * the other one sits in compiler-rt/lib/profile directory. To make changes
+ * in this file, first modify the master copy and copy it over to compiler-rt.
+ * Testing of any change in this file can start only after the two copies are
+ * synced up.
+ *
+ * The first part of the file includes macros that defines types, names, and
+ * initializers for the member fields of the core data structures. The field
+ * declarations for one structure is enabled by defining the field activation
+ * macro associated with that structure. Only one field activation record
+ * can be defined at one time and the rest definitions will be filtered out by
+ * the preprocessor.
+ *
+ * Examples of how the template is used to instantiate structure definition:
+ * 1. To declare a structure:
+ *
+ * struct ProfData {
+ * #define INSTR_PROF_DATA(Type, LLVMType, Name, Initializer) \
+ * Type Name;
+ * #include "llvm/ProfileData/InstrProfData.inc"
+ * };
+ *
+ * 2. To construct LLVM type arrays for the struct type:
+ *
+ * Type *DataTypes[] = {
+ * #define INSTR_PROF_DATA(Type, LLVMType, Name, Initializer) \
+ * LLVMType,
+ * #include "llvm/ProfileData/InstrProfData.inc"
+ * };
+ *
+ * 4. To construct constant array for the initializers:
+ * #define INSTR_PROF_DATA(Type, LLVMType, Name, Initializer) \
+ * Initializer,
+ * Constant *ConstantVals[] = {
+ * #include "llvm/ProfileData/InstrProfData.inc"
+ * };
+ *
+ *
+ * The second part of the file includes definitions all other entities that
+ * are related to runtime ABI and format. When no field activation macro is
+ * defined, this file can be included to introduce the definitions.
+ *
+\*===----------------------------------------------------------------------===*/
+
+/* INSTR_PROF_DATA start. */
+/* Definition of member fields of the per-function control structure. */
+#ifndef INSTR_PROF_DATA
+#define INSTR_PROF_DATA(Type, LLVMType, Name, Initializer)
+#else
+#define INSTR_PROF_DATA_DEFINED
+#endif
+
+INSTR_PROF_DATA(const uint32_t, llvm::Type::getInt32Ty(Ctx), NameSize, \
+ ConstantInt::get(llvm::Type::getInt32Ty(Ctx), \
+ NamePtr->getType()->getPointerElementType()->getArrayNumElements()))
+INSTR_PROF_DATA(const uint32_t, llvm::Type::getInt32Ty(Ctx), NumCounters, \
+ ConstantInt::get(llvm::Type::getInt32Ty(Ctx), NumCounters))
+INSTR_PROF_DATA(const uint64_t, llvm::Type::getInt64Ty(Ctx), FuncHash, \
+ ConstantInt::get(llvm::Type::getInt64Ty(Ctx), \
+ Inc->getHash()->getZExtValue()))
+INSTR_PROF_DATA(const IntPtrT, llvm::Type::getInt8PtrTy(Ctx), NamePtr, \
+ ConstantExpr::getBitCast(NamePtr, llvm::Type::getInt8PtrTy(Ctx)))
+INSTR_PROF_DATA(const IntPtrT, llvm::Type::getInt64PtrTy(Ctx), CounterPtr, \
+ ConstantExpr::getBitCast(CounterPtr, \
+ llvm::Type::getInt64PtrTy(Ctx)))
+INSTR_PROF_DATA(const IntPtrT, llvm::Type::getInt8PtrTy(Ctx), FunctionPointer, \
+ FunctionAddr)
+INSTR_PROF_DATA(IntPtrT, llvm::Type::getInt8PtrTy(Ctx), Values, \
+ ConstantPointerNull::get(Int8PtrTy))
+INSTR_PROF_DATA(const uint16_t, Int16ArrayTy, NumValueSites[IPVK_Last+1], \
+ ConstantArray::get(Int16ArrayTy, Int16ArrayVals))
+#undef INSTR_PROF_DATA
+/* INSTR_PROF_DATA end. */
+
+/* INSTR_PROF_RAW_HEADER start */
+/* Definition of member fields of the raw profile header data structure. */
+#ifndef INSTR_PROF_RAW_HEADER
+#define INSTR_PROF_RAW_HEADER(Type, Name, Initializer)
+#else
+#define INSTR_PROF_DATA_DEFINED
+#endif
+INSTR_PROF_RAW_HEADER(uint64_t, Magic, __llvm_profile_get_magic())
+INSTR_PROF_RAW_HEADER(uint64_t, Version, __llvm_profile_get_version())
+INSTR_PROF_RAW_HEADER(uint64_t, DataSize, DataSize)
+INSTR_PROF_RAW_HEADER(uint64_t, CountersSize, CountersSize)
+INSTR_PROF_RAW_HEADER(uint64_t, NamesSize, NamesSize)
+INSTR_PROF_RAW_HEADER(uint64_t, CountersDelta, (uintptr_t)CountersBegin)
+INSTR_PROF_RAW_HEADER(uint64_t, NamesDelta, (uintptr_t)NamesBegin)
+INSTR_PROF_RAW_HEADER(uint64_t, ValueKindLast, IPVK_Last)
+INSTR_PROF_RAW_HEADER(uint64_t, ValueDataSize, ValueDataSize)
+INSTR_PROF_RAW_HEADER(uint64_t, ValueDataDelta, (uintptr_t)ValueDataBegin)
+#undef INSTR_PROF_RAW_HEADER
+/* INSTR_PROF_RAW_HEADER end */
+
+/* VALUE_PROF_FUNC_PARAM start */
+/* Definition of parameter types of the runtime API used to do value profiling
+ * for a given value site.
+ */
+#ifndef VALUE_PROF_FUNC_PARAM
+#define VALUE_PROF_FUNC_PARAM(ArgType, ArgName, ArgLLVMType)
+#define INSTR_PROF_COMMA
+#else
+#define INSTR_PROF_DATA_DEFINED
+#define INSTR_PROF_COMMA ,
+#endif
+VALUE_PROF_FUNC_PARAM(uint64_t, TargetValue, Type::getInt64Ty(Ctx)) \
+ INSTR_PROF_COMMA
+VALUE_PROF_FUNC_PARAM(void *, Data, Type::getInt8PtrTy(Ctx)) INSTR_PROF_COMMA
+VALUE_PROF_FUNC_PARAM(uint32_t, CounterIndex, Type::getInt32Ty(Ctx))
+#undef VALUE_PROF_FUNC_PARAM
+#undef INSTR_PROF_COMMA
+/* VALUE_PROF_FUNC_PARAM end */
+
+/* VALUE_PROF_KIND start */
+#ifndef VALUE_PROF_KIND
+#define VALUE_PROF_KIND(Enumerator, Value)
+#else
+#define INSTR_PROF_DATA_DEFINED
+#endif
+VALUE_PROF_KIND(IPVK_IndirectCallTarget, 0)
+/* These two kinds must be the last to be
+ * declared. This is to make sure the string
+ * array created with the template can be
+ * indexed with the kind value.
+ */
+VALUE_PROF_KIND(IPVK_First, IPVK_IndirectCallTarget)
+VALUE_PROF_KIND(IPVK_Last, IPVK_IndirectCallTarget)
+
+#undef VALUE_PROF_KIND
+/* VALUE_PROF_KIND end */
+
+/* COVMAP_FUNC_RECORD start */
+/* Definition of member fields of the function record structure in coverage
+ * map.
+ */
+#ifndef COVMAP_FUNC_RECORD
+#define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Initializer)
+#else
+#define INSTR_PROF_DATA_DEFINED
+#endif
+COVMAP_FUNC_RECORD(const IntPtrT, llvm::Type::getInt8PtrTy(Ctx), \
+ NamePtr, llvm::ConstantExpr::getBitCast(NamePtr, \
+ llvm::Type::getInt8PtrTy(Ctx)))
+COVMAP_FUNC_RECORD(const uint32_t, llvm::Type::getInt32Ty(Ctx), NameSize, \
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(Ctx),\
+ NameValue.size()))
+COVMAP_FUNC_RECORD(const uint32_t, llvm::Type::getInt32Ty(Ctx), DataSize, \
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(Ctx),\
+ CoverageMapping.size()))
+COVMAP_FUNC_RECORD(const uint64_t, llvm::Type::getInt64Ty(Ctx), FuncHash, \
+ llvm::ConstantInt::get(llvm::Type::getInt64Ty(Ctx), FuncHash))
+#undef COVMAP_FUNC_RECORD
+/* COVMAP_FUNC_RECORD end. */
+
+
+#ifdef INSTR_PROF_VALUE_PROF_DATA
+#define INSTR_PROF_DATA_DEFINED
+
+/*!
+ * This is the header of the data structure that defines the on-disk
+ * layout of the value profile data of a particular kind for one function.
+ */
+typedef struct ValueProfRecord {
+ /* The kind of the value profile record. */
+ uint32_t Kind;
+ /*
+ * The number of value profile sites. It is guaranteed to be non-zero;
+ * otherwise the record for this kind won't be emitted.
+ */
+ uint32_t NumValueSites;
+ /*
+ * The first element of the array that stores the number of profiled
+ * values for each value site. The size of the array is NumValueSites.
+ * Since NumValueSites is greater than zero, there is at least one
+ * element in the array.
+ */
+ uint8_t SiteCountArray[1];
+
+ /*
+ * The fake declaration is for documentation purpose only.
+ * Align the start of next field to be on 8 byte boundaries.
+ uint8_t Padding[X];
+ */
+
+ /* The array of value profile data. The size of the array is the sum
+ * of all elements in SiteCountArray[].
+ InstrProfValueData ValueData[];
+ */
+
+#ifdef __cplusplus
+ /*!
+ * \brief Return the number of value sites.
+ */
+ uint32_t getNumValueSites() const { return NumValueSites; }
+ /*!
+ * \brief Read data from this record and save it to Record.
+ */
+ void deserializeTo(InstrProfRecord &Record,
+ InstrProfRecord::ValueMapType *VMap);
+ /*
+ * In-place byte swap:
+ * Do byte swap for this instance. \c Old is the original order before
+ * the swap, and \c New is the New byte order.
+ */
+ void swapBytes(support::endianness Old, support::endianness New);
+#endif
+} ValueProfRecord;
+
+/*!
+ * Per-function header/control data structure for value profiling
+ * data in indexed format.
+ */
+typedef struct ValueProfData {
+ /*
+ * Total size in bytes including this field. It must be a multiple
+ * of sizeof(uint64_t).
+ */
+ uint32_t TotalSize;
+ /*
+ *The number of value profile kinds that has value profile data.
+ * In this implementation, a value profile kind is considered to
+ * have profile data if the number of value profile sites for the
+ * kind is not zero. More aggressively, the implementation can
+ * choose to check the actual data value: if none of the value sites
+ * has any profiled values, the kind can be skipped.
+ */
+ uint32_t NumValueKinds;
+
+ /*
+ * Following are a sequence of variable length records. The prefix/header
+ * of each record is defined by ValueProfRecord type. The number of
+ * records is NumValueKinds.
+ * ValueProfRecord Record_1;
+ * ValueProfRecord Record_N;
+ */
+
+#if __cplusplus
+ /*!
+ * Return the total size in bytes of the on-disk value profile data
+ * given the data stored in Record.
+ */
+ static uint32_t getSize(const InstrProfRecord &Record);
+ /*!
+ * Return a pointer to \c ValueProfData instance ready to be streamed.
+ */
+ static std::unique_ptr<ValueProfData>
+ serializeFrom(const InstrProfRecord &Record);
+ /*!
+ * Check the integrity of the record. Return the error code when
+ * an error is detected, otherwise return instrprof_error::success.
+ */
+ instrprof_error checkIntegrity();
+ /*!
+ * Return a pointer to \c ValueProfileData instance ready to be read.
+ * All data in the instance are properly byte swapped. The input
+ * data is assumed to be in little endian order.
+ */
+ static ErrorOr<std::unique_ptr<ValueProfData>>
+ getValueProfData(const unsigned char *SrcBuffer,
+ const unsigned char *const SrcBufferEnd,
+ support::endianness SrcDataEndianness);
+ /*!
+ * Swap byte order from \c Endianness order to host byte order.
+ */
+ void swapBytesToHost(support::endianness Endianness);
+ /*!
+ * Swap byte order from host byte order to \c Endianness order.
+ */
+ void swapBytesFromHost(support::endianness Endianness);
+ /*!
+ * Return the total size of \c ValueProfileData.
+ */
+ uint32_t getSize() const { return TotalSize; }
+ /*!
+ * Read data from this data and save it to \c Record.
+ */
+ void deserializeTo(InstrProfRecord &Record,
+ InstrProfRecord::ValueMapType *VMap);
+ void operator delete(void *ptr) { ::operator delete(ptr); }
+#endif
+} ValueProfData;
+
+/*
+ * The closure is designed to abstact away two types of value profile data:
+ * - InstrProfRecord which is the primary data structure used to
+ * represent profile data in host tools (reader, writer, and profile-use)
+ * - value profile runtime data structure suitable to be used by C
+ * runtime library.
+ *
+ * Both sources of data need to serialize to disk/memory-buffer in common
+ * format: ValueProfData. The abstraction allows compiler-rt's raw profiler
+ * writer to share the same format and code with indexed profile writer.
+ *
+ * For documentation of the member methods below, refer to corresponding methods
+ * in class InstrProfRecord.
+ */
+typedef struct ValueProfRecordClosure {
+ const void *Record;
+ uint32_t (*GetNumValueKinds)(const void *Record);
+ uint32_t (*GetNumValueSites)(const void *Record, uint32_t VKind);
+ uint32_t (*GetNumValueData)(const void *Record, uint32_t VKind);
+ uint32_t (*GetNumValueDataForSite)(const void *R, uint32_t VK, uint32_t S);
+
+ /*
+ * After extracting the value profile data from the value profile record,
+ * this method is used to map the in-memory value to on-disk value. If
+ * the method is null, value will be written out untranslated.
+ */
+ uint64_t (*RemapValueData)(uint32_t, uint64_t Value);
+ void (*GetValueForSite)(const void *R, InstrProfValueData *Dst, uint32_t K,
+ uint32_t S, uint64_t (*Mapper)(uint32_t, uint64_t));
+ ValueProfData *(*AllocValueProfData)(size_t TotalSizeInBytes);
+} ValueProfRecordClosure;
+
+/*
+ * A wrapper struct that represents value profile runtime data.
+ * Like InstrProfRecord class which is used by profiling host tools,
+ * ValueProfRuntimeRecord also implements the abstract intefaces defined in
+ * ValueProfRecordClosure so that the runtime data can be serialized using
+ * shared C implementation. In this structure, NumValueSites and Nodes
+ * members are the primary fields while other fields hold the derived
+ * information for fast implementation of closure interfaces.
+ */
+typedef struct ValueProfRuntimeRecord {
+ /* Number of sites for each value profile kind. */
+ const uint16_t *NumValueSites;
+ /* An array of linked-list headers. The size of of the array is the
+ * total number of value profile sites : sum(NumValueSites[*])). Each
+ * linked-list stores the values profiled for a value profile site. */
+ ValueProfNode **Nodes;
+
+ /* Total number of value profile kinds which have at least one
+ * value profile sites. */
+ uint32_t NumValueKinds;
+ /* An array recording the number of values tracked at each site.
+ * The size of the array is TotalNumValueSites. */
+ uint8_t *SiteCountArray[IPVK_Last + 1];
+ ValueProfNode **NodesKind[IPVK_Last + 1];
+} ValueProfRuntimeRecord;
+
+/* Forward declarations of C interfaces. */
+int initializeValueProfRuntimeRecord(ValueProfRuntimeRecord *RuntimeRecord,
+ const uint16_t *NumValueSites,
+ ValueProfNode **Nodes);
+void finalizeValueProfRuntimeRecord(ValueProfRuntimeRecord *RuntimeRecord);
+uint32_t getValueProfDataSizeRT(const ValueProfRuntimeRecord *Record);
+ValueProfData *
+serializeValueProfDataFromRT(const ValueProfRuntimeRecord *Record,
+ ValueProfData *Dst);
+uint32_t getNumValueKindsRT(const void *R);
+
+#undef INSTR_PROF_VALUE_PROF_DATA
+#endif /* INSTR_PROF_VALUE_PROF_DATA */
+
+
+#ifdef INSTR_PROF_COMMON_API_IMPL
+#define INSTR_PROF_DATA_DEFINED
+#ifdef __cplusplus
+#define INSTR_PROF_INLINE inline
+#else
+#define INSTR_PROF_INLINE
+#endif
+
+#ifndef offsetof
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#endif
+
+/*!
+ * \brief Return the \c ValueProfRecord header size including the
+ * padding bytes.
+ */
+INSTR_PROF_INLINE
+uint32_t getValueProfRecordHeaderSize(uint32_t NumValueSites) {
+ uint32_t Size = offsetof(ValueProfRecord, SiteCountArray) +
+ sizeof(uint8_t) * NumValueSites;
+ /* Round the size to multiple of 8 bytes. */
+ Size = (Size + 7) & ~7;
+ return Size;
+}
+
+/*!
+ * \brief Return the total size of the value profile record including the
+ * header and the value data.
+ */
+INSTR_PROF_INLINE
+uint32_t getValueProfRecordSize(uint32_t NumValueSites,
+ uint32_t NumValueData) {
+ return getValueProfRecordHeaderSize(NumValueSites) +
+ sizeof(InstrProfValueData) * NumValueData;
+}
+
+/*!
+ * \brief Return the pointer to the start of value data array.
+ */
+INSTR_PROF_INLINE
+InstrProfValueData *getValueProfRecordValueData(ValueProfRecord *This) {
+ return (InstrProfValueData *)((char *)This + getValueProfRecordHeaderSize(
+ This->NumValueSites));
+}
+
+/*!
+ * \brief Return the total number of value data for \c This record.
+ */
+INSTR_PROF_INLINE
+uint32_t getValueProfRecordNumValueData(ValueProfRecord *This) {
+ uint32_t NumValueData = 0;
+ uint32_t I;
+ for (I = 0; I < This->NumValueSites; I++)
+ NumValueData += This->SiteCountArray[I];
+ return NumValueData;
+}
+
+/*!
+ * \brief Use this method to advance to the next \c This \c ValueProfRecord.
+ */
+INSTR_PROF_INLINE
+ValueProfRecord *getValueProfRecordNext(ValueProfRecord *This) {
+ uint32_t NumValueData = getValueProfRecordNumValueData(This);
+ return (ValueProfRecord *)((char *)This +
+ getValueProfRecordSize(This->NumValueSites,
+ NumValueData));
+}
+
+/*!
+ * \brief Return the first \c ValueProfRecord instance.
+ */
+INSTR_PROF_INLINE
+ValueProfRecord *getFirstValueProfRecord(ValueProfData *This) {
+ return (ValueProfRecord *)((char *)This + sizeof(ValueProfData));
+}
+
+/* Closure based interfaces. */
+
+/*!
+ * Return the total size in bytes of the on-disk value profile data
+ * given the data stored in Record.
+ */
+uint32_t getValueProfDataSize(ValueProfRecordClosure *Closure) {
+ uint32_t Kind;
+ uint32_t TotalSize = sizeof(ValueProfData);
+ const void *Record = Closure->Record;
+ uint32_t NumValueKinds = Closure->GetNumValueKinds(Record);
+ if (NumValueKinds == 0)
+ return TotalSize;
+
+ for (Kind = IPVK_First; Kind <= IPVK_Last; Kind++) {
+ uint32_t NumValueSites = Closure->GetNumValueSites(Record, Kind);
+ if (!NumValueSites)
+ continue;
+ TotalSize += getValueProfRecordSize(NumValueSites,
+ Closure->GetNumValueData(Record, Kind));
+ }
+ return TotalSize;
+}
+
+/*!
+ * Extract value profile data of a function for the profile kind \c ValueKind
+ * from the \c Closure and serialize the data into \c This record instance.
+ */
+void serializeValueProfRecordFrom(ValueProfRecord *This,
+ ValueProfRecordClosure *Closure,
+ uint32_t ValueKind, uint32_t NumValueSites) {
+ uint32_t S;
+ const void *Record = Closure->Record;
+ This->Kind = ValueKind;
+ This->NumValueSites = NumValueSites;
+ InstrProfValueData *DstVD = getValueProfRecordValueData(This);
+
+ for (S = 0; S < NumValueSites; S++) {
+ uint32_t ND = Closure->GetNumValueDataForSite(Record, ValueKind, S);
+ This->SiteCountArray[S] = ND;
+ Closure->GetValueForSite(Record, DstVD, ValueKind, S,
+ Closure->RemapValueData);
+ DstVD += ND;
+ }
+}
+
+/*!
+ * Extract value profile data of a function from the \c Closure
+ * and serialize the data into \c DstData if it is not NULL or heap
+ * memory allocated by the \c Closure's allocator method.
+ */
+ValueProfData *serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
+ ValueProfData *DstData) {
+ uint32_t Kind;
+ uint32_t TotalSize = getValueProfDataSize(Closure);
+
+ ValueProfData *VPD =
+ DstData ? DstData : Closure->AllocValueProfData(TotalSize);
+
+ VPD->TotalSize = TotalSize;
+ VPD->NumValueKinds = Closure->GetNumValueKinds(Closure->Record);
+ ValueProfRecord *VR = getFirstValueProfRecord(VPD);
+ for (Kind = IPVK_First; Kind <= IPVK_Last; Kind++) {
+ uint32_t NumValueSites = Closure->GetNumValueSites(Closure->Record, Kind);
+ if (!NumValueSites)
+ continue;
+ serializeValueProfRecordFrom(VR, Closure, Kind, NumValueSites);
+ VR = getValueProfRecordNext(VR);
+ }
+ return VPD;
+}
+
+/*
+ * The value profiler runtime library stores the value profile data
+ * for a given function in \c NumValueSites and \c Nodes structures.
+ * \c ValueProfRuntimeRecord class is used to encapsulate the runtime
+ * profile data and provides fast interfaces to retrieve the profile
+ * information. This interface is used to initialize the runtime record
+ * and pre-compute the information needed for efficient implementation
+ * of callbacks required by ValueProfRecordClosure class.
+ */
+int initializeValueProfRuntimeRecord(ValueProfRuntimeRecord *RuntimeRecord,
+ const uint16_t *NumValueSites,
+ ValueProfNode **Nodes) {
+ unsigned I, J, S = 0, NumValueKinds = 0;
+ RuntimeRecord->NumValueSites = NumValueSites;
+ RuntimeRecord->Nodes = Nodes;
+ for (I = 0; I <= IPVK_Last; I++) {
+ uint16_t N = NumValueSites[I];
+ if (!N) {
+ RuntimeRecord->SiteCountArray[I] = 0;
+ continue;
+ }
+ NumValueKinds++;
+ RuntimeRecord->SiteCountArray[I] = (uint8_t *)calloc(N, 1);
+ if (!RuntimeRecord->SiteCountArray[I])
+ return 1;
+ RuntimeRecord->NodesKind[I] = Nodes ? &Nodes[S] : NULL;
+ for (J = 0; J < N; J++) {
+ /* Compute value count for each site. */
+ uint32_t C = 0;
+ ValueProfNode *Site = Nodes ? RuntimeRecord->NodesKind[I][J] : NULL;
+ while (Site) {
+ C++;
+ Site = Site->Next;
+ }
+ if (C > UCHAR_MAX)
+ C = UCHAR_MAX;
+ RuntimeRecord->SiteCountArray[I][J] = C;
+ }
+ S += N;
+ }
+ RuntimeRecord->NumValueKinds = NumValueKinds;
+ return 0;
+}
+
+void finalizeValueProfRuntimeRecord(ValueProfRuntimeRecord *RuntimeRecord) {
+ unsigned I;
+ for (I = 0; I <= IPVK_Last; I++) {
+ if (RuntimeRecord->SiteCountArray[I])
+ free(RuntimeRecord->SiteCountArray[I]);
+ }
+}
+
+/* ValueProfRecordClosure Interface implementation for
+ * ValueProfDataRuntimeRecord. */
+uint32_t getNumValueKindsRT(const void *R) {
+ return ((const ValueProfRuntimeRecord *)R)->NumValueKinds;
+}
+
+uint32_t getNumValueSitesRT(const void *R, uint32_t VK) {
+ return ((const ValueProfRuntimeRecord *)R)->NumValueSites[VK];
+}
+
+uint32_t getNumValueDataForSiteRT(const void *R, uint32_t VK, uint32_t S) {
+ const ValueProfRuntimeRecord *Record = (const ValueProfRuntimeRecord *)R;
+ return Record->SiteCountArray[VK][S];
+}
+
+uint32_t getNumValueDataRT(const void *R, uint32_t VK) {
+ unsigned I, S = 0;
+ const ValueProfRuntimeRecord *Record = (const ValueProfRuntimeRecord *)R;
+ if (Record->SiteCountArray[VK] == 0)
+ return 0;
+ for (I = 0; I < Record->NumValueSites[VK]; I++)
+ S += Record->SiteCountArray[VK][I];
+ return S;
+}
+
+void getValueForSiteRT(const void *R, InstrProfValueData *Dst, uint32_t VK,
+ uint32_t S, uint64_t (*Mapper)(uint32_t, uint64_t)) {
+ unsigned I, N = 0;
+ const ValueProfRuntimeRecord *Record = (const ValueProfRuntimeRecord *)R;
+ N = getNumValueDataForSiteRT(R, VK, S);
+ if (N == 0)
+ return;
+ ValueProfNode *VNode = Record->NodesKind[VK][S];
+ for (I = 0; I < N; I++) {
+ Dst[I] = VNode->VData;
+ VNode = VNode->Next;
+ }
+}
+
+ValueProfData *allocValueProfDataRT(size_t TotalSizeInBytes) {
+ return (ValueProfData *)calloc(TotalSizeInBytes, 1);
+}
+
+static ValueProfRecordClosure RTRecordClosure = {0,
+ getNumValueKindsRT,
+ getNumValueSitesRT,
+ getNumValueDataRT,
+ getNumValueDataForSiteRT,
+ 0,
+ getValueForSiteRT,
+ allocValueProfDataRT};
+
+/*
+ * Return the size of ValueProfData structure to store data
+ * recorded in the runtime record.
+ */
+uint32_t getValueProfDataSizeRT(const ValueProfRuntimeRecord *Record) {
+ RTRecordClosure.Record = Record;
+ return getValueProfDataSize(&RTRecordClosure);
+}
+
+/*
+ * Return a ValueProfData instance that stores the data collected
+ * from runtime. If \c DstData is provided by the caller, the value
+ * profile data will be store in *DstData and DstData is returned,
+ * otherwise the method will allocate space for the value data and
+ * return pointer to the newly allocated space.
+ */
+ValueProfData *
+serializeValueProfDataFromRT(const ValueProfRuntimeRecord *Record,
+ ValueProfData *DstData) {
+ RTRecordClosure.Record = Record;
+ return serializeValueProfDataFrom(&RTRecordClosure, DstData);
+}
+
+
+#undef INSTR_PROF_COMMON_API_IMPL
+#endif /* INSTR_PROF_COMMON_API_IMPL */
+
+/*============================================================================*/
+
+
+#ifndef INSTR_PROF_DATA_DEFINED
+
+#ifndef INSTR_PROF_DATA_INC_
+#define INSTR_PROF_DATA_INC_
+
+/* Helper macros. */
+#define INSTR_PROF_SIMPLE_QUOTE(x) #x
+#define INSTR_PROF_QUOTE(x) INSTR_PROF_SIMPLE_QUOTE(x)
+#define INSTR_PROF_SIMPLE_CONCAT(x,y) x ## y
+#define INSTR_PROF_CONCAT(x,y) INSTR_PROF_SIMPLE_CONCAT(x,y)
+
+/* Magic number to detect file format and endianness.
+ * Use 255 at one end, since no UTF-8 file can use that character. Avoid 0,
+ * so that utilities, like strings, don't grab it as a string. 129 is also
+ * invalid UTF-8, and high enough to be interesting.
+ * Use "lprofr" in the centre to stand for "LLVM Profile Raw", or "lprofR"
+ * for 32-bit platforms.
+ */
+#define INSTR_PROF_RAW_MAGIC_64 (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
+#define INSTR_PROF_RAW_MAGIC_32 (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
+
+/* Raw profile format version. */
+#define INSTR_PROF_RAW_VERSION 2
+
+/* Runtime section names and name strings. */
+#define INSTR_PROF_DATA_SECT_NAME __llvm_prf_data
+#define INSTR_PROF_NAME_SECT_NAME __llvm_prf_names
+#define INSTR_PROF_CNTS_SECT_NAME __llvm_prf_cnts
+
+#define INSTR_PROF_DATA_SECT_NAME_STR \
+ INSTR_PROF_QUOTE(INSTR_PROF_DATA_SECT_NAME)
+#define INSTR_PROF_NAME_SECT_NAME_STR \
+ INSTR_PROF_QUOTE(INSTR_PROF_NAME_SECT_NAME)
+#define INSTR_PROF_CNTS_SECT_NAME_STR \
+ INSTR_PROF_QUOTE(INSTR_PROF_CNTS_SECT_NAME)
+
+/* Macros to define start/stop section symbol for a given
+ * section on Linux. For instance
+ * INSTR_PROF_SECT_START(INSTR_PROF_DATA_SECT_NAME) will
+ * expand to __start___llvm_prof_data
+ */
+#define INSTR_PROF_SECT_START(Sect) \
+ INSTR_PROF_CONCAT(__start_,Sect)
+#define INSTR_PROF_SECT_STOP(Sect) \
+ INSTR_PROF_CONCAT(__stop_,Sect)
+
+/* Value Profiling API linkage name. */
+#define INSTR_PROF_VALUE_PROF_FUNC __llvm_profile_instrument_target
+#define INSTR_PROF_VALUE_PROF_FUNC_STR \
+ INSTR_PROF_QUOTE(INSTR_PROF_VALUE_PROF_FUNC)
+
+/* InstrProfile per-function control data alignment. */
+#define INSTR_PROF_DATA_ALIGNMENT 8
+
+/* The data structure that represents a tracked value by the
+ * value profiler.
+ */
+typedef struct InstrProfValueData {
+ /* Profiled value. */
+ uint64_t Value;
+ /* Number of times the value appears in the training run. */
+ uint64_t Count;
+} InstrProfValueData;
+
+/* This is an internal data structure used by value profiler. It
+ * is defined here to allow serialization code sharing by LLVM
+ * to be used in unit test.
+ */
+typedef struct ValueProfNode {
+ InstrProfValueData VData;
+ struct ValueProfNode *Next;
+} ValueProfNode;
+
+#endif /* INSTR_PROF_DATA_INC_ */
+
+#else
+#undef INSTR_PROF_DATA_DEFINED
+#endif
+
diff --git a/include/llvm/ProfileData/InstrProfReader.h b/include/llvm/ProfileData/InstrProfReader.h
index f937e7d08d544..fed3e693e7a05 100644
--- a/include/llvm/ProfileData/InstrProfReader.h
+++ b/include/llvm/ProfileData/InstrProfReader.h
@@ -23,6 +23,7 @@
#include "llvm/Support/LineIterator.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/OnDiskHashTable.h"
+#include "llvm/Support/raw_ostream.h"
#include <iterator>
namespace llvm {
@@ -53,7 +54,7 @@ class InstrProfReader {
std::error_code LastError;
public:
- InstrProfReader() : LastError(instrprof_error::success) {}
+ InstrProfReader() : LastError(instrprof_error::success), Symtab() {}
virtual ~InstrProfReader() {}
/// Read the header. Required before reading first record.
@@ -64,7 +65,20 @@ public:
InstrProfIterator begin() { return InstrProfIterator(this); }
InstrProfIterator end() { return InstrProfIterator(); }
+ /// Return the PGO symtab. There are three different readers:
+ /// Raw, Text, and Indexed profile readers. The first two types
+ /// of readers are used only by llvm-profdata tool, while the indexed
+ /// profile reader is also used by llvm-cov tool and the compiler (
+ /// backend or frontend). Since creating PGO symtab can create
+ /// significant runtime and memory overhead (as it touches data
+ /// for the whole program), InstrProfSymtab for the indexed profile
+ /// reader should be created on demand and it is recommended to be
+ /// only used for dumping purpose with llvm-proftool, not with the
+ /// compiler.
+ virtual InstrProfSymtab &getSymtab() = 0;
+
protected:
+ std::unique_ptr<InstrProfSymtab> Symtab;
/// Set the current std::error_code and return same.
std::error_code error(std::error_code EC) {
LastError = EC;
@@ -107,14 +121,24 @@ private:
TextInstrProfReader(const TextInstrProfReader &) = delete;
TextInstrProfReader &operator=(const TextInstrProfReader &) = delete;
+ std::error_code readValueProfileData(InstrProfRecord &Record);
+
public:
TextInstrProfReader(std::unique_ptr<MemoryBuffer> DataBuffer_)
: DataBuffer(std::move(DataBuffer_)), Line(*DataBuffer, true, '#') {}
+ /// Return true if the given buffer is in text instrprof format.
+ static bool hasFormat(const MemoryBuffer &Buffer);
+
/// Read the header.
- std::error_code readHeader() override { return success(); }
+ std::error_code readHeader() override;
/// Read a single record.
std::error_code readNextRecord(InstrProfRecord &Record) override;
+
+ InstrProfSymtab &getSymtab() override {
+ assert(Symtab.get());
+ return *Symtab.get();
+ }
};
/// Reader for the raw instrprof binary format from runtime.
@@ -129,31 +153,19 @@ class RawInstrProfReader : public InstrProfReader {
private:
/// The profile data file contents.
std::unique_ptr<MemoryBuffer> DataBuffer;
- struct ProfileData {
- const uint32_t NameSize;
- const uint32_t NumCounters;
- const uint64_t FuncHash;
- const IntPtrT NamePtr;
- const IntPtrT CounterPtr;
- };
- struct RawHeader {
- const uint64_t Magic;
- const uint64_t Version;
- const uint64_t DataSize;
- const uint64_t CountersSize;
- const uint64_t NamesSize;
- const uint64_t CountersDelta;
- const uint64_t NamesDelta;
- };
-
bool ShouldSwapBytes;
uint64_t CountersDelta;
uint64_t NamesDelta;
- const ProfileData *Data;
- const ProfileData *DataEnd;
+ const RawInstrProf::ProfileData<IntPtrT> *Data;
+ const RawInstrProf::ProfileData<IntPtrT> *DataEnd;
const uint64_t *CountersStart;
const char *NamesStart;
+ const uint8_t *ValueDataStart;
const char *ProfileEnd;
+ uint32_t ValueKindLast;
+ uint32_t CurValueDataSize;
+
+ InstrProfRecord::ValueMapType FunctionPtrToNameMap;
RawInstrProfReader(const RawInstrProfReader &) = delete;
RawInstrProfReader &operator=(const RawInstrProfReader &) = delete;
@@ -165,13 +177,41 @@ public:
std::error_code readHeader() override;
std::error_code readNextRecord(InstrProfRecord &Record) override;
+ InstrProfSymtab &getSymtab() override {
+ assert(Symtab.get());
+ return *Symtab.get();
+ }
+
private:
+ void createSymtab(InstrProfSymtab &Symtab);
std::error_code readNextHeader(const char *CurrentPos);
- std::error_code readHeader(const RawHeader &Header);
- template <class IntT>
- IntT swap(IntT Int) const {
+ std::error_code readHeader(const RawInstrProf::Header &Header);
+ template <class IntT> IntT swap(IntT Int) const {
return ShouldSwapBytes ? sys::getSwappedBytes(Int) : Int;
}
+ support::endianness getDataEndianness() const {
+ support::endianness HostEndian = getHostEndianness();
+ if (!ShouldSwapBytes)
+ return HostEndian;
+ if (HostEndian == support::little)
+ return support::big;
+ else
+ return support::little;
+ }
+
+ inline uint8_t getNumPaddingBytes(uint64_t SizeInBytes) {
+ return 7 & (sizeof(uint64_t) - SizeInBytes % sizeof(uint64_t));
+ }
+ std::error_code readName(InstrProfRecord &Record);
+ std::error_code readFuncHash(InstrProfRecord &Record);
+ std::error_code readRawCounts(InstrProfRecord &Record);
+ std::error_code readValueProfilingData(InstrProfRecord &Record);
+ bool atEnd() const { return Data == DataEnd; }
+ void advanceData() {
+ Data++;
+ ValueDataStart += CurValueDataSize;
+ }
+
const uint64_t *getCounter(IntPtrT CounterPtr) const {
ptrdiff_t Offset = (swap(CounterPtr) - CountersDelta) / sizeof(uint64_t);
return CountersStart + Offset;
@@ -195,10 +235,15 @@ class InstrProfLookupTrait {
std::vector<InstrProfRecord> DataBuffer;
IndexedInstrProf::HashT HashType;
unsigned FormatVersion;
+ // Endianness of the input value profile data.
+ // It should be LE by default, but can be changed
+ // for testing purpose.
+ support::endianness ValueProfDataEndianness;
public:
InstrProfLookupTrait(IndexedInstrProf::HashT HashType, unsigned FormatVersion)
- : HashType(HashType), FormatVersion(FormatVersion) {}
+ : HashType(HashType), FormatVersion(FormatVersion),
+ ValueProfDataEndianness(support::little) {}
typedef ArrayRef<InstrProfRecord> data_type;
@@ -209,6 +254,7 @@ public:
static bool EqualKey(StringRef A, StringRef B) { return A == B; }
static StringRef GetInternalKey(StringRef K) { return K; }
+ static StringRef GetExternalKey(StringRef K) { return K; }
hash_value_type ComputeHash(StringRef K);
@@ -224,11 +270,64 @@ public:
return StringRef((const char *)D, N);
}
+ bool readValueProfilingData(const unsigned char *&D,
+ const unsigned char *const End);
data_type ReadData(StringRef K, const unsigned char *D, offset_type N);
+
+ // Used for testing purpose only.
+ void setValueProfDataEndianness(support::endianness Endianness) {
+ ValueProfDataEndianness = Endianness;
+ }
+};
+
+struct InstrProfReaderIndexBase {
+ // Read all the profile records with the same key pointed to the current
+ // iterator.
+ virtual std::error_code getRecords(ArrayRef<InstrProfRecord> &Data) = 0;
+ // Read all the profile records with the key equal to FuncName
+ virtual std::error_code getRecords(StringRef FuncName,
+ ArrayRef<InstrProfRecord> &Data) = 0;
+ virtual void advanceToNextKey() = 0;
+ virtual bool atEnd() const = 0;
+ virtual void setValueProfDataEndianness(support::endianness Endianness) = 0;
+ virtual ~InstrProfReaderIndexBase() {}
+ virtual uint64_t getVersion() const = 0;
+ virtual void populateSymtab(InstrProfSymtab &) = 0;
};
typedef OnDiskIterableChainedHashTable<InstrProfLookupTrait>
- InstrProfReaderIndex;
+ OnDiskHashTableImplV3;
+
+template <typename HashTableImpl>
+class InstrProfReaderIndex : public InstrProfReaderIndexBase {
+
+private:
+ std::unique_ptr<HashTableImpl> HashTable;
+ typename HashTableImpl::data_iterator RecordIterator;
+ uint64_t FormatVersion;
+
+public:
+ InstrProfReaderIndex(const unsigned char *Buckets,
+ const unsigned char *const Payload,
+ const unsigned char *const Base,
+ IndexedInstrProf::HashT HashType, uint64_t Version);
+
+ std::error_code getRecords(ArrayRef<InstrProfRecord> &Data) override;
+ std::error_code getRecords(StringRef FuncName,
+ ArrayRef<InstrProfRecord> &Data) override;
+ void advanceToNextKey() override { RecordIterator++; }
+ bool atEnd() const override {
+ return RecordIterator == HashTable->data_end();
+ }
+ void setValueProfDataEndianness(support::endianness Endianness) override {
+ HashTable->getInfoObj().setValueProfDataEndianness(Endianness);
+ }
+ ~InstrProfReaderIndex() override {}
+ uint64_t getVersion() const override { return FormatVersion; }
+ void populateSymtab(InstrProfSymtab &Symtab) override {
+ Symtab.create(HashTable->keys());
+ }
+};
/// Reader for the indexed binary instrprof format.
class IndexedInstrProfReader : public InstrProfReader {
@@ -236,17 +335,15 @@ private:
/// The profile data file contents.
std::unique_ptr<MemoryBuffer> DataBuffer;
/// The index into the profile data.
- std::unique_ptr<InstrProfReaderIndex> Index;
- /// Iterator over the profile data.
- InstrProfReaderIndex::data_iterator RecordIterator;
- /// The file format version of the profile data.
- uint64_t FormatVersion;
+ std::unique_ptr<InstrProfReaderIndexBase> Index;
/// The maximal execution count among all functions.
uint64_t MaxFunctionCount;
IndexedInstrProfReader(const IndexedInstrProfReader &) = delete;
IndexedInstrProfReader &operator=(const IndexedInstrProfReader &) = delete;
+
public:
+ uint64_t getVersion() const { return Index->getVersion(); }
IndexedInstrProfReader(std::unique_ptr<MemoryBuffer> DataBuffer)
: DataBuffer(std::move(DataBuffer)), Index(nullptr) {}
@@ -258,9 +355,15 @@ public:
/// Read a single record.
std::error_code readNextRecord(InstrProfRecord &Record) override;
+ /// Return the pointer to InstrProfRecord associated with FuncName
+ /// and FuncHash
+ ErrorOr<InstrProfRecord> getInstrProfRecord(StringRef FuncName,
+ uint64_t FuncHash);
+
/// Fill Counts with the profile data for the given function name.
std::error_code getFunctionCounts(StringRef FuncName, uint64_t FuncHash,
std::vector<uint64_t> &Counts);
+
/// Return the maximum of all known function counts.
uint64_t getMaximumFunctionCount() { return MaxFunctionCount; }
@@ -270,6 +373,16 @@ public:
static ErrorOr<std::unique_ptr<IndexedInstrProfReader>>
create(std::unique_ptr<MemoryBuffer> Buffer);
+
+ // Used for testing purpose only.
+ void setValueProfDataEndianness(support::endianness Endianness) {
+ Index->setValueProfDataEndianness(Endianness);
+ }
+
+ // See description in the base class. This interface is designed
+ // to be used by llvm-profdata (for dumping). Avoid using this when
+ // the client is the compiler.
+ InstrProfSymtab &getSymtab() override;
};
} // end namespace llvm
diff --git a/include/llvm/ProfileData/InstrProfWriter.h b/include/llvm/ProfileData/InstrProfWriter.h
index ce0bb52424988..e7f53de051c3c 100644
--- a/include/llvm/ProfileData/InstrProfWriter.h
+++ b/include/llvm/ProfileData/InstrProfWriter.h
@@ -15,38 +15,43 @@
#ifndef LLVM_PROFILEDATA_INSTRPROFWRITER_H
#define LLVM_PROFILEDATA_INSTRPROFWRITER_H
-#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/StringMap.h"
#include "llvm/ProfileData/InstrProf.h"
#include "llvm/Support/DataTypes.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
-#include <vector>
namespace llvm {
/// Writer for instrumentation based profile data.
class InstrProfWriter {
public:
- typedef SmallDenseMap<uint64_t, std::vector<uint64_t>, 1> CounterData;
+ typedef SmallDenseMap<uint64_t, InstrProfRecord, 1> ProfilingData;
+
private:
- StringMap<CounterData> FunctionData;
+ StringMap<ProfilingData> FunctionData;
uint64_t MaxFunctionCount;
+
public:
InstrProfWriter() : MaxFunctionCount(0) {}
/// Add function counts for the given function. If there are already counts
/// for this function and the hash and number of counts match, each counter is
- /// summed.
- std::error_code addFunctionCounts(StringRef FunctionName,
- uint64_t FunctionHash,
- ArrayRef<uint64_t> Counters);
+ /// summed. Optionally scale counts by \p Weight.
+ std::error_code addRecord(InstrProfRecord &&I, uint64_t Weight = 1);
/// Write the profile to \c OS
void write(raw_fd_ostream &OS);
+ /// Write the profile in text format to \c OS
+ void writeText(raw_fd_ostream &OS);
+ /// Write \c Record in text format to \c OS
+ static void writeRecordInText(const InstrProfRecord &Record,
+ InstrProfSymtab &Symtab, raw_fd_ostream &OS);
/// Write the profile, returning the raw data. For testing.
std::unique_ptr<MemoryBuffer> writeBuffer();
+ // Internal interface for testing purpose only.
+ void setValueProfDataEndianness(support::endianness Endianness);
+
private:
std::pair<uint64_t, uint64_t> writeImpl(raw_ostream &OS);
};
diff --git a/include/llvm/ProfileData/SampleProf.h b/include/llvm/ProfileData/SampleProf.h
index 1b82e55aa77a8..8df3fe8032093 100644
--- a/include/llvm/ProfileData/SampleProf.h
+++ b/include/llvm/ProfileData/SampleProf.h
@@ -11,14 +11,17 @@
// sample profile data.
//
//===----------------------------------------------------------------------===//
+
#ifndef LLVM_PROFILEDATA_SAMPLEPROF_H_
#define LLVM_PROFILEDATA_SAMPLEPROF_H_
-#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/raw_ostream.h"
+
+#include <map>
#include <system_error>
namespace llvm {
@@ -32,13 +35,27 @@ enum class sampleprof_error {
too_large,
truncated,
malformed,
- unrecognized_format
+ unrecognized_format,
+ unsupported_writing_format,
+ truncated_name_table,
+ not_implemented,
+ counter_overflow
};
inline std::error_code make_error_code(sampleprof_error E) {
return std::error_code(static_cast<int>(E), sampleprof_category());
}
+inline sampleprof_error MergeResult(sampleprof_error &Accumulator,
+ sampleprof_error Result) {
+ // Prefer first error encountered as later errors may be secondary effects of
+ // the initial problem.
+ if (Accumulator == sampleprof_error::success &&
+ Result != sampleprof_error::success)
+ Accumulator = Result;
+ return Accumulator;
+}
+
} // end namespace llvm
namespace std {
@@ -57,7 +74,7 @@ static inline uint64_t SPMagic() {
uint64_t('2') << (64 - 56) | uint64_t(0xff);
}
-static inline uint64_t SPVersion() { return 100; }
+static inline uint64_t SPVersion() { return 102; }
/// Represents the relative location of an instruction.
///
@@ -69,36 +86,36 @@ static inline uint64_t SPVersion() { return 100; }
/// that are on the same line but belong to different basic blocks
/// (e.g., the two post-increment instructions in "if (p) x++; else y++;").
struct LineLocation {
- LineLocation(int L, unsigned D) : LineOffset(L), Discriminator(D) {}
- int LineOffset;
- unsigned Discriminator;
+ LineLocation(uint32_t L, uint32_t D) : LineOffset(L), Discriminator(D) {}
+ void print(raw_ostream &OS) const;
+ void dump() const;
+ bool operator<(const LineLocation &O) const {
+ return LineOffset < O.LineOffset ||
+ (LineOffset == O.LineOffset && Discriminator < O.Discriminator);
+ }
+
+ uint32_t LineOffset;
+ uint32_t Discriminator;
};
-} // End namespace sampleprof
+raw_ostream &operator<<(raw_ostream &OS, const LineLocation &Loc);
-template <> struct DenseMapInfo<sampleprof::LineLocation> {
- typedef DenseMapInfo<int> OffsetInfo;
- typedef DenseMapInfo<unsigned> DiscriminatorInfo;
- static inline sampleprof::LineLocation getEmptyKey() {
- return sampleprof::LineLocation(OffsetInfo::getEmptyKey(),
- DiscriminatorInfo::getEmptyKey());
- }
- static inline sampleprof::LineLocation getTombstoneKey() {
- return sampleprof::LineLocation(OffsetInfo::getTombstoneKey(),
- DiscriminatorInfo::getTombstoneKey());
- }
- static inline unsigned getHashValue(sampleprof::LineLocation Val) {
- return DenseMapInfo<std::pair<int, unsigned>>::getHashValue(
- std::pair<int, unsigned>(Val.LineOffset, Val.Discriminator));
- }
- static inline bool isEqual(sampleprof::LineLocation LHS,
- sampleprof::LineLocation RHS) {
- return LHS.LineOffset == RHS.LineOffset &&
- LHS.Discriminator == RHS.Discriminator;
- }
+/// Represents the relative location of a callsite.
+///
+/// Callsite locations are specified by the line offset from the
+/// beginning of the function (marked by the line where the function
+/// head is), the discriminator value within that line, and the callee
+/// function name.
+struct CallsiteLocation : public LineLocation {
+ CallsiteLocation(uint32_t L, uint32_t D, StringRef N)
+ : LineLocation(L, D), CalleeName(N) {}
+ void print(raw_ostream &OS) const;
+ void dump() const;
+
+ StringRef CalleeName;
};
-namespace sampleprof {
+raw_ostream &operator<<(raw_ostream &OS, const CallsiteLocation &Loc);
/// Representation of a single sample record.
///
@@ -112,52 +129,79 @@ namespace sampleprof {
/// will be a list of one or more functions.
class SampleRecord {
public:
- typedef StringMap<unsigned> CallTargetMap;
+ typedef StringMap<uint64_t> CallTargetMap;
SampleRecord() : NumSamples(0), CallTargets() {}
/// Increment the number of samples for this record by \p S.
+ /// Optionally scale sample count \p S by \p Weight.
///
/// Sample counts accumulate using saturating arithmetic, to avoid wrapping
/// around unsigned integers.
- void addSamples(unsigned S) {
- if (NumSamples <= std::numeric_limits<unsigned>::max() - S)
- NumSamples += S;
- else
- NumSamples = std::numeric_limits<unsigned>::max();
+ sampleprof_error addSamples(uint64_t S, uint64_t Weight = 1) {
+ bool Overflowed;
+ if (Weight > 1) {
+ S = SaturatingMultiply(S, Weight, &Overflowed);
+ if (Overflowed)
+ return sampleprof_error::counter_overflow;
+ }
+ NumSamples = SaturatingAdd(NumSamples, S, &Overflowed);
+ if (Overflowed)
+ return sampleprof_error::counter_overflow;
+
+ return sampleprof_error::success;
}
/// Add called function \p F with samples \p S.
+ /// Optionally scale sample count \p S by \p Weight.
///
/// Sample counts accumulate using saturating arithmetic, to avoid wrapping
/// around unsigned integers.
- void addCalledTarget(StringRef F, unsigned S) {
- unsigned &TargetSamples = CallTargets[F];
- if (TargetSamples <= std::numeric_limits<unsigned>::max() - S)
- TargetSamples += S;
- else
- TargetSamples = std::numeric_limits<unsigned>::max();
+ sampleprof_error addCalledTarget(StringRef F, uint64_t S,
+ uint64_t Weight = 1) {
+ uint64_t &TargetSamples = CallTargets[F];
+ bool Overflowed;
+ if (Weight > 1) {
+ S = SaturatingMultiply(S, Weight, &Overflowed);
+ if (Overflowed)
+ return sampleprof_error::counter_overflow;
+ }
+ TargetSamples = SaturatingAdd(TargetSamples, S, &Overflowed);
+ if (Overflowed)
+ return sampleprof_error::counter_overflow;
+
+ return sampleprof_error::success;
}
/// Return true if this sample record contains function calls.
bool hasCalls() const { return CallTargets.size() > 0; }
- unsigned getSamples() const { return NumSamples; }
+ uint64_t getSamples() const { return NumSamples; }
const CallTargetMap &getCallTargets() const { return CallTargets; }
/// Merge the samples in \p Other into this record.
- void merge(const SampleRecord &Other) {
- addSamples(Other.getSamples());
- for (const auto &I : Other.getCallTargets())
- addCalledTarget(I.first(), I.second);
+ /// Optionally scale sample counts by \p Weight.
+ sampleprof_error merge(const SampleRecord &Other, uint64_t Weight = 1) {
+ sampleprof_error Result = addSamples(Other.getSamples(), Weight);
+ for (const auto &I : Other.getCallTargets()) {
+ MergeResult(Result, addCalledTarget(I.first(), I.second, Weight));
+ }
+ return Result;
}
+ void print(raw_ostream &OS, unsigned Indent) const;
+ void dump() const;
+
private:
- unsigned NumSamples;
+ uint64_t NumSamples;
CallTargetMap CallTargets;
};
-typedef DenseMap<LineLocation, SampleRecord> BodySampleMap;
+raw_ostream &operator<<(raw_ostream &OS, const SampleRecord &Sample);
+
+typedef std::map<LineLocation, SampleRecord> BodySampleMap;
+class FunctionSamples;
+typedef std::map<CallsiteLocation, FunctionSamples> CallsiteSampleMap;
/// Representation of the samples collected for a function.
///
@@ -167,59 +211,109 @@ typedef DenseMap<LineLocation, SampleRecord> BodySampleMap;
class FunctionSamples {
public:
FunctionSamples() : TotalSamples(0), TotalHeadSamples(0) {}
- void print(raw_ostream &OS = dbgs());
- void addTotalSamples(unsigned Num) { TotalSamples += Num; }
- void addHeadSamples(unsigned Num) { TotalHeadSamples += Num; }
- void addBodySamples(int LineOffset, unsigned Discriminator, unsigned Num) {
- assert(LineOffset >= 0);
- // When dealing with instruction weights, we use the value
- // zero to indicate the absence of a sample. If we read an
- // actual zero from the profile file, use the value 1 to
- // avoid the confusion later on.
- if (Num == 0)
- Num = 1;
- BodySamples[LineLocation(LineOffset, Discriminator)].addSamples(Num);
- }
- void addCalledTargetSamples(int LineOffset, unsigned Discriminator,
- std::string FName, unsigned Num) {
- assert(LineOffset >= 0);
- BodySamples[LineLocation(LineOffset, Discriminator)].addCalledTarget(FName,
- Num);
+ void print(raw_ostream &OS = dbgs(), unsigned Indent = 0) const;
+ void dump() const;
+ sampleprof_error addTotalSamples(uint64_t Num, uint64_t Weight = 1) {
+ bool Overflowed;
+ if (Weight > 1) {
+ Num = SaturatingMultiply(Num, Weight, &Overflowed);
+ if (Overflowed)
+ return sampleprof_error::counter_overflow;
+ }
+ TotalSamples = SaturatingAdd(TotalSamples, Num, &Overflowed);
+ if (Overflowed)
+ return sampleprof_error::counter_overflow;
+
+ return sampleprof_error::success;
}
+ sampleprof_error addHeadSamples(uint64_t Num, uint64_t Weight = 1) {
+ bool Overflowed;
+ if (Weight > 1) {
+ Num = SaturatingMultiply(Num, Weight, &Overflowed);
+ if (Overflowed)
+ return sampleprof_error::counter_overflow;
+ }
+ TotalHeadSamples = SaturatingAdd(TotalHeadSamples, Num, &Overflowed);
+ if (Overflowed)
+ return sampleprof_error::counter_overflow;
- /// Return the sample record at the given location.
- /// Each location is specified by \p LineOffset and \p Discriminator.
- SampleRecord &sampleRecordAt(const LineLocation &Loc) {
- return BodySamples[Loc];
+ return sampleprof_error::success;
+ }
+ sampleprof_error addBodySamples(uint32_t LineOffset, uint32_t Discriminator,
+ uint64_t Num, uint64_t Weight = 1) {
+ return BodySamples[LineLocation(LineOffset, Discriminator)].addSamples(
+ Num, Weight);
+ }
+ sampleprof_error addCalledTargetSamples(uint32_t LineOffset,
+ uint32_t Discriminator,
+ std::string FName, uint64_t Num,
+ uint64_t Weight = 1) {
+ return BodySamples[LineLocation(LineOffset, Discriminator)].addCalledTarget(
+ FName, Num, Weight);
}
/// Return the number of samples collected at the given location.
/// Each location is specified by \p LineOffset and \p Discriminator.
- unsigned samplesAt(int LineOffset, unsigned Discriminator) {
- return sampleRecordAt(LineLocation(LineOffset, Discriminator)).getSamples();
+ /// If the location is not found in profile, return error.
+ ErrorOr<uint64_t> findSamplesAt(uint32_t LineOffset,
+ uint32_t Discriminator) const {
+ const auto &ret = BodySamples.find(LineLocation(LineOffset, Discriminator));
+ if (ret == BodySamples.end())
+ return std::error_code();
+ else
+ return ret->second.getSamples();
}
- bool empty() const { return BodySamples.empty(); }
+ /// Return the function samples at the given callsite location.
+ FunctionSamples &functionSamplesAt(const CallsiteLocation &Loc) {
+ return CallsiteSamples[Loc];
+ }
+
+ /// Return a pointer to function samples at the given callsite location.
+ const FunctionSamples *
+ findFunctionSamplesAt(const CallsiteLocation &Loc) const {
+ auto iter = CallsiteSamples.find(Loc);
+ if (iter == CallsiteSamples.end()) {
+ return nullptr;
+ } else {
+ return &iter->second;
+ }
+ }
+
+ bool empty() const { return TotalSamples == 0; }
/// Return the total number of samples collected inside the function.
- unsigned getTotalSamples() const { return TotalSamples; }
+ uint64_t getTotalSamples() const { return TotalSamples; }
/// Return the total number of samples collected at the head of the
/// function.
- unsigned getHeadSamples() const { return TotalHeadSamples; }
+ uint64_t getHeadSamples() const { return TotalHeadSamples; }
/// Return all the samples collected in the body of the function.
const BodySampleMap &getBodySamples() const { return BodySamples; }
+ /// Return all the callsite samples collected in the body of the function.
+ const CallsiteSampleMap &getCallsiteSamples() const {
+ return CallsiteSamples;
+ }
+
/// Merge the samples in \p Other into this one.
- void merge(const FunctionSamples &Other) {
- addTotalSamples(Other.getTotalSamples());
- addHeadSamples(Other.getHeadSamples());
+ /// Optionally scale samples by \p Weight.
+ sampleprof_error merge(const FunctionSamples &Other, uint64_t Weight = 1) {
+ sampleprof_error Result = sampleprof_error::success;
+ MergeResult(Result, addTotalSamples(Other.getTotalSamples(), Weight));
+ MergeResult(Result, addHeadSamples(Other.getHeadSamples(), Weight));
for (const auto &I : Other.getBodySamples()) {
const LineLocation &Loc = I.first;
const SampleRecord &Rec = I.second;
- sampleRecordAt(Loc).merge(Rec);
+ MergeResult(Result, BodySamples[Loc].merge(Rec, Weight));
+ }
+ for (const auto &I : Other.getCallsiteSamples()) {
+ const CallsiteLocation &Loc = I.first;
+ const FunctionSamples &Rec = I.second;
+ MergeResult(Result, functionSamplesAt(Loc).merge(Rec, Weight));
}
+ return Result;
}
private:
@@ -227,12 +321,12 @@ private:
///
/// Samples are cumulative, they include all the samples collected
/// inside this function and all its inlined callees.
- unsigned TotalSamples;
+ uint64_t TotalSamples;
/// Total number of samples collected at the head of the function.
/// This is an approximation of the number of calls made to this function
/// at runtime.
- unsigned TotalHeadSamples;
+ uint64_t TotalHeadSamples;
/// Map instruction locations to collected samples.
///
@@ -240,10 +334,53 @@ private:
/// collected at the corresponding line offset. All line locations
/// are an offset from the start of the function.
BodySampleMap BodySamples;
+
+ /// Map call sites to collected samples for the called function.
+ ///
+ /// Each entry in this map corresponds to all the samples
+ /// collected for the inlined function call at the given
+ /// location. For example, given:
+ ///
+ /// void foo() {
+ /// 1 bar();
+ /// ...
+ /// 8 baz();
+ /// }
+ ///
+ /// If the bar() and baz() calls were inlined inside foo(), this
+ /// map will contain two entries. One for all the samples collected
+ /// in the call to bar() at line offset 1, the other for all the samples
+ /// collected in the call to baz() at line offset 8.
+ CallsiteSampleMap CallsiteSamples;
};
-} // End namespace sampleprof
+raw_ostream &operator<<(raw_ostream &OS, const FunctionSamples &FS);
-} // End namespace llvm
+/// Sort a LocationT->SampleT map by LocationT.
+///
+/// It produces a sorted list of <LocationT, SampleT> records by ascending
+/// order of LocationT.
+template <class LocationT, class SampleT> class SampleSorter {
+public:
+ typedef std::pair<const LocationT, SampleT> SamplesWithLoc;
+ typedef SmallVector<const SamplesWithLoc *, 20> SamplesWithLocList;
+
+ SampleSorter(const std::map<LocationT, SampleT> &Samples) {
+ for (const auto &I : Samples)
+ V.push_back(&I);
+ std::stable_sort(V.begin(), V.end(),
+ [](const SamplesWithLoc *A, const SamplesWithLoc *B) {
+ return A->first < B->first;
+ });
+ }
+ const SamplesWithLocList &get() const { return V; }
+
+private:
+ SamplesWithLocList V;
+};
+
+} // end namespace sampleprof
+
+} // end namespace llvm
#endif // LLVM_PROFILEDATA_SAMPLEPROF_H_
diff --git a/include/llvm/ProfileData/SampleProfReader.h b/include/llvm/ProfileData/SampleProfReader.h
index c082a1abe9519..6db0fbb0e7abf 100644
--- a/include/llvm/ProfileData/SampleProfReader.h
+++ b/include/llvm/ProfileData/SampleProfReader.h
@@ -9,11 +9,181 @@
//
// This file contains definitions needed for reading sample profiles.
//
+// NOTE: If you are making changes to this file format, please remember
+// to document them in the Clang documentation at
+// tools/clang/docs/UsersManual.rst.
+//
+// Text format
+// -----------
+//
+// Sample profiles are written as ASCII text. The file is divided into
+// sections, which correspond to each of the functions executed at runtime.
+// Each section has the following format
+//
+// function1:total_samples:total_head_samples
+// offset1[.discriminator]: number_of_samples [fn1:num fn2:num ... ]
+// offset2[.discriminator]: number_of_samples [fn3:num fn4:num ... ]
+// ...
+// offsetN[.discriminator]: number_of_samples [fn5:num fn6:num ... ]
+// offsetA[.discriminator]: fnA:num_of_total_samples
+// offsetA1[.discriminator]: number_of_samples [fn7:num fn8:num ... ]
+// ...
+//
+// This is a nested tree in which the identation represents the nesting level
+// of the inline stack. There are no blank lines in the file. And the spacing
+// within a single line is fixed. Additional spaces will result in an error
+// while reading the file.
+//
+// Any line starting with the '#' character is completely ignored.
+//
+// Inlined calls are represented with indentation. The Inline stack is a
+// stack of source locations in which the top of the stack represents the
+// leaf function, and the bottom of the stack represents the actual
+// symbol to which the instruction belongs.
+//
+// Function names must be mangled in order for the profile loader to
+// match them in the current translation unit. The two numbers in the
+// function header specify how many total samples were accumulated in the
+// function (first number), and the total number of samples accumulated
+// in the prologue of the function (second number). This head sample
+// count provides an indicator of how frequently the function is invoked.
+//
+// There are two types of lines in the function body.
+//
+// * Sampled line represents the profile information of a source location.
+// * Callsite line represents the profile information of a callsite.
+//
+// Each sampled line may contain several items. Some are optional (marked
+// below):
+//
+// a. Source line offset. This number represents the line number
+// in the function where the sample was collected. The line number is
+// always relative to the line where symbol of the function is
+// defined. So, if the function has its header at line 280, the offset
+// 13 is at line 293 in the file.
+//
+// Note that this offset should never be a negative number. This could
+// happen in cases like macros. The debug machinery will register the
+// line number at the point of macro expansion. So, if the macro was
+// expanded in a line before the start of the function, the profile
+// converter should emit a 0 as the offset (this means that the optimizers
+// will not be able to associate a meaningful weight to the instructions
+// in the macro).
+//
+// b. [OPTIONAL] Discriminator. This is used if the sampled program
+// was compiled with DWARF discriminator support
+// (http://wiki.dwarfstd.org/index.php?title=Path_Discriminators).
+// DWARF discriminators are unsigned integer values that allow the
+// compiler to distinguish between multiple execution paths on the
+// same source line location.
+//
+// For example, consider the line of code ``if (cond) foo(); else bar();``.
+// If the predicate ``cond`` is true 80% of the time, then the edge
+// into function ``foo`` should be considered to be taken most of the
+// time. But both calls to ``foo`` and ``bar`` are at the same source
+// line, so a sample count at that line is not sufficient. The
+// compiler needs to know which part of that line is taken more
+// frequently.
+//
+// This is what discriminators provide. In this case, the calls to
+// ``foo`` and ``bar`` will be at the same line, but will have
+// different discriminator values. This allows the compiler to correctly
+// set edge weights into ``foo`` and ``bar``.
+//
+// c. Number of samples. This is an integer quantity representing the
+// number of samples collected by the profiler at this source
+// location.
+//
+// d. [OPTIONAL] Potential call targets and samples. If present, this
+// line contains a call instruction. This models both direct and
+// number of samples. For example,
+//
+// 130: 7 foo:3 bar:2 baz:7
+//
+// The above means that at relative line offset 130 there is a call
+// instruction that calls one of ``foo()``, ``bar()`` and ``baz()``,
+// with ``baz()`` being the relatively more frequently called target.
+//
+// Each callsite line may contain several items. Some are optional.
+//
+// a. Source line offset. This number represents the line number of the
+// callsite that is inlined in the profiled binary.
+//
+// b. [OPTIONAL] Discriminator. Same as the discriminator for sampled line.
+//
+// c. Number of samples. This is an integer quantity representing the
+// total number of samples collected for the inlined instance at this
+// callsite
+//
+//
+// Binary format
+// -------------
+//
+// This is a more compact encoding. Numbers are encoded as ULEB128 values
+// and all strings are encoded in a name table. The file is organized in
+// the following sections:
+//
+// MAGIC (uint64_t)
+// File identifier computed by function SPMagic() (0x5350524f463432ff)
+//
+// VERSION (uint32_t)
+// File format version number computed by SPVersion()
+//
+// NAME TABLE
+// SIZE (uint32_t)
+// Number of entries in the name table.
+// NAMES
+// A NUL-separated list of SIZE strings.
+//
+// FUNCTION BODY (one for each uninlined function body present in the profile)
+// HEAD_SAMPLES (uint64_t) [only for top-level functions]
+// Total number of samples collected at the head (prologue) of the
+// function.
+// NOTE: This field should only be present for top-level functions
+// (i.e., not inlined into any caller). Inlined function calls
+// have no prologue, so they don't need this.
+// NAME_IDX (uint32_t)
+// Index into the name table indicating the function name.
+// SAMPLES (uint64_t)
+// Total number of samples collected in this function.
+// NRECS (uint32_t)
+// Total number of sampling records this function's profile.
+// BODY RECORDS
+// A list of NRECS entries. Each entry contains:
+// OFFSET (uint32_t)
+// Line offset from the start of the function.
+// DISCRIMINATOR (uint32_t)
+// Discriminator value (see description of discriminators
+// in the text format documentation above).
+// SAMPLES (uint64_t)
+// Number of samples collected at this location.
+// NUM_CALLS (uint32_t)
+// Number of non-inlined function calls made at this location. In the
+// case of direct calls, this number will always be 1. For indirect
+// calls (virtual functions and function pointers) this will
+// represent all the actual functions called at runtime.
+// CALL_TARGETS
+// A list of NUM_CALLS entries for each called function:
+// NAME_IDX (uint32_t)
+// Index into the name table with the callee name.
+// SAMPLES (uint64_t)
+// Number of samples collected at the call site.
+// NUM_INLINED_FUNCTIONS (uint32_t)
+// Number of callees inlined into this function.
+// INLINED FUNCTION RECORDS
+// A list of NUM_INLINED_FUNCTIONS entries describing each of the inlined
+// callees.
+// OFFSET (uint32_t)
+// Line offset from the start of the function.
+// DISCRIMINATOR (uint32_t)
+// Discriminator value (see description of discriminators
+// in the text format documentation above).
+// FUNCTION BODY
+// A FUNCTION BODY entry describing the inlined function.
//===----------------------------------------------------------------------===//
#ifndef LLVM_PROFILEDATA_SAMPLEPROFREADER_H
#define LLVM_PROFILEDATA_SAMPLEPROFREADER_H
-#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
@@ -24,6 +194,7 @@
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/GCOV.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
@@ -57,7 +228,7 @@ namespace sampleprof {
///
/// The reader supports two file formats: text and binary. The text format
/// is useful for debugging and testing, while the binary format is more
-/// compact. They can both be used interchangeably.
+/// compact and I/O efficient. They can both be used interchangeably.
class SampleProfileReader {
public:
SampleProfileReader(std::unique_ptr<MemoryBuffer> B, LLVMContext &C)
@@ -86,7 +257,7 @@ public:
StringMap<FunctionSamples> &getProfiles() { return Profiles; }
/// \brief Report a parse error message.
- void reportParseError(int64_t LineNumber, Twine Msg) const {
+ void reportError(int64_t LineNumber, Twine Msg) const {
Ctx.diagnose(DiagnosticInfoSampleProfile(Buffer->getBufferIdentifier(),
LineNumber, Msg));
}
@@ -95,6 +266,10 @@ public:
static ErrorOr<std::unique_ptr<SampleProfileReader>>
create(StringRef Filename, LLVMContext &C);
+ /// \brief Create a sample profile reader from the supplied memory buffer.
+ static ErrorOr<std::unique_ptr<SampleProfileReader>>
+ create(std::unique_ptr<MemoryBuffer> &B, LLVMContext &C);
+
protected:
/// \brief Map every function to its associated profile.
///
@@ -120,6 +295,9 @@ public:
/// \brief Read sample profiles from the associated file.
std::error_code read() override;
+
+ /// \brief Return true if \p Buffer is in the format supported by this class.
+ static bool hasFormat(const MemoryBuffer &Buffer);
};
class SampleProfileReaderBinary : public SampleProfileReader {
@@ -153,14 +331,75 @@ protected:
/// \returns the read value.
ErrorOr<StringRef> readString();
+ /// Read a string indirectly via the name table.
+ ErrorOr<StringRef> readStringFromTable();
+
/// \brief Return true if we've reached the end of file.
bool at_eof() const { return Data >= End; }
+ /// Read the contents of the given profile instance.
+ std::error_code readProfile(FunctionSamples &FProfile);
+
/// \brief Points to the current location in the buffer.
const uint8_t *Data;
/// \brief Points to the end of the buffer.
const uint8_t *End;
+
+ /// Function name table.
+ std::vector<StringRef> NameTable;
+};
+
+typedef SmallVector<FunctionSamples *, 10> InlineCallStack;
+
+// Supported histogram types in GCC. Currently, we only need support for
+// call target histograms.
+enum HistType {
+ HIST_TYPE_INTERVAL,
+ HIST_TYPE_POW2,
+ HIST_TYPE_SINGLE_VALUE,
+ HIST_TYPE_CONST_DELTA,
+ HIST_TYPE_INDIR_CALL,
+ HIST_TYPE_AVERAGE,
+ HIST_TYPE_IOR,
+ HIST_TYPE_INDIR_CALL_TOPN
+};
+
+class SampleProfileReaderGCC : public SampleProfileReader {
+public:
+ SampleProfileReaderGCC(std::unique_ptr<MemoryBuffer> B, LLVMContext &C)
+ : SampleProfileReader(std::move(B), C), GcovBuffer(Buffer.get()) {}
+
+ /// \brief Read and validate the file header.
+ std::error_code readHeader() override;
+
+ /// \brief Read sample profiles from the associated file.
+ std::error_code read() override;
+
+ /// \brief Return true if \p Buffer is in the format supported by this class.
+ static bool hasFormat(const MemoryBuffer &Buffer);
+
+protected:
+ std::error_code readNameTable();
+ std::error_code readOneFunctionProfile(const InlineCallStack &InlineStack,
+ bool Update, uint32_t Offset);
+ std::error_code readFunctionProfiles();
+ std::error_code skipNextWord();
+ template <typename T> ErrorOr<T> readNumber();
+ ErrorOr<StringRef> readString();
+
+ /// \brief Read the section tag and check that it's the same as \p Expected.
+ std::error_code readSectionTag(uint32_t Expected);
+
+ /// GCOV buffer containing the profile.
+ GCOVBuffer GcovBuffer;
+
+ /// Function names in this profile.
+ std::vector<std::string> Names;
+
+ /// GCOV tags used to separate sections in the profile file.
+ static const uint32_t GCOVTagAFDOFileNames = 0xaa000000;
+ static const uint32_t GCOVTagAFDOFunction = 0xac000000;
};
} // End namespace sampleprof
diff --git a/include/llvm/ProfileData/SampleProfWriter.h b/include/llvm/ProfileData/SampleProfWriter.h
index 302a82d328612..029dd2ebacb07 100644
--- a/include/llvm/ProfileData/SampleProfWriter.h
+++ b/include/llvm/ProfileData/SampleProfWriter.h
@@ -13,9 +13,8 @@
#ifndef LLVM_PROFILEDATA_SAMPLEPROFWRITER_H
#define LLVM_PROFILEDATA_SAMPLEPROFWRITER_H
+#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/StringRef.h"
-#include "llvm/IR/Function.h"
-#include "llvm/IR/Module.h"
#include "llvm/ProfileData/SampleProf.h"
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/FileSystem.h"
@@ -30,77 +29,102 @@ enum SampleProfileFormat { SPF_None = 0, SPF_Text, SPF_Binary, SPF_GCC };
/// \brief Sample-based profile writer. Base class.
class SampleProfileWriter {
public:
- SampleProfileWriter(StringRef Filename, std::error_code &EC,
- sys::fs::OpenFlags Flags)
- : OS(Filename, EC, Flags) {}
virtual ~SampleProfileWriter() {}
- /// \brief Write sample profiles in \p S for function \p FName.
+ /// Write sample profiles in \p S for function \p FName.
///
- /// \returns true if the file was updated successfully. False, otherwise.
- virtual bool write(StringRef FName, const FunctionSamples &S) = 0;
+ /// \returns status code of the file update operation.
+ virtual std::error_code write(StringRef FName, const FunctionSamples &S) = 0;
- /// \brief Write sample profiles in \p S for function \p F.
- bool write(const Function &F, const FunctionSamples &S) {
- return write(F.getName(), S);
- }
-
- /// \brief Write all the sample profiles for all the functions in \p M.
+ /// Write all the sample profiles in the given map of samples.
///
- /// \returns true if the file was updated successfully. False, otherwise.
- bool write(const Module &M, StringMap<FunctionSamples> &P) {
- for (const auto &F : M) {
- StringRef Name = F.getName();
- if (!write(Name, P[Name]))
- return false;
- }
- return true;
- }
+ /// \returns status code of the file update operation.
+ std::error_code write(const StringMap<FunctionSamples> &ProfileMap) {
+ if (std::error_code EC = writeHeader(ProfileMap))
+ return EC;
- /// \brief Write all the sample profiles in the given map of samples.
- ///
- /// \returns true if the file was updated successfully. False, otherwise.
- bool write(StringMap<FunctionSamples> &ProfileMap) {
- for (auto &I : ProfileMap) {
+ for (const auto &I : ProfileMap) {
StringRef FName = I.first();
- FunctionSamples &Profile = I.second;
- if (!write(FName, Profile))
- return false;
+ const FunctionSamples &Profile = I.second;
+ if (std::error_code EC = write(FName, Profile))
+ return EC;
}
- return true;
+ return sampleprof_error::success;
}
- /// \brief Profile writer factory. Create a new writer based on the value of
- /// \p Format.
+ raw_ostream &getOutputStream() { return *OutputStream; }
+
+ /// Profile writer factory.
+ ///
+ /// Create a new file writer based on the value of \p Format.
static ErrorOr<std::unique_ptr<SampleProfileWriter>>
create(StringRef Filename, SampleProfileFormat Format);
+ /// Create a new stream writer based on the value of \p Format.
+ /// For testing.
+ static ErrorOr<std::unique_ptr<SampleProfileWriter>>
+ create(std::unique_ptr<raw_ostream> &OS, SampleProfileFormat Format);
+
protected:
+ SampleProfileWriter(std::unique_ptr<raw_ostream> &OS)
+ : OutputStream(std::move(OS)) {}
+
+ /// \brief Write a file header for the profile file.
+ virtual std::error_code
+ writeHeader(const StringMap<FunctionSamples> &ProfileMap) = 0;
+
/// \brief Output stream where to emit the profile to.
- raw_fd_ostream OS;
+ std::unique_ptr<raw_ostream> OutputStream;
};
/// \brief Sample-based profile writer (text format).
class SampleProfileWriterText : public SampleProfileWriter {
public:
- SampleProfileWriterText(StringRef F, std::error_code &EC)
- : SampleProfileWriter(F, EC, sys::fs::F_Text) {}
+ std::error_code write(StringRef FName, const FunctionSamples &S) override;
- bool write(StringRef FName, const FunctionSamples &S) override;
- bool write(const Module &M, StringMap<FunctionSamples> &P) {
- return SampleProfileWriter::write(M, P);
+protected:
+ SampleProfileWriterText(std::unique_ptr<raw_ostream> &OS)
+ : SampleProfileWriter(OS), Indent(0) {}
+
+ std::error_code
+ writeHeader(const StringMap<FunctionSamples> &ProfileMap) override {
+ return sampleprof_error::success;
}
+
+private:
+ /// Indent level to use when writing.
+ ///
+ /// This is used when printing inlined callees.
+ unsigned Indent;
+
+ friend ErrorOr<std::unique_ptr<SampleProfileWriter>>
+ SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS,
+ SampleProfileFormat Format);
};
/// \brief Sample-based profile writer (binary format).
class SampleProfileWriterBinary : public SampleProfileWriter {
public:
- SampleProfileWriterBinary(StringRef F, std::error_code &EC);
+ std::error_code write(StringRef F, const FunctionSamples &S) override;
- bool write(StringRef F, const FunctionSamples &S) override;
- bool write(const Module &M, StringMap<FunctionSamples> &P) {
- return SampleProfileWriter::write(M, P);
- }
+protected:
+ SampleProfileWriterBinary(std::unique_ptr<raw_ostream> &OS)
+ : SampleProfileWriter(OS), NameTable() {}
+
+ std::error_code
+ writeHeader(const StringMap<FunctionSamples> &ProfileMap) override;
+ std::error_code writeNameIdx(StringRef FName);
+ std::error_code writeBody(StringRef FName, const FunctionSamples &S);
+
+private:
+ void addName(StringRef FName);
+ void addNames(const FunctionSamples &S);
+
+ MapVector<StringRef, uint32_t> NameTable;
+
+ friend ErrorOr<std::unique_ptr<SampleProfileWriter>>
+ SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS,
+ SampleProfileFormat Format);
};
} // End namespace sampleprof