Mercurial > hg > CbC > CbC_llvm
comparison tools/llvm-cov/CodeCoverage.cpp @ 83:60c9769439b8 LLVM3.7
LLVM 3.7
author | Tatsuki IHA <e125716@ie.u-ryukyu.ac.jp> |
---|---|
date | Wed, 18 Feb 2015 14:55:36 +0900 |
parents | 54457678186b |
children | afa8332a0e37 |
comparison
equal
deleted
inserted
replaced
78:af83660cff7b | 83:60c9769439b8 |
---|---|
11 // report coverage information using the profiling instrumentation and code | 11 // report coverage information using the profiling instrumentation and code |
12 // coverage mapping. | 12 // coverage mapping. |
13 // | 13 // |
14 //===----------------------------------------------------------------------===// | 14 //===----------------------------------------------------------------------===// |
15 | 15 |
16 #include "FunctionCoverageMapping.h" | |
17 #include "RenderingSupport.h" | 16 #include "RenderingSupport.h" |
17 #include "CoverageFilters.h" | |
18 #include "CoverageReport.h" | |
18 #include "CoverageViewOptions.h" | 19 #include "CoverageViewOptions.h" |
19 #include "CoverageFilters.h" | |
20 #include "SourceCoverageDataManager.h" | |
21 #include "SourceCoverageView.h" | 20 #include "SourceCoverageView.h" |
22 #include "CoverageSummary.h" | 21 #include "llvm/ADT/SmallString.h" |
23 #include "CoverageReport.h" | |
24 #include "llvm/ADT/StringRef.h" | 22 #include "llvm/ADT/StringRef.h" |
25 #include "llvm/ADT/SmallString.h" | 23 #include "llvm/ProfileData/CoverageMapping.h" |
26 #include "llvm/ADT/SmallSet.h" | |
27 #include "llvm/ADT/DenseSet.h" | |
28 #include "llvm/ProfileData/InstrProfReader.h" | 24 #include "llvm/ProfileData/InstrProfReader.h" |
29 #include "llvm/ProfileData/CoverageMapping.h" | |
30 #include "llvm/ProfileData/CoverageMappingReader.h" | |
31 #include "llvm/Support/CommandLine.h" | 25 #include "llvm/Support/CommandLine.h" |
32 #include "llvm/Support/FileSystem.h" | 26 #include "llvm/Support/FileSystem.h" |
27 #include "llvm/Support/Format.h" | |
33 #include "llvm/Support/ManagedStatic.h" | 28 #include "llvm/Support/ManagedStatic.h" |
34 #include "llvm/Support/MemoryObject.h" | |
35 #include "llvm/Support/Format.h" | |
36 #include "llvm/Support/Path.h" | 29 #include "llvm/Support/Path.h" |
30 #include "llvm/Support/PrettyStackTrace.h" | |
37 #include "llvm/Support/Signals.h" | 31 #include "llvm/Support/Signals.h" |
38 #include "llvm/Support/PrettyStackTrace.h" | 32 #include <functional> |
39 #include <system_error> | 33 #include <system_error> |
40 #include <functional> | |
41 | 34 |
42 using namespace llvm; | 35 using namespace llvm; |
43 using namespace coverage; | 36 using namespace coverage; |
44 | 37 |
45 namespace { | 38 namespace { |
46 /// \brief Distribute the functions into instantiation sets. | |
47 /// An instantiation set is a collection of functions | |
48 /// that have the same source code, e.g. | |
49 /// template functions specializations. | |
50 class FunctionInstantiationSetCollector { | |
51 ArrayRef<FunctionCoverageMapping> FunctionMappings; | |
52 typedef uint64_t KeyType; | |
53 typedef std::vector<const FunctionCoverageMapping *> SetType; | |
54 std::unordered_map<uint64_t, SetType> InstantiatedFunctions; | |
55 | |
56 static KeyType getKey(const MappingRegion &R) { | |
57 return uint64_t(R.LineStart) | uint64_t(R.ColumnStart) << 32; | |
58 } | |
59 | |
60 public: | |
61 void insert(const FunctionCoverageMapping &Function, unsigned FileID) { | |
62 KeyType Key = 0; | |
63 for (const auto &R : Function.MappingRegions) { | |
64 if (R.FileID == FileID) { | |
65 Key = getKey(R); | |
66 break; | |
67 } | |
68 } | |
69 auto I = InstantiatedFunctions.find(Key); | |
70 if (I == InstantiatedFunctions.end()) { | |
71 SetType Set; | |
72 Set.push_back(&Function); | |
73 InstantiatedFunctions.insert(std::make_pair(Key, Set)); | |
74 } else | |
75 I->second.push_back(&Function); | |
76 } | |
77 | |
78 std::unordered_map<KeyType, SetType>::iterator begin() { | |
79 return InstantiatedFunctions.begin(); | |
80 } | |
81 | |
82 std::unordered_map<KeyType, SetType>::iterator end() { | |
83 return InstantiatedFunctions.end(); | |
84 } | |
85 }; | |
86 | |
87 /// \brief The implementation of the coverage tool. | 39 /// \brief The implementation of the coverage tool. |
88 class CodeCoverageTool { | 40 class CodeCoverageTool { |
89 public: | 41 public: |
90 enum Command { | 42 enum Command { |
91 /// \brief The show command. | 43 /// \brief The show command. |
98 void error(const Twine &Message, StringRef Whence = ""); | 50 void error(const Twine &Message, StringRef Whence = ""); |
99 | 51 |
100 /// \brief Return a memory buffer for the given source file. | 52 /// \brief Return a memory buffer for the given source file. |
101 ErrorOr<const MemoryBuffer &> getSourceFile(StringRef SourceFile); | 53 ErrorOr<const MemoryBuffer &> getSourceFile(StringRef SourceFile); |
102 | 54 |
103 /// \brief Return true if two filepaths refer to the same file. | 55 /// \brief Create source views for the expansions of the view. |
104 bool equivalentFiles(StringRef A, StringRef B); | 56 void attachExpansionSubViews(SourceCoverageView &View, |
105 | 57 ArrayRef<ExpansionRecord> Expansions, |
106 /// \brief Collect a set of function's file ids which correspond to the | 58 CoverageMapping &Coverage); |
107 /// given source file. Return false if the set is empty. | 59 |
108 bool gatherInterestingFileIDs(StringRef SourceFile, | 60 /// \brief Create the source view of a particular function. |
109 const FunctionCoverageMapping &Function, | 61 std::unique_ptr<SourceCoverageView> |
110 SmallSet<unsigned, 8> &InterestingFileIDs); | 62 createFunctionView(const FunctionRecord &Function, CoverageMapping &Coverage); |
111 | |
112 /// \brief Find the file id which is not an expanded file id. | |
113 bool findMainViewFileID(StringRef SourceFile, | |
114 const FunctionCoverageMapping &Function, | |
115 unsigned &MainViewFileID); | |
116 | |
117 bool findMainViewFileID(const FunctionCoverageMapping &Function, | |
118 unsigned &MainViewFileID); | |
119 | |
120 /// \brief Create a source view which shows coverage for an expansion | |
121 /// of a file. | |
122 void createExpansionSubView(const MappingRegion &ExpandedRegion, | |
123 const FunctionCoverageMapping &Function, | |
124 SourceCoverageView &Parent); | |
125 | |
126 void createExpansionSubViews(SourceCoverageView &View, unsigned ViewFileID, | |
127 const FunctionCoverageMapping &Function); | |
128 | |
129 /// \brief Create a source view which shows coverage for an instantiation | |
130 /// of a funciton. | |
131 void createInstantiationSubView(StringRef SourceFile, | |
132 const FunctionCoverageMapping &Function, | |
133 SourceCoverageView &View); | |
134 | 63 |
135 /// \brief Create the main source view of a particular source file. | 64 /// \brief Create the main source view of a particular source file. |
136 /// Return true if this particular source file is not covered. | 65 std::unique_ptr<SourceCoverageView> |
137 bool | 66 createSourceFileView(StringRef SourceFile, CoverageMapping &Coverage); |
138 createSourceFileView(StringRef SourceFile, SourceCoverageView &View, | |
139 ArrayRef<FunctionCoverageMapping> FunctionMappingRecords, | |
140 bool UseOnlyRegionsInMainFile = false); | |
141 | 67 |
142 /// \brief Load the coverage mapping data. Return true if an error occured. | 68 /// \brief Load the coverage mapping data. Return true if an error occured. |
143 bool load(); | 69 std::unique_ptr<CoverageMapping> load(); |
144 | 70 |
145 int run(Command Cmd, int argc, const char **argv); | 71 int run(Command Cmd, int argc, const char **argv); |
146 | 72 |
147 typedef std::function<int(int, const char **)> CommandLineParserType; | 73 typedef std::function<int(int, const char **)> CommandLineParserType; |
148 | 74 |
150 CommandLineParserType commandLineParser); | 76 CommandLineParserType commandLineParser); |
151 | 77 |
152 int report(int argc, const char **argv, | 78 int report(int argc, const char **argv, |
153 CommandLineParserType commandLineParser); | 79 CommandLineParserType commandLineParser); |
154 | 80 |
155 StringRef ObjectFilename; | 81 std::string ObjectFilename; |
156 CoverageViewOptions ViewOpts; | 82 CoverageViewOptions ViewOpts; |
157 std::unique_ptr<IndexedInstrProfReader> PGOReader; | 83 std::string PGOFilename; |
158 CoverageFiltersMatchAll Filters; | 84 CoverageFiltersMatchAll Filters; |
159 std::vector<std::string> SourceFiles; | 85 std::vector<std::string> SourceFiles; |
160 std::vector<std::pair<std::string, std::unique_ptr<MemoryBuffer>>> | 86 std::vector<std::pair<std::string, std::unique_ptr<MemoryBuffer>>> |
161 LoadedSourceFiles; | 87 LoadedSourceFiles; |
162 std::vector<FunctionCoverageMapping> FunctionMappingRecords; | |
163 bool CompareFilenamesOnly; | 88 bool CompareFilenamesOnly; |
89 StringMap<std::string> RemappedFilenames; | |
164 }; | 90 }; |
165 } | 91 } |
166 | 92 |
167 void CodeCoverageTool::error(const Twine &Message, StringRef Whence) { | 93 void CodeCoverageTool::error(const Twine &Message, StringRef Whence) { |
168 errs() << "error: "; | 94 errs() << "error: "; |
171 errs() << Message << "\n"; | 97 errs() << Message << "\n"; |
172 } | 98 } |
173 | 99 |
174 ErrorOr<const MemoryBuffer &> | 100 ErrorOr<const MemoryBuffer &> |
175 CodeCoverageTool::getSourceFile(StringRef SourceFile) { | 101 CodeCoverageTool::getSourceFile(StringRef SourceFile) { |
176 SmallString<256> Path(SourceFile); | 102 // If we've remapped filenames, look up the real location for this file. |
177 sys::fs::make_absolute(Path); | 103 if (!RemappedFilenames.empty()) { |
178 for (const auto &Files : LoadedSourceFiles) { | 104 auto Loc = RemappedFilenames.find(SourceFile); |
179 if (sys::fs::equivalent(Path.str(), Files.first)) { | 105 if (Loc != RemappedFilenames.end()) |
106 SourceFile = Loc->second; | |
107 } | |
108 for (const auto &Files : LoadedSourceFiles) | |
109 if (sys::fs::equivalent(SourceFile, Files.first)) | |
180 return *Files.second; | 110 return *Files.second; |
181 } | |
182 } | |
183 auto Buffer = MemoryBuffer::getFile(SourceFile); | 111 auto Buffer = MemoryBuffer::getFile(SourceFile); |
184 if (auto EC = Buffer.getError()) { | 112 if (auto EC = Buffer.getError()) { |
185 error(EC.message(), SourceFile); | 113 error(EC.message(), SourceFile); |
186 return EC; | 114 return EC; |
187 } | 115 } |
188 LoadedSourceFiles.push_back(std::make_pair( | 116 LoadedSourceFiles.push_back( |
189 std::string(Path.begin(), Path.end()), std::move(Buffer.get()))); | 117 std::make_pair(SourceFile, std::move(Buffer.get()))); |
190 return *LoadedSourceFiles.back().second; | 118 return *LoadedSourceFiles.back().second; |
191 } | 119 } |
192 | 120 |
193 /// \brief Return a line start - line end range which contains | 121 void |
194 /// all the mapping regions of a given function with a particular file id. | 122 CodeCoverageTool::attachExpansionSubViews(SourceCoverageView &View, |
195 std::pair<unsigned, unsigned> | 123 ArrayRef<ExpansionRecord> Expansions, |
196 findExpandedFileInterestingLineRange(unsigned FileID, | 124 CoverageMapping &Coverage) { |
197 const FunctionCoverageMapping &Function) { | |
198 unsigned LineStart = std::numeric_limits<unsigned>::max(); | |
199 unsigned LineEnd = 0; | |
200 for (const auto &Region : Function.MappingRegions) { | |
201 if (Region.FileID != FileID) | |
202 continue; | |
203 LineStart = std::min(Region.LineStart, LineStart); | |
204 LineEnd = std::max(Region.LineEnd, LineEnd); | |
205 } | |
206 return std::make_pair(LineStart, LineEnd); | |
207 } | |
208 | |
209 bool CodeCoverageTool::equivalentFiles(StringRef A, StringRef B) { | |
210 if (CompareFilenamesOnly) | |
211 return sys::path::filename(A).equals_lower(sys::path::filename(B)); | |
212 return sys::fs::equivalent(A, B); | |
213 } | |
214 | |
215 bool CodeCoverageTool::gatherInterestingFileIDs( | |
216 StringRef SourceFile, const FunctionCoverageMapping &Function, | |
217 SmallSet<unsigned, 8> &InterestingFileIDs) { | |
218 bool Interesting = false; | |
219 for (unsigned I = 0, E = Function.Filenames.size(); I < E; ++I) { | |
220 if (equivalentFiles(SourceFile, Function.Filenames[I])) { | |
221 InterestingFileIDs.insert(I); | |
222 Interesting = true; | |
223 } | |
224 } | |
225 return Interesting; | |
226 } | |
227 | |
228 bool | |
229 CodeCoverageTool::findMainViewFileID(StringRef SourceFile, | |
230 const FunctionCoverageMapping &Function, | |
231 unsigned &MainViewFileID) { | |
232 llvm::SmallVector<bool, 8> IsExpandedFile(Function.Filenames.size(), false); | |
233 llvm::SmallVector<bool, 8> FilenameEquivalence(Function.Filenames.size(), | |
234 false); | |
235 for (unsigned I = 0, E = Function.Filenames.size(); I < E; ++I) { | |
236 if (equivalentFiles(SourceFile, Function.Filenames[I])) | |
237 FilenameEquivalence[I] = true; | |
238 } | |
239 for (const auto &Region : Function.MappingRegions) { | |
240 if (Region.Kind == MappingRegion::ExpansionRegion && | |
241 FilenameEquivalence[Region.FileID]) | |
242 IsExpandedFile[Region.ExpandedFileID] = true; | |
243 } | |
244 for (unsigned I = 0, E = Function.Filenames.size(); I < E; ++I) { | |
245 if (!FilenameEquivalence[I] || IsExpandedFile[I]) | |
246 continue; | |
247 MainViewFileID = I; | |
248 return false; | |
249 } | |
250 return true; | |
251 } | |
252 | |
253 bool | |
254 CodeCoverageTool::findMainViewFileID(const FunctionCoverageMapping &Function, | |
255 unsigned &MainViewFileID) { | |
256 llvm::SmallVector<bool, 8> IsExpandedFile(Function.Filenames.size(), false); | |
257 for (const auto &Region : Function.MappingRegions) { | |
258 if (Region.Kind == MappingRegion::ExpansionRegion) | |
259 IsExpandedFile[Region.ExpandedFileID] = true; | |
260 } | |
261 for (unsigned I = 0, E = Function.Filenames.size(); I < E; ++I) { | |
262 if (IsExpandedFile[I]) | |
263 continue; | |
264 MainViewFileID = I; | |
265 return false; | |
266 } | |
267 return true; | |
268 } | |
269 | |
270 void CodeCoverageTool::createExpansionSubView( | |
271 const MappingRegion &ExpandedRegion, | |
272 const FunctionCoverageMapping &Function, SourceCoverageView &Parent) { | |
273 auto ExpandedLines = findExpandedFileInterestingLineRange( | |
274 ExpandedRegion.ExpandedFileID, Function); | |
275 if (ViewOpts.Debug) | |
276 llvm::outs() << "Expansion of " << ExpandedRegion.ExpandedFileID << ":" | |
277 << ExpandedLines.first << " -> " << ExpandedLines.second | |
278 << " @ " << ExpandedRegion.FileID << ", " | |
279 << ExpandedRegion.LineStart << ":" | |
280 << ExpandedRegion.ColumnStart << "\n"; | |
281 auto SourceBuffer = | |
282 getSourceFile(Function.Filenames[ExpandedRegion.ExpandedFileID]); | |
283 if (!SourceBuffer) | |
284 return; | |
285 auto SubView = llvm::make_unique<SourceCoverageView>( | |
286 SourceBuffer.get(), Parent.getOptions(), ExpandedLines.first, | |
287 ExpandedLines.second, ExpandedRegion); | |
288 SourceCoverageDataManager RegionManager; | |
289 for (const auto &Region : Function.MappingRegions) { | |
290 if (Region.FileID == ExpandedRegion.ExpandedFileID) | |
291 RegionManager.insert(Region); | |
292 } | |
293 SubView->load(RegionManager); | |
294 createExpansionSubViews(*SubView, ExpandedRegion.ExpandedFileID, Function); | |
295 Parent.addChild(std::move(SubView)); | |
296 } | |
297 | |
298 void CodeCoverageTool::createExpansionSubViews( | |
299 SourceCoverageView &View, unsigned ViewFileID, | |
300 const FunctionCoverageMapping &Function) { | |
301 if (!ViewOpts.ShowExpandedRegions) | 125 if (!ViewOpts.ShowExpandedRegions) |
302 return; | 126 return; |
303 for (const auto &Region : Function.MappingRegions) { | 127 for (const auto &Expansion : Expansions) { |
304 if (Region.Kind != CounterMappingRegion::ExpansionRegion) | 128 auto ExpansionCoverage = Coverage.getCoverageForExpansion(Expansion); |
129 if (ExpansionCoverage.empty()) | |
305 continue; | 130 continue; |
306 if (Region.FileID != ViewFileID) | 131 auto SourceBuffer = getSourceFile(ExpansionCoverage.getFilename()); |
132 if (!SourceBuffer) | |
307 continue; | 133 continue; |
308 createExpansionSubView(Region, Function, View); | 134 |
309 } | 135 auto SubViewExpansions = ExpansionCoverage.getExpansions(); |
310 } | 136 auto SubView = llvm::make_unique<SourceCoverageView>( |
311 | 137 SourceBuffer.get(), ViewOpts, std::move(ExpansionCoverage)); |
312 void CodeCoverageTool::createInstantiationSubView( | 138 attachExpansionSubViews(*SubView, SubViewExpansions, Coverage); |
313 StringRef SourceFile, const FunctionCoverageMapping &Function, | 139 View.addExpansion(Expansion.Region, std::move(SubView)); |
314 SourceCoverageView &View) { | 140 } |
315 SourceCoverageDataManager RegionManager; | 141 } |
316 SmallSet<unsigned, 8> InterestingFileIDs; | 142 |
317 if (!gatherInterestingFileIDs(SourceFile, Function, InterestingFileIDs)) | 143 std::unique_ptr<SourceCoverageView> |
318 return; | 144 CodeCoverageTool::createFunctionView(const FunctionRecord &Function, |
319 // Get the interesting regions | 145 CoverageMapping &Coverage) { |
320 for (const auto &Region : Function.MappingRegions) { | 146 auto FunctionCoverage = Coverage.getCoverageForFunction(Function); |
321 if (InterestingFileIDs.count(Region.FileID)) | 147 if (FunctionCoverage.empty()) |
322 RegionManager.insert(Region); | 148 return nullptr; |
323 } | 149 auto SourceBuffer = getSourceFile(FunctionCoverage.getFilename()); |
324 View.load(RegionManager); | 150 if (!SourceBuffer) |
325 unsigned MainFileID; | 151 return nullptr; |
326 if (findMainViewFileID(SourceFile, Function, MainFileID)) | 152 |
327 return; | 153 auto Expansions = FunctionCoverage.getExpansions(); |
328 createExpansionSubViews(View, MainFileID, Function); | 154 auto View = llvm::make_unique<SourceCoverageView>( |
329 } | 155 SourceBuffer.get(), ViewOpts, std::move(FunctionCoverage)); |
330 | 156 attachExpansionSubViews(*View, Expansions, Coverage); |
331 bool CodeCoverageTool::createSourceFileView( | 157 |
332 StringRef SourceFile, SourceCoverageView &View, | 158 return View; |
333 ArrayRef<FunctionCoverageMapping> FunctionMappingRecords, | 159 } |
334 bool UseOnlyRegionsInMainFile) { | 160 |
335 SourceCoverageDataManager RegionManager; | 161 std::unique_ptr<SourceCoverageView> |
336 FunctionInstantiationSetCollector InstantiationSetCollector; | 162 CodeCoverageTool::createSourceFileView(StringRef SourceFile, |
337 | 163 CoverageMapping &Coverage) { |
338 for (const auto &Function : FunctionMappingRecords) { | 164 auto SourceBuffer = getSourceFile(SourceFile); |
339 unsigned MainFileID; | 165 if (!SourceBuffer) |
340 if (findMainViewFileID(SourceFile, Function, MainFileID)) | 166 return nullptr; |
341 continue; | 167 auto FileCoverage = Coverage.getCoverageForFile(SourceFile); |
342 SmallSet<unsigned, 8> InterestingFileIDs; | 168 if (FileCoverage.empty()) |
343 if (UseOnlyRegionsInMainFile) { | 169 return nullptr; |
344 InterestingFileIDs.insert(MainFileID); | 170 |
345 } else if (!gatherInterestingFileIDs(SourceFile, Function, | 171 auto Expansions = FileCoverage.getExpansions(); |
346 InterestingFileIDs)) | 172 auto View = llvm::make_unique<SourceCoverageView>( |
347 continue; | 173 SourceBuffer.get(), ViewOpts, std::move(FileCoverage)); |
348 // Get the interesting regions | 174 attachExpansionSubViews(*View, Expansions, Coverage); |
349 for (const auto &Region : Function.MappingRegions) { | 175 |
350 if (InterestingFileIDs.count(Region.FileID)) | 176 for (auto Function : Coverage.getInstantiations(SourceFile)) { |
351 RegionManager.insert(Region); | 177 auto SubViewCoverage = Coverage.getCoverageForFunction(*Function); |
352 } | 178 auto SubViewExpansions = SubViewCoverage.getExpansions(); |
353 InstantiationSetCollector.insert(Function, MainFileID); | 179 auto SubView = llvm::make_unique<SourceCoverageView>( |
354 createExpansionSubViews(View, MainFileID, Function); | 180 SourceBuffer.get(), ViewOpts, std::move(SubViewCoverage)); |
355 } | 181 attachExpansionSubViews(*SubView, SubViewExpansions, Coverage); |
356 if (RegionManager.getSourceRegions().empty()) | 182 |
357 return true; | 183 if (SubView) { |
358 View.load(RegionManager); | 184 unsigned FileID = Function->CountedRegions.front().FileID; |
359 // Show instantiations | 185 unsigned Line = 0; |
360 if (!ViewOpts.ShowFunctionInstantiations) | 186 for (const auto &CR : Function->CountedRegions) |
361 return false; | 187 if (CR.FileID == FileID) |
362 for (const auto &InstantiationSet : InstantiationSetCollector) { | 188 Line = std::max(CR.LineEnd, Line); |
363 if (InstantiationSet.second.size() < 2) | 189 View->addInstantiation(Function->Name, Line, std::move(SubView)); |
364 continue; | 190 } |
365 auto InterestingRange = findExpandedFileInterestingLineRange( | 191 } |
366 InstantiationSet.second.front()->MappingRegions.front().FileID, | 192 return View; |
367 *InstantiationSet.second.front()); | 193 } |
368 for (auto Function : InstantiationSet.second) { | 194 |
369 auto SubView = llvm::make_unique<SourceCoverageView>( | 195 std::unique_ptr<CoverageMapping> CodeCoverageTool::load() { |
370 View, InterestingRange.first, InterestingRange.second, | 196 auto CoverageOrErr = CoverageMapping::load(ObjectFilename, PGOFilename); |
371 Function->PrettyName); | 197 if (std::error_code EC = CoverageOrErr.getError()) { |
372 createInstantiationSubView(SourceFile, *Function, *SubView); | 198 colored_ostream(errs(), raw_ostream::RED) |
373 View.addChild(std::move(SubView)); | 199 << "error: Failed to load coverage: " << EC.message(); |
374 } | 200 errs() << "\n"; |
375 } | 201 return nullptr; |
376 return false; | 202 } |
377 } | 203 auto Coverage = std::move(CoverageOrErr.get()); |
378 | 204 unsigned Mismatched = Coverage->getMismatchedCount(); |
379 bool CodeCoverageTool::load() { | 205 if (Mismatched) { |
380 auto CounterMappingBuff = MemoryBuffer::getFileOrSTDIN(ObjectFilename); | 206 colored_ostream(errs(), raw_ostream::RED) |
381 if (auto EC = CounterMappingBuff.getError()) { | 207 << "warning: " << Mismatched << " functions have mismatched data. "; |
382 error(EC.message(), ObjectFilename); | 208 errs() << "\n"; |
383 return true; | 209 } |
384 } | 210 |
385 ObjectFileCoverageMappingReader MappingReader(CounterMappingBuff.get()); | 211 if (CompareFilenamesOnly) { |
386 if (auto EC = MappingReader.readHeader()) { | 212 auto CoveredFiles = Coverage.get()->getUniqueSourceFiles(); |
387 error(EC.message(), ObjectFilename); | 213 for (auto &SF : SourceFiles) { |
388 return true; | 214 StringRef SFBase = sys::path::filename(SF); |
389 } | 215 for (const auto &CF : CoveredFiles) |
390 | 216 if (SFBase == sys::path::filename(CF)) { |
391 std::vector<uint64_t> Counts; | 217 RemappedFilenames[CF] = SF; |
392 for (const auto &I : MappingReader) { | 218 SF = CF; |
393 FunctionCoverageMapping Function(I.FunctionName, I.Filenames); | 219 break; |
394 | |
395 // Create the mapping regions with evaluated execution counts | |
396 Counts.clear(); | |
397 PGOReader->getFunctionCounts(Function.Name, I.FunctionHash, Counts); | |
398 | |
399 // Get the biggest referenced counters | |
400 bool RegionError = false; | |
401 CounterMappingContext Ctx(I.Expressions, Counts); | |
402 for (const auto &R : I.MappingRegions) { | |
403 // Compute the values of mapped regions | |
404 if (ViewOpts.Debug) { | |
405 outs() << "File " << R.FileID << "| " << R.LineStart << ":" | |
406 << R.ColumnStart << " -> " << R.LineEnd << ":" << R.ColumnEnd | |
407 << " = "; | |
408 Ctx.dump(R.Count); | |
409 if (R.Kind == CounterMappingRegion::ExpansionRegion) { | |
410 outs() << " (Expanded file id = " << R.ExpandedFileID << ") "; | |
411 } | 220 } |
412 outs() << "\n"; | 221 } |
413 } | 222 } |
414 std::error_code Error; | 223 |
415 Function.MappingRegions.push_back( | 224 return Coverage; |
416 MappingRegion(R, Ctx.evaluate(R.Count, Error))); | |
417 if (Error && !RegionError) { | |
418 colored_ostream(errs(), raw_ostream::RED) | |
419 << "error: Regions and counters don't match in a function '" | |
420 << Function.PrettyName << "' (re-run the instrumented binary)."; | |
421 errs() << "\n"; | |
422 RegionError = true; | |
423 } | |
424 } | |
425 | |
426 if (RegionError || !Filters.matches(Function)) | |
427 continue; | |
428 | |
429 FunctionMappingRecords.push_back(Function); | |
430 } | |
431 return false; | |
432 } | 225 } |
433 | 226 |
434 int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) { | 227 int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) { |
435 // Print a stack trace if we signal out. | 228 // Print a stack trace if we signal out. |
436 sys::PrintStackTraceOnErrorSignal(); | 229 sys::PrintStackTraceOnErrorSignal(); |
437 PrettyStackTraceProgram X(argc, argv); | 230 PrettyStackTraceProgram X(argc, argv); |
438 llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. | 231 llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. |
439 | 232 |
233 cl::opt<std::string, true> ObjectFilename( | |
234 cl::Positional, cl::Required, cl::location(this->ObjectFilename), | |
235 cl::desc("Covered executable or object file.")); | |
236 | |
440 cl::list<std::string> InputSourceFiles( | 237 cl::list<std::string> InputSourceFiles( |
441 cl::Positional, cl::desc("<Source files>"), cl::ZeroOrMore); | 238 cl::Positional, cl::desc("<Source files>"), cl::ZeroOrMore); |
442 | 239 |
443 cl::opt<std::string> PGOFilename( | 240 cl::opt<std::string, true> PGOFilename( |
444 "instr-profile", cl::Required, | 241 "instr-profile", cl::Required, cl::location(this->PGOFilename), |
445 cl::desc( | 242 cl::desc( |
446 "File with the profile data obtained after an instrumented run")); | 243 "File with the profile data obtained after an instrumented run")); |
447 | 244 |
448 cl::opt<bool> DebugDump("dump", cl::Optional, | 245 cl::opt<bool> DebugDump("dump", cl::Optional, |
449 cl::desc("Show internal debug dump")); | 246 cl::desc("Show internal debug dump")); |
450 | 247 |
451 cl::opt<bool> FilenameEquivalence( | 248 cl::opt<bool> FilenameEquivalence( |
452 "filename-equivalence", cl::Optional, | 249 "filename-equivalence", cl::Optional, |
453 cl::desc("Compare the filenames instead of full filepaths")); | 250 cl::desc("Treat source files as equivalent to paths in the coverage data " |
251 "when the file names match, even if the full paths do not")); | |
454 | 252 |
455 cl::OptionCategory FilteringCategory("Function filtering options"); | 253 cl::OptionCategory FilteringCategory("Function filtering options"); |
456 | 254 |
457 cl::list<std::string> NameFilters( | 255 cl::list<std::string> NameFilters( |
458 "name", cl::Optional, | 256 "name", cl::Optional, |
491 | 289 |
492 auto commandLineParser = [&, this](int argc, const char **argv) -> int { | 290 auto commandLineParser = [&, this](int argc, const char **argv) -> int { |
493 cl::ParseCommandLineOptions(argc, argv, "LLVM code coverage tool\n"); | 291 cl::ParseCommandLineOptions(argc, argv, "LLVM code coverage tool\n"); |
494 ViewOpts.Debug = DebugDump; | 292 ViewOpts.Debug = DebugDump; |
495 CompareFilenamesOnly = FilenameEquivalence; | 293 CompareFilenamesOnly = FilenameEquivalence; |
496 | |
497 if (auto EC = IndexedInstrProfReader::create(PGOFilename, PGOReader)) { | |
498 error(EC.message(), PGOFilename); | |
499 return 1; | |
500 } | |
501 | 294 |
502 // Create the function filters | 295 // Create the function filters |
503 if (!NameFilters.empty() || !NameRegexFilters.empty()) { | 296 if (!NameFilters.empty() || !NameRegexFilters.empty()) { |
504 auto NameFilterer = new CoverageFilters; | 297 auto NameFilterer = new CoverageFilters; |
505 for (const auto &Name : NameFilters) | 298 for (const auto &Name : NameFilters) |
527 StatFilterer->push_back(llvm::make_unique<LineCoverageFilter>( | 320 StatFilterer->push_back(llvm::make_unique<LineCoverageFilter>( |
528 RegionCoverageFilter::GreaterThan, LineCoverageGtFilter)); | 321 RegionCoverageFilter::GreaterThan, LineCoverageGtFilter)); |
529 Filters.push_back(std::unique_ptr<CoverageFilter>(StatFilterer)); | 322 Filters.push_back(std::unique_ptr<CoverageFilter>(StatFilterer)); |
530 } | 323 } |
531 | 324 |
532 SourceFiles = InputSourceFiles; | 325 for (const auto &File : InputSourceFiles) { |
326 SmallString<128> Path(File); | |
327 if (!CompareFilenamesOnly) | |
328 if (std::error_code EC = sys::fs::make_absolute(Path)) { | |
329 errs() << "error: " << File << ": " << EC.message(); | |
330 return 1; | |
331 } | |
332 SourceFiles.push_back(Path.str()); | |
333 } | |
533 return 0; | 334 return 0; |
534 }; | 335 }; |
535 | |
536 // Parse the object filename | |
537 if (argc > 1) { | |
538 StringRef Arg(argv[1]); | |
539 if (Arg.equals_lower("-help") || Arg.equals_lower("-version")) { | |
540 cl::ParseCommandLineOptions(2, argv, "LLVM code coverage tool\n"); | |
541 return 0; | |
542 } | |
543 ObjectFilename = Arg; | |
544 | |
545 argv[1] = argv[0]; | |
546 --argc; | |
547 ++argv; | |
548 } else { | |
549 errs() << sys::path::filename(argv[0]) << ": No executable file given!\n"; | |
550 return 1; | |
551 } | |
552 | 336 |
553 switch (Cmd) { | 337 switch (Cmd) { |
554 case Show: | 338 case Show: |
555 return show(argc, argv, commandLineParser); | 339 return show(argc, argv, commandLineParser); |
556 case Report: | 340 case Report: |
603 ViewOpts.ShowRegionMarkers = ShowRegions || ShowBestLineRegionsCounts; | 387 ViewOpts.ShowRegionMarkers = ShowRegions || ShowBestLineRegionsCounts; |
604 ViewOpts.ShowLineStatsOrRegionMarkers = ShowBestLineRegionsCounts; | 388 ViewOpts.ShowLineStatsOrRegionMarkers = ShowBestLineRegionsCounts; |
605 ViewOpts.ShowExpandedRegions = ShowExpansions; | 389 ViewOpts.ShowExpandedRegions = ShowExpansions; |
606 ViewOpts.ShowFunctionInstantiations = ShowInstantiations; | 390 ViewOpts.ShowFunctionInstantiations = ShowInstantiations; |
607 | 391 |
608 if (load()) | 392 auto Coverage = load(); |
393 if (!Coverage) | |
609 return 1; | 394 return 1; |
610 | 395 |
611 if (!Filters.empty()) { | 396 if (!Filters.empty()) { |
612 // Show functions | 397 // Show functions |
613 for (const auto &Function : FunctionMappingRecords) { | 398 for (const auto &Function : Coverage->getCoveredFunctions()) { |
614 unsigned MainFileID; | 399 if (!Filters.matches(Function)) |
615 if (findMainViewFileID(Function, MainFileID)) | |
616 continue; | 400 continue; |
617 StringRef SourceFile = Function.Filenames[MainFileID]; | 401 |
618 auto SourceBuffer = getSourceFile(SourceFile); | 402 auto mainView = createFunctionView(Function, *Coverage); |
619 if (!SourceBuffer) | 403 if (!mainView) { |
620 return 1; | 404 ViewOpts.colored_ostream(outs(), raw_ostream::RED) |
621 auto Range = findExpandedFileInterestingLineRange(MainFileID, Function); | 405 << "warning: Could not read coverage for '" << Function.Name; |
622 SourceCoverageView mainView(SourceBuffer.get(), ViewOpts, Range.first, | 406 outs() << "\n"; |
623 Range.second); | 407 continue; |
624 createSourceFileView(SourceFile, mainView, Function, true); | 408 } |
625 ViewOpts.colored_ostream(outs(), raw_ostream::CYAN) | 409 ViewOpts.colored_ostream(outs(), raw_ostream::CYAN) << Function.Name |
626 << Function.PrettyName << " from " << SourceFile << ":"; | 410 << ":"; |
627 outs() << "\n"; | 411 outs() << "\n"; |
628 mainView.render(outs()); | 412 mainView->render(outs(), /*WholeFile=*/false); |
629 if (FunctionMappingRecords.size() > 1) | 413 outs() << "\n"; |
630 outs() << "\n"; | |
631 } | 414 } |
632 return 0; | 415 return 0; |
633 } | 416 } |
634 | 417 |
635 // Show files | 418 // Show files |
636 bool ShowFilenames = SourceFiles.size() != 1; | 419 bool ShowFilenames = SourceFiles.size() != 1; |
637 | 420 |
638 if (SourceFiles.empty()) { | 421 if (SourceFiles.empty()) |
639 // Get the source files from the function coverage mapping | 422 // Get the source files from the function coverage mapping |
640 std::set<StringRef> UniqueFilenames; | 423 for (StringRef Filename : Coverage->getUniqueSourceFiles()) |
641 for (const auto &Function : FunctionMappingRecords) { | |
642 for (const auto &Filename : Function.Filenames) | |
643 UniqueFilenames.insert(Filename); | |
644 } | |
645 for (const auto &Filename : UniqueFilenames) | |
646 SourceFiles.push_back(Filename); | 424 SourceFiles.push_back(Filename); |
647 } | |
648 | 425 |
649 for (const auto &SourceFile : SourceFiles) { | 426 for (const auto &SourceFile : SourceFiles) { |
650 auto SourceBuffer = getSourceFile(SourceFile); | 427 auto mainView = createSourceFileView(SourceFile, *Coverage); |
651 if (!SourceBuffer) | 428 if (!mainView) { |
652 return 1; | |
653 SourceCoverageView mainView(SourceBuffer.get(), ViewOpts); | |
654 if (createSourceFileView(SourceFile, mainView, FunctionMappingRecords)) { | |
655 ViewOpts.colored_ostream(outs(), raw_ostream::RED) | 429 ViewOpts.colored_ostream(outs(), raw_ostream::RED) |
656 << "warning: The file '" << SourceFile << "' isn't covered."; | 430 << "warning: The file '" << SourceFile << "' isn't covered."; |
657 outs() << "\n"; | 431 outs() << "\n"; |
658 continue; | 432 continue; |
659 } | 433 } |
660 | 434 |
661 if (ShowFilenames) { | 435 if (ShowFilenames) { |
662 ViewOpts.colored_ostream(outs(), raw_ostream::CYAN) << SourceFile << ":"; | 436 ViewOpts.colored_ostream(outs(), raw_ostream::CYAN) << SourceFile << ":"; |
663 outs() << "\n"; | 437 outs() << "\n"; |
664 } | 438 } |
665 mainView.render(outs()); | 439 mainView->render(outs(), /*Wholefile=*/true); |
666 if (SourceFiles.size() > 1) | 440 if (SourceFiles.size() > 1) |
667 outs() << "\n"; | 441 outs() << "\n"; |
668 } | 442 } |
669 | 443 |
670 return 0; | 444 return 0; |
679 if (Err) | 453 if (Err) |
680 return Err; | 454 return Err; |
681 | 455 |
682 ViewOpts.Colors = !NoColors; | 456 ViewOpts.Colors = !NoColors; |
683 | 457 |
684 if (load()) | 458 auto Coverage = load(); |
459 if (!Coverage) | |
685 return 1; | 460 return 1; |
686 | 461 |
687 CoverageSummary Summarizer; | 462 CoverageReport Report(ViewOpts, std::move(Coverage)); |
688 Summarizer.createSummaries(FunctionMappingRecords); | 463 if (SourceFiles.empty()) |
689 CoverageReport Report(ViewOpts, Summarizer); | |
690 if (SourceFiles.empty() && Filters.empty()) { | |
691 Report.renderFileReports(llvm::outs()); | 464 Report.renderFileReports(llvm::outs()); |
692 return 0; | 465 else |
693 } | 466 Report.renderFunctionReports(SourceFiles, llvm::outs()); |
694 | |
695 Report.renderFunctionReports(llvm::outs()); | |
696 return 0; | 467 return 0; |
697 } | 468 } |
698 | 469 |
699 int show_main(int argc, const char **argv) { | 470 int showMain(int argc, const char *argv[]) { |
700 CodeCoverageTool Tool; | 471 CodeCoverageTool Tool; |
701 return Tool.run(CodeCoverageTool::Show, argc, argv); | 472 return Tool.run(CodeCoverageTool::Show, argc, argv); |
702 } | 473 } |
703 | 474 |
704 int report_main(int argc, const char **argv) { | 475 int reportMain(int argc, const char *argv[]) { |
705 CodeCoverageTool Tool; | 476 CodeCoverageTool Tool; |
706 return Tool.run(CodeCoverageTool::Report, argc, argv); | 477 return Tool.run(CodeCoverageTool::Report, argc, argv); |
707 } | 478 } |