May 16 2011

Stay out of the JIT's way

The JIT compiler will; unless told otherwise; apply a number of optimizations at runtime to address both minor and major inefficiencies in the code we write. Examples include the following:

  • Constant Folding
  • Constant and Copy Propagation
  • Method Inlining
  • Code Hoisting and Dominators
  • Loop Unrolling
  • Common SubExpression Elimination
  • Enregistration
  • And others…

Generally we don’t need to think about these details too much, although where hyper-performance concerns exist we should. The reason is because our coding patterns can lead to situations where the JIT decides to completely skip optimizations to ensure it doesn’t break the code we’ve written. Let’s take Method Inlining for example. Here is a list of JIT rules that guide its decision to optimize:

… Method Inlining
There is a cost associated with method calls; arguments need to be pushed on the stack or stored in registers, the method prolog and epilog need to be executed and so on. The cost of these calls can be avoided for certain methods by simply moving the method body of the method being called into the body of the caller. This is called Method In-lining. The JIT uses a number of heuristics to decide whether a method should be in-lined. The following is a list of the more significant of those (note that this is not exhaustive):

  • Methods that are greater than 32 bytes of IL will not be inlined
  • Virtual functions are not inlined
  • Methods that have complex flow control will not be in-lined. Complex flow control is any flow control other than if/then/else; in this case, switch or while
  • Methods that contain exception-handling blocks are not inlined, though methods that throw exceptions are still candidates for inlining
  • If any of the method's formal arguments are structs, the method will not be inlined. …

As developers, there are a few basic behaviors we should follow to ensure we can take advantage of these optimizations:

  • Keep method size small (e.g. < 32 bytes of IL)
  • Keep the contents of a try-catch-finally block small by moving the code to be executed in the try and catch blocks to another method
  • Don’t make members virtual unless you have a clear need to do so

Tags: ,

Comments

1.
trackback DotNetKicks.com says:

Stay out of the JIT's way

You've been kicked (a good thing) - Trackback from DotNetKicks.com

Comments are closed