LLVM API Documentation

OProfileJITEventListener.cpp
Go to the documentation of this file.
00001 //===-- OProfileJITEventListener.cpp - Tell OProfile about JITted code ----===//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 //
00010 // This file defines a JITEventListener object that uses OProfileWrapper to tell
00011 // oprofile about JITted functions, including source line information.
00012 //
00013 //===----------------------------------------------------------------------===//
00014 
00015 #include "llvm/Config/config.h"
00016 #include "llvm/ExecutionEngine/JITEventListener.h"
00017 
00018 #include "llvm/IR/DebugInfo.h"
00019 #include "llvm/IR/Function.h"
00020 #include "llvm/CodeGen/MachineFunction.h"
00021 #include "llvm/ExecutionEngine/ObjectImage.h"
00022 #include "llvm/ExecutionEngine/OProfileWrapper.h"
00023 #include "llvm/Object/ObjectFile.h"
00024 #include "llvm/Support/Debug.h"
00025 #include "llvm/Support/raw_ostream.h"
00026 #include "llvm/Support/Errno.h"
00027 #include "EventListenerCommon.h"
00028 
00029 #include <dirent.h>
00030 #include <fcntl.h>
00031 
00032 using namespace llvm;
00033 using namespace llvm::jitprofiling;
00034 
00035 #define DEBUG_TYPE "oprofile-jit-event-listener"
00036 
00037 namespace {
00038 
00039 class OProfileJITEventListener : public JITEventListener {
00040   OProfileWrapper& Wrapper;
00041 
00042   void initialize();
00043 
00044 public:
00045   OProfileJITEventListener(OProfileWrapper& LibraryWrapper)
00046   : Wrapper(LibraryWrapper) {
00047     initialize();
00048   }
00049 
00050   ~OProfileJITEventListener();
00051 
00052   virtual void NotifyFunctionEmitted(const Function &F,
00053                                 void *FnStart, size_t FnSize,
00054                                 const JITEvent_EmittedFunctionDetails &Details);
00055 
00056   virtual void NotifyFreeingMachineCode(void *OldPtr);
00057 
00058   virtual void NotifyObjectEmitted(const ObjectImage &Obj);
00059 
00060   virtual void NotifyFreeingObject(const ObjectImage &Obj);
00061 };
00062 
00063 void OProfileJITEventListener::initialize() {
00064   if (!Wrapper.op_open_agent()) {
00065     const std::string err_str = sys::StrError();
00066     DEBUG(dbgs() << "Failed to connect to OProfile agent: " << err_str << "\n");
00067   } else {
00068     DEBUG(dbgs() << "Connected to OProfile agent.\n");
00069   }
00070 }
00071 
00072 OProfileJITEventListener::~OProfileJITEventListener() {
00073   if (Wrapper.isAgentAvailable()) {
00074     if (Wrapper.op_close_agent() == -1) {
00075       const std::string err_str = sys::StrError();
00076       DEBUG(dbgs() << "Failed to disconnect from OProfile agent: "
00077                    << err_str << "\n");
00078     } else {
00079       DEBUG(dbgs() << "Disconnected from OProfile agent.\n");
00080     }
00081   }
00082 }
00083 
00084 static debug_line_info LineStartToOProfileFormat(
00085     const MachineFunction &MF, FilenameCache &Filenames,
00086     uintptr_t Address, DebugLoc Loc) {
00087   debug_line_info Result;
00088   Result.vma = Address;
00089   Result.lineno = Loc.getLine();
00090   Result.filename = Filenames.getFilename(
00091     Loc.getScope(MF.getFunction()->getContext()));
00092   DEBUG(dbgs() << "Mapping " << reinterpret_cast<void*>(Result.vma) << " to "
00093                << Result.filename << ":" << Result.lineno << "\n");
00094   return Result;
00095 }
00096 
00097 // Adds the just-emitted function to the symbol table.
00098 void OProfileJITEventListener::NotifyFunctionEmitted(
00099     const Function &F, void *FnStart, size_t FnSize,
00100     const JITEvent_EmittedFunctionDetails &Details) {
00101   assert(F.hasName() && FnStart != 0 && "Bad symbol to add");
00102   if (Wrapper.op_write_native_code(F.getName().data(),
00103                            reinterpret_cast<uint64_t>(FnStart),
00104                            FnStart, FnSize) == -1) {
00105     DEBUG(dbgs() << "Failed to tell OProfile about native function "
00106           << F.getName() << " at ["
00107           << FnStart << "-" << ((char*)FnStart + FnSize) << "]\n");
00108     return;
00109   }
00110 
00111   if (!Details.LineStarts.empty()) {
00112     // Now we convert the line number information from the address/DebugLoc
00113     // format in Details to the address/filename/lineno format that OProfile
00114     // expects.  Note that OProfile 0.9.4 has a bug that causes it to ignore
00115     // line numbers for addresses above 4G.
00116     FilenameCache Filenames;
00117     std::vector<debug_line_info> LineInfo;
00118     LineInfo.reserve(1 + Details.LineStarts.size());
00119 
00120     DebugLoc FirstLoc = Details.LineStarts[0].Loc;
00121     assert(!FirstLoc.isUnknown()
00122            && "LineStarts should not contain unknown DebugLocs");
00123     MDNode *FirstLocScope = FirstLoc.getScope(F.getContext());
00124     DISubprogram FunctionDI = getDISubprogram(FirstLocScope);
00125     if (FunctionDI.Verify()) {
00126       // If we have debug info for the function itself, use that as the line
00127       // number of the first several instructions.  Otherwise, after filling
00128       // LineInfo, we'll adjust the address of the first line number to point at
00129       // the start of the function.
00130       debug_line_info line_info;
00131       line_info.vma = reinterpret_cast<uintptr_t>(FnStart);
00132       line_info.lineno = FunctionDI.getLineNumber();
00133       line_info.filename = Filenames.getFilename(FirstLocScope);
00134       LineInfo.push_back(line_info);
00135     }
00136 
00137     for (std::vector<EmittedFunctionDetails::LineStart>::const_iterator
00138            I = Details.LineStarts.begin(), E = Details.LineStarts.end();
00139          I != E; ++I) {
00140       LineInfo.push_back(LineStartToOProfileFormat(
00141                            *Details.MF, Filenames, I->Address, I->Loc));
00142     }
00143 
00144     // In case the function didn't have line info of its own, adjust the first
00145     // line info's address to include the start of the function.
00146     LineInfo[0].vma = reinterpret_cast<uintptr_t>(FnStart);
00147 
00148     if (Wrapper.op_write_debug_line_info(FnStart, LineInfo.size(),
00149                                       &*LineInfo.begin()) == -1) {
00150       DEBUG(dbgs()
00151             << "Failed to tell OProfile about line numbers for native function "
00152             << F.getName() << " at ["
00153             << FnStart << "-" << ((char*)FnStart + FnSize) << "]\n");
00154     }
00155   }
00156 }
00157 
00158 // Removes the being-deleted function from the symbol table.
00159 void OProfileJITEventListener::NotifyFreeingMachineCode(void *FnStart) {
00160   assert(FnStart && "Invalid function pointer");
00161   if (Wrapper.op_unload_native_code(reinterpret_cast<uint64_t>(FnStart)) == -1) {
00162     DEBUG(dbgs()
00163           << "Failed to tell OProfile about unload of native function at "
00164           << FnStart << "\n");
00165   }
00166 }
00167 
00168 void OProfileJITEventListener::NotifyObjectEmitted(const ObjectImage &Obj) {
00169   if (!Wrapper.isAgentAvailable()) {
00170     return;
00171   }
00172 
00173   // Use symbol info to iterate functions in the object.
00174   for (object::symbol_iterator I = Obj.begin_symbols(), E = Obj.end_symbols();
00175        I != E; ++I) {
00176     object::SymbolRef::Type SymType;
00177     if (I->getType(SymType)) continue;
00178     if (SymType == object::SymbolRef::ST_Function) {
00179       StringRef  Name;
00180       uint64_t   Addr;
00181       uint64_t   Size;
00182       if (I->getName(Name)) continue;
00183       if (I->getAddress(Addr)) continue;
00184       if (I->getSize(Size)) continue;
00185 
00186       if (Wrapper.op_write_native_code(Name.data(), Addr, (void*)Addr, Size)
00187                         == -1) {
00188         DEBUG(dbgs() << "Failed to tell OProfile about native function "
00189           << Name << " at ["
00190           << (void*)Addr << "-" << ((char*)Addr + Size) << "]\n");
00191         continue;
00192       }
00193       // TODO: support line number info (similar to IntelJITEventListener.cpp)
00194     }
00195   }
00196 }
00197 
00198 void OProfileJITEventListener::NotifyFreeingObject(const ObjectImage &Obj) {
00199   if (!Wrapper.isAgentAvailable()) {
00200     return;
00201   }
00202 
00203   // Use symbol info to iterate functions in the object.
00204   for (object::symbol_iterator I = Obj.begin_symbols(), E = Obj.end_symbols();
00205        I != E; ++I) {
00206     object::SymbolRef::Type SymType;
00207     if (I->getType(SymType)) continue;
00208     if (SymType == object::SymbolRef::ST_Function) {
00209       uint64_t   Addr;
00210       if (I->getAddress(Addr)) continue;
00211 
00212       if (Wrapper.op_unload_native_code(Addr) == -1) {
00213         DEBUG(dbgs()
00214           << "Failed to tell OProfile about unload of native function at "
00215           << (void*)Addr << "\n");
00216         continue;
00217       }
00218     }
00219   }
00220 }
00221 
00222 }  // anonymous namespace.
00223 
00224 namespace llvm {
00225 JITEventListener *JITEventListener::createOProfileJITEventListener() {
00226   static std::unique_ptr<OProfileWrapper> JITProfilingWrapper(
00227       new OProfileWrapper);
00228   return new OProfileJITEventListener(*JITProfilingWrapper);
00229 }
00230 
00231 // for testing
00232 JITEventListener *JITEventListener::createOProfileJITEventListener(
00233                                       OProfileWrapper* TestImpl) {
00234   return new OProfileJITEventListener(*TestImpl);
00235 }
00236 
00237 } // namespace llvm
00238