blob: 4e63a43f831e35c633f15217b84a13371ab9951e [file] [log] [blame]
Nick Lewyckyb1928702011-04-16 01:20:23 +00001//===- GCOVProfiling.cpp - Insert edge counters for gcov profiling --------===//
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 pass implements GCOV-style profiling. When this pass is run it emits
11// "gcno" files next to the existing source, and instruments the code that runs
12// to records the edges between blocks that run and emit a complementary "gcda"
13// file on exit.
14//
15//===----------------------------------------------------------------------===//
16
17#define DEBUG_TYPE "insert-gcov-profiling"
18
19#include "ProfilingUtils.h"
20#include "llvm/Transforms/Instrumentation.h"
21#include "llvm/Analysis/DebugInfo.h"
22#include "llvm/Module.h"
23#include "llvm/Pass.h"
24#include "llvm/Instructions.h"
25#include "llvm/Support/raw_ostream.h"
26#include "llvm/Support/Debug.h"
27#include "llvm/Support/DebugLoc.h"
28#include "llvm/Support/InstIterator.h"
29#include "llvm/Support/IRBuilder.h"
30#include "llvm/Support/PathV2.h"
31#include "llvm/ADT/DenseMap.h"
32#include "llvm/ADT/Statistic.h"
33#include "llvm/ADT/STLExtras.h"
34#include "llvm/ADT/StringExtras.h"
35#include "llvm/ADT/StringMap.h"
36#include "llvm/ADT/UniqueVector.h"
37#include <string>
38#include <utility>
39using namespace llvm;
40
41namespace {
42 class GCOVProfiler : public ModulePass {
43 bool runOnModule(Module &M);
44 public:
45 static char ID;
46 GCOVProfiler() : ModulePass(ID) {
47 initializeGCOVProfilerPass(*PassRegistry::getPassRegistry());
48 }
49 virtual const char *getPassName() const {
50 return "GCOV Profiler";
51 }
52
53 private:
54 // Create the GCNO files for the Module based on DebugInfo.
55 void EmitGCNO(DebugInfoFinder &DIF);
56
Nick Lewycky0c4de8a2011-04-16 02:05:18 +000057 // Modify the program to track transitions along edges and call into the
58 // profiling runtime to emit .gcda files when run.
59 bool EmitProfileArcs(DebugInfoFinder &DIF);
60
Nick Lewyckyb1928702011-04-16 01:20:23 +000061 // Get pointers to the functions in the runtime library.
62 Constant *getStartFileFunc();
63 Constant *getEmitFunctionFunc();
64 Constant *getEmitArcsFunc();
65 Constant *getEndFileFunc();
66
67 // Add the function to write out all our counters to the global destructor
68 // list.
69 void InsertCounterWriteout(DebugInfoFinder &,
70 SmallVector<std::pair<GlobalVariable *,
71 uint32_t>, 8> &);
72
73 Module *Mod;
74 LLVMContext *Ctx;
75 };
76}
77
78char GCOVProfiler::ID = 0;
79INITIALIZE_PASS(GCOVProfiler, "insert-gcov-profiling",
80 "Insert instrumentation for GCOV profiling", false, false)
81
82ModulePass *llvm::createGCOVProfilerPass() { return new GCOVProfiler(); }
83
84static DISubprogram FindSubprogram(DIScope scope) {
85 while (!scope.isSubprogram()) {
86 assert(scope.isLexicalBlock() &&
87 "Debug location not lexical block or subprogram");
88 scope = DILexicalBlock(scope).getContext();
89 }
90 return DISubprogram(scope);
91}
92
93namespace {
94 class GCOVRecord {
95 protected:
96 static const char *lines_tag;
97 static const char *function_tag;
98 static const char *block_tag;
99 static const char *edge_tag;
100
101 GCOVRecord() {}
102
103 void WriteBytes(const char *b, int size) {
104 os->write(b, size);
105 }
106
107 void Write(uint32_t i) {
108 WriteBytes(reinterpret_cast<char*>(&i), 4);
109 }
110
111 // Returns the length measured in 4-byte blocks that will be used to
112 // represent this string in a GCOV file
113 unsigned LengthOfGCOVString(StringRef s) {
114 // A GCOV string is a length, followed by a NUL, then between 0 and 3 NULs
115 // padding out to the next 4-byte word. The length is measured in 4-byte words
116 // including padding, not bytes of actual string.
117 return (s.size() + 5) / 4;
118 }
119
120 void WriteGCOVString(StringRef s) {
121 uint32_t len = LengthOfGCOVString(s);
122 Write(len);
123 WriteBytes(s.data(), s.size());
124
125 // Write 1 to 4 bytes of NUL padding.
126 assert((unsigned)(5 - ((s.size() + 1) % 4)) > 0);
127 assert((unsigned)(5 - ((s.size() + 1) % 4)) <= 4);
128 WriteBytes("\0\0\0\0", 5 - ((s.size() + 1) % 4));
129 }
130
131 raw_ostream *os;
132 };
133 const char *GCOVRecord::lines_tag = "\0\0\x45\x01";
134 const char *GCOVRecord::function_tag = "\0\0\0\1";
135 const char *GCOVRecord::block_tag = "\0\0\x41\x01";
136 const char *GCOVRecord::edge_tag = "\0\0\x43\x01";
137
138 class GCOVFunction;
139 class GCOVBlock;
140
141 // Constructed only by requesting it from a GCOVBlock, this object stores a
142 // list of line numbers and a single filename, representing lines that belong
143 // to the block.
144 class GCOVLines : public GCOVRecord {
145 public:
146 void AddLine(uint32_t line) {
147 lines.push_back(line);
148 }
149
150 uint32_t Length() {
151 return LengthOfGCOVString(filename) + 2 + lines.size();
152 }
153
154 private:
155 friend class GCOVBlock;
156
157 GCOVLines(std::string filename, raw_ostream *os)
158 : filename(filename) {
159 this->os = os;
160 }
161
162 std::string filename;
163 SmallVector<uint32_t, 32> lines;
164 };
165
166 // Represent a basic block in GCOV. Each block has a unique number in the
167 // function, number of lines belonging to each block, and a set of edges to
168 // other blocks.
169 class GCOVBlock : public GCOVRecord {
170 public:
171 GCOVLines &GetFile(std::string filename) {
172 GCOVLines *&lines = lines_by_file[filename];
173 if (!lines) {
174 lines = new GCOVLines(filename, os);
175 }
176 return *lines;
177 }
178
179 void AddEdge(GCOVBlock &successor) {
180 out_edges.push_back(&successor);
181 }
182
183 void WriteOut() {
184 uint32_t len = 3;
185 for (StringMap<GCOVLines *>::iterator I = lines_by_file.begin(),
186 E = lines_by_file.end(); I != E; ++I) {
187 len += I->second->Length();
188 }
189
190 WriteBytes(lines_tag, 4);
191 Write(len);
192 Write(number);
193 for (StringMap<GCOVLines *>::iterator I = lines_by_file.begin(),
194 E = lines_by_file.end(); I != E; ++I) {
195 Write(0);
196 WriteGCOVString(I->second->filename);
197 for (int i = 0, e = I->second->lines.size(); i != e; ++i) {
198 Write(I->second->lines[i]);
199 }
200 }
201 Write(0);
202 Write(0);
203 }
204
205 ~GCOVBlock() {
206 DeleteContainerSeconds(lines_by_file);
207 }
208
209 private:
210 friend class GCOVFunction;
211
212 GCOVBlock(uint32_t number, raw_ostream *os)
213 : number(number) {
214 this->os = os;
215 }
216
217 uint32_t number;
218 BasicBlock *block;
219 StringMap<GCOVLines *> lines_by_file;
220 SmallVector<GCOVBlock *, 4> out_edges;
221 };
222
223 // A function has a unique identifier, a checksum (we leave as zero) and a
224 // set of blocks and a map of edges between blocks. This is the only GCOV
225 // object users can construct, the blocks and lines will be rooted here.
226 class GCOVFunction : public GCOVRecord {
227 public:
228 GCOVFunction(DISubprogram SP, raw_ostream *os) {
229 this->os = os;
230
231 Function *F = SP.getFunction();
232 uint32_t i = 0;
233 for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) {
234 blocks[BB] = new GCOVBlock(i++, os);
235 }
236
237 WriteBytes(function_tag, 4);
238 uint32_t block_len = 1 + 1 + 1 + LengthOfGCOVString(SP.getName()) +
239 1 + LengthOfGCOVString(SP.getFilename()) + 1;
240 Write(block_len);
241 uint32_t ident = reinterpret_cast<intptr_t>((MDNode*)SP);
242 Write(ident);
243 Write(0); // checksum
244 WriteGCOVString(SP.getName());
245 WriteGCOVString(SP.getFilename());
246 Write(SP.getLineNumber());
247 }
248
249 ~GCOVFunction() {
250 DeleteContainerSeconds(blocks);
251 }
252
253 GCOVBlock &GetBlock(BasicBlock *BB) {
254 return *blocks[BB];
255 }
256
257 void WriteOut() {
258 // Emit count of blocks.
259 WriteBytes(block_tag, 4);
260 Write(blocks.size());
261 for (int i = 0, e = blocks.size(); i != e; ++i) {
262 Write(0); // No flags on our blocks.
263 }
264
265 // Emit edges between blocks.
266 for (DenseMap<BasicBlock *, GCOVBlock *>::iterator I = blocks.begin(),
267 E = blocks.end(); I != E; ++I) {
268 GCOVBlock &block = *I->second;
269 if (block.out_edges.empty()) continue;
270
271 WriteBytes(edge_tag, 4);
272 Write(block.out_edges.size() * 2 + 1);
273 Write(block.number);
274 for (int i = 0, e = block.out_edges.size(); i != e; ++i) {
275 Write(block.out_edges[i]->number);
276 Write(0); // no flags
277 }
278 }
279
280 // Emit lines for each block.
281 for (DenseMap<BasicBlock *, GCOVBlock *>::iterator I = blocks.begin(),
282 E = blocks.end(); I != E; ++I) {
283 I->second->WriteOut();
284 }
285 }
286
287 private:
288 DenseMap<BasicBlock *, GCOVBlock *> blocks;
289 };
290}
291
Nick Lewycky0c4de8a2011-04-16 02:05:18 +0000292// Replace the stem of a file, or add one if missing.
293static std::string ReplaceStem(std::string orig_filename, std::string new_stem){
294 return (sys::path::stem(orig_filename) + "." + new_stem).str();
295}
296
297bool GCOVProfiler::runOnModule(Module &M) {
298 Mod = &M;
299 Ctx = &M.getContext();
300
301 DebugInfoFinder DIF;
302 DIF.processModule(*Mod);
303
304 EmitGCNO(DIF);
305 return EmitProfileArcs(DIF);
306}
307
Nick Lewyckyb1928702011-04-16 01:20:23 +0000308void GCOVProfiler::EmitGCNO(DebugInfoFinder &DIF) {
309 DenseMap<const MDNode *, raw_fd_ostream *> gcno_files;
310 for (DebugInfoFinder::iterator I = DIF.compile_unit_begin(),
311 E = DIF.compile_unit_end(); I != E; ++I) {
312 // Each compile unit gets its own .gcno file. This means that whether we run
313 // this pass over the original .o's as they're produced, or run it after
314 // LTO, we'll generate the same .gcno files.
315
316 DICompileUnit CU(*I);
317 raw_fd_ostream *&Out = gcno_files[CU];
318 std::string ErrorInfo;
Nick Lewycky0c4de8a2011-04-16 02:05:18 +0000319 Out = new raw_fd_ostream(ReplaceStem(CU.getFilename(), "gcno").c_str(),
320 ErrorInfo, raw_fd_ostream::F_Binary);
Nick Lewyckyb1928702011-04-16 01:20:23 +0000321 Out->write("oncg*404MVLL", 12);
322 }
323
324 for (DebugInfoFinder::iterator SPI = DIF.subprogram_begin(),
325 SPE = DIF.subprogram_end(); SPI != SPE; ++SPI) {
326 DISubprogram SP(*SPI);
327 raw_fd_ostream *&os = gcno_files[SP.getCompileUnit()];
328
329 GCOVFunction function(SP, os);
330 Function *F = SP.getFunction();
331 for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) {
332 GCOVBlock &block = function.GetBlock(BB);
333 TerminatorInst *TI = BB->getTerminator();
334 if (int successors = TI->getNumSuccessors()) {
335 for (int i = 0; i != successors; ++i) {
336 block.AddEdge(function.GetBlock(TI->getSuccessor(i)));
337 }
338 }
339
340 uint32_t line = 0;
341 for (BasicBlock::iterator I = BB->begin(), IE = BB->end(); I != IE; ++I) {
342 const DebugLoc &loc = I->getDebugLoc();
343 if (loc.isUnknown()) continue;
344 if (line == loc.getLine()) continue;
345 line = loc.getLine();
346 if (SP != FindSubprogram(DIScope(loc.getScope(*Ctx)))) continue;
347
348 GCOVLines &lines = block.GetFile(SP.getFilename());
349 lines.AddLine(loc.getLine());
350 }
351 }
352 function.WriteOut();
353 }
354
355 for (DenseMap<const MDNode *, raw_fd_ostream *>::iterator
356 I = gcno_files.begin(), E = gcno_files.end(); I != E; ++I) {
357 raw_fd_ostream *&Out = I->second;
358 Out->write("\0\0\0\0\0\0\0\0", 4); // EOF
359 Out->close();
360 delete Out;
361 }
362}
363
Nick Lewycky0c4de8a2011-04-16 02:05:18 +0000364bool GCOVProfiler::EmitProfileArcs(DebugInfoFinder &DIF) {
365 if (DIF.subprogram_begin() == DIF.subprogram_end())
366 return false;
Nick Lewyckyb1928702011-04-16 01:20:23 +0000367
368 SmallVector<std::pair<GlobalVariable *, uint32_t>, 8> counters_by_ident;
369 for (DebugInfoFinder::iterator SPI = DIF.subprogram_begin(),
370 SPE = DIF.subprogram_end(); SPI != SPE; ++SPI) {
371 DISubprogram SP(*SPI);
372 Function *F = SP.getFunction();
373
374 // TODO: GCOV format requires a distinct unified exit block.
375 unsigned edges = 0;
376 for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) {
377 TerminatorInst *TI = BB->getTerminator();
378 edges += TI->getNumSuccessors();
379 }
380
381 const ArrayType *counter_type =
382 ArrayType::get(Type::getInt64Ty(*Ctx), edges);
383 GlobalVariable *counter =
384 new GlobalVariable(*Mod, counter_type, false,
385 GlobalValue::InternalLinkage,
386 Constant::getNullValue(counter_type),
387 "__llvm_gcov_ctr", 0, false, 0);
388 counters_by_ident.push_back(
389 std::make_pair(counter, reinterpret_cast<intptr_t>((MDNode*)SP)));
390
391 UniqueVector<BasicBlock *> complex_edge_preds;
392 UniqueVector<BasicBlock *> complex_edge_succs;
393
394 unsigned edge_num = 0;
395 for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) {
396 TerminatorInst *TI = BB->getTerminator();
397 if (int successors = TI->getNumSuccessors()) {
398 IRBuilder<> builder(TI);
399
400 if (successors == 1) {
401 Value *ctr = builder.CreateConstInBoundsGEP2_64(counter, 0, edge_num);
402 Value *count = builder.CreateLoad(ctr);
403 count = builder.CreateAdd(count,
404 ConstantInt::get(Type::getInt64Ty(*Ctx),1));
405 builder.CreateStore(count, ctr);
406 } else if (BranchInst *BI = dyn_cast<BranchInst>(TI)) {
407 Value *sel = builder.CreateSelect(
408 BI->getCondition(),
409 ConstantInt::get(Type::getInt64Ty(*Ctx), edge_num),
410 ConstantInt::get(Type::getInt64Ty(*Ctx), edge_num + 1));
411 SmallVector<Value *, 2> idx;
412 idx.push_back(Constant::getNullValue(Type::getInt64Ty(*Ctx)));
413 idx.push_back(sel);
414 Value *ctr = builder.CreateInBoundsGEP(counter,
415 idx.begin(), idx.end());
416 Value *count = builder.CreateLoad(ctr);
417 count = builder.CreateAdd(count,
418 ConstantInt::get(Type::getInt64Ty(*Ctx),1));
419 builder.CreateStore(count, ctr);
420 } else {
421 complex_edge_preds.insert(BB);
422 for (int i = 0; i != successors; ++i) {
423 complex_edge_succs.insert(TI->getSuccessor(i));
424 }
425 }
426 edge_num += successors;
427 }
428 }
429
430 // TODO: support switch, invoke, indirectbr
431 if (!complex_edge_preds.empty()) {
432 // emit a [preds x [succs x i64*]].
433 for (int i = 0, e = complex_edge_preds.size(); i != e; ++i) {
434 // call runtime to state save
435 }
436 for (int i = 0, e = complex_edge_succs.size(); i != e; ++i) {
437 // call runtime to perform increment
438 }
439 }
440 }
441
442 InsertCounterWriteout(DIF, counters_by_ident);
443
444 return true;
445}
446
447Constant *GCOVProfiler::getStartFileFunc() {
448 const Type *Args[1] = { Type::getInt8PtrTy(*Ctx) };
449 const FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx),
450 Args, false);
451 return Mod->getOrInsertFunction("llvm_gcda_start_file", FTy);
452}
453
454Constant *GCOVProfiler::getEmitFunctionFunc() {
455 const Type *Args[1] = { Type::getInt32Ty(*Ctx) };
456 const FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx),
457 Args, false);
458 return Mod->getOrInsertFunction("llvm_gcda_emit_function", FTy);
459}
460
461Constant *GCOVProfiler::getEmitArcsFunc() {
462 const Type *Args[] = {
463 Type::getInt32Ty(*Ctx), // uint32_t num_counters
464 Type::getInt64PtrTy(*Ctx), // uint64_t *counters
465 };
466 const FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx),
467 Args, false);
468 return Mod->getOrInsertFunction("llvm_gcda_emit_arcs", FTy);
469}
470
471Constant *GCOVProfiler::getEndFileFunc() {
472 const FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), false);
473 return Mod->getOrInsertFunction("llvm_gcda_end_file", FTy);
474}
475
Nick Lewyckyb1928702011-04-16 01:20:23 +0000476void GCOVProfiler::InsertCounterWriteout(
477 DebugInfoFinder &DIF,
478 SmallVector<std::pair<GlobalVariable *, uint32_t>, 8> &counters_by_ident) {
479
480 const FunctionType *WriteoutFTy =
481 FunctionType::get(Type::getVoidTy(*Ctx), false);
482 Function *WriteoutF = Function::Create(WriteoutFTy,
483 GlobalValue::InternalLinkage,
484 "__llvm_gcda_writeout", Mod);
485 WriteoutF->setUnnamedAddr(true);
486 BasicBlock *BB = BasicBlock::Create(*Ctx, "", WriteoutF);
487 IRBuilder<> builder(BB);
488
489 Constant *StartFile = getStartFileFunc();
490 Constant *EmitFunction = getEmitFunctionFunc();
491 Constant *EmitArcs = getEmitArcsFunc();
492 Constant *EndFile = getEndFileFunc();
493
494 for (DebugInfoFinder::iterator CUI = DIF.compile_unit_begin(),
495 CUE = DIF.compile_unit_end(); CUI != CUE; ++CUI) {
496 DICompileUnit compile_unit(*CUI);
497 std::string filename_gcda = ReplaceStem(compile_unit.getFilename(), "gcda");
498 builder.CreateCall(StartFile,
499 builder.CreateGlobalStringPtr(filename_gcda));
500 for (SmallVector<std::pair<GlobalVariable *, uint32_t>, 8>::iterator
501 I = counters_by_ident.begin(), E = counters_by_ident.end();
502 I != E; ++I) {
503 builder.CreateCall(EmitFunction, ConstantInt::get(Type::getInt32Ty(*Ctx),
504 I->second));
505 GlobalVariable *GV = I->first;
506 unsigned num_arcs =
507 cast<ArrayType>(GV->getType()->getElementType())->getNumElements();
508 builder.CreateCall2(
509 EmitArcs,
510 ConstantInt::get(Type::getInt32Ty(*Ctx), num_arcs),
511 builder.CreateConstGEP2_64(GV, 0, 0));
512 }
513 builder.CreateCall(EndFile);
514 }
515 builder.CreateRetVoid();
516
517 InsertProfilingShutdownCall(WriteoutF, Mod);
518}