开发者

Function calls in virtual machine killing performance

开发者 https://www.devze.com 2023-02-05 12:15 出处:网络
I wrote a virtual machine in C, which has a call table populated by pointers to functions that provide the functionality of the VM\'s opcodes. When the virtual machine is run, it first interprets a pr

I wrote a virtual machine in C, which has a call table populated by pointers to functions that provide the functionality of the VM's opcodes. When the virtual machine is run, it first interprets a program, creating an array of indexes corresponding to the appropriate function in the call table for the opcode provided. It then loops through the array, calling each function until it reaches the end.

Each instruction is extremely small, typically one line. Perfect for inlining. The problem is that the compiler doesn't know when any of the virtual machine's instructions are going to be called, as it's decided at runtime, so it can't inline them. The overhead of function calls and argument passing is killing the performance of my VM. Any ideas on how t开发者_如何学JAVAo get around this?


Here are some options for reducing the overhead:

  1. Declare the functions as fastcall (or something similar) to reduce the overhead of argument passing
  2. Use a large switch-case instead of a table of function pointers (the compiler will optimize to a jump table, and you remove the overhead of actually calling the function)
  3. Copy all the code for a VM procedure to one location so that it can run sequentially, rather than returning to the interpreter after each instruction.

Eventually you're going to get to the point of JIT-compiling, on-line profiling and reoptimization, and all sorts of other awesome stuff.


There are many good techniques you might want to look into. Here are two that I'm familiar with:

  1. Inline caching- Essentially, finding what keeps getting called, then switching from a vtable lookup to just adding a bunch of if statements that dispatch to a statically-known location. This technique was used to great effect in the Self language and is one of the JVM's major optimizations.

  2. Tracing- Compiling one version of a piece of a polymorphic dispatch for each type that might end up being used, but deferring compilation until the code has been run sufficiently many times. Mozilla's TraceMonkey JavaScript interpreter uses this to get a huge performance win in many cases.

Hope this helps!

0

精彩评论

暂无评论...
验证码 换一张
取 消