Prev: Painting datagrid view
Next: Use of Assembly Attributes
From: Art on 29 Jun 2010 11:05 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; } }
From: Peter Duniho on 29 Jun 2010 11:23 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
|
Pages: 1 Prev: Painting datagrid view Next: Use of Assembly Attributes |