1 //===-- OProfileJITEventListener.cpp - Tell OProfile about JITted code ----===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file defines a JITEventListener object that uses OProfileWrapper to tell
11 // oprofile about JITted functions, including source line information.
13 //===----------------------------------------------------------------------===//
15 #include "llvm/Config/config.h"
16 #include "llvm/ExecutionEngine/JITEventListener.h"
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"
22 #include "llvm/CodeGen/MachineFunction.h"
23 #include "llvm/ExecutionEngine/OProfileWrapper.h"
24 #include "llvm/Support/Debug.h"
25 #include "llvm/Support/raw_ostream.h"
26 #include "llvm/Support/Errno.h"
27 #include "EventListenerCommon.h"
33 using namespace llvm::jitprofiling;
37 class OProfileJITEventListener : public JITEventListener {
38 OProfileWrapper& Wrapper;
43 OProfileJITEventListener(OProfileWrapper& LibraryWrapper)
44 : Wrapper(LibraryWrapper) {
48 ~OProfileJITEventListener();
50 virtual void NotifyFunctionEmitted(const Function &F,
51 void *FnStart, size_t FnSize,
52 const JITEvent_EmittedFunctionDetails &Details);
54 virtual void NotifyFreeingMachineCode(void *OldPtr);
57 void OProfileJITEventListener::initialize() {
58 if (!Wrapper.op_open_agent()) {
59 const std::string err_str = sys::StrError();
60 DEBUG(dbgs() << "Failed to connect to OProfile agent: " << err_str << "\n");
62 DEBUG(dbgs() << "Connected to OProfile agent.\n");
66 OProfileJITEventListener::~OProfileJITEventListener() {
67 if (Wrapper.isAgentAvailable()) {
68 if (Wrapper.op_close_agent() == -1) {
69 const std::string err_str = sys::StrError();
70 DEBUG(dbgs() << "Failed to disconnect from OProfile agent: "
73 DEBUG(dbgs() << "Disconnected from OProfile agent.\n");
78 static debug_line_info LineStartToOProfileFormat(
79 const MachineFunction &MF, FilenameCache &Filenames,
80 uintptr_t Address, DebugLoc Loc) {
81 debug_line_info Result;
83 Result.lineno = Loc.getLine();
84 Result.filename = Filenames.getFilename(
85 Loc.getScope(MF.getFunction()->getContext()));
86 DEBUG(dbgs() << "Mapping " << reinterpret_cast<void*>(Result.vma) << " to "
87 << Result.filename << ":" << Result.lineno << "\n");
91 // Adds the just-emitted function to the symbol table.
92 void OProfileJITEventListener::NotifyFunctionEmitted(
93 const Function &F, void *FnStart, size_t FnSize,
94 const JITEvent_EmittedFunctionDetails &Details) {
95 assert(F.hasName() && FnStart != 0 && "Bad symbol to add");
96 if (Wrapper.op_write_native_code(F.getName().data(),
97 reinterpret_cast<uint64_t>(FnStart),
98 FnStart, FnSize) == -1) {
99 DEBUG(dbgs() << "Failed to tell OProfile about native function "
100 << F.getName() << " at ["
101 << FnStart << "-" << ((char*)FnStart + FnSize) << "]\n");
105 if (!Details.LineStarts.empty()) {
106 // Now we convert the line number information from the address/DebugLoc
107 // format in Details to the address/filename/lineno format that OProfile
108 // expects. Note that OProfile 0.9.4 has a bug that causes it to ignore
109 // line numbers for addresses above 4G.
110 FilenameCache Filenames;
111 std::vector<debug_line_info> LineInfo;
112 LineInfo.reserve(1 + Details.LineStarts.size());
114 DebugLoc FirstLoc = Details.LineStarts[0].Loc;
115 assert(!FirstLoc.isUnknown()
116 && "LineStarts should not contain unknown DebugLocs");
117 MDNode *FirstLocScope = FirstLoc.getScope(F.getContext());
118 DISubprogram FunctionDI = getDISubprogram(FirstLocScope);
119 if (FunctionDI.Verify()) {
120 // If we have debug info for the function itself, use that as the line
121 // number of the first several instructions. Otherwise, after filling
122 // LineInfo, we'll adjust the address of the first line number to point at
123 // the start of the function.
124 debug_line_info line_info;
125 line_info.vma = reinterpret_cast<uintptr_t>(FnStart);
126 line_info.lineno = FunctionDI.getLineNumber();
127 line_info.filename = Filenames.getFilename(FirstLocScope);
128 LineInfo.push_back(line_info);
131 for (std::vector<EmittedFunctionDetails::LineStart>::const_iterator
132 I = Details.LineStarts.begin(), E = Details.LineStarts.end();
134 LineInfo.push_back(LineStartToOProfileFormat(
135 *Details.MF, Filenames, I->Address, I->Loc));
138 // In case the function didn't have line info of its own, adjust the first
139 // line info's address to include the start of the function.
140 LineInfo[0].vma = reinterpret_cast<uintptr_t>(FnStart);
142 if (Wrapper.op_write_debug_line_info(FnStart, LineInfo.size(),
143 &*LineInfo.begin()) == -1) {
145 << "Failed to tell OProfile about line numbers for native function "
146 << F.getName() << " at ["
147 << FnStart << "-" << ((char*)FnStart + FnSize) << "]\n");
152 // Removes the being-deleted function from the symbol table.
153 void OProfileJITEventListener::NotifyFreeingMachineCode(void *FnStart) {
154 assert(FnStart && "Invalid function pointer");
155 if (Wrapper.op_unload_native_code(reinterpret_cast<uint64_t>(FnStart)) == -1) {
157 << "Failed to tell OProfile about unload of native function at "
162 } // anonymous namespace.
165 JITEventListener *JITEventListener::createOProfileJITEventListener() {
166 static OwningPtr<OProfileWrapper> JITProfilingWrapper(new OProfileWrapper);
167 return new OProfileJITEventListener(*JITProfilingWrapper);
171 JITEventListener *JITEventListener::createOProfileJITEventListener(
172 OProfileWrapper* TestImpl) {
173 return new OProfileJITEventListener(*TestImpl);