LLVM API Documentation
00001 //===-- IntelJITEventListener.cpp - Tell Intel profiler about JITed code --===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // This file defines a JITEventListener object to tell Intel(R) VTune(TM) 00011 // Amplifier XE 2011 about JITted functions. 00012 // 00013 //===----------------------------------------------------------------------===// 00014 00015 #include "llvm/Config/config.h" 00016 #include "llvm/ExecutionEngine/JITEventListener.h" 00017 00018 #include "llvm/IR/DebugInfo.h" 00019 #include "llvm/IR/Function.h" 00020 #include "llvm/IR/Metadata.h" 00021 #include "llvm/ADT/DenseMap.h" 00022 #include "llvm/CodeGen/MachineFunction.h" 00023 #include "llvm/DebugInfo/DIContext.h" 00024 #include "llvm/ExecutionEngine/ObjectImage.h" 00025 #include "llvm/Object/ObjectFile.h" 00026 #include "llvm/Support/Debug.h" 00027 #include "llvm/Support/raw_ostream.h" 00028 #include "llvm/Support/Errno.h" 00029 #include "llvm/IR/ValueHandle.h" 00030 #include "EventListenerCommon.h" 00031 #include "IntelJITEventsWrapper.h" 00032 00033 using namespace llvm; 00034 using namespace llvm::jitprofiling; 00035 00036 #define DEBUG_TYPE "amplifier-jit-event-listener" 00037 00038 namespace { 00039 00040 class IntelJITEventListener : public JITEventListener { 00041 typedef DenseMap<void*, unsigned int> MethodIDMap; 00042 00043 std::unique_ptr<IntelJITEventsWrapper> Wrapper; 00044 MethodIDMap MethodIDs; 00045 FilenameCache Filenames; 00046 00047 typedef SmallVector<const void *, 64> MethodAddressVector; 00048 typedef DenseMap<const void *, MethodAddressVector> ObjectMap; 00049 00050 ObjectMap LoadedObjectMap; 00051 00052 public: 00053 IntelJITEventListener(IntelJITEventsWrapper* libraryWrapper) { 00054 Wrapper.reset(libraryWrapper); 00055 } 00056 00057 ~IntelJITEventListener() { 00058 } 00059 00060 virtual void NotifyFunctionEmitted(const Function &F, 00061 void *FnStart, size_t FnSize, 00062 const EmittedFunctionDetails &Details); 00063 00064 virtual void NotifyFreeingMachineCode(void *OldPtr); 00065 00066 virtual void NotifyObjectEmitted(const ObjectImage &Obj); 00067 00068 virtual void NotifyFreeingObject(const ObjectImage &Obj); 00069 }; 00070 00071 static LineNumberInfo LineStartToIntelJITFormat( 00072 uintptr_t StartAddress, 00073 uintptr_t Address, 00074 DebugLoc Loc) { 00075 LineNumberInfo Result; 00076 00077 Result.Offset = Address - StartAddress; 00078 Result.LineNumber = Loc.getLine(); 00079 00080 return Result; 00081 } 00082 00083 static LineNumberInfo DILineInfoToIntelJITFormat(uintptr_t StartAddress, 00084 uintptr_t Address, 00085 DILineInfo Line) { 00086 LineNumberInfo Result; 00087 00088 Result.Offset = Address - StartAddress; 00089 Result.LineNumber = Line.Line; 00090 00091 return Result; 00092 } 00093 00094 static iJIT_Method_Load FunctionDescToIntelJITFormat( 00095 IntelJITEventsWrapper& Wrapper, 00096 const char* FnName, 00097 uintptr_t FnStart, 00098 size_t FnSize) { 00099 iJIT_Method_Load Result; 00100 memset(&Result, 0, sizeof(iJIT_Method_Load)); 00101 00102 Result.method_id = Wrapper.iJIT_GetNewMethodID(); 00103 Result.method_name = const_cast<char*>(FnName); 00104 Result.method_load_address = reinterpret_cast<void*>(FnStart); 00105 Result.method_size = FnSize; 00106 00107 Result.class_id = 0; 00108 Result.class_file_name = NULL; 00109 Result.user_data = NULL; 00110 Result.user_data_size = 0; 00111 Result.env = iJDE_JittingAPI; 00112 00113 return Result; 00114 } 00115 00116 // Adds the just-emitted function to the symbol table. 00117 void IntelJITEventListener::NotifyFunctionEmitted( 00118 const Function &F, void *FnStart, size_t FnSize, 00119 const EmittedFunctionDetails &Details) { 00120 iJIT_Method_Load FunctionMessage = FunctionDescToIntelJITFormat(*Wrapper, 00121 F.getName().data(), 00122 reinterpret_cast<uint64_t>(FnStart), 00123 FnSize); 00124 00125 std::vector<LineNumberInfo> LineInfo; 00126 00127 if (!Details.LineStarts.empty()) { 00128 // Now convert the line number information from the address/DebugLoc 00129 // format in Details to the offset/lineno in Intel JIT API format. 00130 00131 LineInfo.reserve(Details.LineStarts.size() + 1); 00132 00133 DebugLoc FirstLoc = Details.LineStarts[0].Loc; 00134 assert(!FirstLoc.isUnknown() 00135 && "LineStarts should not contain unknown DebugLocs"); 00136 00137 MDNode *FirstLocScope = FirstLoc.getScope(F.getContext()); 00138 DISubprogram FunctionDI = getDISubprogram(FirstLocScope); 00139 if (FunctionDI.Verify()) { 00140 FunctionMessage.source_file_name = const_cast<char*>( 00141 Filenames.getFullPath(FirstLocScope)); 00142 00143 LineNumberInfo FirstLine; 00144 FirstLine.Offset = 0; 00145 FirstLine.LineNumber = FunctionDI.getLineNumber(); 00146 LineInfo.push_back(FirstLine); 00147 } 00148 00149 for (std::vector<EmittedFunctionDetails::LineStart>::const_iterator I = 00150 Details.LineStarts.begin(), E = Details.LineStarts.end(); 00151 I != E; ++I) { 00152 // This implementation ignores the DebugLoc filename because the Intel 00153 // JIT API does not support multiple source files associated with a single 00154 // JIT function 00155 LineInfo.push_back(LineStartToIntelJITFormat( 00156 reinterpret_cast<uintptr_t>(FnStart), 00157 I->Address, 00158 I->Loc)); 00159 00160 // If we have no file name yet for the function, use the filename from 00161 // the first instruction that has one 00162 if (FunctionMessage.source_file_name == 0) { 00163 MDNode *scope = I->Loc.getScope( 00164 Details.MF->getFunction()->getContext()); 00165 FunctionMessage.source_file_name = const_cast<char*>( 00166 Filenames.getFullPath(scope)); 00167 } 00168 } 00169 00170 FunctionMessage.line_number_size = LineInfo.size(); 00171 FunctionMessage.line_number_table = &*LineInfo.begin(); 00172 } else { 00173 FunctionMessage.line_number_size = 0; 00174 FunctionMessage.line_number_table = 0; 00175 } 00176 00177 Wrapper->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, 00178 &FunctionMessage); 00179 MethodIDs[FnStart] = FunctionMessage.method_id; 00180 } 00181 00182 void IntelJITEventListener::NotifyFreeingMachineCode(void *FnStart) { 00183 MethodIDMap::iterator I = MethodIDs.find(FnStart); 00184 if (I != MethodIDs.end()) { 00185 Wrapper->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_UNLOAD_START, &I->second); 00186 MethodIDs.erase(I); 00187 } 00188 } 00189 00190 void IntelJITEventListener::NotifyObjectEmitted(const ObjectImage &Obj) { 00191 // Get the address of the object image for use as a unique identifier 00192 const void* ObjData = Obj.getData().data(); 00193 DIContext* Context = DIContext::getDWARFContext(*Obj.getObjectFile()); 00194 MethodAddressVector Functions; 00195 00196 // Use symbol info to iterate functions in the object. 00197 for (object::symbol_iterator I = Obj.begin_symbols(), 00198 E = Obj.end_symbols(); 00199 I != E; 00200 ++I) { 00201 std::vector<LineNumberInfo> LineInfo; 00202 std::string SourceFileName; 00203 00204 object::SymbolRef::Type SymType; 00205 if (I->getType(SymType)) continue; 00206 if (SymType == object::SymbolRef::ST_Function) { 00207 StringRef Name; 00208 uint64_t Addr; 00209 uint64_t Size; 00210 if (I->getName(Name)) continue; 00211 if (I->getAddress(Addr)) continue; 00212 if (I->getSize(Size)) continue; 00213 00214 // Record this address in a local vector 00215 Functions.push_back((void*)Addr); 00216 00217 // Build the function loaded notification message 00218 iJIT_Method_Load FunctionMessage = FunctionDescToIntelJITFormat(*Wrapper, 00219 Name.data(), 00220 Addr, 00221 Size); 00222 if (Context) { 00223 DILineInfoTable Lines = Context->getLineInfoForAddressRange(Addr, Size); 00224 DILineInfoTable::iterator Begin = Lines.begin(); 00225 DILineInfoTable::iterator End = Lines.end(); 00226 for (DILineInfoTable::iterator It = Begin; It != End; ++It) { 00227 LineInfo.push_back(DILineInfoToIntelJITFormat((uintptr_t)Addr, 00228 It->first, 00229 It->second)); 00230 } 00231 if (LineInfo.size() == 0) { 00232 FunctionMessage.source_file_name = 0; 00233 FunctionMessage.line_number_size = 0; 00234 FunctionMessage.line_number_table = 0; 00235 } else { 00236 SourceFileName = Lines.front().second.FileName; 00237 FunctionMessage.source_file_name = const_cast<char *>(SourceFileName.c_str()); 00238 FunctionMessage.line_number_size = LineInfo.size(); 00239 FunctionMessage.line_number_table = &*LineInfo.begin(); 00240 } 00241 } else { 00242 FunctionMessage.source_file_name = 0; 00243 FunctionMessage.line_number_size = 0; 00244 FunctionMessage.line_number_table = 0; 00245 } 00246 00247 Wrapper->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, 00248 &FunctionMessage); 00249 MethodIDs[(void*)Addr] = FunctionMessage.method_id; 00250 } 00251 } 00252 00253 // To support object unload notification, we need to keep a list of 00254 // registered function addresses for each loaded object. We will 00255 // use the MethodIDs map to get the registered ID for each function. 00256 LoadedObjectMap[ObjData] = Functions; 00257 } 00258 00259 void IntelJITEventListener::NotifyFreeingObject(const ObjectImage &Obj) { 00260 // Get the address of the object image for use as a unique identifier 00261 const void* ObjData = Obj.getData().data(); 00262 00263 // Get the object's function list from LoadedObjectMap 00264 ObjectMap::iterator OI = LoadedObjectMap.find(ObjData); 00265 if (OI == LoadedObjectMap.end()) 00266 return; 00267 MethodAddressVector& Functions = OI->second; 00268 00269 // Walk the function list, unregistering each function 00270 for (MethodAddressVector::iterator FI = Functions.begin(), 00271 FE = Functions.end(); 00272 FI != FE; 00273 ++FI) { 00274 void* FnStart = const_cast<void*>(*FI); 00275 MethodIDMap::iterator MI = MethodIDs.find(FnStart); 00276 if (MI != MethodIDs.end()) { 00277 Wrapper->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_UNLOAD_START, 00278 &MI->second); 00279 MethodIDs.erase(MI); 00280 } 00281 } 00282 00283 // Erase the object from LoadedObjectMap 00284 LoadedObjectMap.erase(OI); 00285 } 00286 00287 } // anonymous namespace. 00288 00289 namespace llvm { 00290 JITEventListener *JITEventListener::createIntelJITEventListener() { 00291 return new IntelJITEventListener(new IntelJITEventsWrapper); 00292 } 00293 00294 // for testing 00295 JITEventListener *JITEventListener::createIntelJITEventListener( 00296 IntelJITEventsWrapper* TestImpl) { 00297 return new IntelJITEventListener(TestImpl); 00298 } 00299 00300 } // namespace llvm 00301