Hello! Working with LLVM JIT-compiler I found a small bug and I'd like to correct it. Namely, on some tests LLVM fails with message "JIT: Ran out of space for generated machine code!" This error emerges because the test creates big static array. Global variables are placed into memory block for function, that is first seen using given variable. Besides, during memory allocation for function its size is not considered in any way. Although there exist a code block (in JITEmitter::startFunction), which is able to calculate function size, allocator (in DefaultJITMemoryManager::startFunctionBody) does not consider predicted function size. So lli fails, when a test uses big static array. How would you advise to correct this bug? It is possible to allocate global variables in separate memory block(s) (in my opinion, it is not so good to place variables into executable memory area), or it is possible to improve allocator so that it considers predicted function size. However, if using size prediction, JIT calculation of exact function size may occupy time. Probably it would be better to estimate function size instead of exact calculation.
On Wed, Jul 1, 2009 at 9:07 AM, Merkulov Aleksey<steel1.0 at mail.ru> wrote:> Hello! Working with LLVM JIT-compiler I found a small bug and I'd like to correct it. Namely, on some tests LLVM fails with message "JIT: Ran out of space for generated machine code!"I'm working on a patch to fix this, although I've heard DOE may change the MachineCodeEmitter interface to make this less necessary. http://codereview.appspot.com/71042> This error emerges because the test creates big static array. Global variables are placed into memory block for function, that is first seen using given variable. Besides, during memory allocation for function its size is not considered in any way. Although there exist a code block (in JITEmitter::startFunction), which is able to calculate function size, allocator (in DefaultJITMemoryManager::startFunctionBody) does not consider predicted function size. So lli fails, when a test uses big static array.According to the documentation I have read, in general it is not possible to predict code size, but from that block of code it seems like it works for someone using a custom memory manager that does pay attention to size on some platform. I'm also working on a patch to separate globals from code, but apparently Apple wants to support that behavior, even though it breaks freeMachineCodeForFunction. http://llvm.org/bugs/show_bug.cgi?id=4483> How would you advise to correct this bug? It is possible to allocate global variables in separate memory block(s) (in my opinion, it is not so good to place variables into executable memory area), or it is possible to improve allocator so that it considers predicted function size. However, if using size prediction, JIT calculation of exact function size may occupy time. Probably it would be better to estimate function size instead of exact calculation.Unless there is some DOE change that I'm not aware of that totally changes the situation, I think the right thing to do is to just fully implement the API. I think that emitting the binary from the MachineFunction isn't much of a bottleneck, but I don't have hard data that says so. All of the target-specific MachineCodeEmitters are coded to retry on failure. The problem is that right now the memory manager doesn't know how to request more space from the OS. Reid
On Wed, Jul 1, 2009 at 9:43 AM, Reid Kleckner<rnk at mit.edu> wrote:> On Wed, Jul 1, 2009 at 9:07 AM, Merkulov Aleksey<steel1.0 at mail.ru> wrote: >> Hello! Working with LLVM JIT-compiler I found a small bug and I'd like to correct it. Namely, on some tests LLVM fails with message "JIT: Ran out of space for generated machine code!" > > I'm working on a patch to fix this, although I've heard DOE may change > the MachineCodeEmitter interface to make this less necessary.Where "DOE" is "Direct Object Code Emission", described at http://wiki.llvm.org/Direct_Object_Code_Emission
+llvmdev 2009/7/3 Merkulov Aleksey <steel1.0 at mail.ru>:>> > Hello! Working with LLVM JIT-compiler I found a small bug and I'd like to correct it. Namely, on some tests LLVM fails with message "JIT: Ran out of space for generated machine code!" >> >> I'm working on a patch to fix this, although I've heard DOE may change >> the MachineCodeEmitter interface to make this less necessary. >> >> http://codereview.appspot.com/71042 > > Hello! Thanks a lot for the patch! I had applied it and my test stopped to break lli, but it worked incorrectly. So I fixed the patch (see below) and now it seems that my test doesn't break lli and works correctly. > > If allocated block is too small for function body and globals, then it is necessary to remove globals allocated in that block from mappings. So we should backup Relocations before changes in "for (unsigned i = 0, e = Relocations.size(); i != e; ++i) {" loop, and, in case of buffer overflow, we should remove globals from mappings. Also, we should clear ConstPoolAddresses. There are only two changes in function JITEmitter::finishFunction: > > > --- lib/ExecutionEngine/JIT/JITEmitter.cpp (original patch) > +++ lib/ExecutionEngine/JIT/JITEmitter.cpp (my changes) > @@ -946,6 +947,7 @@ > // FnEnd is the end of the function's machine code. > uint8_t *FnEnd = CurBufferPtr; > > + std::vector<MachineRelocation> BackupRelocations = Relocations; > if (!Relocations.empty()) { > CurFn = F.getFunction(); > NumRelos += Relocations.size(); > @@ -1028,8 +1030,18 @@ > MemMgr->endFunctionBody(F.getFunction(), BufferBegin, CurBufferPtr); > > if (CurBufferPtr == BufferEnd) { > - retryWithMoreMemory(F); > - return true; > + for (unsigned i = 0, e = BackupRelocations.size(); i != e; ++i) { > + MachineRelocation &MR = BackupRelocations[i]; > + if (MR.isGlobalValue()) { > + void* ResultPtr = TheJIT->getPointerToGlobalIfAvailable(MR.getGlobalValue()); > + if (BufferBegin <= ResultPtr && ResultPtr < BufferEnd) { > + TheJIT->updateGlobalMapping(MR.getGlobalValue(), 0); > + } > + } > + } > + retryWithMoreMemory(F); > + ConstPoolAddresses.clear(); > + return true; > } else { > // Now that we've succeeded in emitting the function, reset the > // SizeEstimate > >This is a known problem, and the solution I chose was to not emit global data and code into the same buffer, since it breaks freeMachineCodeForFunction in general, which is what retryWithMoreMemory depends on. When that patch, which I sent to llvm-commits last night, goes in I'll fix up this patch so that it allocates more space for code and data. It might still be worth applying this patch because some clients still rely on the old behavior where code and data go together, and if they run out of memory, they're screwed. Reid
Reasonably Related Threads
- [LLVMdev] Question about memory allocation in JIT
- [LLVMdev] Being able to know the jitted code-size before emitting
- [LLVMdev] Being able to know the jitted code-size before emitting
- [LLVMdev] Being able to know the jitted code-size before emitting
- [LLVMdev] Being able to know the jitted code-size before emitting