Dynamic compilation for performance

I have an idea of ​​how I can improve the performance when generating dynamic code, but I'm not sure if this is the best way to approach this problem.

Suppose I have a class


class Calculator
{
  int Value1;
  int Value2;
  //.......... 
  int ValueN;

  void DoCalc()
  {
    if (Value1 > 0)
    {
      DoValue1RelatedStuff();    
    }
    if (Value2 > 0)
    {
      DoValue2RelatedStuff();    
    }
    //....
    //....
    //....
    if (ValueN > 0)
    {
      DoValueNRelatedStuff();    
    }
  }
}

      

The DoCalc method is at the lowest level and is called many times during computation. Another important aspect is that ValueNs are set only at the beginning and do not change during the calculation. Thus, many of the ifs in the DoCalc method are unnecessary as many of the ValueNs are 0. So I was hoping that generating dynamic code could help improve performance.

For example, if I create a method


  void DoCalc_Specific()
  {
    const Value1 = 0;
    const Value2 = 0;
    const ValueN = 1;

    if (Value1 > 0)
    {
      DoValue1RelatedStuff();    
    }
    if (Value2 > 0)
    {
      DoValue2RelatedStuff();    
    }
    ....
    ....
    ....
    if (ValueN > 0)
    {
      DoValueNRelatedStuff();    
    }
  }

      

and compiling it with optimizations enabled on the C # compiler is smart enough to only support the stuff you need. So I would like to create such a method at runtime based on the ValueN values ​​and use the generated method during computation.

I guess I could use expression trees for this, but expression trees only work with simple lambda functions, so I cannot use things like if, while, etc. inside the function body. So in this case, I need to change this method accordingly.

Another possibility is to create the required code as a string and compile it dynamically. But it would be much better for me if I could accept the existing method and modify it accordingly.

There's also Reflection.Emit, but I don't want to stick with it as it would be very difficult to maintain.

BTW. I am not limited to C #. Therefore, I am open to suggestions for programming languages ​​that are best suited for this kind of problem. Except for LISP for several reasons.

One important clarification. DoValue1RelatedStuff () is not a method call in my algorithm. It's just some kind of formula-based calculation, and it's pretty fast. I had to write it like this


if (Value1 > 0)
{
  // Do Value1 Related Stuff
}

      

I have done some performance tests and I can see that with two ifs when disabled, the optimized method is about 2x faster than with redundant ifs.

Here's the code I used for testing:


    public class Program
    {
        static void Main(string[] args)
        {
            int x = 0, y = 2;

            var if_st = DateTime.Now.Ticks;
            for (var i = 0; i  < 10000000; i++)
            {
                WithIf(x, y);
            }
            var if_et = DateTime.Now.Ticks - if_st;
            Console.WriteLine(if_et.ToString());

            var noif_st = DateTime.Now.Ticks;
            for (var i = 0; i  < 10000000; i++)
            {
                Without(x, y);
            }
            var noif_et = DateTime.Now.Ticks - noif_st;
            Console.WriteLine(noif_et.ToString());

            Console.ReadLine();

        }

        static double WithIf(int x, int y)
        {
            var result = 0.0;
            for (var i = 0; i  < 100; i++)
            {
                if (x > 0)
                {
                    result += x * 0.01;
                }
                if (y > 0)
                {
                    result += y * 0.01;
                }
            }
            return result;
        }

        static double Without(int x, int y)
        {
            var result = 0.0;
            for (var i = 0; i < 100; i++)
            {
                result += y * 0.01;
            }
            return result;
        }
    }

      

+2


source to share


4 answers


Usually I didn't even think about such an optimization. How much work does it do DoValueXRelatedStuff()

? More than 10-50 CPU cycles? Yes? This means that you are going to build a rather complex system to save less than 10% of the execution time (and this seems quite optimistic to me). This can easily drop to less than 1%.

Is there room for other optimizations? Best Algorithms? Do you really need to eliminate individual branches taking up only one CPU cycle (if the branch prediction is correct)? Yes? Shouldn't you be thinking about writing code in assembly or something even more machine specific than .NET?



Can't you specify the order N

, complexity of a typical method, and the ratio of expressions that normally evaluate to true?

+2


source


I would be surprised to find a scenario where the overhead of evaluating if statements is worth the effort to dynamically emit code.

Modern processor support for branch prediction and branch prediction , which brings the overhead for branches in small code segments to zero.



Have you tried testing two hand-coded code points that contain all if statements, but have zero values ​​for most, and which delete all the same branches?

+1


source


If you are really into code optimization - before you do anything - run the profiler! It will show you where the bottleneck is and what areas to optimize for.

Also - if the choice of language is not limited (except for LISP), nothing will beat the assembler in terms of performance;)

I remember how you achieved some performance magic by rewriting some internal functions (like the one you have) with assembler.

+1


source


Before you do anything, do you really have a problem?

i.e. does it work long enough to bother you?

If so, find out what actually takes time, not what you guess. This is the quick, dirty and highly efficient method I use to find out where the time is.

Now you are talking about interpretation and compilation. Interpreted code is usually 1-2 orders of magnitude slower than compiled code. The reason is that translators constantly figure out what to do next and then forget, but the compiled code just knows.

If you are in this situation, then it makes sense to pay the price for translation in order to get the speed of the compiled code.

0


source







All Articles