LLVM API Documentation

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
OProfileJITEventListener.cpp
Go to the documentation of this file.
1 //===-- OProfileJITEventListener.cpp - Tell OProfile about JITted code ----===//
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 defines a JITEventListener object that uses OProfileWrapper to tell
11 // oprofile about JITted functions, including source line information.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #include "llvm/Config/config.h"
17 
18 #define DEBUG_TYPE "oprofile-jit-event-listener"
19 #include "llvm/DebugInfo.h"
20 #include "llvm/IR/Function.h"
21 #include "llvm/ADT/OwningPtr.h"
25 #include "llvm/Object/ObjectFile.h"
26 #include "llvm/Support/Debug.h"
28 #include "llvm/Support/Errno.h"
29 #include "EventListenerCommon.h"
30 
31 #include <dirent.h>
32 #include <fcntl.h>
33 
34 using namespace llvm;
35 using namespace llvm::jitprofiling;
36 
37 namespace {
38 
39 class OProfileJITEventListener : public JITEventListener {
41 
42  void initialize();
43 
44 public:
45  OProfileJITEventListener(OProfileWrapper& LibraryWrapper)
46  : Wrapper(LibraryWrapper) {
47  initialize();
48  }
49 
50  ~OProfileJITEventListener();
51 
52  virtual void NotifyFunctionEmitted(const Function &F,
53  void *FnStart, size_t FnSize,
54  const JITEvent_EmittedFunctionDetails &Details);
55 
56  virtual void NotifyFreeingMachineCode(void *OldPtr);
57 
58  virtual void NotifyObjectEmitted(const ObjectImage &Obj);
59 
60  virtual void NotifyFreeingObject(const ObjectImage &Obj);
61 };
62 
64  if (!Wrapper.op_open_agent()) {
65  const std::string err_str = sys::StrError();
66  DEBUG(dbgs() << "Failed to connect to OProfile agent: " << err_str << "\n");
67  } else {
68  DEBUG(dbgs() << "Connected to OProfile agent.\n");
69  }
70 }
71 
72 OProfileJITEventListener::~OProfileJITEventListener() {
73  if (Wrapper.isAgentAvailable()) {
74  if (Wrapper.op_close_agent() == -1) {
75  const std::string err_str = sys::StrError();
76  DEBUG(dbgs() << "Failed to disconnect from OProfile agent: "
77  << err_str << "\n");
78  } else {
79  DEBUG(dbgs() << "Disconnected from OProfile agent.\n");
80  }
81  }
82 }
83 
84 static debug_line_info LineStartToOProfileFormat(
85  const MachineFunction &MF, FilenameCache &Filenames,
86  uintptr_t Address, DebugLoc Loc) {
87  debug_line_info Result;
88  Result.vma = Address;
89  Result.lineno = Loc.getLine();
90  Result.filename = Filenames.getFilename(
91  Loc.getScope(MF.getFunction()->getContext()));
92  DEBUG(dbgs() << "Mapping " << reinterpret_cast<void*>(Result.vma) << " to "
93  << Result.filename << ":" << Result.lineno << "\n");
94  return Result;
95 }
96 
97 // Adds the just-emitted function to the symbol table.
98 void OProfileJITEventListener::NotifyFunctionEmitted(
99  const Function &F, void *FnStart, size_t FnSize,
100  const JITEvent_EmittedFunctionDetails &Details) {
101  assert(F.hasName() && FnStart != 0 && "Bad symbol to add");
102  if (Wrapper.op_write_native_code(F.getName().data(),
103  reinterpret_cast<uint64_t>(FnStart),
104  FnStart, FnSize) == -1) {
105  DEBUG(dbgs() << "Failed to tell OProfile about native function "
106  << F.getName() << " at ["
107  << FnStart << "-" << ((char*)FnStart + FnSize) << "]\n");
108  return;
109  }
110 
111  if (!Details.LineStarts.empty()) {
112  // Now we convert the line number information from the address/DebugLoc
113  // format in Details to the address/filename/lineno format that OProfile
114  // expects. Note that OProfile 0.9.4 has a bug that causes it to ignore
115  // line numbers for addresses above 4G.
116  FilenameCache Filenames;
117  std::vector<debug_line_info> LineInfo;
118  LineInfo.reserve(1 + Details.LineStarts.size());
119 
120  DebugLoc FirstLoc = Details.LineStarts[0].Loc;
121  assert(!FirstLoc.isUnknown()
122  && "LineStarts should not contain unknown DebugLocs");
123  MDNode *FirstLocScope = FirstLoc.getScope(F.getContext());
124  DISubprogram FunctionDI = getDISubprogram(FirstLocScope);
125  if (FunctionDI.Verify()) {
126  // If we have debug info for the function itself, use that as the line
127  // number of the first several instructions. Otherwise, after filling
128  // LineInfo, we'll adjust the address of the first line number to point at
129  // the start of the function.
130  debug_line_info line_info;
131  line_info.vma = reinterpret_cast<uintptr_t>(FnStart);
132  line_info.lineno = FunctionDI.getLineNumber();
133  line_info.filename = Filenames.getFilename(FirstLocScope);
134  LineInfo.push_back(line_info);
135  }
136 
137  for (std::vector<EmittedFunctionDetails::LineStart>::const_iterator
138  I = Details.LineStarts.begin(), E = Details.LineStarts.end();
139  I != E; ++I) {
140  LineInfo.push_back(LineStartToOProfileFormat(
141  *Details.MF, Filenames, I->Address, I->Loc));
142  }
143 
144  // In case the function didn't have line info of its own, adjust the first
145  // line info's address to include the start of the function.
146  LineInfo[0].vma = reinterpret_cast<uintptr_t>(FnStart);
147 
148  if (Wrapper.op_write_debug_line_info(FnStart, LineInfo.size(),
149  &*LineInfo.begin()) == -1) {
150  DEBUG(dbgs()
151  << "Failed to tell OProfile about line numbers for native function "
152  << F.getName() << " at ["
153  << FnStart << "-" << ((char*)FnStart + FnSize) << "]\n");
154  }
155  }
156 }
157 
158 // Removes the being-deleted function from the symbol table.
159 void OProfileJITEventListener::NotifyFreeingMachineCode(void *FnStart) {
160  assert(FnStart && "Invalid function pointer");
161  if (Wrapper.op_unload_native_code(reinterpret_cast<uint64_t>(FnStart)) == -1) {
162  DEBUG(dbgs()
163  << "Failed to tell OProfile about unload of native function at "
164  << FnStart << "\n");
165  }
166 }
167 
168 void OProfileJITEventListener::NotifyObjectEmitted(const ObjectImage &Obj) {
169  if (!Wrapper.isAgentAvailable()) {
170  return;
171  }
172 
173  // Use symbol info to iterate functions in the object.
174  error_code ec;
176  E = Obj.end_symbols();
177  I != E && !ec;
178  I.increment(ec)) {
179  object::SymbolRef::Type SymType;
180  if (I->getType(SymType)) continue;
181  if (SymType == object::SymbolRef::ST_Function) {
182  StringRef Name;
183  uint64_t Addr;
184  uint64_t Size;
185  if (I->getName(Name)) continue;
186  if (I->getAddress(Addr)) continue;
187  if (I->getSize(Size)) continue;
188 
189  if (Wrapper.op_write_native_code(Name.data(), Addr, (void*)Addr, Size)
190  == -1) {
191  DEBUG(dbgs() << "Failed to tell OProfile about native function "
192  << Name << " at ["
193  << (void*)Addr << "-" << ((char*)Addr + Size) << "]\n");
194  continue;
195  }
196  // TODO: support line number info (similar to IntelJITEventListener.cpp)
197  }
198  }
199 }
200 
201 void OProfileJITEventListener::NotifyFreeingObject(const ObjectImage &Obj) {
202  if (!Wrapper.isAgentAvailable()) {
203  return;
204  }
205 
206  // Use symbol info to iterate functions in the object.
207  error_code ec;
209  E = Obj.end_symbols();
210  I != E && !ec;
211  I.increment(ec)) {
212  object::SymbolRef::Type SymType;
213  if (I->getType(SymType)) continue;
214  if (SymType == object::SymbolRef::ST_Function) {
215  uint64_t Addr;
216  if (I->getAddress(Addr)) continue;
217 
218  if (Wrapper.op_unload_native_code(Addr) == -1) {
219  DEBUG(dbgs()
220  << "Failed to tell OProfile about unload of native function at "
221  << (void*)Addr << "\n");
222  continue;
223  }
224  }
225  }
226 }
227 
228 } // anonymous namespace.
229 
230 namespace llvm {
232  static OwningPtr<OProfileWrapper> JITProfilingWrapper(new OProfileWrapper);
233  return new OProfileJITEventListener(*JITProfilingWrapper);
234 }
235 
236 // for testing
238  OProfileWrapper* TestImpl) {
239  return new OProfileJITEventListener(*TestImpl);
240 }
241 
242 } // namespace llvm
243 
LLVMContext & getContext() const
Definition: Function.cpp:167
bool hasName() const
Definition: Value.h:117
MDNode - a tuple of other values.
Definition: Metadata.h:69
F(f)
const Function * getFunction() const
const char * getFilename(MDNode *Scope)
StringRef getName() const
Definition: Value.cpp:167
bool isUnknown() const
isUnknown - Return true if this is an unknown location.
Definition: DebugLoc.h:70
std::string StrError()
Definition: Errno.cpp:32
unsigned getLine() const
Definition: DebugLoc.h:72
DISubprogram - This is a wrapper for a subprogram (e.g. a function).
Definition: DebugInfo.h:429
const char * data() const
Definition: StringRef.h:107
virtual object::symbol_iterator end_symbols() const =0
virtual object::symbol_iterator begin_symbols() const =0
unsigned getLineNumber() const
Definition: DebugInfo.h:440
DISubprogram getDISubprogram(const MDNode *Scope)
getDISubprogram - Find subprogram that is enclosing this scope.
Definition: DebugInfo.cpp:885
static void initialize(TargetLibraryInfo &TLI, const Triple &T, const char **StandardNames)
MDNode * getScope(const LLVMContext &Ctx) const
Definition: DebugLoc.cpp:20
std::vector< LineStart > LineStarts
The list of line boundary information, sorted by address.
raw_ostream & dbgs()
dbgs - Return a circular-buffered debug stream.
Definition: Debug.cpp:101
const MachineFunction * MF
The machine function the struct contains information for.
#define I(x, y, z)
Definition: MD5.cpp:54
bool Verify() const
Verify - Verify that a subprogram descriptor is well formed.
Definition: DebugInfo.cpp:512
#define DEBUG(X)
Definition: Debug.h:97
static JITEventListener * createOProfileJITEventListener()