LCOV - code coverage report
Current view: top level - lib/ProfileData - InstrProfWriter.cpp (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 186 187 99.5 %
Date: 2017-09-14 15:23:50 Functions: 18 18 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //===- InstrProfWriter.cpp - Instrumented profiling writer ----------------===//
       2             : //
       3             : //                     The LLVM Compiler Infrastructure
       4             : //
       5             : // This file is distributed under the University of Illinois Open Source
       6             : // License. See LICENSE.TXT for details.
       7             : //
       8             : //===----------------------------------------------------------------------===//
       9             : //
      10             : // This file contains support for writing profiling data for clang's
      11             : // instrumentation based PGO and coverage.
      12             : //
      13             : //===----------------------------------------------------------------------===//
      14             : 
      15             : #include "llvm/ProfileData/InstrProfWriter.h"
      16             : #include "llvm/ADT/STLExtras.h"
      17             : #include "llvm/ADT/StringRef.h"
      18             : #include "llvm/IR/ProfileSummary.h"
      19             : #include "llvm/ProfileData/InstrProf.h"
      20             : #include "llvm/ProfileData/ProfileCommon.h"
      21             : #include "llvm/Support/Endian.h"
      22             : #include "llvm/Support/EndianStream.h"
      23             : #include "llvm/Support/Error.h"
      24             : #include "llvm/Support/MemoryBuffer.h"
      25             : #include "llvm/Support/OnDiskHashTable.h"
      26             : #include "llvm/Support/raw_ostream.h"
      27             : #include <algorithm>
      28             : #include <cstdint>
      29             : #include <memory>
      30             : #include <string>
      31             : #include <tuple>
      32             : #include <utility>
      33             : #include <vector>
      34             : 
      35             : using namespace llvm;
      36             : 
      37             : // A struct to define how the data stream should be patched. For Indexed
      38             : // profiling, only uint64_t data type is needed.
      39             : struct PatchItem {
      40             :   uint64_t Pos; // Where to patch.
      41             :   uint64_t *D;  // Pointer to an array of source data.
      42             :   int N;        // Number of elements in \c D array.
      43             : };
      44             : 
      45             : namespace llvm {
      46             : 
      47             : // A wrapper class to abstract writer stream with support of bytes
      48             : // back patching.
      49             : class ProfOStream {
      50             : public:
      51         164 :   ProfOStream(raw_fd_ostream &FD) : IsFDOStream(true), OS(FD), LE(FD) {}
      52             :   ProfOStream(raw_string_ostream &STR)
      53         242 :       : IsFDOStream(false), OS(STR), LE(STR) {}
      54             : 
      55         812 :   uint64_t tell() { return OS.tell(); }
      56       37534 :   void write(uint64_t V) { LE.write<uint64_t>(V); }
      57             : 
      58             :   // \c patch can only be called when all data is written and flushed.
      59             :   // For raw_string_ostream, the patch is done on the target string
      60             :   // directly and it won't be reflected in the stream's internal buffer.
      61         203 :   void patch(PatchItem *P, int NItems) {
      62             :     using namespace support;
      63             : 
      64         203 :     if (IsFDOStream) {
      65          82 :       raw_fd_ostream &FDOStream = static_cast<raw_fd_ostream &>(OS);
      66         246 :       for (int K = 0; K < NItems; K++) {
      67         164 :         FDOStream.seek(P[K].Pos);
      68        5330 :         for (int I = 0; I < P[K].N; I++)
      69       10332 :           write(P[K].D[I]);
      70             :       }
      71             :     } else {
      72         121 :       raw_string_ostream &SOStream = static_cast<raw_string_ostream &>(OS);
      73         121 :       std::string &Data = SOStream.str(); // with flush
      74         363 :       for (int K = 0; K < NItems; K++) {
      75       15488 :         for (int I = 0; I < P[K].N; I++) {
      76       15246 :           uint64_t Bytes = endian::byte_swap<uint64_t, little>(P[K].D[I]);
      77       15246 :           Data.replace(P[K].Pos + I * sizeof(uint64_t), sizeof(uint64_t),
      78        7623 :                        (const char *)&Bytes, sizeof(uint64_t));
      79             :         }
      80             :       }
      81             :     }
      82         203 :   }
      83             : 
      84             :   // If \c OS is an instance of \c raw_fd_ostream, this field will be
      85             :   // true. Otherwise, \c OS will be an raw_string_ostream.
      86             :   bool IsFDOStream;
      87             :   raw_ostream &OS;
      88             :   support::endian::Writer<support::little> LE;
      89             : };
      90             : 
      91             : class InstrProfRecordWriterTrait {
      92             : public:
      93             :   using key_type = StringRef;
      94             :   using key_type_ref = StringRef;
      95             : 
      96             :   using data_type = const InstrProfWriter::ProfilingData *const;
      97             :   using data_type_ref = const InstrProfWriter::ProfilingData *const;
      98             : 
      99             :   using hash_value_type = uint64_t;
     100             :   using offset_type = uint64_t;
     101             : 
     102             :   support::endianness ValueProfDataEndianness = support::little;
     103             :   InstrProfSummaryBuilder *SummaryBuilder;
     104             : 
     105         569 :   InstrProfRecordWriterTrait() = default;
     106             : 
     107             :   static hash_value_type ComputeHash(key_type_ref K) {
     108             :     return IndexedInstrProf::ComputeHash(K);
     109             :   }
     110             : 
     111             :   static std::pair<offset_type, offset_type>
     112         326 :   EmitKeyDataLength(raw_ostream &Out, key_type_ref K, data_type_ref V) {
     113             :     using namespace support;
     114             : 
     115         326 :     endian::Writer<little> LE(Out);
     116             : 
     117         326 :     offset_type N = K.size();
     118         652 :     LE.write<offset_type>(N);
     119             : 
     120         326 :     offset_type M = 0;
     121         652 :     for (const auto &ProfileData : *V) {
     122         334 :       const InstrProfRecord &ProfRecord = ProfileData.second;
     123         334 :       M += sizeof(uint64_t); // The function hash
     124         334 :       M += sizeof(uint64_t); // The size of the Counts vector
     125         668 :       M += ProfRecord.Counts.size() * sizeof(uint64_t);
     126             : 
     127             :       // Value data
     128         334 :       M += ValueProfData::getSize(ProfileData.second);
     129             :     }
     130         652 :     LE.write<offset_type>(M);
     131             : 
     132         652 :     return std::make_pair(N, M);
     133             :   }
     134             : 
     135             :   void EmitKey(raw_ostream &Out, key_type_ref K, offset_type N) {
     136         326 :     Out.write(K.data(), N);
     137             :   }
     138             : 
     139         326 :   void EmitData(raw_ostream &Out, key_type_ref, data_type_ref V, offset_type) {
     140             :     using namespace support;
     141             : 
     142         326 :     endian::Writer<little> LE(Out);
     143         652 :     for (const auto &ProfileData : *V) {
     144         334 :       const InstrProfRecord &ProfRecord = ProfileData.second;
     145         334 :       SummaryBuilder->addRecord(ProfRecord);
     146             : 
     147         668 :       LE.write<uint64_t>(ProfileData.first); // Function hash
     148        1002 :       LE.write<uint64_t>(ProfRecord.Counts.size());
     149        2291 :       for (uint64_t I : ProfRecord.Counts)
     150         955 :         LE.write<uint64_t>(I);
     151             : 
     152             :       // Write value data
     153             :       std::unique_ptr<ValueProfData> VDataPtr =
     154         668 :           ValueProfData::serializeFrom(ProfileData.second);
     155         334 :       uint32_t S = VDataPtr->getSize();
     156         334 :       VDataPtr->swapBytesFromHost(ValueProfDataEndianness);
     157         668 :       Out.write((const char *)VDataPtr.get(), S);
     158             :     }
     159         326 :   }
     160             : };
     161             : 
     162             : } // end namespace llvm
     163             : 
     164         243 : InstrProfWriter::InstrProfWriter(bool Sparse)
     165         729 :     : Sparse(Sparse), InfoObj(new InstrProfRecordWriterTrait()) {}
     166             : 
     167         241 : InstrProfWriter::~InstrProfWriter() { delete InfoObj; }
     168             : 
     169             : // Internal interface for testing purpose only.
     170           4 : void InstrProfWriter::setValueProfDataEndianness(
     171             :     support::endianness Endianness) {
     172           4 :   InfoObj->ValueProfDataEndianness = Endianness;
     173           4 : }
     174             : 
     175         145 : void InstrProfWriter::setOutputSparse(bool Sparse) {
     176         145 :   this->Sparse = Sparse;
     177         145 : }
     178             : 
     179         414 : void InstrProfWriter::addRecord(NamedInstrProfRecord &&I, uint64_t Weight,
     180             :                                 function_ref<void(Error)> Warn) {
     181         414 :   auto Name = I.Name;
     182         414 :   auto Hash = I.Hash;
     183         414 :   addRecord(Name, Hash, std::move(I), Weight, Warn);
     184         414 : }
     185             : 
     186         422 : void InstrProfWriter::addRecord(StringRef Name, uint64_t Hash,
     187             :                                 InstrProfRecord &&I, uint64_t Weight,
     188             :                                 function_ref<void(Error)> Warn) {
     189         844 :   auto &ProfileDataMap = FunctionData[Name];
     190             : 
     191             :   bool NewFunc;
     192             :   ProfilingData::iterator Where;
     193         422 :   std::tie(Where, NewFunc) =
     194        2954 :       ProfileDataMap.insert(std::make_pair(Hash, InstrProfRecord()));
     195         422 :   InstrProfRecord &Dest = Where->second;
     196             : 
     197           8 :   auto MapWarn = [&](instrprof_error E) {
     198          24 :     Warn(make_error<InstrProfError>(E));
     199         430 :   };
     200             : 
     201         422 :   if (NewFunc) {
     202             :     // We've never seen a function with this name and hash, add it.
     203         368 :     Dest = std::move(I);
     204         368 :     if (Weight > 1)
     205          20 :       Dest.scale(Weight, MapWarn);
     206             :   } else {
     207             :     // We're updating a function we've seen before.
     208         108 :     Dest.merge(I, Weight, MapWarn);
     209             :   }
     210             : 
     211         422 :   Dest.sortValueData();
     212         422 : }
     213             : 
     214           8 : void InstrProfWriter::mergeRecordsFromWriter(InstrProfWriter &&IPW,
     215             :                                              function_ref<void(Error)> Warn) {
     216          48 :   for (auto &I : IPW.FunctionData)
     217          32 :     for (auto &Func : I.getValue())
     218          16 :       addRecord(I.getKey(), Func.first, std::move(Func.second), 1, Warn);
     219           8 : }
     220             : 
     221         366 : bool InstrProfWriter::shouldEncodeData(const ProfilingData &PD) {
     222         366 :   if (!Sparse)
     223             :     return true;
     224         164 :   for (const auto &Func : PD) {
     225          82 :     const InstrProfRecord &IPR = Func.second;
     226         164 :     if (llvm::any_of(IPR.Counts, [](uint64_t Count) { return Count > 0; }))
     227          70 :       return true;
     228             :   }
     229          12 :   return false;
     230             : }
     231             : 
     232         203 : static void setSummary(IndexedInstrProf::Summary *TheSummary,
     233             :                        ProfileSummary &PS) {
     234             :   using namespace IndexedInstrProf;
     235             : 
     236         203 :   std::vector<ProfileSummaryEntry> &Res = PS.getDetailedSummary();
     237         203 :   TheSummary->NumSummaryFields = Summary::NumKinds;
     238         203 :   TheSummary->NumCutoffEntries = Res.size();
     239         406 :   TheSummary->set(Summary::MaxFunctionCount, PS.getMaxFunctionCount());
     240         406 :   TheSummary->set(Summary::MaxBlockCount, PS.getMaxCount());
     241         406 :   TheSummary->set(Summary::MaxInternalBlockCount, PS.getMaxInternalCount());
     242         406 :   TheSummary->set(Summary::TotalBlockCount, PS.getTotalCount());
     243         406 :   TheSummary->set(Summary::TotalNumBlocks, PS.getNumCounts());
     244         406 :   TheSummary->set(Summary::TotalNumFunctions, PS.getNumFunctions());
     245        3857 :   for (unsigned I = 0; I < Res.size(); I++)
     246       10962 :     TheSummary->setEntry(I, Res[I]);
     247         203 : }
     248             : 
     249         203 : void InstrProfWriter::writeImpl(ProfOStream &OS) {
     250             :   using namespace IndexedInstrProf;
     251             : 
     252         406 :   OnDiskChainedHashTableGenerator<InstrProfRecordWriterTrait> Generator;
     253             : 
     254         812 :   InstrProfSummaryBuilder ISB(ProfileSummaryBuilder::DefaultCutoffs);
     255         203 :   InfoObj->SummaryBuilder = &ISB;
     256             : 
     257             :   // Populate the hash table generator.
     258        1488 :   for (const auto &I : FunctionData)
     259         338 :     if (shouldEncodeData(I.getValue()))
     260         652 :       Generator.insert(I.getKey(), &I.getValue());
     261             :   // Write the header.
     262             :   IndexedInstrProf::Header Header;
     263         203 :   Header.Magic = IndexedInstrProf::Magic;
     264         203 :   Header.Version = IndexedInstrProf::ProfVersion::CurrentVersion;
     265         203 :   if (ProfileKind == PF_IRLevel)
     266          21 :     Header.Version |= VARIANT_MASK_IR_PROF;
     267         203 :   Header.Unused = 0;
     268         203 :   Header.HashType = static_cast<uint64_t>(IndexedInstrProf::HashType);
     269         203 :   Header.HashOffset = 0;
     270         203 :   int N = sizeof(IndexedInstrProf::Header) / sizeof(uint64_t);
     271             : 
     272             :   // Only write out all the fields except 'HashOffset'. We need
     273             :   // to remember the offset of that field to allow back patching
     274             :   // later.
     275        1015 :   for (int I = 0; I < N - 1; I++)
     276        1624 :     OS.write(reinterpret_cast<uint64_t *>(&Header)[I]);
     277             : 
     278             :   // Save the location of Header.HashOffset field in \c OS.
     279         406 :   uint64_t HashTableStartFieldOffset = OS.tell();
     280             :   // Reserve the space for HashOffset field.
     281         203 :   OS.write(0);
     282             : 
     283             :   // Reserve space to write profile summary data.
     284         203 :   uint32_t NumEntries = ProfileSummaryBuilder::DefaultCutoffs.size();
     285         203 :   uint32_t SummarySize = Summary::getSize(Summary::NumKinds, NumEntries);
     286             :   // Remember the summary offset.
     287         406 :   uint64_t SummaryOffset = OS.tell();
     288       12789 :   for (unsigned I = 0; I < SummarySize / sizeof(uint64_t); I++)
     289       12586 :     OS.write(0);
     290             : 
     291             :   // Write the hash table.
     292         203 :   uint64_t HashTableStart = Generator.Emit(OS.OS, *InfoObj);
     293             : 
     294             :   // Allocate space for data to be serialized out.
     295             :   std::unique_ptr<IndexedInstrProf::Summary> TheSummary =
     296         406 :       IndexedInstrProf::allocSummary(SummarySize);
     297             :   // Compute the Summary and copy the data to the data
     298             :   // structure to be serialized out (to disk or buffer).
     299         406 :   std::unique_ptr<ProfileSummary> PS = ISB.getSummary();
     300         406 :   setSummary(TheSummary.get(), *PS);
     301         203 :   InfoObj->SummaryBuilder = nullptr;
     302             : 
     303             :   // Now do the final patch:
     304         203 :   PatchItem PatchItems[] = {
     305             :       // Patch the Header.HashOffset field.
     306             :       {HashTableStartFieldOffset, &HashTableStart, 1},
     307             :       // Patch the summary data.
     308         203 :       {SummaryOffset, reinterpret_cast<uint64_t *>(TheSummary.get()),
     309         406 :        (int)(SummarySize / sizeof(uint64_t))}};
     310         203 :   OS.patch(PatchItems, sizeof(PatchItems) / sizeof(*PatchItems));
     311         203 : }
     312             : 
     313          82 : void InstrProfWriter::write(raw_fd_ostream &OS) {
     314             :   // Write the hash table.
     315          82 :   ProfOStream POS(OS);
     316          82 :   writeImpl(POS);
     317          82 : }
     318             : 
     319         121 : std::unique_ptr<MemoryBuffer> InstrProfWriter::writeBuffer() {
     320         242 :   std::string Data;
     321         242 :   raw_string_ostream OS(Data);
     322         121 :   ProfOStream POS(OS);
     323             :   // Write the hash table.
     324         121 :   writeImpl(POS);
     325             :   // Return this in an aligned memory buffer.
     326         363 :   return MemoryBuffer::getMemBufferCopy(Data);
     327             : }
     328             : 
     329             : static const char *ValueProfKindStr[] = {
     330             : #define VALUE_PROF_KIND(Enumerator, Value) #Enumerator,
     331             : #include "llvm/ProfileData/InstrProfData.inc"
     332             : };
     333             : 
     334          22 : void InstrProfWriter::writeRecordInText(StringRef Name, uint64_t Hash,
     335             :                                         const InstrProfRecord &Func,
     336             :                                         InstrProfSymtab &Symtab,
     337             :                                         raw_fd_ostream &OS) {
     338          22 :   OS << Name << "\n";
     339          22 :   OS << "# Func Hash:\n" << Hash << "\n";
     340          44 :   OS << "# Num Counters:\n" << Func.Counts.size() << "\n";
     341          22 :   OS << "# Counter Values:\n";
     342         142 :   for (uint64_t Count : Func.Counts)
     343          54 :     OS << Count << "\n";
     344             : 
     345          22 :   uint32_t NumValueKinds = Func.getNumValueKinds();
     346          22 :   if (!NumValueKinds) {
     347          19 :     OS << "\n";
     348          19 :     return;
     349             :   }
     350             : 
     351           9 :   OS << "# Num Value Kinds:\n" << Func.getNumValueKinds() << "\n";
     352           9 :   for (uint32_t VK = 0; VK < IPVK_Last + 1; VK++) {
     353           6 :     uint32_t NS = Func.getNumValueSites(VK);
     354           6 :     if (!NS)
     355           1 :       continue;
     356          10 :     OS << "# ValueKind = " << ValueProfKindStr[VK] << ":\n" << VK << "\n";
     357          10 :     OS << "# NumValueSites:\n" << NS << "\n";
     358          16 :     for (uint32_t S = 0; S < NS; S++) {
     359          11 :       uint32_t ND = Func.getNumValueDataForSite(VK, S);
     360          22 :       OS << ND << "\n";
     361          22 :       std::unique_ptr<InstrProfValueData[]> VD = Func.getValueForSite(VK, S);
     362          38 :       for (uint32_t I = 0; I < ND; I++) {
     363          27 :         if (VK == IPVK_IndirectCallTarget)
     364          27 :           OS << Symtab.getFuncName(VD[I].Value) << ":" << VD[I].Count << "\n";
     365             :         else
     366          54 :           OS << VD[I].Value << ":" << VD[I].Count << "\n";
     367             :       }
     368             :     }
     369             :   }
     370             : 
     371           3 :   OS << "\n";
     372             : }
     373             : 
     374           6 : Error InstrProfWriter::writeText(raw_fd_ostream &OS) {
     375           6 :   if (ProfileKind == PF_IRLevel)
     376           2 :     OS << "# IR level Instrumentation Flag\n:ir\n";
     377          12 :   InstrProfSymtab Symtab;
     378          52 :   for (const auto &I : FunctionData)
     379          14 :     if (shouldEncodeData(I.getValue()))
     380          42 :       if (Error E = Symtab.addFuncName(I.getKey()))
     381           0 :         return E;
     382           6 :   Symtab.finalizeSymtab();
     383             : 
     384          52 :   for (const auto &I : FunctionData)
     385          14 :     if (shouldEncodeData(I.getValue()))
     386          28 :       for (const auto &Func : I.getValue())
     387          28 :         writeRecordInText(I.getKey(), Func.first, Func.second, Symtab, OS);
     388          18 :   return Error::success();
     389             : }

Generated by: LCOV version 1.13