Minor Instr PGO code restructuring
[oota-llvm.git] / lib / ProfileData / InstrProfWriter.cpp
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/StringExtras.h"
17 #include "llvm/Support/EndianStream.h"
18 #include "llvm/Support/OnDiskHashTable.h"
19
20 using namespace llvm;
21
22 namespace {
23 class InstrProfRecordTrait {
24 public:
25   typedef StringRef key_type;
26   typedef StringRef key_type_ref;
27
28   typedef const InstrProfWriter::ProfilingData *const data_type;
29   typedef const InstrProfWriter::ProfilingData *const data_type_ref;
30
31   typedef uint64_t hash_value_type;
32   typedef uint64_t offset_type;
33
34   static hash_value_type ComputeHash(key_type_ref K) {
35     return IndexedInstrProf::ComputeHash(IndexedInstrProf::HashType, K);
36   }
37
38   static std::pair<offset_type, offset_type>
39   EmitKeyDataLength(raw_ostream &Out, key_type_ref K, data_type_ref V) {
40     using namespace llvm::support;
41     endian::Writer<little> LE(Out);
42
43     offset_type N = K.size();
44     LE.write<offset_type>(N);
45
46     offset_type M = 0;
47     for (const auto &ProfileData : *V) {
48       M += sizeof(uint64_t); // The function hash
49       M += sizeof(uint64_t); // The size of the Counts vector
50       M += ProfileData.second.Counts.size() * sizeof(uint64_t);
51
52       // Value data
53       M += sizeof(uint64_t); // Number of value kinds with value sites.
54       for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; ++Kind) {
55         const std::vector<InstrProfValueSiteRecord> &ValueSites =
56             ProfileData.second.getValueSitesForKind(Kind);
57         if (ValueSites.empty())
58           continue;
59         M += sizeof(uint64_t); // Value kind
60         M += sizeof(uint64_t); // The number of value sites for given value kind
61         for (InstrProfValueSiteRecord I : ValueSites) {
62           M += sizeof(uint64_t); // Number of value data pairs at a value site
63           M += 2 * sizeof(uint64_t) * I.ValueData.size(); // Value data pairs
64         }
65       }
66     }
67     LE.write<offset_type>(M);
68
69     return std::make_pair(N, M);
70   }
71
72   static void EmitKey(raw_ostream &Out, key_type_ref K, offset_type N){
73     Out.write(K.data(), N);
74   }
75
76   static void EmitData(raw_ostream &Out, key_type_ref, data_type_ref V,
77                        offset_type) {
78     using namespace llvm::support;
79     endian::Writer<little> LE(Out);
80     for (const auto &ProfileData : *V) {
81       LE.write<uint64_t>(ProfileData.first); // Function hash
82       LE.write<uint64_t>(ProfileData.second.Counts.size());
83       for (uint64_t I : ProfileData.second.Counts)
84         LE.write<uint64_t>(I);
85
86       // Compute the number of value kinds with value sites.
87       uint64_t NumValueKinds = 0;
88       for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; ++Kind)
89         NumValueKinds +=
90             !(ProfileData.second.getValueSitesForKind(Kind).empty());
91       LE.write<uint64_t>(NumValueKinds);
92
93       // Write value data
94       for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; ++Kind) {
95         const std::vector<InstrProfValueSiteRecord> &ValueSites =
96             ProfileData.second.getValueSitesForKind(Kind);
97         if (ValueSites.empty())
98           continue;
99         LE.write<uint64_t>(Kind); // Write value kind
100         // Write number of value sites for current value kind
101         LE.write<uint64_t>(ValueSites.size());
102         for (InstrProfValueSiteRecord I : ValueSites) {
103           // Write number of value data pairs at this value site
104           LE.write<uint64_t>(I.ValueData.size());
105           for (auto V : I.ValueData) {
106             if (Kind == IPVK_IndirectCallTarget)
107               LE.write<uint64_t>(ComputeHash((const char *)V.first));
108             else
109               LE.write<uint64_t>(V.first);
110             LE.write<uint64_t>(V.second);
111           }
112         }
113       }
114     }
115   }
116 };
117 }
118
119 static std::error_code combineInstrProfRecords(InstrProfRecord &Dest,
120                                                InstrProfRecord &Source,
121                                                uint64_t &MaxFunctionCount) {
122   // If the number of counters doesn't match we either have bad data
123   // or a hash collision.
124   if (Dest.Counts.size() != Source.Counts.size())
125     return instrprof_error::count_mismatch;
126
127   for (size_t I = 0, E = Source.Counts.size(); I < E; ++I) {
128     if (Dest.Counts[I] + Source.Counts[I] < Dest.Counts[I])
129       return instrprof_error::counter_overflow;
130     Dest.Counts[I] += Source.Counts[I];
131   }
132
133   for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; ++Kind) {
134
135     std::vector<InstrProfValueSiteRecord> &SourceValueSites =
136         Source.getValueSitesForKind(Kind);
137     if (SourceValueSites.empty())
138       continue;
139
140     std::vector<InstrProfValueSiteRecord> &DestValueSites =
141         Dest.getValueSitesForKind(Kind);
142
143     if (DestValueSites.empty()) {
144       DestValueSites.swap(SourceValueSites);
145       continue;
146     }
147
148     if (DestValueSites.size() != SourceValueSites.size())
149       return instrprof_error::value_site_count_mismatch;
150     for (size_t I = 0, E = SourceValueSites.size(); I < E; ++I)
151       DestValueSites[I].mergeValueData(SourceValueSites[I]);
152   }
153
154   // We keep track of the max function count as we go for simplicity.
155   if (Dest.Counts[0] > MaxFunctionCount)
156     MaxFunctionCount = Dest.Counts[0];
157
158   return instrprof_error::success;
159 }
160
161 void InstrProfWriter::updateStringTableReferences(InstrProfRecord &I) {
162   I.Name = StringTable.insertString(I.Name);
163   for (auto &VSite : I.IndirectCallSites)
164     for (auto &VData : VSite.ValueData)
165       VData.first =
166           (uint64_t)StringTable.insertString((const char *)VData.first);
167 }
168
169 std::error_code InstrProfWriter::addRecord(InstrProfRecord &&I) {
170   updateStringTableReferences(I);
171   auto &ProfileDataMap = FunctionData[I.Name];
172
173   auto Where = ProfileDataMap.find(I.Hash);
174   if (Where == ProfileDataMap.end()) {
175     // We've never seen a function with this name and hash, add it.
176     ProfileDataMap[I.Hash] = I;
177
178     // We keep track of the max function count as we go for simplicity.
179     if (I.Counts[0] > MaxFunctionCount)
180       MaxFunctionCount = I.Counts[0];
181     return instrprof_error::success;
182   }
183
184   // We're updating a function we've seen before.
185   return combineInstrProfRecords(Where->second, I, MaxFunctionCount);
186 }
187
188 std::pair<uint64_t, uint64_t> InstrProfWriter::writeImpl(raw_ostream &OS) {
189   OnDiskChainedHashTableGenerator<InstrProfRecordTrait> Generator;
190
191   // Populate the hash table generator.
192   for (const auto &I : FunctionData)
193     Generator.insert(I.getKey(), &I.getValue());
194
195   using namespace llvm::support;
196   endian::Writer<little> LE(OS);
197
198   // Write the header.
199   IndexedInstrProf::Header Header;
200   Header.Magic = IndexedInstrProf::Magic;
201   Header.Version = IndexedInstrProf::Version;
202   Header.MaxFunctionCount = MaxFunctionCount;
203   Header.HashType = static_cast<uint64_t>(IndexedInstrProf::HashType);
204   Header.HashOffset = 0;
205   int N = sizeof(IndexedInstrProf::Header) / sizeof(uint64_t);
206
207   // Only write out all the fields execpt 'HashOffset'. We need
208   // to remember the offset of that field to allow back patching
209   // later.
210   for (int I = 0; I < N - 1; I++)
211     LE.write<uint64_t>(reinterpret_cast<uint64_t *>(&Header)[I]);
212
213   // Save a space to write the hash table start location.
214   uint64_t HashTableStartLoc = OS.tell();
215   // Reserve the space for HashOffset field.
216   LE.write<uint64_t>(0);
217   // Write the hash table.
218   uint64_t HashTableStart = Generator.Emit(OS);
219
220   return std::make_pair(HashTableStartLoc, HashTableStart);
221 }
222
223 void InstrProfWriter::write(raw_fd_ostream &OS) {
224   // Write the hash table.
225   auto TableStart = writeImpl(OS);
226
227   // Go back and fill in the hash table start.
228   using namespace support;
229   OS.seek(TableStart.first);
230   // Now patch the HashOffset field previously reserved.
231   endian::Writer<little>(OS).write<uint64_t>(TableStart.second);
232 }
233
234 std::unique_ptr<MemoryBuffer> InstrProfWriter::writeBuffer() {
235   std::string Data;
236   llvm::raw_string_ostream OS(Data);
237   // Write the hash table.
238   auto TableStart = writeImpl(OS);
239   OS.flush();
240
241   // Go back and fill in the hash table start.
242   using namespace support;
243   uint64_t Bytes = endian::byte_swap<uint64_t, little>(TableStart.second);
244   Data.replace(TableStart.first, sizeof(uint64_t), (const char *)&Bytes,
245                sizeof(uint64_t));
246
247   // Return this in an aligned memory buffer.
248   return MemoryBuffer::getMemBufferCopy(Data);
249 }