[LLVMdev] JITMemoryManager

Frank Henigman fjhenigman at google.com
Tue Oct 1 10:44:43 PDT 2013


Mesa (http://www.mesa3d.org/) uses LLVM to compile shaders.  These are
typically small bits of code (~10KB) and one application can use many
of them.  Mesa creates an ExecutionEngine with a default JIT memory
manager for each shader it compiles, and keeps the engine around as
long as the shader code is needed.  This results in memory waste of
~1MB for each shader.  Half the overhead is in the memory manager
which allocates 512KB even if only a few KB is used, and half is in
the engine, which we can't delete because doing so destroys the memory
manager and the code within it.
A couple solutions:
1) Get a copy of the code then delete the engine.  This might be
doable with MCJIT, but seemingly not with JIT which Mesa wants to use.
2) A new memory manager with less overhead and which also doesn't
delete the code when killed by the engine.
I've got solution 2 working, but LLVM could make it easier.  Deriving
from JITMemoryManager seems complicated - there are a lot of methods
to implement.  Deriving from DefaultJITMemoryManager is not possible
because it's in an anonymous namespace.  So I made a manager that
delegates everything to a shared default memory manager.  This
eliminates overhead by packing everything into one shared manager, and
when a delegating manager gets killed the shared manager persists, so
it's safe to delete the engines.
Below is a generic delegating memory manager.  Using this I only
needed to override a couple methods.  Maybe it could be useful to
others.  See the thread starting with
http://lists.cs.uiuc.edu/pipermail/llvmdev/2013-March/060186.html.
Note how many ifdefs were needed to work with all versions from 3.1 to
now.  If this were added to the LLVM project it could be maintained in
one place with no ifdefs.  If the LLVM maintainers don't want it, I
also have a patch to allow subclassing DefaultJITMemory manager.
Would that be more agreeable?  Thanks.

class DelegatingJITMemoryManager : public llvm::JITMemoryManager {

   protected:
      virtual llvm::JITMemoryManager *mgr() const = 0;

   public:
      /*
       * From JITMemoryManager
       */
      virtual void setMemoryWritable() {
         return mgr()->setMemoryWritable();
      }
      virtual void setMemoryExecutable() {
         return mgr()->setMemoryExecutable();
      }
      virtual void setPoisonMemory(bool poison) {
         return mgr()->setPoisonMemory(poison);
      }
      virtual void AllocateGOT() {
         mgr()->AllocateGOT();
         /*
          * isManagingGOT() is not virtual in base class so we can't delegate.
          * Instead we mirror the value of HasGOT in our instance.
          */
         HasGOT = mgr()->isManagingGOT();
      }
      virtual uint8_t *getGOTBase() const {
         return mgr()->getGOTBase();
      }
      virtual uint8_t *startFunctionBody(const llvm::Function *F,
                                         uintptr_t &ActualSize) {
         return mgr()->startFunctionBody(F, ActualSize);
      }
      virtual uint8_t *allocateStub(const llvm::GlobalValue *F,
                                    unsigned StubSize,
                                    unsigned Alignment) {
         return mgr()->allocateStub(F, StubSize, Alignment);
      }
      virtual void endFunctionBody(const llvm::Function *F,
                                   uint8_t *FunctionStart,
                                   uint8_t *FunctionEnd) {
         return mgr()->endFunctionBody(F, FunctionStart, FunctionEnd);
      }
      virtual uint8_t *allocateSpace(intptr_t Size, unsigned Alignment) {
         return mgr()->allocateSpace(Size, Alignment);
      }
      virtual uint8_t *allocateGlobal(uintptr_t Size, unsigned Alignment) {
         return mgr()->allocateGlobal(Size, Alignment);
      }
      virtual void deallocateFunctionBody(void *Body) {
         return mgr()->deallocateFunctionBody(Body);
      }
#if HAVE_LLVM < 0x0304
      virtual uint8_t *startExceptionTable(const llvm::Function *F,
                                           uintptr_t &ActualSize) {
         return mgr()->startExceptionTable(F, ActualSize);
      }
      virtual void endExceptionTable(const llvm::Function *F,
                                     uint8_t *TableStart,
                                     uint8_t *TableEnd,
                                     uint8_t *FrameRegister) {
         return mgr()->endExceptionTable(F, TableStart, TableEnd,
                                         FrameRegister);
      }
      virtual void deallocateExceptionTable(void *ET) {
         mgr()->deallocateExceptionTable(ET);
      }
#endif
      virtual bool CheckInvariants(std::string &s) {
         return mgr()->CheckInvariants(s);
      }
      virtual size_t GetDefaultCodeSlabSize() {
         return mgr()->GetDefaultCodeSlabSize();
      }
      virtual size_t GetDefaultDataSlabSize() {
         return mgr()->GetDefaultDataSlabSize();
      }
      virtual size_t GetDefaultStubSlabSize() {
         return mgr()->GetDefaultStubSlabSize();
      }
      virtual unsigned GetNumCodeSlabs() {
         return mgr()->GetNumCodeSlabs();
      }
      virtual unsigned GetNumDataSlabs() {
         return mgr()->GetNumDataSlabs();
      }
      virtual unsigned GetNumStubSlabs() {
         return mgr()->GetNumStubSlabs();
      }

      /*
       * From RTDyldMemoryManager
       */
      virtual uint8_t *allocateCodeSection(uintptr_t Size,
                                           unsigned Alignment,
                                           unsigned SectionID) {
         return mgr()->allocateCodeSection(Size, Alignment, SectionID);
      }
#if HAVE_LLVM >= 0x0303
      virtual uint8_t *allocateDataSection(uintptr_t Size,
                                           unsigned Alignment,
                                           unsigned SectionID,
                                           bool IsReadOnly) {
         return mgr()->allocateDataSection(Size, Alignment, SectionID,
                                  IsReadOnly);
      }
      virtual void registerEHFrames(llvm::StringRef SectionData) {
         return mgr()->registerEHFrames(SectionData);
      }
#else
      virtual uint8_t *allocateDataSection(uintptr_t Size,
                                           unsigned Alignment,
                                           unsigned SectionID) {
         return mgr()->allocateDataSection(Size, Alignment, SectionID);
      }
#endif
      virtual void *getPointerToNamedFunction(const std::string &Name,
                                              bool AbortOnFailure=true) {
         return mgr()->getPointerToNamedFunction(Name, AbortOnFailure);
      }
#if HAVE_LLVM == 0x0303
      virtual bool applyPermissions(std::string *ErrMsg = 0) {
         return mgr()->applyPermissions(ErrMsg);
      }
#elif HAVE_LLVM > 0x0303
      virtual bool finalizeMemory(std::string *ErrMsg = 0) {
         return mgr()->finalizeMemory(ErrMsg);
      }
#endif
};



More information about the llvm-dev mailing list