/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/lib/ProfileData/GCOV.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===- GCOV.cpp - LLVM coverage tool --------------------------------------===// |
2 | | // |
3 | | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | | // See https://llvm.org/LICENSE.txt for license information. |
5 | | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | | // |
7 | | //===----------------------------------------------------------------------===// |
8 | | // |
9 | | // GCOV implements the interface to read and write coverage files that use |
10 | | // 'gcov' format. |
11 | | // |
12 | | //===----------------------------------------------------------------------===// |
13 | | |
14 | | #include "llvm/ProfileData/GCOV.h" |
15 | | #include "llvm/ADT/STLExtras.h" |
16 | | #include "llvm/Config/llvm-config.h" |
17 | | #include "llvm/Support/Debug.h" |
18 | | #include "llvm/Support/FileSystem.h" |
19 | | #include "llvm/Support/Format.h" |
20 | | #include "llvm/Support/Path.h" |
21 | | #include "llvm/Support/MD5.h" |
22 | | #include "llvm/Support/raw_ostream.h" |
23 | | #include <algorithm> |
24 | | #include <system_error> |
25 | | |
26 | | using namespace llvm; |
27 | | |
28 | | //===----------------------------------------------------------------------===// |
29 | | // GCOVFile implementation. |
30 | | |
31 | | /// readGCNO - Read GCNO buffer. |
32 | 31 | bool GCOVFile::readGCNO(GCOVBuffer &Buffer) { |
33 | 31 | if (!Buffer.readGCNOFormat()) |
34 | 0 | return false; |
35 | 31 | if (!Buffer.readGCOVVersion(Version)) |
36 | 0 | return false; |
37 | 31 | |
38 | 31 | if (!Buffer.readInt(Checksum)) |
39 | 0 | return false; |
40 | 248 | while (31 true) { |
41 | 248 | if (!Buffer.readFunctionTag()) |
42 | 30 | break; |
43 | 218 | auto GFun = make_unique<GCOVFunction>(*this); |
44 | 218 | if (!GFun->readGCNO(Buffer, Version)) |
45 | 1 | return false; |
46 | 217 | Functions.push_back(std::move(GFun)); |
47 | 217 | } |
48 | 31 | |
49 | 31 | GCNOInitialized = true; |
50 | 30 | return true; |
51 | 31 | } |
52 | | |
53 | | /// readGCDA - Read GCDA buffer. It is required that readGCDA() can only be |
54 | | /// called after readGCNO(). |
55 | 23 | bool GCOVFile::readGCDA(GCOVBuffer &Buffer) { |
56 | 23 | assert(GCNOInitialized && "readGCDA() can only be called after readGCNO()"); |
57 | 23 | if (!Buffer.readGCDAFormat()) |
58 | 0 | return false; |
59 | 23 | GCOV::GCOVVersion GCDAVersion; |
60 | 23 | if (!Buffer.readGCOVVersion(GCDAVersion)) |
61 | 0 | return false; |
62 | 23 | if (Version != GCDAVersion) { |
63 | 0 | errs() << "GCOV versions do not match.\n"; |
64 | 0 | return false; |
65 | 0 | } |
66 | 23 | |
67 | 23 | uint32_t GCDAChecksum; |
68 | 23 | if (!Buffer.readInt(GCDAChecksum)) |
69 | 0 | return false; |
70 | 23 | if (Checksum != GCDAChecksum) { |
71 | 2 | errs() << "File checksums do not match: " << Checksum |
72 | 2 | << " != " << GCDAChecksum << ".\n"; |
73 | 2 | return false; |
74 | 2 | } |
75 | 200 | for (size_t i = 0, e = Functions.size(); 21 i < e; ++i179 ) { |
76 | 179 | if (!Buffer.readFunctionTag()) { |
77 | 0 | errs() << "Unexpected number of functions.\n"; |
78 | 0 | return false; |
79 | 0 | } |
80 | 179 | if (!Functions[i]->readGCDA(Buffer, Version)) |
81 | 0 | return false; |
82 | 179 | } |
83 | 21 | if (Buffer.readObjectTag()) { |
84 | 21 | uint32_t Length; |
85 | 21 | uint32_t Dummy; |
86 | 21 | if (!Buffer.readInt(Length)) |
87 | 0 | return false; |
88 | 21 | if (!Buffer.readInt(Dummy)) |
89 | 0 | return false; // checksum |
90 | 21 | if (!Buffer.readInt(Dummy)) |
91 | 0 | return false; // num |
92 | 21 | if (!Buffer.readInt(RunCount)) |
93 | 0 | return false; |
94 | 21 | Buffer.advanceCursor(Length - 3); |
95 | 21 | } |
96 | 42 | while (21 Buffer.readProgramTag()) { |
97 | 21 | uint32_t Length; |
98 | 21 | if (!Buffer.readInt(Length)) |
99 | 0 | return false; |
100 | 21 | Buffer.advanceCursor(Length); |
101 | 21 | ++ProgramCount; |
102 | 21 | } |
103 | 21 | |
104 | 21 | return true; |
105 | 21 | } |
106 | | |
107 | 6 | void GCOVFile::print(raw_ostream &OS) const { |
108 | 6 | for (const auto &FPtr : Functions) |
109 | 8 | FPtr->print(OS); |
110 | 6 | } |
111 | | |
112 | | #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) |
113 | | /// dump - Dump GCOVFile content to dbgs() for debugging purposes. |
114 | | LLVM_DUMP_METHOD void GCOVFile::dump() const { print(dbgs()); } |
115 | | #endif |
116 | | |
117 | | /// collectLineCounts - Collect line counts. This must be used after |
118 | | /// reading .gcno and .gcda files. |
119 | 28 | void GCOVFile::collectLineCounts(FileInfo &FI) { |
120 | 28 | for (const auto &FPtr : Functions) |
121 | 197 | FPtr->collectLineCounts(FI); |
122 | 28 | FI.setRunCount(RunCount); |
123 | 28 | FI.setProgramCount(ProgramCount); |
124 | 28 | } |
125 | | |
126 | | //===----------------------------------------------------------------------===// |
127 | | // GCOVFunction implementation. |
128 | | |
129 | | /// readGCNO - Read a function from the GCNO buffer. Return false if an error |
130 | | /// occurs. |
131 | 218 | bool GCOVFunction::readGCNO(GCOVBuffer &Buff, GCOV::GCOVVersion Version) { |
132 | 218 | uint32_t Dummy; |
133 | 218 | if (!Buff.readInt(Dummy)) |
134 | 0 | return false; // Function header length |
135 | 218 | if (!Buff.readInt(Ident)) |
136 | 0 | return false; |
137 | 218 | if (!Buff.readInt(Checksum)) |
138 | 0 | return false; |
139 | 218 | if (Version != GCOV::V402) { |
140 | 1 | uint32_t CfgChecksum; |
141 | 1 | if (!Buff.readInt(CfgChecksum)) |
142 | 0 | return false; |
143 | 1 | if (Parent.getChecksum() != CfgChecksum) { |
144 | 0 | errs() << "File checksums do not match: " << Parent.getChecksum() |
145 | 0 | << " != " << CfgChecksum << " in (" << Name << ").\n"; |
146 | 0 | return false; |
147 | 0 | } |
148 | 218 | } |
149 | 218 | if (!Buff.readString(Name)) |
150 | 0 | return false; |
151 | 218 | if (!Buff.readString(Filename)) |
152 | 0 | return false; |
153 | 218 | if (!Buff.readInt(LineNumber)) |
154 | 0 | return false; |
155 | 218 | |
156 | 218 | // read blocks. |
157 | 218 | if (!Buff.readBlockTag()) { |
158 | 0 | errs() << "Block tag not found.\n"; |
159 | 0 | return false; |
160 | 0 | } |
161 | 218 | uint32_t BlockCount; |
162 | 218 | if (!Buff.readInt(BlockCount)) |
163 | 1 | return false; |
164 | 1.36k | for (uint32_t i = 0, e = BlockCount; 217 i != e; ++i1.14k ) { |
165 | 1.14k | if (!Buff.readInt(Dummy)) |
166 | 0 | return false; // Block flags; |
167 | 1.14k | Blocks.push_back(make_unique<GCOVBlock>(*this, i)); |
168 | 1.14k | } |
169 | 217 | |
170 | 217 | // read edges. |
171 | 1.14k | while (217 Buff.readEdgeTag()) { |
172 | 926 | uint32_t EdgeCount; |
173 | 926 | if (!Buff.readInt(EdgeCount)) |
174 | 0 | return false; |
175 | 926 | EdgeCount = (EdgeCount - 1) / 2; |
176 | 926 | uint32_t BlockNo; |
177 | 926 | if (!Buff.readInt(BlockNo)) |
178 | 0 | return false; |
179 | 926 | if (BlockNo >= BlockCount) { |
180 | 0 | errs() << "Unexpected block number: " << BlockNo << " (in " << Name |
181 | 0 | << ").\n"; |
182 | 0 | return false; |
183 | 0 | } |
184 | 2.03k | for (uint32_t i = 0, e = EdgeCount; 926 i != e; ++i1.11k ) { |
185 | 1.11k | uint32_t Dst; |
186 | 1.11k | if (!Buff.readInt(Dst)) |
187 | 0 | return false; |
188 | 1.11k | Edges.push_back(make_unique<GCOVEdge>(*Blocks[BlockNo], *Blocks[Dst])); |
189 | 1.11k | GCOVEdge *Edge = Edges.back().get(); |
190 | 1.11k | Blocks[BlockNo]->addDstEdge(Edge); |
191 | 1.11k | Blocks[Dst]->addSrcEdge(Edge); |
192 | 1.11k | if (!Buff.readInt(Dummy)) |
193 | 0 | return false; // Edge flag |
194 | 1.11k | } |
195 | 926 | } |
196 | 217 | |
197 | 217 | // read line table. |
198 | 1.14k | while (217 Buff.readLineTag()) { |
199 | 926 | uint32_t LineTableLength; |
200 | 926 | // Read the length of this line table. |
201 | 926 | if (!Buff.readInt(LineTableLength)) |
202 | 0 | return false; |
203 | 926 | uint32_t EndPos = Buff.getCursor() + LineTableLength * 4; |
204 | 926 | uint32_t BlockNo; |
205 | 926 | // Read the block number this table is associated with. |
206 | 926 | if (!Buff.readInt(BlockNo)) |
207 | 0 | return false; |
208 | 926 | if (BlockNo >= BlockCount) { |
209 | 0 | errs() << "Unexpected block number: " << BlockNo << " (in " << Name |
210 | 0 | << ").\n"; |
211 | 0 | return false; |
212 | 0 | } |
213 | 926 | GCOVBlock &Block = *Blocks[BlockNo]; |
214 | 926 | // Read the word that pads the beginning of the line table. This may be a |
215 | 926 | // flag of some sort, but seems to always be zero. |
216 | 926 | if (!Buff.readInt(Dummy)) |
217 | 0 | return false; |
218 | 926 | |
219 | 926 | // Line information starts here and continues up until the last word. |
220 | 926 | if (Buff.getCursor() != (EndPos - sizeof(uint32_t))) { |
221 | 721 | StringRef F; |
222 | 721 | // Read the source file name. |
223 | 721 | if (!Buff.readString(F)) |
224 | 0 | return false; |
225 | 721 | if (Filename != F) { |
226 | 0 | errs() << "Multiple sources for a single basic block: " << Filename |
227 | 0 | << " != " << F << " (in " << Name << ").\n"; |
228 | 0 | return false; |
229 | 0 | } |
230 | 721 | // Read lines up to, but not including, the null terminator. |
231 | 1.76k | while (721 Buff.getCursor() < (EndPos - 2 * sizeof(uint32_t))) { |
232 | 1.03k | uint32_t Line; |
233 | 1.03k | if (!Buff.readInt(Line)) |
234 | 0 | return false; |
235 | 1.03k | // Line 0 means this instruction was injected by the compiler. Skip it. |
236 | 1.03k | if (!Line) |
237 | 3 | continue; |
238 | 1.03k | Block.addLine(Line); |
239 | 1.03k | } |
240 | 721 | // Read the null terminator. |
241 | 721 | if (!Buff.readInt(Dummy)) |
242 | 0 | return false; |
243 | 926 | } |
244 | 926 | // The last word is either a flag or padding, it isn't clear which. Skip |
245 | 926 | // over it. |
246 | 926 | if (!Buff.readInt(Dummy)) |
247 | 0 | return false; |
248 | 926 | } |
249 | 217 | return true; |
250 | 217 | } |
251 | | |
252 | | /// readGCDA - Read a function from the GCDA buffer. Return false if an error |
253 | | /// occurs. |
254 | 179 | bool GCOVFunction::readGCDA(GCOVBuffer &Buff, GCOV::GCOVVersion Version) { |
255 | 179 | uint32_t HeaderLength; |
256 | 179 | if (!Buff.readInt(HeaderLength)) |
257 | 0 | return false; // Function header length |
258 | 179 | |
259 | 179 | uint64_t EndPos = Buff.getCursor() + HeaderLength * sizeof(uint32_t); |
260 | 179 | |
261 | 179 | uint32_t GCDAIdent; |
262 | 179 | if (!Buff.readInt(GCDAIdent)) |
263 | 0 | return false; |
264 | 179 | if (Ident != GCDAIdent) { |
265 | 0 | errs() << "Function identifiers do not match: " << Ident |
266 | 0 | << " != " << GCDAIdent << " (in " << Name << ").\n"; |
267 | 0 | return false; |
268 | 0 | } |
269 | 179 | |
270 | 179 | uint32_t GCDAChecksum; |
271 | 179 | if (!Buff.readInt(GCDAChecksum)) |
272 | 0 | return false; |
273 | 179 | if (Checksum != GCDAChecksum) { |
274 | 0 | errs() << "Function checksums do not match: " << Checksum |
275 | 0 | << " != " << GCDAChecksum << " (in " << Name << ").\n"; |
276 | 0 | return false; |
277 | 0 | } |
278 | 179 | |
279 | 179 | uint32_t CfgChecksum; |
280 | 179 | if (Version != GCOV::V402) { |
281 | 1 | if (!Buff.readInt(CfgChecksum)) |
282 | 0 | return false; |
283 | 1 | if (Parent.getChecksum() != CfgChecksum) { |
284 | 0 | errs() << "File checksums do not match: " << Parent.getChecksum() |
285 | 0 | << " != " << CfgChecksum << " (in " << Name << ").\n"; |
286 | 0 | return false; |
287 | 0 | } |
288 | 179 | } |
289 | 179 | |
290 | 179 | if (Buff.getCursor() < EndPos) { |
291 | 178 | StringRef GCDAName; |
292 | 178 | if (!Buff.readString(GCDAName)) |
293 | 0 | return false; |
294 | 178 | if (Name != GCDAName) { |
295 | 0 | errs() << "Function names do not match: " << Name << " != " << GCDAName |
296 | 0 | << ".\n"; |
297 | 0 | return false; |
298 | 0 | } |
299 | 179 | } |
300 | 179 | |
301 | 179 | if (!Buff.readArcTag()) { |
302 | 0 | errs() << "Arc tag not found (in " << Name << ").\n"; |
303 | 0 | return false; |
304 | 0 | } |
305 | 179 | |
306 | 179 | uint32_t Count; |
307 | 179 | if (!Buff.readInt(Count)) |
308 | 0 | return false; |
309 | 179 | Count /= 2; |
310 | 179 | |
311 | 179 | // This for loop adds the counts for each block. A second nested loop is |
312 | 179 | // required to combine the edge counts that are contained in the GCDA file. |
313 | 950 | for (uint32_t BlockNo = 0; Count > 0; ++BlockNo771 ) { |
314 | 771 | // The last block is always reserved for exit block |
315 | 771 | if (BlockNo >= Blocks.size()) { |
316 | 0 | errs() << "Unexpected number of edges (in " << Name << ").\n"; |
317 | 0 | return false; |
318 | 0 | } |
319 | 771 | if (BlockNo == Blocks.size() - 1) |
320 | 1 | errs() << "(" << Name << ") has arcs from exit block.\n"; |
321 | 771 | GCOVBlock &Block = *Blocks[BlockNo]; |
322 | 1.69k | for (size_t EdgeNo = 0, End = Block.getNumDstEdges(); EdgeNo < End; |
323 | 924 | ++EdgeNo) { |
324 | 924 | if (Count == 0) { |
325 | 0 | errs() << "Unexpected number of edges (in " << Name << ").\n"; |
326 | 0 | return false; |
327 | 0 | } |
328 | 924 | uint64_t ArcCount; |
329 | 924 | if (!Buff.readInt64(ArcCount)) |
330 | 0 | return false; |
331 | 924 | Block.addCount(EdgeNo, ArcCount); |
332 | 924 | --Count; |
333 | 924 | } |
334 | 771 | Block.sortDstEdges(); |
335 | 771 | } |
336 | 179 | return true; |
337 | 179 | } |
338 | | |
339 | | /// getEntryCount - Get the number of times the function was called by |
340 | | /// retrieving the entry block's count. |
341 | 40 | uint64_t GCOVFunction::getEntryCount() const { |
342 | 40 | return Blocks.front()->getCount(); |
343 | 40 | } |
344 | | |
345 | | /// getExitCount - Get the number of times the function returned by retrieving |
346 | | /// the exit block's count. |
347 | 40 | uint64_t GCOVFunction::getExitCount() const { |
348 | 40 | return Blocks.back()->getCount(); |
349 | 40 | } |
350 | | |
351 | 8 | void GCOVFunction::print(raw_ostream &OS) const { |
352 | 8 | OS << "===== " << Name << " (" << Ident << ") @ " << Filename << ":" |
353 | 8 | << LineNumber << "\n"; |
354 | 8 | for (const auto &Block : Blocks) |
355 | 32 | Block->print(OS); |
356 | 8 | } |
357 | | |
358 | | #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) |
359 | | /// dump - Dump GCOVFunction content to dbgs() for debugging purposes. |
360 | | LLVM_DUMP_METHOD void GCOVFunction::dump() const { print(dbgs()); } |
361 | | #endif |
362 | | |
363 | | /// collectLineCounts - Collect line counts. This must be used after |
364 | | /// reading .gcno and .gcda files. |
365 | 197 | void GCOVFunction::collectLineCounts(FileInfo &FI) { |
366 | 197 | // If the line number is zero, this is a function that doesn't actually appear |
367 | 197 | // in the source file, so there isn't anything we can do with it. |
368 | 197 | if (LineNumber == 0) |
369 | 2 | return; |
370 | 195 | |
371 | 195 | for (const auto &Block : Blocks) |
372 | 1.02k | Block->collectLineCounts(FI); |
373 | 195 | FI.addFunctionLine(Filename, LineNumber, this); |
374 | 195 | } |
375 | | |
376 | | //===----------------------------------------------------------------------===// |
377 | | // GCOVBlock implementation. |
378 | | |
379 | | /// ~GCOVBlock - Delete GCOVBlock and its content. |
380 | 1.14k | GCOVBlock::~GCOVBlock() { |
381 | 1.14k | SrcEdges.clear(); |
382 | 1.14k | DstEdges.clear(); |
383 | 1.14k | Lines.clear(); |
384 | 1.14k | } |
385 | | |
386 | | /// addCount - Add to block counter while storing the edge count. If the |
387 | | /// destination has no outgoing edges, also update that block's count too. |
388 | 924 | void GCOVBlock::addCount(size_t DstEdgeNo, uint64_t N) { |
389 | 924 | assert(DstEdgeNo < DstEdges.size()); // up to caller to ensure EdgeNo is valid |
390 | 924 | DstEdges[DstEdgeNo]->Count = N; |
391 | 924 | Counter += N; |
392 | 924 | if (!DstEdges[DstEdgeNo]->Dst.getNumDstEdges()) |
393 | 179 | DstEdges[DstEdgeNo]->Dst.Counter += N; |
394 | 924 | } |
395 | | |
396 | | /// sortDstEdges - Sort destination edges by block number, nop if already |
397 | | /// sorted. This is required for printing branch info in the correct order. |
398 | 771 | void GCOVBlock::sortDstEdges() { |
399 | 771 | if (!DstEdgesAreSorted) |
400 | 119 | llvm::stable_sort(DstEdges, [](const GCOVEdge *E1, const GCOVEdge *E2) 17 { |
401 | 119 | return E1->Dst.Number < E2->Dst.Number; |
402 | 119 | }); |
403 | 771 | } |
404 | | |
405 | | /// collectLineCounts - Collect line counts. This must be used after |
406 | | /// reading .gcno and .gcda files. |
407 | 1.02k | void GCOVBlock::collectLineCounts(FileInfo &FI) { |
408 | 1.02k | for (uint32_t N : Lines) |
409 | 938 | FI.addBlockLine(Parent.getFilename(), N, this); |
410 | 1.02k | } |
411 | | |
412 | 32 | void GCOVBlock::print(raw_ostream &OS) const { |
413 | 32 | OS << "Block : " << Number << " Counter : " << Counter << "\n"; |
414 | 32 | if (!SrcEdges.empty()) { |
415 | 24 | OS << "\tSource Edges : "; |
416 | 24 | for (const GCOVEdge *Edge : SrcEdges) |
417 | 28 | OS << Edge->Src.Number << " (" << Edge->Count << "), "; |
418 | 24 | OS << "\n"; |
419 | 24 | } |
420 | 32 | if (!DstEdges.empty()) { |
421 | 24 | OS << "\tDestination Edges : "; |
422 | 24 | for (const GCOVEdge *Edge : DstEdges) |
423 | 28 | OS << Edge->Dst.Number << " (" << Edge->Count << "), "; |
424 | 24 | OS << "\n"; |
425 | 24 | } |
426 | 32 | if (!Lines.empty()) { |
427 | 24 | OS << "\tLines : "; |
428 | 24 | for (uint32_t N : Lines) |
429 | 32 | OS << (N) << ","; |
430 | 24 | OS << "\n"; |
431 | 24 | } |
432 | 32 | } |
433 | | |
434 | | #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) |
435 | | /// dump - Dump GCOVBlock content to dbgs() for debugging purposes. |
436 | | LLVM_DUMP_METHOD void GCOVBlock::dump() const { print(dbgs()); } |
437 | | #endif |
438 | | |
439 | | //===----------------------------------------------------------------------===// |
440 | | // Cycles detection |
441 | | // |
442 | | // The algorithm in GCC is based on the algorihtm by Hawick & James: |
443 | | // "Enumerating Circuits and Loops in Graphs with Self-Arcs and Multiple-Arcs" |
444 | | // http://complexity.massey.ac.nz/cstn/013/cstn-013.pdf. |
445 | | |
446 | | /// Get the count for the detected cycle. |
447 | 1 | uint64_t GCOVBlock::getCycleCount(const Edges &Path) { |
448 | 1 | uint64_t CycleCount = std::numeric_limits<uint64_t>::max(); |
449 | 3 | for (auto E : Path) { |
450 | 3 | CycleCount = std::min(E->CyclesCount, CycleCount); |
451 | 3 | } |
452 | 3 | for (auto E : Path) { |
453 | 3 | E->CyclesCount -= CycleCount; |
454 | 3 | } |
455 | 1 | return CycleCount; |
456 | 1 | } |
457 | | |
458 | | /// Unblock a vertex previously marked as blocked. |
459 | | void GCOVBlock::unblock(const GCOVBlock *U, BlockVector &Blocked, |
460 | 3 | BlockVectorLists &BlockLists) { |
461 | 3 | auto it = find(Blocked, U); |
462 | 3 | if (it == Blocked.end()) { |
463 | 0 | return; |
464 | 0 | } |
465 | 3 | |
466 | 3 | const size_t index = it - Blocked.begin(); |
467 | 3 | Blocked.erase(it); |
468 | 3 | |
469 | 3 | const BlockVector ToUnblock(BlockLists[index]); |
470 | 3 | BlockLists.erase(BlockLists.begin() + index); |
471 | 3 | for (auto GB : ToUnblock) { |
472 | 0 | GCOVBlock::unblock(GB, Blocked, BlockLists); |
473 | 0 | } |
474 | 3 | } |
475 | | |
476 | | bool GCOVBlock::lookForCircuit(const GCOVBlock *V, const GCOVBlock *Start, |
477 | | Edges &Path, BlockVector &Blocked, |
478 | | BlockVectorLists &BlockLists, |
479 | 1.04k | const BlockVector &Blocks, uint64_t &Count) { |
480 | 1.04k | Blocked.push_back(V); |
481 | 1.04k | BlockLists.emplace_back(BlockVector()); |
482 | 1.04k | bool FoundCircuit = false; |
483 | 1.04k | |
484 | 1.35k | for (auto E : V->dsts()) { |
485 | 1.35k | const GCOVBlock *W = &E->Dst; |
486 | 1.35k | if (W < Start || find(Blocks, W) == Blocks.end()1.27k ) { |
487 | 1.24k | continue; |
488 | 1.24k | } |
489 | 108 | |
490 | 108 | Path.push_back(E); |
491 | 108 | |
492 | 108 | if (W == Start) { |
493 | 1 | // We've a cycle. |
494 | 1 | Count += GCOVBlock::getCycleCount(Path); |
495 | 1 | FoundCircuit = true; |
496 | 107 | } else if (find(Blocked, W) == Blocked.end() && // W is not blocked. |
497 | 107 | GCOVBlock::lookForCircuit(W, Start, Path, Blocked, BlockLists, |
498 | 104 | Blocks, Count)) { |
499 | 2 | FoundCircuit = true; |
500 | 2 | } |
501 | 108 | |
502 | 108 | Path.pop_back(); |
503 | 108 | } |
504 | 1.04k | |
505 | 1.04k | if (FoundCircuit) { |
506 | 3 | GCOVBlock::unblock(V, Blocked, BlockLists); |
507 | 1.03k | } else { |
508 | 1.34k | for (auto E : V->dsts()) { |
509 | 1.34k | const GCOVBlock *W = &E->Dst; |
510 | 1.34k | if (W < Start || find(Blocks, W) == Blocks.end()1.27k ) { |
511 | 1.24k | continue; |
512 | 1.24k | } |
513 | 105 | const size_t index = find(Blocked, W) - Blocked.begin(); |
514 | 105 | BlockVector &List = BlockLists[index]; |
515 | 105 | if (find(List, V) == List.end()) { |
516 | 105 | List.push_back(V); |
517 | 105 | } |
518 | 105 | } |
519 | 1.03k | } |
520 | 1.04k | |
521 | 1.04k | return FoundCircuit; |
522 | 1.04k | } |
523 | | |
524 | | /// Get the count for the list of blocks which lie on the same line. |
525 | 738 | void GCOVBlock::getCyclesCount(const BlockVector &Blocks, uint64_t &Count) { |
526 | 938 | for (auto Block : Blocks) { |
527 | 938 | Edges Path; |
528 | 938 | BlockVector Blocked; |
529 | 938 | BlockVectorLists BlockLists; |
530 | 938 | |
531 | 938 | GCOVBlock::lookForCircuit(Block, Block, Path, Blocked, BlockLists, Blocks, |
532 | 938 | Count); |
533 | 938 | } |
534 | 738 | } |
535 | | |
536 | | /// Get the count for the list of blocks which lie on the same line. |
537 | 738 | uint64_t GCOVBlock::getLineCount(const BlockVector &Blocks) { |
538 | 738 | uint64_t Count = 0; |
539 | 738 | |
540 | 938 | for (auto Block : Blocks) { |
541 | 938 | if (Block->getNumSrcEdges() == 0) { |
542 | 18 | // The block has no predecessors and a non-null counter |
543 | 18 | // (can be the case with entry block in functions). |
544 | 18 | Count += Block->getCount(); |
545 | 920 | } else { |
546 | 920 | // Add counts from predecessors that are not on the same line. |
547 | 1.10k | for (auto E : Block->srcs()) { |
548 | 1.10k | const GCOVBlock *W = &E->Src; |
549 | 1.10k | if (find(Blocks, W) == Blocks.end()) { |
550 | 943 | Count += E->Count; |
551 | 943 | } |
552 | 1.10k | } |
553 | 920 | } |
554 | 1.16k | for (auto E : Block->dsts()) { |
555 | 1.16k | E->CyclesCount = E->Count; |
556 | 1.16k | } |
557 | 938 | } |
558 | 738 | |
559 | 738 | GCOVBlock::getCyclesCount(Blocks, Count); |
560 | 738 | |
561 | 738 | return Count; |
562 | 738 | } |
563 | | |
564 | | //===----------------------------------------------------------------------===// |
565 | | // FileInfo implementation. |
566 | | |
567 | | // Safe integer division, returns 0 if numerator is 0. |
568 | 80 | static uint32_t safeDiv(uint64_t Numerator, uint64_t Divisor) { |
569 | 80 | if (!Numerator) |
570 | 24 | return 0; |
571 | 56 | return Numerator / Divisor; |
572 | 56 | } |
573 | | |
574 | | // This custom division function mimics gcov's branch ouputs: |
575 | | // - Round to closest whole number |
576 | | // - Only output 0% or 100% if it's exactly that value |
577 | 69 | static uint32_t branchDiv(uint64_t Numerator, uint64_t Divisor) { |
578 | 69 | if (!Numerator) |
579 | 6 | return 0; |
580 | 63 | if (Numerator == Divisor) |
581 | 27 | return 100; |
582 | 36 | |
583 | 36 | uint8_t Res = (Numerator * 100 + Divisor / 2) / Divisor; |
584 | 36 | if (Res == 0) |
585 | 3 | return 1; |
586 | 33 | if (Res == 100) |
587 | 3 | return 99; |
588 | 30 | return Res; |
589 | 30 | } |
590 | | |
591 | | namespace { |
592 | | struct formatBranchInfo { |
593 | | formatBranchInfo(const GCOV::Options &Options, uint64_t Count, uint64_t Total) |
594 | 116 | : Options(Options), Count(Count), Total(Total) {} |
595 | | |
596 | 116 | void print(raw_ostream &OS) const { |
597 | 116 | if (!Total) |
598 | 8 | OS << "never executed"; |
599 | 108 | else if (Options.BranchCount) |
600 | 39 | OS << "taken " << Count; |
601 | 69 | else |
602 | 69 | OS << "taken " << branchDiv(Count, Total) << "%"; |
603 | 116 | } |
604 | | |
605 | | const GCOV::Options &Options; |
606 | | uint64_t Count; |
607 | | uint64_t Total; |
608 | | }; |
609 | | |
610 | 116 | static raw_ostream &operator<<(raw_ostream &OS, const formatBranchInfo &FBI) { |
611 | 116 | FBI.print(OS); |
612 | 116 | return OS; |
613 | 116 | } |
614 | | |
615 | | class LineConsumer { |
616 | | std::unique_ptr<MemoryBuffer> Buffer; |
617 | | StringRef Remaining; |
618 | | |
619 | | public: |
620 | 46 | LineConsumer(StringRef Filename) { |
621 | 46 | ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr = |
622 | 46 | MemoryBuffer::getFileOrSTDIN(Filename); |
623 | 46 | if (std::error_code EC = BufferOrErr.getError()) { |
624 | 9 | errs() << Filename << ": " << EC.message() << "\n"; |
625 | 9 | Remaining = ""; |
626 | 37 | } else { |
627 | 37 | Buffer = std::move(BufferOrErr.get()); |
628 | 37 | Remaining = Buffer->getBuffer(); |
629 | 37 | } |
630 | 46 | } |
631 | 1.64k | bool empty() { return Remaining.empty(); } |
632 | 1.51k | void printNext(raw_ostream &OS, uint32_t LineNum) { |
633 | 1.51k | StringRef Line; |
634 | 1.51k | if (empty()) |
635 | 116 | Line = "/*EOF*/"; |
636 | 1.40k | else |
637 | 1.40k | std::tie(Line, Remaining) = Remaining.split("\n"); |
638 | 1.51k | OS << format("%5u:", LineNum) << Line << "\n"; |
639 | 1.51k | } |
640 | | }; |
641 | | } // end anonymous namespace |
642 | | |
643 | | /// Convert a path to a gcov filename. If PreservePaths is true, this |
644 | | /// translates "/" to "#", ".." to "^", and drops ".", to match gcov. |
645 | 42 | static std::string mangleCoveragePath(StringRef Filename, bool PreservePaths) { |
646 | 42 | if (!PreservePaths) |
647 | 36 | return sys::path::filename(Filename).str(); |
648 | 6 | |
649 | 6 | // This behaviour is defined by gcov in terms of text replacements, so it's |
650 | 6 | // not likely to do anything useful on filesystems with different textual |
651 | 6 | // conventions. |
652 | 6 | llvm::SmallString<256> Result(""); |
653 | 6 | StringRef::iterator I, S, E; |
654 | 174 | for (I = S = Filename.begin(), E = Filename.end(); I != E; ++I168 ) { |
655 | 168 | if (*I != '/') |
656 | 148 | continue; |
657 | 20 | |
658 | 20 | if (I - S == 1 && *S == '.'4 ) { |
659 | 4 | // ".", the current directory, is skipped. |
660 | 16 | } else if (I - S == 2 && *S == '.'6 && *(S + 1) == '.'6 ) { |
661 | 6 | // "..", the parent directory, is replaced with "^". |
662 | 6 | Result.append("^#"); |
663 | 10 | } else { |
664 | 10 | if (S < I) |
665 | 10 | // Leave other components intact, |
666 | 10 | Result.append(S, I); |
667 | 10 | // And separate with "#". |
668 | 10 | Result.push_back('#'); |
669 | 10 | } |
670 | 20 | S = I + 1; |
671 | 20 | } |
672 | 6 | |
673 | 6 | if (S < I) |
674 | 6 | Result.append(S, I); |
675 | 6 | return Result.str(); |
676 | 6 | } |
677 | | |
678 | | std::string FileInfo::getCoveragePath(StringRef Filename, |
679 | 46 | StringRef MainFilename) { |
680 | 46 | if (Options.NoOutput) |
681 | 8 | // This is probably a bug in gcov, but when -n is specified, paths aren't |
682 | 8 | // mangled at all, and the -l and -p options are ignored. Here, we do the |
683 | 8 | // same. |
684 | 8 | return Filename; |
685 | 38 | |
686 | 38 | std::string CoveragePath; |
687 | 38 | if (Options.LongFileNames && !Filename.equals(MainFilename)4 ) |
688 | 4 | CoveragePath = |
689 | 4 | mangleCoveragePath(MainFilename, Options.PreservePaths) + "##"; |
690 | 38 | CoveragePath += mangleCoveragePath(Filename, Options.PreservePaths); |
691 | 38 | if (Options.HashFilenames) { |
692 | 2 | MD5 Hasher; |
693 | 2 | MD5::MD5Result Result; |
694 | 2 | Hasher.update(Filename.str()); |
695 | 2 | Hasher.final(Result); |
696 | 2 | CoveragePath += "##" + Result.digest().str().str(); |
697 | 2 | } |
698 | 38 | CoveragePath += ".gcov"; |
699 | 38 | return CoveragePath; |
700 | 38 | } |
701 | | |
702 | | std::unique_ptr<raw_ostream> |
703 | 46 | FileInfo::openCoveragePath(StringRef CoveragePath) { |
704 | 46 | if (Options.NoOutput) |
705 | 8 | return llvm::make_unique<raw_null_ostream>(); |
706 | 38 | |
707 | 38 | std::error_code EC; |
708 | 38 | auto OS = |
709 | 38 | llvm::make_unique<raw_fd_ostream>(CoveragePath, EC, sys::fs::F_Text); |
710 | 38 | if (EC) { |
711 | 0 | errs() << EC.message() << "\n"; |
712 | 0 | return llvm::make_unique<raw_null_ostream>(); |
713 | 0 | } |
714 | 38 | return std::move(OS); |
715 | 38 | } |
716 | | |
717 | | /// print - Print source files with collected line count information. |
718 | | void FileInfo::print(raw_ostream &InfoOS, StringRef MainFilename, |
719 | 28 | StringRef GCNOFile, StringRef GCDAFile) { |
720 | 28 | SmallVector<StringRef, 4> Filenames; |
721 | 28 | for (const auto &LI : LineInfo) |
722 | 46 | Filenames.push_back(LI.first()); |
723 | 28 | llvm::sort(Filenames); |
724 | 28 | |
725 | 46 | for (StringRef Filename : Filenames) { |
726 | 46 | auto AllLines = LineConsumer(Filename); |
727 | 46 | |
728 | 46 | std::string CoveragePath = getCoveragePath(Filename, MainFilename); |
729 | 46 | std::unique_ptr<raw_ostream> CovStream = openCoveragePath(CoveragePath); |
730 | 46 | raw_ostream &CovOS = *CovStream; |
731 | 46 | |
732 | 46 | CovOS << " -: 0:Source:" << Filename << "\n"; |
733 | 46 | CovOS << " -: 0:Graph:" << GCNOFile << "\n"; |
734 | 46 | CovOS << " -: 0:Data:" << GCDAFile << "\n"; |
735 | 46 | CovOS << " -: 0:Runs:" << RunCount << "\n"; |
736 | 46 | CovOS << " -: 0:Programs:" << ProgramCount << "\n"; |
737 | 46 | |
738 | 46 | const LineData &Line = LineInfo[Filename]; |
739 | 46 | GCOVCoverage FileCoverage(Filename); |
740 | 1.56k | for (uint32_t LineIndex = 0; LineIndex < Line.LastLine || !AllLines.empty()125 ; |
741 | 1.51k | ++LineIndex) { |
742 | 1.51k | if (Options.BranchInfo) { |
743 | 308 | FunctionLines::const_iterator FuncsIt = Line.Functions.find(LineIndex); |
744 | 308 | if (FuncsIt != Line.Functions.end()) |
745 | 36 | printFunctionSummary(CovOS, FuncsIt->second); |
746 | 308 | } |
747 | 1.51k | |
748 | 1.51k | BlockLines::const_iterator BlocksIt = Line.Blocks.find(LineIndex); |
749 | 1.51k | if (BlocksIt == Line.Blocks.end()) { |
750 | 778 | // No basic blocks are on this line. Not an executable line of code. |
751 | 778 | CovOS << " -:"; |
752 | 778 | AllLines.printNext(CovOS, LineIndex + 1); |
753 | 778 | } else { |
754 | 738 | const BlockVector &Blocks = BlocksIt->second; |
755 | 738 | |
756 | 738 | // Add up the block counts to form line counts. |
757 | 738 | DenseMap<const GCOVFunction *, bool> LineExecs; |
758 | 938 | for (const GCOVBlock *Block : Blocks) { |
759 | 938 | if (Options.FuncCoverage) { |
760 | 98 | // This is a slightly convoluted way to most accurately gather line |
761 | 98 | // statistics for functions. Basically what is happening is that we |
762 | 98 | // don't want to count a single line with multiple blocks more than |
763 | 98 | // once. However, we also don't simply want to give the total line |
764 | 98 | // count to every function that starts on the line. Thus, what is |
765 | 98 | // happening here are two things: |
766 | 98 | // 1) Ensure that the number of logical lines is only incremented |
767 | 98 | // once per function. |
768 | 98 | // 2) If there are multiple blocks on the same line, ensure that the |
769 | 98 | // number of lines executed is incremented as long as at least |
770 | 98 | // one of the blocks are executed. |
771 | 98 | const GCOVFunction *Function = &Block->getParent(); |
772 | 98 | if (FuncCoverages.find(Function) == FuncCoverages.end()) { |
773 | 20 | std::pair<const GCOVFunction *, GCOVCoverage> KeyValue( |
774 | 20 | Function, GCOVCoverage(Function->getName())); |
775 | 20 | FuncCoverages.insert(KeyValue); |
776 | 20 | } |
777 | 98 | GCOVCoverage &FuncCoverage = FuncCoverages.find(Function)->second; |
778 | 98 | |
779 | 98 | if (LineExecs.find(Function) == LineExecs.end()) { |
780 | 80 | if (Block->getCount()) { |
781 | 68 | ++FuncCoverage.LinesExec; |
782 | 68 | LineExecs[Function] = true; |
783 | 68 | } else { |
784 | 12 | LineExecs[Function] = false; |
785 | 12 | } |
786 | 80 | ++FuncCoverage.LogicalLines; |
787 | 80 | } else if (18 !LineExecs[Function]18 && Block->getCount()0 ) { |
788 | 0 | ++FuncCoverage.LinesExec; |
789 | 0 | LineExecs[Function] = true; |
790 | 0 | } |
791 | 98 | } |
792 | 938 | } |
793 | 738 | |
794 | 738 | const uint64_t LineCount = GCOVBlock::getLineCount(Blocks); |
795 | 738 | if (LineCount == 0) |
796 | 165 | CovOS << " #####:"; |
797 | 573 | else { |
798 | 573 | CovOS << format("%9" PRIu64 ":", LineCount); |
799 | 573 | ++FileCoverage.LinesExec; |
800 | 573 | } |
801 | 738 | ++FileCoverage.LogicalLines; |
802 | 738 | |
803 | 738 | AllLines.printNext(CovOS, LineIndex + 1); |
804 | 738 | |
805 | 738 | uint32_t BlockNo = 0; |
806 | 738 | uint32_t EdgeNo = 0; |
807 | 938 | for (const GCOVBlock *Block : Blocks) { |
808 | 938 | // Only print block and branch information at the end of the block. |
809 | 938 | if (Block->getLastLine() != LineIndex + 1) |
810 | 283 | continue; |
811 | 655 | if (Options.AllBlocks) |
812 | 170 | printBlockInfo(CovOS, *Block, LineIndex, BlockNo); |
813 | 655 | if (Options.BranchInfo) { |
814 | 136 | size_t NumEdges = Block->getNumDstEdges(); |
815 | 136 | if (NumEdges > 1) |
816 | 24 | printBranchInfo(CovOS, *Block, FileCoverage, EdgeNo); |
817 | 112 | else if (Options.UncondBranch && NumEdges == 156 ) |
818 | 56 | printUncondBranchInfo(CovOS, EdgeNo, |
819 | 56 | (*Block->dst_begin())->Count); |
820 | 136 | } |
821 | 655 | } |
822 | 738 | } |
823 | 1.51k | } |
824 | 46 | FileCoverages.push_back(std::make_pair(CoveragePath, FileCoverage)); |
825 | 46 | } |
826 | 28 | |
827 | 28 | // FIXME: There is no way to detect calls given current instrumentation. |
828 | 28 | if (Options.FuncCoverage) |
829 | 2 | printFuncCoverage(InfoOS); |
830 | 28 | printFileCoverage(InfoOS); |
831 | 28 | } |
832 | | |
833 | | /// printFunctionSummary - Print function and block summary. |
834 | | void FileInfo::printFunctionSummary(raw_ostream &OS, |
835 | 36 | const FunctionVector &Funcs) const { |
836 | 40 | for (const GCOVFunction *Func : Funcs) { |
837 | 40 | uint64_t EntryCount = Func->getEntryCount(); |
838 | 40 | uint32_t BlocksExec = 0; |
839 | 40 | for (const GCOVBlock &Block : Func->blocks()) |
840 | 216 | if (Block.getNumDstEdges() && Block.getCount()176 ) |
841 | 148 | ++BlocksExec; |
842 | 40 | |
843 | 40 | OS << "function " << Func->getName() << " called " << EntryCount |
844 | 40 | << " returned " << safeDiv(Func->getExitCount() * 100, EntryCount) |
845 | 40 | << "% blocks executed " |
846 | 40 | << safeDiv(BlocksExec * 100, Func->getNumBlocks() - 1) << "%\n"; |
847 | 40 | } |
848 | 36 | } |
849 | | |
850 | | /// printBlockInfo - Output counts for each block. |
851 | | void FileInfo::printBlockInfo(raw_ostream &OS, const GCOVBlock &Block, |
852 | 170 | uint32_t LineIndex, uint32_t &BlockNo) const { |
853 | 170 | if (Block.getCount() == 0) |
854 | 20 | OS << " $$$$$:"; |
855 | 150 | else |
856 | 150 | OS << format("%9" PRIu64 ":", Block.getCount()); |
857 | 170 | OS << format("%5u-block %2u\n", LineIndex + 1, BlockNo++); |
858 | 170 | } |
859 | | |
860 | | /// printBranchInfo - Print conditional branch probabilities. |
861 | | void FileInfo::printBranchInfo(raw_ostream &OS, const GCOVBlock &Block, |
862 | 24 | GCOVCoverage &Coverage, uint32_t &EdgeNo) { |
863 | 24 | SmallVector<uint64_t, 16> BranchCounts; |
864 | 24 | uint64_t TotalCounts = 0; |
865 | 60 | for (const GCOVEdge *Edge : Block.dsts()) { |
866 | 60 | BranchCounts.push_back(Edge->Count); |
867 | 60 | TotalCounts += Edge->Count; |
868 | 60 | if (Block.getCount()) |
869 | 60 | ++Coverage.BranchesExec; |
870 | 60 | if (Edge->Count) |
871 | 52 | ++Coverage.BranchesTaken; |
872 | 60 | ++Coverage.Branches; |
873 | 60 | |
874 | 60 | if (Options.FuncCoverage) { |
875 | 15 | const GCOVFunction *Function = &Block.getParent(); |
876 | 15 | GCOVCoverage &FuncCoverage = FuncCoverages.find(Function)->second; |
877 | 15 | if (Block.getCount()) |
878 | 15 | ++FuncCoverage.BranchesExec; |
879 | 15 | if (Edge->Count) |
880 | 13 | ++FuncCoverage.BranchesTaken; |
881 | 15 | ++FuncCoverage.Branches; |
882 | 15 | } |
883 | 60 | } |
884 | 24 | |
885 | 24 | for (uint64_t N : BranchCounts) |
886 | 60 | OS << format("branch %2u ", EdgeNo++) |
887 | 60 | << formatBranchInfo(Options, N, TotalCounts) << "\n"; |
888 | 24 | } |
889 | | |
890 | | /// printUncondBranchInfo - Print unconditional branch probabilities. |
891 | | void FileInfo::printUncondBranchInfo(raw_ostream &OS, uint32_t &EdgeNo, |
892 | 56 | uint64_t Count) const { |
893 | 56 | OS << format("unconditional %2u ", EdgeNo++) |
894 | 56 | << formatBranchInfo(Options, Count, Count) << "\n"; |
895 | 56 | } |
896 | | |
897 | | // printCoverage - Print generic coverage info used by both printFuncCoverage |
898 | | // and printFileCoverage. |
899 | | void FileInfo::printCoverage(raw_ostream &OS, |
900 | 66 | const GCOVCoverage &Coverage) const { |
901 | 66 | OS << format("Lines executed:%.2f%% of %u\n", |
902 | 66 | double(Coverage.LinesExec) * 100 / Coverage.LogicalLines, |
903 | 66 | Coverage.LogicalLines); |
904 | 66 | if (Options.BranchInfo) { |
905 | 18 | if (Coverage.Branches) { |
906 | 6 | OS << format("Branches executed:%.2f%% of %u\n", |
907 | 6 | double(Coverage.BranchesExec) * 100 / Coverage.Branches, |
908 | 6 | Coverage.Branches); |
909 | 6 | OS << format("Taken at least once:%.2f%% of %u\n", |
910 | 6 | double(Coverage.BranchesTaken) * 100 / Coverage.Branches, |
911 | 6 | Coverage.Branches); |
912 | 12 | } else { |
913 | 12 | OS << "No branches\n"; |
914 | 12 | } |
915 | 18 | OS << "No calls\n"; // to be consistent with gcov |
916 | 18 | } |
917 | 66 | } |
918 | | |
919 | | // printFuncCoverage - Print per-function coverage info. |
920 | 2 | void FileInfo::printFuncCoverage(raw_ostream &OS) const { |
921 | 20 | for (const auto &FC : FuncCoverages) { |
922 | 20 | const GCOVCoverage &Coverage = FC.second; |
923 | 20 | OS << "Function '" << Coverage.Name << "'\n"; |
924 | 20 | printCoverage(OS, Coverage); |
925 | 20 | OS << "\n"; |
926 | 20 | } |
927 | 2 | } |
928 | | |
929 | | // printFileCoverage - Print per-file coverage info. |
930 | 28 | void FileInfo::printFileCoverage(raw_ostream &OS) const { |
931 | 46 | for (const auto &FC : FileCoverages) { |
932 | 46 | const std::string &Filename = FC.first; |
933 | 46 | const GCOVCoverage &Coverage = FC.second; |
934 | 46 | OS << "File '" << Coverage.Name << "'\n"; |
935 | 46 | printCoverage(OS, Coverage); |
936 | 46 | if (!Options.NoOutput) |
937 | 38 | OS << Coverage.Name << ":creating '" << Filename << "'\n"; |
938 | 46 | OS << "\n"; |
939 | 46 | } |
940 | 28 | } |