OProfileJITEventListener.cpp revision 234285
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"
19234285Sdim#include "llvm/Function.h"
20234285Sdim#include "llvm/ADT/OwningPtr.h"
21234285Sdim#include "llvm/Analysis/DebugInfo.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