diff options
author | Jeffrey Yasskin <jyasskin@google.com> | 2009-06-25 02:04:04 +0000 |
---|---|---|
committer | Jeffrey Yasskin <jyasskin@google.com> | 2009-06-25 02:04:04 +0000 |
commit | f8d5534ce95fbffa60c30da5748ac2db2c757077 (patch) | |
tree | d0a7b2a265916b1e0e36ef6423b56749d3429c9a /unittests/ExecutionEngine | |
parent | 10e82e3ff5f86e6c5a3a4ffc94b0104a28ea2cbc (diff) | |
download | external_llvm-f8d5534ce95fbffa60c30da5748ac2db2c757077.zip external_llvm-f8d5534ce95fbffa60c30da5748ac2db2c757077.tar.gz external_llvm-f8d5534ce95fbffa60c30da5748ac2db2c757077.tar.bz2 |
Add a JITEventListener interface that gets called back when a new function is
emitted or the machine code for a function is freed. Chris mentioned that we
may also want a notification when a stub is emitted, but that'll be a future
change. I intend to use this to tell oprofile where functions are emitted and
what lines correspond to what addresses.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@74157 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'unittests/ExecutionEngine')
-rw-r--r-- | unittests/ExecutionEngine/JIT/JITEventListenerTest.cpp | 241 | ||||
-rw-r--r-- | unittests/ExecutionEngine/JIT/Makefile | 15 | ||||
-rw-r--r-- | unittests/ExecutionEngine/Makefile | 19 |
3 files changed, 275 insertions, 0 deletions
diff --git a/unittests/ExecutionEngine/JIT/JITEventListenerTest.cpp b/unittests/ExecutionEngine/JIT/JITEventListenerTest.cpp new file mode 100644 index 0000000..3c9beeb --- /dev/null +++ b/unittests/ExecutionEngine/JIT/JITEventListenerTest.cpp @@ -0,0 +1,241 @@ +//===- 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/Instructions.h" +#include "llvm/Module.h" +#include "llvm/ModuleProvider.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/CodeGen/MachineCodeInfo.h" +#include "llvm/ExecutionEngine/JIT.h" +#include "llvm/Support/TypeBuilder.h" +#include "llvm/Target/TargetSelect.h" +#include "gtest/gtest.h" +#include <vector> + +using namespace llvm; + +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; + const Function *F; + void *Code; +}; + +struct RecordingJITEventListener : public JITEventListener { + std::vector<FunctionEmittedEvent> EmittedEvents; + std::vector<FunctionFreedEvent> FreedEvents; + + int 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(const Function &F, void *OldPtr) { + FunctionFreedEvent Event = {NextIndex++, &F, OldPtr}; + FreedEvents.push_back(Event); + } +}; + +class JITEventListenerTest : public testing::Test { + protected: + JITEventListenerTest() + : M(new Module("module")), + EE(ExecutionEngine::createJIT(new ExistingModuleProvider(M))) { + } + + Module *M; + const OwningPtr<ExecutionEngine> EE; +}; + +Function *buildFunction(Module *M) { + Function *Result = Function::Create( + TypeBuilder<int32_t(int32_t), false>::get(), + GlobalValue::ExternalLinkage, "id", M); + Value *Arg = Result->arg_begin(); + BasicBlock *BB = BasicBlock::Create("entry", Result); + ReturnInst::Create(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, Listener.FreedEvents[0].F); + EXPECT_EQ(F1_addr, Listener.FreedEvents[0].Code); + + EXPECT_EQ(3U, Listener.FreedEvents[1].Index); + EXPECT_EQ(F2, Listener.FreedEvents[1].F); + 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, Listener1.FreedEvents[0].F); + 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, Listener2.FreedEvents[0].F); + 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, Listener3.FreedEvents[0].F); + 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, Listener.FreedEvents[0].F); + EXPECT_EQ(F_addr, Listener.FreedEvents[0].Code); +} + +class JITEnvironment : public testing::Environment { + virtual void SetUp() { + // Required for ExecutionEngine::createJIT to create a JIT. + InitializeNativeTarget(); + } +}; +testing::Environment* const jit_env = + testing::AddGlobalTestEnvironment(new JITEnvironment); + +} // anonymous namespace diff --git a/unittests/ExecutionEngine/JIT/Makefile b/unittests/ExecutionEngine/JIT/Makefile new file mode 100644 index 0000000..0069c76 --- /dev/null +++ b/unittests/ExecutionEngine/JIT/Makefile @@ -0,0 +1,15 @@ +##===- unittests/ExecutionEngine/JIT/Makefile --------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../../.. +TESTNAME = JIT +LINK_COMPONENTS := core support jit native + +include $(LEVEL)/Makefile.config +include $(LLVM_SRC_ROOT)/unittests/Makefile.unittest diff --git a/unittests/ExecutionEngine/Makefile b/unittests/ExecutionEngine/Makefile new file mode 100644 index 0000000..e837a7d --- /dev/null +++ b/unittests/ExecutionEngine/Makefile @@ -0,0 +1,19 @@ +##===- unittests/ExecutionEngine/Makefile ------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../.. + +include $(LEVEL)/Makefile.config + +PARALLEL_DIRS = JIT + +include $(LEVEL)/Makefile.common + +clean:: + $(Verb) $(RM) -f *Tests |