llvm_jit_event_listener.hpp 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. /* <copyright>
  2. This file is provided under a dual BSD/GPLv2 license. When using or
  3. redistributing this file, you may do so under either license.
  4. GPL LICENSE SUMMARY
  5. Copyright (c) 2005-2014 Intel Corporation. All rights reserved.
  6. This program is free software; you can redistribute it and/or modify
  7. it under the terms of version 2 of the GNU General Public License as
  8. published by the Free Software Foundation.
  9. This program is distributed in the hope that it will be useful, but
  10. WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
  16. The full GNU General Public License is included in this distribution
  17. in the file called LICENSE.GPL.
  18. Contact Information:
  19. http://software.intel.com/en-us/articles/intel-vtune-amplifier-xe/
  20. BSD LICENSE
  21. Copyright (c) 2005-2014 Intel Corporation. All rights reserved.
  22. All rights reserved.
  23. Redistribution and use in source and binary forms, with or without
  24. modification, are permitted provided that the following conditions
  25. are met:
  26. * Redistributions of source code must retain the above copyright
  27. notice, this list of conditions and the following disclaimer.
  28. * Redistributions in binary form must reproduce the above copyright
  29. notice, this list of conditions and the following disclaimer in
  30. the documentation and/or other materials provided with the
  31. distribution.
  32. * Neither the name of Intel Corporation nor the names of its
  33. contributors may be used to endorse or promote products derived
  34. from this software without specific prior written permission.
  35. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  36. "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  37. LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  38. A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  39. OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  40. SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  41. LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  42. DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  43. THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  44. (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  45. OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  46. </copyright> */
  47. /*
  48. * This file implements an interface bridge from Low-Level Virtual Machine
  49. * llvm::JITEventListener to Intel JIT Profiling API. It passes the function
  50. * and line information to the appropriate functions in the JIT profiling
  51. * interface so that any LLVM-based JIT engine can emit the JIT code
  52. * notifications that the profiler will receive.
  53. *
  54. * Usage model:
  55. *
  56. * 1. Register the listener implementation instance with the execution engine:
  57. *
  58. * #include <llvm_jit_event_listener.hpp>
  59. * ...
  60. * ExecutionEngine *TheExecutionEngine;
  61. * ...
  62. * TheExecutionEngine = EngineBuilder(TheModule).create();
  63. * ...
  64. * __itt_llvm_jit_event_listener jitListener;
  65. * TheExecutionEngine->RegisterJITEventListener(&jitListener);
  66. * ...
  67. *
  68. * 2. When compiling make sure to add the ITT API include directory to the
  69. * compiler include directories, ITT API library directory to the linker
  70. * library directories and link with jitprofling static library.
  71. */
  72. #ifndef __ITT_LLVM_JIT_EVENT_LISTENER_HPP__
  73. #define __ITT_LLVM_JIT_EVENT_LISTENER_HPP__
  74. #include "jitprofiling.h"
  75. #include <llvm/Function.h>
  76. #include <llvm/ExecutionEngine/JITEventListener.h>
  77. #include <llvm/ADT/StringRef.h>
  78. #include <llvm/Analysis/DebugInfo.h>
  79. #include <map>
  80. #include <cassert>
  81. // Uncomment the line below to turn on logging to stderr
  82. #define JITPROFILING_DEBUG_ENABLE
  83. // Some elementary logging support
  84. #ifdef JITPROFILING_DEBUG_ENABLE
  85. #include <cstdio>
  86. #include <cstdarg>
  87. static void _jit_debug(const char* format, ...)
  88. {
  89. va_list args;
  90. va_start(args, format);
  91. vfprintf(stderr, format, args);
  92. va_end(args);
  93. }
  94. // Use the macro as JITDEBUG(("foo: %d", foo_val));
  95. #define JITDEBUG(x) \
  96. do { \
  97. _jit_debug("jit-listener: "); \
  98. _jit_debug x; \
  99. } \
  100. while (0)
  101. #else
  102. #define JITDEBUG(x)
  103. #endif
  104. // LLVM JIT event listener, translates the notifications to the JIT profiling
  105. // API information.
  106. class __itt_llvm_jit_event_listener : public llvm::JITEventListener
  107. {
  108. public:
  109. __itt_llvm_jit_event_listener() {}
  110. public:
  111. virtual void NotifyFunctionEmitted(const llvm::Function &F,
  112. void *Code, size_t Size, const EmittedFunctionDetails &Details)
  113. {
  114. std::string name = F.getName().str();
  115. JITDEBUG(("function jitted:\n"));
  116. JITDEBUG((" addr=0x%08x\n", (int)Code));
  117. JITDEBUG((" name=`%s'\n", name.c_str()));
  118. JITDEBUG((" code-size=%d\n", (int)Size));
  119. JITDEBUG((" line-infos-count=%d\n", Details.LineStarts.size()));
  120. // The method must not be in the map - the entry must have been cleared
  121. // from the map in NotifyFreeingMachineCode in case of rejitting.
  122. assert(m_addr2MethodId.find(Code) == m_addr2MethodId.end());
  123. int mid = iJIT_GetNewMethodID();
  124. m_addr2MethodId[Code] = mid;
  125. iJIT_Method_Load mload;
  126. memset(&mload, 0, sizeof mload);
  127. mload.method_id = mid;
  128. // Populate the method size and name information
  129. // TODO: The JIT profiling API should have members as const char pointers.
  130. mload.method_name = (char*)name.c_str();
  131. mload.method_load_address = Code;
  132. mload.method_size = (unsigned int)Size;
  133. // Populate line information now.
  134. // From the JIT API documentation it is not quite clear whether the
  135. // line information can be given in ranges, so we'll populate it for
  136. // every byte of the function, hmm.
  137. std::string srcFilePath;
  138. std::vector<LineNumberInfo> lineInfos;
  139. char *addr = (char*)Code;
  140. char *lineAddr = addr; // Exclusive end point at which current
  141. // line info changes.
  142. const llvm::DebugLoc* loc = 0; // Current line info
  143. int lineIndex = -1; // Current index into the line info table
  144. for (int i = 0; i < Size; ++i, ++addr) {
  145. while (addr >= lineAddr) {
  146. if (lineIndex >= 0 && lineIndex < Details.LineStarts.size()) {
  147. loc = &Details.LineStarts[lineIndex].Loc;
  148. std::string p = getSrcFilePath(F.getContext(), *loc);
  149. assert(srcFilePath.empty() || p == srcFilePath);
  150. srcFilePath = p;
  151. } else {
  152. loc = NULL;
  153. }
  154. lineIndex++;
  155. if (lineIndex >= 0 && lineIndex < Details.LineStarts.size()) {
  156. lineAddr = (char*)Details.LineStarts[lineIndex].Address;
  157. } else {
  158. lineAddr = addr + Size;
  159. }
  160. }
  161. if (loc) {
  162. int line = loc->getLine();
  163. LineNumberInfo info = { i, line };
  164. lineInfos.push_back(info);
  165. JITDEBUG((" addr 0x%08x -> line %d\n", addr, line));
  166. }
  167. }
  168. if (!lineInfos.empty()) {
  169. mload.line_number_size = lineInfos.size();
  170. JITDEBUG((" translated to %d line infos to JIT", (int)lineInfos.size()));
  171. mload.line_number_table = &lineInfos[0];
  172. mload.source_file_name = (char*)srcFilePath.c_str();
  173. }
  174. iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, &mload);
  175. }
  176. virtual void NotifyFreeingMachineCode(void *OldPtr)
  177. {
  178. JITDEBUG(("function unjitted\n"));
  179. JITDEBUG((" addr=0x%08x\n", (int)OldPtr));
  180. Addr2MethodId::iterator it = m_addr2MethodId.find(OldPtr);
  181. assert(it != m_addr2MethodId.end());
  182. iJIT_Method_Id mid = { it->second };
  183. iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_UNLOAD_START, &mid);
  184. m_addr2MethodId.erase(it);
  185. }
  186. private:
  187. std::string getSrcFilePath(const llvm::LLVMContext& ctx, const llvm::DebugLoc& loc)
  188. {
  189. llvm::MDNode* node = loc.getAsMDNode(ctx);
  190. llvm::DILocation srcLoc(node);
  191. return srcLoc.getDirectory().str() + "/" + srcLoc.getFilename().str();
  192. }
  193. private:
  194. /// Don't copy
  195. __itt_llvm_jit_event_listener(const __itt_llvm_jit_event_listener&);
  196. __itt_llvm_jit_event_listener& operator=(const __itt_llvm_jit_event_listener&);
  197. private:
  198. typedef std::vector<LineNumberInfo> LineInfoList;
  199. // The method unload notification in VTune JIT profiling API takes the
  200. // method ID, not method address so have to maintain the mapping. Is
  201. // there a more efficient and simple way to do this like attaching the
  202. // method ID information somehow to the LLVM function instance?
  203. //
  204. // TODO: It would be more convenient for the JIT API to take the method
  205. // address, not method ID.
  206. typedef std::map<const void*, int> Addr2MethodId;
  207. Addr2MethodId m_addr2MethodId;
  208. };
  209. #endif // Header guard