For a few weeks now, an experimental JIT compiler has been available in the DWScript SVN for 32bits code. A more detailed article into the hows and whats and WTFs will come later.
Consider this article as an extended teaser, and a sort of call for test cases, benchmarks and eyeballs on the source code.
Following benchmarks were compiled in XE2 with full optimization, no stack frames and no range checking. Absolute values aren’t meaningful, just consider them relatively.
(lower is better)
Delphi XE2-32bit : 515
Delphi XE3-64bit: 162
DWScript JIT 32bit: 281
The JIT was initially tested on the Mandelbrot benchmark, so that’s one of the cases where JITing is almost complete, with the exception of the SetPixel() call.
(higher is better)
Delphi XE2-32bit : 507
Delphi XE3-64bit: 682
DWScript JIT 32bit: 215
Delphi version uses pointers, DWScript version was slightly updated to use dynamic arrays instead and JITting is partial at the moment.
The benchmark involves fairly large matrices, and DWScript use of Variant (16 bytes) rather than Double (8 bytes) means the data no longer fits in the CPU cache, which partly accounts for the poor showing of the JIT.
(lower is better)
Delphi XE2-32bit : 208
Delphi XE3-64bit: 47
DWScript JIT 32bit: 63
This test measures of execution time of the following code (fully JITted), which computes the base values for common array statistics (range, average, deviation, etc.). The Delphi 32bit compiler really suffers because of Min/Max (despite having inlined them).
// "a" a floating point array of non-ordered values for v in a do begin s := s + v; s2 := s2 + v*v; mi := Min(mi, v); ma := Max(ma, v); end;
The DWScript JIT compiler relies on SSE2 to outperform the Delphi 32bit compiler, its current main limitations are:
- JIT centers around floating point and a limited subset of integer and Boolean operations, the rest isn’t JITted yet.
- Function calls aren’t JITted at the moment, and neither are a variety of other statements.
- The JIT works with the same data structures as the interpreted engine, that means script debuggers and everything else works on JITted code as if it was still interpreted, but that also means the basic data unit is still the 16 bytes Variant at the moment.
- The JIT register allocator is currently limited to floating point (ie. no integer or pointer allocations).
- DWScript Integer type is 64bit sized, so for 32bit values, Integer performance is lower than what Delphi 32 can do, even though the JIT can generate typically faster code for it than the Delphi 32bit compiler does for Int64.
The JIT also suffers against a 64bit compiler as there are 64bit CPU instructions (and registers) not accessible in 32bit mode, but a 64bit JIT should be able to go farther.
If you’re interested and want to help, I’m currently looking for benchmarks and test cases, if you have code that compiles in both Delphi and DWScript, particularly on integer maths (encryption, etc.) or object-oriented manipulations (graphs, trees…) that could help. You’re even allowed to have the Delphi version use pointers and other tricks, the comparison doesn’t need to be fair 😉