diff options
author | Eli Bendersky <eli.bendersky@intel.com> | 2012-03-15 06:49:31 +0000 |
---|---|---|
committer | Eli Bendersky <eli.bendersky@intel.com> | 2012-03-15 06:49:31 +0000 |
commit | f963cd3e02cc01453cb9fd1d4f9e20a1e6f97ba2 (patch) | |
tree | 53a54bcb7adc99f82e370ba987359579e183a694 /unittests/ExecutionEngine/JIT | |
parent | 5a89434236a4d6ad5fa6a570cbf3e717b757a148 (diff) | |
download | external_llvm-f963cd3e02cc01453cb9fd1d4f9e20a1e6f97ba2.zip external_llvm-f963cd3e02cc01453cb9fd1d4f9e20a1e6f97ba2.tar.gz external_llvm-f963cd3e02cc01453cb9fd1d4f9e20a1e6f97ba2.tar.bz2 |
Follow-up to r152620: restore JIT event listener tests to unittest/ExecutionEngine/JIT
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@152780 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'unittests/ExecutionEngine/JIT')
-rw-r--r-- | unittests/ExecutionEngine/JIT/IntelJITEventListenerTest.cpp | 110 | ||||
-rw-r--r-- | unittests/ExecutionEngine/JIT/JITEventListenerTest.cpp | 238 | ||||
-rw-r--r-- | unittests/ExecutionEngine/JIT/JITEventListenerTestCommon.h | 209 | ||||
-rw-r--r-- | unittests/ExecutionEngine/JIT/Makefile | 23 | ||||
-rw-r--r-- | unittests/ExecutionEngine/JIT/OProfileJITEventListenerTest.cpp | 166 |
5 files changed, 746 insertions, 0 deletions
diff --git a/unittests/ExecutionEngine/JIT/IntelJITEventListenerTest.cpp b/unittests/ExecutionEngine/JIT/IntelJITEventListenerTest.cpp new file mode 100644 index 0000000..8ed7a15 --- /dev/null +++ b/unittests/ExecutionEngine/JIT/IntelJITEventListenerTest.cpp @@ -0,0 +1,110 @@ +//===- JITEventListenerTest.cpp - Tests for Intel JITEventListener --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "JITEventListenerTestCommon.h" + +using namespace llvm; + +#include "llvm/ExecutionEngine/IntelJITEventsWrapper.h" + +#include <map> +#include <list> + +namespace { + +// map of function ("method") IDs to source locations +NativeCodeMap ReportedDebugFuncs; + +} // namespace + +/// Mock implementaion of Intel JIT API jitprofiling library +namespace test_jitprofiling { + +int NotifyEvent(iJIT_JVM_EVENT EventType, void *EventSpecificData) { + switch (EventType) { + case iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED: { + EXPECT_TRUE(0 != EventSpecificData); + iJIT_Method_Load* msg = static_cast<iJIT_Method_Load*>(EventSpecificData); + + ReportedDebugFuncs[msg->method_id]; + + for(unsigned int i = 0; i < msg->line_number_size; ++i) { + EXPECT_TRUE(0 != msg->line_number_table); + std::pair<std::string, unsigned int> loc( + std::string(msg->source_file_name), + msg->line_number_table[i].LineNumber); + ReportedDebugFuncs[msg->method_id].push_back(loc); + } + } + break; + case iJVM_EVENT_TYPE_METHOD_UNLOAD_START: { + EXPECT_TRUE(0 != EventSpecificData); + unsigned int UnloadId + = *reinterpret_cast<unsigned int*>(EventSpecificData); + EXPECT_TRUE(1 == ReportedDebugFuncs.erase(UnloadId)); + } + default: + break; + } + return 0; +} + +iJIT_IsProfilingActiveFlags IsProfilingActive(void) { + // for testing, pretend we have an Intel Parallel Amplifier XE 2011 + // instance attached + return iJIT_SAMPLING_ON; +} + +unsigned int GetNewMethodID(void) { + static unsigned int id = 0; + return ++id; +} + +} //namespace test_jitprofiling + +class IntelJITEventListenerTest + : public JITEventListenerTestBase<IntelJITEventsWrapper> { +public: + IntelJITEventListenerTest() + : JITEventListenerTestBase<IntelJITEventsWrapper>( + new IntelJITEventsWrapper(test_jitprofiling::NotifyEvent, 0, + test_jitprofiling::IsProfilingActive, 0, 0, + test_jitprofiling::GetNewMethodID)) + { + EXPECT_TRUE(0 != MockWrapper); + + Listener.reset(JITEventListener::createIntelJITEventListener( + MockWrapper.get())); + EXPECT_TRUE(0 != Listener); + EE->RegisterJITEventListener(Listener.get()); + } +}; + +TEST_F(IntelJITEventListenerTest, NoDebugInfo) { + TestNoDebugInfo(ReportedDebugFuncs); +} + +TEST_F(IntelJITEventListenerTest, SingleLine) { + TestSingleLine(ReportedDebugFuncs); +} + +TEST_F(IntelJITEventListenerTest, MultipleLines) { + TestMultipleLines(ReportedDebugFuncs); +} + +// This testcase is disabled because the Intel JIT API does not support a single +// JITted function with source lines associated with multiple files +/* +TEST_F(IntelJITEventListenerTest, MultipleFiles) { + TestMultipleFiles(ReportedDebugFuncs); +} +*/ + +testing::Environment* const jit_env = + testing::AddGlobalTestEnvironment(new JITEnvironment); diff --git a/unittests/ExecutionEngine/JIT/JITEventListenerTest.cpp b/unittests/ExecutionEngine/JIT/JITEventListenerTest.cpp new file mode 100644 index 0000000..f8d8830 --- /dev/null +++ b/unittests/ExecutionEngine/JIT/JITEventListenerTest.cpp @@ -0,0 +1,238 @@ +//===- JITEventListenerTest.cpp - Unit tests for JITEventListeners --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ExecutionEngine/JITEventListener.h" + +#include "llvm/LLVMContext.h" +#include "llvm/Instructions.h" +#include "llvm/Module.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/CodeGen/MachineCodeInfo.h" +#include "llvm/ExecutionEngine/JIT.h" +#include "llvm/Support/TypeBuilder.h" +#include "llvm/Support/TargetSelect.h" +#include "gtest/gtest.h" +#include <vector> + +using namespace llvm; + +int dummy; + +namespace { + +struct FunctionEmittedEvent { + // Indices are local to the RecordingJITEventListener, since the + // JITEventListener interface makes no guarantees about the order of + // calls between Listeners. + unsigned Index; + const Function *F; + void *Code; + size_t Size; + JITEvent_EmittedFunctionDetails Details; +}; +struct FunctionFreedEvent { + unsigned Index; + void *Code; +}; + +struct RecordingJITEventListener : public JITEventListener { + std::vector<FunctionEmittedEvent> EmittedEvents; + std::vector<FunctionFreedEvent> FreedEvents; + + unsigned NextIndex; + + RecordingJITEventListener() : NextIndex(0) {} + + virtual void NotifyFunctionEmitted(const Function &F, + void *Code, size_t Size, + const EmittedFunctionDetails &Details) { + FunctionEmittedEvent Event = {NextIndex++, &F, Code, Size, Details}; + EmittedEvents.push_back(Event); + } + + virtual void NotifyFreeingMachineCode(void *OldPtr) { + FunctionFreedEvent Event = {NextIndex++, OldPtr}; + FreedEvents.push_back(Event); + } +}; + +class JITEventListenerTest : public testing::Test { + protected: + JITEventListenerTest() + : M(new Module("module", getGlobalContext())), + EE(EngineBuilder(M) + .setEngineKind(EngineKind::JIT) + .create()) { + } + + Module *M; + const OwningPtr<ExecutionEngine> EE; +}; + +Function *buildFunction(Module *M) { + Function *Result = Function::Create( + TypeBuilder<int32_t(int32_t), false>::get(getGlobalContext()), + GlobalValue::ExternalLinkage, "id", M); + Value *Arg = Result->arg_begin(); + BasicBlock *BB = BasicBlock::Create(M->getContext(), "entry", Result); + ReturnInst::Create(M->getContext(), Arg, BB); + return Result; +} + +// Tests that a single JITEventListener follows JIT events accurately. +TEST_F(JITEventListenerTest, Simple) { + RecordingJITEventListener Listener; + EE->RegisterJITEventListener(&Listener); + Function *F1 = buildFunction(M); + Function *F2 = buildFunction(M); + + void *F1_addr = EE->getPointerToFunction(F1); + void *F2_addr = EE->getPointerToFunction(F2); + EE->getPointerToFunction(F1); // Should do nothing. + EE->freeMachineCodeForFunction(F1); + EE->freeMachineCodeForFunction(F2); + + ASSERT_EQ(2U, Listener.EmittedEvents.size()); + ASSERT_EQ(2U, Listener.FreedEvents.size()); + + EXPECT_EQ(0U, Listener.EmittedEvents[0].Index); + EXPECT_EQ(F1, Listener.EmittedEvents[0].F); + EXPECT_EQ(F1_addr, Listener.EmittedEvents[0].Code); + EXPECT_LT(0U, Listener.EmittedEvents[0].Size) + << "We don't know how big the function will be, but it had better" + << " contain some bytes."; + + EXPECT_EQ(1U, Listener.EmittedEvents[1].Index); + EXPECT_EQ(F2, Listener.EmittedEvents[1].F); + EXPECT_EQ(F2_addr, Listener.EmittedEvents[1].Code); + EXPECT_LT(0U, Listener.EmittedEvents[1].Size) + << "We don't know how big the function will be, but it had better" + << " contain some bytes."; + + EXPECT_EQ(2U, Listener.FreedEvents[0].Index); + EXPECT_EQ(F1_addr, Listener.FreedEvents[0].Code); + + EXPECT_EQ(3U, Listener.FreedEvents[1].Index); + EXPECT_EQ(F2_addr, Listener.FreedEvents[1].Code); + + F1->eraseFromParent(); + F2->eraseFromParent(); +} + +// Tests that a single JITEventListener follows JIT events accurately. +TEST_F(JITEventListenerTest, MultipleListenersDontInterfere) { + RecordingJITEventListener Listener1; + RecordingJITEventListener Listener2; + RecordingJITEventListener Listener3; + Function *F1 = buildFunction(M); + Function *F2 = buildFunction(M); + + EE->RegisterJITEventListener(&Listener1); + EE->RegisterJITEventListener(&Listener2); + void *F1_addr = EE->getPointerToFunction(F1); + EE->RegisterJITEventListener(&Listener3); + EE->UnregisterJITEventListener(&Listener1); + void *F2_addr = EE->getPointerToFunction(F2); + EE->UnregisterJITEventListener(&Listener2); + EE->UnregisterJITEventListener(&Listener3); + EE->freeMachineCodeForFunction(F1); + EE->RegisterJITEventListener(&Listener2); + EE->RegisterJITEventListener(&Listener3); + EE->RegisterJITEventListener(&Listener1); + EE->freeMachineCodeForFunction(F2); + EE->UnregisterJITEventListener(&Listener1); + EE->UnregisterJITEventListener(&Listener2); + EE->UnregisterJITEventListener(&Listener3); + + // Listener 1. + ASSERT_EQ(1U, Listener1.EmittedEvents.size()); + ASSERT_EQ(1U, Listener1.FreedEvents.size()); + + EXPECT_EQ(0U, Listener1.EmittedEvents[0].Index); + EXPECT_EQ(F1, Listener1.EmittedEvents[0].F); + EXPECT_EQ(F1_addr, Listener1.EmittedEvents[0].Code); + EXPECT_LT(0U, Listener1.EmittedEvents[0].Size) + << "We don't know how big the function will be, but it had better" + << " contain some bytes."; + + EXPECT_EQ(1U, Listener1.FreedEvents[0].Index); + EXPECT_EQ(F2_addr, Listener1.FreedEvents[0].Code); + + // Listener 2. + ASSERT_EQ(2U, Listener2.EmittedEvents.size()); + ASSERT_EQ(1U, Listener2.FreedEvents.size()); + + EXPECT_EQ(0U, Listener2.EmittedEvents[0].Index); + EXPECT_EQ(F1, Listener2.EmittedEvents[0].F); + EXPECT_EQ(F1_addr, Listener2.EmittedEvents[0].Code); + EXPECT_LT(0U, Listener2.EmittedEvents[0].Size) + << "We don't know how big the function will be, but it had better" + << " contain some bytes."; + + EXPECT_EQ(1U, Listener2.EmittedEvents[1].Index); + EXPECT_EQ(F2, Listener2.EmittedEvents[1].F); + EXPECT_EQ(F2_addr, Listener2.EmittedEvents[1].Code); + EXPECT_LT(0U, Listener2.EmittedEvents[1].Size) + << "We don't know how big the function will be, but it had better" + << " contain some bytes."; + + EXPECT_EQ(2U, Listener2.FreedEvents[0].Index); + EXPECT_EQ(F2_addr, Listener2.FreedEvents[0].Code); + + // Listener 3. + ASSERT_EQ(1U, Listener3.EmittedEvents.size()); + ASSERT_EQ(1U, Listener3.FreedEvents.size()); + + EXPECT_EQ(0U, Listener3.EmittedEvents[0].Index); + EXPECT_EQ(F2, Listener3.EmittedEvents[0].F); + EXPECT_EQ(F2_addr, Listener3.EmittedEvents[0].Code); + EXPECT_LT(0U, Listener3.EmittedEvents[0].Size) + << "We don't know how big the function will be, but it had better" + << " contain some bytes."; + + EXPECT_EQ(1U, Listener3.FreedEvents[0].Index); + EXPECT_EQ(F2_addr, Listener3.FreedEvents[0].Code); + + F1->eraseFromParent(); + F2->eraseFromParent(); +} + +TEST_F(JITEventListenerTest, MatchesMachineCodeInfo) { + RecordingJITEventListener Listener; + MachineCodeInfo MCI; + Function *F = buildFunction(M); + + EE->RegisterJITEventListener(&Listener); + EE->runJITOnFunction(F, &MCI); + void *F_addr = EE->getPointerToFunction(F); + EE->freeMachineCodeForFunction(F); + + ASSERT_EQ(1U, Listener.EmittedEvents.size()); + ASSERT_EQ(1U, Listener.FreedEvents.size()); + + EXPECT_EQ(0U, Listener.EmittedEvents[0].Index); + EXPECT_EQ(F, Listener.EmittedEvents[0].F); + EXPECT_EQ(F_addr, Listener.EmittedEvents[0].Code); + EXPECT_EQ(MCI.address(), Listener.EmittedEvents[0].Code); + EXPECT_EQ(MCI.size(), Listener.EmittedEvents[0].Size); + + EXPECT_EQ(1U, Listener.FreedEvents[0].Index); + EXPECT_EQ(F_addr, Listener.FreedEvents[0].Code); +} + +class JITEnvironment : public testing::Environment { + virtual void SetUp() { + // Required to create a JIT. + InitializeNativeTarget(); + } +}; +testing::Environment* const jit_env = + testing::AddGlobalTestEnvironment(new JITEnvironment); + +} // anonymous namespace diff --git a/unittests/ExecutionEngine/JIT/JITEventListenerTestCommon.h b/unittests/ExecutionEngine/JIT/JITEventListenerTestCommon.h new file mode 100644 index 0000000..53608cb --- /dev/null +++ b/unittests/ExecutionEngine/JIT/JITEventListenerTestCommon.h @@ -0,0 +1,209 @@ +//===- JITEventListenerTestCommon.h - Helper for JITEventListener tests ------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===-------------------------------------------------------------------------------===// + +#ifndef JIT_EVENT_LISTENER_TEST_COMMON_H +#define JIT_EVENT_LISTENER_TEST_COMMON_H + +#include "llvm/Analysis/DIBuilder.h" +#include "llvm/Analysis/DebugInfo.h" +#include "llvm/CodeGen/MachineCodeInfo.h" +#include "llvm/Config/config.h" +#include "llvm/ExecutionEngine/JIT.h" +#include "llvm/ExecutionEngine/JITEventListener.h" +#include "llvm/Instructions.h" +#include "llvm/Module.h" +#include "llvm/Support/IRBuilder.h" +#include "llvm/Support/Dwarf.h" +#include "llvm/Support/TypeBuilder.h" +#include "llvm/Support/TargetSelect.h" + +#include "gtest/gtest.h" + +#include <vector> +#include <string> +#include <utility> + +typedef std::vector<std::pair<std::string, unsigned int> > SourceLocations; +typedef std::map<uint64_t, SourceLocations> NativeCodeMap; + +class JITEnvironment : public testing::Environment { + virtual void SetUp() { + // Required to create a JIT. + llvm::InitializeNativeTarget(); + } +}; + +inline unsigned int getLine() { + return 12; +} + +inline unsigned int getCol() { + return 0; +} + +inline const char* getFilename() { + return "mock_source_file.cpp"; +} + +// Test fixture shared by tests for listener implementations +template<typename WrapperT> +class JITEventListenerTestBase : public testing::Test { +protected: + llvm::OwningPtr<WrapperT> MockWrapper; + llvm::OwningPtr<llvm::JITEventListener> Listener; + +public: + llvm::Module* M; + llvm::MDNode* Scope; + llvm::ExecutionEngine* EE; + llvm::DIBuilder* DebugBuilder; + llvm::IRBuilder<> Builder; + + JITEventListenerTestBase(WrapperT* w) + : MockWrapper(w) + , M(new llvm::Module("module", llvm::getGlobalContext())) + , EE(llvm::EngineBuilder(M) + .setEngineKind(llvm::EngineKind::JIT) + .setOptLevel(llvm::CodeGenOpt::None) + .create()) + , DebugBuilder(new llvm::DIBuilder(*M)) + , Builder(llvm::getGlobalContext()) + { + DebugBuilder->createCompileUnit(llvm::dwarf::DW_LANG_C_plus_plus, + "JIT", + "JIT", + "JIT", + true, + "", + 1); + + Scope = DebugBuilder->createFile(getFilename(), "."); + } + + llvm::Function *buildFunction(const SourceLocations& DebugLocations) { + using namespace llvm; + + LLVMContext& GlobalContext = getGlobalContext(); + + SourceLocations::const_iterator CurrentDebugLocation + = DebugLocations.begin(); + + if (CurrentDebugLocation != DebugLocations.end()) { + DebugLoc DebugLocation = DebugLoc::get(getLine(), getCol(), + DebugBuilder->createFile(CurrentDebugLocation->first, ".")); + Builder.SetCurrentDebugLocation(DebugLocation); + CurrentDebugLocation++; + } + + Function *Result = Function::Create( + TypeBuilder<int32_t(int32_t), false>::get(GlobalContext), + GlobalValue::ExternalLinkage, "id", M); + Value *Arg = Result->arg_begin(); + BasicBlock *BB = BasicBlock::Create(M->getContext(), "entry", Result); + Builder.SetInsertPoint(BB); + Value* one = ConstantInt::get(GlobalContext, APInt(32, 1)); + for(; CurrentDebugLocation != DebugLocations.end(); + ++CurrentDebugLocation) { + Arg = Builder.CreateMul(Arg, Builder.CreateAdd(Arg, one)); + Builder.SetCurrentDebugLocation( + DebugLoc::get(CurrentDebugLocation->second, 0, + DebugBuilder->createFile(CurrentDebugLocation->first, "."))); + } + Builder.CreateRet(Arg); + return Result; + } + + void TestNoDebugInfo(NativeCodeMap& ReportedDebugFuncs) { + SourceLocations DebugLocations; + llvm::Function* f = buildFunction(DebugLocations); + EXPECT_TRUE(0 != f); + + //Cause JITting and callbacks to our listener + EXPECT_TRUE(0 != EE->getPointerToFunction(f)); + EXPECT_TRUE(1 == ReportedDebugFuncs.size()); + + EE->freeMachineCodeForFunction(f); + EXPECT_TRUE(ReportedDebugFuncs.size() == 0); + } + + void TestSingleLine(NativeCodeMap& ReportedDebugFuncs) { + SourceLocations DebugLocations; + DebugLocations.push_back(std::make_pair(std::string(getFilename()), + getLine())); + llvm::Function* f = buildFunction(DebugLocations); + EXPECT_TRUE(0 != f); + + EXPECT_TRUE(0 != EE->getPointerToFunction(f)); + EXPECT_TRUE(1 == ReportedDebugFuncs.size()); + EXPECT_STREQ(ReportedDebugFuncs.begin()->second.begin()->first.c_str(), + getFilename()); + EXPECT_EQ(ReportedDebugFuncs.begin()->second.begin()->second, getLine()); + + EE->freeMachineCodeForFunction(f); + EXPECT_TRUE(ReportedDebugFuncs.size() == 0); + } + + void TestMultipleLines(NativeCodeMap& ReportedDebugFuncs) { + using namespace std; + + SourceLocations DebugLocations; + unsigned int c = 5; + for(unsigned int i = 0; i < c; ++i) { + DebugLocations.push_back(make_pair(string(getFilename()), getLine() + i)); + } + + llvm::Function* f = buildFunction(DebugLocations); + EXPECT_TRUE(0 != f); + + EXPECT_TRUE(0 != EE->getPointerToFunction(f)); + EXPECT_TRUE(1 == ReportedDebugFuncs.size()); + SourceLocations& FunctionInfo = ReportedDebugFuncs.begin()->second; + EXPECT_EQ(c, FunctionInfo.size()); + + int VerifyCount = 0; + for(SourceLocations::iterator i = FunctionInfo.begin(); + i != FunctionInfo.end(); + ++i) { + EXPECT_STREQ(i->first.c_str(), getFilename()); + EXPECT_EQ(i->second, getLine() + VerifyCount); + VerifyCount++; + } + + EE->freeMachineCodeForFunction(f); + EXPECT_TRUE(ReportedDebugFuncs.size() == 0); + } + + void TestMultipleFiles(NativeCodeMap& ReportedDebugFuncs) { + + std::string secondFilename("another_file.cpp"); + + SourceLocations DebugLocations; + DebugLocations.push_back(std::make_pair(std::string(getFilename()), + getLine())); + DebugLocations.push_back(std::make_pair(secondFilename, getLine())); + llvm::Function* f = buildFunction(DebugLocations); + EXPECT_TRUE(0 != f); + + EXPECT_TRUE(0 != EE->getPointerToFunction(f)); + EXPECT_TRUE(1 == ReportedDebugFuncs.size()); + SourceLocations& FunctionInfo = ReportedDebugFuncs.begin()->second; + EXPECT_TRUE(2 == FunctionInfo.size()); + + EXPECT_STREQ(FunctionInfo.at(0).first.c_str(), getFilename()); + EXPECT_STREQ(FunctionInfo.at(1).first.c_str(), secondFilename.c_str()); + + EXPECT_EQ(FunctionInfo.at(0).second, getLine()); + EXPECT_EQ(FunctionInfo.at(1).second, getLine()); + + EE->freeMachineCodeForFunction(f); + EXPECT_TRUE(ReportedDebugFuncs.size() == 0); + } +}; + +#endif //JIT_EVENT_LISTENER_TEST_COMMON_H diff --git a/unittests/ExecutionEngine/JIT/Makefile b/unittests/ExecutionEngine/JIT/Makefile index f5abe75..b429033 100644 --- a/unittests/ExecutionEngine/JIT/Makefile +++ b/unittests/ExecutionEngine/JIT/Makefile @@ -12,6 +12,29 @@ TESTNAME = JIT LINK_COMPONENTS := asmparser bitreader bitwriter core jit native support include $(LEVEL)/Makefile.config + +SOURCES := JITEventListenerTest.cpp + +ifeq ($(USE_INTEL_JITEVENTS), 1) + # Build the Intel JIT Events interface tests + SOURCES += IntelJITEventListenerTest.cpp + + # Add the Intel JIT Events include directory + CPPFLAGS += -I$(INTEL_JITEVENTS_INCDIR) + + # Link against the LLVM Intel JIT Evens interface library + LINK_COMPONENTS += inteljitevents +endif + +ifeq ($(USE_OPROFILE), 1) + # Build the OProfile JIT interface tests + SOURCES += OProfileJITEventListenerTest.cpp + + # Link against the LLVM oprofile interface library + LINK_COMPONENTS += oprofilejit +endif + + include $(LLVM_SRC_ROOT)/unittests/Makefile.unittest # Permit these tests to use the JIT's symbolic lookup. diff --git a/unittests/ExecutionEngine/JIT/OProfileJITEventListenerTest.cpp b/unittests/ExecutionEngine/JIT/OProfileJITEventListenerTest.cpp new file mode 100644 index 0000000..9b0ee60 --- /dev/null +++ b/unittests/ExecutionEngine/JIT/OProfileJITEventListenerTest.cpp @@ -0,0 +1,166 @@ +//===- OProfileJITEventListenerTest.cpp - Unit tests for OProfileJITEventsListener --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===--------------------------------------------------------------------------------------===// + +#include "llvm/ExecutionEngine/JITEventListener.h" +#include "llvm/ExecutionEngine/OProfileWrapper.h" +#include "JITEventListenerTestCommon.h" + +#include <map> +#include <list> + +using namespace llvm; + +namespace { + +struct OprofileNativeFunction { + const char* Name; + uint64_t Addr; + const void* CodePtr; + unsigned int CodeSize; + + OprofileNativeFunction(const char* name, + uint64_t addr, + const void* code, + unsigned int size) + : Name(name) + , Addr(addr) + , CodePtr(code) + , CodeSize(size) { + } +}; + +typedef std::list<OprofileNativeFunction> NativeFunctionList; +typedef std::list<debug_line_info> NativeDebugList; +NativeFunctionList NativeFunctions; + +NativeCodeMap ReportedDebugFuncs; + +} // namespace + +/// Mock implementaion of opagent library +namespace test_opagent { + +op_agent_t globalAgent = reinterpret_cast<op_agent_t>(42); + +op_agent_t open_agent() +{ + // return non-null op_agent_t + return globalAgent; +} + +int close_agent(op_agent_t agent) +{ + EXPECT_EQ(globalAgent, agent); + return 0; +} + +int write_native_code(op_agent_t agent, + const char* name, + uint64_t addr, + void const* code, + unsigned int size) +{ + EXPECT_EQ(globalAgent, agent); + OprofileNativeFunction func(name, addr, code, size); + NativeFunctions.push_back(func); + + // Verify no other registration has take place for the same address + EXPECT_TRUE(ReportedDebugFuncs.find(addr) == ReportedDebugFuncs.end()); + + ReportedDebugFuncs[addr]; + return 0; +} + +int write_debug_line_info(op_agent_t agent, + void const* code, + size_t num_entries, + struct debug_line_info const* info) +{ + EXPECT_EQ(globalAgent, agent); + + //verify code has been loaded first + uint64_t addr = reinterpret_cast<uint64_t>(code); + NativeCodeMap::iterator i = ReportedDebugFuncs.find(addr); + EXPECT_TRUE(i != ReportedDebugFuncs.end()); + + NativeDebugList NativeInfo(info, info + num_entries); + + SourceLocations locs; + for(NativeDebugList::iterator i = NativeInfo.begin(); + i != NativeInfo.end(); + ++i) { + locs.push_back(std::make_pair(std::string(i->filename), i->lineno)); + } + ReportedDebugFuncs[addr] = locs; + + return 0; +} + +int unload_native_code(op_agent_t agent, uint64_t addr) { + EXPECT_EQ(globalAgent, agent); + + //verify that something for the given JIT addr has been loaded first + NativeCodeMap::iterator i = ReportedDebugFuncs.find(addr); + EXPECT_TRUE(i != ReportedDebugFuncs.end()); + ReportedDebugFuncs.erase(i); + return 0; +} + +int version() { + return 1; +} + +bool is_oprofile_running() { + return true; +} + +} //namespace test_opagent + +class OProfileJITEventListenerTest +: public JITEventListenerTestBase<OProfileWrapper> +{ +public: + OProfileJITEventListenerTest() + : JITEventListenerTestBase<OProfileWrapper>( + new OProfileWrapper(test_opagent::open_agent, + test_opagent::close_agent, + test_opagent::write_native_code, + test_opagent::write_debug_line_info, + test_opagent::unload_native_code, + test_opagent::version, + test_opagent::version, + test_opagent::is_oprofile_running)) + { + EXPECT_TRUE(0 != MockWrapper); + + Listener.reset(JITEventListener::createOProfileJITEventListener( + MockWrapper.get())); + EXPECT_TRUE(0 != Listener); + EE->RegisterJITEventListener(Listener.get()); + } +}; + +TEST_F(OProfileJITEventListenerTest, NoDebugInfo) { + TestNoDebugInfo(ReportedDebugFuncs); +} + +TEST_F(OProfileJITEventListenerTest, SingleLine) { + TestSingleLine(ReportedDebugFuncs); +} + +TEST_F(OProfileJITEventListenerTest, MultipleLines) { + TestMultipleLines(ReportedDebugFuncs); +} + +TEST_F(OProfileJITEventListenerTest, MultipleFiles) { + TestMultipleFiles(ReportedDebugFuncs); +} + +testing::Environment* const jit_env = + testing::AddGlobalTestEnvironment(new JITEnvironment); |