171d5a254SDimitry Andric //===- InstrProfWriter.h - Instrumented profiling writer --------*- C++ -*-===// 25ca98fd9SDimitry Andric // 3e6d15924SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4e6d15924SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5e6d15924SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 65ca98fd9SDimitry Andric // 75ca98fd9SDimitry Andric //===----------------------------------------------------------------------===// 85ca98fd9SDimitry Andric // 95ca98fd9SDimitry Andric // This file contains support for writing profiling data for instrumentation 105ca98fd9SDimitry Andric // based PGO and coverage. 115ca98fd9SDimitry Andric // 125ca98fd9SDimitry Andric //===----------------------------------------------------------------------===// 135ca98fd9SDimitry Andric 1467c32a98SDimitry Andric #ifndef LLVM_PROFILEDATA_INSTRPROFWRITER_H 1567c32a98SDimitry Andric #define LLVM_PROFILEDATA_INSTRPROFWRITER_H 165ca98fd9SDimitry Andric 1767c32a98SDimitry Andric #include "llvm/ADT/DenseMap.h" 18145449b1SDimitry Andric #include "llvm/ADT/MapVector.h" 1971d5a254SDimitry Andric #include "llvm/ADT/StringMap.h" 20145449b1SDimitry Andric #include "llvm/IR/GlobalValue.h" 21e3b55780SDimitry Andric #include "llvm/Object/BuildID.h" 225ca98fd9SDimitry Andric #include "llvm/ProfileData/InstrProf.h" 23145449b1SDimitry Andric #include "llvm/ProfileData/MemProf.h" 2471d5a254SDimitry Andric #include "llvm/Support/Error.h" 2571d5a254SDimitry Andric #include <cstdint> 2671d5a254SDimitry Andric #include <memory> 277fa27ce4SDimitry Andric #include <random> 285ca98fd9SDimitry Andric 295ca98fd9SDimitry Andric namespace llvm { 305ca98fd9SDimitry Andric 315ca98fd9SDimitry Andric /// Writer for instrumentation based profile data. 3201095a5dSDimitry Andric class InstrProfRecordWriterTrait; 3371d5a254SDimitry Andric class ProfOStream; 34145449b1SDimitry Andric class MemoryBuffer; 3508bbd35aSDimitry Andric class raw_fd_ostream; 3601095a5dSDimitry Andric 375ca98fd9SDimitry Andric class InstrProfWriter { 385ca98fd9SDimitry Andric public: 39ca089b24SDimitry Andric using ProfilingData = SmallDenseMap<uint64_t, InstrProfRecord>; 40dd58ef01SDimitry Andric 415ca98fd9SDimitry Andric private: 4201095a5dSDimitry Andric bool Sparse; 43dd58ef01SDimitry Andric StringMap<ProfilingData> FunctionData; 447fa27ce4SDimitry Andric /// The maximum length of a single temporal profile trace. 457fa27ce4SDimitry Andric uint64_t MaxTemporalProfTraceLength; 467fa27ce4SDimitry Andric /// The maximum number of stored temporal profile traces. 477fa27ce4SDimitry Andric uint64_t TemporalProfTraceReservoirSize; 487fa27ce4SDimitry Andric /// The total number of temporal profile traces seen. 497fa27ce4SDimitry Andric uint64_t TemporalProfTraceStreamSize = 0; 507fa27ce4SDimitry Andric /// The list of temporal profile traces. 517fa27ce4SDimitry Andric SmallVector<TemporalProfTraceTy> TemporalProfTraces; 527fa27ce4SDimitry Andric std::mt19937 RNG; 53145449b1SDimitry Andric 54ac9a064cSDimitry Andric // The MemProf data. 55ac9a064cSDimitry Andric memprof::IndexedMemProfData MemProfData; 56145449b1SDimitry Andric 57e3b55780SDimitry Andric // List of binary ids. 58e3b55780SDimitry Andric std::vector<llvm::object::BuildID> BinaryIds; 59e3b55780SDimitry Andric 60ac9a064cSDimitry Andric // Read the vtable names from raw instr profile reader. 61ac9a064cSDimitry Andric StringSet<> VTableNames; 62ac9a064cSDimitry Andric 63ecbca9f5SDimitry Andric // An enum describing the attributes of the profile. 64ecbca9f5SDimitry Andric InstrProfKind ProfileKind = InstrProfKind::Unknown; 6501095a5dSDimitry Andric // Use raw pointer here for the incomplete type object. 6601095a5dSDimitry Andric InstrProfRecordWriterTrait *InfoObj; 67dd58ef01SDimitry Andric 68ac9a064cSDimitry Andric // Temporary support for writing the previous version of the format, to enable 69ac9a064cSDimitry Andric // some forward compatibility. Currently this suppresses the writing of the 70ac9a064cSDimitry Andric // new vtable names section and header fields. 71ac9a064cSDimitry Andric // TODO: Consider enabling this with future version changes as well, to ease 72ac9a064cSDimitry Andric // deployment of newer versions of llvm-profdata. 73ac9a064cSDimitry Andric bool WritePrevVersion = false; 74ac9a064cSDimitry Andric 75ac9a064cSDimitry Andric // The MemProf version we should write. 76ac9a064cSDimitry Andric memprof::IndexedVersion MemProfVersionRequested; 77ac9a064cSDimitry Andric 78ac9a064cSDimitry Andric // Whether to serialize the full schema. 79ac9a064cSDimitry Andric bool MemProfFullSchema; 80ac9a064cSDimitry Andric 815ca98fd9SDimitry Andric public: 82ac9a064cSDimitry Andric InstrProfWriter( 83ac9a064cSDimitry Andric bool Sparse = false, uint64_t TemporalProfTraceReservoirSize = 0, 84ac9a064cSDimitry Andric uint64_t MaxTemporalProfTraceLength = 0, bool WritePrevVersion = false, 85ac9a064cSDimitry Andric memprof::IndexedVersion MemProfVersionRequested = memprof::Version0, 86ac9a064cSDimitry Andric bool MemProfFullSchema = false); 8701095a5dSDimitry Andric ~InstrProfWriter(); 8867c32a98SDimitry Andric getProfileData()89b60736ecSDimitry Andric StringMap<ProfilingData> &getProfileData() { return FunctionData; } 90b60736ecSDimitry Andric 915ca98fd9SDimitry Andric /// Add function counts for the given function. If there are already counts 925ca98fd9SDimitry Andric /// for this function and the hash and number of counts match, each counter is 93dd58ef01SDimitry Andric /// summed. Optionally scale counts by \p Weight. 94ca089b24SDimitry Andric void addRecord(NamedInstrProfRecord &&I, uint64_t Weight, 95ca089b24SDimitry Andric function_ref<void(Error)> Warn); addRecord(NamedInstrProfRecord && I,function_ref<void (Error)> Warn)96ca089b24SDimitry Andric void addRecord(NamedInstrProfRecord &&I, function_ref<void(Error)> Warn) { 97ca089b24SDimitry Andric addRecord(std::move(I), 1, Warn); 98ca089b24SDimitry Andric } addVTableName(StringRef VTableName)99ac9a064cSDimitry Andric void addVTableName(StringRef VTableName) { VTableNames.insert(VTableName); } 10071d5a254SDimitry Andric 1017fa27ce4SDimitry Andric /// Add \p SrcTraces using reservoir sampling where \p SrcStreamSize is the 1027fa27ce4SDimitry Andric /// total number of temporal profiling traces the source has seen. 1037fa27ce4SDimitry Andric void addTemporalProfileTraces(SmallVectorImpl<TemporalProfTraceTy> &SrcTraces, 1047fa27ce4SDimitry Andric uint64_t SrcStreamSize); 1057fa27ce4SDimitry Andric 106145449b1SDimitry Andric /// Add a memprof record for a function identified by its \p Id. 107145449b1SDimitry Andric void addMemProfRecord(const GlobalValue::GUID Id, 108145449b1SDimitry Andric const memprof::IndexedMemProfRecord &Record); 109145449b1SDimitry Andric 110145449b1SDimitry Andric /// Add a memprof frame identified by the hash of the contents of the frame in 111145449b1SDimitry Andric /// \p FrameId. 112145449b1SDimitry Andric bool addMemProfFrame(const memprof::FrameId, const memprof::Frame &F, 113145449b1SDimitry Andric function_ref<void(Error)> Warn); 114145449b1SDimitry Andric 115ac9a064cSDimitry Andric /// Add a call stack identified by the hash of the contents of the call stack 116ac9a064cSDimitry Andric /// in \p CallStack. 117ac9a064cSDimitry Andric bool addMemProfCallStack(const memprof::CallStackId CSId, 118ac9a064cSDimitry Andric const llvm::SmallVector<memprof::FrameId> &CallStack, 119ac9a064cSDimitry Andric function_ref<void(Error)> Warn); 120ac9a064cSDimitry Andric 121e3b55780SDimitry Andric // Add a binary id to the binary ids list. 122e3b55780SDimitry Andric void addBinaryIds(ArrayRef<llvm::object::BuildID> BIs); 123e3b55780SDimitry Andric 124b915e9e0SDimitry Andric /// Merge existing function counts from the given writer. 125ca089b24SDimitry Andric void mergeRecordsFromWriter(InstrProfWriter &&IPW, 126ca089b24SDimitry Andric function_ref<void(Error)> Warn); 12771d5a254SDimitry Andric 1285a5ac124SDimitry Andric /// Write the profile to \c OS 129344a3780SDimitry Andric Error write(raw_fd_ostream &OS); 13071d5a254SDimitry Andric 1317fa27ce4SDimitry Andric /// Write the profile to a string output stream \c OS 1327fa27ce4SDimitry Andric Error write(raw_string_ostream &OS); 1337fa27ce4SDimitry Andric 134dd58ef01SDimitry Andric /// Write the profile in text format to \c OS 13508bbd35aSDimitry Andric Error writeText(raw_fd_ostream &OS); 13671d5a254SDimitry Andric 1377fa27ce4SDimitry Andric /// Write temporal profile trace data to the header in text format to \c OS 1387fa27ce4SDimitry Andric void writeTextTemporalProfTraceData(raw_fd_ostream &OS, 1397fa27ce4SDimitry Andric InstrProfSymtab &Symtab); 1407fa27ce4SDimitry Andric 141344a3780SDimitry Andric Error validateRecord(const InstrProfRecord &Func); 142344a3780SDimitry Andric 143dd58ef01SDimitry Andric /// Write \c Record in text format to \c OS 144ca089b24SDimitry Andric static void writeRecordInText(StringRef Name, uint64_t Hash, 145ca089b24SDimitry Andric const InstrProfRecord &Counters, 146dd58ef01SDimitry Andric InstrProfSymtab &Symtab, raw_fd_ostream &OS); 14771d5a254SDimitry Andric 1485a5ac124SDimitry Andric /// Write the profile, returning the raw data. For testing. 1495a5ac124SDimitry Andric std::unique_ptr<MemoryBuffer> writeBuffer(); 1505a5ac124SDimitry Andric 151ecbca9f5SDimitry Andric /// Update the attributes of the current profile from the attributes 152ecbca9f5SDimitry Andric /// specified. An error is returned if IR and FE profiles are mixed. mergeProfileKind(const InstrProfKind Other)153ecbca9f5SDimitry Andric Error mergeProfileKind(const InstrProfKind Other) { 154ecbca9f5SDimitry Andric // If the kind is unset, this is the first profile we are merging so just 155ecbca9f5SDimitry Andric // set it to the given type. 156ecbca9f5SDimitry Andric if (ProfileKind == InstrProfKind::Unknown) { 157ecbca9f5SDimitry Andric ProfileKind = Other; 15801095a5dSDimitry Andric return Error::success(); 15901095a5dSDimitry Andric } 160e6d15924SDimitry Andric 161ecbca9f5SDimitry Andric // Returns true if merging is should fail assuming A and B are incompatible. 162ecbca9f5SDimitry Andric auto testIncompatible = [&](InstrProfKind A, InstrProfKind B) { 163ecbca9f5SDimitry Andric return (static_cast<bool>(ProfileKind & A) && 164ecbca9f5SDimitry Andric static_cast<bool>(Other & B)) || 165ecbca9f5SDimitry Andric (static_cast<bool>(ProfileKind & B) && 166ecbca9f5SDimitry Andric static_cast<bool>(Other & A)); 167ecbca9f5SDimitry Andric }; 168ecbca9f5SDimitry Andric 169ecbca9f5SDimitry Andric // Check if the profiles are in-compatible. Clang frontend profiles can't be 170ecbca9f5SDimitry Andric // merged with other profile types. 171145449b1SDimitry Andric if (static_cast<bool>( 172145449b1SDimitry Andric (ProfileKind & InstrProfKind::FrontendInstrumentation) ^ 173145449b1SDimitry Andric (Other & InstrProfKind::FrontendInstrumentation))) { 174e6d15924SDimitry Andric return make_error<InstrProfError>(instrprof_error::unsupported_version); 175ecbca9f5SDimitry Andric } 176145449b1SDimitry Andric if (testIncompatible(InstrProfKind::FunctionEntryOnly, 177145449b1SDimitry Andric InstrProfKind::FunctionEntryInstrumentation)) { 178ecbca9f5SDimitry Andric return make_error<InstrProfError>( 179ecbca9f5SDimitry Andric instrprof_error::unsupported_version, 180ecbca9f5SDimitry Andric "cannot merge FunctionEntryOnly profiles and BB profiles together"); 181ecbca9f5SDimitry Andric } 182e6d15924SDimitry Andric 183ecbca9f5SDimitry Andric // Now we update the profile type with the bits that are set. 184ecbca9f5SDimitry Andric ProfileKind |= Other; 185e6d15924SDimitry Andric return Error::success(); 18601095a5dSDimitry Andric } 18701095a5dSDimitry Andric getProfileKind()188145449b1SDimitry Andric InstrProfKind getProfileKind() const { return ProfileKind; } 189145449b1SDimitry Andric hasSingleByteCoverage()190ac9a064cSDimitry Andric bool hasSingleByteCoverage() const { 191ac9a064cSDimitry Andric return static_cast<bool>(ProfileKind & InstrProfKind::SingleByteCoverage); 192ac9a064cSDimitry Andric } 193ac9a064cSDimitry Andric 194ac9a064cSDimitry Andric // Internal interfaces for testing purpose only. 195b1c73532SDimitry Andric void setValueProfDataEndianness(llvm::endianness Endianness); 19601095a5dSDimitry Andric void setOutputSparse(bool Sparse); setMemProfVersionRequested(memprof::IndexedVersion Version)197ac9a064cSDimitry Andric void setMemProfVersionRequested(memprof::IndexedVersion Version) { 198ac9a064cSDimitry Andric MemProfVersionRequested = Version; 199ac9a064cSDimitry Andric } setMemProfFullSchema(bool Full)200ac9a064cSDimitry Andric void setMemProfFullSchema(bool Full) { MemProfFullSchema = Full; } 201e6d15924SDimitry Andric // Compute the overlap b/w this object and Other. Program level result is 202e6d15924SDimitry Andric // stored in Overlap and function level result is stored in FuncLevelOverlap. 203e6d15924SDimitry Andric void overlapRecord(NamedInstrProfRecord &&Other, OverlapStats &Overlap, 204e6d15924SDimitry Andric OverlapStats &FuncLevelOverlap, 205e6d15924SDimitry Andric const OverlapFuncFilters &FuncFilter); 206dd58ef01SDimitry Andric 2075a5ac124SDimitry Andric private: 208ca089b24SDimitry Andric void addRecord(StringRef Name, uint64_t Hash, InstrProfRecord &&I, 209ca089b24SDimitry Andric uint64_t Weight, function_ref<void(Error)> Warn); 21001095a5dSDimitry Andric bool shouldEncodeData(const ProfilingData &PD); 2117fa27ce4SDimitry Andric /// Add \p Trace using reservoir sampling. 2127fa27ce4SDimitry Andric void addTemporalProfileTrace(TemporalProfTraceTy Trace); 213344a3780SDimitry Andric 214344a3780SDimitry Andric Error writeImpl(ProfOStream &OS); 215ac9a064cSDimitry Andric 216ac9a064cSDimitry Andric // Writes known header fields and reserves space for fields whose value are 217ac9a064cSDimitry Andric // known only after payloads are written. Returns the start byte offset for 218ac9a064cSDimitry Andric // back patching. 219ac9a064cSDimitry Andric uint64_t writeHeader(const IndexedInstrProf::Header &header, 220ac9a064cSDimitry Andric const bool WritePrevVersion, ProfOStream &OS); 221ac9a064cSDimitry Andric 222ac9a064cSDimitry Andric // Writes compressed vtable names to profiles. 223ac9a064cSDimitry Andric Error writeVTableNames(ProfOStream &OS); 2245ca98fd9SDimitry Andric }; 2255ca98fd9SDimitry Andric 2265ca98fd9SDimitry Andric } // end namespace llvm 2275ca98fd9SDimitry Andric 22871d5a254SDimitry Andric #endif // LLVM_PROFILEDATA_INSTRPROFWRITER_H 229