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"
16 #include "llvm/ExecutionEngine/JITEventListener.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"
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"
28
29 #include <dirent.h>
30 #include <fcntl.h>
31
32 using namespace llvm;
33 using namespace llvm::jitprofiling;
34
35 namespace {
36
37 class OProfileJITEventListener : public JITEventListener {
38 OProfileWrapper& Wrapper;
39
40 void initialize();
41
42 public:
OProfileJITEventListener(OProfileWrapper & LibraryWrapper)43 OProfileJITEventListener(OProfileWrapper& LibraryWrapper)
44 : Wrapper(LibraryWrapper) {
45 initialize();
46 }
47
48 ~OProfileJITEventListener();
49
50 virtual void NotifyFunctionEmitted(const Function &F,
51 void *FnStart, size_t FnSize,
52 const JITEvent_EmittedFunctionDetails &Details);
53
54 virtual void NotifyFreeingMachineCode(void *OldPtr);
55 };
56
initialize()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");
61 } else {
62 DEBUG(dbgs() << "Connected to OProfile agent.\n");
63 }
64 }
65
~OProfileJITEventListener()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: "
71 << err_str << "\n");
72 } else {
73 DEBUG(dbgs() << "Disconnected from OProfile agent.\n");
74 }
75 }
76 }
77
LineStartToOProfileFormat(const MachineFunction & MF,FilenameCache & Filenames,uintptr_t Address,DebugLoc Loc)78 static debug_line_info LineStartToOProfileFormat(
79 const MachineFunction &MF, FilenameCache &Filenames,
80 uintptr_t Address, DebugLoc Loc) {
81 debug_line_info Result;
82 Result.vma = Address;
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");
88 return Result;
89 }
90
91 // Adds the just-emitted function to the symbol table.
NotifyFunctionEmitted(const Function & F,void * FnStart,size_t FnSize,const JITEvent_EmittedFunctionDetails & Details)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");
102 return;
103 }
104
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());
113
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);
129 }
130
131 for (std::vector<EmittedFunctionDetails::LineStart>::const_iterator
132 I = Details.LineStarts.begin(), E = Details.LineStarts.end();
133 I != E; ++I) {
134 LineInfo.push_back(LineStartToOProfileFormat(
135 *Details.MF, Filenames, I->Address, I->Loc));
136 }
137
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);
141
142 if (Wrapper.op_write_debug_line_info(FnStart, LineInfo.size(),
143 &*LineInfo.begin()) == -1) {
144 DEBUG(dbgs()
145 << "Failed to tell OProfile about line numbers for native function "
146 << F.getName() << " at ["
147 << FnStart << "-" << ((char*)FnStart + FnSize) << "]\n");
148 }
149 }
150 }
151
152 // Removes the being-deleted function from the symbol table.
NotifyFreeingMachineCode(void * FnStart)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) {
156 DEBUG(dbgs()
157 << "Failed to tell OProfile about unload of native function at "
158 << FnStart << "\n");
159 }
160 }
161
162 } // anonymous namespace.
163
164 namespace llvm {
createOProfileJITEventListener()165 JITEventListener *JITEventListener::createOProfileJITEventListener() {
166 static OwningPtr<OProfileWrapper> JITProfilingWrapper(new OProfileWrapper);
167 return new OProfileJITEventListener(*JITProfilingWrapper);
168 }
169
170 // for testing
createOProfileJITEventListener(OProfileWrapper * TestImpl)171 JITEventListener *JITEventListener::createOProfileJITEventListener(
172 OProfileWrapper* TestImpl) {
173 return new OProfileJITEventListener(*TestImpl);
174 }
175
176 } // namespace llvm
177
178