1234285Sdim//===-- IntelJITEventListener.cpp - Tell Intel profiler about JITed 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 to tell Intel(R) VTune(TM) 11234285Sdim// Amplifier XE 2011 about JITted functions. 12234285Sdim// 13234285Sdim//===----------------------------------------------------------------------===// 14234285Sdim 15234285Sdim#include "llvm/Config/config.h" 16234285Sdim#include "llvm/ExecutionEngine/JITEventListener.h" 17234285Sdim 18234285Sdim#define DEBUG_TYPE "amplifier-jit-event-listener" 19239462Sdim#include "llvm/DebugInfo.h" 20249423Sdim#include "llvm/IR/Function.h" 21249423Sdim#include "llvm/IR/Metadata.h" 22234285Sdim#include "llvm/ADT/DenseMap.h" 23234285Sdim#include "llvm/ADT/OwningPtr.h" 24234285Sdim#include "llvm/CodeGen/MachineFunction.h" 25249423Sdim#include "llvm/DebugInfo/DIContext.h" 26249423Sdim#include "llvm/ExecutionEngine/ObjectImage.h" 27249423Sdim#include "llvm/Object/ObjectFile.h" 28234285Sdim#include "llvm/Support/Debug.h" 29234285Sdim#include "llvm/Support/raw_ostream.h" 30234285Sdim#include "llvm/Support/Errno.h" 31234285Sdim#include "llvm/Support/ValueHandle.h" 32234285Sdim#include "EventListenerCommon.h" 33243830Sdim#include "IntelJITEventsWrapper.h" 34234285Sdim 35234285Sdimusing namespace llvm; 36234285Sdimusing namespace llvm::jitprofiling; 37234285Sdim 38234285Sdimnamespace { 39234285Sdim 40234285Sdimclass IntelJITEventListener : public JITEventListener { 41234285Sdim typedef DenseMap<void*, unsigned int> MethodIDMap; 42234285Sdim 43243830Sdim OwningPtr<IntelJITEventsWrapper> Wrapper; 44234285Sdim MethodIDMap MethodIDs; 45234285Sdim FilenameCache Filenames; 46234285Sdim 47249423Sdim typedef SmallVector<const void *, 64> MethodAddressVector; 48249423Sdim typedef DenseMap<const void *, MethodAddressVector> ObjectMap; 49249423Sdim 50249423Sdim ObjectMap LoadedObjectMap; 51249423Sdim 52234285Sdimpublic: 53243830Sdim IntelJITEventListener(IntelJITEventsWrapper* libraryWrapper) { 54243830Sdim Wrapper.reset(libraryWrapper); 55234285Sdim } 56234285Sdim 57234285Sdim ~IntelJITEventListener() { 58234285Sdim } 59234285Sdim 60234285Sdim virtual void NotifyFunctionEmitted(const Function &F, 61234285Sdim void *FnStart, size_t FnSize, 62234285Sdim const EmittedFunctionDetails &Details); 63234285Sdim 64234285Sdim virtual void NotifyFreeingMachineCode(void *OldPtr); 65243830Sdim 66243830Sdim virtual void NotifyObjectEmitted(const ObjectImage &Obj); 67243830Sdim 68243830Sdim virtual void NotifyFreeingObject(const ObjectImage &Obj); 69234285Sdim}; 70234285Sdim 71234285Sdimstatic LineNumberInfo LineStartToIntelJITFormat( 72234285Sdim uintptr_t StartAddress, 73234285Sdim uintptr_t Address, 74234285Sdim DebugLoc Loc) { 75234285Sdim LineNumberInfo Result; 76234285Sdim 77234285Sdim Result.Offset = Address - StartAddress; 78234285Sdim Result.LineNumber = Loc.getLine(); 79234285Sdim 80234285Sdim return Result; 81234285Sdim} 82234285Sdim 83249423Sdimstatic LineNumberInfo DILineInfoToIntelJITFormat(uintptr_t StartAddress, 84249423Sdim uintptr_t Address, 85249423Sdim DILineInfo Line) { 86249423Sdim LineNumberInfo Result; 87249423Sdim 88249423Sdim Result.Offset = Address - StartAddress; 89249423Sdim Result.LineNumber = Line.getLine(); 90249423Sdim 91249423Sdim return Result; 92249423Sdim} 93249423Sdim 94234285Sdimstatic iJIT_Method_Load FunctionDescToIntelJITFormat( 95234285Sdim IntelJITEventsWrapper& Wrapper, 96234285Sdim const char* FnName, 97234285Sdim uintptr_t FnStart, 98234285Sdim size_t FnSize) { 99234285Sdim iJIT_Method_Load Result; 100234285Sdim memset(&Result, 0, sizeof(iJIT_Method_Load)); 101234285Sdim 102234285Sdim Result.method_id = Wrapper.iJIT_GetNewMethodID(); 103234285Sdim Result.method_name = const_cast<char*>(FnName); 104234285Sdim Result.method_load_address = reinterpret_cast<void*>(FnStart); 105234285Sdim Result.method_size = FnSize; 106234285Sdim 107234285Sdim Result.class_id = 0; 108234285Sdim Result.class_file_name = NULL; 109234285Sdim Result.user_data = NULL; 110234285Sdim Result.user_data_size = 0; 111234285Sdim Result.env = iJDE_JittingAPI; 112234285Sdim 113234285Sdim return Result; 114234285Sdim} 115234285Sdim 116234285Sdim// Adds the just-emitted function to the symbol table. 117234285Sdimvoid IntelJITEventListener::NotifyFunctionEmitted( 118234285Sdim const Function &F, void *FnStart, size_t FnSize, 119234285Sdim const EmittedFunctionDetails &Details) { 120243830Sdim iJIT_Method_Load FunctionMessage = FunctionDescToIntelJITFormat(*Wrapper, 121234285Sdim F.getName().data(), 122234285Sdim reinterpret_cast<uint64_t>(FnStart), 123234285Sdim FnSize); 124234285Sdim 125234285Sdim std::vector<LineNumberInfo> LineInfo; 126234285Sdim 127234285Sdim if (!Details.LineStarts.empty()) { 128234285Sdim // Now convert the line number information from the address/DebugLoc 129234285Sdim // format in Details to the offset/lineno in Intel JIT API format. 130234285Sdim 131234285Sdim LineInfo.reserve(Details.LineStarts.size() + 1); 132234285Sdim 133234285Sdim DebugLoc FirstLoc = Details.LineStarts[0].Loc; 134234285Sdim assert(!FirstLoc.isUnknown() 135234285Sdim && "LineStarts should not contain unknown DebugLocs"); 136234285Sdim 137234285Sdim MDNode *FirstLocScope = FirstLoc.getScope(F.getContext()); 138234285Sdim DISubprogram FunctionDI = getDISubprogram(FirstLocScope); 139234285Sdim if (FunctionDI.Verify()) { 140234285Sdim FunctionMessage.source_file_name = const_cast<char*>( 141234285Sdim Filenames.getFullPath(FirstLocScope)); 142234285Sdim 143234285Sdim LineNumberInfo FirstLine; 144234285Sdim FirstLine.Offset = 0; 145234285Sdim FirstLine.LineNumber = FunctionDI.getLineNumber(); 146234285Sdim LineInfo.push_back(FirstLine); 147234285Sdim } 148234285Sdim 149234285Sdim for (std::vector<EmittedFunctionDetails::LineStart>::const_iterator I = 150234285Sdim Details.LineStarts.begin(), E = Details.LineStarts.end(); 151234285Sdim I != E; ++I) { 152234285Sdim // This implementation ignores the DebugLoc filename because the Intel 153234285Sdim // JIT API does not support multiple source files associated with a single 154234285Sdim // JIT function 155234285Sdim LineInfo.push_back(LineStartToIntelJITFormat( 156234285Sdim reinterpret_cast<uintptr_t>(FnStart), 157234285Sdim I->Address, 158234285Sdim I->Loc)); 159234285Sdim 160234285Sdim // If we have no file name yet for the function, use the filename from 161234285Sdim // the first instruction that has one 162234285Sdim if (FunctionMessage.source_file_name == 0) { 163234285Sdim MDNode *scope = I->Loc.getScope( 164239462Sdim Details.MF->getFunction()->getContext()); 165234285Sdim FunctionMessage.source_file_name = const_cast<char*>( 166234285Sdim Filenames.getFullPath(scope)); 167234285Sdim } 168234285Sdim } 169234285Sdim 170234285Sdim FunctionMessage.line_number_size = LineInfo.size(); 171234285Sdim FunctionMessage.line_number_table = &*LineInfo.begin(); 172234285Sdim } else { 173234285Sdim FunctionMessage.line_number_size = 0; 174234285Sdim FunctionMessage.line_number_table = 0; 175234285Sdim } 176234285Sdim 177243830Sdim Wrapper->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, 178243830Sdim &FunctionMessage); 179234285Sdim MethodIDs[FnStart] = FunctionMessage.method_id; 180234285Sdim} 181234285Sdim 182234285Sdimvoid IntelJITEventListener::NotifyFreeingMachineCode(void *FnStart) { 183234285Sdim MethodIDMap::iterator I = MethodIDs.find(FnStart); 184234285Sdim if (I != MethodIDs.end()) { 185243830Sdim Wrapper->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_UNLOAD_START, &I->second); 186234285Sdim MethodIDs.erase(I); 187234285Sdim } 188234285Sdim} 189234285Sdim 190243830Sdimvoid IntelJITEventListener::NotifyObjectEmitted(const ObjectImage &Obj) { 191249423Sdim // Get the address of the object image for use as a unique identifier 192249423Sdim const void* ObjData = Obj.getData().data(); 193249423Sdim DIContext* Context = DIContext::getDWARFContext(Obj.getObjectFile()); 194249423Sdim MethodAddressVector Functions; 195249423Sdim 196249423Sdim // Use symbol info to iterate functions in the object. 197249423Sdim error_code ec; 198249423Sdim for (object::symbol_iterator I = Obj.begin_symbols(), 199249423Sdim E = Obj.end_symbols(); 200249423Sdim I != E && !ec; 201249423Sdim I.increment(ec)) { 202249423Sdim std::vector<LineNumberInfo> LineInfo; 203249423Sdim std::string SourceFileName; 204249423Sdim 205249423Sdim object::SymbolRef::Type SymType; 206249423Sdim if (I->getType(SymType)) continue; 207249423Sdim if (SymType == object::SymbolRef::ST_Function) { 208249423Sdim StringRef Name; 209249423Sdim uint64_t Addr; 210249423Sdim uint64_t Size; 211249423Sdim if (I->getName(Name)) continue; 212249423Sdim if (I->getAddress(Addr)) continue; 213249423Sdim if (I->getSize(Size)) continue; 214249423Sdim 215249423Sdim // Record this address in a local vector 216249423Sdim Functions.push_back((void*)Addr); 217249423Sdim 218249423Sdim // Build the function loaded notification message 219249423Sdim iJIT_Method_Load FunctionMessage = FunctionDescToIntelJITFormat(*Wrapper, 220249423Sdim Name.data(), 221249423Sdim Addr, 222249423Sdim Size); 223249423Sdim if (Context) { 224249423Sdim DILineInfoTable Lines = Context->getLineInfoForAddressRange(Addr, Size); 225249423Sdim DILineInfoTable::iterator Begin = Lines.begin(); 226249423Sdim DILineInfoTable::iterator End = Lines.end(); 227249423Sdim for (DILineInfoTable::iterator It = Begin; It != End; ++It) { 228249423Sdim LineInfo.push_back(DILineInfoToIntelJITFormat((uintptr_t)Addr, 229249423Sdim It->first, 230249423Sdim It->second)); 231249423Sdim } 232249423Sdim if (LineInfo.size() == 0) { 233249423Sdim FunctionMessage.source_file_name = 0; 234249423Sdim FunctionMessage.line_number_size = 0; 235249423Sdim FunctionMessage.line_number_table = 0; 236249423Sdim } else { 237249423Sdim SourceFileName = Lines.front().second.getFileName(); 238249423Sdim FunctionMessage.source_file_name = (char *)SourceFileName.c_str(); 239249423Sdim FunctionMessage.line_number_size = LineInfo.size(); 240249423Sdim FunctionMessage.line_number_table = &*LineInfo.begin(); 241249423Sdim } 242249423Sdim } else { 243249423Sdim FunctionMessage.source_file_name = 0; 244249423Sdim FunctionMessage.line_number_size = 0; 245249423Sdim FunctionMessage.line_number_table = 0; 246249423Sdim } 247249423Sdim 248249423Sdim Wrapper->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, 249249423Sdim &FunctionMessage); 250249423Sdim MethodIDs[(void*)Addr] = FunctionMessage.method_id; 251249423Sdim } 252249423Sdim } 253249423Sdim 254249423Sdim // To support object unload notification, we need to keep a list of 255249423Sdim // registered function addresses for each loaded object. We will 256249423Sdim // use the MethodIDs map to get the registered ID for each function. 257249423Sdim LoadedObjectMap[ObjData] = Functions; 258243830Sdim} 259243830Sdim 260243830Sdimvoid IntelJITEventListener::NotifyFreeingObject(const ObjectImage &Obj) { 261249423Sdim // Get the address of the object image for use as a unique identifier 262249423Sdim const void* ObjData = Obj.getData().data(); 263249423Sdim 264249423Sdim // Get the object's function list from LoadedObjectMap 265249423Sdim ObjectMap::iterator OI = LoadedObjectMap.find(ObjData); 266249423Sdim if (OI == LoadedObjectMap.end()) 267249423Sdim return; 268249423Sdim MethodAddressVector& Functions = OI->second; 269249423Sdim 270249423Sdim // Walk the function list, unregistering each function 271249423Sdim for (MethodAddressVector::iterator FI = Functions.begin(), 272249423Sdim FE = Functions.end(); 273249423Sdim FI != FE; 274249423Sdim ++FI) { 275249423Sdim void* FnStart = const_cast<void*>(*FI); 276249423Sdim MethodIDMap::iterator MI = MethodIDs.find(FnStart); 277249423Sdim if (MI != MethodIDs.end()) { 278249423Sdim Wrapper->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_UNLOAD_START, 279249423Sdim &MI->second); 280249423Sdim MethodIDs.erase(MI); 281249423Sdim } 282249423Sdim } 283249423Sdim 284249423Sdim // Erase the object from LoadedObjectMap 285249423Sdim LoadedObjectMap.erase(OI); 286243830Sdim} 287243830Sdim 288234285Sdim} // anonymous namespace. 289234285Sdim 290234285Sdimnamespace llvm { 291234285SdimJITEventListener *JITEventListener::createIntelJITEventListener() { 292243830Sdim return new IntelJITEventListener(new IntelJITEventsWrapper); 293234285Sdim} 294234285Sdim 295234285Sdim// for testing 296234285SdimJITEventListener *JITEventListener::createIntelJITEventListener( 297234285Sdim IntelJITEventsWrapper* TestImpl) { 298243830Sdim return new IntelJITEventListener(TestImpl); 299234285Sdim} 300234285Sdim 301234285Sdim} // namespace llvm 302234285Sdim 303