IntelJITEventListener.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. //===-- IntelJITEventListener.cpp - Tell Intel profiler about JITed 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 to tell Intel(R) VTune(TM)
  11. // Amplifier XE 2011 about JITted functions.
  12. //
  13. //===----------------------------------------------------------------------===//
  14. #include "llvm/Config/config.h"
  15. #include "llvm/ExecutionEngine/JITEventListener.h"
  16. #include "llvm/IR/DebugInfo.h"
  17. #include "llvm/IR/Function.h"
  18. #include "llvm/IR/Metadata.h"
  19. #include "llvm/ADT/DenseMap.h"
  20. #include "llvm/CodeGen/MachineFunction.h"
  21. #include "llvm/DebugInfo/DIContext.h"
  22. #include "llvm/ExecutionEngine/ObjectImage.h"
  23. #include "llvm/Object/ObjectFile.h"
  24. #include "llvm/Support/Debug.h"
  25. #include "llvm/Support/raw_ostream.h"
  26. #include "llvm/Support/Errno.h"
  27. #include "llvm/IR/ValueHandle.h"
  28. #include "EventListenerCommon.h"
  29. #include "IntelJITEventsWrapper.h"
  30. using namespace llvm;
  31. using namespace llvm::jitprofiling;
  32. #define DEBUG_TYPE "amplifier-jit-event-listener"
  33. namespace {
  34. class IntelJITEventListener : public JITEventListener {
  35. typedef DenseMap<void*, unsigned int> MethodIDMap;
  36. std::unique_ptr<IntelJITEventsWrapper> Wrapper;
  37. MethodIDMap MethodIDs;
  38. FilenameCache Filenames;
  39. typedef SmallVector<const void *, 64> MethodAddressVector;
  40. typedef DenseMap<const void *, MethodAddressVector> ObjectMap;
  41. ObjectMap LoadedObjectMap;
  42. public:
  43. IntelJITEventListener(IntelJITEventsWrapper* libraryWrapper) {
  44. Wrapper.reset(libraryWrapper);
  45. }
  46. ~IntelJITEventListener() {
  47. }
  48. virtual void NotifyFunctionEmitted(const Function &F,
  49. void *FnStart, size_t FnSize,
  50. const EmittedFunctionDetails &Details);
  51. virtual void NotifyFreeingMachineCode(void *OldPtr);
  52. virtual void NotifyObjectEmitted(const ObjectImage &Obj);
  53. virtual void NotifyFreeingObject(const ObjectImage &Obj);
  54. };
  55. static LineNumberInfo LineStartToIntelJITFormat(
  56. uintptr_t StartAddress,
  57. uintptr_t Address,
  58. DebugLoc Loc) {
  59. LineNumberInfo Result;
  60. Result.Offset = Address - StartAddress;
  61. Result.LineNumber = Loc.getLine();
  62. return Result;
  63. }
  64. static LineNumberInfo DILineInfoToIntelJITFormat(uintptr_t StartAddress,
  65. uintptr_t Address,
  66. DILineInfo Line) {
  67. LineNumberInfo Result;
  68. Result.Offset = Address - StartAddress;
  69. Result.LineNumber = Line.getLine();
  70. return Result;
  71. }
  72. static iJIT_Method_Load FunctionDescToIntelJITFormat(
  73. IntelJITEventsWrapper& Wrapper,
  74. const char* FnName,
  75. uintptr_t FnStart,
  76. size_t FnSize) {
  77. iJIT_Method_Load Result;
  78. memset(&Result, 0, sizeof(iJIT_Method_Load));
  79. Result.method_id = Wrapper.iJIT_GetNewMethodID();
  80. Result.method_name = const_cast<char*>(FnName);
  81. Result.method_load_address = reinterpret_cast<void*>(FnStart);
  82. Result.method_size = FnSize;
  83. Result.class_id = 0;
  84. Result.class_file_name = NULL;
  85. Result.user_data = NULL;
  86. Result.user_data_size = 0;
  87. Result.env = iJDE_JittingAPI;
  88. return Result;
  89. }
  90. // Adds the just-emitted function to the symbol table.
  91. void IntelJITEventListener::NotifyFunctionEmitted(
  92. const Function &F, void *FnStart, size_t FnSize,
  93. const EmittedFunctionDetails &Details) {
  94. iJIT_Method_Load FunctionMessage = FunctionDescToIntelJITFormat(*Wrapper,
  95. F.getName().data(),
  96. reinterpret_cast<uint64_t>(FnStart),
  97. FnSize);
  98. std::vector<LineNumberInfo> LineInfo;
  99. if (!Details.LineStarts.empty()) {
  100. // Now convert the line number information from the address/DebugLoc
  101. // format in Details to the offset/lineno in Intel JIT API format.
  102. LineInfo.reserve(Details.LineStarts.size() + 1);
  103. DebugLoc FirstLoc = Details.LineStarts[0].Loc;
  104. assert(!FirstLoc.isUnknown()
  105. && "LineStarts should not contain unknown DebugLocs");
  106. MDNode *FirstLocScope = FirstLoc.getScope(F.getContext());
  107. DISubprogram FunctionDI = getDISubprogram(FirstLocScope);
  108. if (FunctionDI.Verify()) {
  109. FunctionMessage.source_file_name = const_cast<char*>(
  110. Filenames.getFullPath(FirstLocScope));
  111. LineNumberInfo FirstLine;
  112. FirstLine.Offset = 0;
  113. FirstLine.LineNumber = FunctionDI.getLineNumber();
  114. LineInfo.push_back(FirstLine);
  115. }
  116. for (std::vector<EmittedFunctionDetails::LineStart>::const_iterator I =
  117. Details.LineStarts.begin(), E = Details.LineStarts.end();
  118. I != E; ++I) {
  119. // This implementation ignores the DebugLoc filename because the Intel
  120. // JIT API does not support multiple source files associated with a single
  121. // JIT function
  122. LineInfo.push_back(LineStartToIntelJITFormat(
  123. reinterpret_cast<uintptr_t>(FnStart),
  124. I->Address,
  125. I->Loc));
  126. // If we have no file name yet for the function, use the filename from
  127. // the first instruction that has one
  128. if (FunctionMessage.source_file_name == 0) {
  129. MDNode *scope = I->Loc.getScope(
  130. Details.MF->getFunction()->getContext());
  131. FunctionMessage.source_file_name = const_cast<char*>(
  132. Filenames.getFullPath(scope));
  133. }
  134. }
  135. FunctionMessage.line_number_size = LineInfo.size();
  136. FunctionMessage.line_number_table = &*LineInfo.begin();
  137. } else {
  138. FunctionMessage.line_number_size = 0;
  139. FunctionMessage.line_number_table = 0;
  140. }
  141. Wrapper->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED,
  142. &FunctionMessage);
  143. MethodIDs[FnStart] = FunctionMessage.method_id;
  144. }
  145. void IntelJITEventListener::NotifyFreeingMachineCode(void *FnStart) {
  146. MethodIDMap::iterator I = MethodIDs.find(FnStart);
  147. if (I != MethodIDs.end()) {
  148. Wrapper->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_UNLOAD_START, &I->second);
  149. MethodIDs.erase(I);
  150. }
  151. }
  152. void IntelJITEventListener::NotifyObjectEmitted(const ObjectImage &Obj) {
  153. // Get the address of the object image for use as a unique identifier
  154. const void* ObjData = Obj.getData().data();
  155. DIContext* Context = DIContext::getDWARFContext(Obj.getObjectFile());
  156. MethodAddressVector Functions;
  157. // Use symbol info to iterate functions in the object.
  158. for (object::symbol_iterator I = Obj.begin_symbols(),
  159. E = Obj.end_symbols();
  160. I != E;
  161. ++I) {
  162. std::vector<LineNumberInfo> LineInfo;
  163. std::string SourceFileName;
  164. object::SymbolRef::Type SymType;
  165. if (I->getType(SymType)) continue;
  166. if (SymType == object::SymbolRef::ST_Function) {
  167. StringRef Name;
  168. uint64_t Addr;
  169. uint64_t Size;
  170. if (I->getName(Name)) continue;
  171. if (I->getAddress(Addr)) continue;
  172. if (I->getSize(Size)) continue;
  173. // Record this address in a local vector
  174. Functions.push_back((void*)Addr);
  175. // Build the function loaded notification message
  176. iJIT_Method_Load FunctionMessage = FunctionDescToIntelJITFormat(*Wrapper,
  177. Name.data(),
  178. Addr,
  179. Size);
  180. if (Context) {
  181. DILineInfoTable Lines = Context->getLineInfoForAddressRange(Addr, Size);
  182. DILineInfoTable::iterator Begin = Lines.begin();
  183. DILineInfoTable::iterator End = Lines.end();
  184. for (DILineInfoTable::iterator It = Begin; It != End; ++It) {
  185. LineInfo.push_back(DILineInfoToIntelJITFormat((uintptr_t)Addr,
  186. It->first,
  187. It->second));
  188. }
  189. if (LineInfo.size() == 0) {
  190. FunctionMessage.source_file_name = 0;
  191. FunctionMessage.line_number_size = 0;
  192. FunctionMessage.line_number_table = 0;
  193. } else {
  194. SourceFileName = Lines.front().second.getFileName();
  195. FunctionMessage.source_file_name = const_cast<char *>(SourceFileName.c_str());
  196. FunctionMessage.line_number_size = LineInfo.size();
  197. FunctionMessage.line_number_table = &*LineInfo.begin();
  198. }
  199. } else {
  200. FunctionMessage.source_file_name = 0;
  201. FunctionMessage.line_number_size = 0;
  202. FunctionMessage.line_number_table = 0;
  203. }
  204. Wrapper->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED,
  205. &FunctionMessage);
  206. MethodIDs[(void*)Addr] = FunctionMessage.method_id;
  207. }
  208. }
  209. // To support object unload notification, we need to keep a list of
  210. // registered function addresses for each loaded object. We will
  211. // use the MethodIDs map to get the registered ID for each function.
  212. LoadedObjectMap[ObjData] = Functions;
  213. }
  214. void IntelJITEventListener::NotifyFreeingObject(const ObjectImage &Obj) {
  215. // Get the address of the object image for use as a unique identifier
  216. const void* ObjData = Obj.getData().data();
  217. // Get the object's function list from LoadedObjectMap
  218. ObjectMap::iterator OI = LoadedObjectMap.find(ObjData);
  219. if (OI == LoadedObjectMap.end())
  220. return;
  221. MethodAddressVector& Functions = OI->second;
  222. // Walk the function list, unregistering each function
  223. for (MethodAddressVector::iterator FI = Functions.begin(),
  224. FE = Functions.end();
  225. FI != FE;
  226. ++FI) {
  227. void* FnStart = const_cast<void*>(*FI);
  228. MethodIDMap::iterator MI = MethodIDs.find(FnStart);
  229. if (MI != MethodIDs.end()) {
  230. Wrapper->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_UNLOAD_START,
  231. &MI->second);
  232. MethodIDs.erase(MI);
  233. }
  234. }
  235. // Erase the object from LoadedObjectMap
  236. LoadedObjectMap.erase(OI);
  237. }
  238. } // anonymous namespace.
  239. namespace llvm {
  240. JITEventListener *JITEventListener::createIntelJITEventListener() {
  241. return new IntelJITEventListener(new IntelJITEventsWrapper);
  242. }
  243. // for testing
  244. JITEventListener *JITEventListener::createIntelJITEventListener(
  245. IntelJITEventsWrapper* TestImpl) {
  246. return new IntelJITEventListener(TestImpl);
  247. }
  248. } // namespace llvm