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 calls into OProfile to tell
11 // it about JITted functions. For now, we only record function names and sizes,
12 // but eventually we'll also record line number information.
14 // See http://oprofile.sourceforge.net/doc/devel/jit-interface.html for the
15 // definition of the interface we're using.
17 //===----------------------------------------------------------------------===//
19 #define DEBUG_TYPE "oprofile-jit-event-listener"
20 #include "llvm/Function.h"
21 #include "llvm/Analysis/DebugInfo.h"
22 #include "llvm/CodeGen/MachineFunction.h"
23 #include "llvm/ExecutionEngine/JITEventListener.h"
24 #include "llvm/Support/Debug.h"
25 #include "llvm/Support/raw_ostream.h"
26 #include "llvm/System/Errno.h"
27 #include "llvm/Config/config.h"
37 class OProfileJITEventListener
: public JITEventListener
{
40 OProfileJITEventListener();
41 ~OProfileJITEventListener();
43 virtual void NotifyFunctionEmitted(const Function
&F
,
44 void *FnStart
, size_t FnSize
,
45 const EmittedFunctionDetails
&Details
);
46 virtual void NotifyFreeingMachineCode(const Function
&F
, void *OldPtr
);
49 OProfileJITEventListener::OProfileJITEventListener()
50 : Agent(op_open_agent()) {
52 const std::string err_str
= sys::StrError();
53 DEBUG(errs() << "Failed to connect to OProfile agent: " << err_str
<< "\n");
55 DEBUG(errs() << "Connected to OProfile agent.\n");
59 OProfileJITEventListener::~OProfileJITEventListener() {
61 if (op_close_agent(Agent
) == -1) {
62 const std::string err_str
= sys::StrError();
63 DEBUG(errs() << "Failed to disconnect from OProfile agent: "
66 DEBUG(errs() << "Disconnected from OProfile agent.\n");
72 // Holds the filename of each CompileUnit, so that we can pass the
73 // pointer into oprofile. These char*s are freed in the destructor.
74 DenseMap
<MDNode
*, char*> Filenames
;
75 // Used as the scratch space in DICompileUnit::getFilename().
76 std::string TempFilename
;
79 const char* getFilename(MDNode
*CompileUnit
) {
80 char *&Filename
= Filenames
[CompileUnit
];
81 if (Filename
== NULL
) {
82 DICompileUnit
CU(CompileUnit
);
83 Filename
= strdup(CU
.getFilename(TempFilename
).c_str());
88 for (DenseMap
<MDNode
*, char*>::iterator
89 I
= Filenames
.begin(), E
= Filenames
.end(); I
!= E
;++I
) {
95 static debug_line_info
LineStartToOProfileFormat(
96 const MachineFunction
&MF
, FilenameCache
&Filenames
,
97 uintptr_t Address
, DebugLoc Loc
) {
98 debug_line_info Result
;
100 const DebugLocTuple
& tuple
= MF
.getDebugLocTuple(Loc
);
101 Result
.lineno
= tuple
.Line
;
102 Result
.filename
= Filenames
.getFilename(tuple
.CompileUnit
);
103 DEBUG(errs() << "Mapping " << reinterpret_cast<void*>(Result
.vma
) << " to "
104 << Result
.filename
<< ":" << Result
.lineno
<< "\n");
108 // Adds the just-emitted function to the symbol table.
109 void OProfileJITEventListener::NotifyFunctionEmitted(
110 const Function
&F
, void *FnStart
, size_t FnSize
,
111 const EmittedFunctionDetails
&Details
) {
112 assert(F
.hasName() && FnStart
!= 0 && "Bad symbol to add");
113 if (op_write_native_code(Agent
, F
.getName().data(),
114 reinterpret_cast<uint64_t>(FnStart
),
115 FnStart
, FnSize
) == -1) {
116 DEBUG(errs() << "Failed to tell OProfile about native function "
117 << F
.getName() << " at ["
118 << FnStart
<< "-" << ((char*)FnStart
+ FnSize
) << "]\n");
122 // Now we convert the line number information from the address/DebugLoc format
123 // in Details to the address/filename/lineno format that OProfile expects.
124 // OProfile 0.9.4 (and maybe later versions) has a bug that causes it to
125 // ignore line numbers for addresses above 4G.
126 FilenameCache Filenames
;
127 std::vector
<debug_line_info
> LineInfo
;
128 LineInfo
.reserve(1 + Details
.LineStarts
.size());
129 if (!Details
.MF
->getDefaultDebugLoc().isUnknown()) {
130 LineInfo
.push_back(LineStartToOProfileFormat(
131 *Details
.MF
, Filenames
,
132 reinterpret_cast<uintptr_t>(FnStart
),
133 Details
.MF
->getDefaultDebugLoc()));
135 for (std::vector
<EmittedFunctionDetails::LineStart
>::const_iterator
136 I
= Details
.LineStarts
.begin(), E
= Details
.LineStarts
.end();
138 LineInfo
.push_back(LineStartToOProfileFormat(
139 *Details
.MF
, Filenames
, I
->Address
, I
->Loc
));
141 if (!LineInfo
.empty()) {
142 if (op_write_debug_line_info(Agent
, FnStart
,
143 LineInfo
.size(), &*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 to-be-deleted function from the symbol table.
153 void OProfileJITEventListener::NotifyFreeingMachineCode(
154 const Function
&F
, void *FnStart
) {
155 assert(FnStart
&& "Invalid function pointer");
156 if (op_unload_native_code(Agent
, reinterpret_cast<uint64_t>(FnStart
)) == -1) {
157 DEBUG(errs() << "Failed to tell OProfile about unload of native function "
158 << F
.getName() << " at " << FnStart
<< "\n");
162 } // anonymous namespace.
165 JITEventListener
*createOProfileJITEventListener() {
166 return new OProfileJITEventListener
;
170 #else // USE_OPROFILE
173 // By defining this to return NULL, we can let clients call it unconditionally,
174 // even if they haven't configured with the OProfile libraries.
175 JITEventListener
*createOProfileJITEventListener() {
180 #endif // USE_OPROFILE