OProfileJITEventListener.cpp revision 249423
1234285Sdim//===-- OProfileJITEventListener.cpp - Tell OProfile about JITted code ----===// 2234285Sdim// 3234285Sdim// The LLVM Compiler Infrastructure 4234285Sdim// 5234285Sdim// This file is distributed under the University of Illinois Open Source 6234285Sdim// License. See LICENSE.TXT for details. 7234285Sdim// 8234285Sdim//===----------------------------------------------------------------------===// 9234285Sdim// 10234285Sdim// This file defines a JITEventListener object that uses OProfileWrapper to tell 11234285Sdim// oprofile about JITted functions, including source line information. 12234285Sdim// 13234285Sdim//===----------------------------------------------------------------------===// 14234285Sdim 15234285Sdim#include "llvm/Config/config.h" 16234285Sdim#include "llvm/ExecutionEngine/JITEventListener.h" 17234285Sdim 18234285Sdim#define DEBUG_TYPE "oprofile-jit-event-listener" 19239462Sdim#include "llvm/DebugInfo.h" 20249423Sdim#include "llvm/IR/Function.h" 21234285Sdim#include "llvm/ADT/OwningPtr.h" 22234285Sdim#include "llvm/CodeGen/MachineFunction.h" 23234285Sdim#include "llvm/ExecutionEngine/OProfileWrapper.h" 24234285Sdim#include "llvm/Support/Debug.h" 25234285Sdim#include "llvm/Support/raw_ostream.h" 26234285Sdim#include "llvm/Support/Errno.h" 27234285Sdim#include "EventListenerCommon.h" 28234285Sdim 29234285Sdim#include <dirent.h> 30234285Sdim#include <fcntl.h> 31234285Sdim 32234285Sdimusing namespace llvm; 33234285Sdimusing namespace llvm::jitprofiling; 34234285Sdim 35234285Sdimnamespace { 36234285Sdim 37234285Sdimclass OProfileJITEventListener : public JITEventListener { 38234285Sdim OProfileWrapper& Wrapper; 39234285Sdim 40234285Sdim void initialize(); 41234285Sdim 42234285Sdimpublic: 43234285Sdim OProfileJITEventListener(OProfileWrapper& LibraryWrapper) 44234285Sdim : Wrapper(LibraryWrapper) { 45234285Sdim initialize(); 46234285Sdim } 47234285Sdim 48234285Sdim ~OProfileJITEventListener(); 49234285Sdim 50234285Sdim virtual void NotifyFunctionEmitted(const Function &F, 51234285Sdim void *FnStart, size_t FnSize, 52234285Sdim const JITEvent_EmittedFunctionDetails &Details); 53234285Sdim 54234285Sdim virtual void NotifyFreeingMachineCode(void *OldPtr); 55234285Sdim}; 56234285Sdim 57234285Sdimvoid OProfileJITEventListener::initialize() { 58234285Sdim if (!Wrapper.op_open_agent()) { 59234285Sdim const std::string err_str = sys::StrError(); 60234285Sdim DEBUG(dbgs() << "Failed to connect to OProfile agent: " << err_str << "\n"); 61234285Sdim } else { 62234285Sdim DEBUG(dbgs() << "Connected to OProfile agent.\n"); 63234285Sdim } 64234285Sdim} 65234285Sdim 66234285SdimOProfileJITEventListener::~OProfileJITEventListener() { 67234285Sdim if (Wrapper.isAgentAvailable()) { 68234285Sdim if (Wrapper.op_close_agent() == -1) { 69234285Sdim const std::string err_str = sys::StrError(); 70234285Sdim DEBUG(dbgs() << "Failed to disconnect from OProfile agent: " 71234285Sdim << err_str << "\n"); 72234285Sdim } else { 73234285Sdim DEBUG(dbgs() << "Disconnected from OProfile agent.\n"); 74234285Sdim } 75234285Sdim } 76234285Sdim} 77234285Sdim 78234285Sdimstatic debug_line_info LineStartToOProfileFormat( 79234285Sdim const MachineFunction &MF, FilenameCache &Filenames, 80234285Sdim uintptr_t Address, DebugLoc Loc) { 81234285Sdim debug_line_info Result; 82234285Sdim Result.vma = Address; 83234285Sdim Result.lineno = Loc.getLine(); 84234285Sdim Result.filename = Filenames.getFilename( 85234285Sdim Loc.getScope(MF.getFunction()->getContext())); 86234285Sdim DEBUG(dbgs() << "Mapping " << reinterpret_cast<void*>(Result.vma) << " to " 87234285Sdim << Result.filename << ":" << Result.lineno << "\n"); 88234285Sdim return Result; 89234285Sdim} 90234285Sdim 91234285Sdim// Adds the just-emitted function to the symbol table. 92234285Sdimvoid OProfileJITEventListener::NotifyFunctionEmitted( 93234285Sdim const Function &F, void *FnStart, size_t FnSize, 94234285Sdim const JITEvent_EmittedFunctionDetails &Details) { 95234285Sdim assert(F.hasName() && FnStart != 0 && "Bad symbol to add"); 96234285Sdim if (Wrapper.op_write_native_code(F.getName().data(), 97234285Sdim reinterpret_cast<uint64_t>(FnStart), 98234285Sdim FnStart, FnSize) == -1) { 99234285Sdim DEBUG(dbgs() << "Failed to tell OProfile about native function " 100234285Sdim << F.getName() << " at [" 101234285Sdim << FnStart << "-" << ((char*)FnStart + FnSize) << "]\n"); 102234285Sdim return; 103234285Sdim } 104234285Sdim 105234285Sdim if (!Details.LineStarts.empty()) { 106234285Sdim // Now we convert the line number information from the address/DebugLoc 107234285Sdim // format in Details to the address/filename/lineno format that OProfile 108234285Sdim // expects. Note that OProfile 0.9.4 has a bug that causes it to ignore 109234285Sdim // line numbers for addresses above 4G. 110234285Sdim FilenameCache Filenames; 111234285Sdim std::vector<debug_line_info> LineInfo; 112234285Sdim LineInfo.reserve(1 + Details.LineStarts.size()); 113234285Sdim 114234285Sdim DebugLoc FirstLoc = Details.LineStarts[0].Loc; 115234285Sdim assert(!FirstLoc.isUnknown() 116234285Sdim && "LineStarts should not contain unknown DebugLocs"); 117234285Sdim MDNode *FirstLocScope = FirstLoc.getScope(F.getContext()); 118234285Sdim DISubprogram FunctionDI = getDISubprogram(FirstLocScope); 119234285Sdim if (FunctionDI.Verify()) { 120234285Sdim // If we have debug info for the function itself, use that as the line 121234285Sdim // number of the first several instructions. Otherwise, after filling 122234285Sdim // LineInfo, we'll adjust the address of the first line number to point at 123234285Sdim // the start of the function. 124234285Sdim debug_line_info line_info; 125234285Sdim line_info.vma = reinterpret_cast<uintptr_t>(FnStart); 126234285Sdim line_info.lineno = FunctionDI.getLineNumber(); 127234285Sdim line_info.filename = Filenames.getFilename(FirstLocScope); 128234285Sdim LineInfo.push_back(line_info); 129234285Sdim } 130234285Sdim 131234285Sdim for (std::vector<EmittedFunctionDetails::LineStart>::const_iterator 132234285Sdim I = Details.LineStarts.begin(), E = Details.LineStarts.end(); 133234285Sdim I != E; ++I) { 134234285Sdim LineInfo.push_back(LineStartToOProfileFormat( 135234285Sdim *Details.MF, Filenames, I->Address, I->Loc)); 136234285Sdim } 137234285Sdim 138234285Sdim // In case the function didn't have line info of its own, adjust the first 139234285Sdim // line info's address to include the start of the function. 140234285Sdim LineInfo[0].vma = reinterpret_cast<uintptr_t>(FnStart); 141234285Sdim 142234285Sdim if (Wrapper.op_write_debug_line_info(FnStart, LineInfo.size(), 143234285Sdim &*LineInfo.begin()) == -1) { 144234285Sdim DEBUG(dbgs() 145234285Sdim << "Failed to tell OProfile about line numbers for native function " 146234285Sdim << F.getName() << " at [" 147234285Sdim << FnStart << "-" << ((char*)FnStart + FnSize) << "]\n"); 148234285Sdim } 149234285Sdim } 150234285Sdim} 151234285Sdim 152234285Sdim// Removes the being-deleted function from the symbol table. 153234285Sdimvoid OProfileJITEventListener::NotifyFreeingMachineCode(void *FnStart) { 154234285Sdim assert(FnStart && "Invalid function pointer"); 155234285Sdim if (Wrapper.op_unload_native_code(reinterpret_cast<uint64_t>(FnStart)) == -1) { 156234285Sdim DEBUG(dbgs() 157234285Sdim << "Failed to tell OProfile about unload of native function at " 158234285Sdim << FnStart << "\n"); 159234285Sdim } 160234285Sdim} 161234285Sdim 162234285Sdim} // anonymous namespace. 163234285Sdim 164234285Sdimnamespace llvm { 165234285SdimJITEventListener *JITEventListener::createOProfileJITEventListener() { 166234285Sdim static OwningPtr<OProfileWrapper> JITProfilingWrapper(new OProfileWrapper); 167234285Sdim return new OProfileJITEventListener(*JITProfilingWrapper); 168234285Sdim} 169234285Sdim 170234285Sdim// for testing 171234285SdimJITEventListener *JITEventListener::createOProfileJITEventListener( 172234285Sdim OProfileWrapper* TestImpl) { 173234285Sdim return new OProfileJITEventListener(*TestImpl); 174234285Sdim} 175234285Sdim 176234285Sdim} // namespace llvm 177234285Sdim 178