[llvm-commits] [PATCH] Performance degradation when repeatedly exchanging JITted functions

Clemens Hammacher hammacher at cs.uni-saarland.de
Wed Mar 7 09:25:05 PST 2012


Hello,

some of you may already have read this on the LLVMdev list, but let me 
shortly recapitulate the problem:
When repeatedly calling recompileAndRelinkFunction on the same function, 
the global mapping is always updates with the new version, and at the 
memory location of the old version a jmp is added. This builds long 
chains of jmps, which lead to significant performance degradation, even 
if only exchanging several times (47% performance after exchanging 5 times).
Another problem is that the memory of the old version can never be freed 
since it participates in the jmp-chain. The current patch does not 
tackle this memory issue though.

The solution that this patch implements is the following:

The original stub (which is always being hold by the JITResolver) is 
updated to point to the new version in any case.
Additionally you can set a flag in the ExecutionEngine to always use the 
stub when calling a function. If this flag is set, a 
recompileAndRelinkFunction does *not* patch the old function pointer to 
jump to the new function, since all calls use the stub anyway.

Since several places in the JIT itself rely on the global mapping being 
updated to the start of the newly jitted function, I didn't change that. 
Instead, after jitting a function, the mapping is changed back to the 
stub, if the KeepStubs flag is set.
The only drawback of this is that *directly* recursive calls still 
bypass the stub and jump back directly to the function pointer. To 
estimate how important that issue is you have to distinguish two cases: 
Either one thread wants to exchange a function that is concurrently 
being executed by another thread. Then you run into a lot of other 
problem too, since the whole jitting and memory patching is 
unsynchronized to running code. The other case would be that a thread 
wants to exchange a function that he is currently executing, so that 
further recursive calls use the new version. This is unsafe also in the 
current implementation, since you would overwrite the memory of the 
function that is being executed. So at least it is no regression from 
the current implementation. Nevertheless, it may be allowed later, after 
changing larger parts of the code.

So I think this should be fine for now.

I attached a patch implementing this, and a test case for the new flag. 
Both apply to trunk.

While implementing this, I also stumbled across another bug, so whoever 
commits the attached patches may also just have a look at the fix and 
the testcase I attached to that bug report, since it is slightly related.
http://llvm.org/bugs/show_bug.cgi?id=12197

If you comment on this patch, please also include me personally, since 
I'm not subscribed to llvm-commits.

Thanks,
Clemens
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: implement_KeepStubs.patch
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20120307/8d286003/attachment.ksh>
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: testcase_KeepStubs.patch
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20120307/8d286003/attachment-0001.ksh>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: smime.p7s
Type: application/pkcs7-signature
Size: 6392 bytes
Desc: S/MIME Cryptographic Signature
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20120307/8d286003/attachment.bin>


More information about the llvm-commits mailing list