Re:Branch Prediction and the Performance of Interpreters – D...
by acqq on Monday August 10, 2015 @08:48AM
(#10034187)
> various tricks
They actually present (approximately) a very simple construct that is used to speed the interpreters up:
void labels[] = { &&ADD, &&SUB . . . };
...
goto labels[ vpc++ ];
ADD:
...
goto labels[ vpc++ ];
instead of ...
switch ( *vpc++ )
{
case ADD:
....
break;
case SUB:
It's not really hard. The only problem is that the former is not a standard C and not present in MSVC. Seehttp://stackoverflow.com/questions/6421433/address-of-labels...
"Erlang does (that) for building on Windows. They use MSVC for most of the build, and then GCC for one file to make use of the labels-as-values extension. The resulting object code is then hacked to be made compatible with the MSVC linker."
It obviously mattered enough for Erlang developers to use GCC even for just that critical piece of C code. It doesn't mean that it has to be regularly used in every code (not every switch is executed the way the main interpreter loop is).
Re:Branch Prediction and the Performance of Interpreters – D...
by haberman on Monday August 10, 2015 @10:34AM
(#10034833)
I'd be interested to see benchmark numbers for LuaJIT, which makes it extremely easy to compile with either replicated dispatch (each bytecode instruction footer has a separate dispatch "jmp" instruction) or common dispatch (each bytecode instruction jumps to a common dispatch "jmp" instruction): http://repo.or.cz/w/luajit-2.0.git/blob/a5b1c4d98eeb97a95077...
// Instruction footer.
.if 1
// Replicated dispatch. Less unpredictable branches, but higher I-Cache use.
.define ins_next, ins_NEXT
.define ins_next_, ins_NEXT
.else
// Common dispatch. Lower I-Cache use, only one (very) unpredictable branch.
// Affects only certain kinds of benchmarks (and only with -j off).
// Around 10%-30% slower on Core2, a lot more slower on P4.
.macro ins_next
jmp ->ins_next
.endmacro
.macro ins_next_
->ins_next:
ins_NEXT
.endmacro
.endif
* Interpreters are conceptually a big switch(bytecode) statement in an infinite loop. They use various tricks to make it easier for the processor to predict the target of the next indirect branch
* This previously had a dramatic impact on performance, because branch mispredictions are very expensive and it was difficult for the processor to predict them accurately.
* Recent Intel architectures have improved branch prediction, so the aforementioned tricks no longer have a very big impact (on Haswell x86 processors specifically)