delegate vs condition check

  • Follow


hello everyone,

today i tested the speed of a delegate relaying to a function against
the speed of an an if, that checks the condition of a boolean value,
relaying to a function (the code is attached at the end of this post).
in my test it turned out, the delegate was twice as fast as checking
the boolean.

this lead me to the conclusion, that whenever object behavior depends
on values, known from time of construction, it is faster to compose an
object (compose of delegates and/or other objects) at construction
time, rather than checking condition(s) every time an object is used.
this goes with the constraint, that cost of construction by
composition must be smaller than the summarized cost of using the
object over its lifetime (cost of construction by composition must be
reasonable low).

does everyone concure? do i miss something?


regards,
arthur




 here is the code:

    public abstract class BaseClass
    {
        protected bool _Value;
        public BaseClass(bool Value)
        {
            _Value=Value;
            this.Initialize();
        }
        protected abstract void Initialize();
        public abstract void Action();
        protected void Action1() { }
        protected void Action2() { }
    }

    public class DelegateClass : BaseClass
    {
        public DelegateClass(bool Value) : base(Value) { }
        private DoDelegate _DoAction = null;
        protected override void Initialize()
        {
            if (_Value)
                _DoAction = new DoDelegate(this.Action1);
            else
                _DoAction = new DoDelegate(this.Action2);
        }
        public override void Action()
        {
            _DoAction();
        }
        private delegate void DoDelegate();
    }

    public class ConditionClass : BaseClass
    {
        public ConditionClass(bool Value) : base(Value) { }
        protected override void Initialize()
        {
        }
        public override void Action()
        {
            if (_Value)
                this.Action1();
            else
                this.Action2();
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            int iterations = 100000000;
            Console.WriteLine(iterations);
            bool value = true;
            Console.WriteLine(value);

            BaseClass action = new DelegateClass(value);
            TimeSpan duration = Iterate(iterations, action);
            Console.WriteLine("Delegate: "+duration);

            action = new ConditionClass(value);
            duration = Iterate(iterations, action);
            Console.WriteLine("Condition: "+duration);

            Console.WriteLine("Press ENTER to exit.");
            Console.ReadLine();
        }

        private static TimeSpan Iterate(int iterations, BaseClass
action)
        {
            DateTime start = DateTime.Now;
            for (int i = 0; i < iterations; i++)
            {
                action.Action();
            }
            DateTime end = DateTime.Now;
            TimeSpan duration = end.Subtract(start);
            return duration;
        }
    }
0
Reply Art 6/29/2010 3:05:14 PM

Art wrote:
> hello everyone,
> 
> today i tested the speed of a delegate relaying to a function against
> the speed of an an if, that checks the condition of a boolean value,
> relaying to a function (the code is attached at the end of this post).
> in my test it turned out, the delegate was twice as fast as checking
> the boolean.
> 
> this lead me to the conclusion, that whenever object behavior depends
> on values, known from time of construction, it is faster to compose an
> object (compose of delegates and/or other objects) at construction
> time, rather than checking condition(s) every time an object is used.
> this goes with the constraint, that cost of construction by
> composition must be smaller than the summarized cost of using the
> object over its lifetime (cost of construction by composition must be
> reasonable low).
> 
> does everyone concure? do i miss something?

One big issue with your benchmark code is that it does no "warm-up" 
iterations to attempt to get things into a stable state (JIT compiled, 
cache lines set, CPU pipelines filled including pre-fetch and branch 
prediction, etc.).  You also do only one trial per execution of the 
program, rather than doing several and averaging the results after 
discarding the outliers.  So your observations may or may not be accurate.

That said, while I haven't tried the test myself, I see no obvious 
reason that a delegate invocation _wouldn't_ be faster, since it's an 
invariant condition while the boolean test is not (or at least, there's 
no way for the compiler or CPU to know that it's not).  And it stands to 
reason that invariant conditions can be cached/predicted/etc. better 
than variant conditions.

But, your analysis overlooks a few very important points:

   � The difference in speed (if any) might be accounted for by 
optimizations that the JIT compiler or even CPU is able to make in your 
benchmark code, but which would not apply in a more complicated 
scenario.  The only true way to know for sure whether an optimization 
will help is to test it in production code.

   � Delegates cost memory, and use of memory can slow a program down. 
So whether this approach nets a benefit will depend heavily on how many 
delegates the approach winds up creating.  Doing it in a static class or 
in an instance of a class that is created only once or a few times won't 
change the outcome, but doing it in a class that is instantiated  large 
number of times could produce a significant increase in memory usage, 
which can disturb locality or even cause increased swap file usage, both 
of which will _dramatically_ slow the program down.

   � Whatever the difference in performance cost, it is highly unlikely 
that it is significant when compared to the cost of the code being 
controlled by the condition.  Your benchmark is pretty much a worst-case 
scenario, because the methods being called do nothing at all.  A method 
that does even something as simple as checking a boolean flag will 
automatically take at least as long as the dispatch mechanism itself, 
and of course most methods do things far more interesting than that.

I would expect in the typical case that the cost of dispatch winds up 
being less than 10% of the total cost of calling the method, perhaps 
even less than 1%, and of course that difference in cost is further 
reduced in significant when the cost of the one method being dispatched 
is considered in context of the entire program.  Even if that method 
accounts for 10% of the execution time of the program (which would be 
very unusual), that means that the net effect on program execution time 
would be less than 1% even under the generous assumption that the 
dispatching difference can account for a 10% improvement in method 
invocation time.

In other words, even if this is a valid observation, it's unlikely to 
have any practical effect since the performance improvement is not large 
enough to outweigh the question of which version is more maintainable. 
Either _could_ be the more maintainable approach, depending on context, 
and _that_ is the question that should drive the implementation here, 
not the performance considerations.

Pete
0
Reply Peter 6/29/2010 3:23:36 PM

1 Replies
518 Views

(page loaded in 0.043 seconds)


Reply: